Coverage Report

Created: 2023-11-27 06:31

/src/quickjs/quickjs.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * QuickJS Javascript Engine
3
 * 
4
 * Copyright (c) 2017-2021 Fabrice Bellard
5
 * Copyright (c) 2017-2021 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__)
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
#ifdef CONFIG_BIGNUM
48
#include "libbf.h"
49
#endif
50
51
4.21M
#define OPTIMIZE         1
52
#define SHORT_OPCODES    1
53
#if defined(EMSCRIPTEN)
54
#define DIRECT_DISPATCH  0
55
#else
56
#define DIRECT_DISPATCH  1
57
#endif
58
59
#if defined(__APPLE__)
60
#define MALLOC_OVERHEAD  0
61
#else
62
84.8M
#define MALLOC_OVERHEAD  8
63
#endif
64
65
#if !defined(_WIN32)
66
/* define it if printf uses the RNDN rounding mode instead of RNDNA */
67
#define CONFIG_PRINTF_RNDN
68
#endif
69
70
/* define to include Atomics.* operations which depend on the OS
71
   threads */
72
#if !defined(EMSCRIPTEN)
73
#define CONFIG_ATOMICS
74
#endif
75
76
#if !defined(EMSCRIPTEN)
77
/* enable stack limitation */
78
#define CONFIG_STACK_CHECK
79
#endif
80
81
82
/* dump object free */
83
//#define DUMP_FREE
84
//#define DUMP_CLOSURE
85
/* dump the bytecode of the compiled functions: combination of bits
86
   1: dump pass 3 final byte code
87
   2: dump pass 2 code
88
   4: dump pass 1 code
89
   8: dump stdlib functions
90
  16: dump bytecode in hex
91
  32: dump line number table
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_PROMISE
107
//#define DUMP_READ_OBJECT
108
109
/* test the GC by forcing it before each object allocation */
110
//#define FORCE_GC_AT_MALLOC
111
112
#ifdef CONFIG_ATOMICS
113
#include <pthread.h>
114
#include <stdatomic.h>
115
#include <errno.h>
116
#endif
117
118
enum {
119
    /* classid tag        */    /* union usage   | properties */
120
    JS_CLASS_OBJECT = 1,        /* must be first */
121
    JS_CLASS_ARRAY,             /* u.array       | length */
122
    JS_CLASS_ERROR,
123
    JS_CLASS_NUMBER,            /* u.object_data */
124
    JS_CLASS_STRING,            /* u.object_data */
125
    JS_CLASS_BOOLEAN,           /* u.object_data */
126
    JS_CLASS_SYMBOL,            /* u.object_data */
127
    JS_CLASS_ARGUMENTS,         /* u.array       | length */
128
    JS_CLASS_MAPPED_ARGUMENTS,  /*               | length */
129
    JS_CLASS_DATE,              /* u.object_data */
130
    JS_CLASS_MODULE_NS,
131
    JS_CLASS_C_FUNCTION,        /* u.cfunc */
132
    JS_CLASS_BYTECODE_FUNCTION, /* u.func */
133
    JS_CLASS_BOUND_FUNCTION,    /* u.bound_function */
134
    JS_CLASS_C_FUNCTION_DATA,   /* u.c_function_data_record */
135
    JS_CLASS_GENERATOR_FUNCTION, /* u.func */
136
    JS_CLASS_FOR_IN_ITERATOR,   /* u.for_in_iterator */
137
    JS_CLASS_REGEXP,            /* u.regexp */
138
    JS_CLASS_ARRAY_BUFFER,      /* u.array_buffer */
139
    JS_CLASS_SHARED_ARRAY_BUFFER, /* u.array_buffer */
140
    JS_CLASS_UINT8C_ARRAY,      /* u.array (typed_array) */
141
    JS_CLASS_INT8_ARRAY,        /* u.array (typed_array) */
142
    JS_CLASS_UINT8_ARRAY,       /* u.array (typed_array) */
143
    JS_CLASS_INT16_ARRAY,       /* u.array (typed_array) */
144
    JS_CLASS_UINT16_ARRAY,      /* u.array (typed_array) */
145
    JS_CLASS_INT32_ARRAY,       /* u.array (typed_array) */
146
    JS_CLASS_UINT32_ARRAY,      /* u.array (typed_array) */
147
#ifdef CONFIG_BIGNUM
148
    JS_CLASS_BIG_INT64_ARRAY,   /* u.array (typed_array) */
149
    JS_CLASS_BIG_UINT64_ARRAY,  /* u.array (typed_array) */
150
#endif
151
    JS_CLASS_FLOAT32_ARRAY,     /* u.array (typed_array) */
152
    JS_CLASS_FLOAT64_ARRAY,     /* u.array (typed_array) */
153
    JS_CLASS_DATAVIEW,          /* u.typed_array */
154
#ifdef CONFIG_BIGNUM
155
    JS_CLASS_BIG_INT,           /* u.object_data */
156
    JS_CLASS_BIG_FLOAT,         /* u.object_data */
157
    JS_CLASS_FLOAT_ENV,         /* u.float_env */
158
    JS_CLASS_BIG_DECIMAL,       /* u.object_data */
159
    JS_CLASS_OPERATOR_SET,      /* u.operator_set */
160
#endif
161
    JS_CLASS_MAP,               /* u.map_state */
162
    JS_CLASS_SET,               /* u.map_state */
163
    JS_CLASS_WEAKMAP,           /* u.map_state */
164
    JS_CLASS_WEAKSET,           /* u.map_state */
165
    JS_CLASS_MAP_ITERATOR,      /* u.map_iterator_data */
166
    JS_CLASS_SET_ITERATOR,      /* u.map_iterator_data */
167
    JS_CLASS_ARRAY_ITERATOR,    /* u.array_iterator_data */
168
    JS_CLASS_STRING_ITERATOR,   /* u.array_iterator_data */
169
    JS_CLASS_REGEXP_STRING_ITERATOR,   /* u.regexp_string_iterator_data */
170
    JS_CLASS_GENERATOR,         /* u.generator_data */
171
    JS_CLASS_PROXY,             /* u.proxy_data */
172
    JS_CLASS_PROMISE,           /* u.promise_data */
173
    JS_CLASS_PROMISE_RESOLVE_FUNCTION,  /* u.promise_function_data */
174
    JS_CLASS_PROMISE_REJECT_FUNCTION,   /* u.promise_function_data */
175
    JS_CLASS_ASYNC_FUNCTION,            /* u.func */
176
    JS_CLASS_ASYNC_FUNCTION_RESOLVE,    /* u.async_function_data */
177
    JS_CLASS_ASYNC_FUNCTION_REJECT,     /* u.async_function_data */
178
    JS_CLASS_ASYNC_FROM_SYNC_ITERATOR,  /* u.async_from_sync_iterator_data */
179
    JS_CLASS_ASYNC_GENERATOR_FUNCTION,  /* u.func */
180
    JS_CLASS_ASYNC_GENERATOR,   /* u.async_generator_data */
181
182
    JS_CLASS_INIT_COUNT, /* last entry for predefined classes */
183
};
184
185
/* number of typed array types */
186
24
#define JS_TYPED_ARRAY_COUNT  (JS_CLASS_FLOAT64_ARRAY - JS_CLASS_UINT8C_ARRAY + 1)
187
static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT];
188
44
#define typed_array_size_log2(classid)  (typed_array_size_log2[(classid)- JS_CLASS_UINT8C_ARRAY])
189
190
typedef enum JSErrorEnum {
191
    JS_EVAL_ERROR,
192
    JS_RANGE_ERROR,
193
    JS_REFERENCE_ERROR,
194
    JS_SYNTAX_ERROR,
195
    JS_TYPE_ERROR,
196
    JS_URI_ERROR,
197
    JS_INTERNAL_ERROR,
198
    JS_AGGREGATE_ERROR,
199
    
200
    JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */
201
} JSErrorEnum;
202
203
142k
#define JS_MAX_LOCAL_VARS 65536
204
89.1k
#define JS_STACK_SIZE_MAX 65534
205
4.58M
#define JS_STRING_LEN_MAX ((1 << 30) - 1)
206
207
#define __exception __attribute__((warn_unused_result))
208
209
typedef struct JSShape JSShape;
210
typedef struct JSString JSString;
211
typedef struct JSString JSAtomStruct;
212
213
typedef enum {
214
    JS_GC_PHASE_NONE,
215
    JS_GC_PHASE_DECREF,
216
    JS_GC_PHASE_REMOVE_CYCLES,
217
} JSGCPhaseEnum;
218
219
typedef enum OPCodeEnum OPCodeEnum;
220
221
#ifdef CONFIG_BIGNUM
222
/* function pointers are used for numeric operations so that it is
223
   possible to remove some numeric types */
224
typedef struct {
225
    JSValue (*to_string)(JSContext *ctx, JSValueConst val);
226
    JSValue (*from_string)(JSContext *ctx, const char *buf,
227
                           int radix, int flags, slimb_t *pexponent);
228
    int (*unary_arith)(JSContext *ctx,
229
                       JSValue *pres, OPCodeEnum op, JSValue op1);
230
    int (*binary_arith)(JSContext *ctx, OPCodeEnum op,
231
                        JSValue *pres, JSValue op1, JSValue op2);
232
    int (*compare)(JSContext *ctx, OPCodeEnum op,
233
                   JSValue op1, JSValue op2);
234
    /* only for bigfloat: */
235
    JSValue (*mul_pow10_to_float64)(JSContext *ctx, const bf_t *a,
236
                                    int64_t exponent);
237
    int (*mul_pow10)(JSContext *ctx, JSValue *sp);
238
} JSNumericOperations;
239
#endif
240
241
struct JSRuntime {
242
    JSMallocFunctions mf;
243
    JSMallocState malloc_state;
244
    const char *rt_info;
245
246
    int atom_hash_size; /* power of two */
247
    int atom_count;
248
    int atom_size;
249
    int atom_count_resize; /* resize hash table at this count */
250
    uint32_t *atom_hash;
251
    JSAtomStruct **atom_array;
252
    int atom_free_index; /* 0 = none */
253
254
    int class_count;    /* size of class_array */
255
    JSClass *class_array;
256
257
    struct list_head context_list; /* list of JSContext.link */
258
    /* list of JSGCObjectHeader.link. List of allocated GC objects (used
259
       by the garbage collector) */
260
    struct list_head gc_obj_list;
261
    /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */
262
    struct list_head gc_zero_ref_count_list; 
263
    struct list_head tmp_obj_list; /* used during GC */
264
    JSGCPhaseEnum gc_phase : 8;
265
    size_t malloc_gc_threshold;
266
#ifdef DUMP_LEAKS
267
    struct list_head string_list; /* list of JSString.link */
268
#endif
269
    /* stack limitation */
270
    uintptr_t stack_size; /* in bytes, 0 if no limit */
271
    uintptr_t stack_top;
272
    uintptr_t stack_limit; /* lower stack limit */
273
    
274
    JSValue current_exception;
275
    /* true if inside an out of memory error, to avoid recursing */
276
    BOOL in_out_of_memory : 8;
277
278
    struct JSStackFrame *current_stack_frame;
279
280
    JSInterruptHandler *interrupt_handler;
281
    void *interrupt_opaque;
282
283
    JSHostPromiseRejectionTracker *host_promise_rejection_tracker;
284
    void *host_promise_rejection_tracker_opaque;
285
    
286
    struct list_head job_list; /* list of JSJobEntry.link */
287
288
    JSModuleNormalizeFunc *module_normalize_func;
289
    JSModuleLoaderFunc *module_loader_func;
290
    void *module_loader_opaque;
291
292
    BOOL can_block : 8; /* TRUE if Atomics.wait can block */
293
    /* used to allocate, free and clone SharedArrayBuffers */
294
    JSSharedArrayBufferFunctions sab_funcs;
295
    
296
    /* Shape hash table */
297
    int shape_hash_bits;
298
    int shape_hash_size;
299
    int shape_hash_count; /* number of hashed shapes */
300
    JSShape **shape_hash;
301
#ifdef CONFIG_BIGNUM
302
    bf_context_t bf_ctx;
303
    JSNumericOperations bigint_ops;
304
    JSNumericOperations bigfloat_ops;
305
    JSNumericOperations bigdecimal_ops;
306
    uint32_t operator_count;
307
#endif
308
    void *user_opaque;
309
};
310
311
struct JSClass {
312
    uint32_t class_id; /* 0 means free entry */
313
    JSAtom class_name;
314
    JSClassFinalizer *finalizer;
315
    JSClassGCMark *gc_mark;
316
    JSClassCall *call;
317
    /* pointers for exotic behavior, can be NULL if none are present */
318
    const JSClassExoticMethods *exotic;
319
};
320
321
2.86M
#define JS_MODE_STRICT (1 << 0)
322
214k
#define JS_MODE_STRIP  (1 << 1)
323
4.36M
#define JS_MODE_MATH   (1 << 2)
324
325
typedef struct JSStackFrame {
326
    struct JSStackFrame *prev_frame; /* NULL if first stack frame */
327
    JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */
328
    JSValue *arg_buf; /* arguments */
329
    JSValue *var_buf; /* variables */
330
    struct list_head var_ref_list; /* list of JSVarRef.link */
331
    const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
332
                        instruction after the call */
333
    int arg_count;
334
    int js_mode; /* 0 or JS_MODE_MATH for C functions */
335
    /* only used in generators. Current stack pointer value. NULL if
336
       the function is running. */ 
337
    JSValue *cur_sp;
338
} JSStackFrame;
339
340
typedef enum {
341
    JS_GC_OBJ_TYPE_JS_OBJECT,
342
    JS_GC_OBJ_TYPE_FUNCTION_BYTECODE,
343
    JS_GC_OBJ_TYPE_SHAPE,
344
    JS_GC_OBJ_TYPE_VAR_REF,
345
    JS_GC_OBJ_TYPE_ASYNC_FUNCTION,
346
    JS_GC_OBJ_TYPE_JS_CONTEXT,
347
} JSGCObjectTypeEnum;
348
349
/* header for GC objects. GC objects are C data structures with a
350
   reference count that can reference other GC objects. JS Objects are
351
   a particular type of GC object. */
352
struct JSGCObjectHeader {
353
    int ref_count; /* must come first, 32-bit */
354
    JSGCObjectTypeEnum gc_obj_type : 4;
355
    uint8_t mark : 4; /* used by the GC */
356
    uint8_t dummy1; /* not used by the GC */
357
    uint16_t dummy2; /* not used by the GC */
358
    struct list_head link;
359
};
360
361
typedef struct JSVarRef {
362
    union {
363
        JSGCObjectHeader header; /* must come first */
364
        struct {
365
            int __gc_ref_count; /* corresponds to header.ref_count */
366
            uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
367
368
            /* 0 : the JSVarRef is on the stack. header.link is an element
369
               of JSStackFrame.var_ref_list.
370
               1 : the JSVarRef is detached. header.link has the normal meanning 
371
            */
372
            uint8_t is_detached : 1; 
373
            uint8_t is_arg : 1;
374
            uint16_t var_idx; /* index of the corresponding function variable on
375
                                 the stack */
376
        };
377
    };
378
    JSValue *pvalue; /* pointer to the value, either on the stack or
379
                        to 'value' */
380
    JSValue value; /* used when the variable is no longer on the stack */
381
} JSVarRef;
382
383
#ifdef CONFIG_BIGNUM
384
typedef struct JSFloatEnv {
385
    limb_t prec;
386
    bf_flags_t flags;
387
    unsigned int status;
388
} JSFloatEnv;
389
390
/* the same structure is used for big integers and big floats. Big
391
   integers are never infinite or NaNs */
392
typedef struct JSBigFloat {
393
    JSRefCountHeader header; /* must come first, 32-bit */
394
    bf_t num;
395
} JSBigFloat;
396
397
typedef struct JSBigDecimal {
398
    JSRefCountHeader header; /* must come first, 32-bit */
399
    bfdec_t num;
400
} JSBigDecimal;
401
#endif
402
403
typedef enum {
404
    JS_AUTOINIT_ID_PROTOTYPE,
405
    JS_AUTOINIT_ID_MODULE_NS,
406
    JS_AUTOINIT_ID_PROP,
407
} JSAutoInitIDEnum;
408
409
/* must be large enough to have a negligible runtime cost and small
410
   enough to call the interrupt callback often. */
411
1.36k
#define JS_INTERRUPT_COUNTER_INIT 10000
412
413
struct JSContext {
414
    JSGCObjectHeader header; /* must come first */
415
    JSRuntime *rt;
416
    struct list_head link;
417
418
    uint16_t binary_object_count;
419
    int binary_object_size;
420
421
    JSShape *array_shape;   /* initial shape for Array objects */
422
423
    JSValue *class_proto;
424
    JSValue function_proto;
425
    JSValue function_ctor;
426
    JSValue array_ctor;
427
    JSValue regexp_ctor;
428
    JSValue promise_ctor;
429
    JSValue native_error_proto[JS_NATIVE_ERROR_COUNT];
430
    JSValue iterator_proto;
431
    JSValue async_iterator_proto;
432
    JSValue array_proto_values;
433
    JSValue throw_type_error;
434
    JSValue eval_obj;
435
436
    JSValue global_obj; /* global object */
437
    JSValue global_var_obj; /* contains the global let/const definitions */
438
439
    uint64_t random_state;
440
#ifdef CONFIG_BIGNUM
441
    bf_context_t *bf_ctx;   /* points to rt->bf_ctx, shared by all contexts */
442
    JSFloatEnv fp_env; /* global FP environment */
443
    BOOL bignum_ext : 8; /* enable math mode */
444
    BOOL allow_operator_overloading : 8;
445
#endif
446
    /* when the counter reaches zero, JSRutime.interrupt_handler is called */
447
    int interrupt_counter;
448
    BOOL is_error_property_enabled;
449
450
    struct list_head loaded_modules; /* list of JSModuleDef.link */
451
452
    /* if NULL, RegExp compilation is not supported */
453
    JSValue (*compile_regexp)(JSContext *ctx, JSValueConst pattern,
454
                              JSValueConst flags);
455
    /* if NULL, eval is not supported */
456
    JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj,
457
                             const char *input, size_t input_len,
458
                             const char *filename, int flags, int scope_idx);
459
    void *user_opaque;
460
};
461
462
typedef union JSFloat64Union {
463
    double d;
464
    uint64_t u64;
465
    uint32_t u32[2];
466
} JSFloat64Union;
467
468
enum {
469
    JS_ATOM_TYPE_STRING = 1,
470
    JS_ATOM_TYPE_GLOBAL_SYMBOL,
471
    JS_ATOM_TYPE_SYMBOL,
472
    JS_ATOM_TYPE_PRIVATE,
473
};
474
475
enum {
476
    JS_ATOM_HASH_SYMBOL,
477
    JS_ATOM_HASH_PRIVATE,
478
};
479
480
typedef enum {
481
    JS_ATOM_KIND_STRING,
482
    JS_ATOM_KIND_SYMBOL,
483
    JS_ATOM_KIND_PRIVATE,
484
} JSAtomKindEnum;
485
486
1.75M
#define JS_ATOM_HASH_MASK  ((1 << 30) - 1)
487
488
struct JSString {
489
    JSRefCountHeader header; /* must come first, 32-bit */
490
    uint32_t len : 31;
491
    uint8_t is_wide_char : 1; /* 0 = 8 bits, 1 = 16 bits characters */
492
    /* for JS_ATOM_TYPE_SYMBOL: hash = 0, atom_type = 3,
493
       for JS_ATOM_TYPE_PRIVATE: hash = 1, atom_type = 3
494
       XXX: could change encoding to have one more bit in hash */
495
    uint32_t hash : 30;
496
    uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */
497
    uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */
498
#ifdef DUMP_LEAKS
499
    struct list_head link; /* string list */
500
#endif
501
    union {
502
        uint8_t str8[0]; /* 8 bit strings will get an extra null terminator */
503
        uint16_t str16[0];
504
    } u;
505
};
506
507
typedef struct JSClosureVar {
508
    uint8_t is_local : 1;
509
    uint8_t is_arg : 1;
510
    uint8_t is_const : 1;
511
    uint8_t is_lexical : 1;
512
    uint8_t var_kind : 4; /* see JSVarKindEnum */
513
    /* 8 bits available */
514
    uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the
515
                    parent function. otherwise: index to a closure
516
                    variable of the parent function */
517
    JSAtom var_name;
518
} JSClosureVar;
519
520
3.08k
#define ARG_SCOPE_INDEX 1
521
732k
#define ARG_SCOPE_END (-2)
522
523
typedef struct JSVarScope {
524
    int parent;  /* index into fd->scopes of the enclosing scope */
525
    int first;   /* index into fd->vars of the last variable in this scope */
526
} JSVarScope;
527
528
typedef enum {
529
    /* XXX: add more variable kinds here instead of using bit fields */
530
    JS_VAR_NORMAL,
531
    JS_VAR_FUNCTION_DECL, /* lexical var with function declaration */
532
    JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator
533
                                 function declaration */
534
    JS_VAR_CATCH,
535
    JS_VAR_FUNCTION_NAME, /* function expression name */
536
    JS_VAR_PRIVATE_FIELD,
537
    JS_VAR_PRIVATE_METHOD,
538
    JS_VAR_PRIVATE_GETTER,
539
    JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */
540
    JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */
541
} JSVarKindEnum;
542
543
/* XXX: could use a different structure in bytecode functions to save
544
   memory */
545
typedef struct JSVarDef {
546
    JSAtom var_name;
547
    /* index into fd->scopes of this variable lexical scope */
548
    int scope_level;
549
    /* during compilation: 
550
        - if scope_level = 0: scope in which the variable is defined
551
        - if scope_level != 0: index into fd->vars of the next
552
          variable in the same or enclosing lexical scope
553
       in a bytecode function:
554
       index into fd->vars of the next
555
       variable in the same or enclosing lexical scope
556
    */
557
    int scope_next;    
558
    uint8_t is_const : 1;
559
    uint8_t is_lexical : 1;
560
    uint8_t is_captured : 1;
561
    uint8_t var_kind : 4; /* see JSVarKindEnum */
562
    /* only used during compilation: function pool index for lexical
563
       variables with var_kind =
564
       JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of
565
       the definition of the 'var' variables (they have scope_level =
566
       0) */
567
    int func_pool_idx : 24; /* only used during compilation : index in
568
                               the constant pool for hoisted function
569
                               definition */
570
} JSVarDef;
571
572
/* for the encoding of the pc2line table */
573
413k
#define PC2LINE_BASE     (-1)
574
413k
#define PC2LINE_RANGE    5
575
179k
#define PC2LINE_OP_FIRST 1
576
83.3k
#define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE)
577
578
typedef enum JSFunctionKindEnum {
579
    JS_FUNC_NORMAL = 0,
580
    JS_FUNC_GENERATOR = (1 << 0),
581
    JS_FUNC_ASYNC = (1 << 1),
582
    JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC),
583
} JSFunctionKindEnum;
584
585
typedef struct JSFunctionBytecode {
586
    JSGCObjectHeader header; /* must come first */
587
    uint8_t js_mode;
588
    uint8_t has_prototype : 1; /* true if a prototype field is necessary */
589
    uint8_t has_simple_parameter_list : 1;
590
    uint8_t is_derived_class_constructor : 1;
591
    /* true if home_object needs to be initialized */
592
    uint8_t need_home_object : 1;
593
    uint8_t func_kind : 2;
594
    uint8_t new_target_allowed : 1;
595
    uint8_t super_call_allowed : 1;
596
    uint8_t super_allowed : 1;
597
    uint8_t arguments_allowed : 1;
598
    uint8_t has_debug : 1;
599
    uint8_t backtrace_barrier : 1; /* stop backtrace on this function */
600
    uint8_t read_only_bytecode : 1;
601
    /* XXX: 4 bits available */
602
    uint8_t *byte_code_buf; /* (self pointer) */
603
    int byte_code_len;
604
    JSAtom func_name;
605
    JSVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */
606
    JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */
607
    uint16_t arg_count;
608
    uint16_t var_count;
609
    uint16_t defined_arg_count; /* for length function property */
610
    uint16_t stack_size; /* maximum stack size */
611
    JSContext *realm; /* function realm */
612
    JSValue *cpool; /* constant pool (self pointer) */
613
    int cpool_count;
614
    int closure_var_count;
615
    struct {
616
        /* debug info, move to separate structure to save memory? */
617
        JSAtom filename;
618
        int line_num;
619
        int source_len;
620
        int pc2line_len;
621
        uint8_t *pc2line_buf;
622
        char *source;
623
    } debug;
624
} JSFunctionBytecode;
625
626
typedef struct JSBoundFunction {
627
    JSValue func_obj;
628
    JSValue this_val;
629
    int argc;
630
    JSValue argv[0];
631
} JSBoundFunction;
632
633
typedef enum JSIteratorKindEnum {
634
    JS_ITERATOR_KIND_KEY,
635
    JS_ITERATOR_KIND_VALUE,
636
    JS_ITERATOR_KIND_KEY_AND_VALUE,
637
} JSIteratorKindEnum;
638
639
typedef struct JSForInIterator {
640
    JSValue obj;
641
    BOOL is_array;
642
    uint32_t array_length;
643
    uint32_t idx;
644
} JSForInIterator;
645
646
typedef struct JSRegExp {
647
    JSString *pattern;
648
    JSString *bytecode; /* also contains the flags */
649
} JSRegExp;
650
651
typedef struct JSProxyData {
652
    JSValue target;
653
    JSValue handler;
654
    uint8_t is_func;
655
    uint8_t is_revoked;
656
} JSProxyData;
657
658
typedef struct JSArrayBuffer {
659
    int byte_length; /* 0 if detached */
660
    uint8_t detached;
661
    uint8_t shared; /* if shared, the array buffer cannot be detached */
662
    uint8_t *data; /* NULL if detached */
663
    struct list_head array_list;
664
    void *opaque;
665
    JSFreeArrayBufferDataFunc *free_func;
666
} JSArrayBuffer;
667
668
typedef struct JSTypedArray {
669
    struct list_head link; /* link to arraybuffer */
670
    JSObject *obj; /* back pointer to the TypedArray/DataView object */
671
    JSObject *buffer; /* based array buffer */
672
    uint32_t offset; /* offset in the array buffer */
673
    uint32_t length; /* length in the array buffer */
674
} JSTypedArray;
675
676
typedef struct JSAsyncFunctionState {
677
    JSValue this_val; /* 'this' generator argument */
678
    int argc; /* number of function arguments */
679
    BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */
680
    JSStackFrame frame;
681
} JSAsyncFunctionState;
682
683
/* XXX: could use an object instead to avoid the
684
   JS_TAG_ASYNC_FUNCTION tag for the GC */
685
typedef struct JSAsyncFunctionData {
686
    JSGCObjectHeader header; /* must come first */
687
    JSValue resolving_funcs[2];
688
    BOOL is_active; /* true if the async function state is valid */
689
    JSAsyncFunctionState func_state;
690
} JSAsyncFunctionData;
691
692
typedef enum {
693
   /* binary operators */
694
   JS_OVOP_ADD,
695
   JS_OVOP_SUB,
696
   JS_OVOP_MUL,
697
   JS_OVOP_DIV,
698
   JS_OVOP_MOD,
699
   JS_OVOP_POW,
700
   JS_OVOP_OR,
701
   JS_OVOP_AND,
702
   JS_OVOP_XOR,
703
   JS_OVOP_SHL,
704
   JS_OVOP_SAR,
705
   JS_OVOP_SHR,
706
   JS_OVOP_EQ,
707
   JS_OVOP_LESS,
708
709
   JS_OVOP_BINARY_COUNT,
710
   /* unary operators */
711
   JS_OVOP_POS = JS_OVOP_BINARY_COUNT,
712
   JS_OVOP_NEG,
713
   JS_OVOP_INC,
714
   JS_OVOP_DEC,
715
   JS_OVOP_NOT,
716
717
   JS_OVOP_COUNT,
718
} JSOverloadableOperatorEnum;
719
720
typedef struct {
721
    uint32_t operator_index;
722
    JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */
723
} JSBinaryOperatorDefEntry;
724
725
typedef struct {
726
    int count;
727
    JSBinaryOperatorDefEntry *tab;
728
} JSBinaryOperatorDef;
729
730
typedef struct {
731
    uint32_t operator_counter;
732
    BOOL is_primitive; /* OperatorSet for a primitive type */
733
    /* NULL if no operator is defined */
734
    JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */
735
    JSBinaryOperatorDef left;
736
    JSBinaryOperatorDef right;
737
} JSOperatorSetData;
738
739
typedef struct JSReqModuleEntry {
740
    JSAtom module_name;
741
    JSModuleDef *module; /* used using resolution */
742
} JSReqModuleEntry;
743
744
typedef enum JSExportTypeEnum {
745
    JS_EXPORT_TYPE_LOCAL,
746
    JS_EXPORT_TYPE_INDIRECT,
747
} JSExportTypeEnum;
748
749
typedef struct JSExportEntry {
750
    union {
751
        struct {
752
            int var_idx; /* closure variable index */
753
            JSVarRef *var_ref; /* if != NULL, reference to the variable */
754
        } local; /* for local export */
755
        int req_module_idx; /* module for indirect export */
756
    } u;
757
    JSExportTypeEnum export_type;
758
    JSAtom local_name; /* '*' if export ns from. not used for local
759
                          export after compilation */
760
    JSAtom export_name; /* exported variable name */
761
} JSExportEntry;
762
763
typedef struct JSStarExportEntry {
764
    int req_module_idx; /* in req_module_entries */
765
} JSStarExportEntry;
766
767
typedef struct JSImportEntry {
768
    int var_idx; /* closure variable index */
769
    JSAtom import_name;
770
    int req_module_idx; /* in req_module_entries */
771
} JSImportEntry;
772
773
struct JSModuleDef {
774
    JSRefCountHeader header; /* must come first, 32-bit */
775
    JSAtom module_name;
776
    struct list_head link;
777
778
    JSReqModuleEntry *req_module_entries;
779
    int req_module_entries_count;
780
    int req_module_entries_size;
781
782
    JSExportEntry *export_entries;
783
    int export_entries_count;
784
    int export_entries_size;
785
786
    JSStarExportEntry *star_export_entries;
787
    int star_export_entries_count;
788
    int star_export_entries_size;
789
790
    JSImportEntry *import_entries;
791
    int import_entries_count;
792
    int import_entries_size;
793
794
    JSValue module_ns;
795
    JSValue func_obj; /* only used for JS modules */
796
    JSModuleInitFunc *init_func; /* only used for C modules */
797
    BOOL resolved : 8;
798
    BOOL func_created : 8;
799
    BOOL instantiated : 8;
800
    BOOL evaluated : 8;
801
    BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */
802
    /* true if evaluation yielded an exception. It is saved in
803
       eval_exception */
804
    BOOL eval_has_exception : 8; 
805
    JSValue eval_exception;
806
    JSValue meta_obj; /* for import.meta */
807
};
808
809
typedef struct JSJobEntry {
810
    struct list_head link;
811
    JSContext *ctx;
812
    JSJobFunc *job_func;
813
    int argc;
814
    JSValue argv[0];
815
} JSJobEntry;
816
817
typedef struct JSProperty {
818
    union {
819
        JSValue value;      /* JS_PROP_NORMAL */
820
        struct {            /* JS_PROP_GETSET */
821
            JSObject *getter; /* NULL if undefined */
822
            JSObject *setter; /* NULL if undefined */
823
        } getset;
824
        JSVarRef *var_ref;  /* JS_PROP_VARREF */
825
        struct {            /* JS_PROP_AUTOINIT */
826
            /* in order to use only 2 pointers, we compress the realm
827
               and the init function pointer */
828
            uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x)
829
                                       in the 2 low bits */
830
            void *opaque;
831
        } init;
832
    } u;
833
} JSProperty;
834
835
4.99M
#define JS_PROP_INITIAL_SIZE 2
836
4.99M
#define JS_PROP_INITIAL_HASH_SIZE 4 /* must be a power of two */
837
#define JS_ARRAY_INITIAL_SIZE 2
838
839
typedef struct JSShapeProperty {
840
    uint32_t hash_next : 26; /* 0 if last in list */
841
    uint32_t flags : 6;   /* JS_PROP_XXX */
842
    JSAtom atom; /* JS_ATOM_NULL = free property entry */
843
} JSShapeProperty;
844
845
struct JSShape {
846
    /* hash table of size hash_mask + 1 before the start of the
847
       structure (see prop_hash_end()). */
848
    JSGCObjectHeader header;
849
    /* true if the shape is inserted in the shape hash table. If not,
850
       JSShape.hash is not valid */
851
    uint8_t is_hashed;
852
    /* If true, the shape may have small array index properties 'n' with 0
853
       <= n <= 2^31-1. If false, the shape is guaranteed not to have
854
       small array index properties */
855
    uint8_t has_small_array_index;
856
    uint32_t hash; /* current hash value */
857
    uint32_t prop_hash_mask;
858
    int prop_size; /* allocated properties */
859
    int prop_count; /* include deleted properties */
860
    int deleted_prop_count;
861
    JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */
862
    JSObject *proto;
863
    JSShapeProperty prop[0]; /* prop_size elements */
864
};
865
866
struct JSObject {
867
    union {
868
        JSGCObjectHeader header;
869
        struct {
870
            int __gc_ref_count; /* corresponds to header.ref_count */
871
            uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
872
            
873
            uint8_t extensible : 1;
874
            uint8_t free_mark : 1; /* only used when freeing objects with cycles */
875
            uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */
876
            uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */
877
            uint8_t is_constructor : 1; /* TRUE if object is a constructor function */
878
            uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */
879
            uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */
880
            uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */
881
            uint16_t class_id; /* see JS_CLASS_x */
882
        };
883
    };
884
    /* byte offsets: 16/24 */
885
    JSShape *shape; /* prototype and property names + flag */
886
    JSProperty *prop; /* array of properties */
887
    /* byte offsets: 24/40 */
888
    struct JSMapRecord *first_weak_ref; /* XXX: use a bit and an external hash table? */
889
    /* byte offsets: 28/48 */
890
    union {
891
        void *opaque;
892
        struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */
893
        struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */
894
        struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */
895
        struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */
896
        struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */
897
#ifdef CONFIG_BIGNUM
898
        struct JSFloatEnv *float_env; /* JS_CLASS_FLOAT_ENV */
899
        struct JSOperatorSetData *operator_set; /* JS_CLASS_OPERATOR_SET */
900
#endif
901
        struct JSMapState *map_state;   /* JS_CLASS_MAP..JS_CLASS_WEAKSET */
902
        struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */
903
        struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */
904
        struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */
905
        struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */
906
        struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */
907
        struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */
908
        struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */
909
        struct JSAsyncFunctionData *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */
910
        struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
911
        struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */
912
        struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */
913
            /* also used by JS_CLASS_GENERATOR_FUNCTION, JS_CLASS_ASYNC_FUNCTION and JS_CLASS_ASYNC_GENERATOR_FUNCTION */
914
            struct JSFunctionBytecode *function_bytecode;
915
            JSVarRef **var_refs;
916
            JSObject *home_object; /* for 'super' access */
917
        } func;
918
        struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */
919
            JSContext *realm;
920
            JSCFunctionType c_function;
921
            uint8_t length;
922
            uint8_t cproto;
923
            int16_t magic;
924
        } cfunc;
925
        /* array part for fast arrays and typed arrays */
926
        struct { /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
927
            union {
928
                uint32_t size;          /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */
929
                struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
930
            } u1;
931
            union {
932
                JSValue *values;        /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */ 
933
                void *ptr;              /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
934
                int8_t *int8_ptr;       /* JS_CLASS_INT8_ARRAY */
935
                uint8_t *uint8_ptr;     /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */
936
                int16_t *int16_ptr;     /* JS_CLASS_INT16_ARRAY */
937
                uint16_t *uint16_ptr;   /* JS_CLASS_UINT16_ARRAY */
938
                int32_t *int32_ptr;     /* JS_CLASS_INT32_ARRAY */
939
                uint32_t *uint32_ptr;   /* JS_CLASS_UINT32_ARRAY */
940
                int64_t *int64_ptr;     /* JS_CLASS_INT64_ARRAY */
941
                uint64_t *uint64_ptr;   /* JS_CLASS_UINT64_ARRAY */
942
                float *float_ptr;       /* JS_CLASS_FLOAT32_ARRAY */
943
                double *double_ptr;     /* JS_CLASS_FLOAT64_ARRAY */
944
            } u;
945
            uint32_t count; /* <= 2^31-1. 0 for a detached typed array */
946
        } array;    /* 12/20 bytes */
947
        JSRegExp regexp;    /* JS_CLASS_REGEXP: 8/16 bytes */
948
        JSValue object_data;    /* for JS_SetObjectData(): 8/16/16 bytes */
949
    } u;
950
    /* byte sizes: 40/48/72 */
951
};
952
enum {
953
    __JS_ATOM_NULL = JS_ATOM_NULL,
954
#define DEF(name, str) JS_ATOM_ ## name,
955
#include "quickjs-atom.h"
956
#undef DEF
957
    JS_ATOM_END,
958
};
959
2.86M
#define JS_ATOM_LAST_KEYWORD JS_ATOM_super
960
2.67M
#define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield
961
962
static const char js_atom_init[] =
963
#define DEF(name, str) str "\0"
964
#include "quickjs-atom.h"
965
#undef DEF
966
;
967
968
typedef enum OPCodeFormat {
969
#define FMT(f) OP_FMT_ ## f,
970
#define DEF(id, size, n_pop, n_push, f)
971
#include "quickjs-opcode.h"
972
#undef DEF
973
#undef FMT
974
} OPCodeFormat;
975
976
enum OPCodeEnum {
977
#define FMT(f)
978
#define DEF(id, size, n_pop, n_push, f) OP_ ## id,
979
#define def(id, size, n_pop, n_push, f)
980
#include "quickjs-opcode.h"
981
#undef def
982
#undef DEF
983
#undef FMT
984
    OP_COUNT, /* excluding temporary opcodes */
985
    /* temporary opcodes : overlap with the short opcodes */
986
    OP_TEMP_START = OP_nop + 1,
987
    OP___dummy = OP_TEMP_START - 1,
988
#define FMT(f)
989
#define DEF(id, size, n_pop, n_push, f)
990
#define def(id, size, n_pop, n_push, f) OP_ ## id,
991
#include "quickjs-opcode.h"
992
#undef def
993
#undef DEF
994
#undef FMT
995
    OP_TEMP_END,
996
};
997
998
static int JS_InitAtoms(JSRuntime *rt);
999
static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
1000
                               int atom_type);
1001
static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p);
1002
static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b);
1003
static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
1004
                                  JSValueConst this_obj,
1005
                                  int argc, JSValueConst *argv, int flags);
1006
static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
1007
                                      JSValueConst this_obj,
1008
                                      int argc, JSValueConst *argv, int flags);
1009
static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
1010
                               JSValueConst this_obj, JSValueConst new_target,
1011
                               int argc, JSValue *argv, int flags);
1012
static JSValue JS_CallConstructorInternal(JSContext *ctx,
1013
                                          JSValueConst func_obj,
1014
                                          JSValueConst new_target,
1015
                                          int argc, JSValue *argv, int flags);
1016
static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
1017
                           int argc, JSValueConst *argv);
1018
static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
1019
                             int argc, JSValueConst *argv);
1020
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
1021
                                            JSValue val, BOOL is_array_ctor);
1022
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
1023
                             JSValueConst val, int flags, int scope_idx);
1024
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
1025
static __maybe_unused void JS_DumpAtoms(JSRuntime *rt);
1026
static __maybe_unused void JS_DumpString(JSRuntime *rt,
1027
                                                  const JSString *p);
1028
static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
1029
static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
1030
static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);
1031
static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
1032
                                                      JSValueConst val);
1033
static __maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val);
1034
static __maybe_unused void JS_PrintValue(JSContext *ctx,
1035
                                                  const char *str,
1036
                                                  JSValueConst val);
1037
static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
1038
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
1039
                                 int argc, JSValueConst *argv, int magic);
1040
static void js_array_finalizer(JSRuntime *rt, JSValue val);
1041
static void js_array_mark(JSRuntime *rt, JSValueConst val,
1042
                          JS_MarkFunc *mark_func);
1043
static void js_object_data_finalizer(JSRuntime *rt, JSValue val);
1044
static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
1045
                                JS_MarkFunc *mark_func);
1046
static void js_c_function_finalizer(JSRuntime *rt, JSValue val);
1047
static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
1048
                               JS_MarkFunc *mark_func);
1049
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val);
1050
static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
1051
                                JS_MarkFunc *mark_func);
1052
static void js_bound_function_finalizer(JSRuntime *rt, JSValue val);
1053
static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
1054
                                JS_MarkFunc *mark_func);
1055
static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val);
1056
static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
1057
                                JS_MarkFunc *mark_func);
1058
static void js_regexp_finalizer(JSRuntime *rt, JSValue val);
1059
static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val);
1060
static void js_typed_array_finalizer(JSRuntime *rt, JSValue val);
1061
static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
1062
                                JS_MarkFunc *mark_func);
1063
static void js_proxy_finalizer(JSRuntime *rt, JSValue val);
1064
static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
1065
                                JS_MarkFunc *mark_func);
1066
static void js_map_finalizer(JSRuntime *rt, JSValue val);
1067
static void js_map_mark(JSRuntime *rt, JSValueConst val,
1068
                                JS_MarkFunc *mark_func);
1069
static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val);
1070
static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
1071
                                JS_MarkFunc *mark_func);
1072
static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val);
1073
static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
1074
                                JS_MarkFunc *mark_func);
1075
static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val);
1076
static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
1077
                                JS_MarkFunc *mark_func);
1078
static void js_generator_finalizer(JSRuntime *rt, JSValue obj);
1079
static void js_generator_mark(JSRuntime *rt, JSValueConst val,
1080
                                JS_MarkFunc *mark_func);
1081
static void js_promise_finalizer(JSRuntime *rt, JSValue val);
1082
static void js_promise_mark(JSRuntime *rt, JSValueConst val,
1083
                                JS_MarkFunc *mark_func);
1084
static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val);
1085
static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
1086
                                JS_MarkFunc *mark_func);
1087
#ifdef CONFIG_BIGNUM
1088
static void js_operator_set_finalizer(JSRuntime *rt, JSValue val);
1089
static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
1090
                                 JS_MarkFunc *mark_func);
1091
#endif
1092
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
1093
static int JS_ToBoolFree(JSContext *ctx, JSValue val);
1094
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
1095
static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val);
1096
static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val);
1097
static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
1098
                                 JSValueConst flags);
1099
static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
1100
                                              JSValue pattern, JSValue bc);
1101
static void gc_decref(JSRuntime *rt);
1102
static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
1103
                        const JSClassDef *class_def, JSAtom name);
1104
1105
typedef enum JSStrictEqModeEnum {
1106
    JS_EQ_STRICT,
1107
    JS_EQ_SAME_VALUE,
1108
    JS_EQ_SAME_VALUE_ZERO,
1109
} JSStrictEqModeEnum;
1110
1111
static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
1112
                          JSStrictEqModeEnum eq_mode);
1113
static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2);
1114
static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2);
1115
static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
1116
static JSValue JS_ToObject(JSContext *ctx, JSValueConst val);
1117
static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val);
1118
static JSProperty *add_property(JSContext *ctx,
1119
                                JSObject *p, JSAtom prop, int prop_flags);
1120
#ifdef CONFIG_BIGNUM
1121
static void js_float_env_finalizer(JSRuntime *rt, JSValue val);
1122
static JSValue JS_NewBigFloat(JSContext *ctx);
1123
static inline bf_t *JS_GetBigFloat(JSValueConst val)
1124
0
{
1125
0
    JSBigFloat *p = JS_VALUE_GET_PTR(val);
1126
0
    return &p->num;
1127
0
}
1128
static JSValue JS_NewBigDecimal(JSContext *ctx);
1129
static inline bfdec_t *JS_GetBigDecimal(JSValueConst val)
1130
0
{
1131
0
    JSBigDecimal *p = JS_VALUE_GET_PTR(val);
1132
0
    return &p->num;
1133
0
}
1134
static JSValue JS_NewBigInt(JSContext *ctx);
1135
static inline bf_t *JS_GetBigInt(JSValueConst val)
1136
24.4k
{
1137
24.4k
    JSBigFloat *p = JS_VALUE_GET_PTR(val);
1138
24.4k
    return &p->num;
1139
24.4k
}
1140
static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
1141
                                 BOOL convert_to_safe_integer);
1142
static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val);
1143
static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
1144
static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);
1145
static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);
1146
static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val);
1147
static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
1148
                                   BOOL allow_null_or_undefined);
1149
static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val);
1150
#endif
1151
JSValue JS_ThrowOutOfMemory(JSContext *ctx);
1152
static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);
1153
static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj);
1154
static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
1155
                                   JSValueConst proto_val, BOOL throw_flag);
1156
static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj);
1157
static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj);
1158
static int js_proxy_isArray(JSContext *ctx, JSValueConst obj);
1159
static int JS_CreateProperty(JSContext *ctx, JSObject *p,
1160
                             JSAtom prop, JSValueConst val,
1161
                             JSValueConst getter, JSValueConst setter,
1162
                             int flags);
1163
static int js_string_memcmp(const JSString *p1, const JSString *p2, int len);
1164
static void reset_weak_ref(JSRuntime *rt, JSObject *p);
1165
static JSValue js_array_buffer_constructor3(JSContext *ctx,
1166
                                            JSValueConst new_target,
1167
                                            uint64_t len, JSClassID class_id,
1168
                                            uint8_t *buf,
1169
                                            JSFreeArrayBufferDataFunc *free_func,
1170
                                            void *opaque, BOOL alloc_flag);
1171
static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj);
1172
static JSValue js_typed_array_constructor(JSContext *ctx,
1173
                                          JSValueConst this_val,
1174
                                          int argc, JSValueConst *argv,
1175
                                          int classid);
1176
static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p);
1177
static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p);
1178
static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx);
1179
static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,
1180
                             BOOL is_arg);
1181
static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
1182
                                          JSValueConst this_obj,
1183
                                          int argc, JSValueConst *argv,
1184
                                          int flags);
1185
static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val);
1186
static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
1187
                                           JS_MarkFunc *mark_func);
1188
static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
1189
                               const char *input, size_t input_len,
1190
                               const char *filename, int flags, int scope_idx);
1191
static void js_free_module_def(JSContext *ctx, JSModuleDef *m);
1192
static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
1193
                               JS_MarkFunc *mark_func);
1194
static JSValue js_import_meta(JSContext *ctx);
1195
static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier);
1196
static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);
1197
static JSValue js_new_promise_capability(JSContext *ctx,
1198
                                         JSValue *resolving_funcs,
1199
                                         JSValueConst ctor);
1200
static __exception int perform_promise_then(JSContext *ctx,
1201
                                            JSValueConst promise,
1202
                                            JSValueConst *resolve_reject,
1203
                                            JSValueConst *cap_resolving_funcs);
1204
static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
1205
                                  int argc, JSValueConst *argv, int magic);
1206
static int js_string_compare(JSContext *ctx,
1207
                             const JSString *p1, const JSString *p2);
1208
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val);
1209
static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
1210
                               JSValue prop, JSValue val, int flags);
1211
static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val);
1212
static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val);
1213
static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val);
1214
static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
1215
                                     JSObject *p, JSAtom prop);
1216
static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc);
1217
static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
1218
                            JS_MarkFunc *mark_func);
1219
static void JS_AddIntrinsicBasicObjects(JSContext *ctx);
1220
static void js_free_shape(JSRuntime *rt, JSShape *sh);
1221
static void js_free_shape_null(JSRuntime *rt, JSShape *sh);
1222
static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
1223
                                   JSShapeProperty **pprs);
1224
static int init_shape_hash(JSRuntime *rt);
1225
static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
1226
                                       JSValueConst obj);
1227
static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
1228
                                       JSValueConst obj);
1229
static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len);
1230
static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
1231
                               JSValueConst array_arg);
1232
static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
1233
                              JSValue **arrpp, uint32_t *countp);
1234
static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
1235
                                              JSValueConst sync_iter);
1236
static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val);
1237
static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
1238
                                    JS_MarkFunc *mark_func);
1239
static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
1240
                                       JSValueConst this_val,
1241
                                       int argc, JSValueConst *argv, int flags);
1242
static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val);
1243
static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
1244
                          JSGCObjectTypeEnum type);
1245
static void remove_gc_object(JSGCObjectHeader *h);
1246
static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s);
1247
static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
1248
static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
1249
                                 void *opaque);
1250
static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
1251
                                               JSAtom atom, void *opaque);
1252
void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag);
1253
1254
static const JSClassExoticMethods js_arguments_exotic_methods;
1255
static const JSClassExoticMethods js_string_exotic_methods;
1256
static const JSClassExoticMethods js_proxy_exotic_methods;
1257
static const JSClassExoticMethods js_module_ns_exotic_methods;
1258
static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;
1259
1260
static void js_trigger_gc(JSRuntime *rt, size_t size)
1261
8.38M
{
1262
8.38M
    BOOL force_gc;
1263
#ifdef FORCE_GC_AT_MALLOC
1264
    force_gc = TRUE;
1265
#else
1266
8.38M
    force_gc = ((rt->malloc_state.malloc_size + size) >
1267
8.38M
                rt->malloc_gc_threshold);
1268
8.38M
#endif
1269
8.38M
    if (force_gc) {
1270
#ifdef DUMP_GC
1271
        printf("GC: size=%" PRIu64 "\n",
1272
               (uint64_t)rt->malloc_state.malloc_size);
1273
#endif
1274
91
        JS_RunGC(rt);
1275
91
        rt->malloc_gc_threshold = rt->malloc_state.malloc_size +
1276
91
            (rt->malloc_state.malloc_size >> 1);
1277
91
    }
1278
8.38M
}
1279
1280
static size_t js_malloc_usable_size_unknown(const void *ptr)
1281
0
{
1282
0
    return 0;
1283
0
}
1284
1285
void *js_malloc_rt(JSRuntime *rt, size_t size)
1286
41.8M
{
1287
41.8M
    return rt->mf.js_malloc(&rt->malloc_state, size);
1288
41.8M
}
1289
1290
void js_free_rt(JSRuntime *rt, void *ptr)
1291
42.2M
{
1292
42.2M
    rt->mf.js_free(&rt->malloc_state, ptr);
1293
42.2M
}
1294
1295
void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size)
1296
8.81M
{
1297
8.81M
    return rt->mf.js_realloc(&rt->malloc_state, ptr, size);
1298
8.81M
}
1299
1300
size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr)
1301
2.44M
{
1302
2.44M
    return rt->mf.js_malloc_usable_size(ptr);
1303
2.44M
}
1304
1305
void *js_mallocz_rt(JSRuntime *rt, size_t size)
1306
1.70M
{
1307
1.70M
    void *ptr;
1308
1.70M
    ptr = js_malloc_rt(rt, size);
1309
1.70M
    if (!ptr)
1310
1.11k
        return NULL;
1311
1.70M
    return memset(ptr, 0, size);
1312
1.70M
}
1313
1314
#ifdef CONFIG_BIGNUM
1315
/* called by libbf */
1316
static void *js_bf_realloc(void *opaque, void *ptr, size_t size)
1317
560k
{
1318
560k
    JSRuntime *rt = opaque;
1319
560k
    return js_realloc_rt(rt, ptr, size);
1320
560k
}
1321
#endif /* CONFIG_BIGNUM */
1322
1323
/* Throw out of memory in case of error */
1324
void *js_malloc(JSContext *ctx, size_t size)
1325
31.0M
{
1326
31.0M
    void *ptr;
1327
31.0M
    ptr = js_malloc_rt(ctx->rt, size);
1328
31.0M
    if (unlikely(!ptr)) {
1329
102
        JS_ThrowOutOfMemory(ctx);
1330
102
        return NULL;
1331
102
    }
1332
31.0M
    return ptr;
1333
31.0M
}
1334
1335
/* Throw out of memory in case of error */
1336
void *js_mallocz(JSContext *ctx, size_t size)
1337
1.70M
{
1338
1.70M
    void *ptr;
1339
1.70M
    ptr = js_mallocz_rt(ctx->rt, size);
1340
1.70M
    if (unlikely(!ptr)) {
1341
1.11k
        JS_ThrowOutOfMemory(ctx);
1342
1.11k
        return NULL;
1343
1.11k
    }
1344
1.70M
    return ptr;
1345
1.70M
}
1346
1347
void js_free(JSContext *ctx, void *ptr)
1348
5.81M
{
1349
5.81M
    js_free_rt(ctx->rt, ptr);
1350
5.81M
}
1351
1352
/* Throw out of memory in case of error */
1353
void *js_realloc(JSContext *ctx, void *ptr, size_t size)
1354
1.84M
{
1355
1.84M
    void *ret;
1356
1.84M
    ret = js_realloc_rt(ctx->rt, ptr, size);
1357
1.84M
    if (unlikely(!ret && size != 0)) {
1358
39
        JS_ThrowOutOfMemory(ctx);
1359
39
        return NULL;
1360
39
    }
1361
1.84M
    return ret;
1362
1.84M
}
1363
1364
/* store extra allocated size in *pslack if successful */
1365
void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack)
1366
2.32M
{
1367
2.32M
    void *ret;
1368
2.32M
    ret = js_realloc_rt(ctx->rt, ptr, size);
1369
2.32M
    if (unlikely(!ret && size != 0)) {
1370
4
        JS_ThrowOutOfMemory(ctx);
1371
4
        return NULL;
1372
4
    }
1373
2.32M
    if (pslack) {
1374
2.32M
        size_t new_size = js_malloc_usable_size_rt(ctx->rt, ret);
1375
2.32M
        *pslack = (new_size > size) ? new_size - size : 0;
1376
2.32M
    }
1377
2.32M
    return ret;
1378
2.32M
}
1379
1380
size_t js_malloc_usable_size(JSContext *ctx, const void *ptr)
1381
114k
{
1382
114k
    return js_malloc_usable_size_rt(ctx->rt, ptr);
1383
114k
}
1384
1385
/* Throw out of memory exception in case of error */
1386
char *js_strndup(JSContext *ctx, const char *s, size_t n)
1387
149k
{
1388
149k
    char *ptr;
1389
149k
    ptr = js_malloc(ctx, n + 1);
1390
149k
    if (ptr) {
1391
149k
        memcpy(ptr, s, n);
1392
149k
        ptr[n] = '\0';
1393
149k
    }
1394
149k
    return ptr;
1395
149k
}
1396
1397
char *js_strdup(JSContext *ctx, const char *str)
1398
109k
{
1399
109k
    return js_strndup(ctx, str, strlen(str));
1400
109k
}
1401
1402
static no_inline int js_realloc_array(JSContext *ctx, void **parray,
1403
                                      int elem_size, int *psize, int req_size)
1404
197k
{
1405
197k
    int new_size;
1406
197k
    size_t slack;
1407
197k
    void *new_array;
1408
    /* XXX: potential arithmetic overflow */
1409
197k
    new_size = max_int(req_size, *psize * 3 / 2);
1410
197k
    new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack);
1411
197k
    if (!new_array)
1412
3
        return -1;
1413
197k
    new_size += slack / elem_size;
1414
197k
    *psize = new_size;
1415
197k
    *parray = new_array;
1416
197k
    return 0;
1417
197k
}
1418
1419
/* resize the array and update its size if req_size > *psize */
1420
static inline int js_resize_array(JSContext *ctx, void **parray, int elem_size,
1421
                                  int *psize, int req_size)
1422
6.10M
{
1423
6.10M
    if (unlikely(req_size > *psize))
1424
197k
        return js_realloc_array(ctx, parray, elem_size, psize, req_size);
1425
5.91M
    else
1426
5.91M
        return 0;
1427
6.10M
}
1428
1429
static inline void js_dbuf_init(JSContext *ctx, DynBuf *s)
1430
280k
{
1431
280k
    dbuf_init2(s, ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
1432
280k
}
1433
1434
1.69M
static inline int is_digit(int c) {
1435
1.69M
    return c >= '0' && c <= '9';
1436
1.69M
}
1437
1438
typedef struct JSClassShortDef {
1439
    JSAtom class_name;
1440
    JSClassFinalizer *finalizer;
1441
    JSClassGCMark *gc_mark;
1442
} JSClassShortDef;
1443
1444
static JSClassShortDef const js_std_class_def[] = {
1445
    { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_OBJECT */
1446
    { JS_ATOM_Array, js_array_finalizer, js_array_mark },       /* JS_CLASS_ARRAY */
1447
    { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */
1448
    { JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */
1449
    { JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */
1450
    { JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */
1451
    { JS_ATOM_Symbol, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_SYMBOL */
1452
    { JS_ATOM_Arguments, js_array_finalizer, js_array_mark },   /* JS_CLASS_ARGUMENTS */
1453
    { JS_ATOM_Arguments, NULL, NULL },                          /* JS_CLASS_MAPPED_ARGUMENTS */
1454
    { JS_ATOM_Date, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_DATE */
1455
    { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_MODULE_NS */
1456
    { JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark }, /* JS_CLASS_C_FUNCTION */
1457
    { JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */
1458
    { JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */
1459
    { JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */
1460
    { JS_ATOM_GeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_GENERATOR_FUNCTION */
1461
    { JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark },      /* JS_CLASS_FOR_IN_ITERATOR */
1462
    { JS_ATOM_RegExp, js_regexp_finalizer, NULL },                              /* JS_CLASS_REGEXP */
1463
    { JS_ATOM_ArrayBuffer, js_array_buffer_finalizer, NULL },                   /* JS_CLASS_ARRAY_BUFFER */
1464
    { JS_ATOM_SharedArrayBuffer, js_array_buffer_finalizer, NULL },             /* JS_CLASS_SHARED_ARRAY_BUFFER */
1465
    { JS_ATOM_Uint8ClampedArray, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8C_ARRAY */
1466
    { JS_ATOM_Int8Array, js_typed_array_finalizer, js_typed_array_mark },       /* JS_CLASS_INT8_ARRAY */
1467
    { JS_ATOM_Uint8Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_UINT8_ARRAY */
1468
    { JS_ATOM_Int16Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT16_ARRAY */
1469
    { JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT16_ARRAY */
1470
    { JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT32_ARRAY */
1471
    { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT32_ARRAY */
1472
#ifdef CONFIG_BIGNUM
1473
    { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark },   /* JS_CLASS_BIG_INT64_ARRAY */
1474
    { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark },  /* JS_CLASS_BIG_UINT64_ARRAY */
1475
#endif
1476
    { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT32_ARRAY */
1477
    { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT64_ARRAY */
1478
    { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark },        /* JS_CLASS_DATAVIEW */
1479
#ifdef CONFIG_BIGNUM
1480
    { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark },      /* JS_CLASS_BIG_INT */
1481
    { JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark },    /* JS_CLASS_BIG_FLOAT */
1482
    { JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL },      /* JS_CLASS_FLOAT_ENV */
1483
    { JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark },    /* JS_CLASS_BIG_DECIMAL */
1484
    { JS_ATOM_OperatorSet, js_operator_set_finalizer, js_operator_set_mark },    /* JS_CLASS_OPERATOR_SET */
1485
#endif
1486
    { JS_ATOM_Map, js_map_finalizer, js_map_mark },             /* JS_CLASS_MAP */
1487
    { JS_ATOM_Set, js_map_finalizer, js_map_mark },             /* JS_CLASS_SET */
1488
    { JS_ATOM_WeakMap, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKMAP */
1489
    { JS_ATOM_WeakSet, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKSET */
1490
    { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */
1491
    { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */
1492
    { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */
1493
    { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */
1494
    { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */
1495
    { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */
1496
};
1497
1498
static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab,
1499
                            int start, int count)
1500
7
{
1501
7
    JSClassDef cm_s, *cm = &cm_s;
1502
7
    int i, class_id;
1503
1504
168
    for(i = 0; i < count; i++) {
1505
161
        class_id = i + start;
1506
161
        memset(cm, 0, sizeof(*cm));
1507
161
        cm->finalizer = tab[i].finalizer;
1508
161
        cm->gc_mark = tab[i].gc_mark;
1509
161
        if (JS_NewClass1(rt, class_id, cm, tab[i].class_name) < 0)
1510
0
            return -1;
1511
161
    }
1512
7
    return 0;
1513
7
}
1514
1515
#ifdef CONFIG_BIGNUM
1516
static JSValue JS_ThrowUnsupportedOperation(JSContext *ctx)
1517
0
{
1518
0
    return JS_ThrowTypeError(ctx, "unsupported operation");
1519
0
}
1520
1521
static JSValue invalid_to_string(JSContext *ctx, JSValueConst val)
1522
0
{
1523
0
    return JS_ThrowUnsupportedOperation(ctx);
1524
0
}
1525
1526
static JSValue invalid_from_string(JSContext *ctx, const char *buf,
1527
                                   int radix, int flags, slimb_t *pexponent)
1528
78
{
1529
78
    return JS_NAN;
1530
78
}
1531
1532
static int invalid_unary_arith(JSContext *ctx,
1533
                               JSValue *pres, OPCodeEnum op, JSValue op1)
1534
0
{
1535
0
    JS_FreeValue(ctx, op1);
1536
0
    JS_ThrowUnsupportedOperation(ctx);
1537
0
    return -1;
1538
0
}
1539
1540
static int invalid_binary_arith(JSContext *ctx, OPCodeEnum op,
1541
                                JSValue *pres, JSValue op1, JSValue op2)
1542
0
{
1543
0
    JS_FreeValue(ctx, op1);
1544
0
    JS_FreeValue(ctx, op2);
1545
0
    JS_ThrowUnsupportedOperation(ctx);
1546
0
    return -1;
1547
0
}
1548
1549
static JSValue invalid_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
1550
                                            int64_t exponent)
1551
0
{
1552
0
    return JS_ThrowUnsupportedOperation(ctx);
1553
0
}
1554
1555
static int invalid_mul_pow10(JSContext *ctx, JSValue *sp)
1556
0
{
1557
0
    JS_ThrowUnsupportedOperation(ctx);
1558
0
    return -1;
1559
0
}
1560
1561
static void set_dummy_numeric_ops(JSNumericOperations *ops)
1562
9
{
1563
9
    ops->to_string = invalid_to_string;
1564
9
    ops->from_string = invalid_from_string;
1565
9
    ops->unary_arith = invalid_unary_arith;
1566
9
    ops->binary_arith = invalid_binary_arith;
1567
9
    ops->mul_pow10_to_float64 = invalid_mul_pow10_to_float64;
1568
9
    ops->mul_pow10 = invalid_mul_pow10;
1569
9
}
1570
1571
#endif /* CONFIG_BIGNUM */
1572
1573
#if !defined(CONFIG_STACK_CHECK)
1574
/* no stack limitation */
1575
static inline uintptr_t js_get_stack_pointer(void)
1576
{
1577
    return 0;
1578
}
1579
1580
static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
1581
{
1582
    return FALSE;
1583
}
1584
#else
1585
/* Note: OS and CPU dependent */
1586
static inline uintptr_t js_get_stack_pointer(void)
1587
8.79M
{
1588
8.79M
    return (uintptr_t)__builtin_frame_address(0);
1589
8.79M
}
1590
1591
static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
1592
8.79M
{
1593
8.79M
    uintptr_t sp;
1594
8.79M
    sp = js_get_stack_pointer() - alloca_size;
1595
8.79M
    return unlikely(sp < rt->stack_limit);
1596
8.79M
}
1597
#endif
1598
1599
JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
1600
3
{
1601
3
    JSRuntime *rt;
1602
3
    JSMallocState ms;
1603
1604
3
    memset(&ms, 0, sizeof(ms));
1605
3
    ms.opaque = opaque;
1606
3
    ms.malloc_limit = -1;
1607
1608
3
    rt = mf->js_malloc(&ms, sizeof(JSRuntime));
1609
3
    if (!rt)
1610
0
        return NULL;
1611
3
    memset(rt, 0, sizeof(*rt));
1612
3
    rt->mf = *mf;
1613
3
    if (!rt->mf.js_malloc_usable_size) {
1614
        /* use dummy function if none provided */
1615
0
        rt->mf.js_malloc_usable_size = js_malloc_usable_size_unknown;
1616
0
    }
1617
3
    rt->malloc_state = ms;
1618
3
    rt->malloc_gc_threshold = 256 * 1024;
1619
1620
3
#ifdef CONFIG_BIGNUM
1621
3
    bf_context_init(&rt->bf_ctx, js_bf_realloc, rt);
1622
3
    set_dummy_numeric_ops(&rt->bigint_ops);
1623
3
    set_dummy_numeric_ops(&rt->bigfloat_ops);
1624
3
    set_dummy_numeric_ops(&rt->bigdecimal_ops);
1625
3
#endif
1626
1627
3
    init_list_head(&rt->context_list);
1628
3
    init_list_head(&rt->gc_obj_list);
1629
3
    init_list_head(&rt->gc_zero_ref_count_list);
1630
3
    rt->gc_phase = JS_GC_PHASE_NONE;
1631
    
1632
#ifdef DUMP_LEAKS
1633
    init_list_head(&rt->string_list);
1634
#endif
1635
3
    init_list_head(&rt->job_list);
1636
1637
3
    if (JS_InitAtoms(rt))
1638
0
        goto fail;
1639
1640
    /* create the object, array and function classes */
1641
3
    if (init_class_range(rt, js_std_class_def, JS_CLASS_OBJECT,
1642
3
                         countof(js_std_class_def)) < 0)
1643
0
        goto fail;
1644
3
    rt->class_array[JS_CLASS_ARGUMENTS].exotic = &js_arguments_exotic_methods;
1645
3
    rt->class_array[JS_CLASS_STRING].exotic = &js_string_exotic_methods;
1646
3
    rt->class_array[JS_CLASS_MODULE_NS].exotic = &js_module_ns_exotic_methods;
1647
1648
3
    rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function;
1649
3
    rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_c_function_data_call;
1650
3
    rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function;
1651
3
    rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_generator_function_call;
1652
3
    if (init_shape_hash(rt))
1653
0
        goto fail;
1654
1655
3
    rt->stack_size = JS_DEFAULT_STACK_SIZE;
1656
3
    JS_UpdateStackTop(rt);
1657
1658
3
    rt->current_exception = JS_NULL;
1659
1660
3
    return rt;
1661
0
 fail:
1662
0
    JS_FreeRuntime(rt);
1663
0
    return NULL;
1664
3
}
1665
1666
void *JS_GetRuntimeOpaque(JSRuntime *rt)
1667
0
{
1668
0
    return rt->user_opaque;
1669
0
}
1670
1671
void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque)
1672
0
{
1673
0
    rt->user_opaque = opaque;
1674
0
}
1675
1676
/* default memory allocation functions with memory limitation */
1677
static inline size_t js_def_malloc_usable_size(void *ptr)
1678
98.7M
{
1679
#if defined(__APPLE__)
1680
    return malloc_size(ptr);
1681
#elif defined(_WIN32)
1682
    return _msize(ptr);
1683
#elif defined(EMSCRIPTEN)
1684
    return 0;
1685
#elif defined(__linux__)
1686
98.7M
    return malloc_usable_size(ptr);
1687
#else
1688
    /* change this to `return 0;` if compilation fails */
1689
    return malloc_usable_size(ptr);
1690
#endif
1691
98.7M
}
1692
1693
static void *js_def_malloc(JSMallocState *s, size_t size)
1694
43.0M
{
1695
43.0M
    void *ptr;
1696
1697
    /* Do not allocate zero bytes: behavior is platform dependent */
1698
43.0M
    assert(size != 0);
1699
1700
43.0M
    if (unlikely(s->malloc_size + size > s->malloc_limit))
1701
1.30k
        return NULL;
1702
1703
43.0M
    ptr = malloc(size);
1704
43.0M
    if (!ptr)
1705
0
        return NULL;
1706
1707
43.0M
    s->malloc_count++;
1708
43.0M
    s->malloc_size += js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
1709
43.0M
    return ptr;
1710
43.0M
}
1711
1712
static void js_def_free(JSMallocState *s, void *ptr)
1713
42.2M
{
1714
42.2M
    if (!ptr)
1715
1.11M
        return;
1716
1717
41.1M
    s->malloc_count--;
1718
41.1M
    s->malloc_size -= js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
1719
41.1M
    free(ptr);
1720
41.1M
}
1721
1722
static void *js_def_realloc(JSMallocState *s, void *ptr, size_t size)
1723
8.81M
{
1724
8.81M
    size_t old_size;
1725
1726
8.81M
    if (!ptr) {
1727
1.14M
        if (size == 0)
1728
17.4k
            return NULL;
1729
1.12M
        return js_def_malloc(s, size);
1730
1.14M
    }
1731
7.67M
    old_size = js_def_malloc_usable_size(ptr);
1732
7.67M
    if (size == 0) {
1733
713k
        s->malloc_count--;
1734
713k
        s->malloc_size -= old_size + MALLOC_OVERHEAD;
1735
713k
        free(ptr);
1736
713k
        return NULL;
1737
713k
    }
1738
6.95M
    if (s->malloc_size + size - old_size > s->malloc_limit)
1739
388
        return NULL;
1740
1741
6.95M
    ptr = realloc(ptr, size);
1742
6.95M
    if (!ptr)
1743
0
        return NULL;
1744
1745
6.95M
    s->malloc_size += js_def_malloc_usable_size(ptr) - old_size;
1746
6.95M
    return ptr;
1747
6.95M
}
1748
1749
static const JSMallocFunctions def_malloc_funcs = {
1750
    js_def_malloc,
1751
    js_def_free,
1752
    js_def_realloc,
1753
#if defined(__APPLE__)
1754
    malloc_size,
1755
#elif defined(_WIN32)
1756
    (size_t (*)(const void *))_msize,
1757
#elif defined(EMSCRIPTEN)
1758
    NULL,
1759
#elif defined(__linux__)
1760
    (size_t (*)(const void *))malloc_usable_size,
1761
#else
1762
    /* change this to `NULL,` if compilation fails */
1763
    malloc_usable_size,
1764
#endif
1765
};
1766
1767
JSRuntime *JS_NewRuntime(void)
1768
3
{
1769
3
    return JS_NewRuntime2(&def_malloc_funcs, NULL);
1770
3
}
1771
1772
void JS_SetMemoryLimit(JSRuntime *rt, size_t limit)
1773
3
{
1774
3
    rt->malloc_state.malloc_limit = limit;
1775
3
}
1776
1777
/* use -1 to disable automatic GC */
1778
void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold)
1779
0
{
1780
0
    rt->malloc_gc_threshold = gc_threshold;
1781
0
}
1782
1783
#define malloc(s) malloc_is_forbidden(s)
1784
#define free(p) free_is_forbidden(p)
1785
#define realloc(p,s) realloc_is_forbidden(p,s)
1786
1787
void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque)
1788
2
{
1789
2
    rt->interrupt_handler = cb;
1790
2
    rt->interrupt_opaque = opaque;
1791
2
}
1792
1793
void JS_SetCanBlock(JSRuntime *rt, BOOL can_block)
1794
0
{
1795
0
    rt->can_block = can_block;
1796
0
}
1797
1798
void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
1799
                                      const JSSharedArrayBufferFunctions *sf)
1800
0
{
1801
0
    rt->sab_funcs = *sf;
1802
0
}
1803
1804
/* return 0 if OK, < 0 if exception */
1805
int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func,
1806
                  int argc, JSValueConst *argv)
1807
208k
{
1808
208k
    JSRuntime *rt = ctx->rt;
1809
208k
    JSJobEntry *e;
1810
208k
    int i;
1811
1812
208k
    e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue));
1813
208k
    if (!e)
1814
0
        return -1;
1815
208k
    e->ctx = ctx;
1816
208k
    e->job_func = job_func;
1817
208k
    e->argc = argc;
1818
1.04M
    for(i = 0; i < argc; i++) {
1819
835k
        e->argv[i] = JS_DupValue(ctx, argv[i]);
1820
835k
    }
1821
208k
    list_add_tail(&e->link, &rt->job_list);
1822
208k
    return 0;
1823
208k
}
1824
1825
BOOL JS_IsJobPending(JSRuntime *rt)
1826
0
{
1827
0
    return !list_empty(&rt->job_list);
1828
0
}
1829
1830
/* return < 0 if exception, 0 if no job pending, 1 if a job was
1831
   executed successfully. the context of the job is stored in '*pctx' */
1832
int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx)
1833
109k
{
1834
109k
    JSContext *ctx;
1835
109k
    JSJobEntry *e;
1836
109k
    JSValue res;
1837
109k
    int i, ret;
1838
1839
109k
    if (list_empty(&rt->job_list)) {
1840
311
        *pctx = NULL;
1841
311
        return 0;
1842
311
    }
1843
1844
    /* get the first pending job and execute it */
1845
109k
    e = list_entry(rt->job_list.next, JSJobEntry, link);
1846
109k
    list_del(&e->link);
1847
109k
    ctx = e->ctx;
1848
109k
    res = e->job_func(e->ctx, e->argc, (JSValueConst *)e->argv);
1849
546k
    for(i = 0; i < e->argc; i++)
1850
436k
        JS_FreeValue(ctx, e->argv[i]);
1851
109k
    if (JS_IsException(res))
1852
0
        ret = -1;
1853
109k
    else
1854
109k
        ret = 1;
1855
109k
    JS_FreeValue(ctx, res);
1856
109k
    js_free(ctx, e);
1857
109k
    *pctx = ctx;
1858
109k
    return ret;
1859
109k
}
1860
1861
static inline uint32_t atom_get_free(const JSAtomStruct *p)
1862
671k
{
1863
671k
    return (uintptr_t)p >> 1;
1864
671k
}
1865
1866
static inline BOOL atom_is_free(const JSAtomStruct *p)
1867
285
{
1868
285
    return (uintptr_t)p & 1;
1869
285
}
1870
1871
static inline JSAtomStruct *atom_set_free(uint32_t v)
1872
732k
{
1873
732k
    return (JSAtomStruct *)(((uintptr_t)v << 1) | 1);
1874
732k
}
1875
1876
/* Note: the string contents are uninitialized */
1877
static JSString *js_alloc_string_rt(JSRuntime *rt, int max_len, int is_wide_char)
1878
8.63M
{
1879
8.63M
    JSString *str;
1880
8.63M
    str = js_malloc_rt(rt, sizeof(JSString) + (max_len << is_wide_char) + 1 - is_wide_char);
1881
8.63M
    if (unlikely(!str))
1882
3
        return NULL;
1883
8.63M
    str->header.ref_count = 1;
1884
8.63M
    str->is_wide_char = is_wide_char;
1885
8.63M
    str->len = max_len;
1886
8.63M
    str->atom_type = 0;
1887
8.63M
    str->hash = 0;          /* optional but costless */
1888
8.63M
    str->hash_next = 0;     /* optional */
1889
#ifdef DUMP_LEAKS
1890
    list_add_tail(&str->link, &rt->string_list);
1891
#endif
1892
8.63M
    return str;
1893
8.63M
}
1894
1895
static JSString *js_alloc_string(JSContext *ctx, int max_len, int is_wide_char)
1896
8.63M
{
1897
8.63M
    JSString *p;
1898
8.63M
    p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char);
1899
8.63M
    if (unlikely(!p)) {
1900
3
        JS_ThrowOutOfMemory(ctx);
1901
3
        return NULL;
1902
3
    }
1903
8.63M
    return p;
1904
8.63M
}
1905
1906
/* same as JS_FreeValueRT() but faster */
1907
static inline void js_free_string(JSRuntime *rt, JSString *str)
1908
540k
{
1909
540k
    if (--str->header.ref_count <= 0) {
1910
9.98k
        if (str->atom_type) {
1911
0
            JS_FreeAtomStruct(rt, str);
1912
9.98k
        } else {
1913
#ifdef DUMP_LEAKS
1914
            list_del(&str->link);
1915
#endif
1916
9.98k
            js_free_rt(rt, str);
1917
9.98k
        }
1918
9.98k
    }
1919
540k
}
1920
1921
void JS_SetRuntimeInfo(JSRuntime *rt, const char *s)
1922
0
{
1923
0
    if (rt)
1924
0
        rt->rt_info = s;
1925
0
}
1926
1927
void JS_FreeRuntime(JSRuntime *rt)
1928
0
{
1929
0
    struct list_head *el, *el1;
1930
0
    int i;
1931
1932
0
    JS_FreeValueRT(rt, rt->current_exception);
1933
1934
0
    list_for_each_safe(el, el1, &rt->job_list) {
1935
0
        JSJobEntry *e = list_entry(el, JSJobEntry, link);
1936
0
        for(i = 0; i < e->argc; i++)
1937
0
            JS_FreeValueRT(rt, e->argv[i]);
1938
0
        js_free_rt(rt, e);
1939
0
    }
1940
0
    init_list_head(&rt->job_list);
1941
1942
0
    JS_RunGC(rt);
1943
1944
#ifdef DUMP_LEAKS
1945
    /* leaking objects */
1946
    {
1947
        BOOL header_done;
1948
        JSGCObjectHeader *p;
1949
        int count;
1950
1951
        /* remove the internal refcounts to display only the object
1952
           referenced externally */
1953
        list_for_each(el, &rt->gc_obj_list) {
1954
            p = list_entry(el, JSGCObjectHeader, link);
1955
            p->mark = 0;
1956
        }
1957
        gc_decref(rt);
1958
1959
        header_done = FALSE;
1960
        list_for_each(el, &rt->gc_obj_list) {
1961
            p = list_entry(el, JSGCObjectHeader, link);
1962
            if (p->ref_count != 0) {
1963
                if (!header_done) {
1964
                    printf("Object leaks:\n");
1965
                    JS_DumpObjectHeader(rt);
1966
                    header_done = TRUE;
1967
                }
1968
                JS_DumpGCObject(rt, p);
1969
            }
1970
        }
1971
1972
        count = 0;
1973
        list_for_each(el, &rt->gc_obj_list) {
1974
            p = list_entry(el, JSGCObjectHeader, link);
1975
            if (p->ref_count == 0) {
1976
                count++;
1977
            }
1978
        }
1979
        if (count != 0)
1980
            printf("Secondary object leaks: %d\n", count);
1981
    }
1982
#endif
1983
0
    assert(list_empty(&rt->gc_obj_list));
1984
1985
    /* free the classes */
1986
0
    for(i = 0; i < rt->class_count; i++) {
1987
0
        JSClass *cl = &rt->class_array[i];
1988
0
        if (cl->class_id != 0) {
1989
0
            JS_FreeAtomRT(rt, cl->class_name);
1990
0
        }
1991
0
    }
1992
0
    js_free_rt(rt, rt->class_array);
1993
1994
0
#ifdef CONFIG_BIGNUM
1995
0
    bf_context_end(&rt->bf_ctx);
1996
0
#endif
1997
1998
#ifdef DUMP_LEAKS
1999
    /* only the atoms defined in JS_InitAtoms() should be left */
2000
    {
2001
        BOOL header_done = FALSE;
2002
2003
        for(i = 0; i < rt->atom_size; i++) {
2004
            JSAtomStruct *p = rt->atom_array[i];
2005
            if (!atom_is_free(p) /* && p->str*/) {
2006
                if (i >= JS_ATOM_END || p->header.ref_count != 1) {
2007
                    if (!header_done) {
2008
                        header_done = TRUE;
2009
                        if (rt->rt_info) {
2010
                            printf("%s:1: atom leakage:", rt->rt_info);
2011
                        } else {
2012
                            printf("Atom leaks:\n"
2013
                                   "    %6s %6s %s\n",
2014
                                   "ID", "REFCNT", "NAME");
2015
                        }
2016
                    }
2017
                    if (rt->rt_info) {
2018
                        printf(" ");
2019
                    } else {
2020
                        printf("    %6u %6u ", i, p->header.ref_count);
2021
                    }
2022
                    switch (p->atom_type) {
2023
                    case JS_ATOM_TYPE_STRING:
2024
                        JS_DumpString(rt, p);
2025
                        break;
2026
                    case JS_ATOM_TYPE_GLOBAL_SYMBOL:
2027
                        printf("Symbol.for(");
2028
                        JS_DumpString(rt, p);
2029
                        printf(")");
2030
                        break;
2031
                    case JS_ATOM_TYPE_SYMBOL:
2032
                        if (p->hash == JS_ATOM_HASH_SYMBOL) {
2033
                            printf("Symbol(");
2034
                            JS_DumpString(rt, p);
2035
                            printf(")");
2036
                        } else {
2037
                            printf("Private(");
2038
                            JS_DumpString(rt, p);
2039
                            printf(")");
2040
                        }
2041
                        break;
2042
                    }
2043
                    if (rt->rt_info) {
2044
                        printf(":%u", p->header.ref_count);
2045
                    } else {
2046
                        printf("\n");
2047
                    }
2048
                }
2049
            }
2050
        }
2051
        if (rt->rt_info && header_done)
2052
            printf("\n");
2053
    }
2054
#endif
2055
2056
    /* free the atoms */
2057
0
    for(i = 0; i < rt->atom_size; i++) {
2058
0
        JSAtomStruct *p = rt->atom_array[i];
2059
0
        if (!atom_is_free(p)) {
2060
#ifdef DUMP_LEAKS
2061
            list_del(&p->link);
2062
#endif
2063
0
            js_free_rt(rt, p);
2064
0
        }
2065
0
    }
2066
0
    js_free_rt(rt, rt->atom_array);
2067
0
    js_free_rt(rt, rt->atom_hash);
2068
0
    js_free_rt(rt, rt->shape_hash);
2069
#ifdef DUMP_LEAKS
2070
    if (!list_empty(&rt->string_list)) {
2071
        if (rt->rt_info) {
2072
            printf("%s:1: string leakage:", rt->rt_info);
2073
        } else {
2074
            printf("String leaks:\n"
2075
                   "    %6s %s\n",
2076
                   "REFCNT", "VALUE");
2077
        }
2078
        list_for_each_safe(el, el1, &rt->string_list) {
2079
            JSString *str = list_entry(el, JSString, link);
2080
            if (rt->rt_info) {
2081
                printf(" ");
2082
            } else {
2083
                printf("    %6u ", str->header.ref_count);
2084
            }
2085
            JS_DumpString(rt, str);
2086
            if (rt->rt_info) {
2087
                printf(":%u", str->header.ref_count);
2088
            } else {
2089
                printf("\n");
2090
            }
2091
            list_del(&str->link);
2092
            js_free_rt(rt, str);
2093
        }
2094
        if (rt->rt_info)
2095
            printf("\n");
2096
    }
2097
    {
2098
        JSMallocState *s = &rt->malloc_state;
2099
        if (s->malloc_count > 1) {
2100
            if (rt->rt_info)
2101
                printf("%s:1: ", rt->rt_info);
2102
            printf("Memory leak: %"PRIu64" bytes lost in %"PRIu64" block%s\n",
2103
                   (uint64_t)(s->malloc_size - sizeof(JSRuntime)),
2104
                   (uint64_t)(s->malloc_count - 1), &"s"[s->malloc_count == 2]);
2105
        }
2106
    }
2107
#endif
2108
2109
0
    {
2110
0
        JSMallocState ms = rt->malloc_state;
2111
0
        rt->mf.js_free(&ms, rt);
2112
0
    }
2113
0
}
2114
2115
JSContext *JS_NewContextRaw(JSRuntime *rt)
2116
3
{
2117
3
    JSContext *ctx;
2118
3
    int i;
2119
2120
3
    ctx = js_mallocz_rt(rt, sizeof(JSContext));
2121
3
    if (!ctx)
2122
0
        return NULL;
2123
3
    ctx->header.ref_count = 1;
2124
3
    add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT);
2125
2126
3
    ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) *
2127
3
                                    rt->class_count);
2128
3
    if (!ctx->class_proto) {
2129
0
        js_free_rt(rt, ctx);
2130
0
        return NULL;
2131
0
    }
2132
3
    ctx->rt = rt;
2133
3
    list_add_tail(&ctx->link, &rt->context_list);
2134
3
#ifdef CONFIG_BIGNUM
2135
3
    ctx->bf_ctx = &rt->bf_ctx;
2136
3
    ctx->fp_env.prec = 113;
2137
3
    ctx->fp_env.flags = bf_set_exp_bits(15) | BF_RNDN | BF_FLAG_SUBNORMAL;
2138
3
#endif
2139
177
    for(i = 0; i < rt->class_count; i++)
2140
174
        ctx->class_proto[i] = JS_NULL;
2141
3
    ctx->array_ctor = JS_NULL;
2142
3
    ctx->regexp_ctor = JS_NULL;
2143
3
    ctx->promise_ctor = JS_NULL;
2144
3
    init_list_head(&ctx->loaded_modules);
2145
2146
3
    JS_AddIntrinsicBasicObjects(ctx);
2147
3
    return ctx;
2148
3
}
2149
2150
JSContext *JS_NewContext(JSRuntime *rt)
2151
0
{
2152
0
    JSContext *ctx;
2153
2154
0
    ctx = JS_NewContextRaw(rt);
2155
0
    if (!ctx)
2156
0
        return NULL;
2157
2158
0
    JS_AddIntrinsicBaseObjects(ctx);
2159
0
    JS_AddIntrinsicDate(ctx);
2160
0
    JS_AddIntrinsicEval(ctx);
2161
0
    JS_AddIntrinsicStringNormalize(ctx);
2162
0
    JS_AddIntrinsicRegExp(ctx);
2163
0
    JS_AddIntrinsicJSON(ctx);
2164
0
    JS_AddIntrinsicProxy(ctx);
2165
0
    JS_AddIntrinsicMapSet(ctx);
2166
0
    JS_AddIntrinsicTypedArrays(ctx);
2167
0
    JS_AddIntrinsicPromise(ctx);
2168
0
#ifdef CONFIG_BIGNUM
2169
0
    JS_AddIntrinsicBigInt(ctx);
2170
0
#endif
2171
0
    return ctx;
2172
0
}
2173
2174
void *JS_GetContextOpaque(JSContext *ctx)
2175
0
{
2176
0
    return ctx->user_opaque;
2177
0
}
2178
2179
void JS_SetContextOpaque(JSContext *ctx, void *opaque)
2180
0
{
2181
0
    ctx->user_opaque = opaque;
2182
0
}
2183
2184
/* set the new value and free the old value after (freeing the value
2185
   can reallocate the object data) */
2186
static inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val)
2187
16.1M
{
2188
16.1M
    JSValue old_val;
2189
16.1M
    old_val = *pval;
2190
16.1M
    *pval = new_val;
2191
16.1M
    JS_FreeValue(ctx, old_val);
2192
16.1M
}
2193
2194
void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj)
2195
0
{
2196
0
    JSRuntime *rt = ctx->rt;
2197
0
    assert(class_id < rt->class_count);
2198
0
    set_value(ctx, &ctx->class_proto[class_id], obj);
2199
0
}
2200
2201
JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id)
2202
0
{
2203
0
    JSRuntime *rt = ctx->rt;
2204
0
    assert(class_id < rt->class_count);
2205
0
    return JS_DupValue(ctx, ctx->class_proto[class_id]);
2206
0
}
2207
2208
typedef enum JSFreeModuleEnum {
2209
    JS_FREE_MODULE_ALL,
2210
    JS_FREE_MODULE_NOT_RESOLVED,
2211
    JS_FREE_MODULE_NOT_EVALUATED,
2212
} JSFreeModuleEnum;
2213
2214
/* XXX: would be more efficient with separate module lists */
2215
static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag)
2216
52
{
2217
52
    struct list_head *el, *el1;
2218
3.47k
    list_for_each_safe(el, el1, &ctx->loaded_modules) {
2219
3.47k
        JSModuleDef *m = list_entry(el, JSModuleDef, link);
2220
3.47k
        if (flag == JS_FREE_MODULE_ALL ||
2221
3.47k
            (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved) ||
2222
3.47k
            (flag == JS_FREE_MODULE_NOT_EVALUATED && !m->evaluated)) {
2223
121
            js_free_module_def(ctx, m);
2224
121
        }
2225
3.47k
    }
2226
52
}
2227
2228
JSContext *JS_DupContext(JSContext *ctx)
2229
34.0k
{
2230
34.0k
    ctx->header.ref_count++;
2231
34.0k
    return ctx;
2232
34.0k
}
2233
2234
/* used by the GC */
2235
static void JS_MarkContext(JSRuntime *rt, JSContext *ctx,
2236
                           JS_MarkFunc *mark_func)
2237
182
{
2238
182
    int i;
2239
182
    struct list_head *el;
2240
2241
    /* modules are not seen by the GC, so we directly mark the objects
2242
       referenced by each module */
2243
1.70k
    list_for_each(el, &ctx->loaded_modules) {
2244
1.70k
        JSModuleDef *m = list_entry(el, JSModuleDef, link);
2245
1.70k
        js_mark_module_def(rt, m, mark_func);
2246
1.70k
    }
2247
2248
182
    JS_MarkValue(rt, ctx->global_obj, mark_func);
2249
182
    JS_MarkValue(rt, ctx->global_var_obj, mark_func);
2250
2251
182
    JS_MarkValue(rt, ctx->throw_type_error, mark_func);
2252
182
    JS_MarkValue(rt, ctx->eval_obj, mark_func);
2253
2254
182
    JS_MarkValue(rt, ctx->array_proto_values, mark_func);
2255
1.63k
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
2256
1.45k
        JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);
2257
1.45k
    }
2258
10.7k
    for(i = 0; i < rt->class_count; i++) {
2259
10.5k
        JS_MarkValue(rt, ctx->class_proto[i], mark_func);
2260
10.5k
    }
2261
182
    JS_MarkValue(rt, ctx->iterator_proto, mark_func);
2262
182
    JS_MarkValue(rt, ctx->async_iterator_proto, mark_func);
2263
182
    JS_MarkValue(rt, ctx->promise_ctor, mark_func);
2264
182
    JS_MarkValue(rt, ctx->array_ctor, mark_func);
2265
182
    JS_MarkValue(rt, ctx->regexp_ctor, mark_func);
2266
182
    JS_MarkValue(rt, ctx->function_ctor, mark_func);
2267
182
    JS_MarkValue(rt, ctx->function_proto, mark_func);
2268
2269
182
    if (ctx->array_shape)
2270
182
        mark_func(rt, &ctx->array_shape->header);
2271
182
}
2272
2273
void JS_FreeContext(JSContext *ctx)
2274
31.0k
{
2275
31.0k
    JSRuntime *rt = ctx->rt;
2276
31.0k
    int i;
2277
2278
31.0k
    if (--ctx->header.ref_count > 0)
2279
31.0k
        return;
2280
0
    assert(ctx->header.ref_count == 0);
2281
    
2282
#ifdef DUMP_ATOMS
2283
    JS_DumpAtoms(ctx->rt);
2284
#endif
2285
#ifdef DUMP_SHAPES
2286
    JS_DumpShapes(ctx->rt);
2287
#endif
2288
#ifdef DUMP_OBJECTS
2289
    {
2290
        struct list_head *el;
2291
        JSGCObjectHeader *p;
2292
        printf("JSObjects: {\n");
2293
        JS_DumpObjectHeader(ctx->rt);
2294
        list_for_each(el, &rt->gc_obj_list) {
2295
            p = list_entry(el, JSGCObjectHeader, link);
2296
            JS_DumpGCObject(rt, p);
2297
        }
2298
        printf("}\n");
2299
    }
2300
#endif
2301
#ifdef DUMP_MEM
2302
    {
2303
        JSMemoryUsage stats;
2304
        JS_ComputeMemoryUsage(rt, &stats);
2305
        JS_DumpMemoryUsage(stdout, &stats, rt);
2306
    }
2307
#endif
2308
2309
0
    js_free_modules(ctx, JS_FREE_MODULE_ALL);
2310
2311
0
    JS_FreeValue(ctx, ctx->global_obj);
2312
0
    JS_FreeValue(ctx, ctx->global_var_obj);
2313
2314
0
    JS_FreeValue(ctx, ctx->throw_type_error);
2315
0
    JS_FreeValue(ctx, ctx->eval_obj);
2316
2317
0
    JS_FreeValue(ctx, ctx->array_proto_values);
2318
0
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
2319
0
        JS_FreeValue(ctx, ctx->native_error_proto[i]);
2320
0
    }
2321
0
    for(i = 0; i < rt->class_count; i++) {
2322
0
        JS_FreeValue(ctx, ctx->class_proto[i]);
2323
0
    }
2324
0
    js_free_rt(rt, ctx->class_proto);
2325
0
    JS_FreeValue(ctx, ctx->iterator_proto);
2326
0
    JS_FreeValue(ctx, ctx->async_iterator_proto);
2327
0
    JS_FreeValue(ctx, ctx->promise_ctor);
2328
0
    JS_FreeValue(ctx, ctx->array_ctor);
2329
0
    JS_FreeValue(ctx, ctx->regexp_ctor);
2330
0
    JS_FreeValue(ctx, ctx->function_ctor);
2331
0
    JS_FreeValue(ctx, ctx->function_proto);
2332
2333
0
    js_free_shape_null(ctx->rt, ctx->array_shape);
2334
2335
0
    list_del(&ctx->link);
2336
0
    remove_gc_object(&ctx->header);
2337
0
    js_free_rt(ctx->rt, ctx);
2338
0
}
2339
2340
JSRuntime *JS_GetRuntime(JSContext *ctx)
2341
109k
{
2342
109k
    return ctx->rt;
2343
109k
}
2344
2345
static void update_stack_limit(JSRuntime *rt)
2346
3
{
2347
3
    if (rt->stack_size == 0) {
2348
0
        rt->stack_limit = 0; /* no limit */
2349
3
    } else {
2350
3
        rt->stack_limit = rt->stack_top - rt->stack_size;
2351
3
    }
2352
3
}
2353
2354
void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size)
2355
0
{
2356
0
    rt->stack_size = stack_size;
2357
0
    update_stack_limit(rt);
2358
0
}
2359
2360
void JS_UpdateStackTop(JSRuntime *rt)
2361
3
{
2362
3
    rt->stack_top = js_get_stack_pointer();
2363
3
    update_stack_limit(rt);
2364
3
}
2365
2366
static inline BOOL is_strict_mode(JSContext *ctx)
2367
2.26M
{
2368
2.26M
    JSStackFrame *sf = ctx->rt->current_stack_frame;
2369
2.26M
    return (sf && (sf->js_mode & JS_MODE_STRICT));
2370
2.26M
}
2371
2372
#ifdef CONFIG_BIGNUM
2373
static inline BOOL is_math_mode(JSContext *ctx)
2374
892k
{
2375
892k
    JSStackFrame *sf = ctx->rt->current_stack_frame;
2376
892k
    return (sf && (sf->js_mode & JS_MODE_MATH));
2377
892k
}
2378
#endif
2379
2380
/* JSAtom support */
2381
2382
188M
#define JS_ATOM_TAG_INT (1U << 31)
2383
3.79M
#define JS_ATOM_MAX_INT (JS_ATOM_TAG_INT - 1)
2384
21
#define JS_ATOM_MAX     ((1U << 30) - 1)
2385
2386
/* return the max count from the hash size */
2387
11
#define JS_ATOM_COUNT_RESIZE(n) ((n) * 2)
2388
2389
static inline BOOL __JS_AtomIsConst(JSAtom v)
2390
45.0M
{
2391
#if defined(DUMP_LEAKS) && DUMP_LEAKS > 1
2392
        return (int32_t)v <= 0;
2393
#else
2394
45.0M
        return (int32_t)v < JS_ATOM_END;
2395
45.0M
#endif
2396
45.0M
}
2397
2398
static inline BOOL __JS_AtomIsTaggedInt(JSAtom v)
2399
124M
{
2400
124M
    return (v & JS_ATOM_TAG_INT) != 0;
2401
124M
}
2402
2403
static inline JSAtom __JS_AtomFromUInt32(uint32_t v)
2404
7.47M
{
2405
7.47M
    return v | JS_ATOM_TAG_INT;
2406
7.47M
}
2407
2408
static inline uint32_t __JS_AtomToUInt32(JSAtom atom)
2409
53.3M
{
2410
53.3M
    return atom & ~JS_ATOM_TAG_INT;
2411
53.3M
}
2412
2413
static inline int is_num(int c)
2414
1.84M
{
2415
1.84M
    return c >= '0' && c <= '9';
2416
1.84M
}
2417
2418
/* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */
2419
static inline BOOL is_num_string(uint32_t *pval, const JSString *p)
2420
1.66M
{
2421
1.66M
    uint32_t n;
2422
1.66M
    uint64_t n64;
2423
1.66M
    int c, i, len;
2424
2425
1.66M
    len = p->len;
2426
1.66M
    if (len == 0 || len > 10)
2427
21.3k
        return FALSE;
2428
1.64M
    if (p->is_wide_char)
2429
3.00k
        c = p->u.str16[0];
2430
1.64M
    else
2431
1.64M
        c = p->u.str8[0];
2432
1.64M
    if (is_num(c)) {
2433
104k
        if (c == '0') {
2434
3.37k
            if (len != 1)
2435
1.31k
                return FALSE;
2436
2.06k
            n = 0;
2437
101k
        } else {
2438
101k
            n = c - '0';
2439
202k
            for(i = 1; i < len; i++) {
2440
202k
                if (p->is_wide_char)
2441
74
                    c = p->u.str16[i];
2442
202k
                else
2443
202k
                    c = p->u.str8[i];
2444
202k
                if (!is_num(c))
2445
100k
                    return FALSE;
2446
101k
                n64 = (uint64_t)n * 10 + (c - '0');
2447
101k
                if ((n64 >> 32) != 0)
2448
0
                    return FALSE;
2449
101k
                n = n64;
2450
101k
            }
2451
101k
        }
2452
2.51k
        *pval = n;
2453
2.51k
        return TRUE;
2454
1.54M
    } else {
2455
1.54M
        return FALSE;
2456
1.54M
    }
2457
1.64M
}
2458
2459
/* XXX: could use faster version ? */
2460
static inline uint32_t hash_string8(const uint8_t *str, size_t len, uint32_t h)
2461
1.75M
{
2462
1.75M
    size_t i;
2463
2464
10.0M
    for(i = 0; i < len; i++)
2465
8.25M
        h = h * 263 + str[i];
2466
1.75M
    return h;
2467
1.75M
}
2468
2469
static inline uint32_t hash_string16(const uint16_t *str,
2470
                                     size_t len, uint32_t h)
2471
3.90k
{
2472
3.90k
    size_t i;
2473
2474
615k
    for(i = 0; i < len; i++)
2475
611k
        h = h * 263 + str[i];
2476
3.90k
    return h;
2477
3.90k
}
2478
2479
static uint32_t hash_string(const JSString *str, uint32_t h)
2480
183k
{
2481
183k
    if (str->is_wide_char)
2482
3.90k
        h = hash_string16(str->u.str16, str->len, h);
2483
179k
    else
2484
179k
        h = hash_string8(str->u.str8, str->len, h);
2485
183k
    return h;
2486
183k
}
2487
2488
static __maybe_unused void JS_DumpString(JSRuntime *rt,
2489
                                                  const JSString *p)
2490
0
{
2491
0
    int i, c, sep;
2492
0
2493
0
    if (p == NULL) {
2494
0
        printf("<null>");
2495
0
        return;
2496
0
    }
2497
0
    printf("%d", p->header.ref_count);
2498
0
    sep = (p->header.ref_count == 1) ? '\"' : '\'';
2499
0
    putchar(sep);
2500
0
    for(i = 0; i < p->len; i++) {
2501
0
        if (p->is_wide_char)
2502
0
            c = p->u.str16[i];
2503
0
        else
2504
0
            c = p->u.str8[i];
2505
0
        if (c == sep || c == '\\') {
2506
0
            putchar('\\');
2507
0
            putchar(c);
2508
0
        } else if (c >= ' ' && c <= 126) {
2509
0
            putchar(c);
2510
0
        } else if (c == '\n') {
2511
0
            putchar('\\');
2512
0
            putchar('n');
2513
0
        } else {
2514
0
            printf("\\u%04x", c);
2515
0
        }
2516
0
    }
2517
0
    putchar(sep);
2518
0
}
2519
2520
static __maybe_unused void JS_DumpAtoms(JSRuntime *rt)
2521
0
{
2522
0
    JSAtomStruct *p;
2523
0
    int h, i;
2524
0
    /* This only dumps hashed atoms, not JS_ATOM_TYPE_SYMBOL atoms */
2525
0
    printf("JSAtom count=%d size=%d hash_size=%d:\n",
2526
0
           rt->atom_count, rt->atom_size, rt->atom_hash_size);
2527
0
    printf("JSAtom hash table: {\n");
2528
0
    for(i = 0; i < rt->atom_hash_size; i++) {
2529
0
        h = rt->atom_hash[i];
2530
0
        if (h) {
2531
0
            printf("  %d:", i);
2532
0
            while (h) {
2533
0
                p = rt->atom_array[h];
2534
0
                printf(" ");
2535
0
                JS_DumpString(rt, p);
2536
0
                h = p->hash_next;
2537
0
            }
2538
0
            printf("\n");
2539
0
        }
2540
0
    }
2541
0
    printf("}\n");
2542
0
    printf("JSAtom table: {\n");
2543
0
    for(i = 0; i < rt->atom_size; i++) {
2544
0
        p = rt->atom_array[i];
2545
0
        if (!atom_is_free(p)) {
2546
0
            printf("  %d: { %d %08x ", i, p->atom_type, p->hash);
2547
0
            if (!(p->len == 0 && p->is_wide_char != 0))
2548
0
                JS_DumpString(rt, p);
2549
0
            printf(" %d }\n", p->hash_next);
2550
0
        }
2551
0
    }
2552
0
    printf("}\n");
2553
0
}
2554
2555
static int JS_ResizeAtomHash(JSRuntime *rt, int new_hash_size)
2556
11
{
2557
11
    JSAtomStruct *p;
2558
11
    uint32_t new_hash_mask, h, i, hash_next1, j, *new_hash;
2559
2560
11
    assert((new_hash_size & (new_hash_size - 1)) == 0); /* power of two */
2561
11
    new_hash_mask = new_hash_size - 1;
2562
11
    new_hash = js_mallocz_rt(rt, sizeof(rt->atom_hash[0]) * new_hash_size);
2563
11
    if (!new_hash)
2564
0
        return -1;
2565
32.7k
    for(i = 0; i < rt->atom_hash_size; i++) {
2566
32.7k
        h = rt->atom_hash[i];
2567
37.0k
        while (h != 0) {
2568
4.33k
            p = rt->atom_array[h];
2569
4.33k
            hash_next1 = p->hash_next;
2570
            /* add in new hash table */
2571
4.33k
            j = p->hash & new_hash_mask;
2572
4.33k
            p->hash_next = new_hash[j];
2573
4.33k
            new_hash[j] = h;
2574
4.33k
            h = hash_next1;
2575
4.33k
        }
2576
32.7k
    }
2577
11
    js_free_rt(rt, rt->atom_hash);
2578
11
    rt->atom_hash = new_hash;
2579
11
    rt->atom_hash_size = new_hash_size;
2580
11
    rt->atom_count_resize = JS_ATOM_COUNT_RESIZE(new_hash_size);
2581
    //    JS_DumpAtoms(rt);
2582
11
    return 0;
2583
11
}
2584
2585
static int JS_InitAtoms(JSRuntime *rt)
2586
3
{
2587
3
    int i, len, atom_type;
2588
3
    const char *p;
2589
2590
3
    rt->atom_hash_size = 0;
2591
3
    rt->atom_hash = NULL;
2592
3
    rt->atom_count = 0;
2593
3
    rt->atom_size = 0;
2594
3
    rt->atom_free_index = 0;
2595
3
    if (JS_ResizeAtomHash(rt, 256))     /* there are at least 195 predefined atoms */
2596
0
        return -1;
2597
2598
3
    p = js_atom_init;
2599
675
    for(i = 1; i < JS_ATOM_END; i++) {
2600
672
        if (i == JS_ATOM_Private_brand)
2601
3
            atom_type = JS_ATOM_TYPE_PRIVATE;
2602
669
        else if (i >= JS_ATOM_Symbol_toPrimitive)
2603
42
            atom_type = JS_ATOM_TYPE_SYMBOL;
2604
627
        else
2605
627
            atom_type = JS_ATOM_TYPE_STRING;
2606
672
        len = strlen(p);
2607
672
        if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL)
2608
0
            return -1;
2609
672
        p = p + len + 1;
2610
672
    }
2611
3
    return 0;
2612
3
}
2613
2614
static JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v)
2615
161
{
2616
161
    JSAtomStruct *p;
2617
2618
161
    if (!__JS_AtomIsConst(v)) {
2619
0
        p = rt->atom_array[v];
2620
0
        p->header.ref_count++;
2621
0
    }
2622
161
    return v;
2623
161
}
2624
2625
JSAtom JS_DupAtom(JSContext *ctx, JSAtom v)
2626
16.1M
{
2627
16.1M
    JSRuntime *rt;
2628
16.1M
    JSAtomStruct *p;
2629
2630
16.1M
    if (!__JS_AtomIsConst(v)) {
2631
4.06M
        rt = ctx->rt;
2632
4.06M
        p = rt->atom_array[v];
2633
4.06M
        p->header.ref_count++;
2634
4.06M
    }
2635
16.1M
    return v;
2636
16.1M
}
2637
2638
static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v)
2639
48.2M
{
2640
48.2M
    JSRuntime *rt;
2641
48.2M
    JSAtomStruct *p;
2642
2643
48.2M
    rt = ctx->rt;
2644
48.2M
    if (__JS_AtomIsTaggedInt(v))
2645
2.92M
        return JS_ATOM_KIND_STRING;
2646
45.3M
    p = rt->atom_array[v];
2647
45.3M
    switch(p->atom_type) {
2648
43.1M
    case JS_ATOM_TYPE_STRING:
2649
43.1M
        return JS_ATOM_KIND_STRING;
2650
0
    case JS_ATOM_TYPE_GLOBAL_SYMBOL:
2651
0
        return JS_ATOM_KIND_SYMBOL;
2652
2.17M
    case JS_ATOM_TYPE_SYMBOL:
2653
2.17M
        switch(p->hash) {
2654
1.46M
        case JS_ATOM_HASH_SYMBOL:
2655
1.46M
            return JS_ATOM_KIND_SYMBOL;
2656
706k
        case JS_ATOM_HASH_PRIVATE:
2657
706k
            return JS_ATOM_KIND_PRIVATE;
2658
0
        default:
2659
0
            abort();
2660
2.17M
        }
2661
0
    default:
2662
0
        abort();
2663
45.3M
    }
2664
45.3M
}
2665
2666
static BOOL JS_AtomIsString(JSContext *ctx, JSAtom v)
2667
0
{
2668
0
    return JS_AtomGetKind(ctx, v) == JS_ATOM_KIND_STRING;
2669
0
}
2670
2671
static JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p)
2672
1.55M
{
2673
1.55M
    uint32_t i = p->hash_next;  /* atom_index */
2674
1.55M
    if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
2675
1.11M
        JSAtomStruct *p1;
2676
2677
1.11M
        i = rt->atom_hash[p->hash & (rt->atom_hash_size - 1)];
2678
1.11M
        p1 = rt->atom_array[i];
2679
1.11M
        while (p1 != p) {
2680
7
            assert(i != 0);
2681
7
            i = p1->hash_next;
2682
7
            p1 = rt->atom_array[i];
2683
7
        }
2684
1.11M
    }
2685
1.55M
    return i;
2686
1.55M
}
2687
2688
/* string case (internal). Return JS_ATOM_NULL if error. 'str' is
2689
   freed. */
2690
static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
2691
1.81M
{
2692
1.81M
    uint32_t h, h1, i;
2693
1.81M
    JSAtomStruct *p;
2694
1.81M
    int len;
2695
2696
#if 0
2697
    printf("__JS_NewAtom: ");  JS_DumpString(rt, str); printf("\n");
2698
#endif
2699
1.81M
    if (atom_type < JS_ATOM_TYPE_SYMBOL) {
2700
        /* str is not NULL */
2701
1.29M
        if (str->atom_type == atom_type) {
2702
            /* str is the atom, return its index */
2703
1.11M
            i = js_get_atom_index(rt, str);
2704
            /* reduce string refcount and increase atom's unless constant */
2705
1.11M
            if (__JS_AtomIsConst(i))
2706
6.94k
                str->header.ref_count--;
2707
1.11M
            return i;
2708
1.11M
        }
2709
        /* try and locate an already registered atom */
2710
183k
        len = str->len;
2711
183k
        h = hash_string(str, atom_type);
2712
183k
        h &= JS_ATOM_HASH_MASK;
2713
183k
        h1 = h & (rt->atom_hash_size - 1);
2714
183k
        i = rt->atom_hash[h1];
2715
290k
        while (i != 0) {
2716
131k
            p = rt->atom_array[i];
2717
131k
            if (p->hash == h &&
2718
131k
                p->atom_type == atom_type &&
2719
131k
                p->len == len &&
2720
131k
                js_string_memcmp(p, str, len) == 0) {
2721
24.4k
                if (!__JS_AtomIsConst(i))
2722
24.3k
                    p->header.ref_count++;
2723
24.4k
                goto done;
2724
24.4k
            }
2725
107k
            i = p->hash_next;
2726
107k
        }
2727
513k
    } else {
2728
513k
        h1 = 0; /* avoid warning */
2729
513k
        if (atom_type == JS_ATOM_TYPE_SYMBOL) {
2730
42
            h = JS_ATOM_HASH_SYMBOL;
2731
513k
        } else {
2732
513k
            h = JS_ATOM_HASH_PRIVATE;
2733
513k
            atom_type = JS_ATOM_TYPE_SYMBOL;
2734
513k
        }
2735
513k
    }
2736
2737
671k
    if (rt->atom_free_index == 0) {
2738
        /* allow new atom entries */
2739
21
        uint32_t new_size, start;
2740
21
        JSAtomStruct **new_array;
2741
2742
        /* alloc new with size progression 3/2:
2743
           4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066 1599 2398 3597 5395 8092
2744
           preallocating space for predefined atoms (at least 195).
2745
         */
2746
21
        new_size = max_int(211, rt->atom_size * 3 / 2);
2747
21
        if (new_size > JS_ATOM_MAX)
2748
0
            goto fail;
2749
        /* XXX: should use realloc2 to use slack space */
2750
21
        new_array = js_realloc_rt(rt, rt->atom_array, sizeof(*new_array) * new_size);
2751
21
        if (!new_array)
2752
0
            goto fail;
2753
        /* Note: the atom 0 is not used */
2754
21
        start = rt->atom_size;
2755
21
        if (start == 0) {
2756
            /* JS_ATOM_NULL entry */
2757
3
            p = js_mallocz_rt(rt, sizeof(JSAtomStruct));
2758
3
            if (!p) {
2759
0
                js_free_rt(rt, new_array);
2760
0
                goto fail;
2761
0
            }
2762
3
            p->header.ref_count = 1;  /* not refcounted */
2763
3
            p->atom_type = JS_ATOM_TYPE_SYMBOL;
2764
#ifdef DUMP_LEAKS
2765
            list_add_tail(&p->link, &rt->string_list);
2766
#endif
2767
3
            new_array[0] = p;
2768
3
            rt->atom_count++;
2769
3
            start = 1;
2770
3
        }
2771
21
        rt->atom_size = new_size;
2772
21
        rt->atom_array = new_array;
2773
21
        rt->atom_free_index = start;
2774
62.4k
        for(i = start; i < new_size; i++) {
2775
62.4k
            uint32_t next;
2776
62.4k
            if (i == (new_size - 1))
2777
21
                next = 0;
2778
62.4k
            else
2779
62.4k
                next = i + 1;
2780
62.4k
            rt->atom_array[i] = atom_set_free(next);
2781
62.4k
        }
2782
21
    }
2783
2784
671k
    if (str) {
2785
671k
        if (str->atom_type == 0) {
2786
158k
            p = str;
2787
158k
            p->atom_type = atom_type;
2788
513k
        } else {
2789
513k
            p = js_malloc_rt(rt, sizeof(JSString) +
2790
513k
                             (str->len << str->is_wide_char) +
2791
513k
                             1 - str->is_wide_char);
2792
513k
            if (unlikely(!p))
2793
0
                goto fail;
2794
513k
            p->header.ref_count = 1;
2795
513k
            p->is_wide_char = str->is_wide_char;
2796
513k
            p->len = str->len;
2797
#ifdef DUMP_LEAKS
2798
            list_add_tail(&p->link, &rt->string_list);
2799
#endif
2800
513k
            memcpy(p->u.str8, str->u.str8, (str->len << str->is_wide_char) +
2801
513k
                   1 - str->is_wide_char);
2802
513k
            js_free_string(rt, str);
2803
513k
        }
2804
671k
    } else {
2805
0
        p = js_malloc_rt(rt, sizeof(JSAtomStruct)); /* empty wide string */
2806
0
        if (!p)
2807
0
            return JS_ATOM_NULL;
2808
0
        p->header.ref_count = 1;
2809
0
        p->is_wide_char = 1;    /* Hack to represent NULL as a JSString */
2810
0
        p->len = 0;
2811
#ifdef DUMP_LEAKS
2812
        list_add_tail(&p->link, &rt->string_list);
2813
#endif
2814
0
    }
2815
2816
    /* use an already free entry */
2817
671k
    i = rt->atom_free_index;
2818
671k
    rt->atom_free_index = atom_get_free(rt->atom_array[i]);
2819
671k
    rt->atom_array[i] = p;
2820
2821
671k
    p->hash = h;
2822
671k
    p->hash_next = i;   /* atom_index */
2823
671k
    p->atom_type = atom_type;
2824
2825
671k
    rt->atom_count++;
2826
2827
671k
    if (atom_type != JS_ATOM_TYPE_SYMBOL) {
2828
158k
        p->hash_next = rt->atom_hash[h1];
2829
158k
        rt->atom_hash[h1] = i;
2830
158k
        if (unlikely(rt->atom_count >= rt->atom_count_resize))
2831
8
            JS_ResizeAtomHash(rt, rt->atom_hash_size * 2);
2832
158k
    }
2833
2834
    //    JS_DumpAtoms(rt);
2835
671k
    return i;
2836
2837
0
 fail:
2838
0
    i = JS_ATOM_NULL;
2839
24.4k
 done:
2840
24.4k
    if (str)
2841
24.4k
        js_free_string(rt, str);
2842
24.4k
    return i;
2843
0
}
2844
2845
/* only works with zero terminated 8 bit strings */
2846
static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
2847
                               int atom_type)
2848
672
{
2849
672
    JSString *p;
2850
672
    p = js_alloc_string_rt(rt, len, 0);
2851
672
    if (!p)
2852
0
        return JS_ATOM_NULL;
2853
672
    memcpy(p->u.str8, str, len);
2854
672
    p->u.str8[len] = '\0';
2855
672
    return __JS_NewAtom(rt, p, atom_type);
2856
672
}
2857
2858
static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
2859
                            int atom_type)
2860
1.57M
{
2861
1.57M
    uint32_t h, h1, i;
2862
1.57M
    JSAtomStruct *p;
2863
2864
1.57M
    h = hash_string8((const uint8_t *)str, len, JS_ATOM_TYPE_STRING);
2865
1.57M
    h &= JS_ATOM_HASH_MASK;
2866
1.57M
    h1 = h & (rt->atom_hash_size - 1);
2867
1.57M
    i = rt->atom_hash[h1];
2868
1.59M
    while (i != 0) {
2869
1.55M
        p = rt->atom_array[i];
2870
1.55M
        if (p->hash == h &&
2871
1.55M
            p->atom_type == JS_ATOM_TYPE_STRING &&
2872
1.55M
            p->len == len &&
2873
1.55M
            p->is_wide_char == 0 &&
2874
1.55M
            memcmp(p->u.str8, str, len) == 0) {
2875
1.53M
            if (!__JS_AtomIsConst(i))
2876
1.03M
                p->header.ref_count++;
2877
1.53M
            return i;
2878
1.53M
        }
2879
24.3k
        i = p->hash_next;
2880
24.3k
    }
2881
39.1k
    return JS_ATOM_NULL;
2882
1.57M
}
2883
2884
static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p)
2885
670k
{
2886
#if 0   /* JS_ATOM_NULL is not refcounted: __JS_AtomIsConst() includes 0 */
2887
    if (unlikely(i == JS_ATOM_NULL)) {
2888
        p->header.ref_count = INT32_MAX / 2;
2889
        return;
2890
    }
2891
#endif
2892
670k
    uint32_t i = p->hash_next;  /* atom_index */
2893
670k
    if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
2894
157k
        JSAtomStruct *p0, *p1;
2895
157k
        uint32_t h0;
2896
2897
157k
        h0 = p->hash & (rt->atom_hash_size - 1);
2898
157k
        i = rt->atom_hash[h0];
2899
157k
        p1 = rt->atom_array[i];
2900
157k
        if (p1 == p) {
2901
157k
            rt->atom_hash[h0] = p1->hash_next;
2902
157k
        } else {
2903
76
            for(;;) {
2904
76
                assert(i != 0);
2905
76
                p0 = p1;
2906
76
                i = p1->hash_next;
2907
76
                p1 = rt->atom_array[i];
2908
76
                if (p1 == p) {
2909
51
                    p0->hash_next = p1->hash_next;
2910
51
                    break;
2911
51
                }
2912
76
            }
2913
51
        }
2914
157k
    }
2915
    /* insert in free atom list */
2916
670k
    rt->atom_array[i] = atom_set_free(rt->atom_free_index);
2917
670k
    rt->atom_free_index = i;
2918
    /* free the string structure */
2919
#ifdef DUMP_LEAKS
2920
    list_del(&p->link);
2921
#endif
2922
670k
    js_free_rt(rt, p);
2923
670k
    rt->atom_count--;
2924
670k
    assert(rt->atom_count >= 0);
2925
670k
}
2926
2927
static void __JS_FreeAtom(JSRuntime *rt, uint32_t i)
2928
6.39M
{
2929
6.39M
    JSAtomStruct *p;
2930
2931
6.39M
    p = rt->atom_array[i];
2932
6.39M
    if (--p->header.ref_count > 0)
2933
6.24M
        return;
2934
146k
    JS_FreeAtomStruct(rt, p);
2935
146k
}
2936
2937
/* Warning: 'p' is freed */
2938
static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p)
2939
1.30M
{
2940
1.30M
    JSRuntime *rt = ctx->rt;
2941
1.30M
    uint32_t n;
2942
1.30M
    if (is_num_string(&n, p)) {
2943
2.51k
        if (n <= JS_ATOM_MAX_INT) {
2944
2.51k
            js_free_string(rt, p);
2945
2.51k
            return __JS_AtomFromUInt32(n);
2946
2.51k
        }
2947
2.51k
    }
2948
    /* XXX: should generate an exception */
2949
1.29M
    return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING);
2950
1.30M
}
2951
2952
JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len)
2953
1.67M
{
2954
1.67M
    JSValue val;
2955
2956
1.67M
    if (len == 0 || !is_digit(*str)) {
2957
1.57M
        JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);
2958
1.57M
        if (atom)
2959
1.53M
            return atom;
2960
1.57M
    }
2961
138k
    val = JS_NewStringLen(ctx, str, len);
2962
138k
    if (JS_IsException(val))
2963
0
        return JS_ATOM_NULL;
2964
138k
    return JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(val));
2965
138k
}
2966
2967
JSAtom JS_NewAtom(JSContext *ctx, const char *str)
2968
225k
{
2969
225k
    return JS_NewAtomLen(ctx, str, strlen(str));
2970
225k
}
2971
2972
JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
2973
0
{
2974
0
    if (n <= JS_ATOM_MAX_INT) {
2975
0
        return __JS_AtomFromUInt32(n);
2976
0
    } else {
2977
0
        char buf[11];
2978
0
        JSValue val;
2979
0
        snprintf(buf, sizeof(buf), "%u", n);
2980
0
        val = JS_NewString(ctx, buf);
2981
0
        if (JS_IsException(val))
2982
0
            return JS_ATOM_NULL;
2983
0
        return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
2984
0
                            JS_ATOM_TYPE_STRING);
2985
0
    }
2986
0
}
2987
2988
static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n)
2989
0
{
2990
0
    if ((uint64_t)n <= JS_ATOM_MAX_INT) {
2991
0
        return __JS_AtomFromUInt32((uint32_t)n);
2992
0
    } else {
2993
0
        char buf[24];
2994
0
        JSValue val;
2995
0
        snprintf(buf, sizeof(buf), "%" PRId64 , n);
2996
0
        val = JS_NewString(ctx, buf);
2997
0
        if (JS_IsException(val))
2998
0
            return JS_ATOM_NULL;
2999
0
        return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
3000
0
                            JS_ATOM_TYPE_STRING);
3001
0
    }
3002
0
}
3003
3004
/* 'p' is freed */
3005
static JSValue JS_NewSymbol(JSContext *ctx, JSString *p, int atom_type)
3006
513k
{
3007
513k
    JSRuntime *rt = ctx->rt;
3008
513k
    JSAtom atom;
3009
513k
    atom = __JS_NewAtom(rt, p, atom_type);
3010
513k
    if (atom == JS_ATOM_NULL)
3011
0
        return JS_ThrowOutOfMemory(ctx);
3012
513k
    return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]);
3013
513k
}
3014
3015
/* descr must be a non-numeric string atom */
3016
static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,
3017
                                    int atom_type)
3018
513k
{
3019
513k
    JSRuntime *rt = ctx->rt;
3020
513k
    JSString *p;
3021
3022
513k
    assert(!__JS_AtomIsTaggedInt(descr));
3023
513k
    assert(descr < rt->atom_size);
3024
513k
    p = rt->atom_array[descr];
3025
513k
    JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
3026
513k
    return JS_NewSymbol(ctx, p, atom_type);
3027
513k
}
3028
3029
#define ATOM_GET_STR_BUF_SIZE 64
3030
3031
/* Should only be used for debug. */
3032
static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,
3033
                                   JSAtom atom)
3034
285
{
3035
285
    if (__JS_AtomIsTaggedInt(atom)) {
3036
0
        snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom));
3037
285
    } else {
3038
285
        JSAtomStruct *p;
3039
285
        assert(atom < rt->atom_size);
3040
285
        if (atom == JS_ATOM_NULL) {
3041
0
            snprintf(buf, buf_size, "<null>");
3042
285
        } else {
3043
285
            int i, c;
3044
285
            char *q;
3045
285
            JSString *str;
3046
3047
285
            q = buf;
3048
285
            p = rt->atom_array[atom];
3049
285
            assert(!atom_is_free(p));
3050
285
            str = p;
3051
285
            if (str) {
3052
285
                if (!str->is_wide_char) {
3053
                    /* special case ASCII strings */
3054
285
                    c = 0;
3055
19.4k
                    for(i = 0; i < str->len; i++) {
3056
19.1k
                        c |= str->u.str8[i];
3057
19.1k
                    }
3058
285
                    if (c < 0x80)
3059
284
                        return (const char *)str->u.str8;
3060
285
                }
3061
3
                for(i = 0; i < str->len; i++) {
3062
2
                    if (str->is_wide_char)
3063
0
                        c = str->u.str16[i];
3064
2
                    else
3065
2
                        c = str->u.str8[i];
3066
2
                    if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX)
3067
0
                        break;
3068
2
                    if (c < 128) {
3069
1
                        *q++ = c;
3070
1
                    } else {
3071
1
                        q += unicode_to_utf8((uint8_t *)q, c);
3072
1
                    }
3073
2
                }
3074
1
            }
3075
1
            *q = '\0';
3076
1
        }
3077
285
    }
3078
1
    return buf;
3079
285
}
3080
3081
static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom)
3082
285
{
3083
285
    return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom);
3084
285
}
3085
3086
static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string)
3087
8.96M
{
3088
8.96M
    char buf[ATOM_GET_STR_BUF_SIZE];
3089
3090
8.96M
    if (__JS_AtomIsTaggedInt(atom)) {
3091
1.79M
        snprintf(buf, sizeof(buf), "%u", __JS_AtomToUInt32(atom));
3092
1.79M
        return JS_NewString(ctx, buf);
3093
7.16M
    } else {
3094
7.16M
        JSRuntime *rt = ctx->rt;
3095
7.16M
        JSAtomStruct *p;
3096
7.16M
        assert(atom < rt->atom_size);
3097
7.16M
        p = rt->atom_array[atom];
3098
7.16M
        if (p->atom_type == JS_ATOM_TYPE_STRING) {
3099
7.15M
            goto ret_string;
3100
7.15M
        } else if (force_string) {
3101
10.0k
            if (p->len == 0 && p->is_wide_char != 0) {
3102
                /* no description string */
3103
0
                p = rt->atom_array[JS_ATOM_empty_string];
3104
0
            }
3105
7.16M
        ret_string:
3106
7.16M
            return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
3107
10.0k
        } else {
3108
28
            return JS_DupValue(ctx, JS_MKPTR(JS_TAG_SYMBOL, p));
3109
28
        }
3110
7.16M
    }
3111
8.96M
}
3112
3113
JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom)
3114
3.51M
{
3115
3.51M
    return __JS_AtomToValue(ctx, atom, FALSE);
3116
3.51M
}
3117
3118
JSValue JS_AtomToString(JSContext *ctx, JSAtom atom)
3119
5.45M
{
3120
5.45M
    return __JS_AtomToValue(ctx, atom, TRUE);
3121
5.45M
}
3122
3123
/* return TRUE if the atom is an array index (i.e. 0 <= index <=
3124
   2^32-2 and return its value */
3125
static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom)
3126
42.6M
{
3127
42.6M
    if (__JS_AtomIsTaggedInt(atom)) {
3128
42.2M
        *pval = __JS_AtomToUInt32(atom);
3129
42.2M
        return TRUE;
3130
42.2M
    } else {
3131
367k
        JSRuntime *rt = ctx->rt;
3132
367k
        JSAtomStruct *p;
3133
367k
        uint32_t val;
3134
3135
367k
        assert(atom < rt->atom_size);
3136
367k
        p = rt->atom_array[atom];
3137
367k
        if (p->atom_type == JS_ATOM_TYPE_STRING &&
3138
367k
            is_num_string(&val, p) && val != -1) {
3139
0
            *pval = val;
3140
0
            return TRUE;
3141
367k
        } else {
3142
367k
            *pval = 0;
3143
367k
            return FALSE;
3144
367k
        }
3145
367k
    }
3146
42.6M
}
3147
3148
/* This test must be fast if atom is not a numeric index (e.g. a
3149
   method name). Return JS_UNDEFINED if not a numeric
3150
   index. JS_EXCEPTION can also be returned. */
3151
static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
3152
0
{
3153
0
    JSRuntime *rt = ctx->rt;
3154
0
    JSAtomStruct *p1;
3155
0
    JSString *p;
3156
0
    int c, len, ret;
3157
0
    JSValue num, str;
3158
3159
0
    if (__JS_AtomIsTaggedInt(atom))
3160
0
        return JS_NewInt32(ctx, __JS_AtomToUInt32(atom));
3161
0
    assert(atom < rt->atom_size);
3162
0
    p1 = rt->atom_array[atom];
3163
0
    if (p1->atom_type != JS_ATOM_TYPE_STRING)
3164
0
        return JS_UNDEFINED;
3165
0
    p = p1;
3166
0
    len = p->len;
3167
0
    if (p->is_wide_char) {
3168
0
        const uint16_t *r = p->u.str16, *r_end = p->u.str16 + len;
3169
0
        if (r >= r_end)
3170
0
            return JS_UNDEFINED;
3171
0
        c = *r;
3172
0
        if (c == '-') {
3173
0
            if (r >= r_end)
3174
0
                return JS_UNDEFINED;
3175
0
            r++;
3176
0
            c = *r;
3177
            /* -0 case is specific */
3178
0
            if (c == '0' && len == 2)
3179
0
                goto minus_zero;
3180
0
        }
3181
        /* XXX: should test NaN, but the tests do not check it */
3182
0
        if (!is_num(c)) {
3183
            /* XXX: String should be normalized, therefore 8-bit only */
3184
0
            const uint16_t nfinity16[7] = { 'n', 'f', 'i', 'n', 'i', 't', 'y' };
3185
0
            if (!(c =='I' && (r_end - r) == 8 &&
3186
0
                  !memcmp(r + 1, nfinity16, sizeof(nfinity16))))
3187
0
                return JS_UNDEFINED;
3188
0
        }
3189
0
    } else {
3190
0
        const uint8_t *r = p->u.str8, *r_end = p->u.str8 + len;
3191
0
        if (r >= r_end)
3192
0
            return JS_UNDEFINED;
3193
0
        c = *r;
3194
0
        if (c == '-') {
3195
0
            if (r >= r_end)
3196
0
                return JS_UNDEFINED;
3197
0
            r++;
3198
0
            c = *r;
3199
            /* -0 case is specific */
3200
0
            if (c == '0' && len == 2) {
3201
0
            minus_zero:
3202
0
                return __JS_NewFloat64(ctx, -0.0);
3203
0
            }
3204
0
        }
3205
0
        if (!is_num(c)) {
3206
0
            if (!(c =='I' && (r_end - r) == 8 &&
3207
0
                  !memcmp(r + 1, "nfinity", 7)))
3208
0
                return JS_UNDEFINED;
3209
0
        }
3210
0
    }
3211
    /* XXX: bignum: would be better to only accept integer to avoid
3212
       relying on current floating point precision */
3213
    /* this is ECMA CanonicalNumericIndexString primitive */
3214
0
    num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p));
3215
0
    if (JS_IsException(num))
3216
0
        return num;
3217
0
    str = JS_ToString(ctx, num);
3218
0
    if (JS_IsException(str)) {
3219
0
        JS_FreeValue(ctx, num);
3220
0
        return str;
3221
0
    }
3222
0
    ret = js_string_compare(ctx, p, JS_VALUE_GET_STRING(str));
3223
0
    JS_FreeValue(ctx, str);
3224
0
    if (ret == 0) {
3225
0
        return num;
3226
0
    } else {
3227
0
        JS_FreeValue(ctx, num);
3228
0
        return JS_UNDEFINED;
3229
0
    }
3230
0
}
3231
3232
/* return -1 if exception or TRUE/FALSE */
3233
static int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom)
3234
0
{
3235
0
    JSValue num;
3236
0
    num = JS_AtomIsNumericIndex1(ctx, atom);
3237
0
    if (likely(JS_IsUndefined(num)))
3238
0
        return FALSE;
3239
0
    if (JS_IsException(num))
3240
0
        return -1;
3241
0
    JS_FreeValue(ctx, num);
3242
0
    return TRUE;
3243
0
}
3244
3245
void JS_FreeAtom(JSContext *ctx, JSAtom v)
3246
13.0M
{
3247
13.0M
    if (!__JS_AtomIsConst(v))
3248
3.53M
        __JS_FreeAtom(ctx->rt, v);
3249
13.0M
}
3250
3251
void JS_FreeAtomRT(JSRuntime *rt, JSAtom v)
3252
13.1M
{
3253
13.1M
    if (!__JS_AtomIsConst(v))
3254
2.86M
        __JS_FreeAtom(rt, v);
3255
13.1M
}
3256
3257
/* return TRUE if 'v' is a symbol with a string description */
3258
static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)
3259
369k
{
3260
369k
    JSRuntime *rt;
3261
369k
    JSAtomStruct *p;
3262
3263
369k
    rt = ctx->rt;
3264
369k
    if (__JS_AtomIsTaggedInt(v))
3265
6.13k
        return FALSE;
3266
363k
    p = rt->atom_array[v];
3267
363k
    return (((p->atom_type == JS_ATOM_TYPE_SYMBOL &&
3268
363k
              p->hash == JS_ATOM_HASH_SYMBOL) ||
3269
363k
             p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL) &&
3270
363k
            !(p->len == 0 && p->is_wide_char != 0));
3271
369k
}
3272
3273
static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom)
3274
0
{
3275
0
    char buf[ATOM_GET_STR_BUF_SIZE];
3276
0
    const char *p;
3277
0
    int i;
3278
0
3279
0
    /* XXX: should handle embedded null characters */
3280
0
    /* XXX: should move encoding code to JS_AtomGetStr */
3281
0
    p = JS_AtomGetStr(ctx, buf, sizeof(buf), atom);
3282
0
    for (i = 0; p[i]; i++) {
3283
0
        int c = (unsigned char)p[i];
3284
0
        if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
3285
0
              (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0)))
3286
0
            break;
3287
0
    }
3288
0
    if (i > 0 && p[i] == '\0') {
3289
0
        printf("%s", p);
3290
0
    } else {
3291
0
        putchar('"');
3292
0
        printf("%.*s", i, p);
3293
0
        for (; p[i]; i++) {
3294
0
            int c = (unsigned char)p[i];
3295
0
            if (c == '\"' || c == '\\') {
3296
0
                putchar('\\');
3297
0
                putchar(c);
3298
0
            } else if (c >= ' ' && c <= 126) {
3299
0
                putchar(c);
3300
0
            } else if (c == '\n') {
3301
0
                putchar('\\');
3302
0
                putchar('n');
3303
0
            } else {
3304
0
                printf("\\u%04x", c);
3305
0
            }
3306
0
        }
3307
0
        putchar('\"');
3308
0
    }
3309
0
}
3310
3311
/* free with JS_FreeCString() */
3312
const char *JS_AtomToCString(JSContext *ctx, JSAtom atom)
3313
4.27k
{
3314
4.27k
    JSValue str;
3315
4.27k
    const char *cstr;
3316
3317
4.27k
    str = JS_AtomToString(ctx, atom);
3318
4.27k
    if (JS_IsException(str))
3319
0
        return NULL;
3320
4.27k
    cstr = JS_ToCString(ctx, str);
3321
4.27k
    JS_FreeValue(ctx, str);
3322
4.27k
    return cstr;
3323
4.27k
}
3324
3325
/* return a string atom containing name concatenated with str1 */
3326
static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1)
3327
222
{
3328
222
    JSValue str;
3329
222
    JSAtom atom;
3330
222
    const char *cstr;
3331
222
    char *cstr2;
3332
222
    size_t len, len1;
3333
    
3334
222
    str = JS_AtomToString(ctx, name);
3335
222
    if (JS_IsException(str))
3336
0
        return JS_ATOM_NULL;
3337
222
    cstr = JS_ToCStringLen(ctx, &len, str);
3338
222
    if (!cstr)
3339
0
        goto fail;
3340
222
    len1 = strlen(str1);
3341
222
    cstr2 = js_malloc(ctx, len + len1 + 1);
3342
222
    if (!cstr2)
3343
0
        goto fail;
3344
222
    memcpy(cstr2, cstr, len);
3345
222
    memcpy(cstr2 + len, str1, len1);
3346
222
    cstr2[len + len1] = '\0';
3347
222
    atom = JS_NewAtomLen(ctx, cstr2, len + len1);
3348
222
    js_free(ctx, cstr2);
3349
222
    JS_FreeCString(ctx, cstr);
3350
222
    JS_FreeValue(ctx, str);
3351
222
    return atom;
3352
0
 fail:
3353
0
    JS_FreeCString(ctx, cstr);
3354
0
    JS_FreeValue(ctx, str);
3355
0
    return JS_ATOM_NULL;
3356
222
}
3357
3358
static JSAtom js_atom_concat_num(JSContext *ctx, JSAtom name, uint32_t n)
3359
222
{
3360
222
    char buf[16];
3361
222
    snprintf(buf, sizeof(buf), "%u", n);
3362
222
    return js_atom_concat_str(ctx, name, buf);
3363
222
}
3364
3365
static inline BOOL JS_IsEmptyString(JSValueConst v)
3366
94
{
3367
94
    return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0;
3368
94
}
3369
3370
/* JSClass support */
3371
3372
/* a new class ID is allocated if *pclass_id != 0 */
3373
JSClassID JS_NewClassID(JSClassID *pclass_id)
3374
0
{
3375
0
    JSClassID class_id;
3376
    /* XXX: make it thread safe */
3377
0
    class_id = *pclass_id;
3378
0
    if (class_id == 0) {
3379
0
        class_id = js_class_id_alloc++;
3380
0
        *pclass_id = class_id;
3381
0
    }
3382
0
    return class_id;
3383
0
}
3384
3385
BOOL JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id)
3386
4
{
3387
4
    return (class_id < rt->class_count &&
3388
4
            rt->class_array[class_id].class_id != 0);
3389
4
}
3390
3391
/* create a new object internal class. Return -1 if error, 0 if
3392
   OK. The finalizer can be NULL if none is needed. */
3393
static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
3394
                        const JSClassDef *class_def, JSAtom name)
3395
161
{
3396
161
    int new_size, i;
3397
161
    JSClass *cl, *new_class_array;
3398
161
    struct list_head *el;
3399
3400
161
    if (class_id >= (1 << 16))
3401
0
        return -1;
3402
161
    if (class_id < rt->class_count &&
3403
161
        rt->class_array[class_id].class_id != 0)
3404
0
        return -1;
3405
3406
161
    if (class_id >= rt->class_count) {
3407
3
        new_size = max_int(JS_CLASS_INIT_COUNT,
3408
3
                           max_int(class_id + 1, rt->class_count * 3 / 2));
3409
3410
        /* reallocate the context class prototype array, if any */
3411
3
        list_for_each(el, &rt->context_list) {
3412
0
            JSContext *ctx = list_entry(el, JSContext, link);
3413
0
            JSValue *new_tab;
3414
0
            new_tab = js_realloc_rt(rt, ctx->class_proto,
3415
0
                                    sizeof(ctx->class_proto[0]) * new_size);
3416
0
            if (!new_tab)
3417
0
                return -1;
3418
0
            for(i = rt->class_count; i < new_size; i++)
3419
0
                new_tab[i] = JS_NULL;
3420
0
            ctx->class_proto = new_tab;
3421
0
        }
3422
        /* reallocate the class array */
3423
3
        new_class_array = js_realloc_rt(rt, rt->class_array,
3424
3
                                        sizeof(JSClass) * new_size);
3425
3
        if (!new_class_array)
3426
0
            return -1;
3427
3
        memset(new_class_array + rt->class_count, 0,
3428
3
               (new_size - rt->class_count) * sizeof(JSClass));
3429
3
        rt->class_array = new_class_array;
3430
3
        rt->class_count = new_size;
3431
3
    }
3432
161
    cl = &rt->class_array[class_id];
3433
161
    cl->class_id = class_id;
3434
161
    cl->class_name = JS_DupAtomRT(rt, name);
3435
161
    cl->finalizer = class_def->finalizer;
3436
161
    cl->gc_mark = class_def->gc_mark;
3437
161
    cl->call = class_def->call;
3438
161
    cl->exotic = class_def->exotic;
3439
161
    return 0;
3440
161
}
3441
3442
int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def)
3443
0
{
3444
0
    int ret, len;
3445
0
    JSAtom name;
3446
3447
0
    len = strlen(class_def->class_name);
3448
0
    name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
3449
0
    if (name == JS_ATOM_NULL) {
3450
0
        name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
3451
0
        if (name == JS_ATOM_NULL)
3452
0
            return -1;
3453
0
    }
3454
0
    ret = JS_NewClass1(rt, class_id, class_def, name);
3455
0
    JS_FreeAtomRT(rt, name);
3456
0
    return ret;
3457
0
}
3458
3459
static JSValue js_new_string8(JSContext *ctx, const uint8_t *buf, int len)
3460
7.00M
{
3461
7.00M
    JSString *str;
3462
3463
7.00M
    if (len <= 0) {
3464
124k
        return JS_AtomToString(ctx, JS_ATOM_empty_string);
3465
124k
    }
3466
6.88M
    str = js_alloc_string(ctx, len, 0);
3467
6.88M
    if (!str)
3468
3
        return JS_EXCEPTION;
3469
6.88M
    memcpy(str->u.str8, buf, len);
3470
6.88M
    str->u.str8[len] = '\0';
3471
6.88M
    return JS_MKPTR(JS_TAG_STRING, str);
3472
6.88M
}
3473
3474
static JSValue js_new_string16(JSContext *ctx, const uint16_t *buf, int len)
3475
116k
{
3476
116k
    JSString *str;
3477
116k
    str = js_alloc_string(ctx, len, 1);
3478
116k
    if (!str)
3479
0
        return JS_EXCEPTION;
3480
116k
    memcpy(str->u.str16, buf, len * 2);
3481
116k
    return JS_MKPTR(JS_TAG_STRING, str);
3482
116k
}
3483
3484
static JSValue js_new_string_char(JSContext *ctx, uint16_t c)
3485
2.18M
{
3486
2.18M
    if (c < 0x100) {
3487
2.07M
        uint8_t ch8 = c;
3488
2.07M
        return js_new_string8(ctx, &ch8, 1);
3489
2.07M
    } else {
3490
116k
        uint16_t ch16 = c;
3491
116k
        return js_new_string16(ctx, &ch16, 1);
3492
116k
    }
3493
2.18M
}
3494
3495
static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end)
3496
2.50M
{
3497
2.50M
    int len = end - start;
3498
2.50M
    if (start == 0 && end == p->len) {
3499
463
        return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
3500
463
    }
3501
2.49M
    if (p->is_wide_char && len > 0) {
3502
79.3k
        JSString *str;
3503
79.3k
        int i;
3504
79.3k
        uint16_t c = 0;
3505
170k
        for (i = start; i < end; i++) {
3506
91.0k
            c |= p->u.str16[i];
3507
91.0k
        }
3508
79.3k
        if (c > 0xFF)
3509
93
            return js_new_string16(ctx, p->u.str16 + start, len);
3510
3511
79.2k
        str = js_alloc_string(ctx, len, 0);
3512
79.2k
        if (!str)
3513
0
            return JS_EXCEPTION;
3514
158k
        for (i = 0; i < len; i++) {
3515
79.6k
            str->u.str8[i] = p->u.str16[start + i];
3516
79.6k
        }
3517
79.2k
        str->u.str8[len] = '\0';
3518
79.2k
        return JS_MKPTR(JS_TAG_STRING, str);
3519
2.42M
    } else {
3520
2.42M
        return js_new_string8(ctx, p->u.str8 + start, len);
3521
2.42M
    }
3522
2.49M
}
3523
3524
typedef struct StringBuffer {
3525
    JSContext *ctx;
3526
    JSString *str;
3527
    int len;
3528
    int size;
3529
    int is_wide_char;
3530
    int error_status;
3531
} StringBuffer;
3532
3533
/* It is valid to call string_buffer_end() and all string_buffer functions even
3534
   if string_buffer_init() or another string_buffer function returns an error.
3535
   If the error_status is set, string_buffer_end() returns JS_EXCEPTION.
3536
 */
3537
static int string_buffer_init2(JSContext *ctx, StringBuffer *s, int size,
3538
                               int is_wide)
3539
1.05M
{
3540
1.05M
    s->ctx = ctx;
3541
1.05M
    s->size = size;
3542
1.05M
    s->len = 0;
3543
1.05M
    s->is_wide_char = is_wide;
3544
1.05M
    s->error_status = 0;
3545
1.05M
    s->str = js_alloc_string(ctx, size, is_wide);
3546
1.05M
    if (unlikely(!s->str)) {
3547
0
        s->size = 0;
3548
0
        return s->error_status = -1;
3549
0
    }
3550
#ifdef DUMP_LEAKS
3551
    /* the StringBuffer may reallocate the JSString, only link it at the end */
3552
    list_del(&s->str->link);
3553
#endif
3554
1.05M
    return 0;
3555
1.05M
}
3556
3557
static inline int string_buffer_init(JSContext *ctx, StringBuffer *s, int size)
3558
726k
{
3559
726k
    return string_buffer_init2(ctx, s, size, 0);
3560
726k
}
3561
3562
static void string_buffer_free(StringBuffer *s)
3563
295
{
3564
295
    js_free(s->ctx, s->str);
3565
295
    s->str = NULL;
3566
295
}
3567
3568
static int string_buffer_set_error(StringBuffer *s)
3569
1
{
3570
1
    js_free(s->ctx, s->str);
3571
1
    s->str = NULL;
3572
1
    s->size = 0;
3573
1
    s->len = 0;
3574
1
    return s->error_status = -1;
3575
1
}
3576
3577
static no_inline int string_buffer_widen(StringBuffer *s, int size)
3578
226k
{
3579
226k
    JSString *str;
3580
226k
    size_t slack;
3581
226k
    int i;
3582
3583
226k
    if (s->error_status)
3584
0
        return -1;
3585
3586
226k
    str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack);
3587
226k
    if (!str)
3588
0
        return string_buffer_set_error(s);
3589
226k
    size += slack >> 1;
3590
2.03M
    for(i = s->len; i-- > 0;) {
3591
1.81M
        str->u.str16[i] = str->u.str8[i];
3592
1.81M
    }
3593
226k
    s->is_wide_char = 1;
3594
226k
    s->size = size;
3595
226k
    s->str = str;
3596
226k
    return 0;
3597
226k
}
3598
3599
static no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c)
3600
663k
{
3601
663k
    JSString *new_str;
3602
663k
    int new_size;
3603
663k
    size_t new_size_bytes, slack;
3604
3605
663k
    if (s->error_status)
3606
0
        return -1;
3607
3608
663k
    if (new_len > JS_STRING_LEN_MAX) {
3609
0
        JS_ThrowInternalError(s->ctx, "string too long");
3610
0
        return string_buffer_set_error(s);
3611
0
    }
3612
663k
    new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX);
3613
663k
    if (!s->is_wide_char && c >= 0x100) {
3614
202k
        return string_buffer_widen(s, new_size);
3615
202k
    }
3616
461k
    new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char;
3617
461k
    new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack);
3618
461k
    if (!new_str)
3619
1
        return string_buffer_set_error(s);
3620
461k
    new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX);
3621
461k
    s->size = new_size;
3622
461k
    s->str = new_str;
3623
461k
    return 0;
3624
461k
}
3625
3626
static no_inline int string_buffer_putc_slow(StringBuffer *s, uint32_t c)
3627
45.1k
{
3628
45.1k
    if (unlikely(s->len >= s->size)) {
3629
21.8k
        if (string_buffer_realloc(s, s->len + 1, c))
3630
1
            return -1;
3631
21.8k
    }
3632
45.1k
    if (s->is_wide_char) {
3633
4.44k
        s->str->u.str16[s->len++] = c;
3634
40.6k
    } else if (c < 0x100) {
3635
17.4k
        s->str->u.str8[s->len++] = c;
3636
23.2k
    } else {
3637
23.2k
        if (string_buffer_widen(s, s->size))
3638
0
            return -1;
3639
23.2k
        s->str->u.str16[s->len++] = c;
3640
23.2k
    }
3641
45.1k
    return 0;
3642
45.1k
}
3643
3644
/* 0 <= c <= 0xff */
3645
static int string_buffer_putc8(StringBuffer *s, uint32_t c)
3646
6.12M
{
3647
6.12M
    if (unlikely(s->len >= s->size)) {
3648
18.0k
        if (string_buffer_realloc(s, s->len + 1, c))
3649
0
            return -1;
3650
18.0k
    }
3651
6.12M
    if (s->is_wide_char) {
3652
5.70M
        s->str->u.str16[s->len++] = c;
3653
5.70M
    } else {
3654
422k
        s->str->u.str8[s->len++] = c;
3655
422k
    }
3656
6.12M
    return 0;
3657
6.12M
}
3658
3659
/* 0 <= c <= 0xffff */
3660
static int string_buffer_putc16(StringBuffer *s, uint32_t c)
3661
13.6M
{
3662
13.6M
    if (likely(s->len < s->size)) {
3663
13.5M
        if (s->is_wide_char) {
3664
8.87M
            s->str->u.str16[s->len++] = c;
3665
8.87M
            return 0;
3666
8.87M
        } else if (c < 0x100) {
3667
4.68M
            s->str->u.str8[s->len++] = c;
3668
4.68M
            return 0;
3669
4.68M
        }
3670
13.5M
    }
3671
45.1k
    return string_buffer_putc_slow(s, c);
3672
13.6M
}
3673
3674
/* 0 <= c <= 0x10ffff */
3675
static int string_buffer_putc(StringBuffer *s, uint32_t c)
3676
5.87M
{
3677
5.87M
    if (unlikely(c >= 0x10000)) {
3678
        /* surrogate pair */
3679
1.58k
        c -= 0x10000;
3680
1.58k
        if (string_buffer_putc16(s, (c >> 10) + 0xd800))
3681
0
            return -1;
3682
1.58k
        c = (c & 0x3ff) + 0xdc00;
3683
1.58k
    }
3684
5.87M
    return string_buffer_putc16(s, c);
3685
5.87M
}
3686
3687
6.79M
static int string_get(const JSString *p, int idx) {
3688
6.79M
    return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx];
3689
6.79M
}
3690
3691
static int string_getc(const JSString *p, int *pidx)
3692
603k
{
3693
603k
    int idx, c, c1;
3694
603k
    idx = *pidx;
3695
603k
    if (p->is_wide_char) {
3696
208k
        c = p->u.str16[idx++];
3697
208k
        if (c >= 0xd800 && c < 0xdc00 && idx < p->len) {
3698
171
            c1 = p->u.str16[idx];
3699
171
            if (c1 >= 0xdc00 && c1 < 0xe000) {
3700
108
                c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
3701
108
                idx++;
3702
108
            }
3703
171
        }
3704
394k
    } else {
3705
394k
        c = p->u.str8[idx++];
3706
394k
    }
3707
603k
    *pidx = idx;
3708
603k
    return c;
3709
603k
}
3710
3711
static int string_buffer_write8(StringBuffer *s, const uint8_t *p, int len)
3712
1.43M
{
3713
1.43M
    int i;
3714
3715
1.43M
    if (s->len + len > s->size) {
3716
219k
        if (string_buffer_realloc(s, s->len + len, 0))
3717
0
            return -1;
3718
219k
    }
3719
1.43M
    if (s->is_wide_char) {
3720
411k
        for (i = 0; i < len; i++) {
3721
208k
            s->str->u.str16[s->len + i] = p[i];
3722
208k
        }
3723
202k
        s->len += len;
3724
1.23M
    } else {
3725
1.23M
        memcpy(&s->str->u.str8[s->len], p, len);
3726
1.23M
        s->len += len;
3727
1.23M
    }
3728
1.43M
    return 0;
3729
1.43M
}
3730
3731
static int string_buffer_write16(StringBuffer *s, const uint16_t *p, int len)
3732
405k
{
3733
405k
    int c = 0, i;
3734
3735
27.2M
    for (i = 0; i < len; i++) {
3736
26.8M
        c |= p[i];
3737
26.8M
    }
3738
405k
    if (s->len + len > s->size) {
3739
404k
        if (string_buffer_realloc(s, s->len + len, c))
3740
0
            return -1;
3741
404k
    } else if (!s->is_wide_char && c >= 0x100) {
3742
81
        if (string_buffer_widen(s, s->size))
3743
0
            return -1;
3744
81
    }
3745
405k
    if (s->is_wide_char) {
3746
405k
        memcpy(&s->str->u.str16[s->len], p, len << 1);
3747
405k
        s->len += len;
3748
405k
    } else {
3749
0
        for (i = 0; i < len; i++) {
3750
0
            s->str->u.str8[s->len + i] = p[i];
3751
0
        }
3752
0
        s->len += len;
3753
0
    }
3754
405k
    return 0;
3755
405k
}
3756
3757
/* appending an ASCII string */
3758
static int string_buffer_puts8(StringBuffer *s, const char *str)
3759
60
{
3760
60
    return string_buffer_write8(s, (const uint8_t *)str, strlen(str));
3761
60
}
3762
3763
static int string_buffer_concat(StringBuffer *s, const JSString *p,
3764
                                uint32_t from, uint32_t to)
3765
1.41M
{
3766
1.41M
    if (to <= from)
3767
219k
        return 0;
3768
1.19M
    if (p->is_wide_char)
3769
405k
        return string_buffer_write16(s, p->u.str16 + from, to - from);
3770
789k
    else
3771
789k
        return string_buffer_write8(s, p->u.str8 + from, to - from);
3772
1.19M
}
3773
3774
static int string_buffer_concat_value(StringBuffer *s, JSValueConst v)
3775
16
{
3776
16
    JSString *p;
3777
16
    JSValue v1;
3778
16
    int res;
3779
3780
16
    if (s->error_status) {
3781
        /* prevent exception overload */
3782
0
        return -1;
3783
0
    }
3784
16
    if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
3785
15
        v1 = JS_ToString(s->ctx, v);
3786
15
        if (JS_IsException(v1))
3787
0
            return string_buffer_set_error(s);
3788
15
        p = JS_VALUE_GET_STRING(v1);
3789
15
        res = string_buffer_concat(s, p, 0, p->len);
3790
15
        JS_FreeValue(s->ctx, v1);
3791
15
        return res;
3792
15
    }
3793
1
    p = JS_VALUE_GET_STRING(v);
3794
1
    return string_buffer_concat(s, p, 0, p->len);
3795
16
}
3796
3797
static int string_buffer_concat_value_free(StringBuffer *s, JSValue v)
3798
1.10M
{
3799
1.10M
    JSString *p;
3800
1.10M
    int res;
3801
3802
1.10M
    if (s->error_status) {
3803
        /* prevent exception overload */
3804
0
        JS_FreeValue(s->ctx, v);
3805
0
        return -1;
3806
0
    }
3807
1.10M
    if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
3808
5.35k
        v = JS_ToStringFree(s->ctx, v);
3809
5.35k
        if (JS_IsException(v))
3810
0
            return string_buffer_set_error(s);
3811
5.35k
    }
3812
1.10M
    p = JS_VALUE_GET_STRING(v);
3813
1.10M
    res = string_buffer_concat(s, p, 0, p->len);
3814
1.10M
    JS_FreeValue(s->ctx, v);
3815
1.10M
    return res;
3816
1.10M
}
3817
3818
static int string_buffer_fill(StringBuffer *s, int c, int count)
3819
0
{
3820
    /* XXX: optimize */
3821
0
    if (s->len + count > s->size) {
3822
0
        if (string_buffer_realloc(s, s->len + count, c))
3823
0
            return -1;
3824
0
    }
3825
0
    while (count-- > 0) {
3826
0
        if (string_buffer_putc16(s, c))
3827
0
            return -1;
3828
0
    }
3829
0
    return 0;
3830
0
}
3831
3832
static JSValue string_buffer_end(StringBuffer *s)
3833
1.05M
{
3834
1.05M
    JSString *str;
3835
1.05M
    str = s->str;
3836
1.05M
    if (s->error_status)
3837
0
        return JS_EXCEPTION;
3838
1.05M
    if (s->len == 0) {
3839
421k
        js_free(s->ctx, str);
3840
421k
        s->str = NULL;
3841
421k
        return JS_AtomToString(s->ctx, JS_ATOM_empty_string);
3842
421k
    }
3843
633k
    if (s->len < s->size) {
3844
        /* smaller size so js_realloc should not fail, but OK if it does */
3845
        /* XXX: should add some slack to avoid unnecessary calls */
3846
        /* XXX: might need to use malloc+free to ensure smaller size */
3847
304k
        str = js_realloc_rt(s->ctx->rt, str, sizeof(JSString) +
3848
304k
                            (s->len << s->is_wide_char) + 1 - s->is_wide_char);
3849
304k
        if (str == NULL)
3850
0
            str = s->str;
3851
304k
        s->str = str;
3852
304k
    }
3853
633k
    if (!s->is_wide_char)
3854
406k
        str->u.str8[s->len] = 0;
3855
#ifdef DUMP_LEAKS
3856
    list_add_tail(&str->link, &s->ctx->rt->string_list);
3857
#endif
3858
633k
    str->is_wide_char = s->is_wide_char;
3859
633k
    str->len = s->len;
3860
633k
    s->str = NULL;
3861
633k
    return JS_MKPTR(JS_TAG_STRING, str);
3862
1.05M
}
3863
3864
/* create a string from a UTF-8 buffer */
3865
JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)
3866
2.52M
{
3867
2.52M
    const uint8_t *p, *p_end, *p_start, *p_next;
3868
2.52M
    uint32_t c;
3869
2.52M
    StringBuffer b_s, *b = &b_s;
3870
2.52M
    size_t len1;
3871
    
3872
2.52M
    p_start = (const uint8_t *)buf;
3873
2.52M
    p_end = p_start + buf_len;
3874
2.52M
    p = p_start;
3875
15.2M
    while (p < p_end && *p < 128)
3876
12.6M
        p++;
3877
2.52M
    len1 = p - p_start;
3878
2.52M
    if (len1 > JS_STRING_LEN_MAX)
3879
0
        return JS_ThrowInternalError(ctx, "string too long");
3880
2.52M
    if (p == p_end) {
3881
        /* ASCII string */
3882
2.50M
        return js_new_string8(ctx, (const uint8_t *)buf, buf_len);
3883
2.50M
    } else {
3884
21.4k
        if (string_buffer_init(ctx, b, buf_len))
3885
0
            goto fail;
3886
21.4k
        string_buffer_write8(b, p_start, len1);
3887
6.34M
        while (p < p_end) {
3888
6.32M
            if (*p < 128) {
3889
5.36M
                string_buffer_putc8(b, *p++);
3890
5.36M
            } else {
3891
                /* parse utf-8 sequence, return 0xFFFFFFFF for error */
3892
952k
                c = unicode_from_utf8(p, p_end - p, &p_next);
3893
952k
                if (c < 0x10000) {
3894
13.3k
                    p = p_next;
3895
939k
                } else if (c <= 0x10FFFF) {
3896
429
                    p = p_next;
3897
                    /* surrogate pair */
3898
429
                    c -= 0x10000;
3899
429
                    string_buffer_putc16(b, (c >> 10) + 0xd800);
3900
429
                    c = (c & 0x3ff) + 0xdc00;
3901
939k
                } else {
3902
                    /* invalid char */
3903
939k
                    c = 0xfffd;
3904
                    /* skip the invalid chars */
3905
                    /* XXX: seems incorrect. Why not just use c = *p++; ? */
3906
1.16M
                    while (p < p_end && (*p >= 0x80 && *p < 0xc0))
3907
223k
                        p++;
3908
939k
                    if (p < p_end) {
3909
939k
                        p++;
3910
964k
                        while (p < p_end && (*p >= 0x80 && *p < 0xc0))
3911
25.8k
                            p++;
3912
939k
                    }
3913
939k
                }
3914
952k
                string_buffer_putc16(b, c);
3915
952k
            }
3916
6.32M
        }
3917
21.4k
    }
3918
21.4k
    return string_buffer_end(b);
3919
3920
0
 fail:
3921
0
    string_buffer_free(b);
3922
0
    return JS_EXCEPTION;
3923
2.52M
}
3924
3925
static JSValue JS_ConcatString3(JSContext *ctx, const char *str1,
3926
                                JSValue str2, const char *str3)
3927
311k
{
3928
311k
    StringBuffer b_s, *b = &b_s;
3929
311k
    int len1, len3;
3930
311k
    JSString *p;
3931
3932
311k
    if (unlikely(JS_VALUE_GET_TAG(str2) != JS_TAG_STRING)) {
3933
0
        str2 = JS_ToStringFree(ctx, str2);
3934
0
        if (JS_IsException(str2))
3935
0
            goto fail;
3936
0
    }
3937
311k
    p = JS_VALUE_GET_STRING(str2);
3938
311k
    len1 = strlen(str1);
3939
311k
    len3 = strlen(str3);
3940
3941
311k
    if (string_buffer_init2(ctx, b, len1 + p->len + len3, p->is_wide_char))
3942
0
        goto fail;
3943
3944
311k
    string_buffer_write8(b, (const uint8_t *)str1, len1);
3945
311k
    string_buffer_concat(b, p, 0, p->len);
3946
311k
    string_buffer_write8(b, (const uint8_t *)str3, len3);
3947
3948
311k
    JS_FreeValue(ctx, str2);
3949
311k
    return string_buffer_end(b);
3950
3951
0
 fail:
3952
0
    JS_FreeValue(ctx, str2);
3953
0
    return JS_EXCEPTION;
3954
311k
}
3955
3956
JSValue JS_NewString(JSContext *ctx, const char *str)
3957
2.32M
{
3958
2.32M
    return JS_NewStringLen(ctx, str, strlen(str));
3959
2.32M
}
3960
3961
JSValue JS_NewAtomString(JSContext *ctx, const char *str)
3962
26
{
3963
26
    JSAtom atom = JS_NewAtom(ctx, str);
3964
26
    if (atom == JS_ATOM_NULL)
3965
0
        return JS_EXCEPTION;
3966
26
    JSValue val = JS_AtomToString(ctx, atom);
3967
26
    JS_FreeAtom(ctx, atom);
3968
26
    return val;
3969
26
}
3970
3971
/* return (NULL, 0) if exception. */
3972
/* return pointer into a JSString with a live ref_count */
3973
/* cesu8 determines if non-BMP1 codepoints are encoded as 1 or 2 utf-8 sequences */
3974
const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, BOOL cesu8)
3975
775k
{
3976
775k
    JSValue val;
3977
775k
    JSString *str, *str_new;
3978
775k
    int pos, len, c, c1;
3979
775k
    uint8_t *q;
3980
3981
775k
    if (JS_VALUE_GET_TAG(val1) != JS_TAG_STRING) {
3982
52
        val = JS_ToString(ctx, val1);
3983
52
        if (JS_IsException(val))
3984
0
            goto fail;
3985
775k
    } else {
3986
775k
        val = JS_DupValue(ctx, val1);
3987
775k
    }
3988
3989
775k
    str = JS_VALUE_GET_STRING(val);
3990
775k
    len = str->len;
3991
775k
    if (!str->is_wide_char) {
3992
548k
        const uint8_t *src = str->u.str8;
3993
548k
        int count;
3994
3995
        /* count the number of non-ASCII characters */
3996
        /* Scanning the whole string is required for ASCII strings,
3997
           and computing the number of non-ASCII bytes is less expensive
3998
           than testing each byte, hence this method is faster for ASCII
3999
           strings, which is the most common case.
4000
         */
4001
548k
        count = 0;
4002
9.09M
        for (pos = 0; pos < len; pos++) {
4003
8.54M
            count += src[pos] >> 7;
4004
8.54M
        }
4005
548k
        if (count == 0) {
4006
546k
            if (plen)
4007
327k
                *plen = len;
4008
546k
            return (const char *)src;
4009
546k
        }
4010
2.71k
        str_new = js_alloc_string(ctx, len + count, 0);
4011
2.71k
        if (!str_new)
4012
0
            goto fail;
4013
2.71k
        q = str_new->u.str8;
4014
192k
        for (pos = 0; pos < len; pos++) {
4015
190k
            c = src[pos];
4016
190k
            if (c < 0x80) {
4017
187k
                *q++ = c;
4018
187k
            } else {
4019
2.71k
                *q++ = (c >> 6) | 0xc0;
4020
2.71k
                *q++ = (c & 0x3f) | 0x80;
4021
2.71k
            }
4022
190k
        }
4023
226k
    } else {
4024
226k
        const uint16_t *src = str->u.str16;
4025
        /* Allocate 3 bytes per 16 bit code point. Surrogate pairs may
4026
           produce 4 bytes but use 2 code points.
4027
         */
4028
226k
        str_new = js_alloc_string(ctx, len * 3, 0);
4029
226k
        if (!str_new)
4030
0
            goto fail;
4031
226k
        q = str_new->u.str8;
4032
226k
        pos = 0;
4033
29.8M
        while (pos < len) {
4034
29.6M
            c = src[pos++];
4035
29.6M
            if (c < 0x80) {
4036
28.2M
                *q++ = c;
4037
28.2M
            } else {
4038
1.33M
                if (c >= 0xd800 && c < 0xdc00) {
4039
1.79k
                    if (pos < len && !cesu8) {
4040
1.69k
                        c1 = src[pos];
4041
1.69k
                        if (c1 >= 0xdc00 && c1 < 0xe000) {
4042
1.53k
                            pos++;
4043
                            /* surrogate pair */
4044
1.53k
                            c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
4045
1.53k
                        } else {
4046
                            /* Keep unmatched surrogate code points */
4047
                            /* c = 0xfffd; */ /* error */
4048
166
                        }
4049
1.69k
                    } else {
4050
                        /* Keep unmatched surrogate code points */
4051
                        /* c = 0xfffd; */ /* error */
4052
93
                    }
4053
1.79k
                }
4054
1.33M
                q += unicode_to_utf8(q, c);
4055
1.33M
            }
4056
29.6M
        }
4057
226k
    }
4058
4059
229k
    *q = '\0';
4060
229k
    str_new->len = q - str_new->u.str8;
4061
229k
    JS_FreeValue(ctx, val);
4062
229k
    if (plen)
4063
219k
        *plen = str_new->len;
4064
229k
    return (const char *)str_new->u.str8;
4065
0
 fail:
4066
0
    if (plen)
4067
0
        *plen = 0;
4068
0
    return NULL;
4069
775k
}
4070
4071
void JS_FreeCString(JSContext *ctx, const char *ptr)
4072
775k
{
4073
775k
    JSString *p;
4074
775k
    if (!ptr)
4075
165
        return;
4076
    /* purposely removing constness */
4077
775k
    p = (JSString *)(void *)(ptr - offsetof(JSString, u));
4078
775k
    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
4079
775k
}
4080
4081
static int memcmp16_8(const uint16_t *src1, const uint8_t *src2, int len)
4082
669
{
4083
669
    int c, i;
4084
671
    for(i = 0; i < len; i++) {
4085
660
        c = src1[i] - src2[i];
4086
660
        if (c != 0)
4087
658
            return c;
4088
660
    }
4089
11
    return 0;
4090
669
}
4091
4092
static int memcmp16(const uint16_t *src1, const uint16_t *src2, int len)
4093
3.17k
{
4094
3.17k
    int c, i;
4095
67.5k
    for(i = 0; i < len; i++) {
4096
64.4k
        c = src1[i] - src2[i];
4097
64.4k
        if (c != 0)
4098
31
            return c;
4099
64.4k
    }
4100
3.14k
    return 0;
4101
3.17k
}
4102
4103
static int js_string_memcmp(const JSString *p1, const JSString *p2, int len)
4104
25.5k
{
4105
25.5k
    int res;
4106
4107
25.5k
    if (likely(!p1->is_wide_char)) {
4108
22.3k
        if (likely(!p2->is_wide_char))
4109
21.7k
            res = memcmp(p1->u.str8, p2->u.str8, len);
4110
590
        else
4111
590
            res = -memcmp16_8(p2->u.str16, p1->u.str8, len);
4112
22.3k
    } else {
4113
3.25k
        if (!p2->is_wide_char)
4114
79
            res = memcmp16_8(p1->u.str16, p2->u.str8, len);
4115
3.17k
        else
4116
3.17k
            res = memcmp16(p1->u.str16, p2->u.str16, len);
4117
3.25k
    }
4118
25.5k
    return res;
4119
25.5k
}
4120
4121
/* return < 0, 0 or > 0 */
4122
static int js_string_compare(JSContext *ctx,
4123
                             const JSString *p1, const JSString *p2)
4124
1.07k
{
4125
1.07k
    int res, len;
4126
1.07k
    len = min_int(p1->len, p2->len);
4127
1.07k
    res = js_string_memcmp(p1, p2, len);
4128
1.07k
    if (res == 0) {
4129
332
        if (p1->len == p2->len)
4130
8
            res = 0;
4131
324
        else if (p1->len < p2->len)
4132
302
            res = -1;
4133
22
        else
4134
22
            res = 1;
4135
332
    }
4136
1.07k
    return res;
4137
1.07k
}
4138
4139
static void copy_str16(uint16_t *dst, const JSString *p, int offset, int len)
4140
14.8k
{
4141
14.8k
    if (p->is_wide_char) {
4142
8.42k
        memcpy(dst, p->u.str16 + offset, len * 2);
4143
8.42k
    } else {
4144
6.42k
        const uint8_t *src1 = p->u.str8 + offset;
4145
6.42k
        int i;
4146
4147
1.51M
        for(i = 0; i < len; i++)
4148
1.50M
            dst[i] = src1[i];
4149
6.42k
    }
4150
14.8k
}
4151
4152
static JSValue JS_ConcatString1(JSContext *ctx,
4153
                                const JSString *p1, const JSString *p2)
4154
270k
{
4155
270k
    JSString *p;
4156
270k
    uint32_t len;
4157
270k
    int is_wide_char;
4158
4159
270k
    len = p1->len + p2->len;
4160
270k
    if (len > JS_STRING_LEN_MAX)
4161
0
        return JS_ThrowInternalError(ctx, "string too long");
4162
270k
    is_wide_char = p1->is_wide_char | p2->is_wide_char;
4163
270k
    p = js_alloc_string(ctx, len, is_wide_char);
4164
270k
    if (!p)
4165
0
        return JS_EXCEPTION;
4166
270k
    if (!is_wide_char) {
4167
262k
        memcpy(p->u.str8, p1->u.str8, p1->len);
4168
262k
        memcpy(p->u.str8 + p1->len, p2->u.str8, p2->len);
4169
262k
        p->u.str8[len] = '\0';
4170
262k
    } else {
4171
7.42k
        copy_str16(p->u.str16, p1, 0, p1->len);
4172
7.42k
        copy_str16(p->u.str16 + p1->len, p2, 0, p2->len);
4173
7.42k
    }
4174
270k
    return JS_MKPTR(JS_TAG_STRING, p);
4175
270k
}
4176
4177
/* op1 and op2 are converted to strings. For convience, op1 or op2 =
4178
   JS_EXCEPTION are accepted and return JS_EXCEPTION.  */
4179
static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2)
4180
279k
{
4181
279k
    JSValue ret;
4182
279k
    JSString *p1, *p2;
4183
4184
279k
    if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING)) {
4185
108k
        op1 = JS_ToStringFree(ctx, op1);
4186
108k
        if (JS_IsException(op1)) {
4187
0
            JS_FreeValue(ctx, op2);
4188
0
            return JS_EXCEPTION;
4189
0
        }
4190
108k
    }
4191
279k
    if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING)) {
4192
164k
        op2 = JS_ToStringFree(ctx, op2);
4193
164k
        if (JS_IsException(op2)) {
4194
0
            JS_FreeValue(ctx, op1);
4195
0
            return JS_EXCEPTION;
4196
0
        }
4197
164k
    }
4198
279k
    p1 = JS_VALUE_GET_STRING(op1);
4199
279k
    p2 = JS_VALUE_GET_STRING(op2);
4200
4201
    /* XXX: could also check if p1 is empty */
4202
279k
    if (p2->len == 0) {
4203
399
        goto ret_op1;
4204
399
    }
4205
278k
    if (p1->header.ref_count == 1 && p1->is_wide_char == p2->is_wide_char
4206
278k
    &&  js_malloc_usable_size(ctx, p1) >= sizeof(*p1) + ((p1->len + p2->len) << p2->is_wide_char) + 1 - p1->is_wide_char) {
4207
        /* Concatenate in place in available space at the end of p1 */
4208
8.84k
        if (p1->is_wide_char) {
4209
0
            memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1);
4210
0
            p1->len += p2->len;
4211
8.84k
        } else {
4212
8.84k
            memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len);
4213
8.84k
            p1->len += p2->len;
4214
8.84k
            p1->u.str8[p1->len] = '\0';
4215
8.84k
        }
4216
9.24k
    ret_op1:
4217
9.24k
        JS_FreeValue(ctx, op2);
4218
9.24k
        return op1;
4219
8.84k
    }
4220
270k
    ret = JS_ConcatString1(ctx, p1, p2);
4221
270k
    JS_FreeValue(ctx, op1);
4222
270k
    JS_FreeValue(ctx, op2);
4223
270k
    return ret;
4224
278k
}
4225
4226
/* Shape support */
4227
4228
static inline size_t get_shape_size(size_t hash_size, size_t prop_size)
4229
6.66M
{
4230
6.66M
    return hash_size * sizeof(uint32_t) + sizeof(JSShape) +
4231
6.66M
        prop_size * sizeof(JSShapeProperty);
4232
6.66M
}
4233
4234
static inline JSShape *get_shape_from_alloc(void *sh_alloc, size_t hash_size)
4235
6.66M
{
4236
6.66M
    return (JSShape *)(void *)((uint32_t *)sh_alloc + hash_size);
4237
6.66M
}
4238
4239
static inline uint32_t *prop_hash_end(JSShape *sh)
4240
108M
{
4241
108M
    return (uint32_t *)sh;
4242
108M
}
4243
4244
static inline void *get_alloc_from_shape(JSShape *sh)
4245
7.58M
{
4246
7.58M
    return prop_hash_end(sh) - ((intptr_t)sh->prop_hash_mask + 1);
4247
7.58M
}
4248
4249
static inline JSShapeProperty *get_shape_prop(JSShape *sh)
4250
103M
{
4251
103M
    return sh->prop;
4252
103M
}
4253
4254
static int init_shape_hash(JSRuntime *rt)
4255
3
{
4256
3
    rt->shape_hash_bits = 4;   /* 16 shapes */
4257
3
    rt->shape_hash_size = 1 << rt->shape_hash_bits;
4258
3
    rt->shape_hash_count = 0;
4259
3
    rt->shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
4260
3
                                   rt->shape_hash_size);
4261
3
    if (!rt->shape_hash)
4262
0
        return -1;
4263
3
    return 0;
4264
3
}
4265
4266
/* same magic hash multiplier as the Linux kernel */
4267
static uint32_t shape_hash(uint32_t h, uint32_t val)
4268
70.5M
{
4269
70.5M
    return (h + val) * 0x9e370001;
4270
70.5M
}
4271
4272
/* truncate the shape hash to 'hash_bits' bits */
4273
static uint32_t get_shape_hash(uint32_t h, int hash_bits)
4274
51.0M
{
4275
51.0M
    return h >> (32 - hash_bits);
4276
51.0M
}
4277
4278
static uint32_t shape_initial_hash(JSObject *proto)
4279
12.5M
{
4280
12.5M
    uint32_t h;
4281
12.5M
    h = shape_hash(1, (uintptr_t)proto);
4282
12.5M
    if (sizeof(proto) > 4)
4283
12.5M
        h = shape_hash(h, (uint64_t)(uintptr_t)proto >> 32);
4284
12.5M
    return h;
4285
12.5M
}
4286
4287
static int resize_shape_hash(JSRuntime *rt, int new_shape_hash_bits)
4288
12
{
4289
12
    int new_shape_hash_size, i;
4290
12
    uint32_t h;
4291
12
    JSShape **new_shape_hash, *sh, *sh_next;
4292
4293
12
    new_shape_hash_size = 1 << new_shape_hash_bits;
4294
12
    new_shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
4295
12
                                   new_shape_hash_size);
4296
12
    if (!new_shape_hash)
4297
0
        return -1;
4298
8.30k
    for(i = 0; i < rt->shape_hash_size; i++) {
4299
12.4k
        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh_next) {
4300
4.14k
            sh_next = sh->shape_hash_next;
4301
4.14k
            h = get_shape_hash(sh->hash, new_shape_hash_bits);
4302
4.14k
            sh->shape_hash_next = new_shape_hash[h];
4303
4.14k
            new_shape_hash[h] = sh;
4304
4.14k
        }
4305
8.28k
    }
4306
12
    js_free_rt(rt, rt->shape_hash);
4307
12
    rt->shape_hash_bits = new_shape_hash_bits;
4308
12
    rt->shape_hash_size = new_shape_hash_size;
4309
12
    rt->shape_hash = new_shape_hash;
4310
12
    return 0;
4311
12
}
4312
4313
static void js_shape_hash_link(JSRuntime *rt, JSShape *sh)
4314
14.8M
{
4315
14.8M
    uint32_t h;
4316
14.8M
    h = get_shape_hash(sh->hash, rt->shape_hash_bits);
4317
14.8M
    sh->shape_hash_next = rt->shape_hash[h];
4318
14.8M
    rt->shape_hash[h] = sh;
4319
14.8M
    rt->shape_hash_count++;
4320
14.8M
}
4321
4322
static void js_shape_hash_unlink(JSRuntime *rt, JSShape *sh)
4323
14.8M
{
4324
14.8M
    uint32_t h;
4325
14.8M
    JSShape **psh;
4326
4327
14.8M
    h = get_shape_hash(sh->hash, rt->shape_hash_bits);
4328
14.8M
    psh = &rt->shape_hash[h];
4329
14.8M
    while (*psh != sh)
4330
2.45k
        psh = &(*psh)->shape_hash_next;
4331
14.8M
    *psh = sh->shape_hash_next;
4332
14.8M
    rt->shape_hash_count--;
4333
14.8M
}
4334
4335
/* create a new empty shape with prototype 'proto' */
4336
static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto,
4337
                                        int hash_size, int prop_size)
4338
4.99M
{
4339
4.99M
    JSRuntime *rt = ctx->rt;
4340
4.99M
    void *sh_alloc;
4341
4.99M
    JSShape *sh;
4342
4343
    /* resize the shape hash table if necessary */
4344
4.99M
    if (2 * (rt->shape_hash_count + 1) > rt->shape_hash_size) {
4345
12
        resize_shape_hash(rt, rt->shape_hash_bits + 1);
4346
12
    }
4347
4348
4.99M
    sh_alloc = js_malloc(ctx, get_shape_size(hash_size, prop_size));
4349
4.99M
    if (!sh_alloc)
4350
56
        return NULL;
4351
4.99M
    sh = get_shape_from_alloc(sh_alloc, hash_size);
4352
4.99M
    sh->header.ref_count = 1;
4353
4.99M
    add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
4354
4.99M
    if (proto)
4355
4.64M
        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, proto));
4356
4.99M
    sh->proto = proto;
4357
4.99M
    memset(prop_hash_end(sh) - hash_size, 0, sizeof(prop_hash_end(sh)[0]) *
4358
4.99M
           hash_size);
4359
4.99M
    sh->prop_hash_mask = hash_size - 1;
4360
4.99M
    sh->prop_size = prop_size;
4361
4.99M
    sh->prop_count = 0;
4362
4.99M
    sh->deleted_prop_count = 0;
4363
    
4364
    /* insert in the hash table */
4365
4.99M
    sh->hash = shape_initial_hash(proto);
4366
4.99M
    sh->is_hashed = TRUE;
4367
4.99M
    sh->has_small_array_index = FALSE;
4368
4.99M
    js_shape_hash_link(ctx->rt, sh);
4369
4.99M
    return sh;
4370
4.99M
}
4371
4372
static JSShape *js_new_shape(JSContext *ctx, JSObject *proto)
4373
4.99M
{
4374
4.99M
    return js_new_shape2(ctx, proto, JS_PROP_INITIAL_HASH_SIZE,
4375
4.99M
                         JS_PROP_INITIAL_SIZE);
4376
4.99M
}
4377
4378
/* The shape is cloned. The new shape is not inserted in the shape
4379
   hash table */
4380
static JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1)
4381
925k
{
4382
925k
    JSShape *sh;
4383
925k
    void *sh_alloc, *sh_alloc1;
4384
925k
    size_t size;
4385
925k
    JSShapeProperty *pr;
4386
925k
    uint32_t i, hash_size;
4387
4388
925k
    hash_size = sh1->prop_hash_mask + 1;
4389
925k
    size = get_shape_size(hash_size, sh1->prop_size);
4390
925k
    sh_alloc = js_malloc(ctx, size);
4391
925k
    if (!sh_alloc)
4392
5
        return NULL;
4393
925k
    sh_alloc1 = get_alloc_from_shape(sh1);
4394
925k
    memcpy(sh_alloc, sh_alloc1, size);
4395
925k
    sh = get_shape_from_alloc(sh_alloc, hash_size);
4396
925k
    sh->header.ref_count = 1;
4397
925k
    add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
4398
925k
    sh->is_hashed = FALSE;
4399
925k
    if (sh->proto) {
4400
844k
        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
4401
844k
    }
4402
2.66M
    for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
4403
1.73M
        JS_DupAtom(ctx, pr->atom);
4404
1.73M
    }
4405
925k
    return sh;
4406
925k
}
4407
4408
static JSShape *js_dup_shape(JSShape *sh)
4409
8.28M
{
4410
8.28M
    sh->header.ref_count++;
4411
8.28M
    return sh;
4412
8.28M
}
4413
4414
static void js_free_shape0(JSRuntime *rt, JSShape *sh)
4415
5.91M
{
4416
5.91M
    uint32_t i;
4417
5.91M
    JSShapeProperty *pr;
4418
4419
5.91M
    assert(sh->header.ref_count == 0);
4420
5.91M
    if (sh->is_hashed)
4421
5.89M
        js_shape_hash_unlink(rt, sh);
4422
5.91M
    if (sh->proto != NULL) {
4423
5.48M
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
4424
5.48M
    }
4425
5.91M
    pr = get_shape_prop(sh);
4426
16.5M
    for(i = 0; i < sh->prop_count; i++) {
4427
10.6M
        JS_FreeAtomRT(rt, pr->atom);
4428
10.6M
        pr++;
4429
10.6M
    }
4430
5.91M
    remove_gc_object(&sh->header);
4431
5.91M
    js_free_rt(rt, get_alloc_from_shape(sh));
4432
5.91M
}
4433
4434
static void js_free_shape(JSRuntime *rt, JSShape *sh)
4435
13.9M
{
4436
13.9M
    if (unlikely(--sh->header.ref_count <= 0)) {
4437
5.91M
        js_free_shape0(rt, sh);
4438
5.91M
    }
4439
13.9M
}
4440
4441
static void js_free_shape_null(JSRuntime *rt, JSShape *sh)
4442
0
{
4443
0
    if (sh)
4444
0
        js_free_shape(rt, sh);
4445
0
}
4446
4447
/* make space to hold at least 'count' properties */
4448
static no_inline int resize_properties(JSContext *ctx, JSShape **psh,
4449
                                       JSObject *p, uint32_t count)
4450
745k
{
4451
745k
    JSShape *sh;
4452
745k
    uint32_t new_size, new_hash_size, new_hash_mask, i;
4453
745k
    JSShapeProperty *pr;
4454
745k
    void *sh_alloc;
4455
745k
    intptr_t h;
4456
4457
745k
    sh = *psh;
4458
745k
    new_size = max_int(count, sh->prop_size * 3 / 2);
4459
    /* Reallocate prop array first to avoid crash or size inconsistency
4460
       in case of memory allocation failure */
4461
745k
    if (p) {
4462
745k
        JSProperty *new_prop;
4463
745k
        new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
4464
745k
        if (unlikely(!new_prop))
4465
39
            return -1;
4466
745k
        p->prop = new_prop;
4467
745k
    }
4468
745k
    new_hash_size = sh->prop_hash_mask + 1;
4469
958k
    while (new_hash_size < new_size)
4470
212k
        new_hash_size = 2 * new_hash_size;
4471
745k
    if (new_hash_size != (sh->prop_hash_mask + 1)) {
4472
212k
        JSShape *old_sh;
4473
        /* resize the hash table and the properties */
4474
212k
        old_sh = sh;
4475
212k
        sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
4476
212k
        if (!sh_alloc)
4477
24
            return -1;
4478
212k
        sh = get_shape_from_alloc(sh_alloc, new_hash_size);
4479
212k
        list_del(&old_sh->header.link);
4480
        /* copy all the fields and the properties */
4481
212k
        memcpy(sh, old_sh,
4482
212k
               sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count);
4483
212k
        list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
4484
212k
        new_hash_mask = new_hash_size - 1;
4485
212k
        sh->prop_hash_mask = new_hash_mask;
4486
212k
        memset(prop_hash_end(sh) - new_hash_size, 0,
4487
212k
               sizeof(prop_hash_end(sh)[0]) * new_hash_size);
4488
6.79M
        for(i = 0, pr = sh->prop; i < sh->prop_count; i++, pr++) {
4489
6.58M
            if (pr->atom != JS_ATOM_NULL) {
4490
6.58M
                h = ((uintptr_t)pr->atom & new_hash_mask);
4491
6.58M
                pr->hash_next = prop_hash_end(sh)[-h - 1];
4492
6.58M
                prop_hash_end(sh)[-h - 1] = i + 1;
4493
6.58M
            }
4494
6.58M
        }
4495
212k
        js_free(ctx, get_alloc_from_shape(old_sh));
4496
532k
    } else {
4497
        /* only resize the properties */
4498
532k
        list_del(&sh->header.link);
4499
532k
        sh_alloc = js_realloc(ctx, get_alloc_from_shape(sh),
4500
532k
                              get_shape_size(new_hash_size, new_size));
4501
532k
        if (unlikely(!sh_alloc)) {
4502
            /* insert again in the GC list */
4503
0
            list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
4504
0
            return -1;
4505
0
        }
4506
532k
        sh = get_shape_from_alloc(sh_alloc, new_hash_size);
4507
532k
        list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
4508
532k
    }
4509
745k
    *psh = sh;
4510
745k
    sh->prop_size = new_size;
4511
745k
    return 0;
4512
745k
}
4513
4514
/* remove the deleted properties. */
4515
static int compact_properties(JSContext *ctx, JSObject *p)
4516
6
{
4517
6
    JSShape *sh, *old_sh;
4518
6
    void *sh_alloc;
4519
6
    intptr_t h;
4520
6
    uint32_t new_hash_size, i, j, new_hash_mask, new_size;
4521
6
    JSShapeProperty *old_pr, *pr;
4522
6
    JSProperty *prop, *new_prop;
4523
    
4524
6
    sh = p->shape;
4525
6
    assert(!sh->is_hashed);
4526
4527
6
    new_size = max_int(JS_PROP_INITIAL_SIZE,
4528
6
                       sh->prop_count - sh->deleted_prop_count);
4529
6
    assert(new_size <= sh->prop_size);
4530
4531
6
    new_hash_size = sh->prop_hash_mask + 1;
4532
12
    while ((new_hash_size / 2) >= new_size)
4533
6
        new_hash_size = new_hash_size / 2;
4534
6
    new_hash_mask = new_hash_size - 1;
4535
4536
    /* resize the hash table and the properties */
4537
6
    old_sh = sh;
4538
6
    sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
4539
6
    if (!sh_alloc)
4540
0
        return -1;
4541
6
    sh = get_shape_from_alloc(sh_alloc, new_hash_size);
4542
6
    list_del(&old_sh->header.link);
4543
6
    memcpy(sh, old_sh, sizeof(JSShape));
4544
6
    list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
4545
    
4546
6
    memset(prop_hash_end(sh) - new_hash_size, 0,
4547
6
           sizeof(prop_hash_end(sh)[0]) * new_hash_size);
4548
4549
6
    j = 0;
4550
6
    old_pr = old_sh->prop;
4551
6
    pr = sh->prop;
4552
6
    prop = p->prop;
4553
1.93k
    for(i = 0; i < sh->prop_count; i++) {
4554
1.92k
        if (old_pr->atom != JS_ATOM_NULL) {
4555
966
            pr->atom = old_pr->atom;
4556
966
            pr->flags = old_pr->flags;
4557
966
            h = ((uintptr_t)old_pr->atom & new_hash_mask);
4558
966
            pr->hash_next = prop_hash_end(sh)[-h - 1];
4559
966
            prop_hash_end(sh)[-h - 1] = j + 1;
4560
966
            prop[j] = prop[i];
4561
966
            j++;
4562
966
            pr++;
4563
966
        }
4564
1.92k
        old_pr++;
4565
1.92k
    }
4566
6
    assert(j == (sh->prop_count - sh->deleted_prop_count));
4567
6
    sh->prop_hash_mask = new_hash_mask;
4568
6
    sh->prop_size = new_size;
4569
6
    sh->deleted_prop_count = 0;
4570
6
    sh->prop_count = j;
4571
4572
6
    p->shape = sh;
4573
6
    js_free(ctx, get_alloc_from_shape(old_sh));
4574
    
4575
    /* reduce the size of the object properties */
4576
6
    new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
4577
6
    if (new_prop)
4578
6
        p->prop = new_prop;
4579
6
    return 0;
4580
6
}
4581
4582
static int add_shape_property(JSContext *ctx, JSShape **psh,
4583
                              JSObject *p, JSAtom atom, int prop_flags)
4584
8.98M
{
4585
8.98M
    JSRuntime *rt = ctx->rt;
4586
8.98M
    JSShape *sh = *psh;
4587
8.98M
    JSShapeProperty *pr, *prop;
4588
8.98M
    uint32_t hash_mask, new_shape_hash = 0;
4589
8.98M
    intptr_t h;
4590
4591
    /* update the shape hash */
4592
8.98M
    if (sh->is_hashed) {
4593
8.93M
        js_shape_hash_unlink(rt, sh);
4594
8.93M
        new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags);
4595
8.93M
    }
4596
4597
8.98M
    if (unlikely(sh->prop_count >= sh->prop_size)) {
4598
745k
        if (resize_properties(ctx, psh, p, sh->prop_count + 1)) {
4599
            /* in case of error, reinsert in the hash table.
4600
               sh is still valid if resize_properties() failed */
4601
63
            if (sh->is_hashed)
4602
63
                js_shape_hash_link(rt, sh);
4603
63
            return -1;
4604
63
        }
4605
745k
        sh = *psh;
4606
745k
    }
4607
8.98M
    if (sh->is_hashed) {
4608
8.93M
        sh->hash = new_shape_hash;
4609
8.93M
        js_shape_hash_link(rt, sh);
4610
8.93M
    }
4611
    /* Initialize the new shape property.
4612
       The object property at p->prop[sh->prop_count] is uninitialized */
4613
8.98M
    prop = get_shape_prop(sh);
4614
8.98M
    pr = &prop[sh->prop_count++];
4615
8.98M
    pr->atom = JS_DupAtom(ctx, atom);
4616
8.98M
    pr->flags = prop_flags;
4617
8.98M
    sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom);
4618
    /* add in hash table */
4619
8.98M
    hash_mask = sh->prop_hash_mask;
4620
8.98M
    h = atom & hash_mask;
4621
8.98M
    pr->hash_next = prop_hash_end(sh)[-h - 1];
4622
8.98M
    prop_hash_end(sh)[-h - 1] = sh->prop_count;
4623
8.98M
    return 0;
4624
8.98M
}
4625
4626
/* find a hashed empty shape matching the prototype. Return NULL if
4627
   not found */
4628
static JSShape *find_hashed_shape_proto(JSRuntime *rt, JSObject *proto)
4629
7.50M
{
4630
7.50M
    JSShape *sh1;
4631
7.50M
    uint32_t h, h1;
4632
4633
7.50M
    h = shape_initial_hash(proto);
4634
7.50M
    h1 = get_shape_hash(h, rt->shape_hash_bits);
4635
7.92M
    for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
4636
2.93M
        if (sh1->hash == h &&
4637
2.93M
            sh1->proto == proto &&
4638
2.93M
            sh1->prop_count == 0) {
4639
2.51M
            return sh1;
4640
2.51M
        }
4641
2.93M
    }
4642
4.99M
    return NULL;
4643
7.50M
}
4644
4645
/* find a hashed shape matching sh + (prop, prop_flags). Return NULL if
4646
   not found */
4647
static JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh,
4648
                                       JSAtom atom, int prop_flags)
4649
13.8M
{
4650
13.8M
    JSShape *sh1;
4651
13.8M
    uint32_t h, h1, i, n;
4652
4653
13.8M
    h = sh->hash;
4654
13.8M
    h = shape_hash(h, atom);
4655
13.8M
    h = shape_hash(h, prop_flags);
4656
13.8M
    h1 = get_shape_hash(h, rt->shape_hash_bits);
4657
16.5M
    for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
4658
        /* we test the hash first so that the rest is done only if the
4659
           shapes really match */
4660
7.61M
        if (sh1->hash == h &&
4661
7.61M
            sh1->proto == sh->proto &&
4662
7.61M
            sh1->prop_count == ((n = sh->prop_count) + 1)) {
4663
13.1M
            for(i = 0; i < n; i++) {
4664
8.24M
                if (unlikely(sh1->prop[i].atom != sh->prop[i].atom) ||
4665
8.24M
                    unlikely(sh1->prop[i].flags != sh->prop[i].flags))
4666
0
                    goto next;
4667
8.24M
            }
4668
4.89M
            if (unlikely(sh1->prop[n].atom != atom) ||
4669
4.89M
                unlikely(sh1->prop[n].flags != prop_flags))
4670
0
                goto next;
4671
4.89M
            return sh1;
4672
4.89M
        }
4673
2.71M
    next: ;
4674
2.71M
    }
4675
8.93M
    return NULL;
4676
13.8M
}
4677
4678
static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
4679
0
{
4680
0
    char atom_buf[ATOM_GET_STR_BUF_SIZE];
4681
0
    int j;
4682
0
4683
0
    /* XXX: should output readable class prototype */
4684
0
    printf("%5d %3d%c %14p %5d %5d", i,
4685
0
           sh->header.ref_count, " *"[sh->is_hashed],
4686
0
           (void *)sh->proto, sh->prop_size, sh->prop_count);
4687
0
    for(j = 0; j < sh->prop_count; j++) {
4688
0
        printf(" %s", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf),
4689
0
                                      sh->prop[j].atom));
4690
0
    }
4691
0
    printf("\n");
4692
0
}
4693
4694
static __maybe_unused void JS_DumpShapes(JSRuntime *rt)
4695
0
{
4696
0
    int i;
4697
0
    JSShape *sh;
4698
0
    struct list_head *el;
4699
0
    JSObject *p;
4700
0
    JSGCObjectHeader *gp;
4701
0
    
4702
0
    printf("JSShapes: {\n");
4703
0
    printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS");
4704
0
    for(i = 0; i < rt->shape_hash_size; i++) {
4705
0
        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
4706
0
            JS_DumpShape(rt, i, sh);
4707
0
            assert(sh->is_hashed);
4708
0
        }
4709
0
    }
4710
0
    /* dump non-hashed shapes */
4711
0
    list_for_each(el, &rt->gc_obj_list) {
4712
0
        gp = list_entry(el, JSGCObjectHeader, link);
4713
0
        if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
4714
0
            p = (JSObject *)gp;
4715
0
            if (!p->shape->is_hashed) {
4716
0
                JS_DumpShape(rt, -1, p->shape);
4717
0
            }
4718
0
        }
4719
0
    }
4720
0
    printf("}\n");
4721
0
}
4722
4723
static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID class_id)
4724
8.38M
{
4725
8.38M
    JSObject *p;
4726
4727
8.38M
    js_trigger_gc(ctx->rt, sizeof(JSObject));
4728
8.38M
    p = js_malloc(ctx, sizeof(JSObject));
4729
8.38M
    if (unlikely(!p))
4730
14
        goto fail;
4731
8.38M
    p->class_id = class_id;
4732
8.38M
    p->extensible = TRUE;
4733
8.38M
    p->free_mark = 0;
4734
8.38M
    p->is_exotic = 0;
4735
8.38M
    p->fast_array = 0;
4736
8.38M
    p->is_constructor = 0;
4737
8.38M
    p->is_uncatchable_error = 0;
4738
8.38M
    p->tmp_mark = 0;
4739
8.38M
    p->is_HTMLDDA = 0;
4740
8.38M
    p->first_weak_ref = NULL;
4741
8.38M
    p->u.opaque = NULL;
4742
8.38M
    p->shape = sh;
4743
8.38M
    p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size);
4744
8.38M
    if (unlikely(!p->prop)) {
4745
1
        js_free(ctx, p);
4746
15
    fail:
4747
15
        js_free_shape(ctx->rt, sh);
4748
15
        return JS_EXCEPTION;
4749
1
    }
4750
4751
8.38M
    switch(class_id) {
4752
1.66M
    case JS_CLASS_OBJECT:
4753
1.66M
        break;
4754
1.07M
    case JS_CLASS_ARRAY:
4755
1.07M
        {
4756
1.07M
            JSProperty *pr;
4757
1.07M
            p->is_exotic = 1;
4758
1.07M
            p->fast_array = 1;
4759
1.07M
            p->u.array.u.values = NULL;
4760
1.07M
            p->u.array.count = 0;
4761
1.07M
            p->u.array.u1.size = 0;
4762
            /* the length property is always the first one */
4763
1.07M
            if (likely(sh == ctx->array_shape)) {
4764
874k
                pr = &p->prop[0];
4765
874k
            } else {
4766
                /* only used for the first array */
4767
                /* cannot fail */
4768
201k
                pr = add_property(ctx, p, JS_ATOM_length,
4769
201k
                                  JS_PROP_WRITABLE | JS_PROP_LENGTH);
4770
201k
            }
4771
1.07M
            pr->u.value = JS_NewInt32(ctx, 0);
4772
1.07M
        }
4773
1.07M
        break;
4774
220
    case JS_CLASS_C_FUNCTION:
4775
220
        p->prop[0].u.value = JS_UNDEFINED;
4776
220
        break;
4777
0
    case JS_CLASS_ARGUMENTS:
4778
0
    case JS_CLASS_UINT8C_ARRAY:
4779
0
    case JS_CLASS_INT8_ARRAY:
4780
0
    case JS_CLASS_UINT8_ARRAY:
4781
0
    case JS_CLASS_INT16_ARRAY:
4782
0
    case JS_CLASS_UINT16_ARRAY:
4783
0
    case JS_CLASS_INT32_ARRAY:
4784
0
    case JS_CLASS_UINT32_ARRAY:
4785
0
#ifdef CONFIG_BIGNUM
4786
0
    case JS_CLASS_BIG_INT64_ARRAY:
4787
0
    case JS_CLASS_BIG_UINT64_ARRAY:
4788
0
#endif
4789
0
    case JS_CLASS_FLOAT32_ARRAY:
4790
0
    case JS_CLASS_FLOAT64_ARRAY:
4791
0
        p->is_exotic = 1;
4792
0
        p->fast_array = 1;
4793
0
        p->u.array.u.ptr = NULL;
4794
0
        p->u.array.count = 0;
4795
0
        break;
4796
0
    case JS_CLASS_DATAVIEW:
4797
0
        p->u.array.u.ptr = NULL;
4798
0
        p->u.array.count = 0;
4799
0
        break;
4800
730k
    case JS_CLASS_NUMBER:
4801
1.29M
    case JS_CLASS_STRING:
4802
1.29M
    case JS_CLASS_BOOLEAN:
4803
1.29M
    case JS_CLASS_SYMBOL:
4804
1.29M
    case JS_CLASS_DATE:
4805
1.29M
#ifdef CONFIG_BIGNUM
4806
1.29M
    case JS_CLASS_BIG_INT:
4807
1.29M
    case JS_CLASS_BIG_FLOAT:
4808
1.29M
    case JS_CLASS_BIG_DECIMAL:
4809
1.29M
#endif
4810
1.29M
        p->u.object_data = JS_UNDEFINED;
4811
1.29M
        goto set_exotic;
4812
19.5k
    case JS_CLASS_REGEXP:
4813
19.5k
        p->u.regexp.pattern = NULL;
4814
19.5k
        p->u.regexp.bytecode = NULL;
4815
19.5k
        goto set_exotic;
4816
4.32M
    default:
4817
5.63M
    set_exotic:
4818
5.63M
        if (ctx->rt->class_array[class_id].exotic) {
4819
560k
            p->is_exotic = 1;
4820
560k
        }
4821
5.63M
        break;
4822
8.38M
    }
4823
8.38M
    p->header.ref_count = 1;
4824
8.38M
    add_gc_object(ctx->rt, &p->header, JS_GC_OBJ_TYPE_JS_OBJECT);
4825
8.38M
    return JS_MKPTR(JS_TAG_OBJECT, p);
4826
8.38M
}
4827
4828
static JSObject *get_proto_obj(JSValueConst proto_val)
4829
7.50M
{
4830
7.50M
    if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT)
4831
746k
        return NULL;
4832
6.76M
    else
4833
6.76M
        return JS_VALUE_GET_OBJ(proto_val);
4834
7.50M
}
4835
4836
/* WARNING: proto must be an object or JS_NULL */
4837
JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto_val,
4838
                               JSClassID class_id)
4839
7.50M
{
4840
7.50M
    JSShape *sh;
4841
7.50M
    JSObject *proto;
4842
4843
7.50M
    proto = get_proto_obj(proto_val);
4844
7.50M
    sh = find_hashed_shape_proto(ctx->rt, proto);
4845
7.50M
    if (likely(sh)) {
4846
2.51M
        sh = js_dup_shape(sh);
4847
4.99M
    } else {
4848
4.99M
        sh = js_new_shape(ctx, proto);
4849
4.99M
        if (!sh)
4850
56
            return JS_EXCEPTION;
4851
4.99M
    }
4852
7.50M
    return JS_NewObjectFromShape(ctx, sh, class_id);
4853
7.50M
}
4854
4855
#if 0
4856
static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj)
4857
{
4858
    JSObject *p;
4859
4860
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
4861
        p = JS_VALUE_GET_OBJ(obj);
4862
        switch(p->class_id) {
4863
        case JS_CLASS_NUMBER:
4864
        case JS_CLASS_STRING:
4865
        case JS_CLASS_BOOLEAN:
4866
        case JS_CLASS_SYMBOL:
4867
        case JS_CLASS_DATE:
4868
#ifdef CONFIG_BIGNUM
4869
        case JS_CLASS_BIG_INT:
4870
        case JS_CLASS_BIG_FLOAT:
4871
        case JS_CLASS_BIG_DECIMAL:
4872
#endif
4873
            return JS_DupValue(ctx, p->u.object_data);
4874
        }
4875
    }
4876
    return JS_UNDEFINED;
4877
}
4878
#endif
4879
4880
static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val)
4881
1.29M
{
4882
1.29M
    JSObject *p;
4883
4884
1.29M
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
4885
1.29M
        p = JS_VALUE_GET_OBJ(obj);
4886
1.29M
        switch(p->class_id) {
4887
730k
        case JS_CLASS_NUMBER:
4888
1.29M
        case JS_CLASS_STRING:
4889
1.29M
        case JS_CLASS_BOOLEAN:
4890
1.29M
        case JS_CLASS_SYMBOL:
4891
1.29M
        case JS_CLASS_DATE:
4892
1.29M
#ifdef CONFIG_BIGNUM
4893
1.29M
        case JS_CLASS_BIG_INT:
4894
1.29M
        case JS_CLASS_BIG_FLOAT:
4895
1.29M
        case JS_CLASS_BIG_DECIMAL:
4896
1.29M
#endif
4897
1.29M
            JS_FreeValue(ctx, p->u.object_data);
4898
1.29M
            p->u.object_data = val;
4899
1.29M
            return 0;
4900
1.29M
        }
4901
1.29M
    }
4902
0
    JS_FreeValue(ctx, val);
4903
0
    if (!JS_IsException(obj))
4904
0
        JS_ThrowTypeError(ctx, "invalid object type");
4905
0
    return -1;
4906
1.29M
}
4907
4908
JSValue JS_NewObjectClass(JSContext *ctx, int class_id)
4909
3.60M
{
4910
3.60M
    return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id);
4911
3.60M
}
4912
4913
JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto)
4914
345k
{
4915
345k
    return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT);
4916
345k
}
4917
4918
JSValue JS_NewArray(JSContext *ctx)
4919
874k
{
4920
874k
    return JS_NewObjectFromShape(ctx, js_dup_shape(ctx->array_shape),
4921
874k
                                 JS_CLASS_ARRAY);
4922
874k
}
4923
4924
JSValue JS_NewObject(JSContext *ctx)
4925
1.10M
{
4926
    /* inline JS_NewObjectClass(ctx, JS_CLASS_OBJECT); */
4927
1.10M
    return JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT);
4928
1.10M
}
4929
4930
static void js_function_set_properties(JSContext *ctx, JSValueConst func_obj,
4931
                                       JSAtom name, int len)
4932
2.77M
{
4933
    /* ES6 feature non compatible with ES5.1: length is configurable */
4934
2.77M
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, JS_NewInt32(ctx, len),
4935
2.77M
                           JS_PROP_CONFIGURABLE);
4936
2.77M
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name,
4937
2.77M
                           JS_AtomToString(ctx, name), JS_PROP_CONFIGURABLE);
4938
2.77M
}
4939
4940
static BOOL js_class_has_bytecode(JSClassID class_id)
4941
1.32M
{
4942
1.32M
    return (class_id == JS_CLASS_BYTECODE_FUNCTION ||
4943
1.32M
            class_id == JS_CLASS_GENERATOR_FUNCTION ||
4944
1.32M
            class_id == JS_CLASS_ASYNC_FUNCTION ||
4945
1.32M
            class_id == JS_CLASS_ASYNC_GENERATOR_FUNCTION);
4946
1.32M
}
4947
4948
/* return NULL without exception if not a function or no bytecode */
4949
static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val)
4950
365
{
4951
365
    JSObject *p;
4952
365
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
4953
0
        return NULL;
4954
365
    p = JS_VALUE_GET_OBJ(val);
4955
365
    if (!js_class_has_bytecode(p->class_id))
4956
10
        return NULL;
4957
355
    return p->u.func.function_bytecode;
4958
365
}
4959
4960
static void js_method_set_home_object(JSContext *ctx, JSValueConst func_obj,
4961
                                      JSValueConst home_obj)
4962
1.03M
{
4963
1.03M
    JSObject *p, *p1;
4964
1.03M
    JSFunctionBytecode *b;
4965
4966
1.03M
    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
4967
0
        return;
4968
1.03M
    p = JS_VALUE_GET_OBJ(func_obj);
4969
1.03M
    if (!js_class_has_bytecode(p->class_id))
4970
0
        return;
4971
1.03M
    b = p->u.func.function_bytecode;
4972
1.03M
    if (b->need_home_object) {
4973
351k
        p1 = p->u.func.home_object;
4974
351k
        if (p1) {
4975
0
            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
4976
0
        }
4977
351k
        if (JS_VALUE_GET_TAG(home_obj) == JS_TAG_OBJECT)
4978
351k
            p1 = JS_VALUE_GET_OBJ(JS_DupValue(ctx, home_obj));
4979
0
        else
4980
0
            p1 = NULL;
4981
351k
        p->u.func.home_object = p1;
4982
351k
    }
4983
1.03M
}
4984
4985
static JSValue js_get_function_name(JSContext *ctx, JSAtom name)
4986
369k
{
4987
369k
    JSValue name_str;
4988
4989
369k
    name_str = JS_AtomToString(ctx, name);
4990
369k
    if (JS_AtomSymbolHasDescription(ctx, name)) {
4991
0
        name_str = JS_ConcatString3(ctx, "[", name_str, "]");
4992
0
    }
4993
369k
    return name_str;
4994
369k
}
4995
4996
/* Modify the name of a method according to the atom and
4997
   'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and
4998
   JS_PROP_HAS_SET. Also set the home object of the method.
4999
   Return < 0 if exception. */
5000
static int js_method_set_properties(JSContext *ctx, JSValueConst func_obj,
5001
                                    JSAtom name, int flags, JSValueConst home_obj)
5002
359k
{
5003
359k
    JSValue name_str;
5004
5005
359k
    name_str = js_get_function_name(ctx, name);
5006
359k
    if (flags & JS_PROP_HAS_GET) {
5007
0
        name_str = JS_ConcatString3(ctx, "get ", name_str, "");
5008
359k
    } else if (flags & JS_PROP_HAS_SET) {
5009
0
        name_str = JS_ConcatString3(ctx, "set ", name_str, "");
5010
0
    }
5011
359k
    if (JS_IsException(name_str))
5012
0
        return -1;
5013
359k
    if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name_str,
5014
359k
                               JS_PROP_CONFIGURABLE) < 0)
5015
0
        return -1;
5016
359k
    js_method_set_home_object(ctx, func_obj, home_obj);
5017
359k
    return 0;
5018
359k
}
5019
5020
/* Note: at least 'length' arguments will be readable in 'argv' */
5021
static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
5022
                                const char *name,
5023
                                int length, JSCFunctionEnum cproto, int magic,
5024
                                JSValueConst proto_val)
5025
220
{
5026
220
    JSValue func_obj;
5027
220
    JSObject *p;
5028
220
    JSAtom name_atom;
5029
    
5030
220
    func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION);
5031
220
    if (JS_IsException(func_obj))
5032
0
        return func_obj;
5033
220
    p = JS_VALUE_GET_OBJ(func_obj);
5034
220
    p->u.cfunc.realm = JS_DupContext(ctx);
5035
220
    p->u.cfunc.c_function.generic = func;
5036
220
    p->u.cfunc.length = length;
5037
220
    p->u.cfunc.cproto = cproto;
5038
220
    p->u.cfunc.magic = magic;
5039
220
    p->is_constructor = (cproto == JS_CFUNC_constructor ||
5040
220
                         cproto == JS_CFUNC_constructor_magic ||
5041
220
                         cproto == JS_CFUNC_constructor_or_func ||
5042
220
                         cproto == JS_CFUNC_constructor_or_func_magic);
5043
220
    if (!name)
5044
4
        name = "";
5045
220
    name_atom = JS_NewAtom(ctx, name);
5046
220
    js_function_set_properties(ctx, func_obj, name_atom, length);
5047
220
    JS_FreeAtom(ctx, name_atom);
5048
220
    return func_obj;
5049
220
}
5050
5051
/* Note: at least 'length' arguments will be readable in 'argv' */
5052
JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
5053
                         const char *name,
5054
                         int length, JSCFunctionEnum cproto, int magic)
5055
175
{
5056
175
    return JS_NewCFunction3(ctx, func, name, length, cproto, magic,
5057
175
                            ctx->function_proto);
5058
175
}
5059
5060
typedef struct JSCFunctionDataRecord {
5061
    JSCFunctionData *func;
5062
    uint8_t length;
5063
    uint8_t data_len;
5064
    uint16_t magic;
5065
    JSValue data[0];
5066
} JSCFunctionDataRecord;
5067
5068
static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val)
5069
208k
{
5070
208k
    JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
5071
208k
    int i;
5072
5073
208k
    if (s) {
5074
626k
        for(i = 0; i < s->data_len; i++) {
5075
417k
            JS_FreeValueRT(rt, s->data[i]);
5076
417k
        }
5077
208k
        js_free_rt(rt, s);
5078
208k
    }
5079
208k
}
5080
5081
static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
5082
                                    JS_MarkFunc *mark_func)
5083
24
{
5084
24
    JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
5085
24
    int i;
5086
5087
24
    if (s) {
5088
72
        for(i = 0; i < s->data_len; i++) {
5089
48
            JS_MarkValue(rt, s->data[i], mark_func);
5090
48
        }
5091
24
    }
5092
24
}
5093
5094
static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
5095
                                       JSValueConst this_val,
5096
                                       int argc, JSValueConst *argv, int flags)
5097
208k
{
5098
208k
    JSCFunctionDataRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA);
5099
208k
    JSValueConst *arg_buf;
5100
208k
    int i;
5101
5102
    /* XXX: could add the function on the stack for debug */
5103
208k
    if (unlikely(argc < s->length)) {
5104
0
        arg_buf = alloca(sizeof(arg_buf[0]) * s->length);
5105
0
        for(i = 0; i < argc; i++)
5106
0
            arg_buf[i] = argv[i];
5107
0
        for(i = argc; i < s->length; i++)
5108
0
            arg_buf[i] = JS_UNDEFINED;
5109
208k
    } else {
5110
208k
        arg_buf = argv;
5111
208k
    }
5112
5113
208k
    return s->func(ctx, this_val, argc, arg_buf, s->magic, s->data);
5114
208k
}
5115
5116
JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
5117
                            int length, int magic, int data_len,
5118
                            JSValueConst *data)
5119
208k
{
5120
208k
    JSCFunctionDataRecord *s;
5121
208k
    JSValue func_obj;
5122
208k
    int i;
5123
5124
208k
    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
5125
208k
                                      JS_CLASS_C_FUNCTION_DATA);
5126
208k
    if (JS_IsException(func_obj))
5127
0
        return func_obj;
5128
208k
    s = js_malloc(ctx, sizeof(*s) + data_len * sizeof(JSValue));
5129
208k
    if (!s) {
5130
0
        JS_FreeValue(ctx, func_obj);
5131
0
        return JS_EXCEPTION;
5132
0
    }
5133
208k
    s->func = func;
5134
208k
    s->length = length;
5135
208k
    s->data_len = data_len;
5136
208k
    s->magic = magic;
5137
626k
    for(i = 0; i < data_len; i++)
5138
417k
        s->data[i] = JS_DupValue(ctx, data[i]);
5139
208k
    JS_SetOpaque(func_obj, s);
5140
208k
    js_function_set_properties(ctx, func_obj,
5141
208k
                               JS_ATOM_empty_string, length);
5142
208k
    return func_obj;
5143
208k
}
5144
5145
static JSContext *js_autoinit_get_realm(JSProperty *pr)
5146
60.9k
{
5147
60.9k
    return (JSContext *)(pr->u.init.realm_and_id & ~3);
5148
60.9k
}
5149
5150
static JSAutoInitIDEnum js_autoinit_get_id(JSProperty *pr)
5151
55
{
5152
55
    return pr->u.init.realm_and_id & 3;
5153
55
}
5154
5155
static void js_autoinit_free(JSRuntime *rt, JSProperty *pr)
5156
932
{
5157
932
    JS_FreeContext(js_autoinit_get_realm(pr));
5158
932
}
5159
5160
static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr,
5161
                             JS_MarkFunc *mark_func)
5162
59.9k
{
5163
59.9k
    mark_func(rt, &js_autoinit_get_realm(pr)->header);
5164
59.9k
}
5165
5166
static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags)
5167
14.2M
{
5168
14.2M
    if (unlikely(prop_flags & JS_PROP_TMASK)) {
5169
13.2k
        if ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
5170
0
            if (pr->u.getset.getter)
5171
0
                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
5172
0
            if (pr->u.getset.setter)
5173
0
                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
5174
13.2k
        } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
5175
12.4k
            free_var_ref(rt, pr->u.var_ref);
5176
12.4k
        } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
5177
877
            js_autoinit_free(rt, pr);
5178
877
        }
5179
14.2M
    } else {
5180
14.2M
        JS_FreeValueRT(rt, pr->u.value);
5181
14.2M
    }
5182
14.2M
}
5183
5184
static force_inline JSShapeProperty *find_own_property1(JSObject *p,
5185
                                                        JSAtom atom)
5186
470k
{
5187
470k
    JSShape *sh;
5188
470k
    JSShapeProperty *pr, *prop;
5189
470k
    intptr_t h;
5190
470k
    sh = p->shape;
5191
470k
    h = (uintptr_t)atom & sh->prop_hash_mask;
5192
470k
    h = prop_hash_end(sh)[-h - 1];
5193
470k
    prop = get_shape_prop(sh);
5194
508k
    while (h) {
5195
79.6k
        pr = &prop[h - 1];
5196
79.6k
        if (likely(pr->atom == atom)) {
5197
41.6k
            return pr;
5198
41.6k
        }
5199
38.0k
        h = pr->hash_next;
5200
38.0k
    }
5201
429k
    return NULL;
5202
470k
}
5203
5204
static force_inline JSShapeProperty *find_own_property(JSProperty **ppr,
5205
                                                       JSObject *p,
5206
                                                       JSAtom atom)
5207
63.6M
{
5208
63.6M
    JSShape *sh;
5209
63.6M
    JSShapeProperty *pr, *prop;
5210
63.6M
    intptr_t h;
5211
63.6M
    sh = p->shape;
5212
63.6M
    h = (uintptr_t)atom & sh->prop_hash_mask;
5213
63.6M
    h = prop_hash_end(sh)[-h - 1];
5214
63.6M
    prop = get_shape_prop(sh);
5215
78.4M
    while (h) {
5216
30.4M
        pr = &prop[h - 1];
5217
30.4M
        if (likely(pr->atom == atom)) {
5218
15.6M
            *ppr = &p->prop[h - 1];
5219
            /* the compiler should be able to assume that pr != NULL here */
5220
15.6M
            return pr;
5221
15.6M
        }
5222
14.8M
        h = pr->hash_next;
5223
14.8M
    }
5224
48.0M
    *ppr = NULL;
5225
48.0M
    return NULL;
5226
63.6M
}
5227
5228
/* indicate that the object may be part of a function prototype cycle */
5229
static void set_cycle_flag(JSContext *ctx, JSValueConst obj)
5230
652k
{
5231
652k
}
5232
5233
static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref)
5234
1.66M
{
5235
1.66M
    if (var_ref) {
5236
1.66M
        assert(var_ref->header.ref_count > 0);
5237
1.66M
        if (--var_ref->header.ref_count == 0) {
5238
1.58M
            if (var_ref->is_detached) {
5239
1.57M
                JS_FreeValueRT(rt, var_ref->value);
5240
1.57M
                remove_gc_object(&var_ref->header);
5241
1.57M
            } else {
5242
7.86k
                list_del(&var_ref->header.link); /* still on the stack */
5243
7.86k
            }
5244
1.58M
            js_free_rt(rt, var_ref);
5245
1.58M
        }
5246
1.66M
    }
5247
1.66M
}
5248
5249
static void js_array_finalizer(JSRuntime *rt, JSValue val)
5250
1.07M
{
5251
1.07M
    JSObject *p = JS_VALUE_GET_OBJ(val);
5252
1.07M
    int i;
5253
5254
4.01M
    for(i = 0; i < p->u.array.count; i++) {
5255
2.94M
        JS_FreeValueRT(rt, p->u.array.u.values[i]);
5256
2.94M
    }
5257
1.07M
    js_free_rt(rt, p->u.array.u.values);
5258
1.07M
}
5259
5260
static void js_array_mark(JSRuntime *rt, JSValueConst val,
5261
                          JS_MarkFunc *mark_func)
5262
1.32k
{
5263
1.32k
    JSObject *p = JS_VALUE_GET_OBJ(val);
5264
1.32k
    int i;
5265
5266
1.32k
    for(i = 0; i < p->u.array.count; i++) {
5267
0
        JS_MarkValue(rt, p->u.array.u.values[i], mark_func);
5268
0
    }
5269
1.32k
}
5270
5271
static void js_object_data_finalizer(JSRuntime *rt, JSValue val)
5272
1.29M
{
5273
1.29M
    JSObject *p = JS_VALUE_GET_OBJ(val);
5274
1.29M
    JS_FreeValueRT(rt, p->u.object_data);
5275
1.29M
    p->u.object_data = JS_UNDEFINED;
5276
1.29M
}
5277
5278
static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
5279
                                JS_MarkFunc *mark_func)
5280
3.25k
{
5281
3.25k
    JSObject *p = JS_VALUE_GET_OBJ(val);
5282
3.25k
    JS_MarkValue(rt, p->u.object_data, mark_func);
5283
3.25k
}
5284
5285
static void js_c_function_finalizer(JSRuntime *rt, JSValue val)
5286
0
{
5287
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5288
5289
0
    if (p->u.cfunc.realm)
5290
0
        JS_FreeContext(p->u.cfunc.realm);
5291
0
}
5292
5293
static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
5294
                               JS_MarkFunc *mark_func)
5295
18.7k
{
5296
18.7k
    JSObject *p = JS_VALUE_GET_OBJ(val);
5297
5298
18.7k
    if (p->u.cfunc.realm)
5299
18.7k
        mark_func(rt, &p->u.cfunc.realm->header);
5300
18.7k
}
5301
5302
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val)
5303
2.47M
{
5304
2.47M
    JSObject *p1, *p = JS_VALUE_GET_OBJ(val);
5305
2.47M
    JSFunctionBytecode *b;
5306
2.47M
    JSVarRef **var_refs;
5307
2.47M
    int i;
5308
5309
2.47M
    p1 = p->u.func.home_object;
5310
2.47M
    if (p1) {
5311
351k
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, p1));
5312
351k
    }
5313
2.47M
    b = p->u.func.function_bytecode;
5314
2.47M
    if (b) {
5315
2.47M
        var_refs = p->u.func.var_refs;
5316
2.47M
        if (var_refs) {
5317
3.01M
            for(i = 0; i < b->closure_var_count; i++)
5318
1.64M
                free_var_ref(rt, var_refs[i]);
5319
1.36M
            js_free_rt(rt, var_refs);
5320
1.36M
        }
5321
2.47M
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b));
5322
2.47M
    }
5323
2.47M
}
5324
5325
static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
5326
                                      JS_MarkFunc *mark_func)
5327
3.11M
{
5328
3.11M
    JSObject *p = JS_VALUE_GET_OBJ(val);
5329
3.11M
    JSVarRef **var_refs = p->u.func.var_refs;
5330
3.11M
    JSFunctionBytecode *b = p->u.func.function_bytecode;
5331
3.11M
    int i;
5332
5333
3.11M
    if (p->u.func.home_object) {
5334
640k
        JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object),
5335
640k
                     mark_func);
5336
640k
    }
5337
3.11M
    if (b) {
5338
3.11M
        if (var_refs) {
5339
5.84M
            for(i = 0; i < b->closure_var_count; i++) {
5340
3.16M
                JSVarRef *var_ref = var_refs[i];
5341
3.16M
                if (var_ref && var_ref->is_detached) {
5342
3.16M
                    mark_func(rt, &var_ref->header);
5343
3.16M
                }
5344
3.16M
            }
5345
2.67M
        }
5346
        /* must mark the function bytecode because template objects may be
5347
           part of a cycle */
5348
3.11M
        JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func);
5349
3.11M
    }
5350
3.11M
}
5351
5352
static void js_bound_function_finalizer(JSRuntime *rt, JSValue val)
5353
0
{
5354
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5355
0
    JSBoundFunction *bf = p->u.bound_function;
5356
0
    int i;
5357
5358
0
    JS_FreeValueRT(rt, bf->func_obj);
5359
0
    JS_FreeValueRT(rt, bf->this_val);
5360
0
    for(i = 0; i < bf->argc; i++) {
5361
0
        JS_FreeValueRT(rt, bf->argv[i]);
5362
0
    }
5363
0
    js_free_rt(rt, bf);
5364
0
}
5365
5366
static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
5367
                                JS_MarkFunc *mark_func)
5368
0
{
5369
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5370
0
    JSBoundFunction *bf = p->u.bound_function;
5371
0
    int i;
5372
5373
0
    JS_MarkValue(rt, bf->func_obj, mark_func);
5374
0
    JS_MarkValue(rt, bf->this_val, mark_func);
5375
0
    for(i = 0; i < bf->argc; i++)
5376
0
        JS_MarkValue(rt, bf->argv[i], mark_func);
5377
0
}
5378
5379
static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val)
5380
734k
{
5381
734k
    JSObject *p = JS_VALUE_GET_OBJ(val);
5382
734k
    JSForInIterator *it = p->u.for_in_iterator;
5383
734k
    JS_FreeValueRT(rt, it->obj);
5384
734k
    js_free_rt(rt, it);
5385
734k
}
5386
5387
static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
5388
                                JS_MarkFunc *mark_func)
5389
640
{
5390
640
    JSObject *p = JS_VALUE_GET_OBJ(val);
5391
640
    JSForInIterator *it = p->u.for_in_iterator;
5392
640
    JS_MarkValue(rt, it->obj, mark_func);
5393
640
}
5394
5395
static void free_object(JSRuntime *rt, JSObject *p)
5396
8.08M
{
5397
8.08M
    int i;
5398
8.08M
    JSClassFinalizer *finalizer;
5399
8.08M
    JSShape *sh;
5400
8.08M
    JSShapeProperty *pr;
5401
5402
8.08M
    p->free_mark = 1; /* used to tell the object is invalid when
5403
                         freeing cycles */
5404
    /* free all the fields */
5405
8.08M
    sh = p->shape;
5406
8.08M
    pr = get_shape_prop(sh);
5407
22.3M
    for(i = 0; i < sh->prop_count; i++) {
5408
14.2M
        free_property(rt, &p->prop[i], pr->flags);
5409
14.2M
        pr++;
5410
14.2M
    }
5411
8.08M
    js_free_rt(rt, p->prop);
5412
    /* as an optimization we destroy the shape immediately without
5413
       putting it in gc_zero_ref_count_list */
5414
8.08M
    js_free_shape(rt, sh);
5415
5416
    /* fail safe */
5417
8.08M
    p->shape = NULL;
5418
8.08M
    p->prop = NULL;
5419
5420
8.08M
    if (unlikely(p->first_weak_ref)) {
5421
0
        reset_weak_ref(rt, p);
5422
0
    }
5423
5424
8.08M
    finalizer = rt->class_array[p->class_id].finalizer;
5425
8.08M
    if (finalizer)
5426
6.30M
        (*finalizer)(rt, JS_MKPTR(JS_TAG_OBJECT, p));
5427
5428
    /* fail safe */
5429
8.08M
    p->class_id = 0;
5430
8.08M
    p->u.opaque = NULL;
5431
8.08M
    p->u.func.var_refs = NULL;
5432
8.08M
    p->u.func.home_object = NULL;
5433
5434
8.08M
    remove_gc_object(&p->header);
5435
8.08M
    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && p->header.ref_count != 0) {
5436
864k
        list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list);
5437
7.21M
    } else {
5438
7.21M
        js_free_rt(rt, p);
5439
7.21M
    }
5440
8.08M
}
5441
5442
static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp)
5443
8.11M
{
5444
8.11M
    switch(gp->gc_obj_type) {
5445
8.08M
    case JS_GC_OBJ_TYPE_JS_OBJECT:
5446
8.08M
        free_object(rt, (JSObject *)gp);
5447
8.08M
        break;
5448
30.0k
    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
5449
30.0k
        free_function_bytecode(rt, (JSFunctionBytecode *)gp);
5450
30.0k
        break;
5451
0
    default:
5452
0
        abort();
5453
8.11M
    }
5454
8.11M
}
5455
5456
static void free_zero_refcount(JSRuntime *rt)
5457
5.85M
{
5458
5.85M
    struct list_head *el;
5459
5.85M
    JSGCObjectHeader *p;
5460
    
5461
5.85M
    rt->gc_phase = JS_GC_PHASE_DECREF;
5462
12.0M
    for(;;) {
5463
12.0M
        el = rt->gc_zero_ref_count_list.next;
5464
12.0M
        if (el == &rt->gc_zero_ref_count_list)
5465
5.85M
            break;
5466
6.20M
        p = list_entry(el, JSGCObjectHeader, link);
5467
6.20M
        assert(p->ref_count == 0);
5468
6.20M
        free_gc_object(rt, p);
5469
6.20M
    }
5470
5.85M
    rt->gc_phase = JS_GC_PHASE_NONE;
5471
5.85M
}
5472
5473
/* called with the ref_count of 'v' reaches zero. */
5474
void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
5475
16.6M
{
5476
16.6M
    uint32_t tag = JS_VALUE_GET_TAG(v);
5477
5478
#ifdef DUMP_FREE
5479
    {
5480
        printf("Freeing ");
5481
        if (tag == JS_TAG_OBJECT) {
5482
            JS_DumpObject(rt, JS_VALUE_GET_OBJ(v));
5483
        } else {
5484
            JS_DumpValueShort(rt, v);
5485
            printf("\n");
5486
        }
5487
    }
5488
#endif
5489
5490
16.6M
    switch(tag) {
5491
7.98M
    case JS_TAG_STRING:
5492
7.98M
        {
5493
7.98M
            JSString *p = JS_VALUE_GET_STRING(v);
5494
7.98M
            if (p->atom_type) {
5495
20.4k
                JS_FreeAtomStruct(rt, p);
5496
7.96M
            } else {
5497
#ifdef DUMP_LEAKS
5498
                list_del(&p->link);
5499
#endif
5500
7.96M
                js_free_rt(rt, p);
5501
7.96M
            }
5502
7.98M
        }
5503
7.98M
        break;
5504
8.08M
    case JS_TAG_OBJECT:
5505
8.11M
    case JS_TAG_FUNCTION_BYTECODE:
5506
8.11M
        {
5507
8.11M
            JSGCObjectHeader *p = JS_VALUE_GET_PTR(v);
5508
8.11M
            if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
5509
6.20M
                list_del(&p->link);
5510
6.20M
                list_add(&p->link, &rt->gc_zero_ref_count_list);
5511
6.20M
                if (rt->gc_phase == JS_GC_PHASE_NONE) {
5512
5.85M
                    free_zero_refcount(rt);
5513
5.85M
                }
5514
6.20M
            }
5515
8.11M
        }
5516
8.11M
        break;
5517
0
    case JS_TAG_MODULE:
5518
0
        abort(); /* never freed here */
5519
0
        break;
5520
0
#ifdef CONFIG_BIGNUM
5521
12.2k
    case JS_TAG_BIG_INT:
5522
12.2k
    case JS_TAG_BIG_FLOAT:
5523
12.2k
        {
5524
12.2k
            JSBigFloat *bf = JS_VALUE_GET_PTR(v);
5525
12.2k
            bf_delete(&bf->num);
5526
12.2k
            js_free_rt(rt, bf);
5527
12.2k
        }
5528
12.2k
        break;
5529
0
    case JS_TAG_BIG_DECIMAL:
5530
0
        {
5531
0
            JSBigDecimal *bf = JS_VALUE_GET_PTR(v);
5532
0
            bfdec_delete(&bf->num);
5533
0
            js_free_rt(rt, bf);
5534
0
        }
5535
0
        break;
5536
0
#endif
5537
502k
    case JS_TAG_SYMBOL:
5538
502k
        {
5539
502k
            JSAtomStruct *p = JS_VALUE_GET_PTR(v);
5540
502k
            JS_FreeAtomStruct(rt, p);
5541
502k
        }
5542
502k
        break;
5543
0
    default:
5544
0
        printf("__JS_FreeValue: unknown tag=%d\n", tag);
5545
0
        abort();
5546
16.6M
    }
5547
16.6M
}
5548
5549
void __JS_FreeValue(JSContext *ctx, JSValue v)
5550
8.85M
{
5551
8.85M
    __JS_FreeValueRT(ctx->rt, v);
5552
8.85M
}
5553
5554
/* garbage collection */
5555
5556
static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
5557
                          JSGCObjectTypeEnum type)
5558
15.9M
{
5559
15.9M
    h->mark = 0;
5560
15.9M
    h->gc_obj_type = type;
5561
15.9M
    list_add_tail(&h->link, &rt->gc_obj_list);
5562
15.9M
}
5563
5564
static void remove_gc_object(JSGCObjectHeader *h)
5565
15.6M
{
5566
15.6M
    list_del(&h->link);
5567
15.6M
}
5568
5569
void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
5570
18.6M
{
5571
18.6M
    if (JS_VALUE_HAS_REF_COUNT(val)) {
5572
14.1M
        switch(JS_VALUE_GET_TAG(val)) {
5573
5.39M
        case JS_TAG_OBJECT:
5574
8.51M
        case JS_TAG_FUNCTION_BYTECODE:
5575
8.51M
            mark_func(rt, JS_VALUE_GET_PTR(val));
5576
8.51M
            break;
5577
5.59M
        default:
5578
5.59M
            break;
5579
14.1M
        }
5580
14.1M
    }
5581
18.6M
}
5582
5583
static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
5584
                          JS_MarkFunc *mark_func)
5585
8.32M
{
5586
8.32M
    switch(gp->gc_obj_type) {
5587
5.16M
    case JS_GC_OBJ_TYPE_JS_OBJECT:
5588
5.16M
        {
5589
5.16M
            JSObject *p = (JSObject *)gp;
5590
5.16M
            JSShapeProperty *prs;
5591
5.16M
            JSShape *sh;
5592
5.16M
            int i;
5593
5.16M
            sh = p->shape;
5594
5.16M
            mark_func(rt, &sh->header);
5595
            /* mark all the fields */
5596
5.16M
            prs = get_shape_prop(sh);
5597
15.6M
            for(i = 0; i < sh->prop_count; i++) {
5598
10.5M
                JSProperty *pr = &p->prop[i];
5599
10.5M
                if (prs->atom != JS_ATOM_NULL) {
5600
10.5M
                    if (prs->flags & JS_PROP_TMASK) {
5601
66.1k
                        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
5602
6.18k
                            if (pr->u.getset.getter)
5603
6.18k
                                mark_func(rt, &pr->u.getset.getter->header);
5604
6.18k
                            if (pr->u.getset.setter)
5605
546
                                mark_func(rt, &pr->u.getset.setter->header);
5606
59.9k
                        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
5607
0
                            if (pr->u.var_ref->is_detached) {
5608
                                /* Note: the tag does not matter
5609
                                   provided it is a GC object */
5610
0
                                mark_func(rt, &pr->u.var_ref->header);
5611
0
                            }
5612
59.9k
                        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
5613
59.9k
                            js_autoinit_mark(rt, pr, mark_func);
5614
59.9k
                        }
5615
10.4M
                    } else {
5616
10.4M
                        JS_MarkValue(rt, pr->u.value, mark_func);
5617
10.4M
                    }
5618
10.5M
                }
5619
10.5M
                prs++;
5620
10.5M
            }
5621
5622
5.16M
            if (p->class_id != JS_CLASS_OBJECT) {
5623
4.48M
                JSClassGCMark *gc_mark;
5624
4.48M
                gc_mark = rt->class_array[p->class_id].gc_mark;
5625
4.48M
                if (gc_mark)
5626
4.48M
                    gc_mark(rt, JS_MKPTR(JS_TAG_OBJECT, p), mark_func);
5627
4.48M
            }
5628
5.16M
        }
5629
5.16M
        break;
5630
48.8k
    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
5631
        /* the template objects can be part of a cycle */
5632
48.8k
        {
5633
48.8k
            JSFunctionBytecode *b = (JSFunctionBytecode *)gp;
5634
48.8k
            int i;
5635
67.4k
            for(i = 0; i < b->cpool_count; i++) {
5636
18.5k
                JS_MarkValue(rt, b->cpool[i], mark_func);
5637
18.5k
            }
5638
48.8k
            if (b->realm)
5639
48.8k
                mark_func(rt, &b->realm->header);
5640
48.8k
        }
5641
48.8k
        break;
5642
3.08M
    case JS_GC_OBJ_TYPE_VAR_REF:
5643
3.08M
        {
5644
3.08M
            JSVarRef *var_ref = (JSVarRef *)gp;
5645
            /* only detached variable referenced are taken into account */
5646
3.08M
            assert(var_ref->is_detached);
5647
3.08M
            JS_MarkValue(rt, *var_ref->pvalue, mark_func);
5648
3.08M
        }
5649
0
        break;
5650
0
    case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
5651
0
        {
5652
0
            JSAsyncFunctionData *s = (JSAsyncFunctionData *)gp;
5653
0
            if (s->is_active)
5654
0
                async_func_mark(rt, &s->func_state, mark_func);
5655
0
            JS_MarkValue(rt, s->resolving_funcs[0], mark_func);
5656
0
            JS_MarkValue(rt, s->resolving_funcs[1], mark_func);
5657
0
        }
5658
0
        break;
5659
22.2k
    case JS_GC_OBJ_TYPE_SHAPE:
5660
22.2k
        {
5661
22.2k
            JSShape *sh = (JSShape *)gp;
5662
22.2k
            if (sh->proto != NULL) {
5663
21.2k
                mark_func(rt, &sh->proto->header);
5664
21.2k
            }
5665
22.2k
        }
5666
22.2k
        break;
5667
182
    case JS_GC_OBJ_TYPE_JS_CONTEXT:
5668
182
        {
5669
182
            JSContext *ctx = (JSContext *)gp;
5670
182
            JS_MarkContext(rt, ctx, mark_func);
5671
182
        }
5672
182
        break;
5673
0
    default:
5674
0
        abort();
5675
8.32M
    }
5676
8.32M
}
5677
5678
static void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p)
5679
8.50M
{
5680
8.50M
    assert(p->ref_count > 0);
5681
8.50M
    p->ref_count--;
5682
8.50M
    if (p->ref_count == 0 && p->mark == 1) {
5683
1.47M
        list_del(&p->link);
5684
1.47M
        list_add_tail(&p->link, &rt->tmp_obj_list);
5685
1.47M
    }
5686
8.50M
}
5687
5688
static void gc_decref(JSRuntime *rt)
5689
91
{
5690
91
    struct list_head *el, *el1;
5691
91
    JSGCObjectHeader *p;
5692
    
5693
91
    init_list_head(&rt->tmp_obj_list);
5694
5695
    /* decrement the refcount of all the children of all the GC
5696
       objects and move the GC objects with zero refcount to
5697
       tmp_obj_list */
5698
4.16M
    list_for_each_safe(el, el1, &rt->gc_obj_list) {
5699
4.16M
        p = list_entry(el, JSGCObjectHeader, link);
5700
4.16M
        assert(p->mark == 0);
5701
4.16M
        mark_children(rt, p, gc_decref_child);
5702
4.16M
        p->mark = 1;
5703
4.16M
        if (p->ref_count == 0) {
5704
2.24M
            list_del(&p->link);
5705
2.24M
            list_add_tail(&p->link, &rt->tmp_obj_list);
5706
2.24M
        }
5707
4.16M
    }
5708
91
}
5709
5710
static void gc_scan_incref_child(JSRuntime *rt, JSGCObjectHeader *p)
5711
1.24M
{
5712
1.24M
    p->ref_count++;
5713
1.24M
    if (p->ref_count == 1) {
5714
        /* ref_count was 0: remove from tmp_obj_list and add at the
5715
           end of gc_obj_list */
5716
264k
        list_del(&p->link);
5717
264k
        list_add_tail(&p->link, &rt->gc_obj_list);
5718
264k
        p->mark = 0; /* reset the mark for the next GC call */
5719
264k
    }
5720
1.24M
}
5721
5722
static void gc_scan_incref_child2(JSRuntime *rt, JSGCObjectHeader *p)
5723
7.26M
{
5724
7.26M
    p->ref_count++;
5725
7.26M
}
5726
5727
static void gc_scan(JSRuntime *rt)
5728
91
{
5729
91
    struct list_head *el;
5730
91
    JSGCObjectHeader *p;
5731
5732
    /* keep the objects with a refcount > 0 and their children. */
5733
712k
    list_for_each(el, &rt->gc_obj_list) {
5734
712k
        p = list_entry(el, JSGCObjectHeader, link);
5735
712k
        assert(p->ref_count > 0);
5736
712k
        p->mark = 0; /* reset the mark for the next GC call */
5737
712k
        mark_children(rt, p, gc_scan_incref_child);
5738
712k
    }
5739
    
5740
    /* restore the refcount of the objects to be deleted. */
5741
3.44M
    list_for_each(el, &rt->tmp_obj_list) {
5742
3.44M
        p = list_entry(el, JSGCObjectHeader, link);
5743
3.44M
        mark_children(rt, p, gc_scan_incref_child2);
5744
3.44M
    }
5745
91
}
5746
5747
static void gc_free_cycles(JSRuntime *rt)
5748
91
{
5749
91
    struct list_head *el, *el1;
5750
91
    JSGCObjectHeader *p;
5751
#ifdef DUMP_GC_FREE
5752
    BOOL header_done = FALSE;
5753
#endif
5754
5755
91
    rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES;
5756
5757
1.92M
    for(;;) {
5758
1.92M
        el = rt->tmp_obj_list.next;
5759
1.92M
        if (el == &rt->tmp_obj_list)
5760
91
            break;
5761
1.92M
        p = list_entry(el, JSGCObjectHeader, link);
5762
        /* Only need to free the GC object associated with JS
5763
           values. The rest will be automatically removed because they
5764
           must be referenced by them. */
5765
1.92M
        switch(p->gc_obj_type) {
5766
1.88M
        case JS_GC_OBJ_TYPE_JS_OBJECT:
5767
1.90M
        case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
5768
#ifdef DUMP_GC_FREE
5769
            if (!header_done) {
5770
                printf("Freeing cycles:\n");
5771
                JS_DumpObjectHeader(rt);
5772
                header_done = TRUE;
5773
            }
5774
            JS_DumpGCObject(rt, p);
5775
#endif
5776
1.90M
            free_gc_object(rt, p);
5777
1.90M
            break;
5778
18.3k
        default:
5779
18.3k
            list_del(&p->link);
5780
18.3k
            list_add_tail(&p->link, &rt->gc_zero_ref_count_list);
5781
18.3k
            break;
5782
1.92M
        }
5783
1.92M
    }
5784
91
    rt->gc_phase = JS_GC_PHASE_NONE;
5785
           
5786
879k
    list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) {
5787
879k
        p = list_entry(el, JSGCObjectHeader, link);
5788
879k
        assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT ||
5789
879k
               p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
5790
879k
        js_free_rt(rt, p);
5791
879k
    }
5792
5793
91
    init_list_head(&rt->gc_zero_ref_count_list);
5794
91
}
5795
5796
void JS_RunGC(JSRuntime *rt)
5797
91
{
5798
    /* decrement the reference of the children of each object. mark =
5799
       1 after this pass. */
5800
91
    gc_decref(rt);
5801
5802
    /* keep the GC objects with a non zero refcount and their childs */
5803
91
    gc_scan(rt);
5804
5805
    /* free the GC objects in a cycle */
5806
91
    gc_free_cycles(rt);
5807
91
}
5808
5809
/* Return false if not an object or if the object has already been
5810
   freed (zombie objects are visible in finalizers when freeing
5811
   cycles). */
5812
BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj)
5813
0
{
5814
0
    JSObject *p;
5815
0
    if (!JS_IsObject(obj))
5816
0
        return FALSE;
5817
0
    p = JS_VALUE_GET_OBJ(obj);
5818
0
    return !p->free_mark;
5819
0
}
5820
5821
/* Compute memory used by various object types */
5822
/* XXX: poor man's approach to handling multiply referenced objects */
5823
typedef struct JSMemoryUsage_helper {
5824
    double memory_used_count;
5825
    double str_count;
5826
    double str_size;
5827
    int64_t js_func_count;
5828
    double js_func_size;
5829
    int64_t js_func_code_size;
5830
    int64_t js_func_pc2line_count;
5831
    int64_t js_func_pc2line_size;
5832
} JSMemoryUsage_helper;
5833
5834
static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp);
5835
5836
static void compute_jsstring_size(JSString *str, JSMemoryUsage_helper *hp)
5837
0
{
5838
0
    if (!str->atom_type) {  /* atoms are handled separately */
5839
0
        double s_ref_count = str->header.ref_count;
5840
0
        hp->str_count += 1 / s_ref_count;
5841
0
        hp->str_size += ((sizeof(*str) + (str->len << str->is_wide_char) +
5842
0
                          1 - str->is_wide_char) / s_ref_count);
5843
0
    }
5844
0
}
5845
5846
static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *hp)
5847
0
{
5848
0
    int memory_used_count, js_func_size, i;
5849
5850
0
    memory_used_count = 0;
5851
0
    js_func_size = offsetof(JSFunctionBytecode, debug);
5852
0
    if (b->vardefs) {
5853
0
        js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs);
5854
0
    }
5855
0
    if (b->cpool) {
5856
0
        js_func_size += b->cpool_count * sizeof(*b->cpool);
5857
0
        for (i = 0; i < b->cpool_count; i++) {
5858
0
            JSValueConst val = b->cpool[i];
5859
0
            compute_value_size(val, hp);
5860
0
        }
5861
0
    }
5862
0
    if (b->closure_var) {
5863
0
        js_func_size += b->closure_var_count * sizeof(*b->closure_var);
5864
0
    }
5865
0
    if (!b->read_only_bytecode && b->byte_code_buf) {
5866
0
        hp->js_func_code_size += b->byte_code_len;
5867
0
    }
5868
0
    if (b->has_debug) {
5869
0
        js_func_size += sizeof(*b) - offsetof(JSFunctionBytecode, debug);
5870
0
        if (b->debug.source) {
5871
0
            memory_used_count++;
5872
0
            js_func_size += b->debug.source_len + 1;
5873
0
        }
5874
0
        if (b->debug.pc2line_len) {
5875
0
            memory_used_count++;
5876
0
            hp->js_func_pc2line_count += 1;
5877
0
            hp->js_func_pc2line_size += b->debug.pc2line_len;
5878
0
        }
5879
0
    }
5880
0
    hp->js_func_size += js_func_size;
5881
0
    hp->js_func_count += 1;
5882
0
    hp->memory_used_count += memory_used_count;
5883
0
}
5884
5885
static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp)
5886
0
{
5887
0
    switch(JS_VALUE_GET_TAG(val)) {
5888
0
    case JS_TAG_STRING:
5889
0
        compute_jsstring_size(JS_VALUE_GET_STRING(val), hp);
5890
0
        break;
5891
0
#ifdef CONFIG_BIGNUM
5892
0
    case JS_TAG_BIG_INT:
5893
0
    case JS_TAG_BIG_FLOAT:
5894
0
    case JS_TAG_BIG_DECIMAL:
5895
        /* should track JSBigFloat usage */
5896
0
        break;
5897
0
#endif
5898
0
    }
5899
0
}
5900
5901
void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
5902
0
{
5903
0
    struct list_head *el, *el1;
5904
0
    int i;
5905
0
    JSMemoryUsage_helper mem = { 0 }, *hp = &mem;
5906
5907
0
    memset(s, 0, sizeof(*s));
5908
0
    s->malloc_count = rt->malloc_state.malloc_count;
5909
0
    s->malloc_size = rt->malloc_state.malloc_size;
5910
0
    s->malloc_limit = rt->malloc_state.malloc_limit;
5911
5912
0
    s->memory_used_count = 2; /* rt + rt->class_array */
5913
0
    s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count;
5914
5915
0
    list_for_each(el, &rt->context_list) {
5916
0
        JSContext *ctx = list_entry(el, JSContext, link);
5917
0
        JSShape *sh = ctx->array_shape;
5918
0
        s->memory_used_count += 2; /* ctx + ctx->class_proto */
5919
0
        s->memory_used_size += sizeof(JSContext) +
5920
0
            sizeof(JSValue) * rt->class_count;
5921
0
        s->binary_object_count += ctx->binary_object_count;
5922
0
        s->binary_object_size += ctx->binary_object_size;
5923
5924
        /* the hashed shapes are counted separately */
5925
0
        if (sh && !sh->is_hashed) {
5926
0
            int hash_size = sh->prop_hash_mask + 1;
5927
0
            s->shape_count++;
5928
0
            s->shape_size += get_shape_size(hash_size, sh->prop_size);
5929
0
        }
5930
0
        list_for_each(el1, &ctx->loaded_modules) {
5931
0
            JSModuleDef *m = list_entry(el1, JSModuleDef, link);
5932
0
            s->memory_used_count += 1;
5933
0
            s->memory_used_size += sizeof(*m);
5934
0
            if (m->req_module_entries) {
5935
0
                s->memory_used_count += 1;
5936
0
                s->memory_used_size += m->req_module_entries_count * sizeof(*m->req_module_entries);
5937
0
            }
5938
0
            if (m->export_entries) {
5939
0
                s->memory_used_count += 1;
5940
0
                s->memory_used_size += m->export_entries_count * sizeof(*m->export_entries);
5941
0
                for (i = 0; i < m->export_entries_count; i++) {
5942
0
                    JSExportEntry *me = &m->export_entries[i];
5943
0
                    if (me->export_type == JS_EXPORT_TYPE_LOCAL && me->u.local.var_ref) {
5944
                        /* potential multiple count */
5945
0
                        s->memory_used_count += 1;
5946
0
                        compute_value_size(me->u.local.var_ref->value, hp);
5947
0
                    }
5948
0
                }
5949
0
            }
5950
0
            if (m->star_export_entries) {
5951
0
                s->memory_used_count += 1;
5952
0
                s->memory_used_size += m->star_export_entries_count * sizeof(*m->star_export_entries);
5953
0
            }
5954
0
            if (m->import_entries) {
5955
0
                s->memory_used_count += 1;
5956
0
                s->memory_used_size += m->import_entries_count * sizeof(*m->import_entries);
5957
0
            }
5958
0
            compute_value_size(m->module_ns, hp);
5959
0
            compute_value_size(m->func_obj, hp);
5960
0
        }
5961
0
    }
5962
5963
0
    list_for_each(el, &rt->gc_obj_list) {
5964
0
        JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
5965
0
        JSObject *p;
5966
0
        JSShape *sh;
5967
0
        JSShapeProperty *prs;
5968
5969
        /* XXX: could count the other GC object types too */
5970
0
        if (gp->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) {
5971
0
            compute_bytecode_size((JSFunctionBytecode *)gp, hp);
5972
0
            continue;
5973
0
        } else if (gp->gc_obj_type != JS_GC_OBJ_TYPE_JS_OBJECT) {
5974
0
            continue;
5975
0
        }
5976
0
        p = (JSObject *)gp;
5977
0
        sh = p->shape;
5978
0
        s->obj_count++;
5979
0
        if (p->prop) {
5980
0
            s->memory_used_count++;
5981
0
            s->prop_size += sh->prop_size * sizeof(*p->prop);
5982
0
            s->prop_count += sh->prop_count;
5983
0
            prs = get_shape_prop(sh);
5984
0
            for(i = 0; i < sh->prop_count; i++) {
5985
0
                JSProperty *pr = &p->prop[i];
5986
0
                if (prs->atom != JS_ATOM_NULL && !(prs->flags & JS_PROP_TMASK)) {
5987
0
                    compute_value_size(pr->u.value, hp);
5988
0
                }
5989
0
                prs++;
5990
0
            }
5991
0
        }
5992
        /* the hashed shapes are counted separately */
5993
0
        if (!sh->is_hashed) {
5994
0
            int hash_size = sh->prop_hash_mask + 1;
5995
0
            s->shape_count++;
5996
0
            s->shape_size += get_shape_size(hash_size, sh->prop_size);
5997
0
        }
5998
5999
0
        switch(p->class_id) {
6000
0
        case JS_CLASS_ARRAY:             /* u.array | length */
6001
0
        case JS_CLASS_ARGUMENTS:         /* u.array | length */
6002
0
            s->array_count++;
6003
0
            if (p->fast_array) {
6004
0
                s->fast_array_count++;
6005
0
                if (p->u.array.u.values) {
6006
0
                    s->memory_used_count++;
6007
0
                    s->memory_used_size += p->u.array.count *
6008
0
                        sizeof(*p->u.array.u.values);
6009
0
                    s->fast_array_elements += p->u.array.count;
6010
0
                    for (i = 0; i < p->u.array.count; i++) {
6011
0
                        compute_value_size(p->u.array.u.values[i], hp);
6012
0
                    }
6013
0
                }
6014
0
            }
6015
0
            break;
6016
0
        case JS_CLASS_NUMBER:            /* u.object_data */
6017
0
        case JS_CLASS_STRING:            /* u.object_data */
6018
0
        case JS_CLASS_BOOLEAN:           /* u.object_data */
6019
0
        case JS_CLASS_SYMBOL:            /* u.object_data */
6020
0
        case JS_CLASS_DATE:              /* u.object_data */
6021
0
#ifdef CONFIG_BIGNUM
6022
0
        case JS_CLASS_BIG_INT:           /* u.object_data */
6023
0
        case JS_CLASS_BIG_FLOAT:         /* u.object_data */
6024
0
        case JS_CLASS_BIG_DECIMAL:         /* u.object_data */
6025
0
#endif
6026
0
            compute_value_size(p->u.object_data, hp);
6027
0
            break;
6028
0
        case JS_CLASS_C_FUNCTION:        /* u.cfunc */
6029
0
            s->c_func_count++;
6030
0
            break;
6031
0
        case JS_CLASS_BYTECODE_FUNCTION: /* u.func */
6032
0
            {
6033
0
                JSFunctionBytecode *b = p->u.func.function_bytecode;
6034
0
                JSVarRef **var_refs = p->u.func.var_refs;
6035
                /* home_object: object will be accounted for in list scan */
6036
0
                if (var_refs) {
6037
0
                    s->memory_used_count++;
6038
0
                    s->js_func_size += b->closure_var_count * sizeof(*var_refs);
6039
0
                    for (i = 0; i < b->closure_var_count; i++) {
6040
0
                        if (var_refs[i]) {
6041
0
                            double ref_count = var_refs[i]->header.ref_count;
6042
0
                            s->memory_used_count += 1 / ref_count;
6043
0
                            s->js_func_size += sizeof(*var_refs[i]) / ref_count;
6044
                            /* handle non object closed values */
6045
0
                            if (var_refs[i]->pvalue == &var_refs[i]->value) {
6046
                                /* potential multiple count */
6047
0
                                compute_value_size(var_refs[i]->value, hp);
6048
0
                            }
6049
0
                        }
6050
0
                    }
6051
0
                }
6052
0
            }
6053
0
            break;
6054
0
        case JS_CLASS_BOUND_FUNCTION:    /* u.bound_function */
6055
0
            {
6056
0
                JSBoundFunction *bf = p->u.bound_function;
6057
                /* func_obj and this_val are objects */
6058
0
                for (i = 0; i < bf->argc; i++) {
6059
0
                    compute_value_size(bf->argv[i], hp);
6060
0
                }
6061
0
                s->memory_used_count += 1;
6062
0
                s->memory_used_size += sizeof(*bf) + bf->argc * sizeof(*bf->argv);
6063
0
            }
6064
0
            break;
6065
0
        case JS_CLASS_C_FUNCTION_DATA:   /* u.c_function_data_record */
6066
0
            {
6067
0
                JSCFunctionDataRecord *fd = p->u.c_function_data_record;
6068
0
                if (fd) {
6069
0
                    for (i = 0; i < fd->data_len; i++) {
6070
0
                        compute_value_size(fd->data[i], hp);
6071
0
                    }
6072
0
                    s->memory_used_count += 1;
6073
0
                    s->memory_used_size += sizeof(*fd) + fd->data_len * sizeof(*fd->data);
6074
0
                }
6075
0
            }
6076
0
            break;
6077
0
        case JS_CLASS_REGEXP:            /* u.regexp */
6078
0
            compute_jsstring_size(p->u.regexp.pattern, hp);
6079
0
            compute_jsstring_size(p->u.regexp.bytecode, hp);
6080
0
            break;
6081
6082
0
        case JS_CLASS_FOR_IN_ITERATOR:   /* u.for_in_iterator */
6083
0
            {
6084
0
                JSForInIterator *it = p->u.for_in_iterator;
6085
0
                if (it) {
6086
0
                    compute_value_size(it->obj, hp);
6087
0
                    s->memory_used_count += 1;
6088
0
                    s->memory_used_size += sizeof(*it);
6089
0
                }
6090
0
            }
6091
0
            break;
6092
0
        case JS_CLASS_ARRAY_BUFFER:      /* u.array_buffer */
6093
0
        case JS_CLASS_SHARED_ARRAY_BUFFER: /* u.array_buffer */
6094
0
            {
6095
0
                JSArrayBuffer *abuf = p->u.array_buffer;
6096
0
                if (abuf) {
6097
0
                    s->memory_used_count += 1;
6098
0
                    s->memory_used_size += sizeof(*abuf);
6099
0
                    if (abuf->data) {
6100
0
                        s->memory_used_count += 1;
6101
0
                        s->memory_used_size += abuf->byte_length;
6102
0
                    }
6103
0
                }
6104
0
            }
6105
0
            break;
6106
0
        case JS_CLASS_GENERATOR:         /* u.generator_data */
6107
0
        case JS_CLASS_UINT8C_ARRAY:      /* u.typed_array / u.array */
6108
0
        case JS_CLASS_INT8_ARRAY:        /* u.typed_array / u.array */
6109
0
        case JS_CLASS_UINT8_ARRAY:       /* u.typed_array / u.array */
6110
0
        case JS_CLASS_INT16_ARRAY:       /* u.typed_array / u.array */
6111
0
        case JS_CLASS_UINT16_ARRAY:      /* u.typed_array / u.array */
6112
0
        case JS_CLASS_INT32_ARRAY:       /* u.typed_array / u.array */
6113
0
        case JS_CLASS_UINT32_ARRAY:      /* u.typed_array / u.array */
6114
0
#ifdef CONFIG_BIGNUM
6115
0
        case JS_CLASS_BIG_INT64_ARRAY:   /* u.typed_array / u.array */
6116
0
        case JS_CLASS_BIG_UINT64_ARRAY:  /* u.typed_array / u.array */
6117
0
#endif
6118
0
        case JS_CLASS_FLOAT32_ARRAY:     /* u.typed_array / u.array */
6119
0
        case JS_CLASS_FLOAT64_ARRAY:     /* u.typed_array / u.array */
6120
0
        case JS_CLASS_DATAVIEW:          /* u.typed_array */
6121
0
#ifdef CONFIG_BIGNUM
6122
0
        case JS_CLASS_FLOAT_ENV:         /* u.float_env */
6123
0
#endif
6124
0
        case JS_CLASS_MAP:               /* u.map_state */
6125
0
        case JS_CLASS_SET:               /* u.map_state */
6126
0
        case JS_CLASS_WEAKMAP:           /* u.map_state */
6127
0
        case JS_CLASS_WEAKSET:           /* u.map_state */
6128
0
        case JS_CLASS_MAP_ITERATOR:      /* u.map_iterator_data */
6129
0
        case JS_CLASS_SET_ITERATOR:      /* u.map_iterator_data */
6130
0
        case JS_CLASS_ARRAY_ITERATOR:    /* u.array_iterator_data */
6131
0
        case JS_CLASS_STRING_ITERATOR:   /* u.array_iterator_data */
6132
0
        case JS_CLASS_PROXY:             /* u.proxy_data */
6133
0
        case JS_CLASS_PROMISE:           /* u.promise_data */
6134
0
        case JS_CLASS_PROMISE_RESOLVE_FUNCTION:  /* u.promise_function_data */
6135
0
        case JS_CLASS_PROMISE_REJECT_FUNCTION:   /* u.promise_function_data */
6136
0
        case JS_CLASS_ASYNC_FUNCTION_RESOLVE:    /* u.async_function_data */
6137
0
        case JS_CLASS_ASYNC_FUNCTION_REJECT:     /* u.async_function_data */
6138
0
        case JS_CLASS_ASYNC_FROM_SYNC_ITERATOR:  /* u.async_from_sync_iterator_data */
6139
0
        case JS_CLASS_ASYNC_GENERATOR:   /* u.async_generator_data */
6140
            /* TODO */
6141
0
        default:
6142
            /* XXX: class definition should have an opaque block size */
6143
0
            if (p->u.opaque) {
6144
0
                s->memory_used_count += 1;
6145
0
            }
6146
0
            break;
6147
0
        }
6148
0
    }
6149
0
    s->obj_size += s->obj_count * sizeof(JSObject);
6150
6151
    /* hashed shapes */
6152
0
    s->memory_used_count++; /* rt->shape_hash */
6153
0
    s->memory_used_size += sizeof(rt->shape_hash[0]) * rt->shape_hash_size;
6154
0
    for(i = 0; i < rt->shape_hash_size; i++) {
6155
0
        JSShape *sh;
6156
0
        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
6157
0
            int hash_size = sh->prop_hash_mask + 1;
6158
0
            s->shape_count++;
6159
0
            s->shape_size += get_shape_size(hash_size, sh->prop_size);
6160
0
        }
6161
0
    }
6162
6163
    /* atoms */
6164
0
    s->memory_used_count += 2; /* rt->atom_array, rt->atom_hash */
6165
0
    s->atom_count = rt->atom_count;
6166
0
    s->atom_size = sizeof(rt->atom_array[0]) * rt->atom_size +
6167
0
        sizeof(rt->atom_hash[0]) * rt->atom_hash_size;
6168
0
    for(i = 0; i < rt->atom_size; i++) {
6169
0
        JSAtomStruct *p = rt->atom_array[i];
6170
0
        if (!atom_is_free(p)) {
6171
0
            s->atom_size += (sizeof(*p) + (p->len << p->is_wide_char) +
6172
0
                             1 - p->is_wide_char);
6173
0
        }
6174
0
    }
6175
0
    s->str_count = round(mem.str_count);
6176
0
    s->str_size = round(mem.str_size);
6177
0
    s->js_func_count = mem.js_func_count;
6178
0
    s->js_func_size = round(mem.js_func_size);
6179
0
    s->js_func_code_size = mem.js_func_code_size;
6180
0
    s->js_func_pc2line_count = mem.js_func_pc2line_count;
6181
0
    s->js_func_pc2line_size = mem.js_func_pc2line_size;
6182
0
    s->memory_used_count += round(mem.memory_used_count) +
6183
0
        s->atom_count + s->str_count +
6184
0
        s->obj_count + s->shape_count +
6185
0
        s->js_func_count + s->js_func_pc2line_count;
6186
0
    s->memory_used_size += s->atom_size + s->str_size +
6187
0
        s->obj_size + s->prop_size + s->shape_size +
6188
0
        s->js_func_size + s->js_func_code_size + s->js_func_pc2line_size;
6189
0
}
6190
6191
void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
6192
0
{
6193
0
    fprintf(fp, "QuickJS memory usage -- "
6194
0
#ifdef CONFIG_BIGNUM
6195
0
            "BigNum "
6196
0
#endif
6197
0
            CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n",
6198
0
            (int)sizeof(void *) * 8, (int64_t)(ssize_t)s->malloc_limit);
6199
0
#if 1
6200
0
    if (rt) {
6201
0
        static const struct {
6202
0
            const char *name;
6203
0
            size_t size;
6204
0
        } object_types[] = {
6205
0
            { "JSRuntime", sizeof(JSRuntime) },
6206
0
            { "JSContext", sizeof(JSContext) },
6207
0
            { "JSObject", sizeof(JSObject) },
6208
0
            { "JSString", sizeof(JSString) },
6209
0
            { "JSFunctionBytecode", sizeof(JSFunctionBytecode) },
6210
0
        };
6211
0
        int i, usage_size_ok = 0;
6212
0
        for(i = 0; i < countof(object_types); i++) {
6213
0
            unsigned int size = object_types[i].size;
6214
0
            void *p = js_malloc_rt(rt, size);
6215
0
            if (p) {
6216
0
                unsigned int size1 = js_malloc_usable_size_rt(rt, p);
6217
0
                if (size1 >= size) {
6218
0
                    usage_size_ok = 1;
6219
0
                    fprintf(fp, "  %3u + %-2u  %s\n",
6220
0
                            size, size1 - size, object_types[i].name);
6221
0
                }
6222
0
                js_free_rt(rt, p);
6223
0
            }
6224
0
        }
6225
0
        if (!usage_size_ok) {
6226
0
            fprintf(fp, "  malloc_usable_size unavailable\n");
6227
0
        }
6228
0
        {
6229
0
            int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 };
6230
0
            int class_id;
6231
0
            struct list_head *el;
6232
0
            list_for_each(el, &rt->gc_obj_list) {
6233
0
                JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
6234
0
                JSObject *p;
6235
0
                if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
6236
0
                    p = (JSObject *)gp;
6237
0
                    obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++;
6238
0
                }
6239
0
            }
6240
0
            fprintf(fp, "\n" "JSObject classes\n");
6241
0
            if (obj_classes[0])
6242
0
                fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[0], 0, "none");
6243
0
            for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) {
6244
0
                if (obj_classes[class_id]) {
6245
0
                    char buf[ATOM_GET_STR_BUF_SIZE];
6246
0
                    fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[class_id], class_id,
6247
0
                            JS_AtomGetStrRT(rt, buf, sizeof(buf), js_std_class_def[class_id - 1].class_name));
6248
0
                }
6249
0
            }
6250
0
            if (obj_classes[JS_CLASS_INIT_COUNT])
6251
0
                fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other");
6252
0
        }
6253
0
        fprintf(fp, "\n");
6254
0
    }
6255
0
#endif
6256
0
    fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE");
6257
6258
0
    if (s->malloc_count) {
6259
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per block)\n",
6260
0
                "memory allocated", s->malloc_count, s->malloc_size,
6261
0
                (double)s->malloc_size / s->malloc_count);
6262
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%d overhead, %0.1f average slack)\n",
6263
0
                "memory used", s->memory_used_count, s->memory_used_size,
6264
0
                MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) /
6265
0
                                  s->memory_used_count));
6266
0
    }
6267
0
    if (s->atom_count) {
6268
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per atom)\n",
6269
0
                "atoms", s->atom_count, s->atom_size,
6270
0
                (double)s->atom_size / s->atom_count);
6271
0
    }
6272
0
    if (s->str_count) {
6273
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per string)\n",
6274
0
                "strings", s->str_count, s->str_size,
6275
0
                (double)s->str_size / s->str_count);
6276
0
    }
6277
0
    if (s->obj_count) {
6278
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
6279
0
                "objects", s->obj_count, s->obj_size,
6280
0
                (double)s->obj_size / s->obj_count);
6281
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
6282
0
                "  properties", s->prop_count, s->prop_size,
6283
0
                (double)s->prop_count / s->obj_count);
6284
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per shape)\n",
6285
0
                "  shapes", s->shape_count, s->shape_size,
6286
0
                (double)s->shape_size / s->shape_count);
6287
0
    }
6288
0
    if (s->js_func_count) {
6289
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
6290
0
                "bytecode functions", s->js_func_count, s->js_func_size);
6291
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
6292
0
                "  bytecode", s->js_func_count, s->js_func_code_size,
6293
0
                (double)s->js_func_code_size / s->js_func_count);
6294
0
        if (s->js_func_pc2line_count) {
6295
0
            fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
6296
0
                    "  pc2line", s->js_func_pc2line_count,
6297
0
                    s->js_func_pc2line_size,
6298
0
                    (double)s->js_func_pc2line_size / s->js_func_pc2line_count);
6299
0
        }
6300
0
    }
6301
0
    if (s->c_func_count) {
6302
0
        fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count);
6303
0
    }
6304
0
    if (s->array_count) {
6305
0
        fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count);
6306
0
        if (s->fast_array_count) {
6307
0
            fprintf(fp, "%-20s %8"PRId64"\n", "  fast arrays", s->fast_array_count);
6308
0
            fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per fast array)\n",
6309
0
                    "  elements", s->fast_array_elements,
6310
0
                    s->fast_array_elements * (int)sizeof(JSValue),
6311
0
                    (double)s->fast_array_elements / s->fast_array_count);
6312
0
        }
6313
0
    }
6314
0
    if (s->binary_object_count) {
6315
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
6316
0
                "binary objects", s->binary_object_count, s->binary_object_size);
6317
0
    }
6318
0
}
6319
6320
JSValue JS_GetGlobalObject(JSContext *ctx)
6321
2
{
6322
2
    return JS_DupValue(ctx, ctx->global_obj);
6323
2
}
6324
6325
/* WARNING: obj is freed */
6326
JSValue JS_Throw(JSContext *ctx, JSValue obj)
6327
111k
{
6328
111k
    JSRuntime *rt = ctx->rt;
6329
111k
    JS_FreeValue(ctx, rt->current_exception);
6330
111k
    rt->current_exception = obj;
6331
111k
    return JS_EXCEPTION;
6332
111k
}
6333
6334
/* return the pending exception (cannot be called twice). */
6335
JSValue JS_GetException(JSContext *ctx)
6336
109k
{
6337
109k
    JSValue val;
6338
109k
    JSRuntime *rt = ctx->rt;
6339
109k
    val = rt->current_exception;
6340
109k
    rt->current_exception = JS_NULL;
6341
109k
    return val;
6342
109k
}
6343
6344
static void dbuf_put_leb128(DynBuf *s, uint32_t v)
6345
80.3k
{
6346
80.3k
    uint32_t a;
6347
95.4k
    for(;;) {
6348
95.4k
        a = v & 0x7f;
6349
95.4k
        v >>= 7;
6350
95.4k
        if (v != 0) {
6351
15.0k
            dbuf_putc(s, a | 0x80);
6352
80.3k
        } else {
6353
80.3k
            dbuf_putc(s, a);
6354
80.3k
            break;
6355
80.3k
        }
6356
95.4k
    }
6357
80.3k
}
6358
6359
static void dbuf_put_sleb128(DynBuf *s, int32_t v1)
6360
33.1k
{
6361
33.1k
    uint32_t v = v1;
6362
33.1k
    dbuf_put_leb128(s, (2 * v) ^ -(v >> 31));
6363
33.1k
}
6364
6365
static int get_leb128(uint32_t *pval, const uint8_t *buf,
6366
                      const uint8_t *buf_end)
6367
21.1k
{
6368
21.1k
    const uint8_t *ptr = buf;
6369
21.1k
    uint32_t v, a, i;
6370
21.1k
    v = 0;
6371
23.7k
    for(i = 0; i < 5; i++) {
6372
23.7k
        if (unlikely(ptr >= buf_end))
6373
0
            break;
6374
23.7k
        a = *ptr++;
6375
23.7k
        v |= (a & 0x7f) << (i * 7);
6376
23.7k
        if (!(a & 0x80)) {
6377
21.1k
            *pval = v;
6378
21.1k
            return ptr - buf;
6379
21.1k
        }
6380
23.7k
    }
6381
0
    *pval = 0;
6382
0
    return -1;
6383
21.1k
}
6384
6385
static int get_sleb128(int32_t *pval, const uint8_t *buf,
6386
                       const uint8_t *buf_end)
6387
3.52k
{
6388
3.52k
    int ret;
6389
3.52k
    uint32_t val;
6390
3.52k
    ret = get_leb128(&val, buf, buf_end);
6391
3.52k
    if (ret < 0) {
6392
0
        *pval = 0;
6393
0
        return -1;
6394
0
    }
6395
3.52k
    *pval = (val >> 1) ^ -(val & 1);
6396
3.52k
    return ret;
6397
3.52k
}
6398
6399
static int find_line_num(JSContext *ctx, JSFunctionBytecode *b,
6400
                         uint32_t pc_value)
6401
4.15k
{
6402
4.15k
    const uint8_t *p_end, *p;
6403
4.15k
    int new_line_num, line_num, pc, v, ret;
6404
4.15k
    unsigned int op;
6405
6406
4.15k
    if (!b->has_debug || !b->debug.pc2line_buf) {
6407
        /* function was stripped */
6408
29
        return -1;
6409
29
    }
6410
6411
4.12k
    p = b->debug.pc2line_buf;
6412
4.12k
    p_end = p + b->debug.pc2line_len;
6413
4.12k
    pc = 0;
6414
4.12k
    line_num = b->debug.line_num;
6415
29.1k
    while (p < p_end) {
6416
26.2k
        op = *p++;
6417
26.2k
        if (op == 0) {
6418
3.41k
            uint32_t val;
6419
3.41k
            ret = get_leb128(&val, p, p_end);
6420
3.41k
            if (ret < 0)
6421
0
                goto fail;
6422
3.41k
            pc += val;
6423
3.41k
            p += ret;
6424
3.41k
            ret = get_sleb128(&v, p, p_end);
6425
3.41k
            if (ret < 0) {
6426
0
            fail:
6427
                /* should never happen */
6428
0
                return b->debug.line_num;
6429
0
            }
6430
3.41k
            p += ret;
6431
3.41k
            new_line_num = line_num + v;
6432
22.8k
        } else {
6433
22.8k
            op -= PC2LINE_OP_FIRST;
6434
22.8k
            pc += (op / PC2LINE_RANGE);
6435
22.8k
            new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE;
6436
22.8k
        }
6437
26.2k
        if (pc_value < pc)
6438
1.20k
            return line_num;
6439
25.0k
        line_num = new_line_num;
6440
25.0k
    }
6441
2.92k
    return line_num;
6442
4.12k
}
6443
6444
/* in order to avoid executing arbitrary code during the stack trace
6445
   generation, we only look at simple 'name' properties containing a
6446
   string. */
6447
static const char *get_func_name(JSContext *ctx, JSValueConst func)
6448
5.17k
{
6449
5.17k
    JSProperty *pr;
6450
5.17k
    JSShapeProperty *prs;
6451
5.17k
    JSValueConst val;
6452
    
6453
5.17k
    if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)
6454
0
        return NULL;
6455
5.17k
    prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name);
6456
5.17k
    if (!prs)
6457
94
        return NULL;
6458
5.07k
    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
6459
0
        return NULL;
6460
5.07k
    val = pr->u.value;
6461
5.07k
    if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
6462
0
        return NULL;
6463
5.07k
    return JS_ToCString(ctx, val);
6464
5.07k
}
6465
6466
5.17k
#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)
6467
/* only taken into account if filename is provided */
6468
1.03k
#define JS_BACKTRACE_FLAG_SINGLE_LEVEL     (1 << 1)
6469
6470
/* if filename != NULL, an additional level is added with the filename
6471
   and line number information (used for parse error). */
6472
static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
6473
                            const char *filename, int line_num,
6474
                            int backtrace_flags)
6475
110k
{
6476
110k
    JSStackFrame *sf;
6477
110k
    JSValue str;
6478
110k
    DynBuf dbuf;
6479
110k
    const char *func_name_str;
6480
110k
    const char *str1;
6481
110k
    JSObject *p;
6482
110k
    BOOL backtrace_barrier;
6483
    
6484
110k
    js_dbuf_init(ctx, &dbuf);
6485
110k
    if (filename) {
6486
1.03k
        dbuf_printf(&dbuf, "    at %s", filename);
6487
1.03k
        if (line_num != -1)
6488
1.03k
            dbuf_printf(&dbuf, ":%d", line_num);
6489
1.03k
        dbuf_putc(&dbuf, '\n');
6490
1.03k
        str = JS_NewString(ctx, filename);
6491
1.03k
        JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
6492
1.03k
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6493
1.03k
        JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
6494
1.03k
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6495
1.03k
        if (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL)
6496
0
            goto done;
6497
1.03k
    }
6498
115k
    for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
6499
5.17k
        if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {
6500
0
            backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;
6501
0
            continue;
6502
0
        }
6503
5.17k
        func_name_str = get_func_name(ctx, sf->cur_func);
6504
5.17k
        if (!func_name_str || func_name_str[0] == '\0')
6505
126
            str1 = "<anonymous>";
6506
5.04k
        else
6507
5.04k
            str1 = func_name_str;
6508
5.17k
        dbuf_printf(&dbuf, "    at %s", str1);
6509
5.17k
        JS_FreeCString(ctx, func_name_str);
6510
6511
5.17k
        p = JS_VALUE_GET_OBJ(sf->cur_func);
6512
5.17k
        backtrace_barrier = FALSE;
6513
5.17k
        if (js_class_has_bytecode(p->class_id)) {
6514
5.10k
            JSFunctionBytecode *b;
6515
5.10k
            const char *atom_str;
6516
5.10k
            int line_num1;
6517
6518
5.10k
            b = p->u.func.function_bytecode;
6519
5.10k
            backtrace_barrier = b->backtrace_barrier;
6520
5.10k
            if (b->has_debug) {
6521
4.15k
                line_num1 = find_line_num(ctx, b,
6522
4.15k
                                          sf->cur_pc - b->byte_code_buf - 1);
6523
4.15k
                atom_str = JS_AtomToCString(ctx, b->debug.filename);
6524
4.15k
                dbuf_printf(&dbuf, " (%s",
6525
4.15k
                            atom_str ? atom_str : "<null>");
6526
4.15k
                JS_FreeCString(ctx, atom_str);
6527
4.15k
                if (line_num1 != -1)
6528
4.12k
                    dbuf_printf(&dbuf, ":%d", line_num1);
6529
4.15k
                dbuf_putc(&dbuf, ')');
6530
4.15k
            }
6531
5.10k
        } else {
6532
69
            dbuf_printf(&dbuf, " (native)");
6533
69
        }
6534
5.17k
        dbuf_putc(&dbuf, '\n');
6535
        /* stop backtrace if JS_EVAL_FLAG_BACKTRACE_BARRIER was used */
6536
5.17k
        if (backtrace_barrier)
6537
0
            break;
6538
5.17k
    }
6539
110k
 done:
6540
110k
    dbuf_putc(&dbuf, '\0');
6541
110k
    if (dbuf_error(&dbuf))
6542
0
        str = JS_NULL;
6543
110k
    else
6544
110k
        str = JS_NewString(ctx, (char *)dbuf.buf);
6545
110k
    dbuf_free(&dbuf);
6546
110k
    JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str,
6547
110k
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6548
110k
}
6549
6550
/* Note: it is important that no exception is returned by this function */
6551
static BOOL is_backtrace_needed(JSContext *ctx, JSValueConst obj)
6552
5.05k
{
6553
5.05k
    JSObject *p;
6554
5.05k
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6555
4
        return FALSE;
6556
5.05k
    p = JS_VALUE_GET_OBJ(obj);
6557
5.05k
    if (p->class_id != JS_CLASS_ERROR)
6558
0
        return FALSE;
6559
5.05k
    if (find_own_property1(p, JS_ATOM_stack))
6560
4.69k
        return FALSE;
6561
357
    return TRUE;
6562
5.05k
}
6563
6564
JSValue JS_NewError(JSContext *ctx)
6565
0
{
6566
0
    return JS_NewObjectClass(ctx, JS_CLASS_ERROR);
6567
0
}
6568
6569
static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num,
6570
                              const char *fmt, va_list ap, BOOL add_backtrace)
6571
111k
{
6572
111k
    char buf[256];
6573
111k
    JSValue obj, ret;
6574
6575
111k
    vsnprintf(buf, sizeof(buf), fmt, ap);
6576
111k
    obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num],
6577
111k
                                 JS_CLASS_ERROR);
6578
111k
    if (unlikely(JS_IsException(obj))) {
6579
        /* out of memory: throw JS_NULL to avoid recursing */
6580
68
        obj = JS_NULL;
6581
111k
    } else {
6582
111k
        JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,
6583
111k
                               JS_NewString(ctx, buf),
6584
111k
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6585
111k
    }
6586
111k
    if (add_backtrace) {
6587
109k
        build_backtrace(ctx, obj, NULL, 0, 0);
6588
109k
    }
6589
111k
    ret = JS_Throw(ctx, obj);
6590
111k
    return ret;
6591
111k
}
6592
6593
static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num,
6594
                             const char *fmt, va_list ap)
6595
110k
{
6596
110k
    JSRuntime *rt = ctx->rt;
6597
110k
    JSStackFrame *sf;
6598
110k
    BOOL add_backtrace;
6599
6600
    /* the backtrace is added later if called from a bytecode function */
6601
110k
    sf = rt->current_stack_frame;
6602
110k
    add_backtrace = !rt->in_out_of_memory &&
6603
110k
        (!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL));
6604
110k
    return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace);
6605
110k
}
6606
6607
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...)
6608
89
{
6609
89
    JSValue val;
6610
89
    va_list ap;
6611
6612
89
    va_start(ap, fmt);
6613
89
    val = JS_ThrowError(ctx, JS_SYNTAX_ERROR, fmt, ap);
6614
89
    va_end(ap);
6615
89
    return val;
6616
89
}
6617
6618
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...)
6619
174
{
6620
174
    JSValue val;
6621
174
    va_list ap;
6622
6623
174
    va_start(ap, fmt);
6624
174
    val = JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
6625
174
    va_end(ap);
6626
174
    return val;
6627
174
}
6628
6629
static int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...)
6630
24.2k
{
6631
24.2k
    va_list ap;
6632
6633
24.2k
    if ((flags & JS_PROP_THROW) ||
6634
24.2k
        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
6635
2
        va_start(ap, fmt);
6636
2
        JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
6637
2
        va_end(ap);
6638
2
        return -1;
6639
24.2k
    } else {
6640
24.2k
        return FALSE;
6641
24.2k
    }
6642
24.2k
}
6643
6644
/* never use it directly */
6645
static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
6646
2
{
6647
2
    char buf[ATOM_GET_STR_BUF_SIZE];
6648
2
    return JS_ThrowTypeError(ctx, fmt,
6649
2
                             JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
6650
2
}
6651
6652
/* never use it directly */
6653
static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
6654
3
{
6655
3
    char buf[ATOM_GET_STR_BUF_SIZE];
6656
3
    return JS_ThrowSyntaxError(ctx, fmt,
6657
3
                             JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
6658
3
}
6659
6660
/* %s is replaced by 'atom'. The macro is used so that gcc can check
6661
    the format string. */
6662
2
#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, "")
6663
3
#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, "")
6664
6665
static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)
6666
0
{
6667
0
    if ((flags & JS_PROP_THROW) ||
6668
0
        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
6669
0
        JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom);
6670
0
        return -1;
6671
0
    } else {
6672
0
        return FALSE;
6673
0
    }
6674
0
}
6675
6676
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...)
6677
109k
{
6678
109k
    JSValue val;
6679
109k
    va_list ap;
6680
6681
109k
    va_start(ap, fmt);
6682
109k
    val = JS_ThrowError(ctx, JS_REFERENCE_ERROR, fmt, ap);
6683
109k
    va_end(ap);
6684
109k
    return val;
6685
109k
}
6686
6687
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...)
6688
0
{
6689
0
    JSValue val;
6690
0
    va_list ap;
6691
6692
0
    va_start(ap, fmt);
6693
0
    val = JS_ThrowError(ctx, JS_RANGE_ERROR, fmt, ap);
6694
0
    va_end(ap);
6695
0
    return val;
6696
0
}
6697
6698
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...)
6699
1.23k
{
6700
1.23k
    JSValue val;
6701
1.23k
    va_list ap;
6702
6703
1.23k
    va_start(ap, fmt);
6704
1.23k
    val = JS_ThrowError(ctx, JS_INTERNAL_ERROR, fmt, ap);
6705
1.23k
    va_end(ap);
6706
1.23k
    return val;
6707
1.23k
}
6708
6709
JSValue JS_ThrowOutOfMemory(JSContext *ctx)
6710
1.26k
{
6711
1.26k
    JSRuntime *rt = ctx->rt;
6712
1.26k
    if (!rt->in_out_of_memory) {
6713
1.20k
        rt->in_out_of_memory = TRUE;
6714
1.20k
        JS_ThrowInternalError(ctx, "out of memory");
6715
1.20k
        rt->in_out_of_memory = FALSE;
6716
1.20k
    }
6717
1.26k
    return JS_EXCEPTION;
6718
1.26k
}
6719
6720
static JSValue JS_ThrowStackOverflow(JSContext *ctx)
6721
21
{
6722
21
    return JS_ThrowInternalError(ctx, "stack overflow");
6723
21
}
6724
6725
static JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx)
6726
3
{
6727
3
    return JS_ThrowTypeError(ctx, "not an object");
6728
3
}
6729
6730
static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx)
6731
0
{
6732
0
    return JS_ThrowTypeError(ctx, "not a symbol");
6733
0
}
6734
6735
static JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name)
6736
222
{
6737
222
    char buf[ATOM_GET_STR_BUF_SIZE];
6738
222
    return JS_ThrowReferenceError(ctx, "'%s' is not defined",
6739
222
                                  JS_AtomGetStr(ctx, buf, sizeof(buf), name));
6740
222
}
6741
6742
static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name)
6743
0
{
6744
0
    char buf[ATOM_GET_STR_BUF_SIZE];
6745
0
    return JS_ThrowReferenceError(ctx, "%s is not initialized",
6746
0
                                  name == JS_ATOM_NULL ? "lexical variable" :
6747
0
                                  JS_AtomGetStr(ctx, buf, sizeof(buf), name));
6748
0
}
6749
6750
static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx,
6751
                                                    JSFunctionBytecode *b,
6752
                                                    int idx, BOOL is_ref)
6753
0
{
6754
0
    JSAtom atom = JS_ATOM_NULL;
6755
0
    if (is_ref) {
6756
0
        atom = b->closure_var[idx].var_name;
6757
0
    } else {
6758
        /* not present if the function is stripped and contains no eval() */
6759
0
        if (b->vardefs)
6760
0
            atom = b->vardefs[b->arg_count + idx].var_name;
6761
0
    }
6762
0
    return JS_ThrowReferenceErrorUninitialized(ctx, atom);
6763
0
}
6764
6765
static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
6766
0
{
6767
0
    JSRuntime *rt = ctx->rt;
6768
0
    JSAtom name;
6769
0
    name = rt->class_array[class_id].class_name;
6770
0
    return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
6771
0
}
6772
6773
static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
6774
1.36k
{
6775
1.36k
    JSRuntime *rt = ctx->rt;
6776
1.36k
    ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
6777
1.36k
    if (rt->interrupt_handler) {
6778
1.36k
        if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {
6779
            /* XXX: should set a specific flag to avoid catching */
6780
11
            JS_ThrowInternalError(ctx, "interrupted");
6781
11
            JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE);
6782
11
            return -1;
6783
11
        }
6784
1.36k
    }
6785
1.35k
    return 0;
6786
1.36k
}
6787
6788
static inline __exception int js_poll_interrupts(JSContext *ctx)
6789
13.6M
{
6790
13.6M
    if (unlikely(--ctx->interrupt_counter <= 0)) {
6791
1.36k
        return __js_poll_interrupts(ctx);
6792
13.6M
    } else {
6793
13.6M
        return 0;
6794
13.6M
    }
6795
13.6M
}
6796
6797
/* return -1 (exception) or TRUE/FALSE */
6798
static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj,
6799
                                   JSValueConst proto_val,
6800
                                   BOOL throw_flag)
6801
0
{
6802
0
    JSObject *proto, *p, *p1;
6803
0
    JSShape *sh;
6804
6805
0
    if (throw_flag) {
6806
0
        if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL ||
6807
0
            JS_VALUE_GET_TAG(obj) == JS_TAG_UNDEFINED)
6808
0
            goto not_obj;
6809
0
    } else {
6810
0
        if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6811
0
            goto not_obj;
6812
0
    }
6813
0
    p = JS_VALUE_GET_OBJ(obj);
6814
0
    if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) {
6815
0
        if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_NULL) {
6816
0
        not_obj:
6817
0
            JS_ThrowTypeErrorNotAnObject(ctx);
6818
0
            return -1;
6819
0
        }
6820
0
        proto = NULL;
6821
0
    } else {
6822
0
        proto = JS_VALUE_GET_OBJ(proto_val);
6823
0
    }
6824
6825
0
    if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6826
0
        return TRUE;
6827
6828
0
    if (unlikely(p->class_id == JS_CLASS_PROXY))
6829
0
        return js_proxy_setPrototypeOf(ctx, obj, proto_val, throw_flag);
6830
0
    sh = p->shape;
6831
0
    if (sh->proto == proto)
6832
0
        return TRUE;
6833
0
    if (!p->extensible) {
6834
0
        if (throw_flag) {
6835
0
            JS_ThrowTypeError(ctx, "object is not extensible");
6836
0
            return -1;
6837
0
        } else {
6838
0
            return FALSE;
6839
0
        }
6840
0
    }
6841
0
    if (proto) {
6842
        /* check if there is a cycle */
6843
0
        p1 = proto;
6844
0
        do {
6845
0
            if (p1 == p) {
6846
0
                if (throw_flag) {
6847
0
                    JS_ThrowTypeError(ctx, "circular prototype chain");
6848
0
                    return -1;
6849
0
                } else {
6850
0
                    return FALSE;
6851
0
                }
6852
0
            }
6853
            /* Note: for Proxy objects, proto is NULL */
6854
0
            p1 = p1->shape->proto;
6855
0
        } while (p1 != NULL);
6856
0
        JS_DupValue(ctx, proto_val);
6857
0
    }
6858
6859
0
    if (js_shape_prepare_update(ctx, p, NULL))
6860
0
        return -1;
6861
0
    sh = p->shape;
6862
0
    if (sh->proto)
6863
0
        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
6864
0
    sh->proto = proto;
6865
0
    return TRUE;
6866
0
}
6867
6868
/* return -1 (exception) or TRUE/FALSE */
6869
int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val)
6870
0
{
6871
0
    return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE);
6872
0
}
6873
6874
/* Only works for primitive types, otherwise return JS_NULL. */
6875
static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val)
6876
397k
{
6877
397k
    switch(JS_VALUE_GET_NORM_TAG(val)) {
6878
0
#ifdef CONFIG_BIGNUM
6879
12
    case JS_TAG_BIG_INT:
6880
12
        val = ctx->class_proto[JS_CLASS_BIG_INT];
6881
12
        break;
6882
0
    case JS_TAG_BIG_FLOAT:
6883
0
        val = ctx->class_proto[JS_CLASS_BIG_FLOAT];
6884
0
        break;
6885
0
    case JS_TAG_BIG_DECIMAL:
6886
0
        val = ctx->class_proto[JS_CLASS_BIG_DECIMAL];
6887
0
        break;
6888
0
#endif
6889
12.1k
    case JS_TAG_INT:
6890
24.4k
    case JS_TAG_FLOAT64:
6891
24.4k
        val = ctx->class_proto[JS_CLASS_NUMBER];
6892
24.4k
        break;
6893
8
    case JS_TAG_BOOL:
6894
8
        val = ctx->class_proto[JS_CLASS_BOOLEAN];
6895
8
        break;
6896
372k
    case JS_TAG_STRING:
6897
372k
        val = ctx->class_proto[JS_CLASS_STRING];
6898
372k
        break;
6899
0
    case JS_TAG_SYMBOL:
6900
0
        val = ctx->class_proto[JS_CLASS_SYMBOL];
6901
0
        break;
6902
0
    case JS_TAG_OBJECT:
6903
0
    case JS_TAG_NULL:
6904
0
    case JS_TAG_UNDEFINED:
6905
0
    default:
6906
0
        val = JS_NULL;
6907
0
        break;
6908
397k
    }
6909
397k
    return val;
6910
397k
}
6911
6912
/* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */
6913
JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj)
6914
2.20M
{
6915
2.20M
    JSValue val;
6916
2.20M
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
6917
2.20M
        JSObject *p;
6918
2.20M
        p = JS_VALUE_GET_OBJ(obj);
6919
2.20M
        if (unlikely(p->class_id == JS_CLASS_PROXY)) {
6920
0
            val = js_proxy_getPrototypeOf(ctx, obj);
6921
2.20M
        } else {
6922
2.20M
            p = p->shape->proto;
6923
2.20M
            if (!p)
6924
734k
                val = JS_NULL;
6925
1.46M
            else
6926
1.46M
                val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
6927
2.20M
        }
6928
2.20M
    } else {
6929
0
        val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj));
6930
0
    }
6931
2.20M
    return val;
6932
2.20M
}
6933
6934
static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj)
6935
2.20M
{
6936
2.20M
    JSValue obj1;
6937
2.20M
    obj1 = JS_GetPrototype(ctx, obj);
6938
2.20M
    JS_FreeValue(ctx, obj);
6939
2.20M
    return obj1;
6940
2.20M
}
6941
6942
/* return TRUE, FALSE or (-1) in case of exception */
6943
static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val,
6944
                                   JSValueConst obj)
6945
0
{
6946
0
    JSValue obj_proto;
6947
0
    JSObject *proto;
6948
0
    const JSObject *p, *proto1;
6949
0
    BOOL ret;
6950
6951
0
    if (!JS_IsFunction(ctx, obj))
6952
0
        return FALSE;
6953
0
    p = JS_VALUE_GET_OBJ(obj);
6954
0
    if (p->class_id == JS_CLASS_BOUND_FUNCTION) {
6955
0
        JSBoundFunction *s = p->u.bound_function;
6956
0
        return JS_IsInstanceOf(ctx, val, s->func_obj);
6957
0
    }
6958
6959
    /* Only explicitly boxed values are instances of constructors */
6960
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
6961
0
        return FALSE;
6962
0
    obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype);
6963
0
    if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) {
6964
0
        if (!JS_IsException(obj_proto))
6965
0
            JS_ThrowTypeError(ctx, "operand 'prototype' property is not an object");
6966
0
        ret = -1;
6967
0
        goto done;
6968
0
    }
6969
0
    proto = JS_VALUE_GET_OBJ(obj_proto);
6970
0
    p = JS_VALUE_GET_OBJ(val);
6971
0
    for(;;) {
6972
0
        proto1 = p->shape->proto;
6973
0
        if (!proto1) {
6974
            /* slow case if proxy in the prototype chain */
6975
0
            if (unlikely(p->class_id == JS_CLASS_PROXY)) {
6976
0
                JSValue obj1;
6977
0
                obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p));
6978
0
                for(;;) {
6979
0
                    obj1 = JS_GetPrototypeFree(ctx, obj1);
6980
0
                    if (JS_IsException(obj1)) {
6981
0
                        ret = -1;
6982
0
                        break;
6983
0
                    }
6984
0
                    if (JS_IsNull(obj1)) {
6985
0
                        ret = FALSE;
6986
0
                        break;
6987
0
                    }
6988
0
                    if (proto == JS_VALUE_GET_OBJ(obj1)) {
6989
0
                        JS_FreeValue(ctx, obj1);
6990
0
                        ret = TRUE;
6991
0
                        break;
6992
0
                    }
6993
                    /* must check for timeout to avoid infinite loop */
6994
0
                    if (js_poll_interrupts(ctx)) {
6995
0
                        JS_FreeValue(ctx, obj1);
6996
0
                        ret = -1;
6997
0
                        break;
6998
0
                    }
6999
0
                }
7000
0
            } else {
7001
0
                ret = FALSE;
7002
0
            }
7003
0
            break;
7004
0
        }
7005
0
        p = proto1;
7006
0
        if (proto == p) {
7007
0
            ret = TRUE;
7008
0
            break;
7009
0
        }
7010
0
    }
7011
0
done:
7012
0
    JS_FreeValue(ctx, obj_proto);
7013
0
    return ret;
7014
0
}
7015
7016
/* return TRUE, FALSE or (-1) in case of exception */
7017
int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj)
7018
0
{
7019
0
    JSValue method;
7020
7021
0
    if (!JS_IsObject(obj))
7022
0
        goto fail;
7023
0
    method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_hasInstance);
7024
0
    if (JS_IsException(method))
7025
0
        return -1;
7026
0
    if (!JS_IsNull(method) && !JS_IsUndefined(method)) {
7027
0
        JSValue ret;
7028
0
        ret = JS_CallFree(ctx, method, obj, 1, &val);
7029
0
        return JS_ToBoolFree(ctx, ret);
7030
0
    }
7031
7032
    /* legacy case */
7033
0
    if (!JS_IsFunction(ctx, obj)) {
7034
0
    fail:
7035
0
        JS_ThrowTypeError(ctx, "invalid 'instanceof' right operand");
7036
0
        return -1;
7037
0
    }
7038
0
    return JS_OrdinaryIsInstanceOf(ctx, val, obj);
7039
0
}
7040
7041
/* return the value associated to the autoinit property or an exception */
7042
typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
7043
7044
static JSAutoInitFunc *js_autoinit_func_table[] = {
7045
    js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */
7046
    js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */
7047
    JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */
7048
};
7049
7050
/* warning: 'prs' is reallocated after it */
7051
static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
7052
                               JSProperty *pr, JSShapeProperty *prs)
7053
55
{
7054
55
    JSValue val;
7055
55
    JSContext *realm;
7056
55
    JSAutoInitFunc *func;
7057
7058
55
    if (js_shape_prepare_update(ctx, p, &prs))
7059
0
        return -1;
7060
7061
55
    realm = js_autoinit_get_realm(pr);
7062
55
    func = js_autoinit_func_table[js_autoinit_get_id(pr)];
7063
    /* 'func' shall not modify the object properties 'pr' */
7064
55
    val = func(realm, p, prop, pr->u.init.opaque);
7065
55
    js_autoinit_free(ctx->rt, pr);
7066
55
    prs->flags &= ~JS_PROP_TMASK;
7067
55
    pr->u.value = JS_UNDEFINED;
7068
55
    if (JS_IsException(val))
7069
0
        return -1;
7070
55
    pr->u.value = val;
7071
55
    return 0;
7072
55
}
7073
7074
JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
7075
                               JSAtom prop, JSValueConst this_obj,
7076
                               BOOL throw_ref_error)
7077
11.6M
{
7078
11.6M
    JSObject *p;
7079
11.6M
    JSProperty *pr;
7080
11.6M
    JSShapeProperty *prs;
7081
11.6M
    uint32_t tag;
7082
7083
11.6M
    tag = JS_VALUE_GET_TAG(obj);
7084
11.6M
    if (unlikely(tag != JS_TAG_OBJECT)) {
7085
372k
        switch(tag) {
7086
0
        case JS_TAG_NULL:
7087
0
            return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop);
7088
2
        case JS_TAG_UNDEFINED:
7089
2
            return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop);
7090
0
        case JS_TAG_EXCEPTION:
7091
0
            return JS_EXCEPTION;
7092
372k
        case JS_TAG_STRING:
7093
372k
            {
7094
372k
                JSString *p1 = JS_VALUE_GET_STRING(obj);
7095
372k
                if (__JS_AtomIsTaggedInt(prop)) {
7096
11
                    uint32_t idx, ch;
7097
11
                    idx = __JS_AtomToUInt32(prop);
7098
11
                    if (idx < p1->len) {
7099
0
                        if (p1->is_wide_char)
7100
0
                            ch = p1->u.str16[idx];
7101
0
                        else
7102
0
                            ch = p1->u.str8[idx];
7103
0
                        return js_new_string_char(ctx, ch);
7104
0
                    }
7105
372k
                } else if (prop == JS_ATOM_length) {
7106
6
                    return JS_NewInt32(ctx, p1->len);
7107
6
                }
7108
372k
            }
7109
372k
            break;
7110
372k
        default:
7111
172
            break;
7112
372k
        }
7113
        /* cannot raise an exception */
7114
372k
        p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));
7115
372k
        if (!p)
7116
0
            return JS_UNDEFINED;
7117
11.2M
    } else {
7118
11.2M
        p = JS_VALUE_GET_OBJ(obj);
7119
11.2M
    }
7120
7121
20.0M
    for(;;) {
7122
20.0M
        prs = find_own_property(&pr, p, prop);
7123
20.0M
        if (prs) {
7124
            /* found */
7125
8.00M
            if (unlikely(prs->flags & JS_PROP_TMASK)) {
7126
337k
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
7127
337k
                    if (unlikely(!pr->u.getset.getter)) {
7128
0
                        return JS_UNDEFINED;
7129
337k
                    } else {
7130
337k
                        JSValue func = JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter);
7131
                        /* Note: the field could be removed in the getter */
7132
337k
                        func = JS_DupValue(ctx, func);
7133
337k
                        return JS_CallFree(ctx, func, this_obj, 0, NULL);
7134
337k
                    }
7135
337k
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
7136
0
                    JSValue val = *pr->u.var_ref->pvalue;
7137
0
                    if (unlikely(JS_IsUninitialized(val)))
7138
0
                        return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7139
0
                    return JS_DupValue(ctx, val);
7140
55
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
7141
                    /* Instantiate property and retry */
7142
55
                    if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
7143
0
                        return JS_EXCEPTION;
7144
55
                    continue;
7145
55
                }
7146
7.66M
            } else {
7147
7.66M
                return JS_DupValue(ctx, pr->u.value);
7148
7.66M
            }
7149
8.00M
        }
7150
12.0M
        if (unlikely(p->is_exotic)) {
7151
            /* exotic behaviors */
7152
5.48M
            if (p->fast_array) {
7153
2.27M
                if (__JS_AtomIsTaggedInt(prop)) {
7154
4.32k
                    uint32_t idx = __JS_AtomToUInt32(prop);
7155
4.32k
                    if (idx < p->u.array.count) {
7156
                        /* we avoid duplicating the code */
7157
2.06k
                        return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
7158
2.25k
                    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
7159
2.25k
                               p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
7160
0
                        return JS_UNDEFINED;
7161
0
                    }
7162
2.26M
                } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
7163
2.26M
                           p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
7164
0
                    int ret;
7165
0
                    ret = JS_AtomIsNumericIndex(ctx, prop);
7166
0
                    if (ret != 0) {
7167
0
                        if (ret < 0)
7168
0
                            return JS_EXCEPTION;
7169
0
                        return JS_UNDEFINED;
7170
0
                    }
7171
0
                }
7172
3.21M
            } else {
7173
3.21M
                const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7174
3.21M
                if (em) {
7175
1.59M
                    if (em->get_property) {
7176
0
                        JSValue obj1, retval;
7177
                        /* XXX: should pass throw_ref_error */
7178
                        /* Note: if 'p' is a prototype, it can be
7179
                           freed in the called function */
7180
0
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7181
0
                        retval = em->get_property(ctx, obj1, prop, this_obj);
7182
0
                        JS_FreeValue(ctx, obj1);
7183
0
                        return retval;
7184
0
                    }
7185
1.59M
                    if (em->get_own_property) {
7186
1.59M
                        JSPropertyDescriptor desc;
7187
1.59M
                        int ret;
7188
1.59M
                        JSValue obj1;
7189
7190
                        /* Note: if 'p' is a prototype, it can be
7191
                           freed in the called function */
7192
1.59M
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7193
1.59M
                        ret = em->get_own_property(ctx, &desc, obj1, prop);
7194
1.59M
                        JS_FreeValue(ctx, obj1);
7195
1.59M
                        if (ret < 0)
7196
0
                            return JS_EXCEPTION;
7197
1.59M
                        if (ret) {
7198
1.58M
                            if (desc.flags & JS_PROP_GETSET) {
7199
0
                                JS_FreeValue(ctx, desc.setter);
7200
0
                                return JS_CallFree(ctx, desc.getter, this_obj, 0, NULL);
7201
1.58M
                            } else {
7202
1.58M
                                return desc.value;
7203
1.58M
                            }
7204
1.58M
                        }
7205
1.59M
                    }
7206
1.59M
                }
7207
3.21M
            }
7208
5.48M
        }
7209
10.4M
        p = p->shape->proto;
7210
10.4M
        if (!p)
7211
2.07M
            break;
7212
10.4M
    }
7213
2.07M
    if (unlikely(throw_ref_error)) {
7214
202
        return JS_ThrowReferenceErrorNotDefined(ctx, prop);
7215
2.07M
    } else {
7216
2.07M
        return JS_UNDEFINED;
7217
2.07M
    }
7218
2.07M
}
7219
7220
static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom)
7221
0
{
7222
0
    return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist",
7223
0
                                 atom);
7224
0
}
7225
7226
/* Private fields can be added even on non extensible objects or
7227
   Proxies */
7228
static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj,
7229
                                 JSValueConst name, JSValue val)
7230
409k
{
7231
409k
    JSObject *p;
7232
409k
    JSShapeProperty *prs;
7233
409k
    JSProperty *pr;
7234
409k
    JSAtom prop;
7235
7236
409k
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
7237
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7238
0
        goto fail;
7239
0
    }
7240
    /* safety check */
7241
409k
    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
7242
0
        JS_ThrowTypeErrorNotASymbol(ctx);
7243
0
        goto fail;
7244
0
    }
7245
409k
    prop = js_symbol_to_atom(ctx, (JSValue)name);
7246
409k
    p = JS_VALUE_GET_OBJ(obj);
7247
409k
    prs = find_own_property(&pr, p, prop);
7248
409k
    if (prs) {
7249
0
        JS_ThrowTypeErrorAtom(ctx, "private class field '%s' already exists",
7250
0
                              prop);
7251
0
        goto fail;
7252
0
    }
7253
409k
    pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
7254
409k
    if (unlikely(!pr)) {
7255
0
    fail:
7256
0
        JS_FreeValue(ctx, val);
7257
0
        return -1;
7258
0
    }
7259
409k
    pr->u.value = val;
7260
409k
    return 0;
7261
409k
}
7262
7263
static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj,
7264
                                  JSValueConst name)
7265
0
{
7266
0
    JSObject *p;
7267
0
    JSShapeProperty *prs;
7268
0
    JSProperty *pr;
7269
0
    JSAtom prop;
7270
7271
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7272
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
7273
    /* safety check */
7274
0
    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL))
7275
0
        return JS_ThrowTypeErrorNotASymbol(ctx);
7276
0
    prop = js_symbol_to_atom(ctx, (JSValue)name);
7277
0
    p = JS_VALUE_GET_OBJ(obj);
7278
0
    prs = find_own_property(&pr, p, prop);
7279
0
    if (!prs) {
7280
0
        JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
7281
0
        return JS_EXCEPTION;
7282
0
    }
7283
0
    return JS_DupValue(ctx, pr->u.value);
7284
0
}
7285
7286
static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj,
7287
                              JSValueConst name, JSValue val)
7288
0
{
7289
0
    JSObject *p;
7290
0
    JSShapeProperty *prs;
7291
0
    JSProperty *pr;
7292
0
    JSAtom prop;
7293
7294
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
7295
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7296
0
        goto fail;
7297
0
    }
7298
    /* safety check */
7299
0
    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
7300
0
        JS_ThrowTypeErrorNotASymbol(ctx);
7301
0
        goto fail;
7302
0
    }
7303
0
    prop = js_symbol_to_atom(ctx, (JSValue)name);
7304
0
    p = JS_VALUE_GET_OBJ(obj);
7305
0
    prs = find_own_property(&pr, p, prop);
7306
0
    if (!prs) {
7307
0
        JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
7308
0
    fail:
7309
0
        JS_FreeValue(ctx, val);
7310
0
        return -1;
7311
0
    }
7312
0
    set_value(ctx, &pr->u.value, val);
7313
0
    return 0;
7314
0
}
7315
7316
static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
7317
13.9k
{
7318
13.9k
    JSObject *p, *p1;
7319
13.9k
    JSShapeProperty *prs;
7320
13.9k
    JSProperty *pr;
7321
13.9k
    JSValue brand;
7322
13.9k
    JSAtom brand_atom;
7323
    
7324
13.9k
    if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) {
7325
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7326
0
        return -1;
7327
0
    }
7328
13.9k
    p = JS_VALUE_GET_OBJ(home_obj);
7329
13.9k
    prs = find_own_property(&pr, p, JS_ATOM_Private_brand);
7330
13.9k
    if (!prs) {
7331
13.9k
        brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE);
7332
13.9k
        if (JS_IsException(brand))
7333
0
            return -1;
7334
        /* if the brand is not present, add it */
7335
13.9k
        pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E);
7336
13.9k
        if (!pr) {
7337
0
            JS_FreeValue(ctx, brand);
7338
0
            return -1;
7339
0
        }
7340
13.9k
        pr->u.value = JS_DupValue(ctx, brand);
7341
13.9k
    } else {
7342
0
        brand = JS_DupValue(ctx, pr->u.value);
7343
0
    }
7344
13.9k
    brand_atom = js_symbol_to_atom(ctx, brand);
7345
    
7346
13.9k
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
7347
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7348
0
        JS_FreeAtom(ctx, brand_atom);
7349
0
        return -1;
7350
0
    }
7351
13.9k
    p1 = JS_VALUE_GET_OBJ(obj);
7352
13.9k
    pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E);
7353
13.9k
    JS_FreeAtom(ctx, brand_atom);
7354
13.9k
    if (!pr)
7355
0
        return -1;
7356
13.9k
    pr->u.value = JS_UNDEFINED;
7357
13.9k
    return 0;
7358
13.9k
}
7359
7360
static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
7361
0
{
7362
0
    JSObject *p, *p1, *home_obj;
7363
0
    JSShapeProperty *prs;
7364
0
    JSProperty *pr;
7365
0
    JSValueConst brand;
7366
    
7367
    /* get the home object of 'func' */
7368
0
    if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) {
7369
0
    not_obj:
7370
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7371
0
        return -1;
7372
0
    }
7373
0
    p1 = JS_VALUE_GET_OBJ(func);
7374
0
    if (!js_class_has_bytecode(p1->class_id))
7375
0
        goto not_obj;
7376
0
    home_obj = p1->u.func.home_object;
7377
0
    if (!home_obj)
7378
0
        goto not_obj;
7379
0
    prs = find_own_property(&pr, home_obj, JS_ATOM_Private_brand);
7380
0
    if (!prs) {
7381
0
        JS_ThrowTypeError(ctx, "expecting <brand> private field");
7382
0
        return -1;
7383
0
    }
7384
0
    brand = pr->u.value;
7385
    /* safety check */
7386
0
    if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL))
7387
0
        goto not_obj;
7388
    
7389
    /* get the brand array of 'obj' */
7390
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7391
0
        goto not_obj;
7392
0
    p = JS_VALUE_GET_OBJ(obj);
7393
0
    prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand));
7394
0
    if (!prs) {
7395
0
        JS_ThrowTypeError(ctx, "invalid brand on object");
7396
0
        return -1;
7397
0
    }
7398
0
    return 0;
7399
0
}
7400
7401
static uint32_t js_string_obj_get_length(JSContext *ctx,
7402
                                         JSValueConst obj)
7403
333k
{
7404
333k
    JSObject *p;
7405
333k
    JSString *p1;
7406
333k
    uint32_t len = 0;
7407
7408
    /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
7409
333k
    p = JS_VALUE_GET_OBJ(obj);
7410
333k
    if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
7411
333k
        p1 = JS_VALUE_GET_STRING(p->u.object_data);
7412
333k
        len = p1->len;
7413
333k
    }
7414
333k
    return len;
7415
333k
}
7416
7417
static int num_keys_cmp(const void *p1, const void *p2, void *opaque)
7418
19.6M
{
7419
19.6M
    JSContext *ctx = opaque;
7420
19.6M
    JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom;
7421
19.6M
    JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom;
7422
19.6M
    uint32_t v1, v2;
7423
19.6M
    BOOL atom1_is_integer, atom2_is_integer;
7424
7425
19.6M
    atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1);
7426
19.6M
    atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2);
7427
19.6M
    assert(atom1_is_integer && atom2_is_integer);
7428
19.6M
    if (v1 < v2)
7429
10.5M
        return -1;
7430
9.02M
    else if (v1 == v2)
7431
0
        return 0;
7432
9.02M
    else
7433
9.02M
        return 1;
7434
19.6M
}
7435
7436
static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
7437
2.75M
{
7438
2.75M
    uint32_t i;
7439
2.75M
    if (tab) {
7440
7.79M
        for(i = 0; i < len; i++)
7441
5.04M
            JS_FreeAtom(ctx, tab[i].atom);
7442
2.75M
        js_free(ctx, tab);
7443
2.75M
    }
7444
2.75M
}
7445
7446
/* return < 0 in case if exception, 0 if OK. ptab and its atoms must
7447
   be freed by the user. */
7448
static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
7449
                                                      JSPropertyEnum **ptab,
7450
                                                      uint32_t *plen,
7451
                                                      JSObject *p, int flags)
7452
2.75M
{
7453
2.75M
    int i, j;
7454
2.75M
    JSShape *sh;
7455
2.75M
    JSShapeProperty *prs;
7456
2.75M
    JSPropertyEnum *tab_atom, *tab_exotic;
7457
2.75M
    JSAtom atom;
7458
2.75M
    uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count;
7459
2.75M
    uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count;
7460
2.75M
    BOOL is_enumerable, num_sorted;
7461
2.75M
    uint32_t num_key;
7462
2.75M
    JSAtomKindEnum kind;
7463
    
7464
    /* clear pointer for consistency in case of failure */
7465
2.75M
    *ptab = NULL;
7466
2.75M
    *plen = 0;
7467
7468
    /* compute the number of returned properties */
7469
2.75M
    num_keys_count = 0;
7470
2.75M
    str_keys_count = 0;
7471
2.75M
    sym_keys_count = 0;
7472
2.75M
    exotic_keys_count = 0;
7473
2.75M
    exotic_count = 0;
7474
2.75M
    tab_exotic = NULL;
7475
2.75M
    sh = p->shape;
7476
26.9M
    for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
7477
24.1M
        atom = prs->atom;
7478
24.1M
        if (atom != JS_ATOM_NULL) {
7479
24.1M
            is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
7480
24.1M
            kind = JS_AtomGetKind(ctx, atom);
7481
24.1M
            if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
7482
24.1M
                ((flags >> kind) & 1) != 0) {
7483
                /* need to raise an exception in case of the module
7484
                   name space (implicit GetOwnProperty) */
7485
1.63M
                if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) &&
7486
1.63M
                    (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY))) {
7487
0
                    JSVarRef *var_ref = p->prop[i].u.var_ref;
7488
0
                    if (unlikely(JS_IsUninitialized(*var_ref->pvalue))) {
7489
0
                        JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7490
0
                        return -1;
7491
0
                    }
7492
0
                }
7493
1.63M
                if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
7494
1.46M
                    num_keys_count++;
7495
1.46M
                } else if (kind == JS_ATOM_KIND_STRING) {
7496
177k
                    str_keys_count++;
7497
177k
                } else {
7498
0
                    sym_keys_count++;
7499
0
                }
7500
1.63M
            }
7501
24.1M
        }
7502
24.1M
    }
7503
7504
2.75M
    if (p->is_exotic) {
7505
166k
        if (p->fast_array) {
7506
20
            if (flags & JS_GPN_STRING_MASK) {
7507
20
                num_keys_count += p->u.array.count;
7508
20
            }
7509
166k
        } else if (p->class_id == JS_CLASS_STRING) {
7510
166k
            if (flags & JS_GPN_STRING_MASK) {
7511
166k
                num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7512
166k
            }
7513
166k
        } else {
7514
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7515
0
            if (em && em->get_own_property_names) {
7516
0
                if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count,
7517
0
                                               JS_MKPTR(JS_TAG_OBJECT, p)))
7518
0
                    return -1;
7519
0
                for(i = 0; i < exotic_count; i++) {
7520
0
                    atom = tab_exotic[i].atom;
7521
0
                    kind = JS_AtomGetKind(ctx, atom);
7522
0
                    if (((flags >> kind) & 1) != 0) {
7523
0
                        is_enumerable = FALSE;
7524
0
                        if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) {
7525
0
                            JSPropertyDescriptor desc;
7526
0
                            int res;
7527
                            /* set the "is_enumerable" field if necessary */
7528
0
                            res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
7529
0
                            if (res < 0) {
7530
0
                                js_free_prop_enum(ctx, tab_exotic, exotic_count);
7531
0
                                return -1;
7532
0
                            }
7533
0
                            if (res) {
7534
0
                                is_enumerable =
7535
0
                                    ((desc.flags & JS_PROP_ENUMERABLE) != 0);
7536
0
                                js_free_desc(ctx, &desc);
7537
0
                            }
7538
0
                            tab_exotic[i].is_enumerable = is_enumerable;
7539
0
                        }
7540
0
                        if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) {
7541
0
                            exotic_keys_count++;
7542
0
                        }
7543
0
                    }
7544
0
                }
7545
0
            }
7546
0
        }
7547
166k
    }
7548
7549
    /* fill them */
7550
7551
2.75M
    atom_count = num_keys_count + str_keys_count + sym_keys_count + exotic_keys_count;
7552
    /* avoid allocating 0 bytes */
7553
2.75M
    tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));
7554
2.75M
    if (!tab_atom) {
7555
0
        js_free_prop_enum(ctx, tab_exotic, exotic_count);
7556
0
        return -1;
7557
0
    }
7558
7559
2.75M
    num_index = 0;
7560
2.75M
    str_index = num_keys_count;
7561
2.75M
    sym_index = str_index + str_keys_count;
7562
7563
2.75M
    num_sorted = TRUE;
7564
2.75M
    sh = p->shape;
7565
26.9M
    for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
7566
24.1M
        atom = prs->atom;
7567
24.1M
        if (atom != JS_ATOM_NULL) {
7568
24.1M
            is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
7569
24.1M
            kind = JS_AtomGetKind(ctx, atom);
7570
24.1M
            if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
7571
24.1M
                ((flags >> kind) & 1) != 0) {
7572
1.63M
                if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
7573
1.46M
                    j = num_index++;
7574
1.46M
                    num_sorted = FALSE;
7575
1.46M
                } else if (kind == JS_ATOM_KIND_STRING) {
7576
177k
                    j = str_index++;
7577
177k
                } else {
7578
0
                    j = sym_index++;
7579
0
                }
7580
1.63M
                tab_atom[j].atom = JS_DupAtom(ctx, atom);
7581
1.63M
                tab_atom[j].is_enumerable = is_enumerable;
7582
1.63M
            }
7583
24.1M
        }
7584
24.1M
    }
7585
7586
2.75M
    if (p->is_exotic) {
7587
166k
        int len;
7588
166k
        if (p->fast_array) {
7589
20
            if (flags & JS_GPN_STRING_MASK) {
7590
20
                len = p->u.array.count;
7591
20
                goto add_array_keys;
7592
20
            }
7593
166k
        } else if (p->class_id == JS_CLASS_STRING) {
7594
166k
            if (flags & JS_GPN_STRING_MASK) {
7595
166k
                len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7596
166k
            add_array_keys:
7597
3.56M
                for(i = 0; i < len; i++) {
7598
3.40M
                    tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
7599
3.40M
                    if (tab_atom[num_index].atom == JS_ATOM_NULL) {
7600
0
                        js_free_prop_enum(ctx, tab_atom, num_index);
7601
0
                        return -1;
7602
0
                    }
7603
3.40M
                    tab_atom[num_index].is_enumerable = TRUE;
7604
3.40M
                    num_index++;
7605
3.40M
                }
7606
166k
            }
7607
166k
        } else {
7608
            /* Note: exotic keys are not reordered and comes after the object own properties. */
7609
0
            for(i = 0; i < exotic_count; i++) {
7610
0
                atom = tab_exotic[i].atom;
7611
0
                is_enumerable = tab_exotic[i].is_enumerable;
7612
0
                kind = JS_AtomGetKind(ctx, atom);
7613
0
                if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
7614
0
                    ((flags >> kind) & 1) != 0) {
7615
0
                    tab_atom[sym_index].atom = atom;
7616
0
                    tab_atom[sym_index].is_enumerable = is_enumerable;
7617
0
                    sym_index++;
7618
0
                } else {
7619
0
                    JS_FreeAtom(ctx, atom);
7620
0
                }
7621
0
            }
7622
0
            js_free(ctx, tab_exotic);
7623
0
        }
7624
166k
    }
7625
7626
2.75M
    assert(num_index == num_keys_count);
7627
2.75M
    assert(str_index == num_keys_count + str_keys_count);
7628
2.75M
    assert(sym_index == atom_count);
7629
7630
2.75M
    if (num_keys_count != 0 && !num_sorted) {
7631
1.15k
        rqsort(tab_atom, num_keys_count, sizeof(tab_atom[0]), num_keys_cmp,
7632
1.15k
               ctx);
7633
1.15k
    }
7634
2.75M
    *ptab = tab_atom;
7635
2.75M
    *plen = atom_count;
7636
2.75M
    return 0;
7637
2.75M
}
7638
7639
int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
7640
                           uint32_t *plen, JSValueConst obj, int flags)
7641
0
{
7642
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
7643
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7644
0
        return -1;
7645
0
    }
7646
0
    return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
7647
0
                                          JS_VALUE_GET_OBJ(obj), flags);
7648
0
}
7649
7650
/* Return -1 if exception,
7651
   FALSE if the property does not exist, TRUE if it exists. If TRUE is
7652
   returned, the property descriptor 'desc' is filled present. */
7653
static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
7654
                                     JSObject *p, JSAtom prop)
7655
17.1M
{
7656
17.1M
    JSShapeProperty *prs;
7657
17.1M
    JSProperty *pr;
7658
7659
17.1M
retry:
7660
17.1M
    prs = find_own_property(&pr, p, prop);
7661
17.1M
    if (prs) {
7662
1.54M
        if (desc) {
7663
4
            desc->flags = prs->flags & JS_PROP_C_W_E;
7664
4
            desc->getter = JS_UNDEFINED;
7665
4
            desc->setter = JS_UNDEFINED;
7666
4
            desc->value = JS_UNDEFINED;
7667
4
            if (unlikely(prs->flags & JS_PROP_TMASK)) {
7668
0
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
7669
0
                    desc->flags |= JS_PROP_GETSET;
7670
0
                    if (pr->u.getset.getter)
7671
0
                        desc->getter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
7672
0
                    if (pr->u.getset.setter)
7673
0
                        desc->setter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
7674
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
7675
0
                    JSValue val = *pr->u.var_ref->pvalue;
7676
0
                    if (unlikely(JS_IsUninitialized(val))) {
7677
0
                        JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7678
0
                        return -1;
7679
0
                    }
7680
0
                    desc->value = JS_DupValue(ctx, val);
7681
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
7682
                    /* Instantiate property and retry */
7683
0
                    if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
7684
0
                        return -1;
7685
0
                    goto retry;
7686
0
                }
7687
4
            } else {
7688
4
                desc->value = JS_DupValue(ctx, pr->u.value);
7689
4
            }
7690
1.54M
        } else {
7691
            /* for consistency, send the exception even if desc is NULL */
7692
1.54M
            if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF)) {
7693
0
                if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) {
7694
0
                    JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7695
0
                    return -1;
7696
0
                }
7697
1.54M
            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
7698
                /* nothing to do: delay instantiation until actual value and/or attributes are read */
7699
0
            }
7700
1.54M
        }
7701
1.54M
        return TRUE;
7702
1.54M
    }
7703
15.6M
    if (p->is_exotic) {
7704
3.92M
        if (p->fast_array) {
7705
            /* specific case for fast arrays */
7706
201k
            if (__JS_AtomIsTaggedInt(prop)) {
7707
201k
                uint32_t idx;
7708
201k
                idx = __JS_AtomToUInt32(prop);
7709
201k
                if (idx < p->u.array.count) {
7710
201k
                    if (desc) {
7711
0
                        desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE |
7712
0
                            JS_PROP_CONFIGURABLE;
7713
0
                        desc->getter = JS_UNDEFINED;
7714
0
                        desc->setter = JS_UNDEFINED;
7715
0
                        desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
7716
0
                    }
7717
201k
                    return TRUE;
7718
201k
                }
7719
201k
            }
7720
3.72M
        } else {
7721
3.72M
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7722
3.72M
            if (em && em->get_own_property) {
7723
3.72M
                return em->get_own_property(ctx, desc,
7724
3.72M
                                            JS_MKPTR(JS_TAG_OBJECT, p), prop);
7725
3.72M
            }
7726
3.72M
        }
7727
3.92M
    }
7728
11.7M
    return FALSE;
7729
15.6M
}
7730
7731
int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
7732
                      JSValueConst obj, JSAtom prop)
7733
0
{
7734
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
7735
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7736
0
        return -1;
7737
0
    }
7738
0
    return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop);
7739
0
}
7740
7741
/* return -1 if exception (Proxy object only) or TRUE/FALSE */
7742
int JS_IsExtensible(JSContext *ctx, JSValueConst obj)
7743
0
{
7744
0
    JSObject *p;
7745
7746
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7747
0
        return FALSE;
7748
0
    p = JS_VALUE_GET_OBJ(obj);
7749
0
    if (unlikely(p->class_id == JS_CLASS_PROXY))
7750
0
        return js_proxy_isExtensible(ctx, obj);
7751
0
    else
7752
0
        return p->extensible;
7753
0
}
7754
7755
/* return -1 if exception (Proxy object only) or TRUE/FALSE */
7756
int JS_PreventExtensions(JSContext *ctx, JSValueConst obj)
7757
1.18k
{
7758
1.18k
    JSObject *p;
7759
7760
1.18k
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7761
0
        return FALSE;
7762
1.18k
    p = JS_VALUE_GET_OBJ(obj);
7763
1.18k
    if (unlikely(p->class_id == JS_CLASS_PROXY))
7764
0
        return js_proxy_preventExtensions(ctx, obj);
7765
1.18k
    p->extensible = FALSE;
7766
1.18k
    return TRUE;
7767
1.18k
}
7768
7769
/* return -1 if exception otherwise TRUE or FALSE */
7770
int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop)
7771
7.13M
{
7772
7.13M
    JSObject *p;
7773
7.13M
    int ret;
7774
7.13M
    JSValue obj1;
7775
7776
7.13M
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7777
0
        return FALSE;
7778
7.13M
    p = JS_VALUE_GET_OBJ(obj);
7779
14.4M
    for(;;) {
7780
14.4M
        if (p->is_exotic) {
7781
3.94M
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7782
3.94M
            if (em && em->has_property) {
7783
                /* has_property can free the prototype */
7784
0
                obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7785
0
                ret = em->has_property(ctx, obj1, prop);
7786
0
                JS_FreeValue(ctx, obj1);
7787
0
                return ret;
7788
0
            }
7789
3.94M
        }
7790
        /* JS_GetOwnPropertyInternal can free the prototype */
7791
14.4M
        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7792
14.4M
        ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop);
7793
14.4M
        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7794
14.4M
        if (ret != 0)
7795
3.53M
            return ret;
7796
10.8M
        if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
7797
10.8M
            p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
7798
0
            ret = JS_AtomIsNumericIndex(ctx, prop);
7799
0
            if (ret != 0) {
7800
0
                if (ret < 0)
7801
0
                    return -1;
7802
0
                return FALSE;
7803
0
            }
7804
0
        }
7805
10.8M
        p = p->shape->proto;
7806
10.8M
        if (!p)
7807
3.59M
            break;
7808
10.8M
    }
7809
3.59M
    return FALSE;
7810
7.13M
}
7811
7812
/* val must be a symbol */
7813
static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val)
7814
423k
{
7815
423k
    JSAtomStruct *p = JS_VALUE_GET_PTR(val);
7816
423k
    return js_get_atom_index(ctx->rt, p);
7817
423k
}
7818
7819
/* return JS_ATOM_NULL in case of exception */
7820
JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
7821
4.86M
{
7822
4.86M
    JSAtom atom;
7823
4.86M
    uint32_t tag;
7824
4.86M
    tag = JS_VALUE_GET_TAG(val);
7825
4.86M
    if (tag == JS_TAG_INT &&
7826
4.86M
        (uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) {
7827
        /* fast path for integer values */
7828
3.70M
        atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val));
7829
3.70M
    } else if (tag == JS_TAG_SYMBOL) {
7830
10.0k
        JSAtomStruct *p = JS_VALUE_GET_PTR(val);
7831
10.0k
        atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p));
7832
1.14M
    } else {
7833
1.14M
        JSValue str;
7834
1.14M
        str = JS_ToPropertyKey(ctx, val);
7835
1.14M
        if (JS_IsException(str))
7836
0
            return JS_ATOM_NULL;
7837
1.14M
        if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) {
7838
0
            atom = js_symbol_to_atom(ctx, str);
7839
1.14M
        } else {
7840
1.14M
            atom = JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(str));
7841
1.14M
        }
7842
1.14M
    }
7843
4.86M
    return atom;
7844
4.86M
}
7845
7846
static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
7847
                                   JSValue prop)
7848
1.30M
{
7849
1.30M
    JSAtom atom;
7850
1.30M
    JSValue ret;
7851
7852
1.30M
    if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
7853
1.30M
               JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
7854
1.29M
        JSObject *p;
7855
1.29M
        uint32_t idx, len;
7856
        /* fast path for array access */
7857
1.29M
        p = JS_VALUE_GET_OBJ(this_obj);
7858
1.29M
        idx = JS_VALUE_GET_INT(prop);
7859
1.29M
        len = (uint32_t)p->u.array.count;
7860
1.29M
        if (unlikely(idx >= len))
7861
832k
            goto slow_path;
7862
465k
        switch(p->class_id) {
7863
465k
        case JS_CLASS_ARRAY:
7864
465k
        case JS_CLASS_ARGUMENTS:
7865
465k
            return JS_DupValue(ctx, p->u.array.u.values[idx]);
7866
0
        case JS_CLASS_INT8_ARRAY:
7867
0
            return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]);
7868
0
        case JS_CLASS_UINT8C_ARRAY:
7869
0
        case JS_CLASS_UINT8_ARRAY:
7870
0
            return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]);
7871
0
        case JS_CLASS_INT16_ARRAY:
7872
0
            return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]);
7873
0
        case JS_CLASS_UINT16_ARRAY:
7874
0
            return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]);
7875
0
        case JS_CLASS_INT32_ARRAY:
7876
0
            return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]);
7877
0
        case JS_CLASS_UINT32_ARRAY:
7878
0
            return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]);
7879
0
#ifdef CONFIG_BIGNUM
7880
0
        case JS_CLASS_BIG_INT64_ARRAY:
7881
0
            return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
7882
0
        case JS_CLASS_BIG_UINT64_ARRAY:
7883
0
            return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
7884
0
#endif
7885
0
        case JS_CLASS_FLOAT32_ARRAY:
7886
0
            return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]);
7887
0
        case JS_CLASS_FLOAT64_ARRAY:
7888
0
            return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]);
7889
0
        default:
7890
0
            goto slow_path;
7891
465k
        }
7892
465k
    } else {
7893
839k
    slow_path:
7894
839k
        atom = JS_ValueToAtom(ctx, prop);
7895
839k
        JS_FreeValue(ctx, prop);
7896
839k
        if (unlikely(atom == JS_ATOM_NULL))
7897
0
            return JS_EXCEPTION;
7898
839k
        ret = JS_GetProperty(ctx, this_obj, atom);
7899
839k
        JS_FreeAtom(ctx, atom);
7900
839k
        return ret;
7901
839k
    }
7902
1.30M
}
7903
7904
JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
7905
                             uint32_t idx)
7906
1.07M
{
7907
1.07M
    return JS_GetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx));
7908
1.07M
}
7909
7910
/* Check if an object has a generalized numeric property. Return value:
7911
   -1 for exception,
7912
   TRUE if property exists, stored into *pval,
7913
   FALSE if proprty does not exist.
7914
 */
7915
static int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, JSValue *pval)
7916
225k
{
7917
225k
    JSValue val = JS_UNDEFINED;
7918
225k
    JSAtom prop;
7919
225k
    int present;
7920
7921
225k
    if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) {
7922
        /* fast path */
7923
225k
        present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx));
7924
225k
        if (present > 0) {
7925
225k
            val = JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
7926
225k
            if (unlikely(JS_IsException(val)))
7927
0
                present = -1;
7928
225k
        }
7929
225k
    } else {
7930
0
        prop = JS_NewAtomInt64(ctx, idx);
7931
0
        present = -1;
7932
0
        if (likely(prop != JS_ATOM_NULL)) {
7933
0
            present = JS_HasProperty(ctx, obj, prop);
7934
0
            if (present > 0) {
7935
0
                val = JS_GetProperty(ctx, obj, prop);
7936
0
                if (unlikely(JS_IsException(val)))
7937
0
                    present = -1;
7938
0
            }
7939
0
            JS_FreeAtom(ctx, prop);
7940
0
        }
7941
0
    }
7942
225k
    *pval = val;
7943
225k
    return present;
7944
225k
}
7945
7946
static JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx)
7947
0
{
7948
0
    JSAtom prop;
7949
0
    JSValue val;
7950
7951
0
    if ((uint64_t)idx <= INT32_MAX) {
7952
        /* fast path for fast arrays */
7953
0
        return JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
7954
0
    }
7955
0
    prop = JS_NewAtomInt64(ctx, idx);
7956
0
    if (prop == JS_ATOM_NULL)
7957
0
        return JS_EXCEPTION;
7958
7959
0
    val = JS_GetProperty(ctx, obj, prop);
7960
0
    JS_FreeAtom(ctx, prop);
7961
0
    return val;
7962
0
}
7963
7964
JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
7965
                          const char *prop)
7966
67.9k
{
7967
67.9k
    JSAtom atom;
7968
67.9k
    JSValue ret;
7969
67.9k
    atom = JS_NewAtom(ctx, prop);
7970
67.9k
    ret = JS_GetProperty(ctx, this_obj, atom);
7971
67.9k
    JS_FreeAtom(ctx, atom);
7972
67.9k
    return ret;
7973
67.9k
}
7974
7975
/* Note: the property value is not initialized. Return NULL if memory
7976
   error. */
7977
static JSProperty *add_property(JSContext *ctx,
7978
                                JSObject *p, JSAtom prop, int prop_flags)
7979
13.8M
{
7980
13.8M
    JSShape *sh, *new_sh;
7981
7982
13.8M
    sh = p->shape;
7983
13.8M
    if (sh->is_hashed) {
7984
        /* try to find an existing shape */
7985
13.8M
        new_sh = find_hashed_shape_prop(ctx->rt, sh, prop, prop_flags);
7986
13.8M
        if (new_sh) {
7987
            /* matching shape found: use it */
7988
            /*  the property array may need to be resized */
7989
4.89M
            if (new_sh->prop_size != sh->prop_size) {
7990
541k
                JSProperty *new_prop;
7991
541k
                new_prop = js_realloc(ctx, p->prop, sizeof(p->prop[0]) *
7992
541k
                                      new_sh->prop_size);
7993
541k
                if (!new_prop)
7994
0
                    return NULL;
7995
541k
                p->prop = new_prop;
7996
541k
            }
7997
4.89M
            p->shape = js_dup_shape(new_sh);
7998
4.89M
            js_free_shape(ctx->rt, sh);
7999
4.89M
            return &p->prop[new_sh->prop_count - 1];
8000
8.93M
        } else if (sh->header.ref_count != 1) {
8001
            /* if the shape is shared, clone it */
8002
913k
            new_sh = js_clone_shape(ctx, sh);
8003
913k
            if (!new_sh)
8004
5
                return NULL;
8005
            /* hash the cloned shape */
8006
913k
            new_sh->is_hashed = TRUE;
8007
913k
            js_shape_hash_link(ctx->rt, new_sh);
8008
913k
            js_free_shape(ctx->rt, p->shape);
8009
913k
            p->shape = new_sh;
8010
913k
        }
8011
13.8M
    }
8012
8.98M
    assert(p->shape->header.ref_count == 1);
8013
8.98M
    if (add_shape_property(ctx, &p->shape, p, prop, prop_flags))
8014
63
        return NULL;
8015
8.98M
    return &p->prop[p->shape->prop_count - 1];
8016
8.98M
}
8017
8018
/* can be called on Array or Arguments objects. return < 0 if
8019
   memory alloc error. */
8020
static no_inline __exception int convert_fast_array_to_array(JSContext *ctx,
8021
                                                             JSObject *p)
8022
21.6k
{
8023
21.6k
    JSProperty *pr;
8024
21.6k
    JSShape *sh;
8025
21.6k
    JSValue *tab;
8026
21.6k
    uint32_t i, len, new_count;
8027
8028
21.6k
    if (js_shape_prepare_update(ctx, p, NULL))
8029
0
        return -1;
8030
21.6k
    len = p->u.array.count;
8031
    /* resize the properties once to simplify the error handling */
8032
21.6k
    sh = p->shape;
8033
21.6k
    new_count = sh->prop_count + len;
8034
21.6k
    if (new_count > sh->prop_size) {
8035
63
        if (resize_properties(ctx, &p->shape, p, new_count))
8036
0
            return -1;
8037
63
    }
8038
8039
21.6k
    tab = p->u.array.u.values;
8040
46.0k
    for(i = 0; i < len; i++) {
8041
        /* add_property cannot fail here but
8042
           __JS_AtomFromUInt32(i) fails for i > INT32_MAX */
8043
24.3k
        pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E);
8044
24.3k
        pr->u.value = *tab++;
8045
24.3k
    }
8046
21.6k
    js_free(ctx, p->u.array.u.values);
8047
21.6k
    p->u.array.count = 0;
8048
21.6k
    p->u.array.u.values = NULL; /* fail safe */
8049
21.6k
    p->u.array.u1.size = 0;
8050
21.6k
    p->fast_array = 0;
8051
21.6k
    return 0;
8052
21.6k
}
8053
8054
static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom)
8055
83.4k
{
8056
83.4k
    JSShape *sh;
8057
83.4k
    JSShapeProperty *pr, *lpr, *prop;
8058
83.4k
    JSProperty *pr1;
8059
83.4k
    uint32_t lpr_idx;
8060
83.4k
    intptr_t h, h1;
8061
8062
83.4k
 redo:
8063
83.4k
    sh = p->shape;
8064
83.4k
    h1 = atom & sh->prop_hash_mask;
8065
83.4k
    h = prop_hash_end(sh)[-h1 - 1];
8066
83.4k
    prop = get_shape_prop(sh);
8067
83.4k
    lpr = NULL;
8068
83.4k
    lpr_idx = 0;   /* prevent warning */
8069
103k
    while (h != 0) {
8070
21.4k
        pr = &prop[h - 1];
8071
21.4k
        if (likely(pr->atom == atom)) {
8072
            /* found ! */
8073
1.04k
            if (!(pr->flags & JS_PROP_CONFIGURABLE))
8074
0
                return FALSE;
8075
            /* realloc the shape if needed */
8076
1.04k
            if (lpr)
8077
0
                lpr_idx = lpr - get_shape_prop(sh);
8078
1.04k
            if (js_shape_prepare_update(ctx, p, &pr))
8079
0
                return -1;
8080
1.04k
            sh = p->shape;
8081
            /* remove property */
8082
1.04k
            if (lpr) {
8083
0
                lpr = get_shape_prop(sh) + lpr_idx;
8084
0
                lpr->hash_next = pr->hash_next;
8085
1.04k
            } else {
8086
1.04k
                prop_hash_end(sh)[-h1 - 1] = pr->hash_next;
8087
1.04k
            }
8088
1.04k
            sh->deleted_prop_count++;
8089
            /* free the entry */
8090
1.04k
            pr1 = &p->prop[h - 1];
8091
1.04k
            free_property(ctx->rt, pr1, pr->flags);
8092
1.04k
            JS_FreeAtom(ctx, pr->atom);
8093
            /* put default values */
8094
1.04k
            pr->flags = 0;
8095
1.04k
            pr->atom = JS_ATOM_NULL;
8096
1.04k
            pr1->u.value = JS_UNDEFINED;
8097
8098
            /* compact the properties if too many deleted properties */
8099
1.04k
            if (sh->deleted_prop_count >= 8 &&
8100
1.04k
                sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) {
8101
6
                compact_properties(ctx, p);
8102
6
            }
8103
1.04k
            return TRUE;
8104
1.04k
        }
8105
20.4k
        lpr = pr;
8106
20.4k
        h = pr->hash_next;
8107
20.4k
    }
8108
8109
82.3k
    if (p->is_exotic) {
8110
82.1k
        if (p->fast_array) {
8111
82.1k
            uint32_t idx;
8112
82.1k
            if (JS_AtomIsArrayIndex(ctx, &idx, atom) &&
8113
82.1k
                idx < p->u.array.count) {
8114
81.5k
                if (p->class_id == JS_CLASS_ARRAY ||
8115
81.5k
                    p->class_id == JS_CLASS_ARGUMENTS) {
8116
                    /* Special case deleting the last element of a fast Array */
8117
81.5k
                    if (idx == p->u.array.count - 1) {
8118
81.5k
                        JS_FreeValue(ctx, p->u.array.u.values[idx]);
8119
81.5k
                        p->u.array.count = idx;
8120
81.5k
                        return TRUE;
8121
81.5k
                    }
8122
0
                    if (convert_fast_array_to_array(ctx, p))
8123
0
                        return -1;
8124
0
                    goto redo;
8125
0
                } else {
8126
0
                    return FALSE;
8127
0
                }
8128
81.5k
            }
8129
82.1k
        } else {
8130
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8131
0
            if (em && em->delete_property) {
8132
0
                return em->delete_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), atom);
8133
0
            }
8134
0
        }
8135
82.1k
    }
8136
    /* not found */
8137
764
    return TRUE;
8138
82.3k
}
8139
8140
static int call_setter(JSContext *ctx, JSObject *setter,
8141
                       JSValueConst this_obj, JSValue val, int flags)
8142
0
{
8143
0
    JSValue ret, func;
8144
0
    if (likely(setter)) {
8145
0
        func = JS_MKPTR(JS_TAG_OBJECT, setter);
8146
        /* Note: the field could be removed in the setter */
8147
0
        func = JS_DupValue(ctx, func);
8148
0
        ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst *)&val);
8149
0
        JS_FreeValue(ctx, val);
8150
0
        if (JS_IsException(ret))
8151
0
            return -1;
8152
0
        JS_FreeValue(ctx, ret);
8153
0
        return TRUE;
8154
0
    } else {
8155
0
        JS_FreeValue(ctx, val);
8156
0
        if ((flags & JS_PROP_THROW) ||
8157
0
            ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
8158
0
            JS_ThrowTypeError(ctx, "no setter for property");
8159
0
            return -1;
8160
0
        }
8161
0
        return FALSE;
8162
0
    }
8163
0
}
8164
8165
/* set the array length and remove the array elements if necessary. */
8166
static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
8167
                            int flags)
8168
604k
{
8169
604k
    uint32_t len, idx, cur_len;
8170
604k
    int i, ret;
8171
8172
    /* Note: this call can reallocate the properties of 'p' */
8173
604k
    ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE);
8174
604k
    if (ret)
8175
0
        return -1;
8176
    /* JS_ToArrayLengthFree() must be done before the read-only test */
8177
604k
    if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE)))
8178
0
        return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
8179
8180
604k
    if (likely(p->fast_array)) {
8181
604k
        uint32_t old_len = p->u.array.count;
8182
604k
        if (len < old_len) {
8183
0
            for(i = len; i < old_len; i++) {
8184
0
                JS_FreeValue(ctx, p->u.array.u.values[i]);
8185
0
            }
8186
0
            p->u.array.count = len;
8187
0
        }
8188
604k
        p->prop[0].u.value = JS_NewUint32(ctx, len);
8189
604k
    } else {
8190
        /* Note: length is always a uint32 because the object is an
8191
           array */
8192
5
        JS_ToUint32(ctx, &cur_len, p->prop[0].u.value);
8193
5
        if (len < cur_len) {
8194
0
            uint32_t d;
8195
0
            JSShape *sh;
8196
0
            JSShapeProperty *pr;
8197
8198
0
            d = cur_len - len;
8199
0
            sh = p->shape;
8200
0
            if (d <= sh->prop_count) {
8201
0
                JSAtom atom;
8202
8203
                /* faster to iterate */
8204
0
                while (cur_len > len) {
8205
0
                    atom = JS_NewAtomUInt32(ctx, cur_len - 1);
8206
0
                    ret = delete_property(ctx, p, atom);
8207
0
                    JS_FreeAtom(ctx, atom);
8208
0
                    if (unlikely(!ret)) {
8209
                        /* unlikely case: property is not
8210
                           configurable */
8211
0
                        break;
8212
0
                    }
8213
0
                    cur_len--;
8214
0
                }
8215
0
            } else {
8216
                /* faster to iterate thru all the properties. Need two
8217
                   passes in case one of the property is not
8218
                   configurable */
8219
0
                cur_len = len;
8220
0
                for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
8221
0
                    i++, pr++) {
8222
0
                    if (pr->atom != JS_ATOM_NULL &&
8223
0
                        JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
8224
0
                        if (idx >= cur_len &&
8225
0
                            !(pr->flags & JS_PROP_CONFIGURABLE)) {
8226
0
                            cur_len = idx + 1;
8227
0
                        }
8228
0
                    }
8229
0
                }
8230
8231
0
                for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
8232
0
                    i++, pr++) {
8233
0
                    if (pr->atom != JS_ATOM_NULL &&
8234
0
                        JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
8235
0
                        if (idx >= cur_len) {
8236
                            /* remove the property */
8237
0
                            delete_property(ctx, p, pr->atom);
8238
                            /* WARNING: the shape may have been modified */
8239
0
                            sh = p->shape;
8240
0
                            pr = get_shape_prop(sh) + i;
8241
0
                        }
8242
0
                    }
8243
0
                }
8244
0
            }
8245
5
        } else {
8246
5
            cur_len = len;
8247
5
        }
8248
5
        set_value(ctx, &p->prop[0].u.value, JS_NewUint32(ctx, cur_len));
8249
5
        if (unlikely(cur_len > len)) {
8250
0
            return JS_ThrowTypeErrorOrFalse(ctx, flags, "not configurable");
8251
0
        }
8252
5
    }
8253
604k
    return TRUE;
8254
604k
}
8255
8256
/* return -1 if exception */
8257
static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len)
8258
1.43M
{
8259
1.43M
    uint32_t new_size;
8260
1.43M
    size_t slack;
8261
1.43M
    JSValue *new_array_prop;
8262
    /* XXX: potential arithmetic overflow */
8263
1.43M
    new_size = max_int(new_len, p->u.array.u1.size * 3 / 2);
8264
1.43M
    new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack);
8265
1.43M
    if (!new_array_prop)
8266
0
        return -1;
8267
1.43M
    new_size += slack / sizeof(*new_array_prop);
8268
1.43M
    p->u.array.u.values = new_array_prop;
8269
1.43M
    p->u.array.u1.size = new_size;
8270
1.43M
    return 0;
8271
1.43M
}
8272
8273
/* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array =
8274
   TRUE and p->extensible = TRUE */
8275
static int add_fast_array_element(JSContext *ctx, JSObject *p,
8276
                                  JSValue val, int flags)
8277
3.04M
{
8278
3.04M
    uint32_t new_len, array_len;
8279
    /* extend the array by one */
8280
    /* XXX: convert to slow array if new_len > 2^31-1 elements */
8281
3.04M
    new_len = p->u.array.count + 1;
8282
    /* update the length if necessary. We assume that if the length is
8283
       not an integer, then if it >= 2^31.  */
8284
3.04M
    if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) {
8285
3.04M
        array_len = JS_VALUE_GET_INT(p->prop[0].u.value);
8286
3.04M
        if (new_len > array_len) {
8287
2.96M
            if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) {
8288
0
                JS_FreeValue(ctx, val);
8289
0
                return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
8290
0
            }
8291
2.96M
            p->prop[0].u.value = JS_NewInt32(ctx, new_len);
8292
2.96M
        }
8293
3.04M
    }
8294
3.04M
    if (unlikely(new_len > p->u.array.u1.size)) {
8295
1.43M
        if (expand_fast_array(ctx, p, new_len)) {
8296
0
            JS_FreeValue(ctx, val);
8297
0
            return -1;
8298
0
        }
8299
1.43M
    }
8300
3.04M
    p->u.array.u.values[new_len - 1] = val;
8301
3.04M
    p->u.array.count = new_len;
8302
3.04M
    return TRUE;
8303
3.04M
}
8304
8305
static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
8306
4
{
8307
4
    JS_FreeValue(ctx, desc->getter);
8308
4
    JS_FreeValue(ctx, desc->setter);
8309
4
    JS_FreeValue(ctx, desc->value);
8310
4
}
8311
8312
/* generic (and slower) version of JS_SetProperty() for
8313
 * Reflect.set(). 'obj' must be an object.  */
8314
static int JS_SetPropertyGeneric(JSContext *ctx,
8315
                                 JSValueConst obj, JSAtom prop,
8316
                                 JSValue val, JSValueConst this_obj,
8317
                                 int flags)
8318
0
{
8319
0
    int ret;
8320
0
    JSPropertyDescriptor desc;
8321
0
    JSValue obj1;
8322
0
    JSObject *p;
8323
    
8324
0
    obj1 = JS_DupValue(ctx, obj);
8325
0
    for(;;) {
8326
0
        p = JS_VALUE_GET_OBJ(obj1);
8327
0
        if (p->is_exotic) {
8328
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8329
0
            if (em && em->set_property) {
8330
0
                ret = em->set_property(ctx, obj1, prop,
8331
0
                                       val, this_obj, flags);
8332
0
                JS_FreeValue(ctx, obj1);
8333
0
                JS_FreeValue(ctx, val);
8334
0
                return ret;
8335
0
            }
8336
0
        }
8337
8338
0
        ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
8339
0
        if (ret < 0) {
8340
0
            JS_FreeValue(ctx, obj1);
8341
0
            JS_FreeValue(ctx, val);
8342
0
            return ret;
8343
0
        }
8344
0
        if (ret) {
8345
0
            if (desc.flags & JS_PROP_GETSET) {
8346
0
                JSObject *setter;
8347
0
                if (JS_IsUndefined(desc.setter))
8348
0
                    setter = NULL;
8349
0
                else
8350
0
                    setter = JS_VALUE_GET_OBJ(desc.setter);
8351
0
                ret = call_setter(ctx, setter, this_obj, val, flags);
8352
0
                JS_FreeValue(ctx, desc.getter);
8353
0
                JS_FreeValue(ctx, desc.setter);
8354
0
                JS_FreeValue(ctx, obj1);
8355
0
                return ret;
8356
0
            } else {
8357
0
                JS_FreeValue(ctx, desc.value);
8358
0
                if (!(desc.flags & JS_PROP_WRITABLE)) {
8359
0
                    JS_FreeValue(ctx, obj1);
8360
0
                    goto read_only_error;
8361
0
                }
8362
0
            }
8363
0
            break;
8364
0
        }
8365
        /* Note: at this point 'obj1' cannot be a proxy. XXX: may have
8366
           to check recursion */
8367
0
        obj1 = JS_GetPrototypeFree(ctx, obj1);
8368
0
        if (JS_IsNull(obj1))
8369
0
            break;
8370
0
    }
8371
0
    JS_FreeValue(ctx, obj1);
8372
8373
0
    if (!JS_IsObject(this_obj)) {
8374
0
        JS_FreeValue(ctx, val);
8375
0
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "receiver is not an object");
8376
0
    }
8377
    
8378
0
    p = JS_VALUE_GET_OBJ(this_obj);
8379
8380
    /* modify the property in this_obj if it already exists */
8381
0
    ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
8382
0
    if (ret < 0) {
8383
0
        JS_FreeValue(ctx, val);
8384
0
        return ret;
8385
0
    }
8386
0
    if (ret) {
8387
0
        if (desc.flags & JS_PROP_GETSET) {
8388
0
            JS_FreeValue(ctx, desc.getter);
8389
0
            JS_FreeValue(ctx, desc.setter);
8390
0
            JS_FreeValue(ctx, val);
8391
0
            return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden");
8392
0
        } else {
8393
0
            JS_FreeValue(ctx, desc.value);
8394
0
            if (!(desc.flags & JS_PROP_WRITABLE) ||
8395
0
                p->class_id == JS_CLASS_MODULE_NS) {
8396
0
            read_only_error:
8397
0
                JS_FreeValue(ctx, val);
8398
0
                return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
8399
0
            }
8400
0
        }
8401
0
        ret = JS_DefineProperty(ctx, this_obj, prop, val,
8402
0
                                JS_UNDEFINED, JS_UNDEFINED,
8403
0
                                JS_PROP_HAS_VALUE);
8404
0
        JS_FreeValue(ctx, val);
8405
0
        return ret;
8406
0
    }
8407
8408
0
    ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,
8409
0
                            flags |
8410
0
                            JS_PROP_HAS_VALUE |
8411
0
                            JS_PROP_HAS_ENUMERABLE |
8412
0
                            JS_PROP_HAS_WRITABLE |
8413
0
                            JS_PROP_HAS_CONFIGURABLE |
8414
0
                            JS_PROP_C_W_E);
8415
0
    JS_FreeValue(ctx, val);
8416
0
    return ret;
8417
0
}
8418
8419
/* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is
8420
   freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD,
8421
   JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set,
8422
   the new property is not added and an error is raised. */
8423
int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj,
8424
                           JSAtom prop, JSValue val, int flags)
8425
4.73M
{
8426
4.73M
    JSObject *p, *p1;
8427
4.73M
    JSShapeProperty *prs;
8428
4.73M
    JSProperty *pr;
8429
4.73M
    uint32_t tag;
8430
4.73M
    JSPropertyDescriptor desc;
8431
4.73M
    int ret;
8432
#if 0
8433
    printf("JS_SetPropertyInternal: "); print_atom(ctx, prop); printf("\n");
8434
#endif
8435
4.73M
    tag = JS_VALUE_GET_TAG(this_obj);
8436
4.73M
    if (unlikely(tag != JS_TAG_OBJECT)) {
8437
24.2k
        switch(tag) {
8438
0
        case JS_TAG_NULL:
8439
0
            JS_FreeValue(ctx, val);
8440
0
            JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop);
8441
0
            return -1;
8442
0
        case JS_TAG_UNDEFINED:
8443
0
            JS_FreeValue(ctx, val);
8444
0
            JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop);
8445
0
            return -1;
8446
24.2k
        default:
8447
            /* even on a primitive type we can have setters on the prototype */
8448
24.2k
            p = NULL;
8449
24.2k
            p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, this_obj));
8450
24.2k
            goto prototype_lookup;
8451
24.2k
        }
8452
24.2k
    }
8453
4.71M
    p = JS_VALUE_GET_OBJ(this_obj);
8454
4.71M
retry:
8455
4.71M
    prs = find_own_property(&pr, p, prop);
8456
4.71M
    if (prs) {
8457
2.87M
        if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE |
8458
2.87M
                                  JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) {
8459
            /* fast case */
8460
2.25M
            set_value(ctx, &pr->u.value, val);
8461
2.25M
            return TRUE;
8462
2.25M
        } else if (prs->flags & JS_PROP_LENGTH) {
8463
604k
            assert(p->class_id == JS_CLASS_ARRAY);
8464
604k
            assert(prop == JS_ATOM_length);
8465
604k
            return set_array_length(ctx, p, val, flags);
8466
604k
        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
8467
0
            return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
8468
12.4k
        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
8469
            /* JS_PROP_WRITABLE is always true for variable
8470
               references, but they are write protected in module name
8471
               spaces. */
8472
12.4k
            if (p->class_id == JS_CLASS_MODULE_NS)
8473
0
                goto read_only_prop;
8474
12.4k
            set_value(ctx, pr->u.var_ref->pvalue, val);
8475
12.4k
            return TRUE;
8476
12.4k
        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
8477
            /* Instantiate property and retry (potentially useless) */
8478
0
            if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) {
8479
0
                JS_FreeValue(ctx, val);
8480
0
                return -1;
8481
0
            }
8482
0
            goto retry;
8483
0
        } else {
8484
0
            goto read_only_prop;
8485
0
        }
8486
2.87M
    }
8487
8488
1.84M
    p1 = p;
8489
1.91M
    for(;;) {
8490
1.91M
        if (p1->is_exotic) {
8491
1.53k
            if (p1->fast_array) {
8492
1.52k
                if (__JS_AtomIsTaggedInt(prop)) {
8493
129
                    uint32_t idx = __JS_AtomToUInt32(prop);
8494
129
                    if (idx < p1->u.array.count) {
8495
0
                        if (unlikely(p == p1))
8496
0
                            return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, flags);
8497
0
                        else
8498
0
                            break;
8499
129
                    } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&
8500
129
                               p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
8501
0
                        goto typed_array_oob;
8502
0
                    }
8503
1.40k
                } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&
8504
1.40k
                           p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
8505
0
                    ret = JS_AtomIsNumericIndex(ctx, prop);
8506
0
                    if (ret != 0) {
8507
0
                        if (ret < 0) {
8508
0
                            JS_FreeValue(ctx, val);
8509
0
                            return -1;
8510
0
                        }
8511
0
                    typed_array_oob:
8512
0
                        val = JS_ToNumberFree(ctx, val);
8513
0
                        JS_FreeValue(ctx, val);
8514
0
                        if (JS_IsException(val))
8515
0
                            return -1;
8516
0
                        return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
8517
0
                    }
8518
0
                }
8519
1.52k
            } else {
8520
5
                const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic;
8521
5
                if (em) {
8522
2
                    JSValue obj1;
8523
2
                    if (em->set_property) {
8524
                        /* set_property can free the prototype */
8525
0
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
8526
0
                        ret = em->set_property(ctx, obj1, prop,
8527
0
                                               val, this_obj, flags);
8528
0
                        JS_FreeValue(ctx, obj1);
8529
0
                        JS_FreeValue(ctx, val);
8530
0
                        return ret;
8531
0
                    }
8532
2
                    if (em->get_own_property) {
8533
                        /* get_own_property can free the prototype */
8534
2
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
8535
2
                        ret = em->get_own_property(ctx, &desc,
8536
2
                                                   obj1, prop);
8537
2
                        JS_FreeValue(ctx, obj1);
8538
2
                        if (ret < 0) {
8539
0
                            JS_FreeValue(ctx, val);
8540
0
                            return ret;
8541
0
                        }
8542
2
                        if (ret) {
8543
0
                            if (desc.flags & JS_PROP_GETSET) {
8544
0
                                JSObject *setter;
8545
0
                                if (JS_IsUndefined(desc.setter))
8546
0
                                    setter = NULL;
8547
0
                                else
8548
0
                                    setter = JS_VALUE_GET_OBJ(desc.setter);
8549
0
                                ret = call_setter(ctx, setter, this_obj, val, flags);
8550
0
                                JS_FreeValue(ctx, desc.getter);
8551
0
                                JS_FreeValue(ctx, desc.setter);
8552
0
                                return ret;
8553
0
                            } else {
8554
0
                                JS_FreeValue(ctx, desc.value);
8555
0
                                if (!(desc.flags & JS_PROP_WRITABLE))
8556
0
                                    goto read_only_prop;
8557
0
                                if (likely(p == p1)) {
8558
0
                                    ret = JS_DefineProperty(ctx, this_obj, prop, val,
8559
0
                                                            JS_UNDEFINED, JS_UNDEFINED,
8560
0
                                                            JS_PROP_HAS_VALUE);
8561
0
                                    JS_FreeValue(ctx, val);
8562
0
                                    return ret;
8563
0
                                } else {
8564
0
                                    break;
8565
0
                                }
8566
0
                            }
8567
0
                        }
8568
2
                    }
8569
2
                }
8570
5
            }
8571
1.53k
        }
8572
1.91M
        p1 = p1->shape->proto;
8573
1.94M
    prototype_lookup:
8574
1.94M
        if (!p1)
8575
1.86M
            break;
8576
8577
75.2k
    retry2:
8578
75.2k
        prs = find_own_property(&pr, p1, prop);
8579
75.2k
        if (prs) {
8580
0
            if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
8581
0
                return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
8582
0
            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
8583
                /* Instantiate property and retry (potentially useless) */
8584
0
                if (JS_AutoInitProperty(ctx, p1, prop, pr, prs))
8585
0
                    return -1;
8586
0
                goto retry2;
8587
0
            } else if (!(prs->flags & JS_PROP_WRITABLE)) {
8588
0
            read_only_prop:
8589
0
                JS_FreeValue(ctx, val);
8590
0
                return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
8591
0
            }
8592
0
        }
8593
75.2k
    }
8594
8595
1.86M
    if (unlikely(flags & JS_PROP_NO_ADD)) {
8596
0
        JS_FreeValue(ctx, val);
8597
0
        JS_ThrowReferenceErrorNotDefined(ctx, prop);
8598
0
        return -1;
8599
0
    }
8600
8601
1.86M
    if (unlikely(!p)) {
8602
24.2k
        JS_FreeValue(ctx, val);
8603
24.2k
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "not an object");
8604
24.2k
    }
8605
8606
1.84M
    if (unlikely(!p->extensible)) {
8607
0
        JS_FreeValue(ctx, val);
8608
0
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
8609
0
    }
8610
8611
1.84M
    if (p->is_exotic) {
8612
766
        if (p->class_id == JS_CLASS_ARRAY && p->fast_array &&
8613
766
            __JS_AtomIsTaggedInt(prop)) {
8614
63
            uint32_t idx = __JS_AtomToUInt32(prop);
8615
63
            if (idx == p->u.array.count) {
8616
                /* fast case */
8617
0
                return add_fast_array_element(ctx, p, val, flags);
8618
63
            } else {
8619
63
                goto generic_create_prop;
8620
63
            }
8621
703
        } else {
8622
766
        generic_create_prop:
8623
766
            ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,
8624
766
                                    flags |
8625
766
                                    JS_PROP_HAS_VALUE |
8626
766
                                    JS_PROP_HAS_ENUMERABLE |
8627
766
                                    JS_PROP_HAS_WRITABLE |
8628
766
                                    JS_PROP_HAS_CONFIGURABLE |
8629
766
                                    JS_PROP_C_W_E);
8630
766
            JS_FreeValue(ctx, val);
8631
766
            return ret;
8632
703
        }
8633
766
    }
8634
8635
1.84M
    pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
8636
1.84M
    if (unlikely(!pr)) {
8637
63
        JS_FreeValue(ctx, val);
8638
63
        return -1;
8639
63
    }
8640
1.84M
    pr->u.value = val;
8641
1.84M
    return TRUE;
8642
1.84M
}
8643
8644
/* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */
8645
static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
8646
                               JSValue prop, JSValue val, int flags)
8647
1.56M
{
8648
1.56M
    if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
8649
1.56M
               JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
8650
427k
        JSObject *p;
8651
427k
        uint32_t idx;
8652
427k
        double d;
8653
427k
        int32_t v;
8654
8655
        /* fast path for array access */
8656
427k
        p = JS_VALUE_GET_OBJ(this_obj);
8657
427k
        idx = JS_VALUE_GET_INT(prop);
8658
427k
        switch(p->class_id) {
8659
427k
        case JS_CLASS_ARRAY:
8660
427k
            if (unlikely(idx >= (uint32_t)p->u.array.count)) {
8661
225k
                JSObject *p1;
8662
225k
                JSShape *sh1;
8663
8664
                /* fast path to add an element to the array */
8665
225k
                if (idx != (uint32_t)p->u.array.count ||
8666
225k
                    !p->fast_array || !p->extensible)
8667
24.3k
                    goto slow_path;
8668
                /* check if prototype chain has a numeric property */
8669
201k
                p1 = p->shape->proto;
8670
604k
                while (p1 != NULL) {
8671
403k
                    sh1 = p1->shape;
8672
403k
                    if (p1->class_id == JS_CLASS_ARRAY) {
8673
201k
                        if (unlikely(!p1->fast_array))
8674
0
                            goto slow_path;
8675
201k
                    } else if (p1->class_id == JS_CLASS_OBJECT) {
8676
201k
                        if (unlikely(sh1->has_small_array_index))
8677
0
                            goto slow_path;
8678
201k
                    } else {
8679
0
                        goto slow_path;
8680
0
                    }
8681
403k
                    p1 = sh1->proto;
8682
403k
                }
8683
                /* add element */
8684
201k
                return add_fast_array_element(ctx, p, val, flags);
8685
201k
            }
8686
201k
            set_value(ctx, &p->u.array.u.values[idx], val);
8687
201k
            break;
8688
0
        case JS_CLASS_ARGUMENTS:
8689
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8690
0
                goto slow_path;
8691
0
            set_value(ctx, &p->u.array.u.values[idx], val);
8692
0
            break;
8693
0
        case JS_CLASS_UINT8C_ARRAY:
8694
0
            if (JS_ToUint8ClampFree(ctx, &v, val))
8695
0
                return -1;
8696
            /* Note: the conversion can detach the typed array, so the
8697
               array bound check must be done after */
8698
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8699
0
                goto ta_out_of_bound;
8700
0
            p->u.array.u.uint8_ptr[idx] = v;
8701
0
            break;
8702
0
        case JS_CLASS_INT8_ARRAY:
8703
0
        case JS_CLASS_UINT8_ARRAY:
8704
0
            if (JS_ToInt32Free(ctx, &v, val))
8705
0
                return -1;
8706
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8707
0
                goto ta_out_of_bound;
8708
0
            p->u.array.u.uint8_ptr[idx] = v;
8709
0
            break;
8710
0
        case JS_CLASS_INT16_ARRAY:
8711
0
        case JS_CLASS_UINT16_ARRAY:
8712
0
            if (JS_ToInt32Free(ctx, &v, val))
8713
0
                return -1;
8714
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8715
0
                goto ta_out_of_bound;
8716
0
            p->u.array.u.uint16_ptr[idx] = v;
8717
0
            break;
8718
0
        case JS_CLASS_INT32_ARRAY:
8719
0
        case JS_CLASS_UINT32_ARRAY:
8720
0
            if (JS_ToInt32Free(ctx, &v, val))
8721
0
                return -1;
8722
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8723
0
                goto ta_out_of_bound;
8724
0
            p->u.array.u.uint32_ptr[idx] = v;
8725
0
            break;
8726
0
#ifdef CONFIG_BIGNUM
8727
0
        case JS_CLASS_BIG_INT64_ARRAY:
8728
0
        case JS_CLASS_BIG_UINT64_ARRAY:
8729
            /* XXX: need specific conversion function */
8730
0
            {
8731
0
                int64_t v;
8732
0
                if (JS_ToBigInt64Free(ctx, &v, val))
8733
0
                    return -1;
8734
0
                if (unlikely(idx >= (uint32_t)p->u.array.count))
8735
0
                    goto ta_out_of_bound;
8736
0
                p->u.array.u.uint64_ptr[idx] = v;
8737
0
            }
8738
0
            break;
8739
0
#endif
8740
0
        case JS_CLASS_FLOAT32_ARRAY:
8741
0
            if (JS_ToFloat64Free(ctx, &d, val))
8742
0
                return -1;
8743
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8744
0
                goto ta_out_of_bound;
8745
0
            p->u.array.u.float_ptr[idx] = d;
8746
0
            break;
8747
0
        case JS_CLASS_FLOAT64_ARRAY:
8748
0
            if (JS_ToFloat64Free(ctx, &d, val))
8749
0
                return -1;
8750
0
            if (unlikely(idx >= (uint32_t)p->u.array.count)) {
8751
0
            ta_out_of_bound:
8752
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
8753
0
            }
8754
0
            p->u.array.u.double_ptr[idx] = d;
8755
0
            break;
8756
0
        default:
8757
0
            goto slow_path;
8758
427k
        }
8759
201k
        return TRUE;
8760
1.13M
    } else {
8761
1.13M
        JSAtom atom;
8762
1.13M
        int ret;
8763
1.15M
    slow_path:
8764
1.15M
        atom = JS_ValueToAtom(ctx, prop);
8765
1.15M
        JS_FreeValue(ctx, prop);
8766
1.15M
        if (unlikely(atom == JS_ATOM_NULL)) {
8767
0
            JS_FreeValue(ctx, val);
8768
0
            return -1;
8769
0
        }
8770
1.15M
        ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags);
8771
1.15M
        JS_FreeAtom(ctx, atom);
8772
1.15M
        return ret;
8773
1.15M
    }
8774
1.56M
}
8775
8776
int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
8777
                         uint32_t idx, JSValue val)
8778
12
{
8779
12
    return JS_SetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx), val,
8780
12
                               JS_PROP_THROW);
8781
12
}
8782
8783
int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj,
8784
                        int64_t idx, JSValue val)
8785
427k
{
8786
427k
    JSAtom prop;
8787
427k
    int res;
8788
8789
427k
    if ((uint64_t)idx <= INT32_MAX) {
8790
        /* fast path for fast arrays */
8791
427k
        return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val,
8792
427k
                                   JS_PROP_THROW);
8793
427k
    }
8794
0
    prop = JS_NewAtomInt64(ctx, idx);
8795
0
    if (prop == JS_ATOM_NULL) {
8796
0
        JS_FreeValue(ctx, val);
8797
0
        return -1;
8798
0
    }
8799
0
    res = JS_SetProperty(ctx, this_obj, prop, val);
8800
0
    JS_FreeAtom(ctx, prop);
8801
0
    return res;
8802
0
}
8803
8804
int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
8805
                      const char *prop, JSValue val)
8806
10
{
8807
10
    JSAtom atom;
8808
10
    int ret;
8809
10
    atom = JS_NewAtom(ctx, prop);
8810
10
    ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW);
8811
10
    JS_FreeAtom(ctx, atom);
8812
10
    return ret;
8813
10
}
8814
8815
/* compute the property flags. For each flag: (JS_PROP_HAS_x forces
8816
   it, otherwise def_flags is used)
8817
   Note: makes assumption about the bit pattern of the flags
8818
*/
8819
static int get_prop_flags(int flags, int def_flags)
8820
2.86M
{
8821
2.86M
    int mask;
8822
2.86M
    mask = (flags >> JS_PROP_HAS_SHIFT) & JS_PROP_C_W_E;
8823
2.86M
    return (flags & mask) | (def_flags & ~mask);
8824
2.86M
}
8825
8826
static int JS_CreateProperty(JSContext *ctx, JSObject *p,
8827
                             JSAtom prop, JSValueConst val,
8828
                             JSValueConst getter, JSValueConst setter,
8829
                             int flags)
8830
14.7M
{
8831
14.7M
    JSProperty *pr;
8832
14.7M
    int ret, prop_flags;
8833
8834
    /* add a new property or modify an existing exotic one */
8835
14.7M
    if (p->is_exotic) {
8836
4.00M
        if (p->class_id == JS_CLASS_ARRAY) {
8837
2.88M
            uint32_t idx, len;
8838
8839
2.88M
            if (p->fast_array) {
8840
2.88M
                if (__JS_AtomIsTaggedInt(prop)) {
8841
2.86M
                    idx = __JS_AtomToUInt32(prop);
8842
2.86M
                    if (idx == p->u.array.count) {
8843
2.86M
                        if (!p->extensible)
8844
0
                            goto not_extensible;
8845
2.86M
                        if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET))
8846
0
                            goto convert_to_array;
8847
2.86M
                        prop_flags = get_prop_flags(flags, 0);
8848
2.86M
                        if (prop_flags != JS_PROP_C_W_E)
8849
21.5k
                            goto convert_to_array;
8850
2.84M
                        return add_fast_array_element(ctx, p,
8851
2.84M
                                                      JS_DupValue(ctx, val), flags);
8852
2.86M
                    } else {
8853
66
                        goto convert_to_array;
8854
66
                    }
8855
2.86M
                } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
8856
                    /* convert the fast array to normal array */
8857
21.6k
                convert_to_array:
8858
21.6k
                    if (convert_fast_array_to_array(ctx, p))
8859
0
                        return -1;
8860
21.6k
                    goto generic_array;
8861
21.6k
                }
8862
2.88M
            } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
8863
1.70k
                JSProperty *plen;
8864
1.70k
                JSShapeProperty *pslen;
8865
23.3k
            generic_array:
8866
                /* update the length field */
8867
23.3k
                plen = &p->prop[0];
8868
23.3k
                JS_ToUint32(ctx, &len, plen->u.value);
8869
23.3k
                if ((idx + 1) > len) {
8870
23.3k
                    pslen = get_shape_prop(p->shape);
8871
23.3k
                    if (unlikely(!(pslen->flags & JS_PROP_WRITABLE)))
8872
0
                        return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
8873
                    /* XXX: should update the length after defining
8874
                       the property */
8875
23.3k
                    len = idx + 1;
8876
23.3k
                    set_value(ctx, &plen->u.value, JS_NewUint32(ctx, len));
8877
23.3k
                }
8878
23.3k
            }
8879
2.88M
        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
8880
1.12M
                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
8881
0
            ret = JS_AtomIsNumericIndex(ctx, prop);
8882
0
            if (ret != 0) {
8883
0
                if (ret < 0)
8884
0
                    return -1;
8885
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "cannot create numeric index in typed array");
8886
0
            }
8887
1.12M
        } else if (!(flags & JS_PROP_NO_EXOTIC)) {
8888
560k
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8889
560k
            if (em) {
8890
560k
                if (em->define_own_property) {
8891
560k
                    return em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p),
8892
560k
                                                   prop, val, getter, setter, flags);
8893
560k
                }
8894
0
                ret = JS_IsExtensible(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
8895
0
                if (ret < 0)
8896
0
                    return -1;
8897
0
                if (!ret)
8898
0
                    goto not_extensible;
8899
0
            }
8900
560k
        }
8901
4.00M
    }
8902
8903
11.3M
    if (!p->extensible) {
8904
0
    not_extensible:
8905
0
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
8906
0
    }
8907
8908
11.3M
    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
8909
68
        prop_flags = (flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
8910
68
            JS_PROP_GETSET;
8911
11.3M
    } else {
8912
11.3M
        prop_flags = flags & JS_PROP_C_W_E;
8913
11.3M
    }
8914
11.3M
    pr = add_property(ctx, p, prop, prop_flags);
8915
11.3M
    if (unlikely(!pr))
8916
5
        return -1;
8917
11.3M
    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
8918
68
        pr->u.getset.getter = NULL;
8919
68
        if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) {
8920
68
            pr->u.getset.getter =
8921
68
                JS_VALUE_GET_OBJ(JS_DupValue(ctx, getter));
8922
68
        }
8923
68
        pr->u.getset.setter = NULL;
8924
68
        if ((flags & JS_PROP_HAS_SET) && JS_IsFunction(ctx, setter)) {
8925
6
            pr->u.getset.setter =
8926
6
                JS_VALUE_GET_OBJ(JS_DupValue(ctx, setter));
8927
6
        }
8928
11.3M
    } else {
8929
11.3M
        if (flags & JS_PROP_HAS_VALUE) {
8930
11.3M
            pr->u.value = JS_DupValue(ctx, val);
8931
11.3M
        } else {
8932
0
            pr->u.value = JS_UNDEFINED;
8933
0
        }
8934
11.3M
    }
8935
11.3M
    return TRUE;
8936
11.3M
}
8937
8938
/* return FALSE if not OK */
8939
static BOOL check_define_prop_flags(int prop_flags, int flags)
8940
1.97M
{
8941
1.97M
    BOOL has_accessor, is_getset;
8942
8943
1.97M
    if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
8944
964
        if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) ==
8945
964
            (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) {
8946
0
            return FALSE;
8947
0
        }
8948
964
        if ((flags & JS_PROP_HAS_ENUMERABLE) &&
8949
964
            (flags & JS_PROP_ENUMERABLE) != (prop_flags & JS_PROP_ENUMERABLE))
8950
0
            return FALSE;
8951
964
    }
8952
1.97M
    if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
8953
1.97M
                 JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
8954
1.97M
        if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
8955
964
            has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0);
8956
964
            is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET);
8957
964
            if (has_accessor != is_getset)
8958
0
                return FALSE;
8959
964
            if (!has_accessor && !is_getset && !(prop_flags & JS_PROP_WRITABLE)) {
8960
                /* not writable: cannot set the writable bit */
8961
0
                if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
8962
0
                    (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE))
8963
0
                    return FALSE;
8964
0
            }
8965
964
        }
8966
1.97M
    }
8967
1.97M
    return TRUE;
8968
1.97M
}
8969
8970
/* ensure that the shape can be safely modified */
8971
static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
8972
                                   JSShapeProperty **pprs)
8973
43.1k
{
8974
43.1k
    JSShape *sh;
8975
43.1k
    uint32_t idx = 0;    /* prevent warning */
8976
8977
43.1k
    sh = p->shape;
8978
43.1k
    if (sh->is_hashed) {
8979
21.6k
        if (sh->header.ref_count != 1) {
8980
11.4k
            if (pprs)
8981
6
                idx = *pprs - get_shape_prop(sh);
8982
            /* clone the shape (the resulting one is no longer hashed) */
8983
11.4k
            sh = js_clone_shape(ctx, sh);
8984
11.4k
            if (!sh)
8985
0
                return -1;
8986
11.4k
            js_free_shape(ctx->rt, p->shape);
8987
11.4k
            p->shape = sh;
8988
11.4k
            if (pprs)
8989
6
                *pprs = get_shape_prop(sh) + idx;
8990
11.4k
        } else {
8991
10.2k
            js_shape_hash_unlink(ctx->rt, sh);
8992
10.2k
            sh->is_hashed = FALSE;
8993
10.2k
        }
8994
21.6k
    }
8995
43.1k
    return 0;
8996
43.1k
}
8997
8998
static int js_update_property_flags(JSContext *ctx, JSObject *p,
8999
                                    JSShapeProperty **pprs, int flags)
9000
3.97M
{
9001
3.97M
    if (flags != (*pprs)->flags) {
9002
20.3k
        if (js_shape_prepare_update(ctx, p, pprs))
9003
0
            return -1;
9004
20.3k
        (*pprs)->flags = flags;
9005
20.3k
    }
9006
3.97M
    return 0;
9007
3.97M
}
9008
9009
/* allowed flags:
9010
   JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE
9011
   JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE,
9012
   JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE,
9013
   JS_PROP_THROW, JS_PROP_NO_EXOTIC.
9014
   If JS_PROP_THROW is set, return an exception instead of FALSE.
9015
   if JS_PROP_NO_EXOTIC is set, do not call the exotic
9016
   define_own_property callback.
9017
   return -1 (exception), FALSE or TRUE.
9018
*/
9019
int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
9020
                      JSAtom prop, JSValueConst val,
9021
                      JSValueConst getter, JSValueConst setter, int flags)
9022
16.7M
{
9023
16.7M
    JSObject *p;
9024
16.7M
    JSShapeProperty *prs;
9025
16.7M
    JSProperty *pr;
9026
16.7M
    int mask, res;
9027
9028
16.7M
    if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) {
9029
3
        JS_ThrowTypeErrorNotAnObject(ctx);
9030
3
        return -1;
9031
3
    }
9032
16.7M
    p = JS_VALUE_GET_OBJ(this_obj);
9033
9034
16.7M
 redo_prop_update:
9035
16.7M
    prs = find_own_property(&pr, p, prop);
9036
16.7M
    if (prs) {
9037
        /* the range of the Array length property is always tested before */
9038
1.97M
        if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) {
9039
0
            uint32_t array_length;
9040
0
            if (JS_ToArrayLengthFree(ctx, &array_length,
9041
0
                                     JS_DupValue(ctx, val), FALSE)) {
9042
0
                return -1;
9043
0
            }
9044
            /* this code relies on the fact that Uint32 are never allocated */
9045
0
            val = (JSValueConst)JS_NewUint32(ctx, array_length);
9046
            /* prs may have been modified */
9047
0
            prs = find_own_property(&pr, p, prop);
9048
0
            assert(prs != NULL);
9049
0
        }
9050
        /* property already exists */
9051
1.97M
        if (!check_define_prop_flags(prs->flags, flags)) {
9052
0
        not_configurable:
9053
0
            return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
9054
0
        }
9055
9056
1.97M
        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
9057
            /* Instantiate property and retry */
9058
0
            if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
9059
0
                return -1;
9060
0
            goto redo_prop_update;
9061
0
        }
9062
9063
1.97M
        if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
9064
1.97M
                     JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9065
1.97M
            if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9066
0
                JSObject *new_getter, *new_setter;
9067
9068
0
                if (JS_IsFunction(ctx, getter)) {
9069
0
                    new_getter = JS_VALUE_GET_OBJ(getter);
9070
0
                } else {
9071
0
                    new_getter = NULL;
9072
0
                }
9073
0
                if (JS_IsFunction(ctx, setter)) {
9074
0
                    new_setter = JS_VALUE_GET_OBJ(setter);
9075
0
                } else {
9076
0
                    new_setter = NULL;
9077
0
                }
9078
9079
0
                if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET) {
9080
0
                    if (js_shape_prepare_update(ctx, p, &prs))
9081
0
                        return -1;
9082
                    /* convert to getset */
9083
0
                    if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
9084
0
                        free_var_ref(ctx->rt, pr->u.var_ref);
9085
0
                    } else {
9086
0
                        JS_FreeValue(ctx, pr->u.value);
9087
0
                    }
9088
0
                    prs->flags = (prs->flags &
9089
0
                                  (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
9090
0
                        JS_PROP_GETSET;
9091
0
                    pr->u.getset.getter = NULL;
9092
0
                    pr->u.getset.setter = NULL;
9093
0
                } else {
9094
0
                    if (!(prs->flags & JS_PROP_CONFIGURABLE)) {
9095
0
                        if ((flags & JS_PROP_HAS_GET) &&
9096
0
                            new_getter != pr->u.getset.getter) {
9097
0
                            goto not_configurable;
9098
0
                        }
9099
0
                        if ((flags & JS_PROP_HAS_SET) &&
9100
0
                            new_setter != pr->u.getset.setter) {
9101
0
                            goto not_configurable;
9102
0
                        }
9103
0
                    }
9104
0
                }
9105
0
                if (flags & JS_PROP_HAS_GET) {
9106
0
                    if (pr->u.getset.getter)
9107
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
9108
0
                    if (new_getter)
9109
0
                        JS_DupValue(ctx, getter);
9110
0
                    pr->u.getset.getter = new_getter;
9111
0
                }
9112
0
                if (flags & JS_PROP_HAS_SET) {
9113
0
                    if (pr->u.getset.setter)
9114
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
9115
0
                    if (new_setter)
9116
0
                        JS_DupValue(ctx, setter);
9117
0
                    pr->u.getset.setter = new_setter;
9118
0
                }
9119
1.97M
            } else {
9120
1.97M
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
9121
                    /* convert to data descriptor */
9122
0
                    if (js_shape_prepare_update(ctx, p, &prs))
9123
0
                        return -1;
9124
0
                    if (pr->u.getset.getter)
9125
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
9126
0
                    if (pr->u.getset.setter)
9127
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
9128
0
                    prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
9129
0
                    pr->u.value = JS_UNDEFINED;
9130
1.97M
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
9131
                    /* Note: JS_PROP_VARREF is always writable */
9132
1.97M
                } else {
9133
1.97M
                    if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
9134
1.97M
                        (flags & JS_PROP_HAS_VALUE)) {
9135
0
                        if (!js_same_value(ctx, val, pr->u.value)) {
9136
0
                            goto not_configurable;
9137
0
                        } else {
9138
0
                            return TRUE;
9139
0
                        }
9140
0
                    }
9141
1.97M
                }
9142
1.97M
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
9143
0
                    if (flags & JS_PROP_HAS_VALUE) {
9144
0
                        if (p->class_id == JS_CLASS_MODULE_NS) {
9145
                            /* JS_PROP_WRITABLE is always true for variable
9146
                               references, but they are write protected in module name
9147
                               spaces. */
9148
0
                            if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue))
9149
0
                                goto not_configurable;
9150
0
                        }
9151
                        /* update the reference */
9152
0
                        set_value(ctx, pr->u.var_ref->pvalue,
9153
0
                                  JS_DupValue(ctx, val));
9154
0
                    }
9155
                    /* if writable is set to false, no longer a
9156
                       reference (for mapped arguments) */
9157
0
                    if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
9158
0
                        JSValue val1;
9159
0
                        if (js_shape_prepare_update(ctx, p, &prs))
9160
0
                            return -1;
9161
0
                        val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue);
9162
0
                        free_var_ref(ctx->rt, pr->u.var_ref);
9163
0
                        pr->u.value = val1;
9164
0
                        prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
9165
0
                    }
9166
1.97M
                } else if (prs->flags & JS_PROP_LENGTH) {
9167
0
                    if (flags & JS_PROP_HAS_VALUE) {
9168
                        /* Note: no JS code is executable because
9169
                           'val' is guaranted to be a Uint32 */
9170
0
                        res = set_array_length(ctx, p, JS_DupValue(ctx, val),
9171
0
                                               flags);
9172
0
                    } else {
9173
0
                        res = TRUE;
9174
0
                    }
9175
                    /* still need to reset the writable flag if
9176
                       needed.  The JS_PROP_LENGTH is kept because the
9177
                       Uint32 test is still done if the length
9178
                       property is read-only. */
9179
0
                    if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
9180
0
                        JS_PROP_HAS_WRITABLE) {
9181
0
                        prs = get_shape_prop(p->shape);
9182
0
                        if (js_update_property_flags(ctx, p, &prs,
9183
0
                                                     prs->flags & ~JS_PROP_WRITABLE))
9184
0
                            return -1;
9185
0
                    }
9186
0
                    return res;
9187
1.97M
                } else {
9188
1.97M
                    if (flags & JS_PROP_HAS_VALUE) {
9189
1.97M
                        JS_FreeValue(ctx, pr->u.value);
9190
1.97M
                        pr->u.value = JS_DupValue(ctx, val);
9191
1.97M
                    }
9192
1.97M
                    if (flags & JS_PROP_HAS_WRITABLE) {
9193
1.97M
                        if (js_update_property_flags(ctx, p, &prs,
9194
1.97M
                                                     (prs->flags & ~JS_PROP_WRITABLE) |
9195
1.97M
                                                     (flags & JS_PROP_WRITABLE)))
9196
0
                            return -1;
9197
1.97M
                    }
9198
1.97M
                }
9199
1.97M
            }
9200
1.97M
        }
9201
1.97M
        mask = 0;
9202
1.97M
        if (flags & JS_PROP_HAS_CONFIGURABLE)
9203
1.97M
            mask |= JS_PROP_CONFIGURABLE;
9204
1.97M
        if (flags & JS_PROP_HAS_ENUMERABLE)
9205
1.97M
            mask |= JS_PROP_ENUMERABLE;
9206
1.97M
        if (js_update_property_flags(ctx, p, &prs,
9207
1.97M
                                     (prs->flags & ~mask) | (flags & mask)))
9208
0
            return -1;
9209
1.97M
        return TRUE;
9210
1.97M
    }
9211
9212
    /* handle modification of fast array elements */
9213
14.7M
    if (p->fast_array) {
9214
2.87M
        uint32_t idx;
9215
2.87M
        uint32_t prop_flags;
9216
2.87M
        if (p->class_id == JS_CLASS_ARRAY) {
9217
2.87M
            if (__JS_AtomIsTaggedInt(prop)) {
9218
2.86M
                idx = __JS_AtomToUInt32(prop);
9219
2.86M
                if (idx < p->u.array.count) {
9220
0
                    prop_flags = get_prop_flags(flags, JS_PROP_C_W_E);
9221
0
                    if (prop_flags != JS_PROP_C_W_E)
9222
0
                        goto convert_to_slow_array;
9223
0
                    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9224
0
                    convert_to_slow_array:
9225
0
                        if (convert_fast_array_to_array(ctx, p))
9226
0
                            return -1;
9227
0
                        else
9228
0
                            goto redo_prop_update;
9229
0
                    }
9230
0
                    if (flags & JS_PROP_HAS_VALUE) {
9231
0
                        set_value(ctx, &p->u.array.u.values[idx], JS_DupValue(ctx, val));
9232
0
                    }
9233
0
                    return TRUE;
9234
0
                }
9235
2.86M
            }
9236
2.87M
        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
9237
0
                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
9238
0
            JSValue num;
9239
0
            int ret;
9240
9241
0
            if (!__JS_AtomIsTaggedInt(prop)) {
9242
                /* slow path with to handle all numeric indexes */
9243
0
                num = JS_AtomIsNumericIndex1(ctx, prop);
9244
0
                if (JS_IsUndefined(num))
9245
0
                    goto typed_array_done;
9246
0
                if (JS_IsException(num))
9247
0
                    return -1;
9248
0
                ret = JS_NumberIsInteger(ctx, num);
9249
0
                if (ret < 0) {
9250
0
                    JS_FreeValue(ctx, num);
9251
0
                    return -1;
9252
0
                }
9253
0
                if (!ret) {
9254
0
                    JS_FreeValue(ctx, num);
9255
0
                    return JS_ThrowTypeErrorOrFalse(ctx, flags, "non integer index in typed array");
9256
0
                }
9257
0
                ret = JS_NumberIsNegativeOrMinusZero(ctx, num);
9258
0
                JS_FreeValue(ctx, num);
9259
0
                if (ret) {
9260
0
                    return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array");
9261
0
                }
9262
0
                if (!__JS_AtomIsTaggedInt(prop))
9263
0
                    goto typed_array_oob;
9264
0
            }
9265
0
            idx = __JS_AtomToUInt32(prop);
9266
            /* if the typed array is detached, p->u.array.count = 0 */
9267
0
            if (idx >= typed_array_get_length(ctx, p)) {
9268
0
            typed_array_oob:
9269
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array");
9270
0
            }
9271
0
            prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
9272
0
            if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) ||
9273
0
                prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) {
9274
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags");
9275
0
            }
9276
0
            if (flags & JS_PROP_HAS_VALUE) {
9277
0
                return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), JS_DupValue(ctx, val), flags);
9278
0
            }
9279
0
            return TRUE;
9280
0
        typed_array_done: ;
9281
0
        }
9282
2.87M
    }
9283
9284
14.7M
    return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags);
9285
14.7M
}
9286
9287
static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj,
9288
                                     JSAtom prop, JSAutoInitIDEnum id,
9289
                                     void *opaque, int flags)
9290
1.58k
{
9291
1.58k
    JSObject *p;
9292
1.58k
    JSProperty *pr;
9293
9294
1.58k
    if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT)
9295
0
        return FALSE;
9296
9297
1.58k
    p = JS_VALUE_GET_OBJ(this_obj);
9298
9299
1.58k
    if (find_own_property(&pr, p, prop)) {
9300
        /* property already exists */
9301
0
        abort();
9302
0
        return FALSE;
9303
0
    }
9304
9305
    /* Specialized CreateProperty */
9306
1.58k
    pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT);
9307
1.58k
    if (unlikely(!pr))
9308
0
        return -1;
9309
1.58k
    pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx);
9310
1.58k
    assert((pr->u.init.realm_and_id & 3) == 0);
9311
1.58k
    assert(id <= 3);
9312
1.58k
    pr->u.init.realm_and_id |= id;
9313
1.58k
    pr->u.init.opaque = opaque;
9314
1.58k
    return TRUE;
9315
1.58k
}
9316
9317
/* shortcut to add or redefine a new property value */
9318
int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj,
9319
                           JSAtom prop, JSValue val, int flags)
9320
15.8M
{
9321
15.8M
    int ret;
9322
15.8M
    ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED,
9323
15.8M
                            flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE);
9324
15.8M
    JS_FreeValue(ctx, val);
9325
15.8M
    return ret;
9326
15.8M
}
9327
9328
int JS_DefinePropertyValueValue(JSContext *ctx, JSValueConst this_obj,
9329
                                JSValue prop, JSValue val, int flags)
9330
2.84M
{
9331
2.84M
    JSAtom atom;
9332
2.84M
    int ret;
9333
2.84M
    atom = JS_ValueToAtom(ctx, prop);
9334
2.84M
    JS_FreeValue(ctx, prop);
9335
2.84M
    if (unlikely(atom == JS_ATOM_NULL)) {
9336
0
        JS_FreeValue(ctx, val);
9337
0
        return -1;
9338
0
    }
9339
2.84M
    ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
9340
2.84M
    JS_FreeAtom(ctx, atom);
9341
2.84M
    return ret;
9342
2.84M
}
9343
9344
int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj,
9345
                                 uint32_t idx, JSValue val, int flags)
9346
264k
{
9347
264k
    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewUint32(ctx, idx),
9348
264k
                                       val, flags);
9349
264k
}
9350
9351
int JS_DefinePropertyValueInt64(JSContext *ctx, JSValueConst this_obj,
9352
                                int64_t idx, JSValue val, int flags)
9353
0
{
9354
0
    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),
9355
0
                                       val, flags);
9356
0
}
9357
9358
int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
9359
                              const char *prop, JSValue val, int flags)
9360
410
{
9361
410
    JSAtom atom;
9362
410
    int ret;
9363
410
    atom = JS_NewAtom(ctx, prop);
9364
410
    ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
9365
410
    JS_FreeAtom(ctx, atom);
9366
410
    return ret;
9367
410
}
9368
9369
/* shortcut to add getter & setter */
9370
int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,
9371
                            JSAtom prop, JSValue getter, JSValue setter,
9372
                            int flags)
9373
64
{
9374
64
    int ret;
9375
64
    ret = JS_DefineProperty(ctx, this_obj, prop, JS_UNDEFINED, getter, setter,
9376
64
                            flags | JS_PROP_HAS_GET | JS_PROP_HAS_SET |
9377
64
                            JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE);
9378
64
    JS_FreeValue(ctx, getter);
9379
64
    JS_FreeValue(ctx, setter);
9380
64
    return ret;
9381
64
}
9382
9383
static int JS_CreateDataPropertyUint32(JSContext *ctx, JSValueConst this_obj,
9384
                                       int64_t idx, JSValue val, int flags)
9385
2.58M
{
9386
2.58M
    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),
9387
2.58M
                                       val, flags | JS_PROP_CONFIGURABLE |
9388
2.58M
                                       JS_PROP_ENUMERABLE | JS_PROP_WRITABLE);
9389
2.58M
}
9390
9391
9392
/* return TRUE if 'obj' has a non empty 'name' string */
9393
static BOOL js_object_has_name(JSContext *ctx, JSValueConst obj)
9394
1.57M
{
9395
1.57M
    JSProperty *pr;
9396
1.57M
    JSShapeProperty *prs;
9397
1.57M
    JSValueConst val;
9398
1.57M
    JSString *p;
9399
    
9400
1.57M
    prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name);
9401
1.57M
    if (!prs)
9402
326k
        return FALSE;
9403
1.24M
    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
9404
0
        return TRUE;
9405
1.24M
    val = pr->u.value;
9406
1.24M
    if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
9407
0
        return TRUE;
9408
1.24M
    p = JS_VALUE_GET_STRING(val);
9409
1.24M
    return (p->len != 0);
9410
1.24M
}
9411
9412
static int JS_DefineObjectName(JSContext *ctx, JSValueConst obj,
9413
                               JSAtom name, int flags)
9414
1.56M
{
9415
1.56M
    if (name != JS_ATOM_NULL
9416
1.56M
    &&  JS_IsObject(obj)
9417
1.56M
    &&  !js_object_has_name(ctx, obj)
9418
1.56M
    &&  JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, JS_AtomToString(ctx, name), flags) < 0) {
9419
0
        return -1;
9420
0
    }
9421
1.56M
    return 0;
9422
1.56M
}
9423
9424
static int JS_DefineObjectNameComputed(JSContext *ctx, JSValueConst obj,
9425
                                       JSValueConst str, int flags)
9426
10.0k
{
9427
10.0k
    if (JS_IsObject(obj) &&
9428
10.0k
        !js_object_has_name(ctx, obj)) {
9429
10.0k
        JSAtom prop;
9430
10.0k
        JSValue name_str;
9431
10.0k
        prop = JS_ValueToAtom(ctx, str);
9432
10.0k
        if (prop == JS_ATOM_NULL)
9433
0
            return -1;
9434
10.0k
        name_str = js_get_function_name(ctx, prop);
9435
10.0k
        JS_FreeAtom(ctx, prop);
9436
10.0k
        if (JS_IsException(name_str))
9437
0
            return -1;
9438
10.0k
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name_str, flags) < 0)
9439
0
            return -1;
9440
10.0k
    }
9441
10.0k
    return 0;
9442
10.0k
}
9443
9444
16.2k
#define DEFINE_GLOBAL_LEX_VAR (1 << 7)
9445
9.56k
#define DEFINE_GLOBAL_FUNC_VAR (1 << 6)
9446
9447
static JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop)
9448
1
{
9449
1
    return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop);
9450
1
}
9451
9452
/* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */
9453
/* XXX: could support exotic global object. */
9454
static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags)
9455
8.60k
{
9456
8.60k
    JSObject *p;
9457
8.60k
    JSShapeProperty *prs;
9458
9459
8.60k
    p = JS_VALUE_GET_OBJ(ctx->global_obj);
9460
8.60k
    prs = find_own_property1(p, prop);
9461
    /* XXX: should handle JS_PROP_AUTOINIT */
9462
8.60k
    if (flags & DEFINE_GLOBAL_LEX_VAR) {
9463
5
        if (prs && !(prs->flags & JS_PROP_CONFIGURABLE))
9464
0
            goto fail_redeclaration;
9465
8.59k
    } else {
9466
8.59k
        if (!prs && !p->extensible)
9467
0
            goto define_error;
9468
8.59k
        if (flags & DEFINE_GLOBAL_FUNC_VAR) {
9469
971
            if (prs) {
9470
933
                if (!(prs->flags & JS_PROP_CONFIGURABLE) &&
9471
933
                    ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET ||
9472
929
                     ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) !=
9473
929
                      (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) {
9474
0
                define_error:
9475
0
                    JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'",
9476
0
                                          prop);
9477
0
                    return -1;
9478
0
                }
9479
933
            }
9480
971
        }
9481
8.59k
    }
9482
    /* check if there already is a lexical declaration */
9483
8.60k
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9484
8.60k
    prs = find_own_property1(p, prop);
9485
8.60k
    if (prs) {
9486
1
    fail_redeclaration:
9487
1
        JS_ThrowSyntaxErrorVarRedeclaration(ctx, prop);
9488
1
        return -1;
9489
1
    }
9490
8.60k
    return 0;
9491
8.60k
}
9492
9493
/* def_flags is (0, DEFINE_GLOBAL_LEX_VAR) |
9494
   JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE */
9495
/* XXX: could support exotic global object. */
9496
static int JS_DefineGlobalVar(JSContext *ctx, JSAtom prop, int def_flags)
9497
7.62k
{
9498
7.62k
    JSObject *p;
9499
7.62k
    JSShapeProperty *prs;
9500
7.62k
    JSProperty *pr;
9501
7.62k
    JSValue val;
9502
7.62k
    int flags;
9503
9504
7.62k
    if (def_flags & DEFINE_GLOBAL_LEX_VAR) {
9505
4
        p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9506
4
        flags = JS_PROP_ENUMERABLE | (def_flags & JS_PROP_WRITABLE) |
9507
4
            JS_PROP_CONFIGURABLE;
9508
4
        val = JS_UNINITIALIZED;
9509
7.62k
    } else {
9510
7.62k
        p = JS_VALUE_GET_OBJ(ctx->global_obj);
9511
7.62k
        flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
9512
7.62k
            (def_flags & JS_PROP_CONFIGURABLE);
9513
7.62k
        val = JS_UNDEFINED;
9514
7.62k
    }
9515
7.62k
    prs = find_own_property1(p, prop);
9516
7.62k
    if (prs)
9517
7.60k
        return 0;
9518
23
    if (!p->extensible)
9519
0
        return 0;
9520
23
    pr = add_property(ctx, p, prop, flags);
9521
23
    if (unlikely(!pr))
9522
0
        return -1;
9523
23
    pr->u.value = val;
9524
23
    return 0;
9525
23
}
9526
9527
/* 'def_flags' is 0 or JS_PROP_CONFIGURABLE. */
9528
/* XXX: could support exotic global object. */
9529
static int JS_DefineGlobalFunction(JSContext *ctx, JSAtom prop,
9530
                                   JSValueConst func, int def_flags)
9531
971
{
9532
9533
971
    JSObject *p;
9534
971
    JSShapeProperty *prs;
9535
971
    int flags;
9536
9537
971
    p = JS_VALUE_GET_OBJ(ctx->global_obj);
9538
971
    prs = find_own_property1(p, prop);
9539
971
    flags = JS_PROP_HAS_VALUE | JS_PROP_THROW;
9540
971
    if (!prs || (prs->flags & JS_PROP_CONFIGURABLE)) {
9541
7
        flags |= JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | def_flags |
9542
7
            JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE;
9543
7
    }
9544
971
    if (JS_DefineProperty(ctx, ctx->global_obj, prop, func,
9545
971
                          JS_UNDEFINED, JS_UNDEFINED, flags) < 0)
9546
0
        return -1;
9547
971
    return 0;
9548
971
}
9549
9550
static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop,
9551
                               BOOL throw_ref_error)
9552
626k
{
9553
626k
    JSObject *p;
9554
626k
    JSShapeProperty *prs;
9555
626k
    JSProperty *pr;
9556
9557
    /* no exotic behavior is possible in global_var_obj */
9558
626k
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9559
626k
    prs = find_own_property(&pr, p, prop);
9560
626k
    if (prs) {
9561
        /* XXX: should handle JS_PROP_TMASK properties */
9562
2
        if (unlikely(JS_IsUninitialized(pr->u.value)))
9563
0
            return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
9564
2
        return JS_DupValue(ctx, pr->u.value);
9565
2
    }
9566
626k
    return JS_GetPropertyInternal(ctx, ctx->global_obj, prop,
9567
626k
                                 ctx->global_obj, throw_ref_error);
9568
626k
}
9569
9570
/* construct a reference to a global variable */
9571
static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom prop, JSValue *sp)
9572
1.09M
{
9573
1.09M
    JSObject *p;
9574
1.09M
    JSShapeProperty *prs;
9575
1.09M
    JSProperty *pr;
9576
9577
    /* no exotic behavior is possible in global_var_obj */
9578
1.09M
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9579
1.09M
    prs = find_own_property(&pr, p, prop);
9580
1.09M
    if (prs) {
9581
        /* XXX: should handle JS_PROP_AUTOINIT properties? */
9582
        /* XXX: conformance: do these tests in
9583
           OP_put_var_ref/OP_get_var_ref ? */
9584
0
        if (unlikely(JS_IsUninitialized(pr->u.value))) {
9585
0
            JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
9586
0
            return -1;
9587
0
        }
9588
0
        if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
9589
0
            return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
9590
0
        }
9591
0
        sp[0] = JS_DupValue(ctx, ctx->global_var_obj);
9592
1.09M
    } else {
9593
1.09M
        int ret;
9594
1.09M
        ret = JS_HasProperty(ctx, ctx->global_obj, prop);
9595
1.09M
        if (ret < 0)
9596
0
            return -1;
9597
1.09M
        if (ret) {
9598
1.09M
            sp[0] = JS_DupValue(ctx, ctx->global_obj);
9599
1.09M
        } else {
9600
66
            sp[0] = JS_UNDEFINED;
9601
66
        }
9602
1.09M
    }
9603
1.09M
    sp[1] = JS_AtomToValue(ctx, prop);
9604
1.09M
    return 0;
9605
1.09M
}
9606
9607
/* use for strict variable access: test if the variable exists */
9608
static int JS_CheckGlobalVar(JSContext *ctx, JSAtom prop)
9609
419k
{
9610
419k
    JSObject *p;
9611
419k
    JSShapeProperty *prs;
9612
419k
    int ret;
9613
9614
    /* no exotic behavior is possible in global_var_obj */
9615
419k
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9616
419k
    prs = find_own_property1(p, prop);
9617
419k
    if (prs) {
9618
0
        ret = TRUE;
9619
419k
    } else {
9620
419k
        ret = JS_HasProperty(ctx, ctx->global_obj, prop);
9621
419k
        if (ret < 0)
9622
0
            return -1;
9623
419k
    }
9624
419k
    return ret;
9625
419k
}
9626
9627
/* flag = 0: normal variable write
9628
   flag = 1: initialize lexical variable
9629
   flag = 2: normal variable write, strict check was done before
9630
*/
9631
static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val,
9632
                           int flag)
9633
1.14M
{
9634
1.14M
    JSObject *p;
9635
1.14M
    JSShapeProperty *prs;
9636
1.14M
    JSProperty *pr;
9637
1.14M
    int flags;
9638
9639
    /* no exotic behavior is possible in global_var_obj */
9640
1.14M
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9641
1.14M
    prs = find_own_property(&pr, p, prop);
9642
1.14M
    if (prs) {
9643
        /* XXX: should handle JS_PROP_AUTOINIT properties? */
9644
6.36k
        if (flag != 1) {
9645
6.35k
            if (unlikely(JS_IsUninitialized(pr->u.value))) {
9646
0
                JS_FreeValue(ctx, val);
9647
0
                JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
9648
0
                return -1;
9649
0
            }
9650
6.35k
            if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
9651
0
                JS_FreeValue(ctx, val);
9652
0
                return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
9653
0
            }
9654
6.35k
        }
9655
6.36k
        set_value(ctx, &pr->u.value, val);
9656
6.36k
        return 0;
9657
6.36k
    }
9658
1.13M
    flags = JS_PROP_THROW_STRICT;
9659
1.13M
    if (is_strict_mode(ctx)) 
9660
419k
        flags |= JS_PROP_NO_ADD;
9661
1.13M
    return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags);
9662
1.14M
}
9663
9664
/* return -1, FALSE or TRUE. return FALSE if not configurable or
9665
   invalid object. return -1 in case of exception.
9666
   flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */
9667
int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags)
9668
83.4k
{
9669
83.4k
    JSValue obj1;
9670
83.4k
    JSObject *p;
9671
83.4k
    int res;
9672
    
9673
83.4k
    obj1 = JS_ToObject(ctx, obj);
9674
83.4k
    if (JS_IsException(obj1))
9675
0
        return -1;
9676
83.4k
    p = JS_VALUE_GET_OBJ(obj1);
9677
83.4k
    res = delete_property(ctx, p, prop);
9678
83.4k
    JS_FreeValue(ctx, obj1);
9679
83.4k
    if (res != FALSE)
9680
83.4k
        return res;
9681
0
    if ((flags & JS_PROP_THROW) ||
9682
0
        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
9683
0
        JS_ThrowTypeError(ctx, "could not delete property");
9684
0
        return -1;
9685
0
    }
9686
0
    return FALSE;
9687
0
}
9688
9689
int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int flags)
9690
81.5k
{
9691
81.5k
    JSAtom prop;
9692
81.5k
    int res;
9693
9694
81.5k
    if ((uint64_t)idx <= JS_ATOM_MAX_INT) {
9695
        /* fast path for fast arrays */
9696
81.5k
        return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags);
9697
81.5k
    }
9698
0
    prop = JS_NewAtomInt64(ctx, idx);
9699
0
    if (prop == JS_ATOM_NULL)
9700
0
        return -1;
9701
0
    res = JS_DeleteProperty(ctx, obj, prop, flags);
9702
0
    JS_FreeAtom(ctx, prop);
9703
0
    return res;
9704
0
}
9705
9706
BOOL JS_IsFunction(JSContext *ctx, JSValueConst val)
9707
3.45M
{
9708
3.45M
    JSObject *p;
9709
3.45M
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9710
72
        return FALSE;
9711
3.45M
    p = JS_VALUE_GET_OBJ(val);
9712
3.45M
    switch(p->class_id) {
9713
77.3k
    case JS_CLASS_BYTECODE_FUNCTION:
9714
77.3k
        return TRUE;
9715
0
    case JS_CLASS_PROXY:
9716
0
        return p->u.proxy_data->is_func;
9717
3.37M
    default:
9718
3.37M
        return (ctx->rt->class_array[p->class_id].call != NULL);
9719
3.45M
    }
9720
3.45M
}
9721
9722
BOOL JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func, int magic)
9723
2.62k
{
9724
2.62k
    JSObject *p;
9725
2.62k
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9726
2
        return FALSE;
9727
2.62k
    p = JS_VALUE_GET_OBJ(val);
9728
2.62k
    if (p->class_id == JS_CLASS_C_FUNCTION)
9729
2.62k
        return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic);
9730
0
    else
9731
0
        return FALSE;
9732
2.62k
}
9733
9734
BOOL JS_IsConstructor(JSContext *ctx, JSValueConst val)
9735
201k
{
9736
201k
    JSObject *p;
9737
201k
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9738
0
        return FALSE;
9739
201k
    p = JS_VALUE_GET_OBJ(val);
9740
201k
    return p->is_constructor;
9741
201k
}
9742
9743
BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, BOOL val)
9744
327k
{
9745
327k
    JSObject *p;
9746
327k
    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
9747
0
        return FALSE;
9748
327k
    p = JS_VALUE_GET_OBJ(func_obj);
9749
327k
    p->is_constructor = val;
9750
327k
    return TRUE;
9751
327k
}
9752
9753
BOOL JS_IsError(JSContext *ctx, JSValueConst val)
9754
52
{
9755
52
    JSObject *p;
9756
52
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9757
5
        return FALSE;
9758
47
    p = JS_VALUE_GET_OBJ(val);
9759
47
    return (p->class_id == JS_CLASS_ERROR);
9760
52
}
9761
9762
/* used to avoid catching interrupt exceptions */
9763
BOOL JS_IsUncatchableError(JSContext *ctx, JSValueConst val)
9764
5.05k
{
9765
5.05k
    JSObject *p;
9766
5.05k
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9767
4
        return FALSE;
9768
5.05k
    p = JS_VALUE_GET_OBJ(val);
9769
5.05k
    return p->class_id == JS_CLASS_ERROR && p->is_uncatchable_error;
9770
5.05k
}
9771
9772
void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag)
9773
11
{
9774
11
    JSObject *p;
9775
11
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9776
0
        return;
9777
11
    p = JS_VALUE_GET_OBJ(val);
9778
11
    if (p->class_id == JS_CLASS_ERROR)
9779
11
        p->is_uncatchable_error = flag;
9780
11
}
9781
9782
void JS_ResetUncatchableError(JSContext *ctx)
9783
0
{
9784
0
    JS_SetUncatchableError(ctx, ctx->rt->current_exception, FALSE);
9785
0
}
9786
9787
void JS_SetOpaque(JSValue obj, void *opaque)
9788
1.00M
{
9789
1.00M
   JSObject *p;
9790
1.00M
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
9791
1.00M
        p = JS_VALUE_GET_OBJ(obj);
9792
1.00M
        p->u.opaque = opaque;
9793
1.00M
    }
9794
1.00M
}
9795
9796
/* return NULL if not an object of class class_id */
9797
void *JS_GetOpaque(JSValueConst obj, JSClassID class_id)
9798
1.90M
{
9799
1.90M
    JSObject *p;
9800
1.90M
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
9801
0
        return NULL;
9802
1.90M
    p = JS_VALUE_GET_OBJ(obj);
9803
1.90M
    if (p->class_id != class_id)
9804
0
        return NULL;
9805
1.90M
    return p->u.opaque;
9806
1.90M
}
9807
9808
void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id)
9809
606k
{
9810
606k
    void *p = JS_GetOpaque(obj, class_id);
9811
606k
    if (unlikely(!p)) {
9812
0
        JS_ThrowTypeErrorInvalidClass(ctx, class_id);
9813
0
    }
9814
606k
    return p;
9815
606k
}
9816
9817
1.16M
#define HINT_STRING  0
9818
1.60M
#define HINT_NUMBER  1
9819
800k
#define HINT_NONE    2
9820
/* don't try Symbol.toPrimitive */
9821
1.91M
#define HINT_FORCE_ORDINARY (1 << 4)
9822
9823
static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)
9824
1.58M
{
9825
1.58M
    int i;
9826
1.58M
    BOOL force_ordinary;
9827
9828
1.58M
    JSAtom method_name;
9829
1.58M
    JSValue method, ret;
9830
1.58M
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9831
626k
        return val;
9832
959k
    force_ordinary = hint & HINT_FORCE_ORDINARY;
9833
959k
    hint &= ~HINT_FORCE_ORDINARY;
9834
959k
    if (!force_ordinary) {
9835
959k
        method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive);
9836
959k
        if (JS_IsException(method))
9837
0
            goto exception;
9838
        /* ECMA says *If exoticToPrim is not undefined* but tests in
9839
           test262 use null as a non callable converter */
9840
959k
        if (!JS_IsUndefined(method) && !JS_IsNull(method)) {
9841
0
            JSAtom atom;
9842
0
            JSValue arg;
9843
0
            switch(hint) {
9844
0
            case HINT_STRING:
9845
0
                atom = JS_ATOM_string;
9846
0
                break;
9847
0
            case HINT_NUMBER:
9848
0
                atom = JS_ATOM_number;
9849
0
                break;
9850
0
            default:
9851
0
            case HINT_NONE:
9852
0
                atom = JS_ATOM_default;
9853
0
                break;
9854
0
            }
9855
0
            arg = JS_AtomToString(ctx, atom);
9856
0
            ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);
9857
0
            JS_FreeValue(ctx, arg);
9858
0
            if (JS_IsException(ret))
9859
0
                goto exception;
9860
0
            JS_FreeValue(ctx, val);
9861
0
            if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT)
9862
0
                return ret;
9863
0
            JS_FreeValue(ctx, ret);
9864
0
            return JS_ThrowTypeError(ctx, "toPrimitive");
9865
0
        }
9866
959k
    }
9867
959k
    if (hint != HINT_STRING)
9868
753k
        hint = HINT_NUMBER;
9869
1.71M
    for(i = 0; i < 2; i++) {
9870
1.71M
        if ((i ^ hint) == 0) {
9871
959k
            method_name = JS_ATOM_toString;
9872
959k
        } else {
9873
753k
            method_name = JS_ATOM_valueOf;
9874
753k
        }
9875
1.71M
        method = JS_GetProperty(ctx, val, method_name);
9876
1.71M
        if (JS_IsException(method))
9877
0
            goto exception;
9878
1.71M
        if (JS_IsFunction(ctx, method)) {
9879
1.71M
            ret = JS_CallFree(ctx, method, val, 0, NULL);
9880
1.71M
            if (JS_IsException(ret))
9881
8
                goto exception;
9882
1.71M
            if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
9883
959k
                JS_FreeValue(ctx, val);
9884
959k
                return ret;
9885
959k
            }
9886
753k
            JS_FreeValue(ctx, ret);
9887
753k
        } else {
9888
0
            JS_FreeValue(ctx, method);
9889
0
        }
9890
1.71M
    }
9891
0
    JS_ThrowTypeError(ctx, "toPrimitive");
9892
8
exception:
9893
8
    JS_FreeValue(ctx, val);
9894
8
    return JS_EXCEPTION;
9895
0
}
9896
9897
static JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint)
9898
205k
{
9899
205k
    return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint);
9900
205k
}
9901
9902
void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj)
9903
0
{
9904
0
    JSObject *p;
9905
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
9906
0
        return;
9907
0
    p = JS_VALUE_GET_OBJ(obj);
9908
0
    p->is_HTMLDDA = TRUE;
9909
0
}
9910
9911
static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj)
9912
1.73k
{
9913
1.73k
    JSObject *p;
9914
1.73k
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
9915
1.72k
        return FALSE;
9916
18
    p = JS_VALUE_GET_OBJ(obj);
9917
18
    return p->is_HTMLDDA;
9918
1.73k
}
9919
                         
9920
static int JS_ToBoolFree(JSContext *ctx, JSValue val)
9921
331k
{
9922
331k
    uint32_t tag = JS_VALUE_GET_TAG(val);
9923
331k
    switch(tag) {
9924
0
    case JS_TAG_INT:
9925
0
        return JS_VALUE_GET_INT(val) != 0;
9926
102k
    case JS_TAG_BOOL:
9927
102k
    case JS_TAG_NULL:
9928
102k
    case JS_TAG_UNDEFINED:
9929
102k
        return JS_VALUE_GET_INT(val);
9930
0
    case JS_TAG_EXCEPTION:
9931
0
        return -1;
9932
6.20k
    case JS_TAG_STRING:
9933
6.20k
        {
9934
6.20k
            BOOL ret = JS_VALUE_GET_STRING(val)->len != 0;
9935
6.20k
            JS_FreeValue(ctx, val);
9936
6.20k
            return ret;
9937
102k
        }
9938
0
#ifdef CONFIG_BIGNUM
9939
7.96k
    case JS_TAG_BIG_INT:
9940
7.96k
    case JS_TAG_BIG_FLOAT:
9941
7.96k
        {
9942
7.96k
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
9943
7.96k
            BOOL ret;
9944
7.96k
            ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
9945
7.96k
            JS_FreeValue(ctx, val);
9946
7.96k
            return ret;
9947
7.96k
        }
9948
0
    case JS_TAG_BIG_DECIMAL:
9949
0
        {
9950
0
            JSBigDecimal *p = JS_VALUE_GET_PTR(val);
9951
0
            BOOL ret;
9952
0
            ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
9953
0
            JS_FreeValue(ctx, val);
9954
0
            return ret;
9955
7.96k
        }
9956
0
#endif
9957
215k
    case JS_TAG_OBJECT:
9958
215k
        {
9959
215k
            JSObject *p = JS_VALUE_GET_OBJ(val);
9960
215k
            BOOL ret;
9961
215k
            ret = !p->is_HTMLDDA;
9962
215k
            JS_FreeValue(ctx, val);
9963
215k
            return ret;
9964
7.96k
        }
9965
0
        break;
9966
29
    default:
9967
29
        if (JS_TAG_IS_FLOAT64(tag)) {
9968
29
            double d = JS_VALUE_GET_FLOAT64(val);
9969
29
            return !isnan(d) && d != 0;
9970
29
        } else {
9971
0
            JS_FreeValue(ctx, val);
9972
0
            return TRUE;
9973
0
        }
9974
331k
    }
9975
331k
}
9976
9977
int JS_ToBool(JSContext *ctx, JSValueConst val)
9978
0
{
9979
0
    return JS_ToBoolFree(ctx, JS_DupValue(ctx, val));
9980
0
}
9981
9982
static int skip_spaces(const char *pc)
9983
1.04M
{
9984
1.04M
    const uint8_t *p, *p_next, *p_start;
9985
1.04M
    uint32_t c;
9986
9987
1.04M
    p = p_start = (const uint8_t *)pc;
9988
1.05M
    for (;;) {
9989
1.05M
        c = *p;
9990
1.05M
        if (c < 128) {
9991
1.05M
            if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20)))
9992
1.04M
                break;
9993
8.74k
            p++;
9994
8.74k
        } else {
9995
451
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
9996
451
            if (!lre_is_space(c))
9997
442
                break;
9998
9
            p = p_next;
9999
9
        }
10000
1.05M
    }
10001
1.04M
    return p - p_start;
10002
1.04M
}
10003
10004
static inline int to_digit(int c)
10005
1.27M
{
10006
1.27M
    if (c >= '0' && c <= '9')
10007
343k
        return c - '0';
10008
932k
    else if (c >= 'A' && c <= 'Z')
10009
6.76k
        return c - 'A' + 10;
10010
925k
    else if (c >= 'a' && c <= 'z')
10011
624k
        return c - 'a' + 10;
10012
301k
    else
10013
301k
        return 36;
10014
1.27M
}
10015
10016
/* XXX: remove */
10017
static double js_strtod(const char *p, int radix, BOOL is_float)
10018
67.9k
{
10019
67.9k
    double d;
10020
67.9k
    int c;
10021
    
10022
67.9k
    if (!is_float || radix != 10) {
10023
56.3k
        uint64_t n_max, n;
10024
56.3k
        int int_exp, is_neg;
10025
        
10026
56.3k
        is_neg = 0;
10027
56.3k
        if (*p == '-') {
10028
4.77k
            is_neg = 1;
10029
4.77k
            p++;
10030
4.77k
        }
10031
10032
        /* skip leading zeros */
10033
75.1k
        while (*p == '0')
10034
18.7k
            p++;
10035
56.3k
        n = 0;
10036
56.3k
        if (radix == 10)
10037
50.5k
            n_max = ((uint64_t)-1 - 9) / 10; /* most common case */
10038
5.83k
        else
10039
5.83k
            n_max = ((uint64_t)-1 - (radix - 1)) / radix;
10040
        /* XXX: could be more precise */
10041
56.3k
        int_exp = 0;
10042
178k
        while (*p != '\0') {
10043
121k
            c = to_digit((uint8_t)*p);
10044
121k
            if (c >= radix)
10045
0
                break;
10046
121k
            if (n <= n_max) {
10047
113k
                n = n * radix + c;
10048
113k
            } else {
10049
8.17k
                int_exp++;
10050
8.17k
            }
10051
121k
            p++;
10052
121k
        }
10053
56.3k
        d = n;
10054
56.3k
        if (int_exp != 0) {
10055
240
            d *= pow(radix, int_exp);
10056
240
        }
10057
56.3k
        if (is_neg)
10058
4.77k
            d = -d;
10059
56.3k
    } else {
10060
11.5k
        d = strtod(p, NULL);
10061
11.5k
    }
10062
67.9k
    return d;
10063
67.9k
}
10064
10065
1.14M
#define ATOD_INT_ONLY        (1 << 0)
10066
/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
10067
582k
#define ATOD_ACCEPT_BIN_OCT  (1 << 2)
10068
/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
10069
71.8k
#define ATOD_ACCEPT_LEGACY_OCTAL  (1 << 4)
10070
/* accept _ between digits as a digit separator */
10071
648k
#define ATOD_ACCEPT_UNDERSCORES  (1 << 5)
10072
/* allow a suffix to override the type */
10073
145k
#define ATOD_ACCEPT_SUFFIX    (1 << 6) 
10074
/* default type */
10075
582k
#define ATOD_TYPE_MASK        (3 << 7)
10076
1.20M
#define ATOD_TYPE_FLOAT64     (0 << 7)
10077
23.0k
#define ATOD_TYPE_BIG_INT     (1 << 7)
10078
142
#define ATOD_TYPE_BIG_FLOAT   (2 << 7)
10079
14
#define ATOD_TYPE_BIG_DECIMAL (3 << 7)
10080
/* assume bigint mode: floats are parsed as integers if no decimal
10081
   point nor exponent */
10082
79.5k
#define ATOD_MODE_BIGINT      (1 << 9) 
10083
/* accept -0x1 */
10084
4.86k
#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10)
10085
10086
#ifdef CONFIG_BIGNUM
10087
static JSValue js_string_to_bigint(JSContext *ctx, const char *buf,
10088
                                   int radix, int flags, slimb_t *pexponent)
10089
11.5k
{
10090
11.5k
    bf_t a_s, *a = &a_s;
10091
11.5k
    int ret;
10092
11.5k
    JSValue val;
10093
11.5k
    val = JS_NewBigInt(ctx);
10094
11.5k
    if (JS_IsException(val))
10095
0
        return val;
10096
11.5k
    a = JS_GetBigInt(val);
10097
11.5k
    ret = bf_atof(a, buf, NULL, radix, BF_PREC_INF, BF_RNDZ);
10098
11.5k
    if (ret & BF_ST_MEM_ERROR) {
10099
0
        JS_FreeValue(ctx, val);
10100
0
        return JS_ThrowOutOfMemory(ctx);
10101
0
    }
10102
11.5k
    val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0);
10103
11.5k
    return val;
10104
11.5k
}
10105
10106
static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf,
10107
                                     int radix, int flags, slimb_t *pexponent)
10108
0
{
10109
0
    bf_t *a;
10110
0
    int ret;
10111
0
    JSValue val;
10112
    
10113
0
    val = JS_NewBigFloat(ctx);
10114
0
    if (JS_IsException(val))
10115
0
        return val;
10116
0
    a = JS_GetBigFloat(val);
10117
0
    if (flags & ATOD_ACCEPT_SUFFIX) {
10118
        /* return the exponent to get infinite precision */
10119
0
        ret = bf_atof2(a, pexponent, buf, NULL, radix, BF_PREC_INF,
10120
0
                       BF_RNDZ | BF_ATOF_EXPONENT);
10121
0
    } else {
10122
0
        ret = bf_atof(a, buf, NULL, radix, ctx->fp_env.prec,
10123
0
                      ctx->fp_env.flags);
10124
0
    }
10125
0
    if (ret & BF_ST_MEM_ERROR) {
10126
0
        JS_FreeValue(ctx, val);
10127
0
        return JS_ThrowOutOfMemory(ctx);
10128
0
    }
10129
0
    return val;
10130
0
}
10131
10132
static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf,
10133
                                       int radix, int flags, slimb_t *pexponent)
10134
0
{
10135
0
    bfdec_t *a;
10136
0
    int ret;
10137
0
    JSValue val;
10138
    
10139
0
    val = JS_NewBigDecimal(ctx);
10140
0
    if (JS_IsException(val))
10141
0
        return val;
10142
0
    a = JS_GetBigDecimal(val);
10143
0
    ret = bfdec_atof(a, buf, NULL, BF_PREC_INF,
10144
0
                     BF_RNDZ | BF_ATOF_NO_NAN_INF);
10145
0
    if (ret & BF_ST_MEM_ERROR) {
10146
0
        JS_FreeValue(ctx, val);
10147
0
        return JS_ThrowOutOfMemory(ctx);
10148
0
    }
10149
0
    return val;
10150
0
}
10151
10152
#endif
10153
10154
/* return an exception in case of memory error. Return JS_NAN if
10155
   invalid syntax */
10156
#ifdef CONFIG_BIGNUM
10157
static JSValue js_atof2(JSContext *ctx, const char *str, const char **pp,
10158
                        int radix, int flags, slimb_t *pexponent)
10159
#else
10160
static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
10161
                       int radix, int flags)
10162
#endif
10163
582k
{
10164
582k
    const char *p, *p_start;
10165
582k
    int sep, is_neg;
10166
582k
    BOOL is_float, has_legacy_octal;
10167
582k
    int atod_type = flags & ATOD_TYPE_MASK;
10168
582k
    char buf1[64], *buf;
10169
582k
    int i, j, len;
10170
582k
    BOOL buf_allocated = FALSE;
10171
582k
    JSValue val;
10172
    
10173
    /* optional separator between digits */
10174
582k
    sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;
10175
582k
    has_legacy_octal = FALSE;
10176
    
10177
582k
    p = str;
10178
582k
    p_start = p;
10179
582k
    is_neg = 0;
10180
582k
    if (p[0] == '+') {
10181
9
        p++;
10182
9
        p_start++;
10183
9
        if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
10184
9
            goto no_radix_prefix;
10185
582k
    } else if (p[0] == '-') {
10186
4.85k
        p++;
10187
4.85k
        p_start++;
10188
4.85k
        is_neg = 1;
10189
4.85k
        if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
10190
4.85k
            goto no_radix_prefix;
10191
4.85k
    }
10192
577k
    if (p[0] == '0') {
10193
18.2k
        if ((p[1] == 'x' || p[1] == 'X') &&
10194
18.2k
            (radix == 0 || radix == 16)) {
10195
78
            p += 2;
10196
78
            radix = 16;
10197
18.1k
        } else if ((p[1] == 'o' || p[1] == 'O') &&
10198
18.1k
                   radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
10199
0
            p += 2;
10200
0
            radix = 8;
10201
18.1k
        } else if ((p[1] == 'b' || p[1] == 'B') &&
10202
18.1k
                   radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
10203
0
            p += 2;
10204
0
            radix = 2;
10205
18.1k
        } else if ((p[1] >= '0' && p[1] <= '9') &&
10206
18.1k
                   radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) {
10207
5.85k
            int i;
10208
5.85k
            has_legacy_octal = TRUE;
10209
5.85k
            sep = 256;
10210
17.1k
            for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++)
10211
11.2k
                continue;
10212
5.85k
            if (p[i] == '8' || p[i] == '9')
10213
36
                goto no_prefix;
10214
5.82k
            p += 1;
10215
5.82k
            radix = 8;
10216
12.3k
        } else {
10217
12.3k
            goto no_prefix;
10218
12.3k
        }
10219
        /* there must be a digit after the prefix */
10220
5.89k
        if (to_digit((uint8_t)*p) >= radix)
10221
2
            goto fail;
10222
18.2k
    no_prefix: ;
10223
559k
    } else {
10224
563k
 no_radix_prefix:
10225
563k
        if (!(flags & ATOD_INT_ONLY) &&
10226
563k
            (atod_type == ATOD_TYPE_FLOAT64 ||
10227
563k
             atod_type == ATOD_TYPE_BIG_FLOAT) &&
10228
563k
            strstart(p, "Infinity", &p)) {
10229
0
#ifdef CONFIG_BIGNUM
10230
0
            if (atod_type == ATOD_TYPE_BIG_FLOAT) {
10231
0
                bf_t *a;
10232
0
                val = JS_NewBigFloat(ctx);
10233
0
                if (JS_IsException(val))
10234
0
                    goto done;
10235
0
                a = JS_GetBigFloat(val);
10236
0
                bf_set_inf(a, is_neg);
10237
0
            } else
10238
0
#endif
10239
0
            {
10240
0
                double d = 1.0 / 0.0;
10241
0
                if (is_neg)
10242
0
                    d = -d;
10243
0
                val = JS_NewFloat64(ctx, d);
10244
0
            }
10245
0
            goto done;
10246
0
        }
10247
563k
    }
10248
582k
    if (radix == 0)
10249
576k
        radix = 10;
10250
582k
    is_float = FALSE;
10251
582k
    p_start = p;
10252
1.12M
    while (to_digit((uint8_t)*p) < radix
10253
1.12M
           ||  (*p == sep && (radix != 10 ||
10254
25
                              p != p_start + 1 || p[-1] != '0') &&
10255
582k
                to_digit((uint8_t)p[1]) < radix)) {
10256
544k
        p++;
10257
544k
    }
10258
582k
    if (!(flags & ATOD_INT_ONLY)) {
10259
582k
        if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) {
10260
6.08k
            is_float = TRUE;
10261
6.08k
            p++;
10262
6.08k
            if (*p == sep)
10263
0
                goto fail;
10264
17.8k
            while (to_digit((uint8_t)*p) < radix ||
10265
17.8k
                   (*p == sep && to_digit((uint8_t)p[1]) < radix))
10266
11.8k
                p++;
10267
6.08k
        }
10268
582k
        if (p > p_start &&
10269
582k
            (((*p == 'e' || *p == 'E') && radix == 10) ||
10270
79.5k
             ((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) {
10271
5.64k
            const char *p1 = p + 1;
10272
5.64k
            is_float = TRUE;
10273
5.64k
            if (*p1 == '+') {
10274
132
                p1++;
10275
5.50k
            } else if (*p1 == '-') {
10276
140
                p1++;
10277
140
            }
10278
5.64k
            if (is_digit((uint8_t)*p1)) {
10279
5.63k
                p = p1 + 1;
10280
15.3k
                while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1])))
10281
9.75k
                    p++;
10282
5.63k
            }
10283
5.64k
        }
10284
582k
    }
10285
582k
    if (p == p_start)
10286
502k
        goto fail;
10287
10288
79.5k
    buf = buf1;
10289
79.5k
    buf_allocated = FALSE;
10290
79.5k
    len = p - p_start;
10291
79.5k
    if (unlikely((len + 2) > sizeof(buf1))) {
10292
93
        buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */
10293
93
        if (!buf)
10294
0
            goto mem_error;
10295
93
        buf_allocated = TRUE;
10296
93
    }
10297
    /* remove the separators and the radix prefixes */
10298
79.5k
    j = 0;
10299
79.5k
    if (is_neg)
10300
4.77k
        buf[j++] = '-';
10301
663k
    for (i = 0; i < len; i++) {
10302
583k
        if (p_start[i] != '_')
10303
583k
            buf[j++] = p_start[i];
10304
583k
    }
10305
79.5k
    buf[j] = '\0';
10306
10307
79.5k
#ifdef CONFIG_BIGNUM
10308
79.5k
    if (flags & ATOD_ACCEPT_SUFFIX) {
10309
65.9k
        if (*p == 'n') {
10310
11.5k
            p++;
10311
11.5k
            atod_type = ATOD_TYPE_BIG_INT;
10312
54.4k
        } else if (*p == 'l') {
10313
71
            p++;
10314
71
            atod_type = ATOD_TYPE_BIG_FLOAT;
10315
54.3k
        } else if (*p == 'm') {
10316
7
            p++;
10317
7
            atod_type = ATOD_TYPE_BIG_DECIMAL;
10318
54.3k
        } else {
10319
54.3k
            if (flags & ATOD_MODE_BIGINT) {
10320
0
                if (!is_float)
10321
0
                    atod_type = ATOD_TYPE_BIG_INT;
10322
0
                if (has_legacy_octal)
10323
0
                    goto fail;
10324
54.3k
            } else {
10325
54.3k
                if (is_float && radix != 10)
10326
0
                    goto fail;
10327
54.3k
            }
10328
54.3k
        }
10329
65.9k
    } else {
10330
13.6k
        if (atod_type == ATOD_TYPE_FLOAT64) {
10331
13.6k
            if (flags & ATOD_MODE_BIGINT) {
10332
0
                if (!is_float)
10333
0
                    atod_type = ATOD_TYPE_BIG_INT;
10334
0
                if (has_legacy_octal)
10335
0
                    goto fail;
10336
13.6k
            } else {
10337
13.6k
                if (is_float && radix != 10)
10338
0
                    goto fail;
10339
13.6k
            }
10340
13.6k
        }
10341
13.6k
    }
10342
10343
79.5k
    switch(atod_type) {
10344
67.9k
    case ATOD_TYPE_FLOAT64:
10345
67.9k
        {
10346
67.9k
            double d;
10347
67.9k
            d = js_strtod(buf, radix, is_float);
10348
            /* return int or float64 */
10349
67.9k
            val = JS_NewFloat64(ctx, d);
10350
67.9k
        }
10351
67.9k
        break;
10352
11.5k
    case ATOD_TYPE_BIG_INT:
10353
11.5k
        if (has_legacy_octal || is_float)
10354
0
            goto fail;
10355
11.5k
        val = ctx->rt->bigint_ops.from_string(ctx, buf, radix, flags, NULL);
10356
11.5k
        break;
10357
71
    case ATOD_TYPE_BIG_FLOAT:
10358
71
        if (has_legacy_octal)
10359
0
            goto fail;
10360
71
        val = ctx->rt->bigfloat_ops.from_string(ctx, buf, radix, flags,
10361
71
                                                pexponent);
10362
71
        break;
10363
7
    case ATOD_TYPE_BIG_DECIMAL:
10364
7
        if (radix != 10)
10365
0
            goto fail;
10366
7
        val = ctx->rt->bigdecimal_ops.from_string(ctx, buf, radix, flags, NULL);
10367
7
        break;
10368
0
    default:
10369
0
        abort();
10370
79.5k
    }
10371
#else
10372
    {
10373
        double d;
10374
        (void)has_legacy_octal;
10375
        if (is_float && radix != 10)
10376
            goto fail;
10377
        d = js_strtod(buf, radix, is_float);
10378
        val = JS_NewFloat64(ctx, d);
10379
    }
10380
#endif
10381
    
10382
582k
done:
10383
582k
    if (buf_allocated)
10384
93
        js_free_rt(ctx->rt, buf);
10385
582k
    if (pp)
10386
582k
        *pp = p;
10387
582k
    return val;
10388
502k
 fail:
10389
502k
    val = JS_NAN;
10390
502k
    goto done;
10391
0
 mem_error:
10392
0
    val = JS_ThrowOutOfMemory(ctx);
10393
0
    goto done;
10394
79.5k
}
10395
10396
#ifdef CONFIG_BIGNUM
10397
static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
10398
                       int radix, int flags)
10399
516k
{
10400
516k
    return js_atof2(ctx, str, pp, radix, flags, NULL);
10401
516k
}
10402
#endif
10403
10404
typedef enum JSToNumberHintEnum {
10405
    TON_FLAG_NUMBER,
10406
    TON_FLAG_NUMERIC,
10407
} JSToNumberHintEnum;
10408
10409
static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
10410
                                   JSToNumberHintEnum flag)
10411
1.86M
{
10412
1.86M
    uint32_t tag;
10413
1.86M
    JSValue ret;
10414
10415
2.34M
 redo:
10416
2.34M
    tag = JS_VALUE_GET_NORM_TAG(val);
10417
2.34M
    switch(tag) {
10418
0
#ifdef CONFIG_BIGNUM
10419
0
    case JS_TAG_BIG_DECIMAL:
10420
0
        if (flag != TON_FLAG_NUMERIC) {
10421
0
            JS_FreeValue(ctx, val);
10422
0
            return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number");
10423
0
        }
10424
0
        ret = val;
10425
0
        break;
10426
2.15k
    case JS_TAG_BIG_INT:
10427
2.15k
        if (flag != TON_FLAG_NUMERIC) {
10428
0
            JS_FreeValue(ctx, val);
10429
0
            return JS_ThrowTypeError(ctx, "cannot convert bigint to number");
10430
0
        }
10431
2.15k
        ret = val;
10432
2.15k
        break;
10433
0
    case JS_TAG_BIG_FLOAT:
10434
0
        if (flag != TON_FLAG_NUMERIC) {
10435
0
            JS_FreeValue(ctx, val);
10436
0
            return JS_ThrowTypeError(ctx, "cannot convert bigfloat to number");
10437
0
        }
10438
0
        ret = val;
10439
0
        break;
10440
0
#endif
10441
460k
    case JS_TAG_FLOAT64:
10442
945k
    case JS_TAG_INT:
10443
945k
    case JS_TAG_EXCEPTION:
10444
945k
        ret = val;
10445
945k
        break;
10446
349k
    case JS_TAG_BOOL:
10447
350k
    case JS_TAG_NULL:
10448
350k
        ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
10449
350k
        break;
10450
31.3k
    case JS_TAG_UNDEFINED:
10451
31.3k
        ret = JS_NAN;
10452
31.3k
        break;
10453
480k
    case JS_TAG_OBJECT:
10454
480k
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
10455
480k
        if (JS_IsException(val))
10456
8
            return JS_EXCEPTION;
10457
480k
        goto redo;
10458
531k
    case JS_TAG_STRING:
10459
531k
        {
10460
531k
            const char *str;
10461
531k
            const char *p;
10462
531k
            size_t len;
10463
            
10464
531k
            str = JS_ToCStringLen(ctx, &len, val);
10465
531k
            JS_FreeValue(ctx, val);
10466
531k
            if (!str)
10467
0
                return JS_EXCEPTION;
10468
531k
            p = str;
10469
531k
            p += skip_spaces(p);
10470
531k
            if ((p - str) == len) {
10471
15.7k
                ret = JS_NewInt32(ctx, 0);
10472
516k
            } else {
10473
516k
                int flags = ATOD_ACCEPT_BIN_OCT;
10474
516k
                ret = js_atof(ctx, p, &p, 0, flags);
10475
516k
                if (!JS_IsException(ret)) {
10476
516k
                    p += skip_spaces(p);
10477
516k
                    if ((p - str) != len) {
10478
506k
                        JS_FreeValue(ctx, ret);
10479
506k
                        ret = JS_NAN;
10480
506k
                    }
10481
516k
                }
10482
516k
            }
10483
531k
            JS_FreeCString(ctx, str);
10484
531k
        }
10485
0
        break;
10486
3
    case JS_TAG_SYMBOL:
10487
3
        JS_FreeValue(ctx, val);
10488
3
        return JS_ThrowTypeError(ctx, "cannot convert symbol to number");
10489
0
    default:
10490
0
        JS_FreeValue(ctx, val);
10491
0
        ret = JS_NAN;
10492
0
        break;
10493
2.34M
    }
10494
1.86M
    return ret;
10495
2.34M
}
10496
10497
static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val)
10498
201k
{
10499
201k
    return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
10500
201k
}
10501
10502
static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)
10503
1.65M
{
10504
1.65M
    return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
10505
1.65M
}
10506
10507
static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)
10508
0
{
10509
0
    return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
10510
0
}
10511
10512
static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
10513
                                          JSValue val)
10514
0
{
10515
0
    double d;
10516
0
    uint32_t tag;
10517
10518
0
    val = JS_ToNumberFree(ctx, val);
10519
0
    if (JS_IsException(val)) {
10520
0
        *pres = JS_FLOAT64_NAN;
10521
0
        return -1;
10522
0
    }
10523
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10524
0
    switch(tag) {
10525
0
    case JS_TAG_INT:
10526
0
        d = JS_VALUE_GET_INT(val);
10527
0
        break;
10528
0
    case JS_TAG_FLOAT64:
10529
0
        d = JS_VALUE_GET_FLOAT64(val);
10530
0
        break;
10531
0
#ifdef CONFIG_BIGNUM
10532
0
    case JS_TAG_BIG_INT:
10533
0
    case JS_TAG_BIG_FLOAT:
10534
0
        {
10535
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10536
            /* XXX: there can be a double rounding issue with some
10537
               primitives (such as JS_ToUint8ClampFree()), but it is
10538
               not critical to fix it. */
10539
0
            bf_get_float64(&p->num, &d, BF_RNDN);
10540
0
            JS_FreeValue(ctx, val);
10541
0
        }
10542
0
        break;
10543
0
#endif
10544
0
    default:
10545
0
        abort();
10546
0
    }
10547
0
    *pres = d;
10548
0
    return 0;
10549
0
}
10550
10551
static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val)
10552
989k
{
10553
989k
    uint32_t tag;
10554
10555
989k
    tag = JS_VALUE_GET_TAG(val);
10556
989k
    if (tag <= JS_TAG_NULL) {
10557
459k
        *pres = JS_VALUE_GET_INT(val);
10558
459k
        return 0;
10559
530k
    } else if (JS_TAG_IS_FLOAT64(tag)) {
10560
530k
        *pres = JS_VALUE_GET_FLOAT64(val);
10561
530k
        return 0;
10562
530k
    } else {
10563
0
        return __JS_ToFloat64Free(ctx, pres, val);
10564
0
    }
10565
989k
}
10566
10567
int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val)
10568
0
{
10569
0
    return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val));
10570
0
}
10571
10572
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
10573
0
{
10574
0
    return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
10575
0
}
10576
10577
/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
10578
static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
10579
0
{
10580
0
    uint32_t tag;
10581
0
    JSValue ret;
10582
10583
0
 redo:
10584
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10585
0
    switch(tag) {
10586
0
    case JS_TAG_INT:
10587
0
    case JS_TAG_BOOL:
10588
0
    case JS_TAG_NULL:
10589
0
    case JS_TAG_UNDEFINED:
10590
0
        ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
10591
0
        break;
10592
0
    case JS_TAG_FLOAT64:
10593
0
        {
10594
0
            double d = JS_VALUE_GET_FLOAT64(val);
10595
0
            if (isnan(d)) {
10596
0
                ret = JS_NewInt32(ctx, 0);
10597
0
            } else {
10598
                /* convert -0 to +0 */
10599
0
                d = trunc(d) + 0.0;
10600
0
                ret = JS_NewFloat64(ctx, d);
10601
0
            }
10602
0
        }
10603
0
        break;
10604
0
#ifdef CONFIG_BIGNUM
10605
0
    case JS_TAG_BIG_FLOAT:
10606
0
        {
10607
0
            bf_t a_s, *a, r_s, *r = &r_s;
10608
0
            BOOL is_nan;
10609
10610
0
            a = JS_ToBigFloat(ctx, &a_s, val);
10611
0
            if (!bf_is_finite(a)) {
10612
0
                is_nan = bf_is_nan(a);
10613
0
                if (is_nan)
10614
0
                    ret = JS_NewInt32(ctx, 0);
10615
0
                else
10616
0
                    ret = JS_DupValue(ctx, val);
10617
0
            } else {
10618
0
                ret = JS_NewBigInt(ctx);
10619
0
                if (!JS_IsException(ret)) {
10620
0
                    r = JS_GetBigInt(ret);
10621
0
                    bf_set(r, a);
10622
0
                    bf_rint(r, BF_RNDZ);
10623
0
                    ret = JS_CompactBigInt(ctx, ret);
10624
0
                }
10625
0
            }
10626
0
            if (a == &a_s)
10627
0
                bf_delete(a);
10628
0
            JS_FreeValue(ctx, val);
10629
0
        }
10630
0
        break;
10631
0
#endif
10632
0
    default:
10633
0
        val = JS_ToNumberFree(ctx, val);
10634
0
        if (JS_IsException(val))
10635
0
            return val;
10636
0
        goto redo;
10637
0
    }
10638
0
    return ret;
10639
0
}
10640
10641
/* Note: the integer value is satured to 32 bits */
10642
static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val)
10643
3
{
10644
3
    uint32_t tag;
10645
3
    int ret;
10646
10647
6
 redo:
10648
6
    tag = JS_VALUE_GET_NORM_TAG(val);
10649
6
    switch(tag) {
10650
0
    case JS_TAG_INT:
10651
0
    case JS_TAG_BOOL:
10652
0
    case JS_TAG_NULL:
10653
0
    case JS_TAG_UNDEFINED:
10654
0
        ret = JS_VALUE_GET_INT(val);
10655
0
        break;
10656
0
    case JS_TAG_EXCEPTION:
10657
0
        *pres = 0;
10658
0
        return -1;
10659
3
    case JS_TAG_FLOAT64:
10660
3
        {
10661
3
            double d = JS_VALUE_GET_FLOAT64(val);
10662
3
            if (isnan(d)) {
10663
3
                ret = 0;
10664
3
            } else {
10665
0
                if (d < INT32_MIN)
10666
0
                    ret = INT32_MIN;
10667
0
                else if (d > INT32_MAX)
10668
0
                    ret = INT32_MAX;
10669
0
                else
10670
0
                    ret = (int)d;
10671
0
            }
10672
3
        }
10673
3
        break;
10674
0
#ifdef CONFIG_BIGNUM
10675
0
    case JS_TAG_BIG_FLOAT:
10676
0
        {
10677
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10678
0
            bf_get_int32(&ret, &p->num, 0);
10679
0
            JS_FreeValue(ctx, val);
10680
0
        }
10681
0
        break;
10682
0
#endif
10683
3
    default:
10684
3
        val = JS_ToNumberFree(ctx, val);
10685
3
        if (JS_IsException(val)) {
10686
0
            *pres = 0;
10687
0
            return -1;
10688
0
        }
10689
3
        goto redo;
10690
6
    }
10691
3
    *pres = ret;
10692
3
    return 0;
10693
6
}
10694
10695
int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val)
10696
0
{
10697
0
    return JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
10698
0
}
10699
10700
int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val,
10701
                    int min, int max, int min_offset)
10702
3
{
10703
3
    int res = JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
10704
3
    if (res == 0) {
10705
3
        if (*pres < min) {
10706
0
            *pres += min_offset;
10707
0
            if (*pres < min)
10708
0
                *pres = min;
10709
3
        } else {
10710
3
            if (*pres > max)
10711
0
                *pres = max;
10712
3
        }
10713
3
    }
10714
3
    return res;
10715
3
}
10716
10717
static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val)
10718
1.18M
{
10719
1.18M
    uint32_t tag;
10720
10721
1.38M
 redo:
10722
1.38M
    tag = JS_VALUE_GET_NORM_TAG(val);
10723
1.38M
    switch(tag) {
10724
780k
    case JS_TAG_INT:
10725
780k
    case JS_TAG_BOOL:
10726
780k
    case JS_TAG_NULL:
10727
780k
    case JS_TAG_UNDEFINED:
10728
780k
        *pres = JS_VALUE_GET_INT(val);
10729
780k
        return 0;
10730
0
    case JS_TAG_EXCEPTION:
10731
0
        *pres = 0;
10732
0
        return -1;
10733
403k
    case JS_TAG_FLOAT64:
10734
403k
        {
10735
403k
            double d = JS_VALUE_GET_FLOAT64(val);
10736
403k
            if (isnan(d)) {
10737
201k
                *pres = 0;
10738
201k
            } else {
10739
201k
                if (d < INT64_MIN)
10740
0
                    *pres = INT64_MIN;
10741
201k
                else if (d > INT64_MAX)
10742
0
                    *pres = INT64_MAX;
10743
201k
                else
10744
201k
                    *pres = (int64_t)d;
10745
201k
            }
10746
403k
        }
10747
403k
        return 0;
10748
0
#ifdef CONFIG_BIGNUM
10749
0
    case JS_TAG_BIG_FLOAT:
10750
0
        {
10751
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10752
0
            bf_get_int64(pres, &p->num, 0);
10753
0
            JS_FreeValue(ctx, val);
10754
0
        }
10755
0
        return 0;
10756
0
#endif
10757
201k
    default:
10758
201k
        val = JS_ToNumberFree(ctx, val);
10759
201k
        if (JS_IsException(val)) {
10760
2
            *pres = 0;
10761
2
            return -1;
10762
2
        }
10763
201k
        goto redo;
10764
1.38M
    }
10765
1.38M
}
10766
10767
int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val)
10768
0
{
10769
0
    return JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
10770
0
}
10771
10772
int JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValueConst val,
10773
                    int64_t min, int64_t max, int64_t neg_offset)
10774
1.18M
{
10775
1.18M
    int res = JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
10776
1.18M
    if (res == 0) {
10777
1.18M
        if (*pres < 0)
10778
201k
            *pres += neg_offset;
10779
1.18M
        if (*pres < min)
10780
201k
            *pres = min;
10781
981k
        else if (*pres > max)
10782
3
            *pres = max;
10783
1.18M
    }
10784
1.18M
    return res;
10785
1.18M
}
10786
10787
/* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0)
10788
   in case of exception */
10789
static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
10790
0
{
10791
0
    uint32_t tag;
10792
0
    int64_t ret;
10793
10794
0
 redo:
10795
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10796
0
    switch(tag) {
10797
0
    case JS_TAG_INT:
10798
0
    case JS_TAG_BOOL:
10799
0
    case JS_TAG_NULL:
10800
0
    case JS_TAG_UNDEFINED:
10801
0
        ret = JS_VALUE_GET_INT(val);
10802
0
        break;
10803
0
    case JS_TAG_FLOAT64:
10804
0
        {
10805
0
            JSFloat64Union u;
10806
0
            double d;
10807
0
            int e;
10808
0
            d = JS_VALUE_GET_FLOAT64(val);
10809
0
            u.d = d;
10810
            /* we avoid doing fmod(x, 2^64) */
10811
0
            e = (u.u64 >> 52) & 0x7ff;
10812
0
            if (likely(e <= (1023 + 62))) {
10813
                /* fast case */
10814
0
                ret = (int64_t)d;
10815
0
            } else if (e <= (1023 + 62 + 53)) {
10816
0
                uint64_t v;
10817
                /* remainder modulo 2^64 */
10818
0
                v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
10819
0
                ret = v << ((e - 1023) - 52);
10820
                /* take the sign into account */
10821
0
                if (u.u64 >> 63)
10822
0
                    ret = -ret;
10823
0
            } else {
10824
0
                ret = 0; /* also handles NaN and +inf */
10825
0
            }
10826
0
        }
10827
0
        break;
10828
0
#ifdef CONFIG_BIGNUM
10829
0
    case JS_TAG_BIG_FLOAT:
10830
0
        {
10831
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10832
0
            bf_get_int64(&ret, &p->num, BF_GET_INT_MOD);
10833
0
            JS_FreeValue(ctx, val);
10834
0
        }
10835
0
        break;
10836
0
#endif
10837
0
    default:
10838
0
        val = JS_ToNumberFree(ctx, val);
10839
0
        if (JS_IsException(val)) {
10840
0
            *pres = 0;
10841
0
            return -1;
10842
0
        }
10843
0
        goto redo;
10844
0
    }
10845
0
    *pres = ret;
10846
0
    return 0;
10847
0
}
10848
10849
int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
10850
0
{
10851
0
    return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val));
10852
0
}
10853
10854
int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val)
10855
0
{
10856
0
    if (JS_IsBigInt(ctx, val))
10857
0
        return JS_ToBigInt64(ctx, pres, val);
10858
0
    else
10859
0
        return JS_ToInt64(ctx, pres, val);
10860
0
}
10861
10862
/* return (<0, 0) in case of exception */
10863
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)
10864
383k
{
10865
383k
    uint32_t tag;
10866
383k
    int32_t ret;
10867
10868
383k
 redo:
10869
383k
    tag = JS_VALUE_GET_NORM_TAG(val);
10870
383k
    switch(tag) {
10871
353k
    case JS_TAG_INT:
10872
353k
    case JS_TAG_BOOL:
10873
353k
    case JS_TAG_NULL:
10874
353k
    case JS_TAG_UNDEFINED:
10875
353k
        ret = JS_VALUE_GET_INT(val);
10876
353k
        break;
10877
29.6k
    case JS_TAG_FLOAT64:
10878
29.6k
        {
10879
29.6k
            JSFloat64Union u;
10880
29.6k
            double d;
10881
29.6k
            int e;
10882
29.6k
            d = JS_VALUE_GET_FLOAT64(val);
10883
29.6k
            u.d = d;
10884
            /* we avoid doing fmod(x, 2^32) */
10885
29.6k
            e = (u.u64 >> 52) & 0x7ff;
10886
29.6k
            if (likely(e <= (1023 + 30))) {
10887
                /* fast case */
10888
5.83k
                ret = (int32_t)d;
10889
23.8k
            } else if (e <= (1023 + 30 + 53)) {
10890
39
                uint64_t v;
10891
                /* remainder modulo 2^32 */
10892
39
                v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
10893
39
                v = v << ((e - 1023) - 52 + 32);
10894
39
                ret = v >> 32;
10895
                /* take the sign into account */
10896
39
                if (u.u64 >> 63)
10897
29
                    ret = -ret;
10898
23.8k
            } else {
10899
23.8k
                ret = 0; /* also handles NaN and +inf */
10900
23.8k
            }
10901
29.6k
        }
10902
29.6k
        break;
10903
0
#ifdef CONFIG_BIGNUM
10904
0
    case JS_TAG_BIG_FLOAT:
10905
0
        {
10906
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10907
0
            bf_get_int32(&ret, &p->num, BF_GET_INT_MOD);
10908
0
            JS_FreeValue(ctx, val);
10909
0
        }
10910
0
        break;
10911
0
#endif
10912
0
    default:
10913
0
        val = JS_ToNumberFree(ctx, val);
10914
0
        if (JS_IsException(val)) {
10915
0
            *pres = 0;
10916
0
            return -1;
10917
0
        }
10918
0
        goto redo;
10919
383k
    }
10920
383k
    *pres = ret;
10921
383k
    return 0;
10922
383k
}
10923
10924
int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val)
10925
23.3k
{
10926
23.3k
    return JS_ToInt32Free(ctx, pres, JS_DupValue(ctx, val));
10927
23.3k
}
10928
10929
static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val)
10930
6.69k
{
10931
6.69k
    return JS_ToInt32Free(ctx, (int32_t *)pres, val);
10932
6.69k
}
10933
10934
static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
10935
0
{
10936
0
    uint32_t tag;
10937
0
    int res;
10938
10939
0
 redo:
10940
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10941
0
    switch(tag) {
10942
0
    case JS_TAG_INT:
10943
0
    case JS_TAG_BOOL:
10944
0
    case JS_TAG_NULL:
10945
0
    case JS_TAG_UNDEFINED:
10946
0
        res = JS_VALUE_GET_INT(val);
10947
0
#ifdef CONFIG_BIGNUM
10948
0
    int_clamp:
10949
0
#endif
10950
0
        res = max_int(0, min_int(255, res));
10951
0
        break;
10952
0
    case JS_TAG_FLOAT64:
10953
0
        {
10954
0
            double d = JS_VALUE_GET_FLOAT64(val);
10955
0
            if (isnan(d)) {
10956
0
                res = 0;
10957
0
            } else {
10958
0
                if (d < 0)
10959
0
                    res = 0;
10960
0
                else if (d > 255)
10961
0
                    res = 255;
10962
0
                else
10963
0
                    res = lrint(d);
10964
0
            }
10965
0
        }
10966
0
        break;
10967
0
#ifdef CONFIG_BIGNUM
10968
0
    case JS_TAG_BIG_FLOAT:
10969
0
        {
10970
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10971
0
            bf_t r_s, *r = &r_s;
10972
0
            bf_init(ctx->bf_ctx, r);
10973
0
            bf_set(r, &p->num);
10974
0
            bf_rint(r, BF_RNDN);
10975
0
            bf_get_int32(&res, r, 0);
10976
0
            bf_delete(r);
10977
0
            JS_FreeValue(ctx, val);
10978
0
        }
10979
0
        goto int_clamp;
10980
0
#endif
10981
0
    default:
10982
0
        val = JS_ToNumberFree(ctx, val);
10983
0
        if (JS_IsException(val)) {
10984
0
            *pres = 0;
10985
0
            return -1;
10986
0
        }
10987
0
        goto redo;
10988
0
    }
10989
0
    *pres = res;
10990
0
    return 0;
10991
0
}
10992
10993
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
10994
                                            JSValue val, BOOL is_array_ctor)
10995
806k
{
10996
806k
    uint32_t tag, len;
10997
10998
806k
    tag = JS_VALUE_GET_TAG(val);
10999
806k
    switch(tag) {
11000
806k
    case JS_TAG_INT:
11001
806k
    case JS_TAG_BOOL:
11002
806k
    case JS_TAG_NULL:
11003
806k
        {
11004
806k
            int v;
11005
806k
            v = JS_VALUE_GET_INT(val);
11006
806k
            if (v < 0)
11007
0
                goto fail;
11008
806k
            len = v;
11009
806k
        }
11010
0
        break;
11011
0
#ifdef CONFIG_BIGNUM
11012
0
    case JS_TAG_BIG_INT:
11013
0
    case JS_TAG_BIG_FLOAT:
11014
0
        {
11015
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11016
0
            bf_t a;
11017
0
            BOOL res;
11018
0
            bf_get_int32((int32_t *)&len, &p->num, BF_GET_INT_MOD);
11019
0
            bf_init(ctx->bf_ctx, &a);
11020
0
            bf_set_ui(&a, len);
11021
0
            res = bf_cmp_eq(&a, &p->num);
11022
0
            bf_delete(&a);
11023
0
            JS_FreeValue(ctx, val);
11024
0
            if (!res)
11025
0
                goto fail;
11026
0
        }
11027
0
        break;
11028
0
#endif
11029
0
    default:
11030
0
        if (JS_TAG_IS_FLOAT64(tag)) {
11031
0
            double d;
11032
0
            d = JS_VALUE_GET_FLOAT64(val);
11033
0
            len = (uint32_t)d;
11034
0
            if (len != d)
11035
0
                goto fail;
11036
0
        } else {
11037
0
            uint32_t len1;
11038
11039
0
            if (is_array_ctor) {
11040
0
                val = JS_ToNumberFree(ctx, val);
11041
0
                if (JS_IsException(val))
11042
0
                    return -1;
11043
                /* cannot recurse because val is a number */
11044
0
                if (JS_ToArrayLengthFree(ctx, &len, val, TRUE))
11045
0
                    return -1;
11046
0
            } else {
11047
                /* legacy behavior: must do the conversion twice and compare */
11048
0
                if (JS_ToUint32(ctx, &len, val)) {
11049
0
                    JS_FreeValue(ctx, val);
11050
0
                    return -1;
11051
0
                }
11052
0
                val = JS_ToNumberFree(ctx, val);
11053
0
                if (JS_IsException(val))
11054
0
                    return -1;
11055
                /* cannot recurse because val is a number */
11056
0
                if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE))
11057
0
                    return -1;
11058
0
                if (len1 != len) {
11059
0
                fail:
11060
0
                    JS_ThrowRangeError(ctx, "invalid array length");
11061
0
                    return -1;
11062
0
                }
11063
0
            }
11064
0
        }
11065
0
        break;
11066
806k
    }
11067
806k
    *plen = len;
11068
806k
    return 0;
11069
806k
}
11070
11071
1.00M
#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
11072
11073
static BOOL is_safe_integer(double d)
11074
0
{
11075
0
    return isfinite(d) && floor(d) == d &&
11076
0
        fabs(d) <= (double)MAX_SAFE_INTEGER;
11077
0
}
11078
11079
int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
11080
0
{
11081
0
    int64_t v;
11082
0
    if (JS_ToInt64Sat(ctx, &v, val))
11083
0
        return -1;
11084
0
    if (v < 0 || v > MAX_SAFE_INTEGER) {
11085
0
        JS_ThrowRangeError(ctx, "invalid array index");
11086
0
        *plen = 0;
11087
0
        return -1;
11088
0
    }
11089
0
    *plen = v;
11090
0
    return 0;
11091
0
}
11092
11093
/* convert a value to a length between 0 and MAX_SAFE_INTEGER.
11094
   return -1 for exception */
11095
static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
11096
                                       JSValue val)
11097
780k
{
11098
780k
    int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0);
11099
780k
    JS_FreeValue(ctx, val);
11100
780k
    return res;
11101
780k
}
11102
11103
/* Note: can return an exception */
11104
static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)
11105
0
{
11106
0
    double d;
11107
0
    if (!JS_IsNumber(val))
11108
0
        return FALSE;
11109
0
    if (unlikely(JS_ToFloat64(ctx, &d, val)))
11110
0
        return -1;
11111
0
    return isfinite(d) && floor(d) == d;
11112
0
}
11113
11114
static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val)
11115
0
{
11116
0
    uint32_t tag;
11117
11118
0
    tag = JS_VALUE_GET_NORM_TAG(val);
11119
0
    switch(tag) {
11120
0
    case JS_TAG_INT:
11121
0
        {
11122
0
            int v;
11123
0
            v = JS_VALUE_GET_INT(val);
11124
0
            return (v < 0);
11125
0
        }
11126
0
    case JS_TAG_FLOAT64:
11127
0
        {
11128
0
            JSFloat64Union u;
11129
0
            u.d = JS_VALUE_GET_FLOAT64(val);
11130
0
            return (u.u64 >> 63);
11131
0
        }
11132
0
#ifdef CONFIG_BIGNUM
11133
0
    case JS_TAG_BIG_INT:
11134
0
        {
11135
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11136
            /* Note: integer zeros are not necessarily positive */
11137
0
            return p->num.sign && !bf_is_zero(&p->num);
11138
0
        }
11139
0
    case JS_TAG_BIG_FLOAT:
11140
0
        {
11141
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11142
0
            return p->num.sign;
11143
0
        }
11144
0
        break;
11145
0
    case JS_TAG_BIG_DECIMAL:
11146
0
        {
11147
0
            JSBigDecimal *p = JS_VALUE_GET_PTR(val);
11148
0
            return p->num.sign;
11149
0
        }
11150
0
        break;
11151
0
#endif
11152
0
    default:
11153
0
        return FALSE;
11154
0
    }
11155
0
}
11156
11157
#ifdef CONFIG_BIGNUM
11158
11159
static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)
11160
173
{
11161
173
    JSValue ret;
11162
173
    bf_t a_s, *a;
11163
173
    char *str;
11164
173
    int saved_sign;
11165
11166
173
    a = JS_ToBigInt(ctx, &a_s, val);
11167
173
    if (!a)
11168
0
        return JS_EXCEPTION;
11169
173
    saved_sign = a->sign;
11170
173
    if (a->expn == BF_EXP_ZERO)
11171
4
        a->sign = 0;
11172
173
    str = bf_ftoa(NULL, a, radix, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC |
11173
173
                  BF_FTOA_JS_QUIRKS);
11174
173
    a->sign = saved_sign;
11175
173
    JS_FreeBigInt(ctx, a, &a_s);
11176
173
    if (!str)
11177
0
        return JS_ThrowOutOfMemory(ctx);
11178
173
    ret = JS_NewString(ctx, str);
11179
173
    bf_free(ctx->bf_ctx, str);
11180
173
    return ret;
11181
173
}
11182
11183
static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val)
11184
173
{
11185
173
    return js_bigint_to_string1(ctx, val, 10);
11186
173
}
11187
11188
static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix,
11189
                       limb_t prec, bf_flags_t flags)
11190
0
{
11191
0
    JSValue val, ret;
11192
0
    bf_t a_s, *a;
11193
0
    char *str;
11194
0
    int saved_sign;
11195
11196
0
    val = JS_ToNumeric(ctx, val1);
11197
0
    if (JS_IsException(val))
11198
0
        return val;
11199
0
    a = JS_ToBigFloat(ctx, &a_s, val);
11200
0
    saved_sign = a->sign;
11201
0
    if (a->expn == BF_EXP_ZERO)
11202
0
        a->sign = 0;
11203
0
    flags |= BF_FTOA_JS_QUIRKS;
11204
0
    if ((flags & BF_FTOA_FORMAT_MASK) == BF_FTOA_FORMAT_FREE_MIN) {
11205
        /* Note: for floating point numbers with a radix which is not
11206
           a power of two, the current precision is used to compute
11207
           the number of digits. */
11208
0
        if ((radix & (radix - 1)) != 0) {
11209
0
            bf_t r_s, *r = &r_s;
11210
0
            int prec, flags1;
11211
            /* must round first */
11212
0
            if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
11213
0
                prec = ctx->fp_env.prec;
11214
0
                flags1 = ctx->fp_env.flags &
11215
0
                    (BF_FLAG_SUBNORMAL | (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT));
11216
0
            } else {
11217
0
                prec = 53;
11218
0
                flags1 = bf_set_exp_bits(11) | BF_FLAG_SUBNORMAL;
11219
0
            }
11220
0
            bf_init(ctx->bf_ctx, r);
11221
0
            bf_set(r, a);
11222
0
            bf_round(r, prec, flags1 | BF_RNDN);
11223
0
            str = bf_ftoa(NULL, r, radix, prec, flags1 | flags);
11224
0
            bf_delete(r);
11225
0
        } else {
11226
0
            str = bf_ftoa(NULL, a, radix, BF_PREC_INF, flags);
11227
0
        }
11228
0
    } else {
11229
0
        str = bf_ftoa(NULL, a, radix, prec, flags);
11230
0
    }
11231
0
    a->sign = saved_sign;
11232
0
    if (a == &a_s)
11233
0
        bf_delete(a);
11234
0
    JS_FreeValue(ctx, val);
11235
0
    if (!str)
11236
0
        return JS_ThrowOutOfMemory(ctx);
11237
0
    ret = JS_NewString(ctx, str);
11238
0
    bf_free(ctx->bf_ctx, str);
11239
0
    return ret;
11240
0
}
11241
11242
static JSValue js_bigfloat_to_string(JSContext *ctx, JSValueConst val)
11243
0
{
11244
0
    return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
11245
0
}
11246
11247
static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val,
11248
                                        limb_t prec, int flags)
11249
0
{
11250
0
    JSValue ret;
11251
0
    bfdec_t *a;
11252
0
    char *str;
11253
0
    int saved_sign;
11254
11255
0
    a = JS_ToBigDecimal(ctx, val);
11256
0
    saved_sign = a->sign;
11257
0
    if (a->expn == BF_EXP_ZERO)
11258
0
        a->sign = 0;
11259
0
    str = bfdec_ftoa(NULL, a, prec, flags | BF_FTOA_JS_QUIRKS);
11260
0
    a->sign = saved_sign;
11261
0
    if (!str)
11262
0
        return JS_ThrowOutOfMemory(ctx);
11263
0
    ret = JS_NewString(ctx, str);
11264
0
    bf_free(ctx->bf_ctx, str);
11265
0
    return ret;
11266
0
}
11267
11268
static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
11269
0
{
11270
0
    return js_bigdecimal_to_string1(ctx, val, 0,
11271
0
                                    BF_RNDZ | BF_FTOA_FORMAT_FREE);
11272
0
}
11273
11274
#endif /* CONFIG_BIGNUM */
11275
11276
/* 2 <= base <= 36 */
11277
static char *i64toa(char *buf_end, int64_t n, unsigned int base)
11278
2.11k
{
11279
2.11k
    char *q = buf_end;
11280
2.11k
    int digit, is_neg;
11281
11282
2.11k
    is_neg = 0;
11283
2.11k
    if (n < 0) {
11284
0
        is_neg = 1;
11285
0
        n = -n;
11286
0
    }
11287
2.11k
    *--q = '\0';
11288
2.29k
    do {
11289
2.29k
        digit = (uint64_t)n % base;
11290
2.29k
        n = (uint64_t)n / base;
11291
2.29k
        if (digit < 10)
11292
2.29k
            digit += '0';
11293
0
        else
11294
0
            digit += 'a' - 10;
11295
2.29k
        *--q = digit;
11296
2.29k
    } while (n != 0);
11297
2.11k
    if (is_neg)
11298
0
        *--q = '-';
11299
2.11k
    return q;
11300
2.11k
}
11301
11302
/* buf1 contains the printf result */
11303
static void js_ecvt1(double d, int n_digits, int *decpt, int *sign, char *buf,
11304
                     int rounding_mode, char *buf1, int buf1_size)
11305
6.22k
{
11306
6.22k
    if (rounding_mode != FE_TONEAREST)
11307
0
        fesetround(rounding_mode);
11308
6.22k
    snprintf(buf1, buf1_size, "%+.*e", n_digits - 1, d);
11309
6.22k
    if (rounding_mode != FE_TONEAREST)
11310
0
        fesetround(FE_TONEAREST);
11311
6.22k
    *sign = (buf1[0] == '-');
11312
    /* mantissa */
11313
6.22k
    buf[0] = buf1[1];
11314
6.22k
    if (n_digits > 1)
11315
4.74k
        memcpy(buf + 1, buf1 + 3, n_digits - 1);
11316
6.22k
    buf[n_digits] = '\0';
11317
    /* exponent */
11318
6.22k
    *decpt = atoi(buf1 + n_digits + 2 + (n_digits > 1)) + 1;
11319
6.22k
}
11320
11321
/* maximum buffer size for js_dtoa */
11322
0
#define JS_DTOA_BUF_SIZE 128
11323
11324
/* needed because ecvt usually limits the number of digits to
11325
   17. Return the number of digits. */
11326
static int js_ecvt(double d, int n_digits, int *decpt, int *sign, char *buf,
11327
                   BOOL is_fixed)
11328
2.28k
{
11329
2.28k
    int rounding_mode;
11330
2.28k
    char buf_tmp[JS_DTOA_BUF_SIZE];
11331
11332
2.28k
    if (!is_fixed) {
11333
2.28k
        unsigned int n_digits_min, n_digits_max;
11334
        /* find the minimum amount of digits (XXX: inefficient but simple) */
11335
2.28k
        n_digits_min = 1;
11336
2.28k
        n_digits_max = 17;
11337
6.22k
        while (n_digits_min < n_digits_max) {
11338
3.94k
            n_digits = (n_digits_min + n_digits_max) / 2;
11339
3.94k
            js_ecvt1(d, n_digits, decpt, sign, buf, FE_TONEAREST,
11340
3.94k
                     buf_tmp, sizeof(buf_tmp));
11341
3.94k
            if (strtod(buf_tmp, NULL) == d) {
11342
                /* no need to keep the trailing zeros */
11343
16.3k
                while (n_digits >= 2 && buf[n_digits - 1] == '0')
11344
14.1k
                    n_digits--;
11345
2.13k
                n_digits_max = n_digits;
11346
2.13k
            } else {
11347
1.81k
                n_digits_min = n_digits + 1;
11348
1.81k
            }
11349
3.94k
        }
11350
2.28k
        n_digits = n_digits_max;
11351
2.28k
        rounding_mode = FE_TONEAREST;
11352
2.28k
    } else {
11353
0
        rounding_mode = FE_TONEAREST;
11354
0
#ifdef CONFIG_PRINTF_RNDN
11355
0
        {
11356
0
            char buf1[JS_DTOA_BUF_SIZE], buf2[JS_DTOA_BUF_SIZE];
11357
0
            int decpt1, sign1, decpt2, sign2;
11358
            /* The JS rounding is specified as round to nearest ties away
11359
               from zero (RNDNA), but in printf the "ties" case is not
11360
               specified (for example it is RNDN for glibc, RNDNA for
11361
               Windows), so we must round manually. */
11362
0
            js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_TONEAREST,
11363
0
                     buf_tmp, sizeof(buf_tmp));
11364
            /* XXX: could use 2 digits to reduce the average running time */
11365
0
            if (buf1[n_digits] == '5') {
11366
0
                js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_DOWNWARD,
11367
0
                         buf_tmp, sizeof(buf_tmp));
11368
0
                js_ecvt1(d, n_digits + 1, &decpt2, &sign2, buf2, FE_UPWARD,
11369
0
                         buf_tmp, sizeof(buf_tmp));
11370
0
                if (memcmp(buf1, buf2, n_digits + 1) == 0 && decpt1 == decpt2) {
11371
                    /* exact result: round away from zero */
11372
0
                    if (sign1)
11373
0
                        rounding_mode = FE_DOWNWARD;
11374
0
                    else
11375
0
                        rounding_mode = FE_UPWARD;
11376
0
                }
11377
0
            }
11378
0
        }
11379
0
#endif /* CONFIG_PRINTF_RNDN */
11380
0
    }
11381
2.28k
    js_ecvt1(d, n_digits, decpt, sign, buf, rounding_mode,
11382
2.28k
             buf_tmp, sizeof(buf_tmp));
11383
2.28k
    return n_digits;
11384
2.28k
}
11385
11386
static int js_fcvt1(char *buf, int buf_size, double d, int n_digits,
11387
                    int rounding_mode)
11388
0
{
11389
0
    int n;
11390
0
    if (rounding_mode != FE_TONEAREST)
11391
0
        fesetround(rounding_mode);
11392
0
    n = snprintf(buf, buf_size, "%.*f", n_digits, d);
11393
0
    if (rounding_mode != FE_TONEAREST)
11394
0
        fesetround(FE_TONEAREST);
11395
0
    assert(n < buf_size);
11396
0
    return n;
11397
0
}
11398
11399
static void js_fcvt(char *buf, int buf_size, double d, int n_digits)
11400
0
{
11401
0
    int rounding_mode;
11402
0
    rounding_mode = FE_TONEAREST;
11403
0
#ifdef CONFIG_PRINTF_RNDN
11404
0
    {
11405
0
        int n1, n2;
11406
0
        char buf1[JS_DTOA_BUF_SIZE];
11407
0
        char buf2[JS_DTOA_BUF_SIZE];
11408
11409
        /* The JS rounding is specified as round to nearest ties away from
11410
           zero (RNDNA), but in printf the "ties" case is not specified
11411
           (for example it is RNDN for glibc, RNDNA for Windows), so we
11412
           must round manually. */
11413
0
        n1 = js_fcvt1(buf1, sizeof(buf1), d, n_digits + 1, FE_TONEAREST);
11414
0
        rounding_mode = FE_TONEAREST;
11415
        /* XXX: could use 2 digits to reduce the average running time */
11416
0
        if (buf1[n1 - 1] == '5') {
11417
0
            n1 = js_fcvt1(buf1, sizeof(buf1), d, n_digits + 1, FE_DOWNWARD);
11418
0
            n2 = js_fcvt1(buf2, sizeof(buf2), d, n_digits + 1, FE_UPWARD);
11419
0
            if (n1 == n2 && memcmp(buf1, buf2, n1) == 0) {
11420
                /* exact result: round away from zero */
11421
0
                if (buf1[0] == '-')
11422
0
                    rounding_mode = FE_DOWNWARD;
11423
0
                else
11424
0
                    rounding_mode = FE_UPWARD;
11425
0
            }
11426
0
        }
11427
0
    }
11428
0
#endif /* CONFIG_PRINTF_RNDN */
11429
0
    js_fcvt1(buf, buf_size, d, n_digits, rounding_mode);
11430
0
}
11431
11432
/* radix != 10 is only supported with flags = JS_DTOA_VAR_FORMAT */
11433
/* use as many digits as necessary */
11434
180k
#define JS_DTOA_VAR_FORMAT   (0 << 0)
11435
/* use n_digits significant digits (1 <= n_digits <= 101) */
11436
2.28k
#define JS_DTOA_FIXED_FORMAT (1 << 0)
11437
/* force fractional format: [-]dd.dd with n_digits fractional digits */
11438
0
#define JS_DTOA_FRAC_FORMAT  (2 << 0)
11439
/* force exponential notation either in fixed or variable format */
11440
2.28k
#define JS_DTOA_FORCE_EXP    (1 << 2)
11441
11442
/* XXX: slow and maybe not fully correct. Use libbf when it is fast enough.
11443
   XXX: radix != 10 is only supported for small integers
11444
*/
11445
static void js_dtoa1(char *buf, double d, int radix, int n_digits, int flags)
11446
175k
{
11447
175k
    char *q;
11448
11449
175k
    if (!isfinite(d)) {
11450
171k
        if (isnan(d)) {
11451
170k
            strcpy(buf, "NaN");
11452
170k
        } else {
11453
1.08k
            q = buf;
11454
1.08k
            if (d < 0)
11455
0
                *q++ = '-';
11456
1.08k
            strcpy(q, "Infinity");
11457
1.08k
        }
11458
171k
    } else if (flags == JS_DTOA_VAR_FORMAT) {
11459
4.39k
        int64_t i64;
11460
4.39k
        char buf1[70], *ptr;
11461
4.39k
        i64 = (int64_t)d;
11462
4.39k
        if (d != i64 || i64 > MAX_SAFE_INTEGER || i64 < -MAX_SAFE_INTEGER)
11463
2.28k
            goto generic_conv;
11464
        /* fast path for integers */
11465
2.11k
        ptr = i64toa(buf1 + sizeof(buf1), i64, radix);
11466
2.11k
        strcpy(buf, ptr);
11467
2.11k
    } else {
11468
0
        if (d == 0.0)
11469
0
            d = 0.0; /* convert -0 to 0 */
11470
0
        if (flags == JS_DTOA_FRAC_FORMAT) {
11471
0
            js_fcvt(buf, JS_DTOA_BUF_SIZE, d, n_digits);
11472
0
        } else {
11473
0
            char buf1[JS_DTOA_BUF_SIZE];
11474
0
            int sign, decpt, k, n, i, p, n_max;
11475
0
            BOOL is_fixed;
11476
2.28k
        generic_conv:
11477
2.28k
            is_fixed = ((flags & 3) == JS_DTOA_FIXED_FORMAT);
11478
2.28k
            if (is_fixed) {
11479
0
                n_max = n_digits;
11480
2.28k
            } else {
11481
2.28k
                n_max = 21;
11482
2.28k
            }
11483
            /* the number has k digits (k >= 1) */
11484
2.28k
            k = js_ecvt(d, n_digits, &decpt, &sign, buf1, is_fixed);
11485
2.28k
            n = decpt; /* d=10^(n-k)*(buf1) i.e. d= < x.yyyy 10^(n-1) */
11486
2.28k
            q = buf;
11487
2.28k
            if (sign)
11488
0
                *q++ = '-';
11489
2.28k
            if (flags & JS_DTOA_FORCE_EXP)
11490
0
                goto force_exp;
11491
2.28k
            if (n >= 1 && n <= n_max) {
11492
106
                if (k <= n) {
11493
2
                    memcpy(q, buf1, k);
11494
2
                    q += k;
11495
8
                    for(i = 0; i < (n - k); i++)
11496
6
                        *q++ = '0';
11497
2
                    *q = '\0';
11498
104
                } else {
11499
                    /* k > n */
11500
104
                    memcpy(q, buf1, n);
11501
104
                    q += n;
11502
104
                    *q++ = '.';
11503
414
                    for(i = 0; i < (k - n); i++)
11504
310
                        *q++ = buf1[n + i];
11505
104
                    *q = '\0';
11506
104
                }
11507
2.17k
            } else if (n >= -5 && n <= 0) {
11508
1.53k
                *q++ = '0';
11509
1.53k
                *q++ = '.';
11510
1.53k
                for(i = 0; i < -n; i++)
11511
0
                    *q++ = '0';
11512
1.53k
                memcpy(q, buf1, k);
11513
1.53k
                q += k;
11514
1.53k
                *q = '\0';
11515
1.53k
            } else {
11516
643
            force_exp:
11517
                /* exponential notation */
11518
643
                *q++ = buf1[0];
11519
643
                if (k > 1) {
11520
232
                    *q++ = '.';
11521
3.86k
                    for(i = 1; i < k; i++)
11522
3.63k
                        *q++ = buf1[i];
11523
232
                }
11524
643
                *q++ = 'e';
11525
643
                p = n - 1;
11526
643
                if (p >= 0)
11527
560
                    *q++ = '+';
11528
643
                sprintf(q, "%d", p);
11529
643
            }
11530
2.28k
        }
11531
0
    }
11532
175k
}
11533
11534
static JSValue js_dtoa(JSContext *ctx,
11535
                       double d, int radix, int n_digits, int flags)
11536
175k
{
11537
175k
    char buf[JS_DTOA_BUF_SIZE];
11538
175k
    js_dtoa1(buf, d, radix, n_digits, flags);
11539
175k
    return JS_NewString(ctx, buf);
11540
175k
}
11541
11542
JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey)
11543
2.20M
{
11544
2.20M
    uint32_t tag;
11545
2.20M
    const char *str;
11546
2.20M
    char buf[32];
11547
11548
2.20M
    tag = JS_VALUE_GET_NORM_TAG(val);
11549
2.20M
    switch(tag) {
11550
1.70M
    case JS_TAG_STRING:
11551
1.70M
        return JS_DupValue(ctx, val);
11552
121k
    case JS_TAG_INT:
11553
121k
        snprintf(buf, sizeof(buf), "%d", JS_VALUE_GET_INT(val));
11554
121k
        str = buf;
11555
121k
        goto new_string;
11556
423
    case JS_TAG_BOOL:
11557
423
        return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
11558
421
                          JS_ATOM_true : JS_ATOM_false);
11559
15
    case JS_TAG_NULL:
11560
15
        return JS_AtomToString(ctx, JS_ATOM_null);
11561
86
    case JS_TAG_UNDEFINED:
11562
86
        return JS_AtomToString(ctx, JS_ATOM_undefined);
11563
0
    case JS_TAG_EXCEPTION:
11564
0
        return JS_EXCEPTION;
11565
205k
    case JS_TAG_OBJECT:
11566
205k
        {
11567
205k
            JSValue val1, ret;
11568
205k
            val1 = JS_ToPrimitive(ctx, val, HINT_STRING);
11569
205k
            if (JS_IsException(val1))
11570
0
                return val1;
11571
205k
            ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey);
11572
205k
            JS_FreeValue(ctx, val1);
11573
205k
            return ret;
11574
205k
        }
11575
0
        break;
11576
0
    case JS_TAG_FUNCTION_BYTECODE:
11577
0
        str = "[function bytecode]";
11578
0
        goto new_string;
11579
0
    case JS_TAG_SYMBOL:
11580
0
        if (is_ToPropertyKey) {
11581
0
            return JS_DupValue(ctx, val);
11582
0
        } else {
11583
0
            return JS_ThrowTypeError(ctx, "cannot convert symbol to string");
11584
0
        }
11585
175k
    case JS_TAG_FLOAT64:
11586
175k
        return js_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0,
11587
175k
                       JS_DTOA_VAR_FORMAT);
11588
0
#ifdef CONFIG_BIGNUM
11589
173
    case JS_TAG_BIG_INT:
11590
173
        return ctx->rt->bigint_ops.to_string(ctx, val);
11591
0
    case JS_TAG_BIG_FLOAT:
11592
0
        return ctx->rt->bigfloat_ops.to_string(ctx, val);
11593
0
    case JS_TAG_BIG_DECIMAL:
11594
0
        return ctx->rt->bigdecimal_ops.to_string(ctx, val);
11595
0
#endif
11596
0
    default:
11597
0
        str = "[unsupported type]";
11598
121k
    new_string:
11599
121k
        return JS_NewString(ctx, str);
11600
2.20M
    }
11601
2.20M
}
11602
11603
JSValue JS_ToString(JSContext *ctx, JSValueConst val)
11604
850k
{
11605
850k
    return JS_ToStringInternal(ctx, val, FALSE);
11606
850k
}
11607
11608
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val)
11609
278k
{
11610
278k
    JSValue ret;
11611
278k
    ret = JS_ToString(ctx, val);
11612
278k
    JS_FreeValue(ctx, val);
11613
278k
    return ret;
11614
278k
}
11615
11616
static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val)
11617
0
{
11618
0
    if (JS_IsUndefined(val) || JS_IsNull(val))
11619
0
        return JS_ToStringFree(ctx, val);
11620
0
    return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL);
11621
0
}
11622
11623
JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val)
11624
1.15M
{
11625
1.15M
    return JS_ToStringInternal(ctx, val, TRUE);
11626
1.15M
}
11627
11628
static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val)
11629
167k
{
11630
167k
    uint32_t tag = JS_VALUE_GET_TAG(val);
11631
167k
    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
11632
0
        return JS_ThrowTypeError(ctx, "null or undefined are forbidden");
11633
167k
    return JS_ToString(ctx, val);
11634
167k
}
11635
11636
static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
11637
0
{
11638
0
    JSValue val;
11639
0
    JSString *p;
11640
0
    int i;
11641
0
    uint32_t c;
11642
0
    StringBuffer b_s, *b = &b_s;
11643
0
    char buf[16];
11644
11645
0
    val = JS_ToStringCheckObject(ctx, val1);
11646
0
    if (JS_IsException(val))
11647
0
        return val;
11648
0
    p = JS_VALUE_GET_STRING(val);
11649
11650
0
    if (string_buffer_init(ctx, b, p->len + 2))
11651
0
        goto fail;
11652
11653
0
    if (string_buffer_putc8(b, '\"'))
11654
0
        goto fail;
11655
0
    for(i = 0; i < p->len; ) {
11656
0
        c = string_getc(p, &i);
11657
0
        switch(c) {
11658
0
        case '\t':
11659
0
            c = 't';
11660
0
            goto quote;
11661
0
        case '\r':
11662
0
            c = 'r';
11663
0
            goto quote;
11664
0
        case '\n':
11665
0
            c = 'n';
11666
0
            goto quote;
11667
0
        case '\b':
11668
0
            c = 'b';
11669
0
            goto quote;
11670
0
        case '\f':
11671
0
            c = 'f';
11672
0
            goto quote;
11673
0
        case '\"':
11674
0
        case '\\':
11675
0
        quote:
11676
0
            if (string_buffer_putc8(b, '\\'))
11677
0
                goto fail;
11678
0
            if (string_buffer_putc8(b, c))
11679
0
                goto fail;
11680
0
            break;
11681
0
        default:
11682
0
            if (c < 32 || (c >= 0xd800 && c < 0xe000)) {
11683
0
                snprintf(buf, sizeof(buf), "\\u%04x", c);
11684
0
                if (string_buffer_puts8(b, buf))
11685
0
                    goto fail;
11686
0
            } else {
11687
0
                if (string_buffer_putc(b, c))
11688
0
                    goto fail;
11689
0
            }
11690
0
            break;
11691
0
        }
11692
0
    }
11693
0
    if (string_buffer_putc8(b, '\"'))
11694
0
        goto fail;
11695
0
    JS_FreeValue(ctx, val);
11696
0
    return string_buffer_end(b);
11697
0
 fail:
11698
0
    JS_FreeValue(ctx, val);
11699
0
    string_buffer_free(b);
11700
0
    return JS_EXCEPTION;
11701
0
}
11702
11703
static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
11704
0
{
11705
0
    printf("%14s %4s %4s %14s %10s %s\n",
11706
0
           "ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS");
11707
0
}
11708
11709
/* for debug only: dump an object without side effect */
11710
static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
11711
0
{
11712
0
    uint32_t i;
11713
0
    char atom_buf[ATOM_GET_STR_BUF_SIZE];
11714
0
    JSShape *sh;
11715
0
    JSShapeProperty *prs;
11716
0
    JSProperty *pr;
11717
0
    BOOL is_first = TRUE;
11718
0
11719
0
    /* XXX: should encode atoms with special characters */
11720
0
    sh = p->shape; /* the shape can be NULL while freeing an object */
11721
0
    printf("%14p %4d ",
11722
0
           (void *)p,
11723
0
           p->header.ref_count);
11724
0
    if (sh) {
11725
0
        printf("%3d%c %14p ",
11726
0
               sh->header.ref_count,
11727
0
               " *"[sh->is_hashed],
11728
0
               (void *)sh->proto);
11729
0
    } else {
11730
0
        printf("%3s  %14s ", "-", "-");
11731
0
    }
11732
0
    printf("%10s ",
11733
0
           JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), rt->class_array[p->class_id].class_name));
11734
0
    if (p->is_exotic && p->fast_array) {
11735
0
        printf("[ ");
11736
0
        for(i = 0; i < p->u.array.count; i++) {
11737
0
            if (i != 0)
11738
0
                printf(", ");
11739
0
            switch (p->class_id) {
11740
0
            case JS_CLASS_ARRAY:
11741
0
            case JS_CLASS_ARGUMENTS:
11742
0
                JS_DumpValueShort(rt, p->u.array.u.values[i]);
11743
0
                break;
11744
0
            case JS_CLASS_UINT8C_ARRAY:
11745
0
            case JS_CLASS_INT8_ARRAY:
11746
0
            case JS_CLASS_UINT8_ARRAY:
11747
0
            case JS_CLASS_INT16_ARRAY:
11748
0
            case JS_CLASS_UINT16_ARRAY:
11749
0
            case JS_CLASS_INT32_ARRAY:
11750
0
            case JS_CLASS_UINT32_ARRAY:
11751
0
#ifdef CONFIG_BIGNUM
11752
0
            case JS_CLASS_BIG_INT64_ARRAY:
11753
0
            case JS_CLASS_BIG_UINT64_ARRAY:
11754
0
#endif
11755
0
            case JS_CLASS_FLOAT32_ARRAY:
11756
0
            case JS_CLASS_FLOAT64_ARRAY:
11757
0
                {
11758
0
                    int size = 1 << typed_array_size_log2(p->class_id);
11759
0
                    const uint8_t *b = p->u.array.u.uint8_ptr + i * size;
11760
0
                    while (size-- > 0)
11761
0
                        printf("%02X", *b++);
11762
0
                }
11763
0
                break;
11764
0
            }
11765
0
        }
11766
0
        printf(" ] ");
11767
0
    }
11768
0
11769
0
    if (sh) {
11770
0
        printf("{ ");
11771
0
        for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
11772
0
            if (prs->atom != JS_ATOM_NULL) {
11773
0
                pr = &p->prop[i];
11774
0
                if (!is_first)
11775
0
                    printf(", ");
11776
0
                printf("%s: ",
11777
0
                       JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), prs->atom));
11778
0
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
11779
0
                    printf("[getset %p %p]", (void *)pr->u.getset.getter,
11780
0
                           (void *)pr->u.getset.setter);
11781
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
11782
0
                    printf("[varref %p]", (void *)pr->u.var_ref);
11783
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
11784
0
                    printf("[autoinit %p %d %p]",
11785
0
                           (void *)js_autoinit_get_realm(pr),
11786
0
                           js_autoinit_get_id(pr),
11787
0
                           (void *)pr->u.init.opaque);
11788
0
                } else {
11789
0
                    JS_DumpValueShort(rt, pr->u.value);
11790
0
                }
11791
0
                is_first = FALSE;
11792
0
            }
11793
0
        }
11794
0
        printf(" }");
11795
0
    }
11796
0
    
11797
0
    if (js_class_has_bytecode(p->class_id)) {
11798
0
        JSFunctionBytecode *b = p->u.func.function_bytecode;
11799
0
        JSVarRef **var_refs;
11800
0
        if (b->closure_var_count) {
11801
0
            var_refs = p->u.func.var_refs;
11802
0
            printf(" Closure:");
11803
0
            for(i = 0; i < b->closure_var_count; i++) {
11804
0
                printf(" ");
11805
0
                JS_DumpValueShort(rt, var_refs[i]->value);
11806
0
            }
11807
0
            if (p->u.func.home_object) {
11808
0
                printf(" HomeObject: ");
11809
0
                JS_DumpValueShort(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));
11810
0
            }
11811
0
        }
11812
0
    }
11813
0
    printf("\n");
11814
0
}
11815
11816
static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
11817
0
{
11818
0
    if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
11819
0
        JS_DumpObject(rt, (JSObject *)p);
11820
0
    } else {
11821
0
        printf("%14p %4d ",
11822
0
               (void *)p,
11823
0
               p->ref_count);
11824
0
        switch(p->gc_obj_type) {
11825
0
        case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
11826
0
            printf("[function bytecode]");
11827
0
            break;
11828
0
        case JS_GC_OBJ_TYPE_SHAPE:
11829
0
            printf("[shape]");
11830
0
            break;
11831
0
        case JS_GC_OBJ_TYPE_VAR_REF:
11832
0
            printf("[var_ref]");
11833
0
            break;
11834
0
        case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
11835
0
            printf("[async_function]");
11836
0
            break;
11837
0
        case JS_GC_OBJ_TYPE_JS_CONTEXT:
11838
0
            printf("[js_context]");
11839
0
            break;
11840
0
        default:
11841
0
            printf("[unknown %d]", p->gc_obj_type);
11842
0
            break;
11843
0
        }
11844
0
        printf("\n");
11845
0
    }
11846
0
}
11847
11848
static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
11849
                                                      JSValueConst val)
11850
0
{
11851
0
    uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
11852
0
    const char *str;
11853
0
11854
0
    switch(tag) {
11855
0
    case JS_TAG_INT:
11856
0
        printf("%d", JS_VALUE_GET_INT(val));
11857
0
        break;
11858
0
    case JS_TAG_BOOL:
11859
0
        if (JS_VALUE_GET_BOOL(val))
11860
0
            str = "true";
11861
0
        else
11862
0
            str = "false";
11863
0
        goto print_str;
11864
0
    case JS_TAG_NULL:
11865
0
        str = "null";
11866
0
        goto print_str;
11867
0
    case JS_TAG_EXCEPTION:
11868
0
        str = "exception";
11869
0
        goto print_str;
11870
0
    case JS_TAG_UNINITIALIZED:
11871
0
        str = "uninitialized";
11872
0
        goto print_str;
11873
0
    case JS_TAG_UNDEFINED:
11874
0
        str = "undefined";
11875
0
    print_str:
11876
0
        printf("%s", str);
11877
0
        break;
11878
0
    case JS_TAG_FLOAT64:
11879
0
        printf("%.14g", JS_VALUE_GET_FLOAT64(val));
11880
0
        break;
11881
0
#ifdef CONFIG_BIGNUM
11882
0
    case JS_TAG_BIG_INT:
11883
0
        {
11884
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11885
0
            char *str;
11886
0
            str = bf_ftoa(NULL, &p->num, 10, 0,
11887
0
                          BF_RNDZ | BF_FTOA_FORMAT_FRAC);
11888
0
            printf("%sn", str);
11889
0
            bf_realloc(&rt->bf_ctx, str, 0);
11890
0
        }
11891
0
        break;
11892
0
    case JS_TAG_BIG_FLOAT:
11893
0
        {
11894
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11895
0
            char *str;
11896
0
            str = bf_ftoa(NULL, &p->num, 16, BF_PREC_INF,
11897
0
                          BF_RNDZ | BF_FTOA_FORMAT_FREE | BF_FTOA_ADD_PREFIX);
11898
0
            printf("%sl", str);
11899
0
            bf_free(&rt->bf_ctx, str);
11900
0
        }
11901
0
        break;
11902
0
    case JS_TAG_BIG_DECIMAL:
11903
0
        {
11904
0
            JSBigDecimal *p = JS_VALUE_GET_PTR(val);
11905
0
            char *str;
11906
0
            str = bfdec_ftoa(NULL, &p->num, BF_PREC_INF,
11907
0
                             BF_RNDZ | BF_FTOA_FORMAT_FREE);
11908
0
            printf("%sm", str);
11909
0
            bf_free(&rt->bf_ctx, str);
11910
0
        }
11911
0
        break;
11912
0
#endif
11913
0
    case JS_TAG_STRING:
11914
0
        {
11915
0
            JSString *p;
11916
0
            p = JS_VALUE_GET_STRING(val);
11917
0
            JS_DumpString(rt, p);
11918
0
        }
11919
0
        break;
11920
0
    case JS_TAG_FUNCTION_BYTECODE:
11921
0
        {
11922
0
            JSFunctionBytecode *b = JS_VALUE_GET_PTR(val);
11923
0
            char buf[ATOM_GET_STR_BUF_SIZE];
11924
0
            printf("[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
11925
0
        }
11926
0
        break;
11927
0
    case JS_TAG_OBJECT:
11928
0
        {
11929
0
            JSObject *p = JS_VALUE_GET_OBJ(val);
11930
0
            JSAtom atom = rt->class_array[p->class_id].class_name;
11931
0
            char atom_buf[ATOM_GET_STR_BUF_SIZE];
11932
0
            printf("[%s %p]",
11933
0
                   JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), atom), (void *)p);
11934
0
        }
11935
0
        break;
11936
0
    case JS_TAG_SYMBOL:
11937
0
        {
11938
0
            JSAtomStruct *p = JS_VALUE_GET_PTR(val);
11939
0
            char atom_buf[ATOM_GET_STR_BUF_SIZE];
11940
0
            printf("Symbol(%s)",
11941
0
                   JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), js_get_atom_index(rt, p)));
11942
0
        }
11943
0
        break;
11944
0
    case JS_TAG_MODULE:
11945
0
        printf("[module]");
11946
0
        break;
11947
0
    default:
11948
0
        printf("[unknown tag %d]", tag);
11949
0
        break;
11950
0
    }
11951
0
}
11952
11953
static __maybe_unused void JS_DumpValue(JSContext *ctx,
11954
                                                 JSValueConst val)
11955
0
{
11956
0
    JS_DumpValueShort(ctx->rt, val);
11957
0
}
11958
11959
static __maybe_unused void JS_PrintValue(JSContext *ctx,
11960
                                                  const char *str,
11961
                                                  JSValueConst val)
11962
0
{
11963
0
    printf("%s=", str);
11964
0
    JS_DumpValueShort(ctx->rt, val);
11965
0
    printf("\n");
11966
0
}
11967
11968
/* return -1 if exception (proxy case) or TRUE/FALSE */
11969
int JS_IsArray(JSContext *ctx, JSValueConst val)
11970
489k
{
11971
489k
    JSObject *p;
11972
489k
    if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
11973
489k
        p = JS_VALUE_GET_OBJ(val);
11974
489k
        if (unlikely(p->class_id == JS_CLASS_PROXY))
11975
0
            return js_proxy_isArray(ctx, val);
11976
489k
        else
11977
489k
            return p->class_id == JS_CLASS_ARRAY;
11978
489k
    } else {
11979
0
        return FALSE;
11980
0
    }
11981
489k
}
11982
11983
static double js_pow(double a, double b)
11984
1
{
11985
1
    if (unlikely(!isfinite(b)) && fabs(a) == 1) {
11986
        /* not compatible with IEEE 754 */
11987
0
        return JS_FLOAT64_NAN;
11988
1
    } else {
11989
1
        return pow(a, b);
11990
1
    }
11991
1
}
11992
11993
#ifdef CONFIG_BIGNUM
11994
11995
JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v)
11996
7
{
11997
7
    JSValue val;
11998
7
    bf_t *a;
11999
7
    val = JS_NewBigInt(ctx);
12000
7
    if (JS_IsException(val))
12001
0
        return val;
12002
7
    a = JS_GetBigInt(val);
12003
7
    if (bf_set_si(a, v)) {
12004
0
        JS_FreeValue(ctx, val);
12005
0
        return JS_ThrowOutOfMemory(ctx);
12006
0
    }
12007
7
    return val;
12008
7
}
12009
12010
JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
12011
7
{
12012
7
    if (is_math_mode(ctx) &&
12013
7
        v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
12014
0
        return JS_NewInt64(ctx, v);
12015
7
    } else {
12016
7
        return JS_NewBigInt64_1(ctx, v);
12017
7
    }
12018
7
}
12019
12020
JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
12021
0
{
12022
0
    JSValue val;
12023
0
    if (is_math_mode(ctx) && v <= MAX_SAFE_INTEGER) {
12024
0
        val = JS_NewInt64(ctx, v);
12025
0
    } else {
12026
0
        bf_t *a;
12027
0
        val = JS_NewBigInt(ctx);
12028
0
        if (JS_IsException(val))
12029
0
            return val;
12030
0
        a = JS_GetBigInt(val);
12031
0
        if (bf_set_ui(a, v)) {
12032
0
            JS_FreeValue(ctx, val);
12033
0
            return JS_ThrowOutOfMemory(ctx);
12034
0
        }
12035
0
    }
12036
0
    return val;
12037
0
}
12038
12039
/* if the returned bigfloat is allocated it is equal to
12040
   'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return
12041
   NULL in case of error. */
12042
static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val)
12043
1.98k
{
12044
1.98k
    uint32_t tag;
12045
1.98k
    bf_t *r;
12046
1.98k
    JSBigFloat *p;
12047
12048
1.98k
    tag = JS_VALUE_GET_NORM_TAG(val);
12049
1.98k
    switch(tag) {
12050
426
    case JS_TAG_INT:
12051
426
    case JS_TAG_BOOL:
12052
426
    case JS_TAG_NULL:
12053
426
        r = buf;
12054
426
        bf_init(ctx->bf_ctx, r);
12055
426
        if (bf_set_si(r, JS_VALUE_GET_INT(val)))
12056
0
            goto fail;
12057
426
        break;
12058
426
    case JS_TAG_FLOAT64:
12059
392
        r = buf;
12060
392
        bf_init(ctx->bf_ctx, r);
12061
392
        if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) {
12062
0
        fail:
12063
0
            bf_delete(r);
12064
0
            return NULL;
12065
0
        }
12066
392
        break;
12067
1.17k
    case JS_TAG_BIG_INT:
12068
1.17k
    case JS_TAG_BIG_FLOAT:
12069
1.17k
        p = JS_VALUE_GET_PTR(val);
12070
1.17k
        r = &p->num;
12071
1.17k
        break;
12072
0
    case JS_TAG_UNDEFINED:
12073
0
    default:
12074
0
        r = buf;
12075
0
        bf_init(ctx->bf_ctx, r);
12076
0
        bf_set_nan(r);
12077
0
        break;
12078
1.98k
    }
12079
1.98k
    return r;
12080
1.98k
}
12081
12082
/* return NULL if invalid type */
12083
static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val)
12084
0
{
12085
0
    uint32_t tag;
12086
0
    JSBigDecimal *p;
12087
0
    bfdec_t *r;
12088
    
12089
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12090
0
    switch(tag) {
12091
0
    case JS_TAG_BIG_DECIMAL:
12092
0
        p = JS_VALUE_GET_PTR(val);
12093
0
        r = &p->num;
12094
0
        break;
12095
0
    default:
12096
0
        JS_ThrowTypeError(ctx, "bigdecimal expected");
12097
0
        r = NULL;
12098
0
        break;
12099
0
    }
12100
0
    return r;
12101
0
}
12102
12103
/* return NaN if bad bigint literal */
12104
static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
12105
17
{
12106
17
    const char *str, *p;
12107
17
    size_t len;
12108
17
    int flags;
12109
    
12110
17
    str = JS_ToCStringLen(ctx, &len, val);
12111
17
    JS_FreeValue(ctx, val);
12112
17
    if (!str)
12113
0
        return JS_EXCEPTION;
12114
17
    p = str;
12115
17
    p += skip_spaces(p);
12116
17
    if ((p - str) == len) {
12117
7
        val = JS_NewBigInt64(ctx, 0);
12118
10
    } else {
12119
10
        flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
12120
10
        if (is_math_mode(ctx))
12121
0
            flags |= ATOD_MODE_BIGINT;
12122
10
        val = js_atof(ctx, p, &p, 0, flags);
12123
10
        p += skip_spaces(p);
12124
10
        if (!JS_IsException(val)) {
12125
10
            if ((p - str) != len) {
12126
10
                JS_FreeValue(ctx, val);
12127
10
                val = JS_NAN;
12128
10
            }
12129
10
        }
12130
10
    }
12131
17
    JS_FreeCString(ctx, str);
12132
17
    return val;
12133
17
}
12134
12135
static JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val)
12136
0
{
12137
0
    val = JS_StringToBigInt(ctx, val);
12138
0
    if (JS_VALUE_IS_NAN(val))
12139
0
        return JS_ThrowSyntaxError(ctx, "invalid bigint literal");
12140
0
    return val;
12141
0
}
12142
12143
/* if the returned bigfloat is allocated it is equal to
12144
   'buf'. Otherwise it is a pointer to the bigfloat in 'val'. */
12145
static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
12146
1.17k
{
12147
1.17k
    uint32_t tag;
12148
1.17k
    bf_t *r;
12149
1.17k
    JSBigFloat *p;
12150
12151
1.17k
 redo:
12152
1.17k
    tag = JS_VALUE_GET_NORM_TAG(val);
12153
1.17k
    switch(tag) {
12154
1
    case JS_TAG_INT:
12155
1
    case JS_TAG_NULL:
12156
1
    case JS_TAG_UNDEFINED:
12157
1
        if (!is_math_mode(ctx))
12158
1
            goto fail;
12159
        /* fall tru */
12160
0
    case JS_TAG_BOOL:
12161
0
        r = buf;
12162
0
        bf_init(ctx->bf_ctx, r);
12163
0
        bf_set_si(r, JS_VALUE_GET_INT(val));
12164
0
        break;
12165
5
    case JS_TAG_FLOAT64:
12166
5
        {
12167
5
            double d = JS_VALUE_GET_FLOAT64(val);
12168
5
            if (!is_math_mode(ctx))
12169
5
                goto fail;
12170
0
            if (!isfinite(d))
12171
0
                goto fail;
12172
0
            r = buf;
12173
0
            bf_init(ctx->bf_ctx, r);
12174
0
            d = trunc(d);
12175
0
            bf_set_float64(r, d);
12176
0
        }
12177
0
        break;
12178
1.16k
    case JS_TAG_BIG_INT:
12179
1.16k
        p = JS_VALUE_GET_PTR(val);
12180
1.16k
        r = &p->num;
12181
1.16k
        break;
12182
0
    case JS_TAG_BIG_FLOAT:
12183
0
        if (!is_math_mode(ctx))
12184
0
            goto fail;
12185
0
        p = JS_VALUE_GET_PTR(val);
12186
0
        if (!bf_is_finite(&p->num))
12187
0
            goto fail;
12188
0
        r = buf;
12189
0
        bf_init(ctx->bf_ctx, r);
12190
0
        bf_set(r, &p->num);
12191
0
        bf_rint(r, BF_RNDZ);
12192
0
        JS_FreeValue(ctx, val);
12193
0
        break;
12194
0
    case JS_TAG_STRING:
12195
0
        val = JS_StringToBigIntErr(ctx, val);
12196
0
        if (JS_IsException(val))
12197
0
            return NULL;
12198
0
        goto redo;
12199
0
    case JS_TAG_OBJECT:
12200
0
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
12201
0
        if (JS_IsException(val))
12202
0
            return NULL;
12203
0
        goto redo;
12204
0
    default:
12205
6
    fail:
12206
6
        JS_FreeValue(ctx, val);
12207
6
        JS_ThrowTypeError(ctx, "cannot convert to bigint");
12208
6
        return NULL;
12209
1.17k
    }
12210
1.16k
    return r;
12211
1.17k
}
12212
12213
static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val)
12214
1.17k
{
12215
1.17k
    return JS_ToBigIntFree(ctx, buf, JS_DupValue(ctx, val));
12216
1.17k
}
12217
12218
static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val)
12219
0
{
12220
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {
12221
0
        return val;
12222
0
    } else {
12223
0
        bf_t a_s, *a, *r;
12224
0
        int ret;
12225
0
        JSValue res; 
12226
12227
0
        res = JS_NewBigInt(ctx);
12228
0
        if (JS_IsException(res))
12229
0
            return JS_EXCEPTION;
12230
0
        a = JS_ToBigIntFree(ctx, &a_s, val);
12231
0
        if (!a) {
12232
0
            JS_FreeValue(ctx, res);
12233
0
            return JS_EXCEPTION;
12234
0
        }
12235
0
        r = JS_GetBigInt(res);
12236
0
        ret = bf_set(r, a);
12237
0
        JS_FreeBigInt(ctx, a, &a_s);
12238
0
        if (ret) {
12239
0
            JS_FreeValue(ctx, res);
12240
0
            return JS_ThrowOutOfMemory(ctx);
12241
0
        }
12242
0
        return JS_CompactBigInt(ctx, res);
12243
0
    }
12244
0
}
12245
12246
/* free the bf_t allocated by JS_ToBigInt */
12247
static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf)
12248
1.16k
{
12249
1.16k
    if (a == buf) {
12250
0
        bf_delete(a);
12251
1.16k
    } else {
12252
1.16k
        JSBigFloat *p = (JSBigFloat *)((uint8_t *)a -
12253
1.16k
                                       offsetof(JSBigFloat, num));
12254
1.16k
        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_FLOAT, p));
12255
1.16k
    }
12256
1.16k
}
12257
12258
/* XXX: merge with JS_ToInt64Free with a specific flag */
12259
static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
12260
0
{
12261
0
    bf_t a_s, *a;
12262
12263
0
    a = JS_ToBigIntFree(ctx, &a_s, val);
12264
0
    if (!a) {
12265
0
        *pres = 0;
12266
0
        return -1;
12267
0
    }
12268
0
    bf_get_int64(pres, a, BF_GET_INT_MOD);
12269
0
    JS_FreeBigInt(ctx, a, &a_s);
12270
0
    return 0;
12271
0
}
12272
12273
int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
12274
0
{
12275
0
    return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val));
12276
0
}
12277
12278
static JSBigFloat *js_new_bf(JSContext *ctx)
12279
111
{
12280
111
    JSBigFloat *p;
12281
111
    p = js_malloc(ctx, sizeof(*p));
12282
111
    if (!p)
12283
0
        return NULL;
12284
111
    p->header.ref_count = 1;
12285
111
    bf_init(ctx->bf_ctx, &p->num);
12286
111
    return p;
12287
111
}
12288
12289
static JSValue JS_NewBigFloat(JSContext *ctx)
12290
0
{
12291
0
    JSBigFloat *p;
12292
0
    p = js_malloc(ctx, sizeof(*p));
12293
0
    if (!p)
12294
0
        return JS_EXCEPTION;
12295
0
    p->header.ref_count = 1;
12296
0
    bf_init(ctx->bf_ctx, &p->num);
12297
0
    return JS_MKPTR(JS_TAG_BIG_FLOAT, p);
12298
0
}
12299
12300
static JSValue JS_NewBigDecimal(JSContext *ctx)
12301
0
{
12302
0
    JSBigDecimal *p;
12303
0
    p = js_malloc(ctx, sizeof(*p));
12304
0
    if (!p)
12305
0
        return JS_EXCEPTION;
12306
0
    p->header.ref_count = 1;
12307
0
    bfdec_init(ctx->bf_ctx, &p->num);
12308
0
    return JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
12309
0
}
12310
12311
static JSValue JS_NewBigInt(JSContext *ctx)
12312
12.2k
{
12313
12.2k
    JSBigFloat *p;
12314
12.2k
    p = js_malloc(ctx, sizeof(*p));
12315
12.2k
    if (!p)
12316
0
        return JS_EXCEPTION;
12317
12.2k
    p->header.ref_count = 1;
12318
12.2k
    bf_init(ctx->bf_ctx, &p->num);
12319
12.2k
    return JS_MKPTR(JS_TAG_BIG_INT, p);
12320
12.2k
}
12321
12322
static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
12323
                                 BOOL convert_to_safe_integer)
12324
12.2k
{
12325
12.2k
    int64_t v;
12326
12.2k
    bf_t *a;
12327
    
12328
12.2k
    if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT)
12329
0
        return val; /* fail safe */
12330
12.2k
    a = JS_GetBigInt(val);
12331
12.2k
    if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 &&
12332
12.2k
        v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
12333
0
        JS_FreeValue(ctx, val);
12334
0
        return JS_NewInt64(ctx, v);
12335
12.2k
    } else if (a->expn == BF_EXP_ZERO && a->sign) {
12336
6
        JSBigFloat *p = JS_VALUE_GET_PTR(val);
12337
6
        assert(p->header.ref_count == 1);
12338
6
        a->sign = 0;
12339
6
    }
12340
12.2k
    return val;
12341
12.2k
}
12342
12343
/* Convert the big int to a safe integer if in math mode. normalize
12344
   the zero representation. Could also be used to convert the bigint
12345
   to a short bigint value. The reference count of the value must be
12346
   1. Cannot fail */
12347
static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
12348
717
{
12349
717
    return JS_CompactBigInt1(ctx, val, is_math_mode(ctx));
12350
717
}
12351
12352
/* must be kept in sync with JSOverloadableOperatorEnum */
12353
/* XXX: use atoms ? */
12354
static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = {
12355
    "+",
12356
    "-",
12357
    "*",
12358
    "/",
12359
    "%",
12360
    "**",
12361
    "|",
12362
    "&",
12363
    "^",
12364
    "<<",
12365
    ">>",
12366
    ">>>",
12367
    "==",
12368
    "<",
12369
    "pos",
12370
    "neg",
12371
    "++",
12372
    "--",
12373
    "~",
12374
};
12375
12376
static int get_ovop_from_opcode(OPCodeEnum op)
12377
0
{
12378
0
    switch(op) {
12379
0
    case OP_add:
12380
0
        return JS_OVOP_ADD;
12381
0
    case OP_sub:
12382
0
        return JS_OVOP_SUB;
12383
0
    case OP_mul:
12384
0
        return JS_OVOP_MUL;
12385
0
    case OP_div:
12386
0
        return JS_OVOP_DIV;
12387
0
    case OP_mod:
12388
0
    case OP_math_mod:
12389
0
        return JS_OVOP_MOD;
12390
0
    case OP_pow:
12391
0
        return JS_OVOP_POW;
12392
0
    case OP_or:
12393
0
        return JS_OVOP_OR;
12394
0
    case OP_and:
12395
0
        return JS_OVOP_AND;
12396
0
    case OP_xor:
12397
0
        return JS_OVOP_XOR;
12398
0
    case OP_shl:
12399
0
        return JS_OVOP_SHL;
12400
0
    case OP_sar:
12401
0
        return JS_OVOP_SAR;
12402
0
    case OP_shr:
12403
0
        return JS_OVOP_SHR;
12404
0
    case OP_eq:
12405
0
    case OP_neq:
12406
0
        return JS_OVOP_EQ;
12407
0
    case OP_lt:
12408
0
    case OP_lte:
12409
0
    case OP_gt:
12410
0
    case OP_gte:
12411
0
        return JS_OVOP_LESS;
12412
0
    case OP_plus:
12413
0
        return JS_OVOP_POS;
12414
0
    case OP_neg:
12415
0
        return JS_OVOP_NEG;
12416
0
    case OP_inc:
12417
0
        return JS_OVOP_INC;
12418
0
    case OP_dec:
12419
0
        return JS_OVOP_DEC;
12420
0
    default:
12421
0
        abort();
12422
0
    }
12423
0
}
12424
12425
/* return NULL if not present */
12426
static JSObject *find_binary_op(JSBinaryOperatorDef *def,
12427
                                uint32_t operator_index,
12428
                                JSOverloadableOperatorEnum op)
12429
0
{
12430
0
    JSBinaryOperatorDefEntry *ent;
12431
0
    int i;
12432
0
    for(i = 0; i < def->count; i++) {
12433
0
        ent = &def->tab[i];
12434
0
        if (ent->operator_index == operator_index)
12435
0
            return ent->ops[op];
12436
0
    }
12437
0
    return NULL;
12438
0
}
12439
12440
/* return -1 if exception, 0 if no operator overloading, 1 if
12441
   overloaded operator called */
12442
static __exception int js_call_binary_op_fallback(JSContext *ctx,
12443
                                                  JSValue *pret,
12444
                                                  JSValueConst op1,
12445
                                                  JSValueConst op2,
12446
                                                  OPCodeEnum op,
12447
                                                  BOOL is_numeric,
12448
                                                  int hint)
12449
355k
{
12450
355k
    JSValue opset1_obj, opset2_obj, method, ret, new_op1, new_op2;
12451
355k
    JSOperatorSetData *opset1, *opset2;
12452
355k
    JSOverloadableOperatorEnum ovop;
12453
355k
    JSObject *p;
12454
355k
    JSValueConst args[2];
12455
    
12456
355k
    if (!ctx->allow_operator_overloading)
12457
355k
        return 0;
12458
    
12459
0
    opset2_obj = JS_UNDEFINED;
12460
0
    opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
12461
0
    if (JS_IsException(opset1_obj))
12462
0
        goto exception;
12463
0
    if (JS_IsUndefined(opset1_obj))
12464
0
        return 0;
12465
0
    opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
12466
0
    if (!opset1)
12467
0
        goto exception;
12468
12469
0
    opset2_obj = JS_GetProperty(ctx, op2, JS_ATOM_Symbol_operatorSet);
12470
0
    if (JS_IsException(opset2_obj))
12471
0
        goto exception;
12472
0
    if (JS_IsUndefined(opset2_obj)) {
12473
0
        JS_FreeValue(ctx, opset1_obj);
12474
0
        return 0;
12475
0
    }
12476
0
    opset2 = JS_GetOpaque2(ctx, opset2_obj, JS_CLASS_OPERATOR_SET);
12477
0
    if (!opset2)
12478
0
        goto exception;
12479
12480
0
    if (opset1->is_primitive && opset2->is_primitive) {
12481
0
        JS_FreeValue(ctx, opset1_obj);
12482
0
        JS_FreeValue(ctx, opset2_obj);
12483
0
        return 0;
12484
0
    }
12485
12486
0
    ovop = get_ovop_from_opcode(op);
12487
    
12488
0
    if (opset1->operator_counter == opset2->operator_counter) {
12489
0
        p = opset1->self_ops[ovop];
12490
0
    } else if (opset1->operator_counter > opset2->operator_counter) {
12491
0
        p = find_binary_op(&opset1->left, opset2->operator_counter, ovop);
12492
0
    } else {
12493
0
        p = find_binary_op(&opset2->right, opset1->operator_counter, ovop);
12494
0
    }
12495
0
    if (!p) {
12496
0
        JS_ThrowTypeError(ctx, "operator %s: no function defined",
12497
0
                          js_overloadable_operator_names[ovop]);
12498
0
        goto exception;
12499
0
    }
12500
12501
0
    if (opset1->is_primitive) {
12502
0
        if (is_numeric) {
12503
0
            new_op1 = JS_ToNumeric(ctx, op1);
12504
0
        } else {
12505
0
            new_op1 = JS_ToPrimitive(ctx, op1, hint);
12506
0
        }
12507
0
        if (JS_IsException(new_op1))
12508
0
            goto exception;
12509
0
    } else {
12510
0
        new_op1 = JS_DupValue(ctx, op1);
12511
0
    }
12512
    
12513
0
    if (opset2->is_primitive) {
12514
0
        if (is_numeric) {
12515
0
            new_op2 = JS_ToNumeric(ctx, op2);
12516
0
        } else {
12517
0
            new_op2 = JS_ToPrimitive(ctx, op2, hint);
12518
0
        }
12519
0
        if (JS_IsException(new_op2)) {
12520
0
            JS_FreeValue(ctx, new_op1);
12521
0
            goto exception;
12522
0
        }
12523
0
    } else {
12524
0
        new_op2 = JS_DupValue(ctx, op2);
12525
0
    }
12526
12527
    /* XXX: could apply JS_ToPrimitive() if primitive type so that the
12528
       operator function does not get a value object */
12529
    
12530
0
    method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12531
0
    if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) {
12532
0
        args[0] = new_op2;
12533
0
        args[1] = new_op1;
12534
0
    } else {
12535
0
        args[0] = new_op1;
12536
0
        args[1] = new_op2;
12537
0
    }
12538
0
    ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
12539
0
    JS_FreeValue(ctx, new_op1);
12540
0
    JS_FreeValue(ctx, new_op2);
12541
0
    if (JS_IsException(ret))
12542
0
        goto exception;
12543
0
    if (ovop == JS_OVOP_EQ) {
12544
0
        BOOL res = JS_ToBoolFree(ctx, ret);
12545
0
        if (op == OP_neq)
12546
0
            res ^= 1;
12547
0
        ret = JS_NewBool(ctx, res);
12548
0
    } else if (ovop == JS_OVOP_LESS) {
12549
0
        if (JS_IsUndefined(ret)) {
12550
0
            ret = JS_FALSE;
12551
0
        } else {
12552
0
            BOOL res = JS_ToBoolFree(ctx, ret);
12553
0
            if (op == OP_lte || op == OP_gte)
12554
0
                res ^= 1;
12555
0
            ret = JS_NewBool(ctx, res);
12556
0
        }
12557
0
    }
12558
0
    JS_FreeValue(ctx, opset1_obj);
12559
0
    JS_FreeValue(ctx, opset2_obj);
12560
0
    *pret = ret;
12561
0
    return 1;
12562
0
 exception:
12563
0
    JS_FreeValue(ctx, opset1_obj);
12564
0
    JS_FreeValue(ctx, opset2_obj);
12565
0
    *pret = JS_UNDEFINED;
12566
0
    return -1;
12567
0
}
12568
12569
/* try to call the operation on the operatorSet field of 'obj'. Only
12570
   used for "/" and "**" on the BigInt prototype in math mode */
12571
static __exception int js_call_binary_op_simple(JSContext *ctx,
12572
                                                JSValue *pret,
12573
                                                JSValueConst obj,
12574
                                                JSValueConst op1,
12575
                                                JSValueConst op2,
12576
                                                OPCodeEnum op)
12577
0
{
12578
0
    JSValue opset1_obj, method, ret, new_op1, new_op2;
12579
0
    JSOperatorSetData *opset1;
12580
0
    JSOverloadableOperatorEnum ovop;
12581
0
    JSObject *p;
12582
0
    JSValueConst args[2];
12583
12584
0
    opset1_obj = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
12585
0
    if (JS_IsException(opset1_obj))
12586
0
        goto exception;
12587
0
    if (JS_IsUndefined(opset1_obj))
12588
0
        return 0;
12589
0
    opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
12590
0
    if (!opset1)
12591
0
        goto exception;
12592
0
    ovop = get_ovop_from_opcode(op);
12593
12594
0
    p = opset1->self_ops[ovop];
12595
0
    if (!p) {
12596
0
        JS_FreeValue(ctx, opset1_obj);
12597
0
        return 0;
12598
0
    }
12599
12600
0
    new_op1 = JS_ToNumeric(ctx, op1);
12601
0
    if (JS_IsException(new_op1))
12602
0
        goto exception;
12603
0
    new_op2 = JS_ToNumeric(ctx, op2);
12604
0
    if (JS_IsException(new_op2)) {
12605
0
        JS_FreeValue(ctx, new_op1);
12606
0
        goto exception;
12607
0
    }
12608
12609
0
    method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12610
0
    args[0] = new_op1;
12611
0
    args[1] = new_op2;
12612
0
    ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
12613
0
    JS_FreeValue(ctx, new_op1);
12614
0
    JS_FreeValue(ctx, new_op2);
12615
0
    if (JS_IsException(ret))
12616
0
        goto exception;
12617
0
    JS_FreeValue(ctx, opset1_obj);
12618
0
    *pret = ret;
12619
0
    return 1;
12620
0
 exception:
12621
0
    JS_FreeValue(ctx, opset1_obj);
12622
0
    *pret = JS_UNDEFINED;
12623
0
    return -1;
12624
0
}
12625
12626
/* return -1 if exception, 0 if no operator overloading, 1 if
12627
   overloaded operator called */
12628
static __exception int js_call_unary_op_fallback(JSContext *ctx,
12629
                                                 JSValue *pret,
12630
                                                 JSValueConst op1,
12631
                                                 OPCodeEnum op)
12632
173k
{
12633
173k
    JSValue opset1_obj, method, ret;
12634
173k
    JSOperatorSetData *opset1;
12635
173k
    JSOverloadableOperatorEnum ovop;
12636
173k
    JSObject *p;
12637
12638
173k
    if (!ctx->allow_operator_overloading)
12639
173k
        return 0;
12640
    
12641
0
    opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
12642
0
    if (JS_IsException(opset1_obj))
12643
0
        goto exception;
12644
0
    if (JS_IsUndefined(opset1_obj))
12645
0
        return 0;
12646
0
    opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
12647
0
    if (!opset1)
12648
0
        goto exception;
12649
0
    if (opset1->is_primitive) {
12650
0
        JS_FreeValue(ctx, opset1_obj);
12651
0
        return 0;
12652
0
    }
12653
12654
0
    ovop = get_ovop_from_opcode(op);
12655
12656
0
    p = opset1->self_ops[ovop];
12657
0
    if (!p) {
12658
0
        JS_ThrowTypeError(ctx, "no overloaded operator %s",
12659
0
                          js_overloadable_operator_names[ovop]);
12660
0
        goto exception;
12661
0
    }
12662
0
    method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12663
0
    ret = JS_CallFree(ctx, method, JS_UNDEFINED, 1, &op1);
12664
0
    if (JS_IsException(ret))
12665
0
        goto exception;
12666
0
    JS_FreeValue(ctx, opset1_obj);
12667
0
    *pret = ret;
12668
0
    return 1;
12669
0
 exception:
12670
0
    JS_FreeValue(ctx, opset1_obj);
12671
0
    *pret = JS_UNDEFINED;
12672
0
    return -1;
12673
0
}
12674
12675
static JSValue throw_bf_exception(JSContext *ctx, int status)
12676
2
{
12677
2
    const char *str;
12678
2
    if (status & BF_ST_MEM_ERROR)
12679
2
        return JS_ThrowOutOfMemory(ctx);
12680
0
    if (status & BF_ST_DIVIDE_ZERO) {
12681
0
        str = "division by zero";
12682
0
    } else if (status & BF_ST_INVALID_OP) {
12683
0
        str = "invalid operation";
12684
0
    } else {
12685
0
        str = "integer overflow";
12686
0
    }
12687
0
    return JS_ThrowRangeError(ctx, "%s", str);
12688
2
}
12689
12690
static int js_unary_arith_bigint(JSContext *ctx,
12691
                                 JSValue *pres, OPCodeEnum op, JSValue op1)
12692
447
{
12693
447
    bf_t a_s, *r, *a;
12694
447
    int ret, v;
12695
447
    JSValue res;
12696
    
12697
447
    if (op == OP_plus && !is_math_mode(ctx)) {
12698
0
        JS_ThrowTypeError(ctx, "bigint argument with unary +");
12699
0
        JS_FreeValue(ctx, op1);
12700
0
        return -1;
12701
0
    }
12702
447
    res = JS_NewBigInt(ctx);
12703
447
    if (JS_IsException(res)) {
12704
0
        JS_FreeValue(ctx, op1);
12705
0
        return -1;
12706
0
    }
12707
447
    r = JS_GetBigInt(res);
12708
447
    a = JS_ToBigInt(ctx, &a_s, op1);
12709
447
    ret = 0;
12710
447
    switch(op) {
12711
0
    case OP_inc:
12712
0
    case OP_dec:
12713
0
        v = 2 * (op - OP_dec) - 1;
12714
0
        ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
12715
0
        break;
12716
0
    case OP_plus:
12717
0
        ret = bf_set(r, a);
12718
0
        break;
12719
35
    case OP_neg:
12720
35
        ret = bf_set(r, a);
12721
35
        bf_neg(r);
12722
35
        break;
12723
412
    case OP_not:
12724
412
        ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ);
12725
412
        bf_neg(r);
12726
412
        break;
12727
0
    default:
12728
0
        abort();
12729
447
    }
12730
447
    JS_FreeBigInt(ctx, a, &a_s);
12731
447
    JS_FreeValue(ctx, op1);
12732
447
    if (unlikely(ret)) {
12733
0
        JS_FreeValue(ctx, res);
12734
0
        throw_bf_exception(ctx, ret);
12735
0
        return -1;
12736
0
    }
12737
447
    res = JS_CompactBigInt(ctx, res);
12738
447
    *pres = res;
12739
447
    return 0;
12740
447
}
12741
12742
static int js_unary_arith_bigfloat(JSContext *ctx,
12743
                                   JSValue *pres, OPCodeEnum op, JSValue op1)
12744
0
{
12745
0
    bf_t a_s, *r, *a;
12746
0
    int ret, v;
12747
0
    JSValue res;
12748
    
12749
0
    if (op == OP_plus && !is_math_mode(ctx)) {
12750
0
        JS_ThrowTypeError(ctx, "bigfloat argument with unary +");
12751
0
        JS_FreeValue(ctx, op1);
12752
0
        return -1;
12753
0
    }
12754
12755
0
    res = JS_NewBigFloat(ctx);
12756
0
    if (JS_IsException(res)) {
12757
0
        JS_FreeValue(ctx, op1);
12758
0
        return -1;
12759
0
    }
12760
0
    r = JS_GetBigFloat(res);
12761
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
12762
0
    ret = 0;
12763
0
    switch(op) {
12764
0
    case OP_inc:
12765
0
    case OP_dec:
12766
0
        v = 2 * (op - OP_dec) - 1;
12767
0
        ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags);
12768
0
        break;
12769
0
    case OP_plus:
12770
0
        ret = bf_set(r, a);
12771
0
        break;
12772
0
    case OP_neg:
12773
0
        ret = bf_set(r, a);
12774
0
        bf_neg(r);
12775
0
        break;
12776
0
    default:
12777
0
        abort();
12778
0
    }
12779
0
    if (a == &a_s)
12780
0
        bf_delete(a);
12781
0
    JS_FreeValue(ctx, op1);
12782
0
    if (unlikely(ret & BF_ST_MEM_ERROR)) {
12783
0
        JS_FreeValue(ctx, res);
12784
0
        throw_bf_exception(ctx, ret);
12785
0
        return -1;
12786
0
    }
12787
0
    *pres = res;
12788
0
    return 0;
12789
0
}
12790
12791
static int js_unary_arith_bigdecimal(JSContext *ctx,
12792
                                     JSValue *pres, OPCodeEnum op, JSValue op1)
12793
0
{
12794
0
    bfdec_t *r, *a;
12795
0
    int ret, v;
12796
0
    JSValue res;
12797
    
12798
0
    if (op == OP_plus && !is_math_mode(ctx)) {
12799
0
        JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");
12800
0
        JS_FreeValue(ctx, op1);
12801
0
        return -1;
12802
0
    }
12803
12804
0
    res = JS_NewBigDecimal(ctx);
12805
0
    if (JS_IsException(res)) {
12806
0
        JS_FreeValue(ctx, op1);
12807
0
        return -1;
12808
0
    }
12809
0
    r = JS_GetBigDecimal(res);
12810
0
    a = JS_ToBigDecimal(ctx, op1);
12811
0
    ret = 0;
12812
0
    switch(op) {
12813
0
    case OP_inc:
12814
0
    case OP_dec:
12815
0
        v = 2 * (op - OP_dec) - 1;
12816
0
        ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
12817
0
        break;
12818
0
    case OP_plus:
12819
0
        ret = bfdec_set(r, a);
12820
0
        break;
12821
0
    case OP_neg:
12822
0
        ret = bfdec_set(r, a);
12823
0
        bfdec_neg(r);
12824
0
        break;
12825
0
    default:
12826
0
        abort();
12827
0
    }
12828
0
    JS_FreeValue(ctx, op1);
12829
0
    if (unlikely(ret)) {
12830
0
        JS_FreeValue(ctx, res);
12831
0
        throw_bf_exception(ctx, ret);
12832
0
        return -1;
12833
0
    }
12834
0
    *pres = res;
12835
0
    return 0;
12836
0
}
12837
12838
static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
12839
                                                     JSValue *sp,
12840
                                                     OPCodeEnum op)
12841
215k
{
12842
215k
    JSValue op1, val;
12843
215k
    int v, ret;
12844
215k
    uint32_t tag;
12845
12846
215k
    op1 = sp[-1];
12847
    /* fast path for float64 */
12848
215k
    if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
12849
18.6k
        goto handle_float64;
12850
196k
    if (JS_IsObject(op1)) {
12851
166k
        ret = js_call_unary_op_fallback(ctx, &val, op1, op);
12852
166k
        if (ret < 0)
12853
0
            return -1;
12854
166k
        if (ret) {
12855
0
            JS_FreeValue(ctx, op1);
12856
0
            sp[-1] = val;
12857
0
            return 0;
12858
0
        }
12859
166k
    }
12860
12861
196k
    op1 = JS_ToNumericFree(ctx, op1);
12862
196k
    if (JS_IsException(op1))
12863
0
        goto exception;
12864
196k
    tag = JS_VALUE_GET_TAG(op1);
12865
196k
    switch(tag) {
12866
25.2k
    case JS_TAG_INT:
12867
25.2k
        {
12868
25.2k
            int64_t v64;
12869
25.2k
            v64 = JS_VALUE_GET_INT(op1);
12870
25.2k
            switch(op) {
12871
5
            case OP_inc:
12872
16
            case OP_dec:
12873
16
                v = 2 * (op - OP_dec) - 1;
12874
16
                v64 += v;
12875
16
                break;
12876
24.7k
            case OP_plus:
12877
24.7k
                break;
12878
527
            case OP_neg:
12879
527
                if (v64 == 0) {
12880
524
                    sp[-1] = __JS_NewFloat64(ctx, -0.0);
12881
524
                    return 0;
12882
524
                } else {
12883
3
                    v64 = -v64;
12884
3
                }
12885
3
                break;
12886
3
            default:
12887
0
                abort();
12888
25.2k
            }
12889
24.7k
            sp[-1] = JS_NewInt64(ctx, v64);
12890
24.7k
        }
12891
0
        break;
12892
35
    case JS_TAG_BIG_INT:
12893
35
    handle_bigint:
12894
35
        if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1))
12895
0
            goto exception;
12896
35
        break;
12897
35
    case JS_TAG_BIG_FLOAT:
12898
0
        if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1))
12899
0
            goto exception;
12900
0
        break;
12901
0
    case JS_TAG_BIG_DECIMAL:
12902
0
        if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1))
12903
0
            goto exception;
12904
0
        break;
12905
171k
    default:
12906
189k
    handle_float64:
12907
189k
        {
12908
189k
            double d;
12909
189k
            if (is_math_mode(ctx))
12910
0
                goto handle_bigint;
12911
189k
            d = JS_VALUE_GET_FLOAT64(op1);
12912
189k
            switch(op) {
12913
102
            case OP_inc:
12914
18.7k
            case OP_dec:
12915
18.7k
                v = 2 * (op - OP_dec) - 1;
12916
18.7k
                d += v;
12917
18.7k
                break;
12918
169k
            case OP_plus:
12919
169k
                break;
12920
1.86k
            case OP_neg:
12921
1.86k
                d = -d;
12922
1.86k
                break;
12923
0
            default:
12924
0
                abort();
12925
189k
            }
12926
189k
            sp[-1] = __JS_NewFloat64(ctx, d);
12927
189k
        }
12928
0
        break;
12929
196k
    }
12930
214k
    return 0;
12931
0
 exception:
12932
0
    sp[-1] = JS_UNDEFINED;
12933
0
    return -1;
12934
196k
}
12935
12936
static __exception int js_post_inc_slow(JSContext *ctx,
12937
                                        JSValue *sp, OPCodeEnum op)
12938
18.6k
{
12939
18.6k
    JSValue op1;
12940
12941
    /* XXX: allow custom operators */
12942
18.6k
    op1 = sp[-1];
12943
18.6k
    op1 = JS_ToNumericFree(ctx, op1);
12944
18.6k
    if (JS_IsException(op1)) {
12945
1
        sp[-1] = JS_UNDEFINED;
12946
1
        return -1;
12947
1
    }
12948
18.6k
    sp[-1] = op1;
12949
18.6k
    sp[0] = JS_DupValue(ctx, op1);
12950
18.6k
    return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec);
12951
18.6k
}
12952
12953
static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
12954
15.3k
{
12955
15.3k
    JSValue op1, val;
12956
15.3k
    int ret;
12957
    
12958
15.3k
    op1 = sp[-1];
12959
15.3k
    if (JS_IsObject(op1)) {
12960
6.80k
        ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not);
12961
6.80k
        if (ret < 0)
12962
0
            return -1;
12963
6.80k
        if (ret) {
12964
0
            JS_FreeValue(ctx, op1);
12965
0
            sp[-1] = val;
12966
0
            return 0;
12967
0
        }
12968
6.80k
    }
12969
12970
15.3k
    op1 = JS_ToNumericFree(ctx, op1);
12971
15.3k
    if (JS_IsException(op1))
12972
3
        goto exception;
12973
15.3k
    if (is_math_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
12974
412
        if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1))
12975
0
            goto exception;
12976
14.9k
    } else {
12977
14.9k
        int32_t v1;
12978
14.9k
        if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
12979
0
            goto exception;
12980
14.9k
        sp[-1] = JS_NewInt32(ctx, ~v1);
12981
14.9k
    }
12982
15.3k
    return 0;
12983
3
 exception:
12984
3
    sp[-1] = JS_UNDEFINED;
12985
3
    return -1;
12986
15.3k
}
12987
12988
static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
12989
                                    JSValue *pres, JSValue op1, JSValue op2)
12990
0
{
12991
0
    bf_t a_s, b_s, *r, *a, *b;
12992
0
    int ret;
12993
0
    JSValue res;
12994
    
12995
0
    res = JS_NewBigFloat(ctx);
12996
0
    if (JS_IsException(res)) {
12997
0
        JS_FreeValue(ctx, op1);
12998
0
        JS_FreeValue(ctx, op2);
12999
0
        return -1;
13000
0
    }
13001
0
    r = JS_GetBigFloat(res);
13002
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
13003
0
    b = JS_ToBigFloat(ctx, &b_s, op2);
13004
0
    bf_init(ctx->bf_ctx, r);
13005
0
    switch(op) {
13006
0
    case OP_add:
13007
0
        ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
13008
0
        break;
13009
0
    case OP_sub:
13010
0
        ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
13011
0
        break;
13012
0
    case OP_mul:
13013
0
        ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
13014
0
        break;
13015
0
    case OP_div:
13016
0
        ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
13017
0
        break;
13018
0
    case OP_math_mod:
13019
        /* Euclidian remainder */
13020
0
        ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
13021
0
                     BF_DIVREM_EUCLIDIAN);
13022
0
        break;
13023
0
    case OP_mod:
13024
0
        ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
13025
0
                     BF_RNDZ);
13026
0
        break;
13027
0
    case OP_pow:
13028
0
        ret = bf_pow(r, a, b, ctx->fp_env.prec,
13029
0
                     ctx->fp_env.flags | BF_POW_JS_QUIRKS);
13030
0
        break;
13031
0
    default:
13032
0
        abort();
13033
0
    }
13034
0
    if (a == &a_s)
13035
0
        bf_delete(a);
13036
0
    if (b == &b_s)
13037
0
        bf_delete(b);
13038
0
    JS_FreeValue(ctx, op1);
13039
0
    JS_FreeValue(ctx, op2);
13040
0
    if (unlikely(ret & BF_ST_MEM_ERROR)) {
13041
0
        JS_FreeValue(ctx, res);
13042
0
        throw_bf_exception(ctx, ret);
13043
0
        return -1;
13044
0
    }
13045
0
    *pres = res;
13046
0
    return 0;
13047
0
}
13048
13049
static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
13050
                                  JSValue *pres, JSValue op1, JSValue op2)
13051
278
{
13052
278
    bf_t a_s, b_s, *r, *a, *b;
13053
278
    int ret;
13054
278
    JSValue res;
13055
    
13056
278
    res = JS_NewBigInt(ctx);
13057
278
    if (JS_IsException(res))
13058
0
        goto fail;
13059
278
    a = JS_ToBigInt(ctx, &a_s, op1);
13060
278
    if (!a)
13061
2
        goto fail;
13062
276
    b = JS_ToBigInt(ctx, &b_s, op2);
13063
276
    if (!b) {
13064
4
        JS_FreeBigInt(ctx, a, &a_s);
13065
4
        goto fail;
13066
4
    }
13067
272
    r = JS_GetBigInt(res);
13068
272
    ret = 0;
13069
272
    switch(op) {
13070
0
    case OP_add:
13071
0
        ret = bf_add(r, a, b, BF_PREC_INF, BF_RNDZ);
13072
0
        break;
13073
35
    case OP_sub:
13074
35
        ret = bf_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
13075
35
        break;
13076
0
    case OP_mul:
13077
0
        ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
13078
0
        break;
13079
149
    case OP_div:
13080
149
        if (!is_math_mode(ctx)) {
13081
149
            bf_t rem_s, *rem = &rem_s;
13082
149
            bf_init(ctx->bf_ctx, rem);
13083
149
            ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ,
13084
149
                            BF_RNDZ);
13085
149
            bf_delete(rem);
13086
149
        } else {
13087
0
            goto math_mode_div_pow;
13088
0
        }
13089
149
        break;
13090
149
    case OP_math_mod:
13091
        /* Euclidian remainder */
13092
0
        ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
13093
0
                     BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP;
13094
0
        break;
13095
6
    case OP_mod:
13096
6
        ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
13097
6
                     BF_RNDZ) & BF_ST_INVALID_OP;
13098
6
        break;
13099
64
    case OP_pow:
13100
64
        if (b->sign) {
13101
0
            if (!is_math_mode(ctx)) {
13102
0
                ret = BF_ST_INVALID_OP;
13103
0
            } else {
13104
0
            math_mode_div_pow:
13105
0
                JS_FreeValue(ctx, res);
13106
0
                ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op);
13107
0
                if (ret != 0) {
13108
0
                    JS_FreeBigInt(ctx, a, &a_s);
13109
0
                    JS_FreeBigInt(ctx, b, &b_s);
13110
0
                    JS_FreeValue(ctx, op1);
13111
0
                    JS_FreeValue(ctx, op2);
13112
0
                    if (ret < 0) {
13113
0
                        return -1;
13114
0
                    } else {
13115
0
                        *pres = res;
13116
0
                        return 0;
13117
0
                    }
13118
0
                }
13119
                /* if no BigInt power operator defined, return a
13120
                   bigfloat */
13121
0
                res = JS_NewBigFloat(ctx);
13122
0
                if (JS_IsException(res)) {
13123
0
                    JS_FreeBigInt(ctx, a, &a_s);
13124
0
                    JS_FreeBigInt(ctx, b, &b_s);
13125
0
                    goto fail;
13126
0
                }
13127
0
                r = JS_GetBigFloat(res);
13128
0
                if (op == OP_div) {
13129
0
                    ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags) & BF_ST_MEM_ERROR;
13130
0
                } else {
13131
0
                    ret = bf_pow(r, a, b, ctx->fp_env.prec,
13132
0
                                 ctx->fp_env.flags | BF_POW_JS_QUIRKS) & BF_ST_MEM_ERROR;
13133
0
                }
13134
0
                JS_FreeBigInt(ctx, a, &a_s);
13135
0
                JS_FreeBigInt(ctx, b, &b_s);
13136
0
                JS_FreeValue(ctx, op1);
13137
0
                JS_FreeValue(ctx, op2);
13138
0
                if (unlikely(ret)) {
13139
0
                    JS_FreeValue(ctx, res);
13140
0
                    throw_bf_exception(ctx, ret);
13141
0
                    return -1;
13142
0
                }
13143
0
                *pres = res;
13144
0
                return 0;
13145
0
            }
13146
64
        } else {
13147
64
            ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS);
13148
64
        }
13149
64
        break;
13150
13151
        /* logical operations */
13152
64
    case OP_shl:
13153
0
    case OP_sar:
13154
0
        {
13155
0
            slimb_t v2;
13156
#if LIMB_BITS == 32
13157
            bf_get_int32(&v2, b, 0);
13158
            if (v2 == INT32_MIN)
13159
                v2 = INT32_MIN + 1;
13160
#else
13161
0
            bf_get_int64(&v2, b, 0);
13162
0
            if (v2 == INT64_MIN)
13163
0
                v2 = INT64_MIN + 1;
13164
0
#endif
13165
0
            if (op == OP_sar)
13166
0
                v2 = -v2;
13167
0
            ret = bf_set(r, a);
13168
0
            ret |= bf_mul_2exp(r, v2, BF_PREC_INF, BF_RNDZ);
13169
0
            if (v2 < 0) {
13170
0
                ret |= bf_rint(r, BF_RNDD) & (BF_ST_OVERFLOW | BF_ST_MEM_ERROR);
13171
0
            }
13172
0
        }
13173
0
        break;
13174
0
    case OP_and:
13175
0
        ret = bf_logic_and(r, a, b);
13176
0
        break;
13177
18
    case OP_or:
13178
18
        ret = bf_logic_or(r, a, b);
13179
18
        break;
13180
0
    case OP_xor:
13181
0
        ret = bf_logic_xor(r, a, b);
13182
0
        break;
13183
0
    default:
13184
0
        abort();
13185
272
    }
13186
272
    JS_FreeBigInt(ctx, a, &a_s);
13187
272
    JS_FreeBigInt(ctx, b, &b_s);
13188
272
    JS_FreeValue(ctx, op1);
13189
272
    JS_FreeValue(ctx, op2);
13190
272
    if (unlikely(ret)) {
13191
2
        JS_FreeValue(ctx, res);
13192
2
        throw_bf_exception(ctx, ret);
13193
2
        return -1;
13194
2
    }
13195
270
    *pres = JS_CompactBigInt(ctx, res);
13196
270
    return 0;
13197
6
 fail:
13198
6
    JS_FreeValue(ctx, res);
13199
6
    JS_FreeValue(ctx, op1);
13200
6
    JS_FreeValue(ctx, op2);
13201
6
    return -1;
13202
272
}
13203
13204
/* b must be a positive integer */
13205
static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b)
13206
0
{
13207
0
    bfdec_t b1;
13208
0
    int32_t b2;
13209
0
    int ret;
13210
13211
0
    bfdec_init(b->ctx, &b1);
13212
0
    ret = bfdec_set(&b1, b);
13213
0
    if (ret) {
13214
0
        bfdec_delete(&b1);
13215
0
        return ret;
13216
0
    }
13217
0
    ret = bfdec_rint(&b1, BF_RNDZ);
13218
0
    if (ret) {
13219
0
        bfdec_delete(&b1);
13220
0
        return BF_ST_INVALID_OP; /* must be an integer */
13221
0
    }
13222
0
    ret = bfdec_get_int32(&b2, &b1);
13223
0
    bfdec_delete(&b1);
13224
0
    if (ret)
13225
0
        return ret; /* overflow */
13226
0
    if (b2 < 0)
13227
0
        return BF_ST_INVALID_OP; /* must be positive */
13228
0
    return bfdec_pow_ui(r, a, b2);
13229
0
}
13230
13231
static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
13232
                                      JSValue *pres, JSValue op1, JSValue op2)
13233
0
{
13234
0
    bfdec_t *r, *a, *b;
13235
0
    int ret;
13236
0
    JSValue res;
13237
13238
0
    res = JS_NewBigDecimal(ctx);
13239
0
    if (JS_IsException(res))
13240
0
        goto fail;
13241
0
    r = JS_GetBigDecimal(res);
13242
    
13243
0
    a = JS_ToBigDecimal(ctx, op1);
13244
0
    if (!a)
13245
0
        goto fail;
13246
0
    b = JS_ToBigDecimal(ctx, op2);
13247
0
    if (!b)
13248
0
        goto fail;
13249
0
    switch(op) {
13250
0
    case OP_add:
13251
0
        ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ);
13252
0
        break;
13253
0
    case OP_sub:
13254
0
        ret = bfdec_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
13255
0
        break;
13256
0
    case OP_mul:
13257
0
        ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
13258
0
        break;
13259
0
    case OP_div:
13260
0
        ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ);
13261
0
        break;
13262
0
    case OP_math_mod:
13263
        /* Euclidian remainder */
13264
0
        ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN);
13265
0
        break;
13266
0
    case OP_mod:
13267
0
        ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ);
13268
0
        break;
13269
0
    case OP_pow:
13270
0
        ret = js_bfdec_pow(r, a, b);
13271
0
        break;
13272
0
    default:
13273
0
        abort();
13274
0
    }
13275
0
    JS_FreeValue(ctx, op1);
13276
0
    JS_FreeValue(ctx, op2);
13277
0
    if (unlikely(ret)) {
13278
0
        JS_FreeValue(ctx, res);
13279
0
        throw_bf_exception(ctx, ret);
13280
0
        return -1;
13281
0
    }
13282
0
    *pres = res;
13283
0
    return 0;
13284
0
 fail:
13285
0
    JS_FreeValue(ctx, res);
13286
0
    JS_FreeValue(ctx, op1);
13287
0
    JS_FreeValue(ctx, op2);
13288
0
    return -1;
13289
0
}
13290
13291
static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
13292
                                                      OPCodeEnum op)
13293
323k
{
13294
323k
    JSValue op1, op2, res;
13295
323k
    uint32_t tag1, tag2;
13296
323k
    int ret;
13297
323k
    double d1, d2;
13298
13299
323k
    op1 = sp[-2];
13300
323k
    op2 = sp[-1];
13301
323k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13302
323k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13303
    /* fast path for float operations */
13304
323k
    if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
13305
12.9k
        d1 = JS_VALUE_GET_FLOAT64(op1);
13306
12.9k
        d2 = JS_VALUE_GET_FLOAT64(op2);
13307
12.9k
        goto handle_float64;
13308
12.9k
    }
13309
13310
    /* try to call an overloaded operator */
13311
310k
    if ((tag1 == JS_TAG_OBJECT &&
13312
310k
         (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
13313
310k
        (tag2 == JS_TAG_OBJECT &&
13314
262k
         (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
13315
72.2k
        ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
13316
72.2k
        if (ret != 0) {
13317
0
            JS_FreeValue(ctx, op1);
13318
0
            JS_FreeValue(ctx, op2);
13319
0
            if (ret < 0) {
13320
0
                goto exception;
13321
0
            } else {
13322
0
                sp[-2] = res;
13323
0
                return 0;
13324
0
            }
13325
0
        }
13326
72.2k
    }
13327
13328
310k
    op1 = JS_ToNumericFree(ctx, op1);
13329
310k
    if (JS_IsException(op1)) {
13330
2
        JS_FreeValue(ctx, op2);
13331
2
        goto exception;
13332
2
    }
13333
310k
    op2 = JS_ToNumericFree(ctx, op2);
13334
310k
    if (JS_IsException(op2)) {
13335
2
        JS_FreeValue(ctx, op1);
13336
2
        goto exception;
13337
2
    }
13338
310k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13339
310k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13340
13341
310k
    if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
13342
17.7k
        int32_t v1, v2;
13343
17.7k
        int64_t v;
13344
17.7k
        v1 = JS_VALUE_GET_INT(op1);
13345
17.7k
        v2 = JS_VALUE_GET_INT(op2);
13346
17.7k
        switch(op) {
13347
8.99k
        case OP_sub:
13348
8.99k
            v = (int64_t)v1 - (int64_t)v2;
13349
8.99k
            break;
13350
4
        case OP_mul:
13351
4
            v = (int64_t)v1 * (int64_t)v2;
13352
4
            if (is_math_mode(ctx) &&
13353
4
                (v < -MAX_SAFE_INTEGER || v > MAX_SAFE_INTEGER))
13354
0
                goto handle_bigint;
13355
4
            if (v == 0 && (v1 | v2) < 0) {
13356
0
                sp[-2] = __JS_NewFloat64(ctx, -0.0);
13357
0
                return 0;
13358
0
            }
13359
4
            break;
13360
8.10k
        case OP_div:
13361
8.10k
            if (is_math_mode(ctx))
13362
0
                goto handle_bigint;
13363
8.10k
            sp[-2] = __JS_NewFloat64(ctx, (double)v1 / (double)v2);
13364
8.10k
            return 0;
13365
0
        case OP_math_mod:
13366
0
            if (unlikely(v2 == 0)) {
13367
0
                throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO);
13368
0
                goto exception;
13369
0
            }
13370
0
            v = (int64_t)v1 % (int64_t)v2;
13371
0
            if (v < 0) {
13372
0
                if (v2 < 0)
13373
0
                    v -= v2;
13374
0
                else
13375
0
                    v += v2;
13376
0
            }
13377
0
            break;
13378
633
        case OP_mod:
13379
633
            if (v1 < 0 || v2 <= 0) {
13380
538
                sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));
13381
538
                return 0;
13382
538
            } else {
13383
95
                v = (int64_t)v1 % (int64_t)v2;
13384
95
            }
13385
95
            break;
13386
95
        case OP_pow:
13387
0
            if (!is_math_mode(ctx)) {
13388
0
                sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));
13389
0
                return 0;
13390
0
            } else {
13391
0
                goto handle_bigint;
13392
0
            }
13393
0
            break;
13394
0
        default:
13395
0
            abort();
13396
17.7k
        }
13397
9.09k
        sp[-2] = JS_NewInt64(ctx, v);
13398
292k
    } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
13399
0
        if (ctx->rt->bigdecimal_ops.binary_arith(ctx, op, sp - 2, op1, op2))
13400
0
            goto exception;
13401
292k
    } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
13402
0
        if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2))
13403
0
            goto exception;
13404
292k
    } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
13405
260
    handle_bigint:
13406
260
        if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
13407
8
            goto exception;
13408
292k
    } else {
13409
292k
        double dr;
13410
        /* float64 result */
13411
292k
        if (JS_ToFloat64Free(ctx, &d1, op1)) {
13412
0
            JS_FreeValue(ctx, op2);
13413
0
            goto exception;
13414
0
        }
13415
292k
        if (JS_ToFloat64Free(ctx, &d2, op2))
13416
0
            goto exception;
13417
305k
    handle_float64:
13418
305k
        if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
13419
0
            goto handle_bigint;
13420
305k
        switch(op) {
13421
52.3k
        case OP_sub:
13422
52.3k
            dr = d1 - d2;
13423
52.3k
            break;
13424
206k
        case OP_mul:
13425
206k
            dr = d1 * d2;
13426
206k
            break;
13427
34.5k
        case OP_div:
13428
34.5k
            dr = d1 / d2;
13429
34.5k
            break;
13430
12.1k
        case OP_mod:
13431
12.1k
            dr = fmod(d1, d2);
13432
12.1k
            break;
13433
0
        case OP_math_mod:
13434
0
            d2 = fabs(d2);
13435
0
            dr = fmod(d1, d2);
13436
            /* XXX: loss of accuracy if dr < 0 */
13437
0
            if (dr < 0)
13438
0
                dr += d2;
13439
0
            break;
13440
1
        case OP_pow:
13441
1
            dr = js_pow(d1, d2);
13442
1
            break;
13443
0
        default:
13444
0
            abort();
13445
305k
        }
13446
305k
        sp[-2] = __JS_NewFloat64(ctx, dr);
13447
305k
    }
13448
314k
    return 0;
13449
12
 exception:
13450
12
    sp[-2] = JS_UNDEFINED;
13451
12
    sp[-1] = JS_UNDEFINED;
13452
12
    return -1;
13453
310k
}
13454
13455
static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
13456
475k
{
13457
475k
    JSValue op1, op2, res;
13458
475k
    uint32_t tag1, tag2;
13459
475k
    int ret;
13460
13461
475k
    op1 = sp[-2];
13462
475k
    op2 = sp[-1];
13463
13464
475k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13465
475k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13466
    /* fast path for float64 */
13467
475k
    if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
13468
0
        double d1, d2;
13469
0
        d1 = JS_VALUE_GET_FLOAT64(op1);
13470
0
        d2 = JS_VALUE_GET_FLOAT64(op2);
13471
0
        sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
13472
0
        return 0;
13473
0
    }
13474
13475
475k
    if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
13476
        /* try to call an overloaded operator */
13477
265k
        if ((tag1 == JS_TAG_OBJECT &&
13478
265k
             (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED &&
13479
163k
              tag2 != JS_TAG_STRING)) ||
13480
265k
            (tag2 == JS_TAG_OBJECT &&
13481
105k
             (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED &&
13482
263k
              tag1 != JS_TAG_STRING))) {
13483
263k
            ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add,
13484
263k
                                             FALSE, HINT_NONE);
13485
263k
            if (ret != 0) {
13486
0
                JS_FreeValue(ctx, op1);
13487
0
                JS_FreeValue(ctx, op2);
13488
0
                if (ret < 0) {
13489
0
                    goto exception;
13490
0
                } else {
13491
0
                    sp[-2] = res;
13492
0
                    return 0;
13493
0
                }
13494
0
            }
13495
263k
        }
13496
13497
265k
        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
13498
265k
        if (JS_IsException(op1)) {
13499
0
            JS_FreeValue(ctx, op2);
13500
0
            goto exception;
13501
0
        }
13502
13503
265k
        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
13504
265k
        if (JS_IsException(op2)) {
13505
0
            JS_FreeValue(ctx, op1);
13506
0
            goto exception;
13507
0
        }
13508
265k
        tag1 = JS_VALUE_GET_NORM_TAG(op1);
13509
265k
        tag2 = JS_VALUE_GET_NORM_TAG(op2);
13510
265k
    }
13511
13512
475k
    if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
13513
272k
        sp[-2] = JS_ConcatString(ctx, op1, op2);
13514
272k
        if (JS_IsException(sp[-2]))
13515
0
            goto exception;
13516
272k
        return 0;
13517
272k
    }
13518
13519
202k
    op1 = JS_ToNumericFree(ctx, op1);
13520
202k
    if (JS_IsException(op1)) {
13521
0
        JS_FreeValue(ctx, op2);
13522
0
        goto exception;
13523
0
    }
13524
202k
    op2 = JS_ToNumericFree(ctx, op2);
13525
202k
    if (JS_IsException(op2)) {
13526
0
        JS_FreeValue(ctx, op1);
13527
0
        goto exception;
13528
0
    }
13529
202k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13530
202k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13531
13532
202k
    if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
13533
192
        int32_t v1, v2;
13534
192
        int64_t v;
13535
192
        v1 = JS_VALUE_GET_INT(op1);
13536
192
        v2 = JS_VALUE_GET_INT(op2);
13537
192
        v = (int64_t)v1 + (int64_t)v2;
13538
192
        sp[-2] = JS_NewInt64(ctx, v);
13539
202k
    } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
13540
0
        if (ctx->rt->bigdecimal_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
13541
0
            goto exception;
13542
202k
    } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
13543
0
        if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
13544
0
            goto exception;
13545
202k
    } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
13546
0
    handle_bigint:
13547
0
        if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
13548
0
            goto exception;
13549
202k
    } else {
13550
202k
        double d1, d2;
13551
        /* float64 result */
13552
202k
        if (JS_ToFloat64Free(ctx, &d1, op1)) {
13553
0
            JS_FreeValue(ctx, op2);
13554
0
            goto exception;
13555
0
        }
13556
202k
        if (JS_ToFloat64Free(ctx, &d2, op2))
13557
0
            goto exception;
13558
202k
        if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
13559
0
            goto handle_bigint;
13560
202k
        sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
13561
202k
    }
13562
202k
    return 0;
13563
0
 exception:
13564
0
    sp[-2] = JS_UNDEFINED;
13565
0
    sp[-1] = JS_UNDEFINED;
13566
0
    return -1;
13567
202k
}
13568
13569
static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
13570
                                                      JSValue *sp,
13571
                                                      OPCodeEnum op)
13572
169k
{
13573
169k
    JSValue op1, op2, res;
13574
169k
    int ret;
13575
169k
    uint32_t tag1, tag2;
13576
169k
    uint32_t v1, v2, r;
13577
13578
169k
    op1 = sp[-2];
13579
169k
    op2 = sp[-1];
13580
169k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13581
169k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13582
13583
    /* try to call an overloaded operator */
13584
169k
    if ((tag1 == JS_TAG_OBJECT &&
13585
169k
         (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
13586
169k
        (tag2 == JS_TAG_OBJECT &&
13587
168k
         (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
13588
13.4k
        ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
13589
13.4k
        if (ret != 0) {
13590
0
            JS_FreeValue(ctx, op1);
13591
0
            JS_FreeValue(ctx, op2);
13592
0
            if (ret < 0) {
13593
0
                goto exception;
13594
0
            } else {
13595
0
                sp[-2] = res;
13596
0
                return 0;
13597
0
            }
13598
0
        }
13599
13.4k
    }
13600
13601
169k
    op1 = JS_ToNumericFree(ctx, op1);
13602
169k
    if (JS_IsException(op1)) {
13603
1
        JS_FreeValue(ctx, op2);
13604
1
        goto exception;
13605
1
    }
13606
169k
    op2 = JS_ToNumericFree(ctx, op2);
13607
169k
    if (JS_IsException(op2)) {
13608
0
        JS_FreeValue(ctx, op1);
13609
0
        goto exception;
13610
0
    }
13611
13612
169k
    if (is_math_mode(ctx))
13613
0
        goto bigint_op;
13614
13615
169k
    tag1 = JS_VALUE_GET_TAG(op1);
13616
169k
    tag2 = JS_VALUE_GET_TAG(op2);
13617
169k
    if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
13618
24
        if (tag1 != tag2) {
13619
6
            JS_FreeValue(ctx, op1);
13620
6
            JS_FreeValue(ctx, op2);
13621
6
            JS_ThrowTypeError(ctx, "both operands must be bigint");
13622
6
            goto exception;
13623
18
        } else {
13624
18
        bigint_op:
13625
18
            if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
13626
0
                goto exception;
13627
18
        }
13628
169k
    } else {
13629
169k
        if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
13630
0
            JS_FreeValue(ctx, op2);
13631
0
            goto exception;
13632
0
        }
13633
169k
        if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
13634
0
            goto exception;
13635
169k
        switch(op) {
13636
1
        case OP_shl:
13637
1
            r = v1 << (v2 & 0x1f);
13638
1
            break;
13639
17
        case OP_sar:
13640
17
            r = (int)v1 >> (v2 & 0x1f);
13641
17
            break;
13642
168k
        case OP_and:
13643
168k
            r = v1 & v2;
13644
168k
            break;
13645
7
        case OP_or:
13646
7
            r = v1 | v2;
13647
7
            break;
13648
569
        case OP_xor:
13649
569
            r = v1 ^ v2;
13650
569
            break;
13651
0
        default:
13652
0
            abort();
13653
169k
        }
13654
169k
        sp[-2] = JS_NewInt32(ctx, r);
13655
169k
    }
13656
169k
    return 0;
13657
7
 exception:
13658
7
    sp[-2] = JS_UNDEFINED;
13659
7
    sp[-1] = JS_UNDEFINED;
13660
7
    return -1;
13661
169k
}
13662
13663
/* Note: also used for bigint */
13664
static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op,
13665
                               JSValue op1, JSValue op2)
13666
994
{
13667
994
    bf_t a_s, b_s, *a, *b;
13668
994
    int res;
13669
    
13670
994
    a = JS_ToBigFloat(ctx, &a_s, op1);
13671
994
    if (!a) {
13672
0
        JS_FreeValue(ctx, op2);
13673
0
        return -1;
13674
0
    }
13675
994
    b = JS_ToBigFloat(ctx, &b_s, op2);
13676
994
    if (!b) {
13677
0
        if (a == &a_s)
13678
0
            bf_delete(a);
13679
0
        JS_FreeValue(ctx, op1);
13680
0
        return -1;
13681
0
    }
13682
994
    switch(op) {
13683
108
    case OP_lt:
13684
108
        res = bf_cmp_lt(a, b); /* if NaN return false */
13685
108
        break;
13686
0
    case OP_lte:
13687
0
        res = bf_cmp_le(a, b); /* if NaN return false */
13688
0
        break;
13689
878
    case OP_gt:
13690
878
        res = bf_cmp_lt(b, a); /* if NaN return false */
13691
878
        break;
13692
7
    case OP_gte:
13693
7
        res = bf_cmp_le(b, a); /* if NaN return false */
13694
7
        break;
13695
1
    case OP_eq:
13696
1
        res = bf_cmp_eq(a, b); /* if NaN return false */
13697
1
        break;
13698
0
    default:
13699
0
        abort();
13700
994
    }
13701
994
    if (a == &a_s)
13702
144
        bf_delete(a);
13703
994
    if (b == &b_s)
13704
674
        bf_delete(b);
13705
994
    JS_FreeValue(ctx, op1);
13706
994
    JS_FreeValue(ctx, op2);
13707
994
    return res;
13708
994
}
13709
13710
static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op,
13711
                                 JSValue op1, JSValue op2)
13712
0
{
13713
0
    bfdec_t *a, *b;
13714
0
    int res;
13715
13716
    /* Note: binary floats are converted to bigdecimal with
13717
       toString(). It is not mathematically correct but is consistent
13718
       with the BigDecimal() constructor behavior */
13719
0
    op1 = JS_ToBigDecimalFree(ctx, op1, TRUE);
13720
0
    if (JS_IsException(op1)) {
13721
0
        JS_FreeValue(ctx, op2);
13722
0
        return -1;
13723
0
    }
13724
0
    op2 = JS_ToBigDecimalFree(ctx, op2, TRUE);
13725
0
    if (JS_IsException(op2)) {
13726
0
        JS_FreeValue(ctx, op1);
13727
0
        return -1;
13728
0
    }
13729
0
    a = JS_ToBigDecimal(ctx, op1);
13730
0
    b = JS_ToBigDecimal(ctx, op2);
13731
    
13732
0
    switch(op) {
13733
0
    case OP_lt:
13734
0
        res = bfdec_cmp_lt(a, b); /* if NaN return false */
13735
0
        break;
13736
0
    case OP_lte:
13737
0
        res = bfdec_cmp_le(a, b); /* if NaN return false */
13738
0
        break;
13739
0
    case OP_gt:
13740
0
        res = bfdec_cmp_lt(b, a); /* if NaN return false */
13741
0
        break;
13742
0
    case OP_gte:
13743
0
        res = bfdec_cmp_le(b, a); /* if NaN return false */
13744
0
        break;
13745
0
    case OP_eq:
13746
0
        res = bfdec_cmp_eq(a, b); /* if NaN return false */
13747
0
        break;
13748
0
    default:
13749
0
        abort();
13750
0
    }
13751
0
    JS_FreeValue(ctx, op1);
13752
0
    JS_FreeValue(ctx, op2);
13753
0
    return res;
13754
0
}
13755
13756
static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
13757
                                        OPCodeEnum op)
13758
182k
{
13759
182k
    JSValue op1, op2, ret;
13760
182k
    int res;
13761
182k
    uint32_t tag1, tag2;
13762
13763
182k
    op1 = sp[-2];
13764
182k
    op2 = sp[-1];
13765
182k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13766
182k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13767
    /* try to call an overloaded operator */
13768
182k
    if ((tag1 == JS_TAG_OBJECT &&
13769
182k
         (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
13770
182k
        (tag2 == JS_TAG_OBJECT &&
13771
182k
         (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
13772
4.27k
        res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op,
13773
4.27k
                                         FALSE, HINT_NUMBER);
13774
4.27k
        if (res != 0) {
13775
0
            JS_FreeValue(ctx, op1);
13776
0
            JS_FreeValue(ctx, op2);
13777
0
            if (res < 0) {
13778
0
                goto exception;
13779
0
            } else {
13780
0
                sp[-2] = ret;
13781
0
                return 0;
13782
0
            }
13783
0
        }
13784
4.27k
    }
13785
182k
    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
13786
182k
    if (JS_IsException(op1)) {
13787
0
        JS_FreeValue(ctx, op2);
13788
0
        goto exception;
13789
0
    }
13790
182k
    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
13791
182k
    if (JS_IsException(op2)) {
13792
0
        JS_FreeValue(ctx, op1);
13793
0
        goto exception;
13794
0
    }
13795
182k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13796
182k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13797
13798
182k
    if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
13799
97
        JSString *p1, *p2;
13800
97
        p1 = JS_VALUE_GET_STRING(op1);
13801
97
        p2 = JS_VALUE_GET_STRING(op2);
13802
97
        res = js_string_compare(ctx, p1, p2);
13803
97
        switch(op) {
13804
0
        case OP_lt:
13805
0
            res = (res < 0);
13806
0
            break;
13807
18
        case OP_lte:
13808
18
            res = (res <= 0);
13809
18
            break;
13810
1
        case OP_gt:
13811
1
            res = (res > 0);
13812
1
            break;
13813
0
        default:
13814
78
        case OP_gte:
13815
78
            res = (res >= 0);
13816
78
            break;
13817
97
        }
13818
97
        JS_FreeValue(ctx, op1);
13819
97
        JS_FreeValue(ctx, op2);
13820
182k
    } else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) &&
13821
182k
               (tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) {
13822
        /* fast path for float64/int */
13823
160k
        goto float64_compare;
13824
160k
    } else {
13825
22.1k
        if (((tag1 == JS_TAG_BIG_INT && tag2 == JS_TAG_STRING) ||
13826
22.1k
             (tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING)) &&
13827
22.1k
            !is_math_mode(ctx)) {
13828
12
            if (tag1 == JS_TAG_STRING) {
13829
5
                op1 = JS_StringToBigInt(ctx, op1);
13830
5
                if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
13831
5
                    goto invalid_bigint_string;
13832
5
            }
13833
7
            if (tag2 == JS_TAG_STRING) {
13834
7
                op2 = JS_StringToBigInt(ctx, op2);
13835
7
                if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) {
13836
5
                invalid_bigint_string:
13837
5
                    JS_FreeValue(ctx, op1);
13838
5
                    JS_FreeValue(ctx, op2);
13839
5
                    res = FALSE;
13840
5
                    goto done;
13841
0
                }
13842
7
            }
13843
22.0k
        } else {
13844
22.0k
            op1 = JS_ToNumericFree(ctx, op1);
13845
22.0k
            if (JS_IsException(op1)) {
13846
0
                JS_FreeValue(ctx, op2);
13847
0
                goto exception;
13848
0
            }
13849
22.0k
            op2 = JS_ToNumericFree(ctx, op2);
13850
22.0k
            if (JS_IsException(op2)) {
13851
0
                JS_FreeValue(ctx, op1);
13852
0
                goto exception;
13853
0
            }
13854
22.0k
        }
13855
13856
22.0k
        tag1 = JS_VALUE_GET_NORM_TAG(op1);
13857
22.0k
        tag2 = JS_VALUE_GET_NORM_TAG(op2);
13858
13859
22.0k
        if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
13860
0
            res = ctx->rt->bigdecimal_ops.compare(ctx, op, op1, op2);
13861
0
            if (res < 0)
13862
0
                goto exception;
13863
22.0k
        } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
13864
0
            res = ctx->rt->bigfloat_ops.compare(ctx, op, op1, op2);
13865
0
            if (res < 0)
13866
0
                goto exception;
13867
22.0k
        } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
13868
993
            res = ctx->rt->bigint_ops.compare(ctx, op, op1, op2);
13869
993
            if (res < 0)
13870
0
                goto exception;
13871
21.1k
        } else {
13872
21.1k
            double d1, d2;
13873
13874
181k
        float64_compare:
13875
            /* can use floating point comparison */
13876
181k
            if (tag1 == JS_TAG_FLOAT64) {
13877
16.9k
                d1 = JS_VALUE_GET_FLOAT64(op1);
13878
164k
            } else {
13879
164k
                d1 = JS_VALUE_GET_INT(op1);
13880
164k
            }
13881
181k
            if (tag2 == JS_TAG_FLOAT64) {
13882
174k
                d2 = JS_VALUE_GET_FLOAT64(op2);
13883
174k
            } else {
13884
6.48k
                d2 = JS_VALUE_GET_INT(op2);
13885
6.48k
            }
13886
181k
            switch(op) {
13887
12.7k
            case OP_lt:
13888
12.7k
                res = (d1 < d2); /* if NaN return false */
13889
12.7k
                break;
13890
9
            case OP_lte:
13891
9
                res = (d1 <= d2); /* if NaN return false */
13892
9
                break;
13893
158k
            case OP_gt:
13894
158k
                res = (d1 > d2); /* if NaN return false */
13895
158k
                break;
13896
0
            default:
13897
10.2k
            case OP_gte:
13898
10.2k
                res = (d1 >= d2); /* if NaN return false */
13899
10.2k
                break;
13900
181k
            }
13901
181k
        }
13902
22.0k
    }
13903
182k
 done:
13904
182k
    sp[-2] = JS_NewBool(ctx, res);
13905
182k
    return 0;
13906
0
 exception:
13907
0
    sp[-2] = JS_UNDEFINED;
13908
0
    sp[-1] = JS_UNDEFINED;
13909
0
    return -1;
13910
182k
}
13911
13912
static BOOL tag_is_number(uint32_t tag)
13913
39.8k
{
13914
39.8k
    return (tag == JS_TAG_INT || tag == JS_TAG_BIG_INT ||
13915
39.8k
            tag == JS_TAG_FLOAT64 || tag == JS_TAG_BIG_FLOAT ||
13916
39.8k
            tag == JS_TAG_BIG_DECIMAL);
13917
39.8k
}
13918
13919
static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
13920
                                            BOOL is_neq)
13921
11.2k
{
13922
11.2k
    JSValue op1, op2, ret;
13923
11.2k
    int res;
13924
11.2k
    uint32_t tag1, tag2;
13925
13926
11.2k
    op1 = sp[-2];
13927
11.2k
    op2 = sp[-1];
13928
16.3k
 redo:
13929
16.3k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13930
16.3k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13931
16.3k
    if (tag_is_number(tag1) && tag_is_number(tag2)) {
13932
68
        if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
13933
11
            res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
13934
57
        } else if ((tag1 == JS_TAG_FLOAT64 &&
13935
57
                    (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) ||
13936
57
                   (tag2 == JS_TAG_FLOAT64 &&
13937
56
                    (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) {
13938
56
            double d1, d2;
13939
56
            if (tag1 == JS_TAG_FLOAT64) {
13940
9
                d1 = JS_VALUE_GET_FLOAT64(op1);
13941
47
            } else {
13942
47
                d1 = JS_VALUE_GET_INT(op1);
13943
47
            }
13944
56
            if (tag2 == JS_TAG_FLOAT64) {
13945
49
                d2 = JS_VALUE_GET_FLOAT64(op2);
13946
49
            } else {
13947
7
                d2 = JS_VALUE_GET_INT(op2);
13948
7
            }
13949
56
            res = (d1 == d2);
13950
56
        } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
13951
0
            res = ctx->rt->bigdecimal_ops.compare(ctx, OP_eq, op1, op2);
13952
0
            if (res < 0)
13953
0
                goto exception;
13954
1
        } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
13955
0
            res = ctx->rt->bigfloat_ops.compare(ctx, OP_eq, op1, op2);
13956
0
            if (res < 0)
13957
0
                goto exception;
13958
1
        } else {
13959
1
            res = ctx->rt->bigint_ops.compare(ctx, OP_eq, op1, op2);
13960
1
            if (res < 0)
13961
0
                goto exception;
13962
1
        }
13963
16.2k
    } else if (tag1 == tag2) {
13964
1.66k
        if (tag1 == JS_TAG_OBJECT) {
13965
            /* try the fallback operator */
13966
683
            res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
13967
683
                                             is_neq ? OP_neq : OP_eq,
13968
683
                                             FALSE, HINT_NONE);
13969
683
            if (res != 0) {
13970
0
                JS_FreeValue(ctx, op1);
13971
0
                JS_FreeValue(ctx, op2);
13972
0
                if (res < 0) {
13973
0
                    goto exception;
13974
0
                } else {
13975
0
                    sp[-2] = ret;
13976
0
                    return 0;
13977
0
                }
13978
0
            }
13979
683
        }
13980
1.66k
        res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
13981
14.6k
    } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
13982
14.6k
               (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
13983
0
        res = TRUE;
13984
14.6k
    } else if ((tag1 == JS_TAG_STRING && tag_is_number(tag2)) ||
13985
14.6k
               (tag2 == JS_TAG_STRING && tag_is_number(tag1))) {
13986
13987
8.69k
        if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) &&
13988
8.69k
            !is_math_mode(ctx)) {
13989
5
            if (tag1 == JS_TAG_STRING) {
13990
5
                op1 = JS_StringToBigInt(ctx, op1);
13991
5
                if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
13992
5
                    goto invalid_bigint_string;
13993
5
            }
13994
0
            if (tag2 == JS_TAG_STRING) {
13995
0
                op2 = JS_StringToBigInt(ctx, op2);
13996
0
                if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) {
13997
5
                invalid_bigint_string:
13998
5
                    JS_FreeValue(ctx, op1);
13999
5
                    JS_FreeValue(ctx, op2);
14000
5
                    res = FALSE;
14001
5
                    goto done;
14002
0
                }
14003
0
            }
14004
8.68k
        } else {
14005
8.68k
            op1 = JS_ToNumericFree(ctx, op1);
14006
8.68k
            if (JS_IsException(op1)) {
14007
0
                JS_FreeValue(ctx, op2);
14008
0
                goto exception;
14009
0
            }
14010
8.68k
            op2 = JS_ToNumericFree(ctx, op2);
14011
8.68k
            if (JS_IsException(op2)) {
14012
0
                JS_FreeValue(ctx, op1);
14013
0
                goto exception;
14014
0
            }
14015
8.68k
        }
14016
8.68k
        res = js_strict_eq(ctx, op1, op2);
14017
8.68k
    } else if (tag1 == JS_TAG_BOOL) {
14018
3.35k
        op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
14019
3.35k
        goto redo;
14020
3.35k
    } else if (tag2 == JS_TAG_BOOL) {
14021
21
        op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
14022
21
        goto redo;
14023
2.56k
    } else if ((tag1 == JS_TAG_OBJECT &&
14024
2.56k
                (tag_is_number(tag2) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) ||
14025
2.56k
               (tag2 == JS_TAG_OBJECT &&
14026
1.69k
                (tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) {
14027
14028
        /* try the fallback operator */
14029
1.69k
        res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
14030
1.69k
                                         is_neq ? OP_neq : OP_eq,
14031
1.69k
                                         FALSE, HINT_NONE);
14032
1.69k
        if (res != 0) {
14033
0
            JS_FreeValue(ctx, op1);
14034
0
            JS_FreeValue(ctx, op2);
14035
0
            if (res < 0) {
14036
0
                goto exception;
14037
0
            } else {
14038
0
                sp[-2] = ret;
14039
0
                return 0;
14040
0
            }
14041
0
        }
14042
14043
1.69k
        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
14044
1.69k
        if (JS_IsException(op1)) {
14045
0
            JS_FreeValue(ctx, op2);
14046
0
            goto exception;
14047
0
        }
14048
1.69k
        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
14049
1.69k
        if (JS_IsException(op2)) {
14050
0
            JS_FreeValue(ctx, op1);
14051
0
            goto exception;
14052
0
        }
14053
1.69k
        goto redo;
14054
1.69k
    } else {
14055
        /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
14056
869
        if ((JS_IsHTMLDDA(ctx, op1) &&
14057
869
             (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
14058
869
            (JS_IsHTMLDDA(ctx, op2) &&
14059
869
             (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
14060
0
            res = TRUE;
14061
869
        } else {
14062
869
            res = FALSE;
14063
869
        }
14064
869
        JS_FreeValue(ctx, op1);
14065
869
        JS_FreeValue(ctx, op2);
14066
869
    }
14067
11.2k
 done:
14068
11.2k
    sp[-2] = JS_NewBool(ctx, res ^ is_neq);
14069
11.2k
    return 0;
14070
0
 exception:
14071
0
    sp[-2] = JS_UNDEFINED;
14072
0
    sp[-1] = JS_UNDEFINED;
14073
0
    return -1;
14074
16.3k
}
14075
14076
static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
14077
1.28k
{
14078
1.28k
    JSValue op1, op2;
14079
1.28k
    uint32_t v1, v2, r;
14080
14081
1.28k
    op1 = sp[-2];
14082
1.28k
    op2 = sp[-1];
14083
1.28k
    op1 = JS_ToNumericFree(ctx, op1);
14084
1.28k
    if (JS_IsException(op1)) {
14085
0
        JS_FreeValue(ctx, op2);
14086
0
        goto exception;
14087
0
    }
14088
1.28k
    op2 = JS_ToNumericFree(ctx, op2);
14089
1.28k
    if (JS_IsException(op2)) {
14090
0
        JS_FreeValue(ctx, op1);
14091
0
        goto exception;
14092
0
    }
14093
    /* XXX: could forbid >>> in bignum mode */
14094
1.28k
    if (!is_math_mode(ctx) &&
14095
1.28k
        (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||
14096
1.28k
         JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT)) {
14097
0
        JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>");
14098
0
        JS_FreeValue(ctx, op1);
14099
0
        JS_FreeValue(ctx, op2);
14100
0
        goto exception;
14101
0
    }
14102
    /* cannot give an exception */
14103
1.28k
    JS_ToUint32Free(ctx, &v1, op1);
14104
1.28k
    JS_ToUint32Free(ctx, &v2, op2);
14105
1.28k
    r = v1 >> (v2 & 0x1f);
14106
1.28k
    sp[-2] = JS_NewUint32(ctx, r);
14107
1.28k
    return 0;
14108
0
 exception:
14109
0
    sp[-2] = JS_UNDEFINED;
14110
0
    sp[-1] = JS_UNDEFINED;
14111
0
    return -1;
14112
1.28k
}
14113
14114
static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
14115
                                       int64_t exponent)
14116
0
{
14117
0
    bf_t r_s, *r = &r_s;
14118
0
    double d;
14119
0
    int ret;
14120
    
14121
    /* always convert to Float64 */
14122
0
    bf_init(ctx->bf_ctx, r);
14123
0
    ret = bf_mul_pow_radix(r, a, 10, exponent,
14124
0
                           53, bf_set_exp_bits(11) | BF_RNDN |
14125
0
                           BF_FLAG_SUBNORMAL);
14126
0
    bf_get_float64(r, &d, BF_RNDN);
14127
0
    bf_delete(r);
14128
0
    if (ret & BF_ST_MEM_ERROR)
14129
0
        return JS_ThrowOutOfMemory(ctx);
14130
0
    else
14131
0
        return __JS_NewFloat64(ctx, d);
14132
0
}
14133
14134
static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
14135
0
{
14136
0
    bf_t a_s, *a, *r;
14137
0
    JSValue op1, op2, res;
14138
0
    int64_t e;
14139
0
    int ret;
14140
14141
0
    res = JS_NewBigFloat(ctx);
14142
0
    if (JS_IsException(res))
14143
0
        return -1;
14144
0
    r = JS_GetBigFloat(res);
14145
0
    op1 = sp[-2];
14146
0
    op2 = sp[-1];
14147
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
14148
0
    if (!a)
14149
0
        return -1;
14150
0
    if (JS_IsBigInt(ctx, op2)) {
14151
0
        ret = JS_ToBigInt64(ctx, &e, op2);
14152
0
    } else {
14153
0
        ret = JS_ToInt64(ctx, &e, op2);
14154
0
    }
14155
0
    if (ret) {
14156
0
        if (a == &a_s)
14157
0
            bf_delete(a);
14158
0
        JS_FreeValue(ctx, res);
14159
0
        return -1;
14160
0
    }
14161
14162
0
    bf_mul_pow_radix(r, a, 10, e, ctx->fp_env.prec, ctx->fp_env.flags);
14163
0
    if (a == &a_s)
14164
0
        bf_delete(a);
14165
0
    JS_FreeValue(ctx, op1);
14166
0
    JS_FreeValue(ctx, op2);
14167
0
    sp[-2] = res;
14168
0
    return 0;
14169
0
}
14170
14171
#else /* !CONFIG_BIGNUM */
14172
14173
static JSValue JS_ThrowUnsupportedBigint(JSContext *ctx)
14174
{
14175
    return JS_ThrowTypeError(ctx, "bigint is not supported");
14176
}
14177
14178
JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
14179
{
14180
    return JS_ThrowUnsupportedBigint(ctx);
14181
}
14182
14183
JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
14184
{
14185
    return JS_ThrowUnsupportedBigint(ctx);
14186
}
14187
14188
int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
14189
{
14190
    JS_ThrowUnsupportedBigint(ctx);
14191
    *pres = 0;
14192
    return -1;
14193
}
14194
14195
static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
14196
                                                     JSValue *sp,
14197
                                                     OPCodeEnum op)
14198
{
14199
    JSValue op1;
14200
    double d;
14201
14202
    op1 = sp[-1];
14203
    if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) {
14204
        sp[-1] = JS_UNDEFINED;
14205
        return -1;
14206
    }
14207
    switch(op) {
14208
    case OP_inc:
14209
        d++;
14210
        break;
14211
    case OP_dec:
14212
        d--;
14213
        break;
14214
    case OP_plus:
14215
        break;
14216
    case OP_neg:
14217
        d = -d;
14218
        break;
14219
    default:
14220
        abort();
14221
    }
14222
    sp[-1] = JS_NewFloat64(ctx, d);
14223
    return 0;
14224
}
14225
14226
/* specific case necessary for correct return value semantics */
14227
static __exception int js_post_inc_slow(JSContext *ctx,
14228
                                        JSValue *sp, OPCodeEnum op)
14229
{
14230
    JSValue op1;
14231
    double d, r;
14232
14233
    op1 = sp[-1];
14234
    if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) {
14235
        sp[-1] = JS_UNDEFINED;
14236
        return -1;
14237
    }
14238
    r = d + 2 * (op - OP_post_dec) - 1;
14239
    sp[0] = JS_NewFloat64(ctx, r);
14240
    sp[-1] = JS_NewFloat64(ctx, d);
14241
    return 0;
14242
}
14243
14244
static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
14245
                                                      OPCodeEnum op)
14246
{
14247
    JSValue op1, op2;
14248
    double d1, d2, r;
14249
14250
    op1 = sp[-2];
14251
    op2 = sp[-1];
14252
    if (unlikely(JS_ToFloat64Free(ctx, &d1, op1))) {
14253
        JS_FreeValue(ctx, op2);
14254
        goto exception;
14255
    }
14256
    if (unlikely(JS_ToFloat64Free(ctx, &d2, op2))) {
14257
        goto exception;
14258
    }
14259
    switch(op) {
14260
    case OP_sub:
14261
        r = d1 - d2;
14262
        break;
14263
    case OP_mul:
14264
        r = d1 * d2;
14265
        break;
14266
    case OP_div:
14267
        r = d1 / d2;
14268
        break;
14269
    case OP_mod:
14270
        r = fmod(d1, d2);
14271
        break;
14272
    case OP_pow:
14273
        r = js_pow(d1, d2);
14274
        break;
14275
    default:
14276
        abort();
14277
    }
14278
    sp[-2] = JS_NewFloat64(ctx, r);
14279
    return 0;
14280
 exception:
14281
    sp[-2] = JS_UNDEFINED;
14282
    sp[-1] = JS_UNDEFINED;
14283
    return -1;
14284
}
14285
14286
static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
14287
{
14288
    JSValue op1, op2;
14289
    uint32_t tag1, tag2;
14290
14291
    op1 = sp[-2];
14292
    op2 = sp[-1];
14293
    tag1 = JS_VALUE_GET_TAG(op1);
14294
    tag2 = JS_VALUE_GET_TAG(op2);
14295
    if ((tag1 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag1)) &&
14296
        (tag2 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag2))) {
14297
        goto add_numbers;
14298
    } else {
14299
        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
14300
        if (JS_IsException(op1)) {
14301
            JS_FreeValue(ctx, op2);
14302
            goto exception;
14303
        }
14304
        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
14305
        if (JS_IsException(op2)) {
14306
            JS_FreeValue(ctx, op1);
14307
            goto exception;
14308
        }
14309
        tag1 = JS_VALUE_GET_TAG(op1);
14310
        tag2 = JS_VALUE_GET_TAG(op2);
14311
        if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
14312
            sp[-2] = JS_ConcatString(ctx, op1, op2);
14313
            if (JS_IsException(sp[-2]))
14314
                goto exception;
14315
        } else {
14316
            double d1, d2;
14317
        add_numbers:
14318
            if (JS_ToFloat64Free(ctx, &d1, op1)) {
14319
                JS_FreeValue(ctx, op2);
14320
                goto exception;
14321
            }
14322
            if (JS_ToFloat64Free(ctx, &d2, op2))
14323
                goto exception;
14324
            sp[-2] = JS_NewFloat64(ctx, d1 + d2);
14325
        }
14326
    }
14327
    return 0;
14328
 exception:
14329
    sp[-2] = JS_UNDEFINED;
14330
    sp[-1] = JS_UNDEFINED;
14331
    return -1;
14332
}
14333
14334
static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
14335
                                                      JSValue *sp,
14336
                                                      OPCodeEnum op)
14337
{
14338
    JSValue op1, op2;
14339
    uint32_t v1, v2, r;
14340
14341
    op1 = sp[-2];
14342
    op2 = sp[-1];
14343
    if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
14344
        JS_FreeValue(ctx, op2);
14345
        goto exception;
14346
    }
14347
    if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
14348
        goto exception;
14349
    switch(op) {
14350
    case OP_shl:
14351
        r = v1 << (v2 & 0x1f);
14352
        break;
14353
    case OP_sar:
14354
        r = (int)v1 >> (v2 & 0x1f);
14355
        break;
14356
    case OP_and:
14357
        r = v1 & v2;
14358
        break;
14359
    case OP_or:
14360
        r = v1 | v2;
14361
        break;
14362
    case OP_xor:
14363
        r = v1 ^ v2;
14364
        break;
14365
    default:
14366
        abort();
14367
    }
14368
    sp[-2] = JS_NewInt32(ctx, r);
14369
    return 0;
14370
 exception:
14371
    sp[-2] = JS_UNDEFINED;
14372
    sp[-1] = JS_UNDEFINED;
14373
    return -1;
14374
}
14375
14376
static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
14377
{
14378
    int32_t v1;
14379
14380
    if (unlikely(JS_ToInt32Free(ctx, &v1, sp[-1]))) {
14381
        sp[-1] = JS_UNDEFINED;
14382
        return -1;
14383
    }
14384
    sp[-1] = JS_NewInt32(ctx, ~v1);
14385
    return 0;
14386
}
14387
14388
static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
14389
                                        OPCodeEnum op)
14390
{
14391
    JSValue op1, op2;
14392
    int res;
14393
14394
    op1 = sp[-2];
14395
    op2 = sp[-1];
14396
    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
14397
    if (JS_IsException(op1)) {
14398
        JS_FreeValue(ctx, op2);
14399
        goto exception;
14400
    }
14401
    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
14402
    if (JS_IsException(op2)) {
14403
        JS_FreeValue(ctx, op1);
14404
        goto exception;
14405
    }
14406
    if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING &&
14407
        JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
14408
        JSString *p1, *p2;
14409
        p1 = JS_VALUE_GET_STRING(op1);
14410
        p2 = JS_VALUE_GET_STRING(op2);
14411
        res = js_string_compare(ctx, p1, p2);
14412
        JS_FreeValue(ctx, op1);
14413
        JS_FreeValue(ctx, op2);
14414
        switch(op) {
14415
        case OP_lt:
14416
            res = (res < 0);
14417
            break;
14418
        case OP_lte:
14419
            res = (res <= 0);
14420
            break;
14421
        case OP_gt:
14422
            res = (res > 0);
14423
            break;
14424
        default:
14425
        case OP_gte:
14426
            res = (res >= 0);
14427
            break;
14428
        }
14429
    } else {
14430
        double d1, d2;
14431
        if (JS_ToFloat64Free(ctx, &d1, op1)) {
14432
            JS_FreeValue(ctx, op2);
14433
            goto exception;
14434
        }
14435
        if (JS_ToFloat64Free(ctx, &d2, op2))
14436
            goto exception;
14437
        switch(op) {
14438
        case OP_lt:
14439
            res = (d1 < d2); /* if NaN return false */
14440
            break;
14441
        case OP_lte:
14442
            res = (d1 <= d2); /* if NaN return false */
14443
            break;
14444
        case OP_gt:
14445
            res = (d1 > d2); /* if NaN return false */
14446
            break;
14447
        default:
14448
        case OP_gte:
14449
            res = (d1 >= d2); /* if NaN return false */
14450
            break;
14451
        }
14452
    }
14453
    sp[-2] = JS_NewBool(ctx, res);
14454
    return 0;
14455
 exception:
14456
    sp[-2] = JS_UNDEFINED;
14457
    sp[-1] = JS_UNDEFINED;
14458
    return -1;
14459
}
14460
14461
static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
14462
                                            BOOL is_neq)
14463
{
14464
    JSValue op1, op2;
14465
    int tag1, tag2;
14466
    BOOL res;
14467
14468
    op1 = sp[-2];
14469
    op2 = sp[-1];
14470
 redo:
14471
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14472
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14473
    if (tag1 == tag2 ||
14474
        (tag1 == JS_TAG_INT && tag2 == JS_TAG_FLOAT64) ||
14475
        (tag2 == JS_TAG_INT && tag1 == JS_TAG_FLOAT64)) {
14476
        res = js_strict_eq(ctx, op1, op2);
14477
    } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
14478
               (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
14479
        res = TRUE;
14480
    } else if ((tag1 == JS_TAG_STRING && (tag2 == JS_TAG_INT ||
14481
                                   tag2 == JS_TAG_FLOAT64)) ||
14482
        (tag2 == JS_TAG_STRING && (tag1 == JS_TAG_INT ||
14483
                                   tag1 == JS_TAG_FLOAT64))) {
14484
        double d1;
14485
        double d2;
14486
        if (JS_ToFloat64Free(ctx, &d1, op1)) {
14487
            JS_FreeValue(ctx, op2);
14488
            goto exception;
14489
        }
14490
        if (JS_ToFloat64Free(ctx, &d2, op2))
14491
            goto exception;
14492
        res = (d1 == d2);
14493
    } else if (tag1 == JS_TAG_BOOL) {
14494
        op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
14495
        goto redo;
14496
    } else if (tag2 == JS_TAG_BOOL) {
14497
        op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
14498
        goto redo;
14499
    } else if (tag1 == JS_TAG_OBJECT &&
14500
               (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64 || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) {
14501
        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
14502
        if (JS_IsException(op1)) {
14503
            JS_FreeValue(ctx, op2);
14504
            goto exception;
14505
        }
14506
        goto redo;
14507
    } else if (tag2 == JS_TAG_OBJECT &&
14508
               (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64 || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL)) {
14509
        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
14510
        if (JS_IsException(op2)) {
14511
            JS_FreeValue(ctx, op1);
14512
            goto exception;
14513
        }
14514
        goto redo;
14515
    } else {
14516
        /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
14517
        if ((JS_IsHTMLDDA(ctx, op1) &&
14518
             (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
14519
            (JS_IsHTMLDDA(ctx, op2) &&
14520
             (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
14521
            res = TRUE;
14522
        } else {
14523
            res = FALSE;
14524
        }
14525
        JS_FreeValue(ctx, op1);
14526
        JS_FreeValue(ctx, op2);
14527
    }
14528
    sp[-2] = JS_NewBool(ctx, res ^ is_neq);
14529
    return 0;
14530
 exception:
14531
    sp[-2] = JS_UNDEFINED;
14532
    sp[-1] = JS_UNDEFINED;
14533
    return -1;
14534
}
14535
14536
static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
14537
{
14538
    JSValue op1, op2;
14539
    uint32_t v1, v2, r;
14540
14541
    op1 = sp[-2];
14542
    op2 = sp[-1];
14543
    if (unlikely(JS_ToUint32Free(ctx, &v1, op1))) {
14544
        JS_FreeValue(ctx, op2);
14545
        goto exception;
14546
    }
14547
    if (unlikely(JS_ToUint32Free(ctx, &v2, op2)))
14548
        goto exception;
14549
    r = v1 >> (v2 & 0x1f);
14550
    sp[-2] = JS_NewUint32(ctx, r);
14551
    return 0;
14552
 exception:
14553
    sp[-2] = JS_UNDEFINED;
14554
    sp[-1] = JS_UNDEFINED;
14555
    return -1;
14556
}
14557
14558
#endif /* !CONFIG_BIGNUM */
14559
14560
/* XXX: Should take JSValueConst arguments */
14561
static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
14562
                          JSStrictEqModeEnum eq_mode)
14563
28.0k
{
14564
28.0k
    BOOL res;
14565
28.0k
    int tag1, tag2;
14566
28.0k
    double d1, d2;
14567
14568
28.0k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14569
28.0k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14570
28.0k
    switch(tag1) {
14571
96
    case JS_TAG_BOOL:
14572
96
        if (tag1 != tag2) {
14573
77
            res = FALSE;
14574
77
        } else {
14575
19
            res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
14576
19
            goto done_no_free;
14577
19
        }
14578
77
        break;
14579
77
    case JS_TAG_NULL:
14580
47
    case JS_TAG_UNDEFINED:
14581
47
        res = (tag1 == tag2);
14582
47
        break;
14583
995
    case JS_TAG_STRING:
14584
995
        {
14585
995
            JSString *p1, *p2;
14586
995
            if (tag1 != tag2) {
14587
16
                res = FALSE;
14588
979
            } else {
14589
979
                p1 = JS_VALUE_GET_STRING(op1);
14590
979
                p2 = JS_VALUE_GET_STRING(op2);
14591
979
                res = (js_string_compare(ctx, p1, p2) == 0);
14592
979
            }
14593
995
        }
14594
995
        break;
14595
36
    case JS_TAG_SYMBOL:
14596
36
        {
14597
36
            JSAtomStruct *p1, *p2;
14598
36
            if (tag1 != tag2) {
14599
30
                res = FALSE;
14600
30
            } else {
14601
6
                p1 = JS_VALUE_GET_PTR(op1);
14602
6
                p2 = JS_VALUE_GET_PTR(op2);
14603
6
                res = (p1 == p2);
14604
6
            }
14605
36
        }
14606
36
        break;
14607
18.2k
    case JS_TAG_OBJECT:
14608
18.2k
        if (tag1 != tag2)
14609
8
            res = FALSE;
14610
18.2k
        else
14611
18.2k
            res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2);
14612
18.2k
        break;
14613
3.61k
    case JS_TAG_INT:
14614
3.61k
        d1 = JS_VALUE_GET_INT(op1);
14615
3.61k
        if (tag2 == JS_TAG_INT) {
14616
333
            d2 = JS_VALUE_GET_INT(op2);
14617
333
            goto number_test;
14618
3.27k
        } else if (tag2 == JS_TAG_FLOAT64) {
14619
3.27k
            d2 = JS_VALUE_GET_FLOAT64(op2);
14620
3.27k
            goto number_test;
14621
3.27k
        } else {
14622
0
            res = FALSE;
14623
0
        }
14624
0
        break;
14625
5.07k
    case JS_TAG_FLOAT64:
14626
5.07k
        d1 = JS_VALUE_GET_FLOAT64(op1);
14627
5.07k
        if (tag2 == JS_TAG_FLOAT64) {
14628
4.88k
            d2 = JS_VALUE_GET_FLOAT64(op2);
14629
4.88k
        } else if (tag2 == JS_TAG_INT) {
14630
186
            d2 = JS_VALUE_GET_INT(op2);
14631
186
        } else {
14632
0
            res = FALSE;
14633
0
            break;
14634
0
        }
14635
8.68k
    number_test:
14636
8.68k
        if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
14637
0
            JSFloat64Union u1, u2;
14638
            /* NaN is not always normalized, so this test is necessary */
14639
0
            if (isnan(d1) || isnan(d2)) {
14640
0
                res = isnan(d1) == isnan(d2);
14641
0
            } else if (eq_mode == JS_EQ_SAME_VALUE_ZERO) {
14642
0
                res = (d1 == d2); /* +0 == -0 */
14643
0
            } else {
14644
0
                u1.d = d1;
14645
0
                u2.d = d2;
14646
0
                res = (u1.u64 == u2.u64); /* +0 != -0 */
14647
0
            }
14648
8.68k
        } else {
14649
8.68k
            res = (d1 == d2); /* if NaN return false and +0 == -0 */
14650
8.68k
        }
14651
8.68k
        goto done_no_free;
14652
0
#ifdef CONFIG_BIGNUM
14653
0
    case JS_TAG_BIG_INT:
14654
0
        {
14655
0
            bf_t a_s, *a, b_s, *b;
14656
0
            if (tag1 != tag2) {
14657
0
                res = FALSE;
14658
0
                break;
14659
0
            }
14660
0
            a = JS_ToBigFloat(ctx, &a_s, op1);
14661
0
            b = JS_ToBigFloat(ctx, &b_s, op2);
14662
0
            res = bf_cmp_eq(a, b);
14663
0
            if (a == &a_s)
14664
0
                bf_delete(a);
14665
0
            if (b == &b_s)
14666
0
                bf_delete(b);
14667
0
        }
14668
0
        break;
14669
0
    case JS_TAG_BIG_FLOAT:
14670
0
        {
14671
0
            JSBigFloat *p1, *p2;
14672
0
            const bf_t *a, *b;
14673
0
            if (tag1 != tag2) {
14674
0
                res = FALSE;
14675
0
                break;
14676
0
            }
14677
0
            p1 = JS_VALUE_GET_PTR(op1);
14678
0
            p2 = JS_VALUE_GET_PTR(op2);
14679
0
            a = &p1->num;
14680
0
            b = &p2->num;
14681
0
            if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
14682
0
                if (eq_mode == JS_EQ_SAME_VALUE_ZERO &&
14683
0
                           a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO) {
14684
0
                    res = TRUE;
14685
0
                } else {
14686
0
                    res = (bf_cmp_full(a, b) == 0);
14687
0
                }
14688
0
            } else {
14689
0
                res = bf_cmp_eq(a, b);
14690
0
            }
14691
0
        }
14692
0
        break;
14693
0
    case JS_TAG_BIG_DECIMAL:
14694
0
        {
14695
0
            JSBigDecimal *p1, *p2;
14696
0
            const bfdec_t *a, *b;
14697
0
            if (tag1 != tag2) {
14698
0
                res = FALSE;
14699
0
                break;
14700
0
            }
14701
0
            p1 = JS_VALUE_GET_PTR(op1);
14702
0
            p2 = JS_VALUE_GET_PTR(op2);
14703
0
            a = &p1->num;
14704
0
            b = &p2->num;
14705
0
            res = bfdec_cmp_eq(a, b);
14706
0
        }
14707
0
        break;
14708
0
#endif
14709
0
    default:
14710
0
        res = FALSE;
14711
0
        break;
14712
28.0k
    }
14713
19.3k
    JS_FreeValue(ctx, op1);
14714
19.3k
    JS_FreeValue(ctx, op2);
14715
28.0k
 done_no_free:
14716
28.0k
    return res;
14717
19.3k
}
14718
14719
static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2)
14720
8.89k
{
14721
8.89k
    return js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
14722
8.89k
}
14723
14724
static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2)
14725
17.5k
{
14726
17.5k
    return js_strict_eq2(ctx,
14727
17.5k
                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
14728
17.5k
                         JS_EQ_SAME_VALUE);
14729
17.5k
}
14730
14731
static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
14732
0
{
14733
0
    return js_strict_eq2(ctx,
14734
0
                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
14735
0
                         JS_EQ_SAME_VALUE_ZERO);
14736
0
}
14737
14738
static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp,
14739
                                       BOOL is_neq)
14740
204
{
14741
204
    BOOL res;
14742
204
    res = js_strict_eq(ctx, sp[-2], sp[-1]);
14743
204
    sp[-2] = JS_NewBool(ctx, res ^ is_neq);
14744
204
    return 0;
14745
204
}
14746
14747
static __exception int js_operator_in(JSContext *ctx, JSValue *sp)
14748
5
{
14749
5
    JSValue op1, op2;
14750
5
    JSAtom atom;
14751
5
    int ret;
14752
14753
5
    op1 = sp[-2];
14754
5
    op2 = sp[-1];
14755
14756
5
    if (JS_VALUE_GET_TAG(op2) != JS_TAG_OBJECT) {
14757
0
        JS_ThrowTypeError(ctx, "invalid 'in' operand");
14758
0
        return -1;
14759
0
    }
14760
5
    atom = JS_ValueToAtom(ctx, op1);
14761
5
    if (unlikely(atom == JS_ATOM_NULL))
14762
0
        return -1;
14763
5
    ret = JS_HasProperty(ctx, op2, atom);
14764
5
    JS_FreeAtom(ctx, atom);
14765
5
    if (ret < 0)
14766
0
        return -1;
14767
5
    JS_FreeValue(ctx, op1);
14768
5
    JS_FreeValue(ctx, op2);
14769
5
    sp[-2] = JS_NewBool(ctx, ret);
14770
5
    return 0;
14771
5
}
14772
14773
static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj,
14774
                                         JSAtom atom)
14775
0
{
14776
0
    JSValue arr, val;
14777
0
    int ret;
14778
14779
0
    arr = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_unscopables);
14780
0
    if (JS_IsException(arr))
14781
0
        return -1;
14782
0
    ret = 0;
14783
0
    if (JS_IsObject(arr)) {
14784
0
        val = JS_GetProperty(ctx, arr, atom);
14785
0
        ret = JS_ToBoolFree(ctx, val);
14786
0
    }
14787
0
    JS_FreeValue(ctx, arr);
14788
0
    return ret;
14789
0
}
14790
14791
static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp)
14792
0
{
14793
0
    JSValue op1, op2;
14794
0
    BOOL ret;
14795
14796
0
    op1 = sp[-2];
14797
0
    op2 = sp[-1];
14798
0
    ret = JS_IsInstanceOf(ctx, op1, op2);
14799
0
    if (ret < 0)
14800
0
        return ret;
14801
0
    JS_FreeValue(ctx, op1);
14802
0
    JS_FreeValue(ctx, op2);
14803
0
    sp[-2] = JS_NewBool(ctx, ret);
14804
0
    return 0;
14805
0
}
14806
14807
static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1)
14808
5.78k
{
14809
5.78k
    JSAtom atom;
14810
5.78k
    uint32_t tag;
14811
14812
5.78k
    tag = JS_VALUE_GET_NORM_TAG(op1);
14813
5.78k
    switch(tag) {
14814
0
#ifdef CONFIG_BIGNUM
14815
0
    case JS_TAG_BIG_INT:
14816
0
        atom = JS_ATOM_bigint;
14817
0
        break;
14818
0
    case JS_TAG_BIG_FLOAT:
14819
0
        atom = JS_ATOM_bigfloat;
14820
0
        break;
14821
0
    case JS_TAG_BIG_DECIMAL:
14822
0
        atom = JS_ATOM_bigdecimal;
14823
0
        break;
14824
0
#endif
14825
0
    case JS_TAG_INT:
14826
384
    case JS_TAG_FLOAT64:
14827
384
        atom = JS_ATOM_number;
14828
384
        break;
14829
901
    case JS_TAG_UNDEFINED:
14830
901
        atom = JS_ATOM_undefined;
14831
901
        break;
14832
0
    case JS_TAG_BOOL:
14833
0
        atom = JS_ATOM_boolean;
14834
0
        break;
14835
1.85k
    case JS_TAG_STRING:
14836
1.85k
        atom = JS_ATOM_string;
14837
1.85k
        break;
14838
159
    case JS_TAG_OBJECT:
14839
159
        {
14840
159
            JSObject *p;
14841
159
            p = JS_VALUE_GET_OBJ(op1);
14842
159
            if (unlikely(p->is_HTMLDDA)) 
14843
0
                atom = JS_ATOM_undefined;
14844
159
            else if (JS_IsFunction(ctx, op1))
14845
46
                atom = JS_ATOM_function;
14846
113
            else
14847
113
                goto obj_type;
14848
159
        }
14849
46
        break;
14850
46
    case JS_TAG_NULL:
14851
113
    obj_type:
14852
113
        atom = JS_ATOM_object;
14853
113
        break;
14854
2.48k
    case JS_TAG_SYMBOL:
14855
2.48k
        atom = JS_ATOM_symbol;
14856
2.48k
        break;
14857
0
    default:
14858
0
        atom = JS_ATOM_unknown;
14859
0
        break;
14860
5.78k
    }
14861
5.78k
    return atom;
14862
5.78k
}
14863
14864
static __exception int js_operator_delete(JSContext *ctx, JSValue *sp)
14865
647
{
14866
647
    JSValue op1, op2;
14867
647
    JSAtom atom;
14868
647
    int ret;
14869
14870
647
    op1 = sp[-2];
14871
647
    op2 = sp[-1];
14872
647
    atom = JS_ValueToAtom(ctx, op2);
14873
647
    if (unlikely(atom == JS_ATOM_NULL))
14874
0
        return -1;
14875
647
    ret = JS_DeleteProperty(ctx, op1, atom, JS_PROP_THROW_STRICT);
14876
647
    JS_FreeAtom(ctx, atom);
14877
647
    if (unlikely(ret < 0))
14878
0
        return -1;
14879
647
    JS_FreeValue(ctx, op1);
14880
647
    JS_FreeValue(ctx, op2);
14881
647
    sp[-2] = JS_NewBool(ctx, ret);
14882
647
    return 0;
14883
647
}
14884
14885
static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val,
14886
                                   int argc, JSValueConst *argv)
14887
0
{
14888
0
    return JS_ThrowTypeError(ctx, "invalid property access");
14889
0
}
14890
14891
/* XXX: not 100% compatible, but mozilla seems to use a similar
14892
   implementation to ensure that caller in non strict mode does not
14893
   throw (ES5 compatibility) */
14894
static JSValue js_function_proto_caller(JSContext *ctx, JSValueConst this_val,
14895
                                        int argc, JSValueConst *argv)
14896
0
{
14897
0
    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
14898
0
    if (!b || (b->js_mode & JS_MODE_STRICT) || !b->has_prototype) {
14899
0
        return js_throw_type_error(ctx, this_val, 0, NULL);
14900
0
    }
14901
0
    return JS_UNDEFINED;
14902
0
}
14903
14904
static JSValue js_function_proto_fileName(JSContext *ctx,
14905
                                          JSValueConst this_val)
14906
0
{
14907
0
    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
14908
0
    if (b && b->has_debug) {
14909
0
        return JS_AtomToString(ctx, b->debug.filename);
14910
0
    }
14911
0
    return JS_UNDEFINED;
14912
0
}
14913
14914
static JSValue js_function_proto_lineNumber(JSContext *ctx,
14915
                                            JSValueConst this_val)
14916
0
{
14917
0
    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
14918
0
    if (b && b->has_debug) {
14919
0
        return JS_NewInt32(ctx, b->debug.line_num);
14920
0
    }
14921
0
    return JS_UNDEFINED;
14922
0
}
14923
14924
static int js_arguments_define_own_property(JSContext *ctx,
14925
                                            JSValueConst this_obj,
14926
                                            JSAtom prop, JSValueConst val,
14927
                                            JSValueConst getter, JSValueConst setter, int flags)
14928
0
{
14929
0
    JSObject *p;
14930
0
    uint32_t idx;
14931
0
    p = JS_VALUE_GET_OBJ(this_obj);
14932
    /* convert to normal array when redefining an existing numeric field */
14933
0
    if (p->fast_array && JS_AtomIsArrayIndex(ctx, &idx, prop) &&
14934
0
        idx < p->u.array.count) {
14935
0
        if (convert_fast_array_to_array(ctx, p))
14936
0
            return -1;
14937
0
    }
14938
    /* run the default define own property */
14939
0
    return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
14940
0
                             flags | JS_PROP_NO_EXOTIC);
14941
0
}
14942
14943
static const JSClassExoticMethods js_arguments_exotic_methods = {
14944
    .define_own_property = js_arguments_define_own_property,
14945
};
14946
14947
static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv)
14948
0
{
14949
0
    JSValue val, *tab;
14950
0
    JSProperty *pr;
14951
0
    JSObject *p;
14952
0
    int i;
14953
14954
0
    val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
14955
0
                                 JS_CLASS_ARGUMENTS);
14956
0
    if (JS_IsException(val))
14957
0
        return val;
14958
0
    p = JS_VALUE_GET_OBJ(val);
14959
14960
    /* add the length field (cannot fail) */
14961
0
    pr = add_property(ctx, p, JS_ATOM_length,
14962
0
                      JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
14963
0
    pr->u.value = JS_NewInt32(ctx, argc);
14964
14965
    /* initialize the fast array part */
14966
0
    tab = NULL;
14967
0
    if (argc > 0) {
14968
0
        tab = js_malloc(ctx, sizeof(tab[0]) * argc);
14969
0
        if (!tab) {
14970
0
            JS_FreeValue(ctx, val);
14971
0
            return JS_EXCEPTION;
14972
0
        }
14973
0
        for(i = 0; i < argc; i++) {
14974
0
            tab[i] = JS_DupValue(ctx, argv[i]);
14975
0
        }
14976
0
    }
14977
0
    p->u.array.u.values = tab;
14978
0
    p->u.array.count = argc;
14979
14980
0
    JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator,
14981
0
                           JS_DupValue(ctx, ctx->array_proto_values),
14982
0
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
14983
    /* add callee property to throw a TypeError in strict mode */
14984
0
    JS_DefineProperty(ctx, val, JS_ATOM_callee, JS_UNDEFINED,
14985
0
                      ctx->throw_type_error, ctx->throw_type_error,
14986
0
                      JS_PROP_HAS_GET | JS_PROP_HAS_SET);
14987
0
    return val;
14988
0
}
14989
14990
12.2k
#define GLOBAL_VAR_OFFSET 0x40000000
14991
161k
#define ARGUMENT_VAR_OFFSET 0x20000000
14992
14993
/* legacy arguments object: add references to the function arguments */
14994
static JSValue js_build_mapped_arguments(JSContext *ctx, int argc,
14995
                                         JSValueConst *argv,
14996
                                         JSStackFrame *sf, int arg_count)
14997
4
{
14998
4
    JSValue val;
14999
4
    JSProperty *pr;
15000
4
    JSObject *p;
15001
4
    int i;
15002
15003
4
    val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
15004
4
                                 JS_CLASS_MAPPED_ARGUMENTS);
15005
4
    if (JS_IsException(val))
15006
0
        return val;
15007
4
    p = JS_VALUE_GET_OBJ(val);
15008
15009
    /* add the length field (cannot fail) */
15010
4
    pr = add_property(ctx, p, JS_ATOM_length,
15011
4
                      JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
15012
4
    pr->u.value = JS_NewInt32(ctx, argc);
15013
15014
4
    for(i = 0; i < arg_count; i++) {
15015
0
        JSVarRef *var_ref;
15016
0
        var_ref = get_var_ref(ctx, sf, i, TRUE);
15017
0
        if (!var_ref)
15018
0
            goto fail;
15019
0
        pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF);
15020
0
        if (!pr) {
15021
0
            free_var_ref(ctx->rt, var_ref);
15022
0
            goto fail;
15023
0
        }
15024
0
        pr->u.var_ref = var_ref;
15025
0
    }
15026
15027
    /* the arguments not mapped to the arguments of the function can
15028
       be normal properties */
15029
19
    for(i = arg_count; i < argc; i++) {
15030
15
        if (JS_DefinePropertyValueUint32(ctx, val, i,
15031
15
                                         JS_DupValue(ctx, argv[i]),
15032
15
                                         JS_PROP_C_W_E) < 0)
15033
0
            goto fail;
15034
15
    }
15035
15036
4
    JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator,
15037
4
                           JS_DupValue(ctx, ctx->array_proto_values),
15038
4
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
15039
    /* callee returns this function in non strict mode */
15040
4
    JS_DefinePropertyValue(ctx, val, JS_ATOM_callee,
15041
4
                           JS_DupValue(ctx, ctx->rt->current_stack_frame->cur_func),
15042
4
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
15043
4
    return val;
15044
0
 fail:
15045
0
    JS_FreeValue(ctx, val);
15046
0
    return JS_EXCEPTION;
15047
4
}
15048
15049
static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *argv)
15050
464k
{
15051
464k
    JSValue val;
15052
464k
    int i, ret;
15053
15054
464k
    val = JS_NewArray(ctx);
15055
464k
    if (JS_IsException(val))
15056
0
        return val;
15057
464k
    for (i = first; i < argc; i++) {
15058
0
        ret = JS_DefinePropertyValueUint32(ctx, val, i - first,
15059
0
                                           JS_DupValue(ctx, argv[i]),
15060
0
                                           JS_PROP_C_W_E);
15061
0
        if (ret < 0) {
15062
0
            JS_FreeValue(ctx, val);
15063
0
            return JS_EXCEPTION;
15064
0
        }
15065
0
    }
15066
464k
    return val;
15067
464k
}
15068
15069
static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
15070
734k
{
15071
734k
    JSObject *p;
15072
734k
    JSPropertyEnum *tab_atom;
15073
734k
    int i;
15074
734k
    JSValue enum_obj, obj1;
15075
734k
    JSForInIterator *it;
15076
734k
    uint32_t tag, tab_atom_count;
15077
15078
734k
    tag = JS_VALUE_GET_TAG(obj);
15079
734k
    if (tag != JS_TAG_OBJECT && tag != JS_TAG_NULL && tag != JS_TAG_UNDEFINED) {
15080
80.4k
        obj = JS_ToObjectFree(ctx, obj);
15081
80.4k
    }
15082
15083
734k
    it = js_malloc(ctx, sizeof(*it));
15084
734k
    if (!it) {
15085
0
        JS_FreeValue(ctx, obj);
15086
0
        return JS_EXCEPTION;
15087
0
    }
15088
734k
    enum_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_FOR_IN_ITERATOR);
15089
734k
    if (JS_IsException(enum_obj)) {
15090
0
        js_free(ctx, it);
15091
0
        JS_FreeValue(ctx, obj);
15092
0
        return JS_EXCEPTION;
15093
0
    }
15094
734k
    it->is_array = FALSE;
15095
734k
    it->obj = obj;
15096
734k
    it->idx = 0;
15097
734k
    p = JS_VALUE_GET_OBJ(enum_obj);
15098
734k
    p->u.for_in_iterator = it;
15099
15100
734k
    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
15101
0
        return enum_obj;
15102
15103
    /* fast path: assume no enumerable properties in the prototype chain */
15104
734k
    obj1 = JS_DupValue(ctx, obj);
15105
2.20M
    for(;;) {
15106
2.20M
        obj1 = JS_GetPrototypeFree(ctx, obj1);
15107
2.20M
        if (JS_IsNull(obj1))
15108
734k
            break;
15109
1.46M
        if (JS_IsException(obj1))
15110
0
            goto fail;
15111
1.46M
        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
15112
1.46M
                                           JS_VALUE_GET_OBJ(obj1),
15113
1.46M
                                           JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
15114
0
            JS_FreeValue(ctx, obj1);
15115
0
            goto fail;
15116
0
        }
15117
1.46M
        js_free_prop_enum(ctx, tab_atom, tab_atom_count);
15118
1.46M
        if (tab_atom_count != 0) {
15119
0
            JS_FreeValue(ctx, obj1);
15120
0
            goto slow_path;
15121
0
        }
15122
        /* must check for timeout to avoid infinite loop */
15123
1.46M
        if (js_poll_interrupts(ctx)) {
15124
2
            JS_FreeValue(ctx, obj1);
15125
2
            goto fail;
15126
2
        }
15127
1.46M
    }
15128
15129
734k
    p = JS_VALUE_GET_OBJ(obj);
15130
15131
734k
    if (p->fast_array) {
15132
0
        JSShape *sh;
15133
0
        JSShapeProperty *prs;
15134
        /* check that there are no enumerable normal fields */
15135
0
        sh = p->shape;
15136
0
        for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
15137
0
            if (prs->flags & JS_PROP_ENUMERABLE)
15138
0
                goto normal_case;
15139
0
        }
15140
        /* for fast arrays, we only store the number of elements */
15141
0
        it->is_array = TRUE;
15142
0
        it->array_length = p->u.array.count;
15143
734k
    } else {
15144
734k
    normal_case:
15145
734k
        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
15146
734k
                                   JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY))
15147
0
            goto fail;
15148
2.55M
        for(i = 0; i < tab_atom_count; i++) {
15149
1.81M
            JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0);
15150
1.81M
        }
15151
734k
        js_free_prop_enum(ctx, tab_atom, tab_atom_count);
15152
734k
    }
15153
734k
    return enum_obj;
15154
15155
0
 slow_path:
15156
    /* non enumerable properties hide the enumerables ones in the
15157
       prototype chain */
15158
0
    obj1 = JS_DupValue(ctx, obj);
15159
0
    for(;;) {
15160
0
        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
15161
0
                                           JS_VALUE_GET_OBJ(obj1),
15162
0
                                           JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
15163
0
            JS_FreeValue(ctx, obj1);
15164
0
            goto fail;
15165
0
        }
15166
0
        for(i = 0; i < tab_atom_count; i++) {
15167
0
            JS_DefinePropertyValue(ctx, enum_obj, tab_atom[i].atom, JS_NULL,
15168
0
                                   (tab_atom[i].is_enumerable ?
15169
0
                                    JS_PROP_ENUMERABLE : 0));
15170
0
        }
15171
0
        js_free_prop_enum(ctx, tab_atom, tab_atom_count);
15172
0
        obj1 = JS_GetPrototypeFree(ctx, obj1);
15173
0
        if (JS_IsNull(obj1))
15174
0
            break;
15175
0
        if (JS_IsException(obj1))
15176
0
            goto fail;
15177
        /* must check for timeout to avoid infinite loop */
15178
0
        if (js_poll_interrupts(ctx)) {
15179
0
            JS_FreeValue(ctx, obj1);
15180
0
            goto fail;
15181
0
        }
15182
0
    }
15183
0
    return enum_obj;
15184
15185
2
 fail:
15186
2
    JS_FreeValue(ctx, enum_obj);
15187
2
    return JS_EXCEPTION;
15188
0
}
15189
15190
/* obj -> enum_obj */
15191
static __exception int js_for_in_start(JSContext *ctx, JSValue *sp)
15192
734k
{
15193
734k
    sp[-1] = build_for_in_iterator(ctx, sp[-1]);
15194
734k
    if (JS_IsException(sp[-1]))
15195
2
        return -1;
15196
734k
    return 0;
15197
734k
}
15198
15199
/* enum_obj -> enum_obj value done */
15200
static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
15201
2.52M
{
15202
2.52M
    JSValueConst enum_obj;
15203
2.52M
    JSObject *p;
15204
2.52M
    JSAtom prop;
15205
2.52M
    JSForInIterator *it;
15206
2.52M
    int ret;
15207
15208
2.52M
    enum_obj = sp[-1];
15209
    /* fail safe */
15210
2.52M
    if (JS_VALUE_GET_TAG(enum_obj) != JS_TAG_OBJECT)
15211
0
        goto done;
15212
2.52M
    p = JS_VALUE_GET_OBJ(enum_obj);
15213
2.52M
    if (p->class_id != JS_CLASS_FOR_IN_ITERATOR)
15214
0
        goto done;
15215
2.52M
    it = p->u.for_in_iterator;
15216
15217
2.52M
    for(;;) {
15218
2.52M
        if (it->is_array) {
15219
0
            if (it->idx >= it->array_length)
15220
0
                goto done;
15221
0
            prop = __JS_AtomFromUInt32(it->idx);
15222
0
            it->idx++;
15223
2.52M
        } else {
15224
2.52M
            JSShape *sh = p->shape;
15225
2.52M
            JSShapeProperty *prs;
15226
2.52M
            if (it->idx >= sh->prop_count)
15227
733k
                goto done;
15228
1.79M
            prs = get_shape_prop(sh) + it->idx;
15229
1.79M
            prop = prs->atom;
15230
1.79M
            it->idx++;
15231
1.79M
            if (prop == JS_ATOM_NULL || !(prs->flags & JS_PROP_ENUMERABLE))
15232
0
                continue;
15233
1.79M
        }
15234
        /* check if the property was deleted */
15235
1.79M
        ret = JS_HasProperty(ctx, it->obj, prop);
15236
1.79M
        if (ret < 0)
15237
0
            return ret;
15238
1.79M
        if (ret)
15239
1.79M
            break;
15240
1.79M
    }
15241
    /* return the property */
15242
1.79M
    sp[0] = JS_AtomToValue(ctx, prop);
15243
1.79M
    sp[1] = JS_FALSE;
15244
1.79M
    return 0;
15245
733k
 done:
15246
    /* return the end */
15247
733k
    sp[0] = JS_UNDEFINED;
15248
733k
    sp[1] = JS_TRUE;
15249
733k
    return 0;
15250
2.52M
}
15251
15252
static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj,
15253
                               JSValueConst method)
15254
167k
{
15255
167k
    JSValue enum_obj;
15256
15257
167k
    enum_obj = JS_Call(ctx, method, obj, 0, NULL);
15258
167k
    if (JS_IsException(enum_obj))
15259
0
        return enum_obj;
15260
167k
    if (!JS_IsObject(enum_obj)) {
15261
0
        JS_FreeValue(ctx, enum_obj);
15262
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
15263
0
    }
15264
167k
    return enum_obj;
15265
167k
}
15266
15267
static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, BOOL is_async)
15268
167k
{
15269
167k
    JSValue method, ret, sync_iter;
15270
15271
167k
    if (is_async) {
15272
0
        method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_asyncIterator);
15273
0
        if (JS_IsException(method))
15274
0
            return method;
15275
0
        if (JS_IsUndefined(method) || JS_IsNull(method)) {
15276
0
            method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
15277
0
            if (JS_IsException(method))
15278
0
                return method;
15279
0
            sync_iter = JS_GetIterator2(ctx, obj, method);
15280
0
            JS_FreeValue(ctx, method);
15281
0
            if (JS_IsException(sync_iter))
15282
0
                return sync_iter;
15283
0
            ret = JS_CreateAsyncFromSyncIterator(ctx, sync_iter);
15284
0
            JS_FreeValue(ctx, sync_iter);
15285
0
            return ret;
15286
0
        }
15287
167k
    } else {
15288
167k
        method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
15289
167k
        if (JS_IsException(method))
15290
0
            return method;
15291
167k
    }
15292
167k
    if (!JS_IsFunction(ctx, method)) {
15293
4
        JS_FreeValue(ctx, method);
15294
4
        return JS_ThrowTypeError(ctx, "value is not iterable");
15295
4
    }
15296
167k
    ret = JS_GetIterator2(ctx, obj, method);
15297
167k
    JS_FreeValue(ctx, method);
15298
167k
    return ret;
15299
167k
}
15300
15301
/* return *pdone = 2 if the iterator object is not parsed */
15302
static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj,
15303
                                JSValueConst method,
15304
                                int argc, JSValueConst *argv, int *pdone)
15305
606k
{
15306
606k
    JSValue obj;
15307
15308
    /* fast path for the built-in iterators (avoid creating the
15309
       intermediate result object) */
15310
606k
    if (JS_IsObject(method)) {
15311
606k
        JSObject *p = JS_VALUE_GET_OBJ(method);
15312
606k
        if (p->class_id == JS_CLASS_C_FUNCTION &&
15313
606k
            p->u.cfunc.cproto == JS_CFUNC_iterator_next) {
15314
606k
            JSCFunctionType func;
15315
606k
            JSValueConst args[1];
15316
15317
            /* in case the function expects one argument */
15318
606k
            if (argc == 0) {
15319
606k
                args[0] = JS_UNDEFINED;
15320
606k
                argv = args;
15321
606k
            }
15322
606k
            func = p->u.cfunc.c_function;
15323
606k
            return func.iterator_next(ctx, enum_obj, argc, argv,
15324
606k
                                      pdone, p->u.cfunc.magic);
15325
606k
        }
15326
606k
    }
15327
0
    obj = JS_Call(ctx, method, enum_obj, argc, argv);
15328
0
    if (JS_IsException(obj))
15329
0
        goto fail;
15330
0
    if (!JS_IsObject(obj)) {
15331
0
        JS_FreeValue(ctx, obj);
15332
0
        JS_ThrowTypeError(ctx, "iterator must return an object");
15333
0
        goto fail;
15334
0
    }
15335
0
    *pdone = 2;
15336
0
    return obj;
15337
0
 fail:
15338
0
    *pdone = FALSE;
15339
0
    return JS_EXCEPTION;
15340
0
}
15341
15342
static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj,
15343
                               JSValueConst method,
15344
                               int argc, JSValueConst *argv, BOOL *pdone)
15345
606k
{
15346
606k
    JSValue obj, value, done_val;
15347
606k
    int done;
15348
15349
606k
    obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done);
15350
606k
    if (JS_IsException(obj))
15351
0
        goto fail;
15352
606k
    if (done != 2) {
15353
606k
        *pdone = done;
15354
606k
        return obj;
15355
606k
    } else {
15356
0
        done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
15357
0
        if (JS_IsException(done_val))
15358
0
            goto fail;
15359
0
        *pdone = JS_ToBoolFree(ctx, done_val);
15360
0
        value = JS_UNDEFINED;
15361
0
        if (!*pdone) {
15362
0
            value = JS_GetProperty(ctx, obj, JS_ATOM_value);
15363
0
        }
15364
0
        JS_FreeValue(ctx, obj);
15365
0
        return value;
15366
0
    }
15367
0
 fail:
15368
0
    JS_FreeValue(ctx, obj);
15369
0
    *pdone = FALSE;
15370
0
    return JS_EXCEPTION;
15371
606k
}
15372
15373
/* return < 0 in case of exception */
15374
static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
15375
                            BOOL is_exception_pending)
15376
164k
{
15377
164k
    JSValue method, ret, ex_obj;
15378
164k
    int res;
15379
15380
164k
    if (is_exception_pending) {
15381
5
        ex_obj = ctx->rt->current_exception;
15382
5
        ctx->rt->current_exception = JS_NULL;
15383
5
        res = -1;
15384
164k
    } else {
15385
164k
        ex_obj = JS_UNDEFINED;
15386
164k
        res = 0;
15387
164k
    }
15388
164k
    method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return);
15389
164k
    if (JS_IsException(method)) {
15390
0
        res = -1;
15391
0
        goto done;
15392
0
    }
15393
164k
    if (JS_IsUndefined(method) || JS_IsNull(method)) {
15394
164k
        goto done;
15395
164k
    }
15396
29
    ret = JS_CallFree(ctx, method, enum_obj, 0, NULL);
15397
29
    if (!is_exception_pending) {
15398
29
        if (JS_IsException(ret)) {
15399
0
            res = -1;
15400
29
        } else if (!JS_IsObject(ret)) {
15401
0
            JS_ThrowTypeErrorNotAnObject(ctx);
15402
0
            res = -1;
15403
0
        }
15404
29
    }
15405
29
    JS_FreeValue(ctx, ret);
15406
164k
 done:
15407
164k
    if (is_exception_pending) {
15408
5
        JS_Throw(ctx, ex_obj);
15409
5
    }
15410
164k
    return res;
15411
29
}
15412
15413
/* obj -> enum_rec (3 slots) */
15414
static __exception int js_for_of_start(JSContext *ctx, JSValue *sp,
15415
                                       BOOL is_async)
15416
165k
{
15417
165k
    JSValue op1, obj, method;
15418
165k
    op1 = sp[-1];
15419
165k
    obj = JS_GetIterator(ctx, op1, is_async);
15420
165k
    if (JS_IsException(obj))
15421
2
        return -1;
15422
165k
    JS_FreeValue(ctx, op1);
15423
165k
    sp[-1] = obj;
15424
165k
    method = JS_GetProperty(ctx, obj, JS_ATOM_next);
15425
165k
    if (JS_IsException(method))
15426
0
        return -1;
15427
165k
    sp[0] = method;
15428
165k
    return 0;
15429
165k
}
15430
15431
/* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset'
15432
   objs. If 'done' is true or in case of exception, 'enum_rec' is set
15433
   to undefined. If 'done' is true, 'value' is always set to
15434
   undefined. */
15435
static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
15436
403k
{
15437
403k
    JSValue value = JS_UNDEFINED;
15438
403k
    int done = 1;
15439
15440
403k
    if (likely(!JS_IsUndefined(sp[offset]))) {
15441
403k
        value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done);
15442
403k
        if (JS_IsException(value))
15443
0
            done = -1;
15444
403k
        if (done) {
15445
            /* value is JS_UNDEFINED or JS_EXCEPTION */
15446
            /* replace the iteration object with undefined */
15447
272
            JS_FreeValue(ctx, sp[offset]);
15448
272
            sp[offset] = JS_UNDEFINED;
15449
272
            if (done < 0) {
15450
0
                return -1;
15451
272
            } else {
15452
272
                JS_FreeValue(ctx, value);
15453
272
                value = JS_UNDEFINED;
15454
272
            }
15455
272
        }
15456
403k
    }
15457
403k
    sp[0] = value;
15458
403k
    sp[1] = JS_NewBool(ctx, done);
15459
403k
    return 0;
15460
403k
}
15461
15462
static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj,
15463
                                           BOOL *pdone)
15464
0
{
15465
0
    JSValue done_val, value;
15466
0
    BOOL done;
15467
0
    done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
15468
0
    if (JS_IsException(done_val))
15469
0
        goto fail;
15470
0
    done = JS_ToBoolFree(ctx, done_val);
15471
0
    value = JS_GetProperty(ctx, obj, JS_ATOM_value);
15472
0
    if (JS_IsException(value))
15473
0
        goto fail;
15474
0
    *pdone = done;
15475
0
    return value;
15476
0
 fail:
15477
0
    *pdone = FALSE;
15478
0
    return JS_EXCEPTION;
15479
0
}
15480
15481
static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)
15482
0
{
15483
0
    JSValue obj, value;
15484
0
    BOOL done;
15485
0
    obj = sp[-1];
15486
0
    if (!JS_IsObject(obj)) {
15487
0
        JS_ThrowTypeError(ctx, "iterator must return an object");
15488
0
        return -1;
15489
0
    }
15490
0
    value = JS_IteratorGetCompleteValue(ctx, obj, &done);
15491
0
    if (JS_IsException(value))
15492
0
        return -1;
15493
0
    JS_FreeValue(ctx, obj);
15494
0
    sp[-1] = value;
15495
0
    sp[0] = JS_NewBool(ctx, done);
15496
0
    return 0;
15497
0
}
15498
15499
static JSValue js_create_iterator_result(JSContext *ctx,
15500
                                         JSValue val,
15501
                                         BOOL done)
15502
29
{
15503
29
    JSValue obj;
15504
29
    obj = JS_NewObject(ctx);
15505
29
    if (JS_IsException(obj)) {
15506
0
        JS_FreeValue(ctx, val);
15507
0
        return obj;
15508
0
    }
15509
29
    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_value,
15510
29
                               val, JS_PROP_C_W_E) < 0) {
15511
0
        goto fail;
15512
0
    }
15513
29
    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done,
15514
29
                               JS_NewBool(ctx, done), JS_PROP_C_W_E) < 0) {
15515
0
    fail:
15516
0
        JS_FreeValue(ctx, obj);
15517
0
        return JS_EXCEPTION;
15518
0
    }
15519
29
    return obj;
15520
29
}
15521
15522
static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
15523
                                      int argc, JSValueConst *argv,
15524
                                      BOOL *pdone, int magic);
15525
15526
static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
15527
                                        int argc, JSValueConst *argv, int magic);
15528
15529
static BOOL js_is_fast_array(JSContext *ctx, JSValueConst obj)
15530
201k
{
15531
    /* Try and handle fast arrays explicitly */
15532
201k
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
15533
201k
        JSObject *p = JS_VALUE_GET_OBJ(obj);
15534
201k
        if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
15535
201k
            return TRUE;
15536
201k
        }
15537
201k
    }
15538
0
    return FALSE;
15539
201k
}
15540
15541
/* Access an Array's internal JSValue array if available */
15542
static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
15543
                              JSValue **arrpp, uint32_t *countp)
15544
201k
{
15545
    /* Try and handle fast arrays explicitly */
15546
201k
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
15547
201k
        JSObject *p = JS_VALUE_GET_OBJ(obj);
15548
201k
        if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
15549
201k
            *countp = p->u.array.count;
15550
201k
            *arrpp = p->u.array.u.values;
15551
201k
            return TRUE;
15552
201k
        }
15553
201k
    }
15554
0
    return FALSE;
15555
201k
}
15556
15557
static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp)
15558
2.62k
{
15559
2.62k
    JSValue iterator, enumobj, method, value;
15560
2.62k
    int is_array_iterator;
15561
2.62k
    JSValue *arrp;
15562
2.62k
    uint32_t i, count32, pos;
15563
    
15564
2.62k
    if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) {
15565
0
        JS_ThrowInternalError(ctx, "invalid index for append");
15566
0
        return -1;
15567
0
    }
15568
15569
2.62k
    pos = JS_VALUE_GET_INT(sp[-2]);
15570
15571
    /* XXX: further optimisations:
15572
       - use ctx->array_proto_values?
15573
       - check if array_iterator_prototype next method is built-in and
15574
         avoid constructing actual iterator object?
15575
       - build this into js_for_of_start and use in all `for (x of o)` loops
15576
     */
15577
2.62k
    iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator);
15578
2.62k
    if (JS_IsException(iterator))
15579
0
        return -1;
15580
2.62k
    is_array_iterator = JS_IsCFunction(ctx, iterator,
15581
2.62k
                                       (JSCFunction *)js_create_array_iterator,
15582
2.62k
                                       JS_ITERATOR_KIND_VALUE);
15583
2.62k
    JS_FreeValue(ctx, iterator);
15584
15585
2.62k
    enumobj = JS_GetIterator(ctx, sp[-1], FALSE);
15586
2.62k
    if (JS_IsException(enumobj))
15587
2
        return -1;
15588
2.62k
    method = JS_GetProperty(ctx, enumobj, JS_ATOM_next);
15589
2.62k
    if (JS_IsException(method)) {
15590
0
        JS_FreeValue(ctx, enumobj);
15591
0
        return -1;
15592
0
    }
15593
2.62k
    if (is_array_iterator
15594
2.62k
    &&  JS_IsCFunction(ctx, method, (JSCFunction *)js_array_iterator_next, 0)
15595
2.62k
    &&  js_get_fast_array(ctx, sp[-1], &arrp, &count32)) {
15596
4
        uint32_t len;
15597
4
        if (js_get_length32(ctx, &len, sp[-1]))
15598
0
            goto exception;
15599
        /* if len > count32, the elements >= count32 might be read in
15600
           the prototypes and might have side effects */
15601
4
        if (len != count32)
15602
0
            goto general_case;
15603
        /* Handle fast arrays explicitly */
15604
41.5k
        for (i = 0; i < count32; i++) {
15605
41.5k
            if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++,
15606
41.5k
                                             JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0)
15607
0
                goto exception;
15608
41.5k
        }
15609
2.61k
    } else {
15610
2.61k
    general_case:
15611
203k
        for (;;) {
15612
203k
            BOOL done;
15613
203k
            value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done);
15614
203k
            if (JS_IsException(value))
15615
0
                goto exception;
15616
203k
            if (done) {
15617
                /* value is JS_UNDEFINED */
15618
2.61k
                break;
15619
2.61k
            }
15620
200k
            if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0)
15621
0
                goto exception;
15622
200k
        }
15623
2.61k
    }
15624
    /* Note: could raise an error if too many elements */
15625
2.62k
    sp[-2] = JS_NewInt32(ctx, pos);
15626
2.62k
    JS_FreeValue(ctx, enumobj);
15627
2.62k
    JS_FreeValue(ctx, method);
15628
2.62k
    return 0;
15629
15630
0
exception:
15631
0
    JS_IteratorClose(ctx, enumobj, TRUE);
15632
0
    JS_FreeValue(ctx, enumobj);
15633
0
    JS_FreeValue(ctx, method);
15634
0
    return -1;
15635
2.62k
}
15636
15637
static __exception int JS_CopyDataProperties(JSContext *ctx,
15638
                                             JSValueConst target,
15639
                                             JSValueConst source,
15640
                                             JSValueConst excluded,
15641
                                             BOOL setprop)
15642
550k
{
15643
550k
    JSPropertyEnum *tab_atom;
15644
550k
    JSValue val;
15645
550k
    uint32_t i, tab_atom_count;
15646
550k
    JSObject *p;
15647
550k
    JSObject *pexcl = NULL;
15648
550k
    int ret, gpn_flags;
15649
550k
    JSPropertyDescriptor desc;
15650
550k
    BOOL is_enumerable;
15651
    
15652
550k
    if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT)
15653
10
        return 0;
15654
15655
550k
    if (JS_VALUE_GET_TAG(excluded) == JS_TAG_OBJECT)
15656
548k
        pexcl = JS_VALUE_GET_OBJ(excluded);
15657
15658
550k
    p = JS_VALUE_GET_OBJ(source);
15659
15660
550k
    gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY;
15661
550k
    if (p->is_exotic) {
15662
5.86k
        const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
15663
        /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it
15664
           introduces a visible change */
15665
5.86k
        if (em && em->get_own_property_names) {
15666
0
            gpn_flags &= ~JS_GPN_ENUM_ONLY;
15667
0
        }
15668
5.86k
    }
15669
550k
    if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
15670
550k
                                       gpn_flags))
15671
0
        return -1;
15672
    
15673
3.77M
    for (i = 0; i < tab_atom_count; i++) {
15674
3.22M
        if (pexcl) {
15675
2.76M
            ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom);
15676
2.76M
            if (ret) {
15677
0
                if (ret < 0)
15678
0
                    goto exception;
15679
0
                continue;
15680
0
            }
15681
2.76M
        }
15682
3.22M
        if (!(gpn_flags & JS_GPN_ENUM_ONLY)) {
15683
            /* test if the property is enumerable */
15684
0
            ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom);
15685
0
            if (ret < 0)
15686
0
                goto exception;
15687
0
            if (!ret)
15688
0
                continue;
15689
0
            is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0;
15690
0
            js_free_desc(ctx, &desc);
15691
0
            if (!is_enumerable)
15692
0
                continue;
15693
0
        }
15694
3.22M
        val = JS_GetProperty(ctx, source, tab_atom[i].atom);
15695
3.22M
        if (JS_IsException(val))
15696
0
            goto exception;
15697
3.22M
        if (setprop)
15698
0
            ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val);
15699
3.22M
        else
15700
3.22M
            ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val,
15701
3.22M
                                         JS_PROP_C_W_E);
15702
3.22M
        if (ret < 0)
15703
0
            goto exception;
15704
3.22M
    }
15705
550k
    js_free_prop_enum(ctx, tab_atom, tab_atom_count);
15706
550k
    return 0;
15707
0
 exception:
15708
0
    js_free_prop_enum(ctx, tab_atom, tab_atom_count);
15709
0
    return -1;
15710
550k
}
15711
15712
/* only valid inside C functions */
15713
static JSValueConst JS_GetActiveFunction(JSContext *ctx)
15714
23
{
15715
23
    return ctx->rt->current_stack_frame->cur_func;
15716
23
}
15717
15718
static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
15719
                             int var_idx, BOOL is_arg)
15720
1.64M
{
15721
1.64M
    JSVarRef *var_ref;
15722
1.64M
    struct list_head *el;
15723
15724
6.44M
    list_for_each(el, &sf->var_ref_list) {
15725
6.44M
        var_ref = list_entry(el, JSVarRef, header.link);
15726
6.44M
        if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) {
15727
58.9k
            var_ref->header.ref_count++;
15728
58.9k
            return var_ref;
15729
58.9k
        }
15730
6.44M
    }
15731
    /* create a new one */
15732
1.58M
    var_ref = js_malloc(ctx, sizeof(JSVarRef));
15733
1.58M
    if (!var_ref)
15734
0
        return NULL;
15735
1.58M
    var_ref->header.ref_count = 1;
15736
1.58M
    var_ref->is_detached = FALSE;
15737
1.58M
    var_ref->is_arg = is_arg;
15738
1.58M
    var_ref->var_idx = var_idx;
15739
1.58M
    list_add_tail(&var_ref->header.link, &sf->var_ref_list);
15740
1.58M
    if (is_arg)
15741
28.8k
        var_ref->pvalue = &sf->arg_buf[var_idx];
15742
1.55M
    else
15743
1.55M
        var_ref->pvalue = &sf->var_buf[var_idx];
15744
1.58M
    var_ref->value = JS_UNDEFINED;
15745
1.58M
    return var_ref;
15746
1.58M
}
15747
15748
static JSValue js_closure2(JSContext *ctx, JSValue func_obj,
15749
                           JSFunctionBytecode *b,
15750
                           JSVarRef **cur_var_refs,
15751
                           JSStackFrame *sf)
15752
2.47M
{
15753
2.47M
    JSObject *p;
15754
2.47M
    JSVarRef **var_refs;
15755
2.47M
    int i;
15756
15757
2.47M
    p = JS_VALUE_GET_OBJ(func_obj);
15758
2.47M
    p->u.func.function_bytecode = b;
15759
2.47M
    p->u.func.home_object = NULL;
15760
2.47M
    p->u.func.var_refs = NULL;
15761
2.47M
    if (b->closure_var_count) {
15762
1.36M
        var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
15763
1.36M
        if (!var_refs)
15764
0
            goto fail;
15765
1.36M
        p->u.func.var_refs = var_refs;
15766
3.01M
        for(i = 0; i < b->closure_var_count; i++) {
15767
1.64M
            JSClosureVar *cv = &b->closure_var[i];
15768
1.64M
            JSVarRef *var_ref;
15769
1.64M
            if (cv->is_local) {
15770
                /* reuse the existing variable reference if it already exists */
15771
1.63M
                var_ref = get_var_ref(ctx, sf, cv->var_idx, cv->is_arg);
15772
1.63M
                if (!var_ref)
15773
0
                    goto fail;
15774
1.63M
            } else {
15775
19.2k
                var_ref = cur_var_refs[cv->var_idx];
15776
19.2k
                var_ref->header.ref_count++;
15777
19.2k
            }
15778
1.64M
            var_refs[i] = var_ref;
15779
1.64M
        }
15780
1.36M
    }
15781
2.47M
    return func_obj;
15782
0
 fail:
15783
    /* bfunc is freed when func_obj is freed */
15784
0
    JS_FreeValue(ctx, func_obj);
15785
0
    return JS_EXCEPTION;
15786
2.47M
}
15787
15788
static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque)
15789
0
{
15790
0
    JSValue obj, this_val;
15791
0
    int ret;
15792
15793
0
    this_val = JS_MKPTR(JS_TAG_OBJECT, p);
15794
0
    obj = JS_NewObject(ctx);
15795
0
    if (JS_IsException(obj))
15796
0
        return JS_EXCEPTION;
15797
0
    set_cycle_flag(ctx, obj);
15798
0
    set_cycle_flag(ctx, this_val);
15799
0
    ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor,
15800
0
                                 JS_DupValue(ctx, this_val),
15801
0
                                 JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
15802
0
    if (ret < 0) {
15803
0
        JS_FreeValue(ctx, obj);
15804
0
        return JS_EXCEPTION;
15805
0
    }
15806
0
    return obj;
15807
0
}
15808
15809
static const uint16_t func_kind_to_class_id[] = {
15810
    [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION,
15811
    [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION,
15812
    [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION,
15813
    [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION,
15814
};
15815
15816
static JSValue js_closure(JSContext *ctx, JSValue bfunc,
15817
                          JSVarRef **cur_var_refs,
15818
                          JSStackFrame *sf)
15819
2.14M
{
15820
2.14M
    JSFunctionBytecode *b;
15821
2.14M
    JSValue func_obj;
15822
2.14M
    JSAtom name_atom;
15823
15824
2.14M
    b = JS_VALUE_GET_PTR(bfunc);
15825
2.14M
    func_obj = JS_NewObjectClass(ctx, func_kind_to_class_id[b->func_kind]);
15826
2.14M
    if (JS_IsException(func_obj)) {
15827
0
        JS_FreeValue(ctx, bfunc);
15828
0
        return JS_EXCEPTION;
15829
0
    }
15830
2.14M
    func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf);
15831
2.14M
    if (JS_IsException(func_obj)) {
15832
        /* bfunc has been freed */
15833
0
        goto fail;
15834
0
    }
15835
2.14M
    name_atom = b->func_name;
15836
2.14M
    if (name_atom == JS_ATOM_NULL)
15837
2.13M
        name_atom = JS_ATOM_empty_string;
15838
2.14M
    js_function_set_properties(ctx, func_obj, name_atom,
15839
2.14M
                               b->defined_arg_count);
15840
15841
2.14M
    if (b->func_kind & JS_FUNC_GENERATOR) {
15842
6.81k
        JSValue proto;
15843
6.81k
        int proto_class_id;
15844
        /* generators have a prototype field which is used as
15845
           prototype for the generator object */
15846
6.81k
        if (b->func_kind == JS_FUNC_ASYNC_GENERATOR)
15847
0
            proto_class_id = JS_CLASS_ASYNC_GENERATOR;
15848
6.81k
        else
15849
6.81k
            proto_class_id = JS_CLASS_GENERATOR;
15850
6.81k
        proto = JS_NewObjectProto(ctx, ctx->class_proto[proto_class_id]);
15851
6.81k
        if (JS_IsException(proto))
15852
0
            goto fail;
15853
6.81k
        JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, proto,
15854
6.81k
                               JS_PROP_WRITABLE);
15855
2.13M
    } else if (b->has_prototype) {
15856
        /* add the 'prototype' property: delay instantiation to avoid
15857
           creating cycles for every javascript function. The prototype
15858
           object is created on the fly when first accessed */
15859
881
        JS_SetConstructorBit(ctx, func_obj, TRUE);
15860
881
        JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype,
15861
881
                                  JS_AUTOINIT_ID_PROTOTYPE, NULL,
15862
881
                                  JS_PROP_WRITABLE);
15863
881
    }
15864
2.14M
    return func_obj;
15865
0
 fail:
15866
    /* bfunc is freed when func_obj is freed */
15867
0
    JS_FreeValue(ctx, func_obj);
15868
0
    return JS_EXCEPTION;
15869
2.14M
}
15870
15871
337k
#define JS_DEFINE_CLASS_HAS_HERITAGE     (1 << 0)
15872
15873
static int js_op_define_class(JSContext *ctx, JSValue *sp,
15874
                              JSAtom class_name, int class_flags,
15875
                              JSVarRef **cur_var_refs,
15876
                              JSStackFrame *sf, BOOL is_computed_name)
15877
326k
{
15878
326k
    JSValue bfunc, parent_class, proto = JS_UNDEFINED;
15879
326k
    JSValue ctor = JS_UNDEFINED, parent_proto = JS_UNDEFINED;
15880
326k
    JSFunctionBytecode *b;
15881
15882
326k
    parent_class = sp[-2];
15883
326k
    bfunc = sp[-1];
15884
15885
326k
    if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) {
15886
0
        if (JS_IsNull(parent_class)) {
15887
0
            parent_proto = JS_NULL;
15888
0
            parent_class = JS_DupValue(ctx, ctx->function_proto);
15889
0
        } else {
15890
0
            if (!JS_IsConstructor(ctx, parent_class)) {
15891
0
                JS_ThrowTypeError(ctx, "parent class must be constructor");
15892
0
                goto fail;
15893
0
            }
15894
0
            parent_proto = JS_GetProperty(ctx, parent_class, JS_ATOM_prototype);
15895
0
            if (JS_IsException(parent_proto))
15896
0
                goto fail;
15897
0
            if (!JS_IsNull(parent_proto) && !JS_IsObject(parent_proto)) {
15898
0
                JS_ThrowTypeError(ctx, "parent prototype must be an object or null");
15899
0
                goto fail;
15900
0
            }
15901
0
        }
15902
326k
    } else {
15903
        /* parent_class is JS_UNDEFINED in this case */
15904
326k
        parent_proto = JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]);
15905
326k
        parent_class = JS_DupValue(ctx, ctx->function_proto);
15906
326k
    }
15907
326k
    proto = JS_NewObjectProto(ctx, parent_proto);
15908
326k
    if (JS_IsException(proto))
15909
0
        goto fail;
15910
15911
326k
    b = JS_VALUE_GET_PTR(bfunc);
15912
326k
    assert(b->func_kind == JS_FUNC_NORMAL);
15913
326k
    ctor = JS_NewObjectProtoClass(ctx, parent_class,
15914
326k
                                  JS_CLASS_BYTECODE_FUNCTION);
15915
326k
    if (JS_IsException(ctor))
15916
0
        goto fail;
15917
326k
    ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf);
15918
326k
    bfunc = JS_UNDEFINED;
15919
326k
    if (JS_IsException(ctor))
15920
0
        goto fail;
15921
326k
    js_method_set_home_object(ctx, ctor, proto);
15922
326k
    JS_SetConstructorBit(ctx, ctor, TRUE);
15923
15924
326k
    JS_DefinePropertyValue(ctx, ctor, JS_ATOM_length,
15925
326k
                           JS_NewInt32(ctx, b->defined_arg_count),
15926
326k
                           JS_PROP_CONFIGURABLE);
15927
15928
326k
    if (is_computed_name) {
15929
10.0k
        if (JS_DefineObjectNameComputed(ctx, ctor, sp[-3],
15930
10.0k
                                        JS_PROP_CONFIGURABLE) < 0)
15931
0
            goto fail;
15932
316k
    } else {
15933
316k
        if (JS_DefineObjectName(ctx, ctor, class_name, JS_PROP_CONFIGURABLE) < 0)
15934
0
            goto fail;
15935
316k
    }
15936
15937
    /* the constructor property must be first. It can be overriden by
15938
       computed property names */
15939
326k
    if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
15940
326k
                               JS_DupValue(ctx, ctor),
15941
326k
                               JS_PROP_CONFIGURABLE |
15942
326k
                               JS_PROP_WRITABLE | JS_PROP_THROW) < 0)
15943
0
        goto fail;
15944
    /* set the prototype property */
15945
326k
    if (JS_DefinePropertyValue(ctx, ctor, JS_ATOM_prototype,
15946
326k
                               JS_DupValue(ctx, proto), JS_PROP_THROW) < 0)
15947
0
        goto fail;
15948
326k
    set_cycle_flag(ctx, ctor);
15949
326k
    set_cycle_flag(ctx, proto);
15950
15951
326k
    JS_FreeValue(ctx, parent_proto);
15952
326k
    JS_FreeValue(ctx, parent_class);
15953
15954
326k
    sp[-2] = ctor;
15955
326k
    sp[-1] = proto;
15956
326k
    return 0;
15957
0
 fail:
15958
0
    JS_FreeValue(ctx, parent_class);
15959
0
    JS_FreeValue(ctx, parent_proto);
15960
0
    JS_FreeValue(ctx, bfunc);
15961
0
    JS_FreeValue(ctx, proto);
15962
0
    JS_FreeValue(ctx, ctor);
15963
0
    sp[-2] = JS_UNDEFINED;
15964
0
    sp[-1] = JS_UNDEFINED;
15965
0
    return -1;
15966
326k
}
15967
15968
static void close_var_refs(JSRuntime *rt, JSStackFrame *sf)
15969
16.7k
{
15970
16.7k
    struct list_head *el, *el1;
15971
16.7k
    JSVarRef *var_ref;
15972
16.7k
    int var_idx;
15973
15974
26.2k
    list_for_each_safe(el, el1, &sf->var_ref_list) {
15975
26.2k
        var_ref = list_entry(el, JSVarRef, header.link);
15976
26.2k
        var_idx = var_ref->var_idx;
15977
26.2k
        if (var_ref->is_arg)
15978
26.1k
            var_ref->value = JS_DupValueRT(rt, sf->arg_buf[var_idx]);
15979
107
        else
15980
107
            var_ref->value = JS_DupValueRT(rt, sf->var_buf[var_idx]);
15981
26.2k
        var_ref->pvalue = &var_ref->value;
15982
        /* the reference is no longer to a local variable */
15983
26.2k
        var_ref->is_detached = TRUE;
15984
26.2k
        add_gc_object(rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
15985
26.2k
    }
15986
16.7k
}
15987
15988
static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_arg)
15989
2.24M
{
15990
2.24M
    struct list_head *el, *el1;
15991
2.24M
    JSVarRef *var_ref;
15992
2.24M
    int var_idx = idx;
15993
15994
13.7M
    list_for_each_safe(el, el1, &sf->var_ref_list) {
15995
13.7M
        var_ref = list_entry(el, JSVarRef, header.link);
15996
13.7M
        if (var_idx == var_ref->var_idx && var_ref->is_arg == is_arg) {
15997
1.54M
            var_ref->value = JS_DupValue(ctx, sf->var_buf[var_idx]);
15998
1.54M
            var_ref->pvalue = &var_ref->value;
15999
1.54M
            list_del(&var_ref->header.link);
16000
            /* the reference is no longer to a local variable */
16001
1.54M
            var_ref->is_detached = TRUE;
16002
1.54M
            add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
16003
1.54M
        }
16004
13.7M
    }
16005
2.24M
}
16006
16007
3.32M
#define JS_CALL_FLAG_COPY_ARGV   (1 << 1)
16008
10.7k
#define JS_CALL_FLAG_GENERATOR   (1 << 2)
16009
16010
static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
16011
                                  JSValueConst this_obj,
16012
                                  int argc, JSValueConst *argv, int flags)
16013
3.40M
{
16014
3.40M
    JSRuntime *rt = ctx->rt;
16015
3.40M
    JSCFunctionType func;
16016
3.40M
    JSObject *p;
16017
3.40M
    JSStackFrame sf_s, *sf = &sf_s, *prev_sf;
16018
3.40M
    JSValue ret_val;
16019
3.40M
    JSValueConst *arg_buf;
16020
3.40M
    int arg_count, i;
16021
3.40M
    JSCFunctionEnum cproto;
16022
16023
3.40M
    p = JS_VALUE_GET_OBJ(func_obj);
16024
3.40M
    cproto = p->u.cfunc.cproto;
16025
3.40M
    arg_count = p->u.cfunc.length;
16026
16027
    /* better to always check stack overflow */
16028
3.40M
    if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count))
16029
6
        return JS_ThrowStackOverflow(ctx);
16030
16031
3.40M
    prev_sf = rt->current_stack_frame;
16032
3.40M
    sf->prev_frame = prev_sf;
16033
3.40M
    rt->current_stack_frame = sf;
16034
3.40M
    ctx = p->u.cfunc.realm; /* change the current realm */
16035
    
16036
3.40M
#ifdef CONFIG_BIGNUM
16037
    /* we only propagate the bignum mode as some runtime functions
16038
       test it */
16039
3.40M
    if (prev_sf)
16040
3.40M
        sf->js_mode = prev_sf->js_mode & JS_MODE_MATH;
16041
47
    else
16042
47
        sf->js_mode = 0;
16043
#else
16044
    sf->js_mode = 0;
16045
#endif
16046
3.40M
    sf->cur_func = (JSValue)func_obj;
16047
3.40M
    sf->arg_count = argc;
16048
3.40M
    arg_buf = argv;
16049
16050
3.40M
    if (unlikely(argc < arg_count)) {
16051
        /* ensure that at least argc_count arguments are readable */
16052
780k
        arg_buf = alloca(sizeof(arg_buf[0]) * arg_count);
16053
982k
        for(i = 0; i < argc; i++)
16054
202k
            arg_buf[i] = argv[i];
16055
1.56M
        for(i = argc; i < arg_count; i++)
16056
780k
            arg_buf[i] = JS_UNDEFINED;
16057
780k
        sf->arg_count = arg_count;
16058
780k
    }
16059
3.40M
    sf->arg_buf = (JSValue*)arg_buf;
16060
16061
3.40M
    func = p->u.cfunc.c_function;
16062
3.40M
    switch(cproto) {
16063
0
    case JS_CFUNC_constructor:
16064
201k
    case JS_CFUNC_constructor_or_func:
16065
201k
        if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
16066
31
            if (cproto == JS_CFUNC_constructor) {
16067
0
            not_a_constructor:
16068
0
                ret_val = JS_ThrowTypeError(ctx, "must be called with new");
16069
0
                break;
16070
31
            } else {
16071
31
                this_obj = JS_UNDEFINED;
16072
31
            }
16073
31
        }
16074
        /* here this_obj is new_target */
16075
        /* fall thru */
16076
2.11M
    case JS_CFUNC_generic:
16077
2.11M
        ret_val = func.generic(ctx, this_obj, argc, arg_buf);
16078
2.11M
        break;
16079
0
    case JS_CFUNC_constructor_magic:
16080
15
    case JS_CFUNC_constructor_or_func_magic:
16081
15
        if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
16082
15
            if (cproto == JS_CFUNC_constructor_magic) {
16083
0
                goto not_a_constructor;
16084
15
            } else {
16085
15
                this_obj = JS_UNDEFINED;
16086
15
            }
16087
15
        }
16088
        /* fall thru */
16089
947k
    case JS_CFUNC_generic_magic:
16090
947k
        ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf,
16091
947k
                                     p->u.cfunc.magic);
16092
947k
        break;
16093
235k
    case JS_CFUNC_getter:
16094
235k
        ret_val = func.getter(ctx, this_obj);
16095
235k
        break;
16096
0
    case JS_CFUNC_setter:
16097
0
        ret_val = func.setter(ctx, this_obj, arg_buf[0]);
16098
0
        break;
16099
102k
    case JS_CFUNC_getter_magic:
16100
102k
        ret_val = func.getter_magic(ctx, this_obj, p->u.cfunc.magic);
16101
102k
        break;
16102
0
    case JS_CFUNC_setter_magic:
16103
0
        ret_val = func.setter_magic(ctx, this_obj, arg_buf[0], p->u.cfunc.magic);
16104
0
        break;
16105
0
    case JS_CFUNC_f_f:
16106
0
        {
16107
0
            double d1;
16108
16109
0
            if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
16110
0
                ret_val = JS_EXCEPTION;
16111
0
                break;
16112
0
            }
16113
0
            ret_val = JS_NewFloat64(ctx, func.f_f(d1));
16114
0
        }
16115
0
        break;
16116
0
    case JS_CFUNC_f_f_f:
16117
0
        {
16118
0
            double d1, d2;
16119
16120
0
            if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
16121
0
                ret_val = JS_EXCEPTION;
16122
0
                break;
16123
0
            }
16124
0
            if (unlikely(JS_ToFloat64(ctx, &d2, arg_buf[1]))) {
16125
0
                ret_val = JS_EXCEPTION;
16126
0
                break;
16127
0
            }
16128
0
            ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2));
16129
0
        }
16130
0
        break;
16131
29
    case JS_CFUNC_iterator_next:
16132
29
        {
16133
29
            int done;
16134
29
            ret_val = func.iterator_next(ctx, this_obj, argc, arg_buf,
16135
29
                                         &done, p->u.cfunc.magic);
16136
29
            if (!JS_IsException(ret_val) && done != 2) {
16137
29
                ret_val = js_create_iterator_result(ctx, ret_val, done);
16138
29
            }
16139
29
        }
16140
29
        break;
16141
0
    default:
16142
0
        abort();
16143
3.40M
    }
16144
16145
3.40M
    rt->current_stack_frame = sf->prev_frame;
16146
3.40M
    return ret_val;
16147
3.40M
}
16148
16149
static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
16150
                                      JSValueConst this_obj,
16151
                                      int argc, JSValueConst *argv, int flags)
16152
0
{
16153
0
    JSObject *p;
16154
0
    JSBoundFunction *bf;
16155
0
    JSValueConst *arg_buf, new_target;
16156
0
    int arg_count, i;
16157
16158
0
    p = JS_VALUE_GET_OBJ(func_obj);
16159
0
    bf = p->u.bound_function;
16160
0
    arg_count = bf->argc + argc;
16161
0
    if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count))
16162
0
        return JS_ThrowStackOverflow(ctx);
16163
0
    arg_buf = alloca(sizeof(JSValue) * arg_count);
16164
0
    for(i = 0; i < bf->argc; i++) {
16165
0
        arg_buf[i] = bf->argv[i];
16166
0
    }
16167
0
    for(i = 0; i < argc; i++) {
16168
0
        arg_buf[bf->argc + i] = argv[i];
16169
0
    }
16170
0
    if (flags & JS_CALL_FLAG_CONSTRUCTOR) {
16171
0
        new_target = this_obj;
16172
0
        if (js_same_value(ctx, func_obj, new_target))
16173
0
            new_target = bf->func_obj;
16174
0
        return JS_CallConstructor2(ctx, bf->func_obj, new_target,
16175
0
                                   arg_count, arg_buf);
16176
0
    } else {
16177
0
        return JS_Call(ctx, bf->func_obj, bf->this_val,
16178
0
                       arg_count, arg_buf);
16179
0
    }
16180
0
}
16181
16182
/* argument of OP_special_object */
16183
typedef enum {
16184
    OP_SPECIAL_OBJECT_ARGUMENTS,
16185
    OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS,
16186
    OP_SPECIAL_OBJECT_THIS_FUNC,
16187
    OP_SPECIAL_OBJECT_NEW_TARGET,
16188
    OP_SPECIAL_OBJECT_HOME_OBJECT,
16189
    OP_SPECIAL_OBJECT_VAR_OBJECT,
16190
    OP_SPECIAL_OBJECT_IMPORT_META,
16191
} OPSpecialObjectEnum;
16192
16193
0
#define FUNC_RET_AWAIT      0
16194
0
#define FUNC_RET_YIELD      1
16195
0
#define FUNC_RET_YIELD_STAR 2
16196
16197
/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
16198
static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
16199
                               JSValueConst this_obj, JSValueConst new_target,
16200
                               int argc, JSValue *argv, int flags)
16201
5.12M
{
16202
5.12M
    JSRuntime *rt = caller_ctx->rt;
16203
5.12M
    JSContext *ctx;
16204
5.12M
    JSObject *p;
16205
5.12M
    JSFunctionBytecode *b;
16206
5.12M
    JSStackFrame sf_s, *sf = &sf_s;
16207
5.12M
    const uint8_t *pc;
16208
5.12M
    int opcode, arg_allocated_size, i;
16209
5.12M
    JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval;
16210
5.12M
    JSVarRef **var_refs;
16211
5.12M
    size_t alloca_size;
16212
16213
#if !DIRECT_DISPATCH
16214
#define SWITCH(pc)      switch (opcode = *pc++)
16215
#define CASE(op)        case op
16216
#define DEFAULT         default
16217
#define BREAK           break
16218
#else
16219
5.12M
    static const void * const dispatch_table[256] = {
16220
1.26G
#define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id,
16221
5.12M
#if SHORT_OPCODES
16222
5.12M
#define def(id, size, n_pop, n_push, f)
16223
#else                                                     
16224
#define def(id, size, n_pop, n_push, f) && case_default,
16225
#endif
16226
5.12M
#include "quickjs-opcode.h"
16227
5.12M
        [ OP_COUNT ... 255 ] = &&case_default
16228
5.12M
    };
16229
76.4M
#define SWITCH(pc)      goto *dispatch_table[opcode = *pc++];
16230
84.1M
#define CASE(op)        case_ ## op
16231
5.12M
#define DEFAULT         case_default
16232
74.8M
#define BREAK           SWITCH(pc)
16233
5.12M
#endif
16234
16235
5.12M
    if (js_poll_interrupts(caller_ctx))
16236
2
        return JS_EXCEPTION;
16237
5.12M
    if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) {
16238
5.38k
        if (flags & JS_CALL_FLAG_GENERATOR) {
16239
5.35k
            JSAsyncFunctionState *s = JS_VALUE_GET_PTR(func_obj);
16240
            /* func_obj get contains a pointer to JSFuncAsyncState */
16241
            /* the stack frame is already allocated */
16242
5.35k
            sf = &s->frame;
16243
5.35k
            p = JS_VALUE_GET_OBJ(sf->cur_func);
16244
5.35k
            b = p->u.func.function_bytecode;
16245
5.35k
            ctx = b->realm;
16246
5.35k
            var_refs = p->u.func.var_refs;
16247
5.35k
            local_buf = arg_buf = sf->arg_buf;
16248
5.35k
            var_buf = sf->var_buf;
16249
5.35k
            stack_buf = sf->var_buf + b->var_count;
16250
5.35k
            sp = sf->cur_sp;
16251
5.35k
            sf->cur_sp = NULL; /* cur_sp is NULL if the function is running */
16252
5.35k
            pc = sf->cur_pc;
16253
5.35k
            sf->prev_frame = rt->current_stack_frame;
16254
5.35k
            rt->current_stack_frame = sf;
16255
5.35k
            if (s->throw_flag)
16256
0
                goto exception;
16257
5.35k
            else
16258
5.35k
                goto restart;
16259
5.35k
        } else {
16260
38
            goto not_a_function;
16261
38
        }
16262
5.38k
    }
16263
5.11M
    p = JS_VALUE_GET_OBJ(func_obj);
16264
5.11M
    if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
16265
3.52M
        JSClassCall *call_func;
16266
3.52M
        call_func = rt->class_array[p->class_id].call;
16267
3.52M
        if (!call_func) {
16268
40
        not_a_function:
16269
40
            return JS_ThrowTypeError(caller_ctx, "not a function");
16270
2
        }
16271
3.52M
        return call_func(caller_ctx, func_obj, this_obj, argc,
16272
3.52M
                         (JSValueConst *)argv, flags);
16273
3.52M
    }
16274
1.59M
    b = p->u.func.function_bytecode;
16275
16276
1.59M
    if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) {
16277
487k
        arg_allocated_size = b->arg_count;
16278
1.10M
    } else {
16279
1.10M
        arg_allocated_size = 0;
16280
1.10M
    }
16281
16282
1.59M
    alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count +
16283
1.59M
                                     b->stack_size);
16284
1.59M
    if (js_check_stack_overflow(rt, alloca_size))
16285
15
        return JS_ThrowStackOverflow(caller_ctx);
16286
16287
1.59M
    sf->js_mode = b->js_mode;
16288
1.59M
    arg_buf = argv;
16289
1.59M
    sf->arg_count = argc;
16290
1.59M
    sf->cur_func = (JSValue)func_obj;
16291
1.59M
    init_list_head(&sf->var_ref_list);
16292
1.59M
    var_refs = p->u.func.var_refs;
16293
16294
1.59M
    local_buf = alloca(alloca_size);
16295
1.59M
    if (unlikely(arg_allocated_size)) {
16296
485k
        int n = min_int(argc, b->arg_count);
16297
485k
        arg_buf = local_buf;
16298
506k
        for(i = 0; i < n; i++)
16299
20.7k
            arg_buf[i] = JS_DupValue(caller_ctx, argv[i]);
16300
990k
        for(; i < b->arg_count; i++)
16301
504k
            arg_buf[i] = JS_UNDEFINED;
16302
485k
        sf->arg_count = b->arg_count;
16303
485k
    }
16304
1.59M
    var_buf = local_buf + arg_allocated_size;
16305
1.59M
    sf->var_buf = var_buf;
16306
1.59M
    sf->arg_buf = arg_buf;
16307
16308
2.58M
    for(i = 0; i < b->var_count; i++)
16309
1.59M
        var_buf[i] = JS_UNDEFINED;
16310
16311
1.59M
    stack_buf = var_buf + b->var_count;
16312
1.59M
    sp = stack_buf;
16313
1.59M
    pc = b->byte_code_buf;
16314
1.59M
    sf->prev_frame = rt->current_stack_frame;
16315
1.59M
    rt->current_stack_frame = sf;
16316
1.59M
    ctx = b->realm; /* set the current realm */
16317
    
16318
1.60M
 restart:
16319
1.60M
    for(;;) {
16320
1.60M
        int call_argc;
16321
1.60M
        JSValue *call_argv;
16322
16323
1.60M
        SWITCH(pc) {
16324
1.60M
        CASE(OP_push_i32):
16325
176k
            *sp++ = JS_NewInt32(ctx, get_u32(pc));
16326
176k
            pc += 4;
16327
176k
            BREAK;
16328
176k
        CASE(OP_push_const):
16329
10.1k
            *sp++ = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
16330
10.1k
            pc += 4;
16331
10.1k
            BREAK;
16332
10.1k
#if SHORT_OPCODES
16333
10.1k
        CASE(OP_push_minus1):
16334
12.9k
        CASE(OP_push_0):
16335
37.0k
        CASE(OP_push_1):
16336
78.2k
        CASE(OP_push_2):
16337
80.5k
        CASE(OP_push_3):
16338
81.0k
        CASE(OP_push_4):
16339
187k
        CASE(OP_push_5):
16340
190k
        CASE(OP_push_6):
16341
349k
        CASE(OP_push_7):
16342
349k
            *sp++ = JS_NewInt32(ctx, opcode - OP_push_0);
16343
349k
            BREAK;
16344
563k
        CASE(OP_push_i8):
16345
563k
            *sp++ = JS_NewInt32(ctx, get_i8(pc));
16346
563k
            pc += 1;
16347
563k
            BREAK;
16348
570k
        CASE(OP_push_i16):
16349
570k
            *sp++ = JS_NewInt32(ctx, get_i16(pc));
16350
570k
            pc += 2;
16351
570k
            BREAK;
16352
1.78M
        CASE(OP_push_const8):
16353
1.78M
            *sp++ = JS_DupValue(ctx, b->cpool[*pc++]);
16354
1.78M
            BREAK;
16355
2.14M
        CASE(OP_fclosure8):
16356
2.14M
            *sp++ = js_closure(ctx, JS_DupValue(ctx, b->cpool[*pc++]), var_refs, sf);
16357
2.14M
            if (unlikely(JS_IsException(sp[-1])))
16358
0
                goto exception;
16359
2.14M
            BREAK;
16360
2.14M
        CASE(OP_push_empty_string):
16361
9.40k
            *sp++ = JS_AtomToString(ctx, JS_ATOM_empty_string);
16362
9.40k
            BREAK;
16363
9.40k
        CASE(OP_get_length):
16364
0
            {
16365
0
                JSValue val;
16366
16367
0
                val = JS_GetProperty(ctx, sp[-1], JS_ATOM_length);
16368
0
                if (unlikely(JS_IsException(val)))
16369
0
                    goto exception;
16370
0
                JS_FreeValue(ctx, sp[-1]);
16371
0
                sp[-1] = val;
16372
0
            }
16373
0
            BREAK;
16374
0
#endif
16375
399k
        CASE(OP_push_atom_value):
16376
399k
            *sp++ = JS_AtomToValue(ctx, get_u32(pc));
16377
399k
            pc += 4;
16378
399k
            BREAK;
16379
4.28M
        CASE(OP_undefined):
16380
4.28M
            *sp++ = JS_UNDEFINED;
16381
4.28M
            BREAK;
16382
4.28M
        CASE(OP_null):
16383
2.71k
            *sp++ = JS_NULL;
16384
2.71k
            BREAK;
16385
431k
        CASE(OP_push_this):
16386
            /* OP_push_this is only called at the start of a function */
16387
431k
            {
16388
431k
                JSValue val;
16389
431k
                if (!(b->js_mode & JS_MODE_STRICT)) {
16390
29
                    uint32_t tag = JS_VALUE_GET_TAG(this_obj);
16391
29
                    if (likely(tag == JS_TAG_OBJECT))
16392
25
                        goto normal_this;
16393
4
                    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) {
16394
4
                        val = JS_DupValue(ctx, ctx->global_obj);
16395
4
                    } else {
16396
0
                        val = JS_ToObject(ctx, this_obj);
16397
0
                        if (JS_IsException(val))
16398
0
                            goto exception;
16399
0
                    }
16400
431k
                } else {
16401
431k
                normal_this:
16402
431k
                    val = JS_DupValue(ctx, this_obj);
16403
431k
                }
16404
431k
                *sp++ = val;
16405
431k
            }
16406
431k
            BREAK;
16407
431k
        CASE(OP_push_false):
16408
0
            *sp++ = JS_FALSE;
16409
0
            BREAK;
16410
87
        CASE(OP_push_true):
16411
87
            *sp++ = JS_TRUE;
16412
87
            BREAK;
16413
1.10M
        CASE(OP_object):
16414
1.10M
            *sp++ = JS_NewObject(ctx);
16415
1.10M
            if (unlikely(JS_IsException(sp[-1])))
16416
0
                goto exception;
16417
1.10M
            BREAK;
16418
1.10M
        CASE(OP_special_object):
16419
216k
            {
16420
216k
                int arg = *pc++;
16421
216k
                switch(arg) {
16422
0
                case OP_SPECIAL_OBJECT_ARGUMENTS:
16423
0
                    *sp++ = js_build_arguments(ctx, argc, (JSValueConst *)argv);
16424
0
                    if (unlikely(JS_IsException(sp[-1])))
16425
0
                        goto exception;
16426
0
                    break;
16427
4
                case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS:
16428
4
                    *sp++ = js_build_mapped_arguments(ctx, argc, (JSValueConst *)argv,
16429
4
                                                      sf, min_int(argc, b->arg_count));
16430
4
                    if (unlikely(JS_IsException(sp[-1])))
16431
0
                        goto exception;
16432
4
                    break;
16433
848
                case OP_SPECIAL_OBJECT_THIS_FUNC:
16434
848
                    *sp++ = JS_DupValue(ctx, sf->cur_func);
16435
848
                    break;
16436
22
                case OP_SPECIAL_OBJECT_NEW_TARGET:
16437
22
                    *sp++ = JS_DupValue(ctx, new_target);
16438
22
                    break;
16439
215k
                case OP_SPECIAL_OBJECT_HOME_OBJECT:
16440
215k
                    {
16441
215k
                        JSObject *p1;
16442
215k
                        p1 = p->u.func.home_object;
16443
215k
                        if (unlikely(!p1))
16444
0
                            *sp++ = JS_UNDEFINED;
16445
215k
                        else
16446
215k
                            *sp++ = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
16447
215k
                    }
16448
215k
                    break;
16449
3
                case OP_SPECIAL_OBJECT_VAR_OBJECT:
16450
3
                    *sp++ = JS_NewObjectProto(ctx, JS_NULL);
16451
3
                    if (unlikely(JS_IsException(sp[-1])))
16452
0
                        goto exception;
16453
3
                    break;
16454
3
                case OP_SPECIAL_OBJECT_IMPORT_META:
16455
0
                    *sp++ = js_import_meta(ctx);
16456
0
                    if (unlikely(JS_IsException(sp[-1])))
16457
0
                        goto exception;
16458
0
                    break;
16459
0
                default:
16460
0
                    abort();
16461
216k
                }
16462
216k
            }
16463
216k
            BREAK;
16464
464k
        CASE(OP_rest):
16465
464k
            {
16466
464k
                int first = get_u16(pc);
16467
464k
                pc += 2;
16468
464k
                *sp++ = js_build_rest(ctx, first, argc, (JSValueConst *)argv);
16469
464k
                if (unlikely(JS_IsException(sp[-1])))
16470
0
                    goto exception;
16471
464k
            }
16472
464k
            BREAK;
16473
16474
4.34M
        CASE(OP_drop):
16475
4.34M
            JS_FreeValue(ctx, sp[-1]);
16476
4.34M
            sp--;
16477
4.34M
            BREAK;
16478
4.34M
        CASE(OP_nip):
16479
0
            JS_FreeValue(ctx, sp[-2]);
16480
0
            sp[-2] = sp[-1];
16481
0
            sp--;
16482
0
            BREAK;
16483
0
        CASE(OP_nip1): /* a b c -> b c */
16484
0
            JS_FreeValue(ctx, sp[-3]);
16485
0
            sp[-3] = sp[-2];
16486
0
            sp[-2] = sp[-1];
16487
0
            sp--;
16488
0
            BREAK;
16489
4.06M
        CASE(OP_dup):
16490
4.06M
            sp[0] = JS_DupValue(ctx, sp[-1]);
16491
4.06M
            sp++;
16492
4.06M
            BREAK;
16493
4.06M
        CASE(OP_dup2): /* a b -> a b a b */
16494
77
            sp[0] = JS_DupValue(ctx, sp[-2]);
16495
77
            sp[1] = JS_DupValue(ctx, sp[-1]);
16496
77
            sp += 2;
16497
77
            BREAK;
16498
77
        CASE(OP_dup3): /* a b c -> a b c a b c */
16499
0
            sp[0] = JS_DupValue(ctx, sp[-3]);
16500
0
            sp[1] = JS_DupValue(ctx, sp[-2]);
16501
0
            sp[2] = JS_DupValue(ctx, sp[-1]);
16502
0
            sp += 3;
16503
0
            BREAK;
16504
11
        CASE(OP_dup1): /* a b -> a a b */
16505
11
            sp[0] = sp[-1];
16506
11
            sp[-1] = JS_DupValue(ctx, sp[-2]);
16507
11
            sp++;
16508
11
            BREAK;
16509
1.04k
        CASE(OP_insert2): /* obj a -> a obj a (dup_x1) */
16510
1.04k
            sp[0] = sp[-1];
16511
1.04k
            sp[-1] = sp[-2];
16512
1.04k
            sp[-2] = JS_DupValue(ctx, sp[0]);
16513
1.04k
            sp++;
16514
1.04k
            BREAK;
16515
54.5k
        CASE(OP_insert3): /* obj prop a -> a obj prop a (dup_x2) */
16516
54.5k
            sp[0] = sp[-1];
16517
54.5k
            sp[-1] = sp[-2];
16518
54.5k
            sp[-2] = sp[-3];
16519
54.5k
            sp[-3] = JS_DupValue(ctx, sp[0]);
16520
54.5k
            sp++;
16521
54.5k
            BREAK;
16522
54.5k
        CASE(OP_insert4): /* this obj prop a -> a this obj prop a */
16523
0
            sp[0] = sp[-1];
16524
0
            sp[-1] = sp[-2];
16525
0
            sp[-2] = sp[-3];
16526
0
            sp[-3] = sp[-4];
16527
0
            sp[-4] = JS_DupValue(ctx, sp[0]);
16528
0
            sp++;
16529
0
            BREAK;
16530
21
        CASE(OP_perm3): /* obj a b -> a obj b (213) */
16531
21
            {
16532
21
                JSValue tmp;
16533
21
                tmp = sp[-2];
16534
21
                sp[-2] = sp[-3];
16535
21
                sp[-3] = tmp;
16536
21
            }
16537
21
            BREAK;
16538
524k
        CASE(OP_rot3l): /* x a b -> a b x (231) */
16539
524k
            {
16540
524k
                JSValue tmp;
16541
524k
                tmp = sp[-3];
16542
524k
                sp[-3] = sp[-2];
16543
524k
                sp[-2] = sp[-1];
16544
524k
                sp[-1] = tmp;
16545
524k
            }
16546
524k
            BREAK;
16547
524k
        CASE(OP_rot4l): /* x a b c -> a b c x */
16548
0
            {
16549
0
                JSValue tmp;
16550
0
                tmp = sp[-4];
16551
0
                sp[-4] = sp[-3];
16552
0
                sp[-3] = sp[-2];
16553
0
                sp[-2] = sp[-1];
16554
0
                sp[-1] = tmp;
16555
0
            }
16556
0
            BREAK;
16557
0
        CASE(OP_rot5l): /* x a b c d -> a b c d x */
16558
0
            {
16559
0
                JSValue tmp;
16560
0
                tmp = sp[-5];
16561
0
                sp[-5] = sp[-4];
16562
0
                sp[-4] = sp[-3];
16563
0
                sp[-3] = sp[-2];
16564
0
                sp[-2] = sp[-1];
16565
0
                sp[-1] = tmp;
16566
0
            }
16567
0
            BREAK;
16568
0
        CASE(OP_rot3r): /* a b x -> x a b (312) */
16569
0
            {
16570
0
                JSValue tmp;
16571
0
                tmp = sp[-1];
16572
0
                sp[-1] = sp[-2];
16573
0
                sp[-2] = sp[-3];
16574
0
                sp[-3] = tmp;
16575
0
            }
16576
0
            BREAK;
16577
1
        CASE(OP_perm4): /* obj prop a b -> a obj prop b */
16578
1
            {
16579
1
                JSValue tmp;
16580
1
                tmp = sp[-2];
16581
1
                sp[-2] = sp[-3];
16582
1
                sp[-3] = sp[-4];
16583
1
                sp[-4] = tmp;
16584
1
            }
16585
1
            BREAK;
16586
1
        CASE(OP_perm5): /* this obj prop a b -> a this obj prop b */
16587
0
            {
16588
0
                JSValue tmp;
16589
0
                tmp = sp[-2];
16590
0
                sp[-2] = sp[-3];
16591
0
                sp[-3] = sp[-4];
16592
0
                sp[-4] = sp[-5];
16593
0
                sp[-5] = tmp;
16594
0
            }
16595
0
            BREAK;
16596
1.20M
        CASE(OP_swap): /* a b -> b a */
16597
1.20M
            {
16598
1.20M
                JSValue tmp;
16599
1.20M
                tmp = sp[-2];
16600
1.20M
                sp[-2] = sp[-1];
16601
1.20M
                sp[-1] = tmp;
16602
1.20M
            }
16603
1.20M
            BREAK;
16604
1.20M
        CASE(OP_swap2): /* a b c d -> c d a b */
16605
0
            {
16606
0
                JSValue tmp1, tmp2;
16607
0
                tmp1 = sp[-4];
16608
0
                tmp2 = sp[-3];
16609
0
                sp[-4] = sp[-2];
16610
0
                sp[-3] = sp[-1];
16611
0
                sp[-2] = tmp1;
16612
0
                sp[-1] = tmp2;
16613
0
            }
16614
0
            BREAK;
16615
16616
4.04k
        CASE(OP_fclosure):
16617
4.04k
            {
16618
4.04k
                JSValue bfunc = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
16619
4.04k
                pc += 4;
16620
4.04k
                *sp++ = js_closure(ctx, bfunc, var_refs, sf);
16621
4.04k
                if (unlikely(JS_IsException(sp[-1])))
16622
0
                    goto exception;
16623
4.04k
            }
16624
4.04k
            BREAK;
16625
4.04k
#if SHORT_OPCODES
16626
4.04k
        CASE(OP_call0):
16627
39.4k
        CASE(OP_call1):
16628
39.4k
        CASE(OP_call2):
16629
39.4k
        CASE(OP_call3):
16630
39.4k
            call_argc = opcode - OP_call0;
16631
39.4k
            goto has_call_argc;
16632
0
#endif
16633
1
        CASE(OP_call):
16634
676
        CASE(OP_tail_call):
16635
676
            {
16636
676
                call_argc = get_u16(pc);
16637
676
                pc += 2;
16638
676
                goto has_call_argc;
16639
40.0k
            has_call_argc:
16640
40.0k
                call_argv = sp - call_argc;
16641
40.0k
                sf->cur_pc = pc;
16642
40.0k
                ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
16643
40.0k
                                          JS_UNDEFINED, call_argc, call_argv, 0);
16644
40.0k
                if (unlikely(JS_IsException(ret_val)))
16645
4.05k
                    goto exception;
16646
36.0k
                if (opcode == OP_tail_call)
16647
0
                    goto done;
16648
107k
                for(i = -1; i < call_argc; i++)
16649
71.6k
                    JS_FreeValue(ctx, call_argv[i]);
16650
36.0k
                sp -= call_argc + 1;
16651
36.0k
                *sp++ = ret_val;
16652
36.0k
            }
16653
36.0k
            BREAK;
16654
215k
        CASE(OP_call_constructor):
16655
215k
            {
16656
215k
                call_argc = get_u16(pc);
16657
215k
                pc += 2;
16658
215k
                call_argv = sp - call_argc;
16659
215k
                sf->cur_pc = pc;
16660
215k
                ret_val = JS_CallConstructorInternal(ctx, call_argv[-2],
16661
215k
                                                     call_argv[-1],
16662
215k
                                                     call_argc, call_argv, 0);
16663
215k
                if (unlikely(JS_IsException(ret_val)))
16664
16
                    goto exception;
16665
646k
                for(i = -2; i < call_argc; i++)
16666
431k
                    JS_FreeValue(ctx, call_argv[i]);
16667
215k
                sp -= call_argc + 2;
16668
215k
                *sp++ = ret_val;
16669
215k
            }
16670
215k
            BREAK;
16671
1.74M
        CASE(OP_call_method):
16672
1.74M
        CASE(OP_tail_call_method):
16673
1.74M
            {
16674
1.74M
                call_argc = get_u16(pc);
16675
1.74M
                pc += 2;
16676
1.74M
                call_argv = sp - call_argc;
16677
1.74M
                sf->cur_pc = pc;
16678
1.74M
                ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2],
16679
1.74M
                                          JS_UNDEFINED, call_argc, call_argv, 0);
16680
1.74M
                if (unlikely(JS_IsException(ret_val)))
16681
679
                    goto exception;
16682
1.74M
                if (opcode == OP_tail_call_method)
16683
0
                    goto done;
16684
6.70M
                for(i = -2; i < call_argc; i++)
16685
4.96M
                    JS_FreeValue(ctx, call_argv[i]);
16686
1.74M
                sp -= call_argc + 2;
16687
1.74M
                *sp++ = ret_val;
16688
1.74M
            }
16689
1.74M
            BREAK;
16690
1.74M
        CASE(OP_array_from):
16691
185k
            {
16692
185k
                int i, ret;
16693
16694
185k
                call_argc = get_u16(pc);
16695
185k
                pc += 2;
16696
185k
                ret_val = JS_NewArray(ctx);
16697
185k
                if (unlikely(JS_IsException(ret_val)))
16698
0
                    goto exception;
16699
185k
                call_argv = sp - call_argc;
16700
210k
                for(i = 0; i < call_argc; i++) {
16701
24.6k
                    ret = JS_DefinePropertyValue(ctx, ret_val, __JS_AtomFromUInt32(i), call_argv[i],
16702
24.6k
                                                 JS_PROP_C_W_E | JS_PROP_THROW);
16703
24.6k
                    call_argv[i] = JS_UNDEFINED;
16704
24.6k
                    if (ret < 0) {
16705
0
                        JS_FreeValue(ctx, ret_val);
16706
0
                        goto exception;
16707
0
                    }
16708
24.6k
                }
16709
185k
                sp -= call_argc;
16710
185k
                *sp++ = ret_val;
16711
185k
            }
16712
185k
            BREAK;
16713
16714
185k
        CASE(OP_apply):
16715
2.61k
            {
16716
2.61k
                int magic;
16717
2.61k
                magic = get_u16(pc);
16718
2.61k
                pc += 2;
16719
16720
2.61k
                ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic);
16721
2.61k
                if (unlikely(JS_IsException(ret_val)))
16722
0
                    goto exception;
16723
2.61k
                JS_FreeValue(ctx, sp[-3]);
16724
2.61k
                JS_FreeValue(ctx, sp[-2]);
16725
2.61k
                JS_FreeValue(ctx, sp[-1]);
16726
2.61k
                sp -= 3;
16727
2.61k
                *sp++ = ret_val;
16728
2.61k
            }
16729
2.61k
            BREAK;
16730
1.15M
        CASE(OP_return):
16731
1.15M
            ret_val = *--sp;
16732
1.15M
            goto done;
16733
431k
        CASE(OP_return_undef):
16734
431k
            ret_val = JS_UNDEFINED;
16735
431k
            goto done;
16736
16737
0
        CASE(OP_check_ctor_return):
16738
            /* return TRUE if 'this' should be returned */
16739
0
            if (!JS_IsObject(sp[-1])) {
16740
0
                if (!JS_IsUndefined(sp[-1])) {
16741
0
                    JS_ThrowTypeError(caller_ctx, "derived class constructor must return an object or undefined");
16742
0
                    goto exception;
16743
0
                }
16744
0
                sp[0] = JS_TRUE;
16745
0
            } else {
16746
0
                sp[0] = JS_FALSE;
16747
0
            }
16748
0
            sp++;
16749
0
            BREAK;
16750
215k
        CASE(OP_check_ctor):
16751
215k
            if (JS_IsUndefined(new_target)) {
16752
7
                JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'");
16753
7
                goto exception;
16754
7
            }
16755
215k
            BREAK;
16756
215k
        CASE(OP_check_brand):
16757
0
            if (JS_CheckBrand(ctx, sp[-2], sp[-1]) < 0)
16758
0
                goto exception;
16759
0
            BREAK;
16760
13.9k
        CASE(OP_add_brand):
16761
13.9k
            if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0)
16762
0
                goto exception;
16763
13.9k
            JS_FreeValue(ctx, sp[-2]);
16764
13.9k
            JS_FreeValue(ctx, sp[-1]);
16765
13.9k
            sp -= 2;
16766
13.9k
            BREAK;
16767
            
16768
13.9k
        CASE(OP_throw):
16769
0
            JS_Throw(ctx, *--sp);
16770
0
            goto exception;
16771
16772
0
        CASE(OP_throw_error):
16773
41
#define JS_THROW_VAR_RO             0
16774
0
#define JS_THROW_VAR_REDECL         1
16775
0
#define JS_THROW_VAR_UNINITIALIZED  2
16776
0
#define JS_THROW_ERROR_DELETE_SUPER   3
16777
193
#define JS_THROW_ERROR_ITERATOR_THROW 4
16778
0
            {
16779
0
                JSAtom atom;
16780
0
                int type;
16781
0
                atom = get_u32(pc);
16782
0
                type = pc[4];
16783
0
                pc += 5;
16784
0
                if (type == JS_THROW_VAR_RO)
16785
0
                    JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, atom);
16786
0
                else
16787
0
                if (type == JS_THROW_VAR_REDECL)
16788
0
                    JS_ThrowSyntaxErrorVarRedeclaration(ctx, atom);
16789
0
                else
16790
0
                if (type == JS_THROW_VAR_UNINITIALIZED)
16791
0
                    JS_ThrowReferenceErrorUninitialized(ctx, atom);
16792
0
                else
16793
0
                if (type == JS_THROW_ERROR_DELETE_SUPER)
16794
0
                    JS_ThrowReferenceError(ctx, "unsupported reference to 'super'");
16795
0
                else
16796
0
                if (type == JS_THROW_ERROR_ITERATOR_THROW)
16797
0
                    JS_ThrowTypeError(ctx, "iterator does not have a throw method");
16798
0
                else
16799
0
                    JS_ThrowInternalError(ctx, "invalid throw var type %d", type);
16800
0
            }
16801
0
            goto exception;
16802
16803
542
        CASE(OP_eval):
16804
542
            {
16805
542
                JSValueConst obj;
16806
542
                int scope_idx;
16807
542
                call_argc = get_u16(pc);
16808
542
                scope_idx = get_u16(pc + 2) - 1;
16809
542
                pc += 4;
16810
542
                call_argv = sp - call_argc;
16811
542
                sf->cur_pc = pc;
16812
542
                if (js_same_value(ctx, call_argv[-1], ctx->eval_obj)) {
16813
542
                    if (call_argc >= 1)
16814
536
                        obj = call_argv[0];
16815
6
                    else
16816
6
                        obj = JS_UNDEFINED;
16817
542
                    ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
16818
542
                                            JS_EVAL_TYPE_DIRECT, scope_idx);
16819
542
                } else {
16820
0
                    ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
16821
0
                                              JS_UNDEFINED, call_argc, call_argv, 0);
16822
0
                }
16823
542
                if (unlikely(JS_IsException(ret_val)))
16824
0
                    goto exception;
16825
1.62k
                for(i = -1; i < call_argc; i++)
16826
1.07k
                    JS_FreeValue(ctx, call_argv[i]);
16827
542
                sp -= call_argc + 1;
16828
542
                *sp++ = ret_val;
16829
542
            }
16830
542
            BREAK;
16831
            /* could merge with OP_apply */
16832
542
        CASE(OP_apply_eval):
16833
0
            {
16834
0
                int scope_idx;
16835
0
                uint32_t len;
16836
0
                JSValue *tab;
16837
0
                JSValueConst obj;
16838
16839
0
                scope_idx = get_u16(pc) - 1;
16840
0
                pc += 2;
16841
0
                tab = build_arg_list(ctx, &len, sp[-1]);
16842
0
                if (!tab)
16843
0
                    goto exception;
16844
0
                if (js_same_value(ctx, sp[-2], ctx->eval_obj)) {
16845
0
                    if (len >= 1)
16846
0
                        obj = tab[0];
16847
0
                    else
16848
0
                        obj = JS_UNDEFINED;
16849
0
                    ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
16850
0
                                            JS_EVAL_TYPE_DIRECT, scope_idx);
16851
0
                } else {
16852
0
                    ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len,
16853
0
                                      (JSValueConst *)tab);
16854
0
                }
16855
0
                free_arg_list(ctx, tab, len);
16856
0
                if (unlikely(JS_IsException(ret_val)))
16857
0
                    goto exception;
16858
0
                JS_FreeValue(ctx, sp[-2]);
16859
0
                JS_FreeValue(ctx, sp[-1]);
16860
0
                sp -= 2;
16861
0
                *sp++ = ret_val;
16862
0
            }
16863
0
            BREAK;
16864
16865
19.3k
        CASE(OP_regexp):
16866
19.3k
            {
16867
19.3k
                sp[-2] = js_regexp_constructor_internal(ctx, JS_UNDEFINED,
16868
19.3k
                                                        sp[-2], sp[-1]);
16869
19.3k
                sp--;
16870
19.3k
            }
16871
19.3k
            BREAK;
16872
16873
19.3k
        CASE(OP_get_super):
16874
0
            {
16875
0
                JSValue proto;
16876
0
                proto = JS_GetPrototype(ctx, sp[-1]);
16877
0
                if (JS_IsException(proto))
16878
0
                    goto exception;
16879
0
                JS_FreeValue(ctx, sp[-1]);
16880
0
                sp[-1] = proto;
16881
0
            }
16882
0
            BREAK;
16883
16884
208k
        CASE(OP_import):
16885
208k
            {
16886
208k
                JSValue val;
16887
208k
                val = js_dynamic_import(ctx, sp[-1]);
16888
208k
                if (JS_IsException(val))
16889
4
                    goto exception;
16890
208k
                JS_FreeValue(ctx, sp[-1]);
16891
208k
                sp[-1] = val;
16892
208k
            }
16893
208k
            BREAK;
16894
16895
419k
        CASE(OP_check_var):
16896
419k
            {
16897
419k
                int ret;
16898
419k
                JSAtom atom;
16899
419k
                atom = get_u32(pc);
16900
419k
                pc += 4;
16901
16902
419k
                ret = JS_CheckGlobalVar(ctx, atom);
16903
419k
                if (ret < 0)
16904
0
                    goto exception;
16905
419k
                *sp++ = JS_NewBool(ctx, ret);
16906
419k
            }
16907
419k
            BREAK;
16908
16909
419k
        CASE(OP_get_var_undef):
16910
626k
        CASE(OP_get_var):
16911
626k
            {
16912
626k
                JSValue val;
16913
626k
                JSAtom atom;
16914
626k
                atom = get_u32(pc);
16915
626k
                pc += 4;
16916
16917
626k
                val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef);
16918
626k
                if (unlikely(JS_IsException(val)))
16919
202
                    goto exception;
16920
626k
                *sp++ = val;
16921
626k
            }
16922
626k
            BREAK;
16923
16924
721k
        CASE(OP_put_var):
16925
721k
        CASE(OP_put_var_init):
16926
721k
            {
16927
721k
                int ret;
16928
721k
                JSAtom atom;
16929
721k
                atom = get_u32(pc);
16930
721k
                pc += 4;
16931
16932
721k
                ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var);
16933
721k
                sp--;
16934
721k
                if (unlikely(ret < 0))
16935
0
                    goto exception;
16936
721k
            }
16937
721k
            BREAK;
16938
16939
721k
        CASE(OP_put_var_strict):
16940
419k
            {
16941
419k
                int ret;
16942
419k
                JSAtom atom;
16943
419k
                atom = get_u32(pc);
16944
419k
                pc += 4;
16945
16946
                /* sp[-2] is JS_TRUE or JS_FALSE */
16947
419k
                if (unlikely(!JS_VALUE_GET_INT(sp[-2]))) {
16948
11
                    JS_ThrowReferenceErrorNotDefined(ctx, atom);
16949
11
                    goto exception;
16950
11
                }
16951
419k
                ret = JS_SetGlobalVar(ctx, atom, sp[-1], 2);
16952
419k
                sp -= 2;
16953
419k
                if (unlikely(ret < 0))
16954
0
                    goto exception;
16955
419k
            }
16956
419k
            BREAK;
16957
16958
419k
        CASE(OP_check_define_var):
16959
8.60k
            {
16960
8.60k
                JSAtom atom;
16961
8.60k
                int flags;
16962
8.60k
                atom = get_u32(pc);
16963
8.60k
                flags = pc[4];
16964
8.60k
                pc += 5;
16965
8.60k
                if (JS_CheckDefineGlobalVar(ctx, atom, flags))
16966
1
                    goto exception;
16967
8.60k
            }
16968
8.60k
            BREAK;
16969
8.60k
        CASE(OP_define_var):
16970
7.62k
            {
16971
7.62k
                JSAtom atom;
16972
7.62k
                int flags;
16973
7.62k
                atom = get_u32(pc);
16974
7.62k
                flags = pc[4];
16975
7.62k
                pc += 5;
16976
7.62k
                if (JS_DefineGlobalVar(ctx, atom, flags))
16977
0
                    goto exception;
16978
7.62k
            }
16979
7.62k
            BREAK;
16980
7.62k
        CASE(OP_define_func):
16981
971
            {
16982
971
                JSAtom atom;
16983
971
                int flags;
16984
971
                atom = get_u32(pc);
16985
971
                flags = pc[4];
16986
971
                pc += 5;
16987
971
                if (JS_DefineGlobalFunction(ctx, atom, sp[-1], flags))
16988
0
                    goto exception;
16989
971
                JS_FreeValue(ctx, sp[-1]);
16990
971
                sp--;
16991
971
            }
16992
971
            BREAK;
16993
16994
37.5k
        CASE(OP_get_loc):
16995
37.5k
            {
16996
37.5k
                int idx;
16997
37.5k
                idx = get_u16(pc);
16998
37.5k
                pc += 2;
16999
37.5k
                sp[0] = JS_DupValue(ctx, var_buf[idx]);
17000
37.5k
                sp++;
17001
37.5k
            }
17002
37.5k
            BREAK;
17003
37.5k
        CASE(OP_put_loc):
17004
27.7k
            {
17005
27.7k
                int idx;
17006
27.7k
                idx = get_u16(pc);
17007
27.7k
                pc += 2;
17008
27.7k
                set_value(ctx, &var_buf[idx], sp[-1]);
17009
27.7k
                sp--;
17010
27.7k
            }
17011
27.7k
            BREAK;
17012
27.7k
        CASE(OP_set_loc):
17013
12.0k
            {
17014
12.0k
                int idx;
17015
12.0k
                idx = get_u16(pc);
17016
12.0k
                pc += 2;
17017
12.0k
                set_value(ctx, &var_buf[idx], JS_DupValue(ctx, sp[-1]));
17018
12.0k
            }
17019
12.0k
            BREAK;
17020
12.0k
        CASE(OP_get_arg):
17021
498
            {
17022
498
                int idx;
17023
498
                idx = get_u16(pc);
17024
498
                pc += 2;
17025
498
                sp[0] = JS_DupValue(ctx, arg_buf[idx]);
17026
498
                sp++;
17027
498
            }
17028
498
            BREAK;
17029
498
        CASE(OP_put_arg):
17030
6
            {
17031
6
                int idx;
17032
6
                idx = get_u16(pc);
17033
6
                pc += 2;
17034
6
                set_value(ctx, &arg_buf[idx], sp[-1]);
17035
6
                sp--;
17036
6
            }
17037
6
            BREAK;
17038
600
        CASE(OP_set_arg):
17039
600
            {
17040
600
                int idx;
17041
600
                idx = get_u16(pc);
17042
600
                pc += 2;
17043
600
                set_value(ctx, &arg_buf[idx], JS_DupValue(ctx, sp[-1]));
17044
600
            }
17045
600
            BREAK;
17046
17047
600
#if SHORT_OPCODES
17048
2.68M
        CASE(OP_get_loc8): *sp++ = JS_DupValue(ctx, var_buf[*pc++]); BREAK;
17049
2.79M
        CASE(OP_put_loc8): set_value(ctx, &var_buf[*pc++], *--sp); BREAK;
17050
2.79M
        CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], JS_DupValue(ctx, sp[-1])); BREAK;
17051
17052
973k
        CASE(OP_get_loc0): *sp++ = JS_DupValue(ctx, var_buf[0]); BREAK;
17053
973k
        CASE(OP_get_loc1): *sp++ = JS_DupValue(ctx, var_buf[1]); BREAK;
17054
470k
        CASE(OP_get_loc2): *sp++ = JS_DupValue(ctx, var_buf[2]); BREAK;
17055
501k
        CASE(OP_get_loc3): *sp++ = JS_DupValue(ctx, var_buf[3]); BREAK;
17056
3.15M
        CASE(OP_put_loc0): set_value(ctx, &var_buf[0], *--sp); BREAK;
17057
3.15M
        CASE(OP_put_loc1): set_value(ctx, &var_buf[1], *--sp); BREAK;
17058
411k
        CASE(OP_put_loc2): set_value(ctx, &var_buf[2], *--sp); BREAK;
17059
227k
        CASE(OP_put_loc3): set_value(ctx, &var_buf[3], *--sp); BREAK;
17060
200k
        CASE(OP_set_loc0): set_value(ctx, &var_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;
17061
2.25k
        CASE(OP_set_loc1): set_value(ctx, &var_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;
17062
3.00k
        CASE(OP_set_loc2): set_value(ctx, &var_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;
17063
19.1k
        CASE(OP_set_loc3): set_value(ctx, &var_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;
17064
37.1k
        CASE(OP_get_arg0): *sp++ = JS_DupValue(ctx, arg_buf[0]); BREAK;
17065
37.1k
        CASE(OP_get_arg1): *sp++ = JS_DupValue(ctx, arg_buf[1]); BREAK;
17066
19.7k
        CASE(OP_get_arg2): *sp++ = JS_DupValue(ctx, arg_buf[2]); BREAK;
17067
18.4k
        CASE(OP_get_arg3): *sp++ = JS_DupValue(ctx, arg_buf[3]); BREAK;
17068
464k
        CASE(OP_put_arg0): set_value(ctx, &arg_buf[0], *--sp); BREAK;
17069
464k
        CASE(OP_put_arg1): set_value(ctx, &arg_buf[1], *--sp); BREAK;
17070
16
        CASE(OP_put_arg2): set_value(ctx, &arg_buf[2], *--sp); BREAK;
17071
17
        CASE(OP_put_arg3): set_value(ctx, &arg_buf[3], *--sp); BREAK;
17072
464k
        CASE(OP_set_arg0): set_value(ctx, &arg_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;
17073
464k
        CASE(OP_set_arg1): set_value(ctx, &arg_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;
17074
13.5k
        CASE(OP_set_arg2): set_value(ctx, &arg_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;
17075
13.5k
        CASE(OP_set_arg3): set_value(ctx, &arg_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;
17076
18.8k
        CASE(OP_get_var_ref0): *sp++ = JS_DupValue(ctx, *var_refs[0]->pvalue); BREAK;
17077
32.9k
        CASE(OP_get_var_ref1): *sp++ = JS_DupValue(ctx, *var_refs[1]->pvalue); BREAK;
17078
32.9k
        CASE(OP_get_var_ref2): *sp++ = JS_DupValue(ctx, *var_refs[2]->pvalue); BREAK;
17079
32.1k
        CASE(OP_get_var_ref3): *sp++ = JS_DupValue(ctx, *var_refs[3]->pvalue); BREAK;
17080
26.2k
        CASE(OP_put_var_ref0): set_value(ctx, var_refs[0]->pvalue, *--sp); BREAK;
17081
822
        CASE(OP_put_var_ref1): set_value(ctx, var_refs[1]->pvalue, *--sp); BREAK;
17082
17.3k
        CASE(OP_put_var_ref2): set_value(ctx, var_refs[2]->pvalue, *--sp); BREAK;
17083
17.3k
        CASE(OP_put_var_ref3): set_value(ctx, var_refs[3]->pvalue, *--sp); BREAK;
17084
12.2k
        CASE(OP_set_var_ref0): set_value(ctx, var_refs[0]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17085
20.1k
        CASE(OP_set_var_ref1): set_value(ctx, var_refs[1]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17086
20.1k
        CASE(OP_set_var_ref2): set_value(ctx, var_refs[2]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17087
1.00k
        CASE(OP_set_var_ref3): set_value(ctx, var_refs[3]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17088
73
#endif
17089
17090
172
        CASE(OP_get_var_ref):
17091
172
            {
17092
172
                int idx;
17093
172
                JSValue val;
17094
172
                idx = get_u16(pc);
17095
172
                pc += 2;
17096
172
                val = *var_refs[idx]->pvalue;
17097
172
                sp[0] = JS_DupValue(ctx, val);
17098
172
                sp++;
17099
172
            }
17100
172
            BREAK;
17101
172
        CASE(OP_put_var_ref):
17102
58
            {
17103
58
                int idx;
17104
58
                idx = get_u16(pc);
17105
58
                pc += 2;
17106
58
                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
17107
58
                sp--;
17108
58
            }
17109
58
            BREAK;
17110
626
        CASE(OP_set_var_ref):
17111
626
            {
17112
626
                int idx;
17113
626
                idx = get_u16(pc);
17114
626
                pc += 2;
17115
626
                set_value(ctx, var_refs[idx]->pvalue, JS_DupValue(ctx, sp[-1]));
17116
626
            }
17117
626
            BREAK;
17118
1.28M
        CASE(OP_get_var_ref_check):
17119
1.28M
            {
17120
1.28M
                int idx;
17121
1.28M
                JSValue val;
17122
1.28M
                idx = get_u16(pc);
17123
1.28M
                pc += 2;
17124
1.28M
                val = *var_refs[idx]->pvalue;
17125
1.28M
                if (unlikely(JS_IsUninitialized(val))) {
17126
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
17127
0
                    goto exception;
17128
0
                }
17129
1.28M
                sp[0] = JS_DupValue(ctx, val);
17130
1.28M
                sp++;
17131
1.28M
            }
17132
1.28M
            BREAK;
17133
1.28M
        CASE(OP_put_var_ref_check):
17134
1.29k
            {
17135
1.29k
                int idx;
17136
1.29k
                idx = get_u16(pc);
17137
1.29k
                pc += 2;
17138
1.29k
                if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) {
17139
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
17140
0
                    goto exception;
17141
0
                }
17142
1.29k
                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
17143
1.29k
                sp--;
17144
1.29k
            }
17145
1.29k
            BREAK;
17146
1.29k
        CASE(OP_put_var_ref_check_init):
17147
0
            {
17148
0
                int idx;
17149
0
                idx = get_u16(pc);
17150
0
                pc += 2;
17151
0
                if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) {
17152
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
17153
0
                    goto exception;
17154
0
                }
17155
0
                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
17156
0
                sp--;
17157
0
            }
17158
0
            BREAK;
17159
2.24M
        CASE(OP_set_loc_uninitialized):
17160
2.24M
            {
17161
2.24M
                int idx;
17162
2.24M
                idx = get_u16(pc);
17163
2.24M
                pc += 2;
17164
2.24M
                set_value(ctx, &var_buf[idx], JS_UNINITIALIZED);
17165
2.24M
            }
17166
2.24M
            BREAK;
17167
2.24M
        CASE(OP_get_loc_check):
17168
1.12M
            {
17169
1.12M
                int idx;
17170
1.12M
                idx = get_u16(pc);
17171
1.12M
                pc += 2;
17172
1.12M
                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
17173
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
17174
0
                    goto exception;
17175
0
                }
17176
1.12M
                sp[0] = JS_DupValue(ctx, var_buf[idx]);
17177
1.12M
                sp++;
17178
1.12M
            }
17179
1.12M
            BREAK;
17180
1.15M
        CASE(OP_put_loc_check):
17181
1.15M
            {
17182
1.15M
                int idx;
17183
1.15M
                idx = get_u16(pc);
17184
1.15M
                pc += 2;
17185
1.15M
                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
17186
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
17187
0
                    goto exception;
17188
0
                }
17189
1.15M
                set_value(ctx, &var_buf[idx], sp[-1]);
17190
1.15M
                sp--;
17191
1.15M
            }
17192
1.15M
            BREAK;
17193
1.15M
        CASE(OP_put_loc_check_init):
17194
0
            {
17195
0
                int idx;
17196
0
                idx = get_u16(pc);
17197
0
                pc += 2;
17198
0
                if (unlikely(!JS_IsUninitialized(var_buf[idx]))) {
17199
0
                    JS_ThrowReferenceError(ctx, "'this' can be initialized only once");
17200
0
                    goto exception;
17201
0
                }
17202
0
                set_value(ctx, &var_buf[idx], sp[-1]);
17203
0
                sp--;
17204
0
            }
17205
0
            BREAK;
17206
2.24M
        CASE(OP_close_loc):
17207
2.24M
            {
17208
2.24M
                int idx;
17209
2.24M
                idx = get_u16(pc);
17210
2.24M
                pc += 2;
17211
2.24M
                close_lexical_var(ctx, sf, idx, FALSE);
17212
2.24M
            }
17213
2.24M
            BREAK;
17214
17215
2.24M
        CASE(OP_make_loc_ref):
17216
12.4k
        CASE(OP_make_arg_ref):
17217
12.4k
        CASE(OP_make_var_ref_ref):
17218
12.4k
            {
17219
12.4k
                JSVarRef *var_ref;
17220
12.4k
                JSProperty *pr;
17221
12.4k
                JSAtom atom;
17222
12.4k
                int idx;
17223
12.4k
                atom = get_u32(pc);
17224
12.4k
                idx = get_u16(pc + 4);
17225
12.4k
                pc += 6;
17226
12.4k
                *sp++ = JS_NewObjectProto(ctx, JS_NULL);
17227
12.4k
                if (unlikely(JS_IsException(sp[-1])))
17228
0
                    goto exception;
17229
12.4k
                if (opcode == OP_make_var_ref_ref) {
17230
2
                    var_ref = var_refs[idx];
17231
2
                    var_ref->header.ref_count++;
17232
12.4k
                } else {
17233
12.4k
                    var_ref = get_var_ref(ctx, sf, idx, opcode == OP_make_arg_ref);
17234
12.4k
                    if (!var_ref)
17235
0
                        goto exception;
17236
12.4k
                }
17237
12.4k
                pr = add_property(ctx, JS_VALUE_GET_OBJ(sp[-1]), atom,
17238
12.4k
                                  JS_PROP_WRITABLE | JS_PROP_VARREF);
17239
12.4k
                if (!pr) {
17240
0
                    free_var_ref(rt, var_ref);
17241
0
                    goto exception;
17242
0
                }
17243
12.4k
                pr->u.var_ref = var_ref;
17244
12.4k
                *sp++ = JS_AtomToValue(ctx, atom);
17245
12.4k
            }
17246
12.4k
            BREAK;
17247
1.09M
        CASE(OP_make_var_ref):
17248
1.09M
            {
17249
1.09M
                JSAtom atom;
17250
1.09M
                atom = get_u32(pc);
17251
1.09M
                pc += 4;
17252
17253
1.09M
                if (JS_GetGlobalVarRef(ctx, atom, sp))
17254
0
                    goto exception;
17255
1.09M
                sp += 2;
17256
1.09M
            }
17257
1.09M
            BREAK;
17258
17259
1.09M
        CASE(OP_goto):
17260
4
            pc += (int32_t)get_u32(pc);
17261
4
            if (unlikely(js_poll_interrupts(ctx)))
17262
0
                goto exception;
17263
4
            BREAK;
17264
4
#if SHORT_OPCODES
17265
1.66M
        CASE(OP_goto16):
17266
1.66M
            pc += (int16_t)get_u16(pc);
17267
1.66M
            if (unlikely(js_poll_interrupts(ctx)))
17268
3
                goto exception;
17269
1.66M
            BREAK;
17270
1.66M
        CASE(OP_goto8):
17271
1.45M
            pc += (int8_t)pc[0];
17272
1.45M
            if (unlikely(js_poll_interrupts(ctx)))
17273
2
                goto exception;
17274
1.45M
            BREAK;
17275
1.45M
#endif
17276
1.45M
        CASE(OP_if_true):
17277
6
            {
17278
6
                int res;
17279
6
                JSValue op1;
17280
17281
6
                op1 = sp[-1];
17282
6
                pc += 4;
17283
6
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17284
3
                    res = JS_VALUE_GET_INT(op1);
17285
3
                } else {
17286
3
                    res = JS_ToBoolFree(ctx, op1);
17287
3
                }
17288
6
                sp--;
17289
6
                if (res) {
17290
4
                    pc += (int32_t)get_u32(pc - 4) - 4;
17291
4
                }
17292
6
                if (unlikely(js_poll_interrupts(ctx)))
17293
0
                    goto exception;
17294
6
            }
17295
6
            BREAK;
17296
1.78M
        CASE(OP_if_false):
17297
1.78M
            {
17298
1.78M
                int res;
17299
1.78M
                JSValue op1;
17300
17301
1.78M
                op1 = sp[-1];
17302
1.78M
                pc += 4;
17303
1.78M
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17304
1.78M
                    res = JS_VALUE_GET_INT(op1);
17305
1.78M
                } else {
17306
15
                    res = JS_ToBoolFree(ctx, op1);
17307
15
                }
17308
1.78M
                sp--;
17309
1.78M
                if (!res) {
17310
1.06M
                    pc += (int32_t)get_u32(pc - 4) - 4;
17311
1.06M
                }
17312
1.78M
                if (unlikely(js_poll_interrupts(ctx)))
17313
0
                    goto exception;
17314
1.78M
            }
17315
1.78M
            BREAK;
17316
1.78M
#if SHORT_OPCODES
17317
1.78M
        CASE(OP_if_true8):
17318
314k
            {
17319
314k
                int res;
17320
314k
                JSValue op1;
17321
17322
314k
                op1 = sp[-1];
17323
314k
                pc += 1;
17324
314k
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17325
314k
                    res = JS_VALUE_GET_INT(op1);
17326
314k
                } else {
17327
0
                    res = JS_ToBoolFree(ctx, op1);
17328
0
                }
17329
314k
                sp--;
17330
314k
                if (res) {
17331
311k
                    pc += (int8_t)pc[-1] - 1;
17332
311k
                }
17333
314k
                if (unlikely(js_poll_interrupts(ctx)))
17334
0
                    goto exception;
17335
314k
            }
17336
314k
            BREAK;
17337
1.38M
        CASE(OP_if_false8):
17338
1.38M
            {
17339
1.38M
                int res;
17340
1.38M
                JSValue op1;
17341
17342
1.38M
                op1 = sp[-1];
17343
1.38M
                pc += 1;
17344
1.38M
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17345
1.17M
                    res = JS_VALUE_GET_INT(op1);
17346
1.17M
                } else {
17347
215k
                    res = JS_ToBoolFree(ctx, op1);
17348
215k
                }
17349
1.38M
                sp--;
17350
1.38M
                if (!res) {
17351
986k
                    pc += (int8_t)pc[-1] - 1;
17352
986k
                }
17353
1.38M
                if (unlikely(js_poll_interrupts(ctx)))
17354
2
                    goto exception;
17355
1.38M
            }
17356
1.38M
            BREAK;
17357
1.38M
#endif
17358
1.38M
        CASE(OP_catch):
17359
0
            {
17360
0
                int32_t diff;
17361
0
                diff = get_u32(pc);
17362
0
                sp[0] = JS_NewCatchOffset(ctx, pc + diff - b->byte_code_buf);
17363
0
                sp++;
17364
0
                pc += 4;
17365
0
            }
17366
0
            BREAK;
17367
0
        CASE(OP_gosub):
17368
0
            {
17369
0
                int32_t diff;
17370
0
                diff = get_u32(pc);
17371
                /* XXX: should have a different tag to avoid security flaw */
17372
0
                sp[0] = JS_NewInt32(ctx, pc + 4 - b->byte_code_buf);
17373
0
                sp++;
17374
0
                pc += diff;
17375
0
            }
17376
0
            BREAK;
17377
0
        CASE(OP_ret):
17378
0
            {
17379
0
                JSValue op1;
17380
0
                uint32_t pos;
17381
0
                op1 = sp[-1];
17382
0
                if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_INT))
17383
0
                    goto ret_fail;
17384
0
                pos = JS_VALUE_GET_INT(op1);
17385
0
                if (unlikely(pos >= b->byte_code_len)) {
17386
0
                ret_fail:
17387
0
                    JS_ThrowInternalError(ctx, "invalid ret value");
17388
0
                    goto exception;
17389
0
                }
17390
0
                sp--;
17391
0
                pc = b->byte_code_buf + pos;
17392
0
            }
17393
0
            BREAK;
17394
17395
734k
        CASE(OP_for_in_start):
17396
734k
            if (js_for_in_start(ctx, sp))
17397
2
                goto exception;
17398
734k
            BREAK;
17399
2.52M
        CASE(OP_for_in_next):
17400
2.52M
            if (js_for_in_next(ctx, sp))
17401
0
                goto exception;
17402
2.52M
            sp += 2;
17403
2.52M
            BREAK;
17404
2.52M
        CASE(OP_for_of_start):
17405
165k
            if (js_for_of_start(ctx, sp, FALSE))
17406
2
                goto exception;
17407
165k
            sp += 1;
17408
165k
            *sp++ = JS_NewCatchOffset(ctx, 0);
17409
165k
            BREAK;
17410
403k
        CASE(OP_for_of_next):
17411
403k
            {
17412
403k
                int offset = -3 - pc[0];
17413
403k
                pc += 1;
17414
403k
                if (js_for_of_next(ctx, sp, offset))
17415
0
                    goto exception;
17416
403k
                sp += 2;
17417
403k
            }
17418
403k
            BREAK;
17419
403k
        CASE(OP_for_await_of_start):
17420
0
            if (js_for_of_start(ctx, sp, TRUE))
17421
0
                goto exception;
17422
0
            sp += 1;
17423
0
            *sp++ = JS_NewCatchOffset(ctx, 0);
17424
0
            BREAK;
17425
0
        CASE(OP_iterator_get_value_done):
17426
0
            if (js_iterator_get_value_done(ctx, sp))
17427
0
                goto exception;
17428
0
            sp += 1;
17429
0
            BREAK;
17430
0
        CASE(OP_iterator_check_object):
17431
0
            if (unlikely(!JS_IsObject(sp[-1]))) {
17432
0
                JS_ThrowTypeError(ctx, "iterator must return an object");
17433
0
                goto exception;
17434
0
            }
17435
0
            BREAK;
17436
17437
165k
        CASE(OP_iterator_close):
17438
            /* iter_obj next catch_offset -> */
17439
165k
            sp--; /* drop the catch offset to avoid getting caught by exception */
17440
165k
            JS_FreeValue(ctx, sp[-1]); /* drop the next method */
17441
165k
            sp--;
17442
165k
            if (!JS_IsUndefined(sp[-1])) {
17443
164k
                if (JS_IteratorClose(ctx, sp[-1], FALSE))
17444
0
                    goto exception;
17445
164k
                JS_FreeValue(ctx, sp[-1]);
17446
164k
            }
17447
165k
            sp--;
17448
165k
            BREAK;
17449
165k
        CASE(OP_iterator_close_return):
17450
0
            {
17451
0
                JSValue ret_val;
17452
                /* iter_obj next catch_offset ... ret_val ->
17453
                   ret_eval iter_obj next catch_offset */
17454
0
                ret_val = *--sp;
17455
0
                while (sp > stack_buf &&
17456
0
                       JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) {
17457
0
                    JS_FreeValue(ctx, *--sp);
17458
0
                }
17459
0
                if (unlikely(sp < stack_buf + 3)) {
17460
0
                    JS_ThrowInternalError(ctx, "iterator_close_return");
17461
0
                    JS_FreeValue(ctx, ret_val);
17462
0
                    goto exception;
17463
0
                }
17464
0
                sp[0] = sp[-1];
17465
0
                sp[-1] = sp[-2];
17466
0
                sp[-2] = sp[-3];
17467
0
                sp[-3] = ret_val;
17468
0
                sp++;
17469
0
            }
17470
0
            BREAK;
17471
17472
0
        CASE(OP_iterator_next):
17473
            /* stack: iter_obj next catch_offset val */
17474
0
            {
17475
0
                JSValue ret;
17476
0
                ret = JS_Call(ctx, sp[-3], sp[-4],
17477
0
                              1, (JSValueConst *)(sp - 1));
17478
0
                if (JS_IsException(ret))
17479
0
                    goto exception;
17480
0
                JS_FreeValue(ctx, sp[-1]);
17481
0
                sp[-1] = ret;
17482
0
            }
17483
0
            BREAK;
17484
17485
0
        CASE(OP_iterator_call):
17486
            /* stack: iter_obj next catch_offset val */
17487
0
            {
17488
0
                JSValue method, ret;
17489
0
                BOOL ret_flag;
17490
0
                int flags;
17491
0
                flags = *pc++;
17492
0
                method = JS_GetProperty(ctx, sp[-4], (flags & 1) ?
17493
0
                                        JS_ATOM_throw : JS_ATOM_return);
17494
0
                if (JS_IsException(method))
17495
0
                    goto exception;
17496
0
                if (JS_IsUndefined(method) || JS_IsNull(method)) {
17497
0
                    ret_flag = TRUE;
17498
0
                } else {
17499
0
                    if (flags & 2) {
17500
                        /* no argument */
17501
0
                        ret = JS_CallFree(ctx, method, sp[-4],
17502
0
                                          0, NULL);
17503
0
                    } else {
17504
0
                        ret = JS_CallFree(ctx, method, sp[-4],
17505
0
                                          1, (JSValueConst *)(sp - 1));
17506
0
                    }
17507
0
                    if (JS_IsException(ret))
17508
0
                        goto exception;
17509
0
                    JS_FreeValue(ctx, sp[-1]);
17510
0
                    sp[-1] = ret;
17511
0
                    ret_flag = FALSE;
17512
0
                }
17513
0
                sp[0] = JS_NewBool(ctx, ret_flag);
17514
0
                sp += 1;
17515
0
            }
17516
0
            BREAK;
17517
17518
14.3k
        CASE(OP_lnot):
17519
14.3k
            {
17520
14.3k
                int res;
17521
14.3k
                JSValue op1;
17522
17523
14.3k
                op1 = sp[-1];
17524
14.3k
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17525
134
                    res = JS_VALUE_GET_INT(op1) != 0;
17526
14.1k
                } else {
17527
14.1k
                    res = JS_ToBoolFree(ctx, op1);
17528
14.1k
                }
17529
14.3k
                sp[-1] = JS_NewBool(ctx, !res);
17530
14.3k
            }
17531
14.3k
            BREAK;
17532
17533
555k
        CASE(OP_get_field):
17534
555k
            {
17535
555k
                JSValue val;
17536
555k
                JSAtom atom;
17537
555k
                atom = get_u32(pc);
17538
555k
                pc += 4;
17539
17540
555k
                val = JS_GetProperty(ctx, sp[-1], atom);
17541
555k
                if (unlikely(JS_IsException(val)))
17542
0
                    goto exception;
17543
555k
                JS_FreeValue(ctx, sp[-1]);
17544
555k
                sp[-1] = val;
17545
555k
            }
17546
555k
            BREAK;
17547
17548
555k
        CASE(OP_get_field2):
17549
404k
            {
17550
404k
                JSValue val;
17551
404k
                JSAtom atom;
17552
404k
                atom = get_u32(pc);
17553
404k
                pc += 4;
17554
17555
404k
                val = JS_GetProperty(ctx, sp[-1], atom);
17556
404k
                if (unlikely(JS_IsException(val)))
17557
0
                    goto exception;
17558
404k
                *sp++ = val;
17559
404k
            }
17560
404k
            BREAK;
17561
17562
404k
        CASE(OP_put_field):
17563
24.8k
            {
17564
24.8k
                int ret;
17565
24.8k
                JSAtom atom;
17566
24.8k
                atom = get_u32(pc);
17567
24.8k
                pc += 4;
17568
17569
24.8k
                ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1],
17570
24.8k
                                             JS_PROP_THROW_STRICT);
17571
24.8k
                JS_FreeValue(ctx, sp[-2]);
17572
24.8k
                sp -= 2;
17573
24.8k
                if (unlikely(ret < 0))
17574
0
                    goto exception;
17575
24.8k
            }
17576
24.8k
            BREAK;
17577
17578
499k
        CASE(OP_private_symbol):
17579
499k
            {
17580
499k
                JSAtom atom;
17581
499k
                JSValue val;
17582
                
17583
499k
                atom = get_u32(pc);
17584
499k
                pc += 4;
17585
499k
                val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE);
17586
499k
                if (JS_IsException(val))
17587
0
                    goto exception;
17588
499k
                *sp++ = val;
17589
499k
            }
17590
499k
            BREAK;
17591
            
17592
499k
        CASE(OP_get_private_field):
17593
0
            {
17594
0
                JSValue val;
17595
17596
0
                val = JS_GetPrivateField(ctx, sp[-2], sp[-1]);
17597
0
                JS_FreeValue(ctx, sp[-1]);
17598
0
                JS_FreeValue(ctx, sp[-2]);
17599
0
                sp[-2] = val;
17600
0
                sp--;
17601
0
                if (unlikely(JS_IsException(val)))
17602
0
                    goto exception;
17603
0
            }
17604
0
            BREAK;
17605
17606
0
        CASE(OP_put_private_field):
17607
0
            {
17608
0
                int ret;
17609
0
                ret = JS_SetPrivateField(ctx, sp[-3], sp[-1], sp[-2]);
17610
0
                JS_FreeValue(ctx, sp[-3]);
17611
0
                JS_FreeValue(ctx, sp[-1]);
17612
0
                sp -= 3;
17613
0
                if (unlikely(ret < 0))
17614
0
                    goto exception;
17615
0
            }
17616
0
            BREAK;
17617
17618
409k
        CASE(OP_define_private_field):
17619
409k
            {
17620
409k
                int ret;
17621
409k
                ret = JS_DefinePrivateField(ctx, sp[-3], sp[-2], sp[-1]);
17622
409k
                JS_FreeValue(ctx, sp[-2]);
17623
409k
                sp -= 2;
17624
409k
                if (unlikely(ret < 0))
17625
0
                    goto exception;
17626
409k
            }
17627
409k
            BREAK;
17628
17629
451k
        CASE(OP_define_field):
17630
451k
            {
17631
451k
                int ret;
17632
451k
                JSAtom atom;
17633
451k
                atom = get_u32(pc);
17634
451k
                pc += 4;
17635
17636
451k
                ret = JS_DefinePropertyValue(ctx, sp[-2], atom, sp[-1],
17637
451k
                                             JS_PROP_C_W_E | JS_PROP_THROW);
17638
451k
                sp--;
17639
451k
                if (unlikely(ret < 0))
17640
0
                    goto exception;
17641
451k
            }
17642
451k
            BREAK;
17643
17644
1.24M
        CASE(OP_set_name):
17645
1.24M
            {
17646
1.24M
                int ret;
17647
1.24M
                JSAtom atom;
17648
1.24M
                atom = get_u32(pc);
17649
1.24M
                pc += 4;
17650
17651
1.24M
                ret = JS_DefineObjectName(ctx, sp[-1], atom, JS_PROP_CONFIGURABLE);
17652
1.24M
                if (unlikely(ret < 0))
17653
0
                    goto exception;
17654
1.24M
            }
17655
1.24M
            BREAK;
17656
1.24M
        CASE(OP_set_name_computed):
17657
3
            {
17658
3
                int ret;
17659
3
                ret = JS_DefineObjectNameComputed(ctx, sp[-1], sp[-2], JS_PROP_CONFIGURABLE);
17660
3
                if (unlikely(ret < 0))
17661
0
                    goto exception;
17662
3
            }
17663
3
            BREAK;
17664
3
        CASE(OP_set_proto):
17665
0
            {
17666
0
                JSValue proto;
17667
0
                proto = sp[-1];
17668
0
                if (JS_IsObject(proto) || JS_IsNull(proto)) {
17669
0
                    if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0)
17670
0
                        goto exception;
17671
0
                }
17672
0
                JS_FreeValue(ctx, proto);
17673
0
                sp--;
17674
0
            }
17675
0
            BREAK;
17676
351k
        CASE(OP_set_home_object):
17677
351k
            js_method_set_home_object(ctx, sp[-1], sp[-2]);
17678
351k
            BREAK;
17679
357k
        CASE(OP_define_method):
17680
359k
        CASE(OP_define_method_computed):
17681
359k
            {
17682
359k
                JSValue getter, setter, value;
17683
359k
                JSValueConst obj;
17684
359k
                JSAtom atom;
17685
359k
                int flags, ret, op_flags;
17686
359k
                BOOL is_computed;
17687
360k
#define OP_DEFINE_METHOD_METHOD 0
17688
359k
#define OP_DEFINE_METHOD_GETTER 1
17689
359k
#define OP_DEFINE_METHOD_SETTER 2
17690
359k
#define OP_DEFINE_METHOD_ENUMERABLE 4
17691
17692
359k
                is_computed = (opcode == OP_define_method_computed);
17693
359k
                if (is_computed) {
17694
2.24k
                    atom = JS_ValueToAtom(ctx, sp[-2]);
17695
2.24k
                    if (unlikely(atom == JS_ATOM_NULL))
17696
0
                        goto exception;
17697
2.24k
                    opcode += OP_define_method - OP_define_method_computed;
17698
357k
                } else {
17699
357k
                    atom = get_u32(pc);
17700
357k
                    pc += 4;
17701
357k
                }
17702
359k
                op_flags = *pc++;
17703
17704
359k
                obj = sp[-2 - is_computed];
17705
359k
                flags = JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE |
17706
359k
                    JS_PROP_HAS_ENUMERABLE | JS_PROP_THROW;
17707
359k
                if (op_flags & OP_DEFINE_METHOD_ENUMERABLE)
17708
0
                    flags |= JS_PROP_ENUMERABLE;
17709
359k
                op_flags &= 3;
17710
359k
                value = JS_UNDEFINED;
17711
359k
                getter = JS_UNDEFINED;
17712
359k
                setter = JS_UNDEFINED;
17713
359k
                if (op_flags == OP_DEFINE_METHOD_METHOD) {
17714
359k
                    value = sp[-1];
17715
359k
                    flags |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE;
17716
359k
                } else if (op_flags == OP_DEFINE_METHOD_GETTER) {
17717
0
                    getter = sp[-1];
17718
0
                    flags |= JS_PROP_HAS_GET;
17719
0
                } else {
17720
0
                    setter = sp[-1];
17721
0
                    flags |= JS_PROP_HAS_SET;
17722
0
                }
17723
359k
                ret = js_method_set_properties(ctx, sp[-1], atom, flags, obj);
17724
359k
                if (ret >= 0) {
17725
359k
                    ret = JS_DefineProperty(ctx, obj, atom, value,
17726
359k
                                            getter, setter, flags);
17727
359k
                }
17728
359k
                JS_FreeValue(ctx, sp[-1]);
17729
359k
                if (is_computed) {
17730
2.24k
                    JS_FreeAtom(ctx, atom);
17731
2.24k
                    JS_FreeValue(ctx, sp[-2]);
17732
2.24k
                }
17733
359k
                sp -= 1 + is_computed;
17734
359k
                if (unlikely(ret < 0))
17735
0
                    goto exception;
17736
359k
            }
17737
359k
            BREAK;
17738
17739
359k
        CASE(OP_define_class):
17740
326k
        CASE(OP_define_class_computed):
17741
326k
            {
17742
326k
                int class_flags;
17743
326k
                JSAtom atom;
17744
                
17745
326k
                atom = get_u32(pc);
17746
326k
                class_flags = pc[4];
17747
326k
                pc += 5;
17748
326k
                if (js_op_define_class(ctx, sp, atom, class_flags,
17749
326k
                                       var_refs, sf,
17750
326k
                                       (opcode == OP_define_class_computed)) < 0)
17751
0
                    goto exception;
17752
326k
            }
17753
326k
            BREAK;
17754
17755
326k
        CASE(OP_get_array_el):
17756
6.47k
            {
17757
6.47k
                JSValue val;
17758
17759
6.47k
                val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
17760
6.47k
                JS_FreeValue(ctx, sp[-2]);
17761
6.47k
                sp[-2] = val;
17762
6.47k
                sp--;
17763
6.47k
                if (unlikely(JS_IsException(val)))
17764
2
                    goto exception;
17765
6.47k
            }
17766
6.46k
            BREAK;
17767
17768
6.46k
        CASE(OP_get_array_el2):
17769
0
            {
17770
0
                JSValue val;
17771
17772
0
                val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
17773
0
                sp[-1] = val;
17774
0
                if (unlikely(JS_IsException(val)))
17775
0
                    goto exception;
17776
0
            }
17777
0
            BREAK;
17778
17779
100
        CASE(OP_get_ref_value):
17780
100
            {
17781
100
                JSValue val;
17782
100
                if (unlikely(JS_IsUndefined(sp[-2]))) {
17783
9
                    JSAtom atom = JS_ValueToAtom(ctx, sp[-1]);
17784
9
                    if (atom != JS_ATOM_NULL) {
17785
9
                        JS_ThrowReferenceErrorNotDefined(ctx, atom);
17786
9
                        JS_FreeAtom(ctx, atom);
17787
9
                    }
17788
9
                    goto exception;
17789
9
                }
17790
91
                val = JS_GetPropertyValue(ctx, sp[-2],
17791
91
                                          JS_DupValue(ctx, sp[-1]));
17792
91
                if (unlikely(JS_IsException(val)))
17793
0
                    goto exception;
17794
91
                sp[0] = val;
17795
91
                sp++;
17796
91
            }
17797
91
            BREAK;
17798
17799
91
        CASE(OP_get_super_value):
17800
0
            {
17801
0
                JSValue val;
17802
0
                JSAtom atom;
17803
0
                atom = JS_ValueToAtom(ctx, sp[-1]);
17804
0
                if (unlikely(atom == JS_ATOM_NULL))
17805
0
                    goto exception;
17806
0
                val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], FALSE);
17807
0
                JS_FreeAtom(ctx, atom);
17808
0
                if (unlikely(JS_IsException(val)))
17809
0
                    goto exception;
17810
0
                JS_FreeValue(ctx, sp[-1]);
17811
0
                JS_FreeValue(ctx, sp[-2]);
17812
0
                JS_FreeValue(ctx, sp[-3]);
17813
0
                sp[-3] = val;
17814
0
                sp -= 2;
17815
0
            }
17816
0
            BREAK;
17817
17818
24.3k
        CASE(OP_put_array_el):
17819
24.3k
            {
17820
24.3k
                int ret;
17821
17822
24.3k
                ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
17823
24.3k
                JS_FreeValue(ctx, sp[-3]);
17824
24.3k
                sp -= 3;
17825
24.3k
                if (unlikely(ret < 0))
17826
2
                    goto exception;
17827
24.3k
            }
17828
24.3k
            BREAK;
17829
17830
1.10M
        CASE(OP_put_ref_value):
17831
1.10M
            {
17832
1.10M
                int ret, flags;
17833
1.10M
                flags = JS_PROP_THROW_STRICT;
17834
1.10M
                if (unlikely(JS_IsUndefined(sp[-3]))) {
17835
32
                    if (is_strict_mode(ctx)) {
17836
0
                        JSAtom atom = JS_ValueToAtom(ctx, sp[-2]);
17837
0
                        if (atom != JS_ATOM_NULL) {
17838
0
                            JS_ThrowReferenceErrorNotDefined(ctx, atom);
17839
0
                            JS_FreeAtom(ctx, atom);
17840
0
                        }
17841
0
                        goto exception;
17842
32
                    } else {
17843
32
                        sp[-3] = JS_DupValue(ctx, ctx->global_obj);
17844
32
                    }
17845
1.10M
                } else {
17846
1.10M
                    if (is_strict_mode(ctx))
17847
540
                        flags |= JS_PROP_NO_ADD;
17848
1.10M
                }
17849
1.10M
                ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], flags);
17850
1.10M
                JS_FreeValue(ctx, sp[-3]);
17851
1.10M
                sp -= 3;
17852
1.10M
                if (unlikely(ret < 0))
17853
0
                    goto exception;
17854
1.10M
            }
17855
1.10M
            BREAK;
17856
17857
1.10M
        CASE(OP_put_super_value):
17858
0
            {
17859
0
                int ret;
17860
0
                JSAtom atom;
17861
0
                if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) {
17862
0
                    JS_ThrowTypeErrorNotAnObject(ctx);
17863
0
                    goto exception;
17864
0
                }
17865
0
                atom = JS_ValueToAtom(ctx, sp[-2]);
17866
0
                if (unlikely(atom == JS_ATOM_NULL))
17867
0
                    goto exception;
17868
0
                ret = JS_SetPropertyGeneric(ctx, sp[-3], atom, sp[-1], sp[-4],
17869
0
                                            JS_PROP_THROW_STRICT);
17870
0
                JS_FreeAtom(ctx, atom);
17871
0
                JS_FreeValue(ctx, sp[-4]);
17872
0
                JS_FreeValue(ctx, sp[-3]);
17873
0
                JS_FreeValue(ctx, sp[-2]);
17874
0
                sp -= 4;
17875
0
                if (ret < 0)
17876
0
                    goto exception;
17877
0
            }
17878
0
            BREAK;
17879
17880
2.44k
        CASE(OP_define_array_el):
17881
2.44k
            {
17882
2.44k
                int ret;
17883
2.44k
                ret = JS_DefinePropertyValueValue(ctx, sp[-3], JS_DupValue(ctx, sp[-2]), sp[-1],
17884
2.44k
                                                  JS_PROP_C_W_E | JS_PROP_THROW);
17885
2.44k
                sp -= 1;
17886
2.44k
                if (unlikely(ret < 0))
17887
0
                    goto exception;
17888
2.44k
            }
17889
2.44k
            BREAK;
17890
17891
2.62k
        CASE(OP_append):    /* array pos enumobj -- array pos */
17892
2.62k
            {
17893
2.62k
                if (js_append_enumerate(ctx, sp))
17894
2
                    goto exception;
17895
2.62k
                JS_FreeValue(ctx, *--sp);
17896
2.62k
            }
17897
2.62k
            BREAK;
17898
17899
550k
        CASE(OP_copy_data_properties):    /* target source excludeList */
17900
550k
            {
17901
                /* stack offsets (-1 based):
17902
                   2 bits for target,
17903
                   3 bits for source,
17904
                   2 bits for exclusionList */
17905
550k
                int mask;
17906
17907
550k
                mask = *pc++;
17908
550k
                if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)],
17909
550k
                                          sp[-1 - ((mask >> 2) & 7)],
17910
550k
                                          sp[-1 - ((mask >> 5) & 7)], 0))
17911
0
                    goto exception;
17912
550k
            }
17913
550k
            BREAK;
17914
17915
550k
        CASE(OP_add):
17916
476k
            {
17917
476k
                JSValue op1, op2;
17918
476k
                op1 = sp[-2];
17919
476k
                op2 = sp[-1];
17920
476k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
17921
1.00k
                    int64_t r;
17922
1.00k
                    r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2);
17923
1.00k
                    if (unlikely((int)r != r))
17924
0
                        goto add_slow;
17925
1.00k
                    sp[-2] = JS_NewInt32(ctx, r);
17926
1.00k
                    sp--;
17927
475k
                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
17928
20
                    sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) +
17929
20
                                             JS_VALUE_GET_FLOAT64(op2));
17930
20
                    sp--;
17931
475k
                } else {
17932
475k
                add_slow:
17933
475k
                    if (js_add_slow(ctx, sp))
17934
0
                        goto exception;
17935
475k
                    sp--;
17936
475k
                }
17937
476k
            }
17938
476k
            BREAK;
17939
476k
        CASE(OP_add_loc):
17940
0
            {
17941
0
                JSValue *pv;
17942
0
                int idx;
17943
0
                idx = *pc;
17944
0
                pc += 1;
17945
17946
0
                pv = &var_buf[idx];
17947
0
                if (likely(JS_VALUE_IS_BOTH_INT(*pv, sp[-1]))) {
17948
0
                    int64_t r;
17949
0
                    r = (int64_t)JS_VALUE_GET_INT(*pv) +
17950
0
                        JS_VALUE_GET_INT(sp[-1]);
17951
0
                    if (unlikely((int)r != r))
17952
0
                        goto add_loc_slow;
17953
0
                    *pv = JS_NewInt32(ctx, r);
17954
0
                    sp--;
17955
0
                } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) {
17956
0
                    JSValue op1;
17957
0
                    op1 = sp[-1];
17958
0
                    sp--;
17959
0
                    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
17960
0
                    if (JS_IsException(op1))
17961
0
                        goto exception;
17962
0
                    op1 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op1);
17963
0
                    if (JS_IsException(op1))
17964
0
                        goto exception;
17965
0
                    set_value(ctx, pv, op1);
17966
0
                } else {
17967
0
                    JSValue ops[2];
17968
0
                add_loc_slow:
17969
                    /* In case of exception, js_add_slow frees ops[0]
17970
                       and ops[1], so we must duplicate *pv */
17971
0
                    ops[0] = JS_DupValue(ctx, *pv);
17972
0
                    ops[1] = sp[-1];
17973
0
                    sp--;
17974
0
                    if (js_add_slow(ctx, ops + 2))
17975
0
                        goto exception;
17976
0
                    set_value(ctx, pv, ops[0]);
17977
0
                }
17978
0
            }
17979
0
            BREAK;
17980
179k
        CASE(OP_sub):
17981
179k
            {
17982
179k
                JSValue op1, op2;
17983
179k
                op1 = sp[-2];
17984
179k
                op2 = sp[-1];
17985
179k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
17986
116k
                    int64_t r;
17987
116k
                    r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2);
17988
116k
                    if (unlikely((int)r != r))
17989
0
                        goto binary_arith_slow;
17990
116k
                    sp[-2] = JS_NewInt32(ctx, r);
17991
116k
                    sp--;
17992
116k
                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
17993
1.48k
                    sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) -
17994
1.48k
                                             JS_VALUE_GET_FLOAT64(op2));
17995
1.48k
                    sp--;
17996
61.3k
                } else {
17997
61.3k
                    goto binary_arith_slow;
17998
61.3k
                }
17999
179k
            }
18000
118k
            BREAK;
18001
213k
        CASE(OP_mul):
18002
213k
            {
18003
213k
                JSValue op1, op2;
18004
213k
                double d;
18005
213k
                op1 = sp[-2];
18006
213k
                op2 = sp[-1];
18007
213k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18008
6.34k
                    int32_t v1, v2;
18009
6.34k
                    int64_t r;
18010
6.34k
                    v1 = JS_VALUE_GET_INT(op1);
18011
6.34k
                    v2 = JS_VALUE_GET_INT(op2);
18012
6.34k
                    r = (int64_t)v1 * v2;
18013
6.34k
                    if (unlikely((int)r != r)) {
18014
7
#ifdef CONFIG_BIGNUM
18015
7
                        if (unlikely(sf->js_mode & JS_MODE_MATH) &&
18016
7
                            (r < -MAX_SAFE_INTEGER || r > MAX_SAFE_INTEGER))
18017
0
                            goto binary_arith_slow;
18018
7
#endif
18019
7
                        d = (double)r;
18020
7
                        goto mul_fp_res;
18021
7
                    }
18022
                    /* need to test zero case for -0 result */
18023
6.33k
                    if (unlikely(r == 0 && (v1 | v2) < 0)) {
18024
0
                        d = -0.0;
18025
0
                        goto mul_fp_res;
18026
0
                    }
18027
6.33k
                    sp[-2] = JS_NewInt32(ctx, r);
18028
6.33k
                    sp--;
18029
206k
                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
18030
164
#ifdef CONFIG_BIGNUM
18031
164
                    if (unlikely(sf->js_mode & JS_MODE_MATH))
18032
0
                        goto binary_arith_slow;
18033
164
#endif
18034
164
                    d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);
18035
171
                mul_fp_res:
18036
171
                    sp[-2] = __JS_NewFloat64(ctx, d);
18037
171
                    sp--;
18038
206k
                } else {
18039
206k
                    goto binary_arith_slow;
18040
206k
                }
18041
213k
            }
18042
6.50k
            BREAK;
18043
196k
        CASE(OP_div):
18044
196k
            {
18045
196k
                JSValue op1, op2;
18046
196k
                op1 = sp[-2];
18047
196k
                op2 = sp[-1];
18048
196k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18049
153k
                    int v1, v2;
18050
153k
                    if (unlikely(sf->js_mode & JS_MODE_MATH))
18051
0
                        goto binary_arith_slow;
18052
153k
                    v1 = JS_VALUE_GET_INT(op1);
18053
153k
                    v2 = JS_VALUE_GET_INT(op2);
18054
153k
                    sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
18055
153k
                    sp--;
18056
153k
                } else {
18057
42.7k
                    goto binary_arith_slow;
18058
42.7k
                }
18059
196k
            }
18060
153k
            BREAK;
18061
153k
        CASE(OP_mod):
18062
24.8k
#ifdef CONFIG_BIGNUM
18063
24.8k
        CASE(OP_math_mod):
18064
24.8k
#endif
18065
24.8k
            {
18066
24.8k
                JSValue op1, op2;
18067
24.8k
                op1 = sp[-2];
18068
24.8k
                op2 = sp[-1];
18069
24.8k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18070
12.0k
                    int v1, v2, r;
18071
12.0k
                    v1 = JS_VALUE_GET_INT(op1);
18072
12.0k
                    v2 = JS_VALUE_GET_INT(op2);
18073
                    /* We must avoid v2 = 0, v1 = INT32_MIN and v2 =
18074
                       -1 and the cases where the result is -0. */
18075
12.0k
                    if (unlikely(v1 < 0 || v2 <= 0))
18076
6
                        goto binary_arith_slow;
18077
12.0k
                    r = v1 % v2;
18078
12.0k
                    sp[-2] = JS_NewInt32(ctx, r);
18079
12.0k
                    sp--;
18080
12.7k
                } else {
18081
12.7k
                    goto binary_arith_slow;
18082
12.7k
                }
18083
24.8k
            }
18084
12.0k
            BREAK;
18085
12.0k
        CASE(OP_pow):
18086
323k
        binary_arith_slow:
18087
323k
            if (js_binary_arith_slow(ctx, sp, opcode))
18088
12
                goto exception;
18089
323k
            sp--;
18090
323k
            BREAK;
18091
18092
393k
        CASE(OP_plus):
18093
393k
            {
18094
393k
                JSValue op1;
18095
393k
                uint32_t tag;
18096
393k
                op1 = sp[-1];
18097
393k
                tag = JS_VALUE_GET_TAG(op1);
18098
393k
                if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) {
18099
199k
                } else {
18100
193k
                    if (js_unary_arith_slow(ctx, sp, opcode))
18101
0
                        goto exception;
18102
193k
                }
18103
393k
            }
18104
393k
            BREAK;
18105
393k
        CASE(OP_neg):
18106
2.53k
            {
18107
2.53k
                JSValue op1;
18108
2.53k
                uint32_t tag;
18109
2.53k
                int val;
18110
2.53k
                double d;
18111
2.53k
                op1 = sp[-1];
18112
2.53k
                tag = JS_VALUE_GET_TAG(op1);
18113
2.53k
                if (tag == JS_TAG_INT) {
18114
13
                    val = JS_VALUE_GET_INT(op1);
18115
                    /* Note: -0 cannot be expressed as integer */
18116
13
                    if (unlikely(val == 0)) {
18117
13
                        d = -0.0;
18118
13
                        goto neg_fp_res;
18119
13
                    }
18120
0
                    if (unlikely(val == INT32_MIN)) {
18121
0
                        d = -(double)val;
18122
0
                        goto neg_fp_res;
18123
0
                    }
18124
0
                    sp[-1] = JS_NewInt32(ctx, -val);
18125
2.51k
                } else if (JS_TAG_IS_FLOAT64(tag)) {
18126
87
                    d = -JS_VALUE_GET_FLOAT64(op1);
18127
100
                neg_fp_res:
18128
100
                    sp[-1] = __JS_NewFloat64(ctx, d);
18129
2.43k
                } else {
18130
2.43k
                    if (js_unary_arith_slow(ctx, sp, opcode))
18131
0
                        goto exception;
18132
2.43k
                }
18133
2.53k
            }
18134
2.53k
            BREAK;
18135
2.53k
        CASE(OP_inc):
18136
110
            {
18137
110
                JSValue op1;
18138
110
                int val;
18139
110
                op1 = sp[-1];
18140
110
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18141
30
                    val = JS_VALUE_GET_INT(op1);
18142
30
                    if (unlikely(val == INT32_MAX))
18143
0
                        goto inc_slow;
18144
30
                    sp[-1] = JS_NewInt32(ctx, val + 1);
18145
80
                } else {
18146
80
                inc_slow:
18147
80
                    if (js_unary_arith_slow(ctx, sp, opcode))
18148
0
                        goto exception;
18149
80
                }
18150
110
            }
18151
110
            BREAK;
18152
110
        CASE(OP_dec):
18153
58
            {
18154
58
                JSValue op1;
18155
58
                int val;
18156
58
                op1 = sp[-1];
18157
58
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18158
0
                    val = JS_VALUE_GET_INT(op1);
18159
0
                    if (unlikely(val == INT32_MIN))
18160
0
                        goto dec_slow;
18161
0
                    sp[-1] = JS_NewInt32(ctx, val - 1);
18162
58
                } else {
18163
58
                dec_slow:
18164
58
                    if (js_unary_arith_slow(ctx, sp, opcode))
18165
0
                        goto exception;
18166
58
                }
18167
58
            }
18168
58
            BREAK;
18169
58
        CASE(OP_post_inc):
18170
18.6k
        CASE(OP_post_dec):
18171
18.6k
            if (js_post_inc_slow(ctx, sp, opcode))
18172
1
                goto exception;
18173
18.6k
            sp++;
18174
18.6k
            BREAK;
18175
18.6k
        CASE(OP_inc_loc):
18176
0
            {
18177
0
                JSValue op1;
18178
0
                int val;
18179
0
                int idx;
18180
0
                idx = *pc;
18181
0
                pc += 1;
18182
18183
0
                op1 = var_buf[idx];
18184
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18185
0
                    val = JS_VALUE_GET_INT(op1);
18186
0
                    if (unlikely(val == INT32_MAX))
18187
0
                        goto inc_loc_slow;
18188
0
                    var_buf[idx] = JS_NewInt32(ctx, val + 1);
18189
0
                } else {
18190
0
                inc_loc_slow:
18191
                    /* must duplicate otherwise the variable value may
18192
                       be destroyed before JS code accesses it */
18193
0
                    op1 = JS_DupValue(ctx, op1);
18194
0
                    if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc))
18195
0
                        goto exception;
18196
0
                    set_value(ctx, &var_buf[idx], op1);
18197
0
                }
18198
0
            }
18199
0
            BREAK;
18200
0
        CASE(OP_dec_loc):
18201
0
            {
18202
0
                JSValue op1;
18203
0
                int val;
18204
0
                int idx;
18205
0
                idx = *pc;
18206
0
                pc += 1;
18207
18208
0
                op1 = var_buf[idx];
18209
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18210
0
                    val = JS_VALUE_GET_INT(op1);
18211
0
                    if (unlikely(val == INT32_MIN))
18212
0
                        goto dec_loc_slow;
18213
0
                    var_buf[idx] = JS_NewInt32(ctx, val - 1);
18214
0
                } else {
18215
0
                dec_loc_slow:
18216
                    /* must duplicate otherwise the variable value may
18217
                       be destroyed before JS code accesses it */
18218
0
                    op1 = JS_DupValue(ctx, op1);
18219
0
                    if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec))
18220
0
                        goto exception;
18221
0
                    set_value(ctx, &var_buf[idx], op1);
18222
0
                }
18223
0
            }
18224
0
            BREAK;
18225
174k
        CASE(OP_not):
18226
174k
            {
18227
174k
                JSValue op1;
18228
174k
                op1 = sp[-1];
18229
174k
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18230
159k
                    sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1));
18231
159k
                } else {
18232
15.3k
                    if (js_not_slow(ctx, sp))
18233
3
                        goto exception;
18234
15.3k
                }
18235
174k
            }
18236
174k
            BREAK;
18237
18238
174k
        CASE(OP_shl):
18239
2
            {
18240
2
                JSValue op1, op2;
18241
2
                op1 = sp[-2];
18242
2
                op2 = sp[-1];
18243
2
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18244
1
                    uint32_t v1, v2;
18245
1
                    v1 = JS_VALUE_GET_INT(op1);
18246
1
                    v2 = JS_VALUE_GET_INT(op2);
18247
1
#ifdef CONFIG_BIGNUM
18248
1
                    {
18249
1
                        int64_t r;
18250
1
                        if (unlikely(sf->js_mode & JS_MODE_MATH)) {
18251
0
                            if (v2 > 0x1f)
18252
0
                                goto shl_slow;
18253
0
                            r = (int64_t)v1 << v2;
18254
0
                            if ((int)r != r)
18255
0
                                goto shl_slow;
18256
1
                        } else {
18257
1
                            v2 &= 0x1f;
18258
1
                        }
18259
1
                    }
18260
#else
18261
                    v2 &= 0x1f;
18262
#endif
18263
1
                    sp[-2] = JS_NewInt32(ctx, v1 << v2);
18264
1
                    sp--;
18265
1
                } else {
18266
1
#ifdef CONFIG_BIGNUM
18267
1
                shl_slow:
18268
1
#endif
18269
1
                    if (js_binary_logic_slow(ctx, sp, opcode))
18270
0
                        goto exception;
18271
1
                    sp--;
18272
1
                }
18273
2
            }
18274
2
            BREAK;
18275
1.28k
        CASE(OP_shr):
18276
1.28k
            {
18277
1.28k
                JSValue op1, op2;
18278
1.28k
                op1 = sp[-2];
18279
1.28k
                op2 = sp[-1];
18280
1.28k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18281
0
                    uint32_t v2;
18282
0
                    v2 = JS_VALUE_GET_INT(op2);
18283
                    /* v1 >>> v2 retains its JS semantics if CONFIG_BIGNUM */
18284
0
                    v2 &= 0x1f;
18285
0
                    sp[-2] = JS_NewUint32(ctx,
18286
0
                                          (uint32_t)JS_VALUE_GET_INT(op1) >>
18287
0
                                          v2);
18288
0
                    sp--;
18289
1.28k
                } else {
18290
1.28k
                    if (js_shr_slow(ctx, sp))
18291
0
                        goto exception;
18292
1.28k
                    sp--;
18293
1.28k
                }
18294
1.28k
            }
18295
1.28k
            BREAK;
18296
1.28k
        CASE(OP_sar):
18297
18
            {
18298
18
                JSValue op1, op2;
18299
18
                op1 = sp[-2];
18300
18
                op2 = sp[-1];
18301
18
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18302
0
                    uint32_t v2;
18303
0
                    v2 = JS_VALUE_GET_INT(op2);
18304
0
#ifdef CONFIG_BIGNUM
18305
0
                    if (unlikely(v2 > 0x1f)) {
18306
0
                        if (unlikely(sf->js_mode & JS_MODE_MATH))
18307
0
                            goto sar_slow;
18308
0
                        else
18309
0
                            v2 &= 0x1f;
18310
0
                    }
18311
#else
18312
                    v2 &= 0x1f;
18313
#endif
18314
0
                    sp[-2] = JS_NewInt32(ctx,
18315
0
                                          (int)JS_VALUE_GET_INT(op1) >> v2);
18316
0
                    sp--;
18317
18
                } else {
18318
18
#ifdef CONFIG_BIGNUM
18319
18
                sar_slow:
18320
18
#endif
18321
18
                    if (js_binary_logic_slow(ctx, sp, opcode))
18322
1
                        goto exception;
18323
17
                    sp--;
18324
17
                }
18325
18
            }
18326
17
            BREAK;
18327
168k
        CASE(OP_and):
18328
168k
            {
18329
168k
                JSValue op1, op2;
18330
168k
                op1 = sp[-2];
18331
168k
                op2 = sp[-1];
18332
168k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18333
105
                    sp[-2] = JS_NewInt32(ctx,
18334
105
                                         JS_VALUE_GET_INT(op1) &
18335
105
                                         JS_VALUE_GET_INT(op2));
18336
105
                    sp--;
18337
168k
                } else {
18338
168k
                    if (js_binary_logic_slow(ctx, sp, opcode))
18339
1
                        goto exception;
18340
168k
                    sp--;
18341
168k
                }
18342
168k
            }
18343
168k
            BREAK;
18344
168k
        CASE(OP_or):
18345
30
            {
18346
30
                JSValue op1, op2;
18347
30
                op1 = sp[-2];
18348
30
                op2 = sp[-1];
18349
30
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18350
0
                    sp[-2] = JS_NewInt32(ctx,
18351
0
                                         JS_VALUE_GET_INT(op1) |
18352
0
                                         JS_VALUE_GET_INT(op2));
18353
0
                    sp--;
18354
30
                } else {
18355
30
                    if (js_binary_logic_slow(ctx, sp, opcode))
18356
5
                        goto exception;
18357
25
                    sp--;
18358
25
                }
18359
30
            }
18360
25
            BREAK;
18361
1.30k
        CASE(OP_xor):
18362
1.30k
            {
18363
1.30k
                JSValue op1, op2;
18364
1.30k
                op1 = sp[-2];
18365
1.30k
                op2 = sp[-1];
18366
1.30k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18367
735
                    sp[-2] = JS_NewInt32(ctx,
18368
735
                                         JS_VALUE_GET_INT(op1) ^
18369
735
                                         JS_VALUE_GET_INT(op2));
18370
735
                    sp--;
18371
735
                } else {
18372
569
                    if (js_binary_logic_slow(ctx, sp, opcode))
18373
0
                        goto exception;
18374
569
                    sp--;
18375
569
                }
18376
1.30k
            }
18377
1.30k
            BREAK;
18378
18379
18380
1.30k
#define OP_CMP(opcode, binary_op, slow_call)              \
18381
359k
            CASE(opcode):                                 \
18382
359k
                {                                         \
18383
359k
                JSValue op1, op2;                         \
18384
359k
                op1 = sp[-2];                             \
18385
359k
                op2 = sp[-1];                                   \
18386
359k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {           \
18387
165k
                    sp[-2] = JS_NewBool(ctx, JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \
18388
165k
                    sp--;                                               \
18389
193k
                } else {                                                \
18390
193k
                    if (slow_call)                                      \
18391
193k
                        goto exception;                                 \
18392
193k
                    sp--;                                               \
18393
193k
                }                                                       \
18394
359k
                }                                                       \
18395
359k
            BREAK
18396
18397
25.6k
            OP_CMP(OP_lt, <, js_relational_slow(ctx, sp, opcode));
18398
25.6k
            OP_CMP(OP_lte, <=, js_relational_slow(ctx, sp, opcode));
18399
624k
            OP_CMP(OP_gt, >, js_relational_slow(ctx, sp, opcode));
18400
624k
            OP_CMP(OP_gte, >=, js_relational_slow(ctx, sp, opcode));
18401
20.6k
            OP_CMP(OP_eq, ==, js_eq_slow(ctx, sp, 0));
18402
13.3k
            OP_CMP(OP_neq, !=, js_eq_slow(ctx, sp, 1));
18403
9.28k
            OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0));
18404
276
            OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1));
18405
18406
276
#ifdef CONFIG_BIGNUM
18407
276
        CASE(OP_mul_pow10):
18408
0
            if (rt->bigfloat_ops.mul_pow10(ctx, sp))
18409
0
                goto exception;
18410
0
            sp--;
18411
0
            BREAK;
18412
0
#endif
18413
5
        CASE(OP_in):
18414
5
            if (js_operator_in(ctx, sp))
18415
0
                goto exception;
18416
5
            sp--;
18417
5
            BREAK;
18418
5
        CASE(OP_instanceof):
18419
0
            if (js_operator_instanceof(ctx, sp))
18420
0
                goto exception;
18421
0
            sp--;
18422
0
            BREAK;
18423
5.78k
        CASE(OP_typeof):
18424
5.78k
            {
18425
5.78k
                JSValue op1;
18426
5.78k
                JSAtom atom;
18427
18428
5.78k
                op1 = sp[-1];
18429
5.78k
                atom = js_operator_typeof(ctx, op1);
18430
5.78k
                JS_FreeValue(ctx, op1);
18431
5.78k
                sp[-1] = JS_AtomToString(ctx, atom);
18432
5.78k
            }
18433
5.78k
            BREAK;
18434
5.78k
        CASE(OP_delete):
18435
647
            if (js_operator_delete(ctx, sp))
18436
0
                goto exception;
18437
647
            sp--;
18438
647
            BREAK;
18439
1.15k
        CASE(OP_delete_var):
18440
1.15k
            {
18441
1.15k
                JSAtom atom;
18442
1.15k
                int ret;
18443
18444
1.15k
                atom = get_u32(pc);
18445
1.15k
                pc += 4;
18446
18447
1.15k
                ret = JS_DeleteProperty(ctx, ctx->global_obj, atom, 0);
18448
1.15k
                if (unlikely(ret < 0))
18449
0
                    goto exception;
18450
1.15k
                *sp++ = JS_NewBool(ctx, ret);
18451
1.15k
            }
18452
1.15k
            BREAK;
18453
18454
2.28M
        CASE(OP_to_object):
18455
2.28M
            if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) {
18456
1.21M
                ret_val = JS_ToObject(ctx, sp[-1]);
18457
1.21M
                if (JS_IsException(ret_val))
18458
32
                    goto exception;
18459
1.21M
                JS_FreeValue(ctx, sp[-1]);
18460
1.21M
                sp[-1] = ret_val;
18461
1.21M
            }
18462
2.28M
            BREAK;
18463
18464
2.28M
        CASE(OP_to_propkey):
18465
2.42k
            switch (JS_VALUE_GET_TAG(sp[-1])) {
18466
0
            case JS_TAG_INT:
18467
0
            case JS_TAG_STRING:
18468
0
            case JS_TAG_SYMBOL:
18469
0
                break;
18470
2.42k
            default:
18471
2.42k
                ret_val = JS_ToPropertyKey(ctx, sp[-1]);
18472
2.42k
                if (JS_IsException(ret_val))
18473
0
                    goto exception;
18474
2.42k
                JS_FreeValue(ctx, sp[-1]);
18475
2.42k
                sp[-1] = ret_val;
18476
2.42k
                break;
18477
2.42k
            }
18478
2.42k
            BREAK;
18479
18480
24.3k
        CASE(OP_to_propkey2):
18481
            /* must be tested first */
18482
24.3k
            if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
18483
0
                JS_ThrowTypeError(ctx, "value has no property");
18484
0
                goto exception;
18485
0
            }
18486
24.3k
            switch (JS_VALUE_GET_TAG(sp[-1])) {
18487
8.65k
            case JS_TAG_INT:
18488
20.6k
            case JS_TAG_STRING:
18489
20.6k
            case JS_TAG_SYMBOL:
18490
20.6k
                break;
18491
3.69k
            default:
18492
3.69k
                ret_val = JS_ToPropertyKey(ctx, sp[-1]);
18493
3.69k
                if (JS_IsException(ret_val))
18494
0
                    goto exception;
18495
3.69k
                JS_FreeValue(ctx, sp[-1]);
18496
3.69k
                sp[-1] = ret_val;
18497
3.69k
                break;
18498
24.3k
            }
18499
24.3k
            BREAK;
18500
#if 0
18501
        CASE(OP_to_string):
18502
            if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_STRING) {
18503
                ret_val = JS_ToString(ctx, sp[-1]);
18504
                if (JS_IsException(ret_val))
18505
                    goto exception;
18506
                JS_FreeValue(ctx, sp[-1]);
18507
                sp[-1] = ret_val;
18508
            }
18509
            BREAK;
18510
#endif
18511
26.5k
        CASE(OP_with_get_var):
18512
26.5k
        CASE(OP_with_put_var):
18513
26.5k
        CASE(OP_with_delete_var):
18514
120k
        CASE(OP_with_make_ref):
18515
3.59M
        CASE(OP_with_get_ref):
18516
3.59M
        CASE(OP_with_get_ref_undef):
18517
3.59M
            {
18518
3.59M
                JSAtom atom;
18519
3.59M
                int32_t diff;
18520
3.59M
                JSValue obj, val;
18521
3.59M
                int ret, is_with;
18522
3.59M
                atom = get_u32(pc);
18523
3.59M
                diff = get_u32(pc + 4);
18524
3.59M
                is_with = pc[8];
18525
3.59M
                pc += 9;
18526
18527
3.59M
                obj = sp[-1];
18528
3.59M
                ret = JS_HasProperty(ctx, obj, atom);
18529
3.59M
                if (unlikely(ret < 0))
18530
0
                    goto exception;
18531
3.59M
                if (ret) {
18532
0
                    if (is_with) {
18533
0
                        ret = js_has_unscopable(ctx, obj, atom);
18534
0
                        if (unlikely(ret < 0))
18535
0
                            goto exception;
18536
0
                        if (ret)
18537
0
                            goto no_with;
18538
0
                    }
18539
0
                    switch (opcode) {
18540
0
                    case OP_with_get_var:
18541
0
                        val = JS_GetProperty(ctx, obj, atom);
18542
0
                        if (unlikely(JS_IsException(val)))
18543
0
                            goto exception;
18544
0
                        set_value(ctx, &sp[-1], val);
18545
0
                        break;
18546
0
                    case OP_with_put_var:
18547
                        /* XXX: check if strict mode */
18548
0
                        ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2],
18549
0
                                                     JS_PROP_THROW_STRICT);
18550
0
                        JS_FreeValue(ctx, sp[-1]);
18551
0
                        sp -= 2;
18552
0
                        if (unlikely(ret < 0))
18553
0
                            goto exception;
18554
0
                        break;
18555
0
                    case OP_with_delete_var:
18556
0
                        ret = JS_DeleteProperty(ctx, obj, atom, 0);
18557
0
                        if (unlikely(ret < 0))
18558
0
                            goto exception;
18559
0
                        JS_FreeValue(ctx, sp[-1]);
18560
0
                        sp[-1] = JS_NewBool(ctx, ret);
18561
0
                        break;
18562
0
                    case OP_with_make_ref:
18563
                        /* produce a pair object/propname on the stack */
18564
0
                        *sp++ = JS_AtomToValue(ctx, atom);
18565
0
                        break;
18566
0
                    case OP_with_get_ref:
18567
                        /* produce a pair object/method on the stack */
18568
0
                        val = JS_GetProperty(ctx, obj, atom);
18569
0
                        if (unlikely(JS_IsException(val)))
18570
0
                            goto exception;
18571
0
                        *sp++ = val;
18572
0
                        break;
18573
0
                    case OP_with_get_ref_undef:
18574
                        /* produce a pair undefined/function on the stack */
18575
0
                        val = JS_GetProperty(ctx, obj, atom);
18576
0
                        if (unlikely(JS_IsException(val)))
18577
0
                            goto exception;
18578
0
                        JS_FreeValue(ctx, sp[-1]);
18579
0
                        sp[-1] = JS_UNDEFINED;
18580
0
                        *sp++ = val;
18581
0
                        break;
18582
0
                    }
18583
0
                    pc += diff - 5;
18584
3.59M
                } else {
18585
3.59M
                no_with:
18586
                    /* if not jumping, drop the object argument */
18587
3.59M
                    JS_FreeValue(ctx, sp[-1]);
18588
3.59M
                    sp--;
18589
3.59M
                }
18590
3.59M
            }
18591
3.59M
            BREAK;
18592
18593
3.59M
        CASE(OP_await):
18594
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_AWAIT);
18595
0
            goto done_generator;
18596
0
        CASE(OP_yield):
18597
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD);
18598
0
            goto done_generator;
18599
0
        CASE(OP_yield_star):
18600
0
        CASE(OP_async_yield_star):
18601
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR);
18602
0
            goto done_generator;
18603
0
        CASE(OP_return_async):
18604
5.35k
        CASE(OP_initial_yield):
18605
5.35k
            ret_val = JS_UNDEFINED;
18606
5.35k
            goto done_generator;
18607
18608
0
        CASE(OP_nop):
18609
0
            BREAK;
18610
2.81k
        CASE(OP_is_undefined_or_null):
18611
2.81k
            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED ||
18612
2.81k
                JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
18613
66
                goto set_true;
18614
2.74k
            } else {
18615
2.74k
                goto free_and_set_false;
18616
2.74k
            }
18617
0
#if SHORT_OPCODES
18618
195k
        CASE(OP_is_undefined):
18619
195k
            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED) {
18620
173k
                goto set_true;
18621
173k
            } else {
18622
21.4k
                goto free_and_set_false;
18623
21.4k
            }
18624
636
        CASE(OP_is_null):
18625
636
            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
18626
0
                goto set_true;
18627
636
            } else {
18628
636
                goto free_and_set_false;
18629
636
            }
18630
            /* XXX: could merge to a single opcode */
18631
0
        CASE(OP_typeof_is_undefined):
18632
            /* different from OP_is_undefined because of isHTMLDDA */
18633
0
            if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) {
18634
0
                goto free_and_set_true;
18635
0
            } else {
18636
0
                goto free_and_set_false;
18637
0
            }
18638
0
        CASE(OP_typeof_is_function):
18639
0
            if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) {
18640
0
                goto free_and_set_true;
18641
0
            } else {
18642
0
                goto free_and_set_false;
18643
0
            }
18644
0
        free_and_set_true:
18645
0
            JS_FreeValue(ctx, sp[-1]);
18646
0
#endif
18647
173k
        set_true:
18648
173k
            sp[-1] = JS_TRUE;
18649
173k
            BREAK;
18650
173k
        free_and_set_false:
18651
24.7k
            JS_FreeValue(ctx, sp[-1]);
18652
24.7k
            sp[-1] = JS_FALSE;
18653
24.7k
            BREAK;
18654
24.7k
        CASE(OP_invalid):
18655
0
        DEFAULT:
18656
0
            JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x",
18657
0
                                  (int)(pc - b->byte_code_buf - 1), opcode);
18658
0
            goto exception;
18659
0
        }
18660
0
    }
18661
5.05k
 exception:
18662
5.05k
    if (is_backtrace_needed(ctx, rt->current_exception)) {
18663
        /* add the backtrace information now (it is not done
18664
           before if the exception happens in a bytecode
18665
           operation */
18666
357
        sf->cur_pc = pc;
18667
357
        build_backtrace(ctx, rt->current_exception, NULL, 0, 0);
18668
357
    }
18669
5.05k
    if (!JS_IsUncatchableError(ctx, rt->current_exception)) {
18670
27.9k
        while (sp > stack_buf) {
18671
22.9k
            JSValue val = *--sp;
18672
22.9k
            JS_FreeValue(ctx, val);
18673
22.9k
            if (JS_VALUE_GET_TAG(val) == JS_TAG_CATCH_OFFSET) {
18674
5
                int pos = JS_VALUE_GET_INT(val);
18675
5
                if (pos == 0) {
18676
                    /* enumerator: close it with a throw */
18677
5
                    JS_FreeValue(ctx, sp[-1]); /* drop the next method */
18678
5
                    sp--;
18679
5
                    JS_IteratorClose(ctx, sp[-1], TRUE);
18680
5
                } else {
18681
0
                    *sp++ = rt->current_exception;
18682
0
                    rt->current_exception = JS_NULL;
18683
0
                    pc = b->byte_code_buf + pos;
18684
0
                    goto restart;
18685
0
                }
18686
5
            }
18687
22.9k
        }
18688
5.04k
    }
18689
5.05k
    ret_val = JS_EXCEPTION;
18690
    /* the local variables are freed by the caller in the generator
18691
       case. Hence the label 'done' should never be reached in a
18692
       generator function. */
18693
5.05k
    if (b->func_kind != JS_FUNC_NORMAL) {
18694
5.35k
    done_generator:
18695
5.35k
        sf->cur_pc = pc;
18696
5.35k
        sf->cur_sp = sp;
18697
5.35k
    } else {
18698
1.59M
    done:
18699
1.59M
        if (unlikely(!list_empty(&sf->var_ref_list))) {
18700
            /* variable references reference the stack: must close them */
18701
11.3k
            close_var_refs(rt, sf);
18702
11.3k
        }
18703
        /* free the local variables and stack */
18704
4.18M
        for(pval = local_buf; pval < sp; pval++) {
18705
2.59M
            JS_FreeValue(ctx, *pval);
18706
2.59M
        }
18707
1.59M
    }
18708
1.60M
    rt->current_stack_frame = sf->prev_frame;
18709
1.60M
    return ret_val;
18710
5.05k
}
18711
18712
JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,
18713
                int argc, JSValueConst *argv)
18714
488k
{
18715
488k
    return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
18716
488k
                           argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
18717
488k
}
18718
18719
static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
18720
                           int argc, JSValueConst *argv)
18721
2.62M
{
18722
2.62M
    JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
18723
2.62M
                                  argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
18724
2.62M
    JS_FreeValue(ctx, func_obj);
18725
2.62M
    return res;
18726
2.62M
}
18727
18728
/* warning: the refcount of the context is not incremented. Return
18729
   NULL in case of exception (case of revoked proxy only) */
18730
static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj)
18731
201k
{
18732
201k
    JSObject *p;
18733
201k
    JSContext *realm;
18734
    
18735
201k
    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
18736
0
        return ctx;
18737
201k
    p = JS_VALUE_GET_OBJ(func_obj);
18738
201k
    switch(p->class_id) {
18739
201k
    case JS_CLASS_C_FUNCTION:
18740
201k
        realm = p->u.cfunc.realm;
18741
201k
        break;
18742
0
    case JS_CLASS_BYTECODE_FUNCTION:
18743
0
    case JS_CLASS_GENERATOR_FUNCTION:
18744
0
    case JS_CLASS_ASYNC_FUNCTION:
18745
0
    case JS_CLASS_ASYNC_GENERATOR_FUNCTION:
18746
0
        {
18747
0
            JSFunctionBytecode *b;
18748
0
            b = p->u.func.function_bytecode;
18749
0
            realm = b->realm;
18750
0
        }
18751
0
        break;
18752
0
    case JS_CLASS_PROXY:
18753
0
        {
18754
0
            JSProxyData *s = p->u.opaque;
18755
0
            if (!s)
18756
0
                return ctx;
18757
0
            if (s->is_revoked) {
18758
0
                JS_ThrowTypeErrorRevokedProxy(ctx);
18759
0
                return NULL;
18760
0
            } else {
18761
0
                realm = JS_GetFunctionRealm(ctx, s->target);
18762
0
            }
18763
0
        }
18764
0
        break;
18765
0
    case JS_CLASS_BOUND_FUNCTION:
18766
0
        {
18767
0
            JSBoundFunction *bf = p->u.bound_function;
18768
0
            realm = JS_GetFunctionRealm(ctx, bf->func_obj);
18769
0
        }
18770
0
        break;
18771
0
    default:
18772
0
        realm = ctx;
18773
0
        break;
18774
201k
    }
18775
201k
    return realm;
18776
201k
}
18777
18778
static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor,
18779
                                   int class_id)
18780
650k
{
18781
650k
    JSValue proto, obj;
18782
650k
    JSContext *realm;
18783
    
18784
650k
    if (JS_IsUndefined(ctor)) {
18785
228k
        proto = JS_DupValue(ctx, ctx->class_proto[class_id]);
18786
422k
    } else {
18787
422k
        proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
18788
422k
        if (JS_IsException(proto))
18789
0
            return proto;
18790
422k
        if (!JS_IsObject(proto)) {
18791
0
            JS_FreeValue(ctx, proto);
18792
0
            realm = JS_GetFunctionRealm(ctx, ctor);
18793
0
            if (!realm)
18794
0
                return JS_EXCEPTION;
18795
0
            proto = JS_DupValue(ctx, realm->class_proto[class_id]);
18796
0
        }
18797
422k
    }
18798
650k
    obj = JS_NewObjectProtoClass(ctx, proto, class_id);
18799
650k
    JS_FreeValue(ctx, proto);
18800
650k
    return obj;
18801
650k
}
18802
18803
/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
18804
static JSValue JS_CallConstructorInternal(JSContext *ctx,
18805
                                          JSValueConst func_obj,
18806
                                          JSValueConst new_target,
18807
                                          int argc, JSValue *argv, int flags)
18808
417k
{
18809
417k
    JSObject *p;
18810
417k
    JSFunctionBytecode *b;
18811
18812
417k
    if (js_poll_interrupts(ctx))
18813
0
        return JS_EXCEPTION;
18814
417k
    flags |= JS_CALL_FLAG_CONSTRUCTOR;
18815
417k
    if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT))
18816
0
        goto not_a_function;
18817
417k
    p = JS_VALUE_GET_OBJ(func_obj);
18818
417k
    if (unlikely(!p->is_constructor))
18819
0
        return JS_ThrowTypeError(ctx, "not a constructor");
18820
417k
    if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
18821
201k
        JSClassCall *call_func;
18822
201k
        call_func = ctx->rt->class_array[p->class_id].call;
18823
201k
        if (!call_func) {
18824
0
        not_a_function:
18825
0
            return JS_ThrowTypeError(ctx, "not a function");
18826
0
        }
18827
201k
        return call_func(ctx, func_obj, new_target, argc,
18828
201k
                         (JSValueConst *)argv, flags);
18829
201k
    }
18830
18831
215k
    b = p->u.func.function_bytecode;
18832
215k
    if (b->is_derived_class_constructor) {
18833
0
        return JS_CallInternal(ctx, func_obj, JS_UNDEFINED, new_target, argc, argv, flags);
18834
215k
    } else {
18835
215k
        JSValue obj, ret;
18836
        /* legacy constructor behavior */
18837
215k
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
18838
215k
        if (JS_IsException(obj))
18839
0
            return JS_EXCEPTION;
18840
215k
        ret = JS_CallInternal(ctx, func_obj, obj, new_target, argc, argv, flags);
18841
215k
        if (JS_VALUE_GET_TAG(ret) == JS_TAG_OBJECT ||
18842
215k
            JS_IsException(ret)) {
18843
16
            JS_FreeValue(ctx, obj);
18844
16
            return ret;
18845
215k
        } else {
18846
215k
            JS_FreeValue(ctx, ret);
18847
215k
            return obj;
18848
215k
        }
18849
215k
    }
18850
215k
}
18851
18852
JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,
18853
                            JSValueConst new_target,
18854
                            int argc, JSValueConst *argv)
18855
0
{
18856
0
    return JS_CallConstructorInternal(ctx, func_obj, new_target,
18857
0
                                      argc, (JSValue *)argv,
18858
0
                                      JS_CALL_FLAG_COPY_ARGV);
18859
0
}
18860
18861
JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,
18862
                           int argc, JSValueConst *argv)
18863
201k
{
18864
201k
    return JS_CallConstructorInternal(ctx, func_obj, func_obj,
18865
201k
                                      argc, (JSValue *)argv,
18866
201k
                                      JS_CALL_FLAG_COPY_ARGV);
18867
201k
}
18868
18869
JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom,
18870
                  int argc, JSValueConst *argv)
18871
144
{
18872
144
    JSValue func_obj;
18873
144
    func_obj = JS_GetProperty(ctx, this_val, atom);
18874
144
    if (JS_IsException(func_obj))
18875
0
        return func_obj;
18876
144
    return JS_CallFree(ctx, func_obj, this_val, argc, argv);
18877
144
}
18878
18879
static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
18880
                             int argc, JSValueConst *argv)
18881
144
{
18882
144
    JSValue res = JS_Invoke(ctx, this_val, atom, argc, argv);
18883
144
    JS_FreeValue(ctx, this_val);
18884
144
    return res;
18885
144
}
18886
18887
/* JSAsyncFunctionState (used by generator and async functions) */
18888
static __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s,
18889
                                       JSValueConst func_obj, JSValueConst this_obj,
18890
                                       int argc, JSValueConst *argv)
18891
5.35k
{
18892
5.35k
    JSObject *p;
18893
5.35k
    JSFunctionBytecode *b;
18894
5.35k
    JSStackFrame *sf;
18895
5.35k
    int local_count, i, arg_buf_len, n;
18896
18897
5.35k
    sf = &s->frame;
18898
5.35k
    init_list_head(&sf->var_ref_list);
18899
5.35k
    p = JS_VALUE_GET_OBJ(func_obj);
18900
5.35k
    b = p->u.func.function_bytecode;
18901
5.35k
    sf->js_mode = b->js_mode;
18902
5.35k
    sf->cur_pc = b->byte_code_buf;
18903
5.35k
    arg_buf_len = max_int(b->arg_count, argc);
18904
5.35k
    local_count = arg_buf_len + b->var_count + b->stack_size;
18905
5.35k
    sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1));
18906
5.35k
    if (!sf->arg_buf)
18907
0
        return -1;
18908
5.35k
    sf->cur_func = JS_DupValue(ctx, func_obj);
18909
5.35k
    s->this_val = JS_DupValue(ctx, this_obj);
18910
5.35k
    s->argc = argc;
18911
5.35k
    sf->arg_count = arg_buf_len;
18912
5.35k
    sf->var_buf = sf->arg_buf + arg_buf_len;
18913
5.35k
    sf->cur_sp = sf->var_buf + b->var_count;
18914
10.6k
    for(i = 0; i < argc; i++)
18915
5.31k
        sf->arg_buf[i] = JS_DupValue(ctx, argv[i]);
18916
5.35k
    n = arg_buf_len + b->var_count;
18917
6.19k
    for(i = argc; i < n; i++)
18918
5.35k
        sf->arg_buf[i] = JS_UNDEFINED;
18919
5.35k
    return 0;
18920
5.35k
}
18921
18922
static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
18923
                            JS_MarkFunc *mark_func)
18924
8.98k
{
18925
8.98k
    JSStackFrame *sf;
18926
8.98k
    JSValue *sp;
18927
18928
8.98k
    sf = &s->frame;
18929
8.98k
    JS_MarkValue(rt, sf->cur_func, mark_func);
18930
8.98k
    JS_MarkValue(rt, s->this_val, mark_func);
18931
8.98k
    if (sf->cur_sp) {
18932
        /* if the function is running, cur_sp is not known so we
18933
           cannot mark the stack. Marking the variables is not needed
18934
           because a running function cannot be part of a removable
18935
           cycle */
18936
18.5k
        for(sp = sf->arg_buf; sp < sf->cur_sp; sp++)
18937
9.58k
            JS_MarkValue(rt, *sp, mark_func);
18938
8.98k
    }
18939
8.98k
}
18940
18941
static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
18942
5.35k
{
18943
5.35k
    JSStackFrame *sf;
18944
5.35k
    JSValue *sp;
18945
18946
5.35k
    sf = &s->frame;
18947
18948
    /* close the closure variables. */
18949
5.35k
    close_var_refs(rt, sf);
18950
    
18951
5.35k
    if (sf->arg_buf) {
18952
        /* cannot free the function if it is running */
18953
5.35k
        assert(sf->cur_sp != NULL);
18954
11.5k
        for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) {
18955
6.15k
            JS_FreeValueRT(rt, *sp);
18956
6.15k
        }
18957
5.35k
        js_free_rt(rt, sf->arg_buf);
18958
5.35k
    }
18959
5.35k
    JS_FreeValueRT(rt, sf->cur_func);
18960
5.35k
    JS_FreeValueRT(rt, s->this_val);
18961
5.35k
}
18962
18963
static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)
18964
5.35k
{
18965
5.35k
    JSValue func_obj;
18966
18967
5.35k
    if (js_check_stack_overflow(ctx->rt, 0))
18968
0
        return JS_ThrowStackOverflow(ctx);
18969
18970
    /* the tag does not matter provided it is not an object */
18971
5.35k
    func_obj = JS_MKPTR(JS_TAG_INT, s);
18972
5.35k
    return JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,
18973
5.35k
                           s->argc, s->frame.arg_buf, JS_CALL_FLAG_GENERATOR);
18974
5.35k
}
18975
18976
18977
/* Generators */
18978
18979
typedef enum JSGeneratorStateEnum {
18980
    JS_GENERATOR_STATE_SUSPENDED_START,
18981
    JS_GENERATOR_STATE_SUSPENDED_YIELD,
18982
    JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
18983
    JS_GENERATOR_STATE_EXECUTING,
18984
    JS_GENERATOR_STATE_COMPLETED,
18985
} JSGeneratorStateEnum;
18986
18987
typedef struct JSGeneratorData {
18988
    JSGeneratorStateEnum state;
18989
    JSAsyncFunctionState func_state;
18990
} JSGeneratorData;
18991
18992
static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s)
18993
5.37k
{
18994
5.37k
    if (s->state == JS_GENERATOR_STATE_COMPLETED)
18995
29
        return;
18996
5.35k
    async_func_free(rt, &s->func_state);
18997
5.35k
    s->state = JS_GENERATOR_STATE_COMPLETED;
18998
5.35k
}
18999
19000
static void js_generator_finalizer(JSRuntime *rt, JSValue obj)
19001
5.35k
{
19002
5.35k
    JSGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_GENERATOR);
19003
19004
5.35k
    if (s) {
19005
5.35k
        free_generator_stack_rt(rt, s);
19006
5.35k
        js_free_rt(rt, s);
19007
5.35k
    }
19008
5.35k
}
19009
19010
static void free_generator_stack(JSContext *ctx, JSGeneratorData *s)
19011
29
{
19012
29
    free_generator_stack_rt(ctx->rt, s);
19013
29
}
19014
19015
static void js_generator_mark(JSRuntime *rt, JSValueConst val,
19016
                              JS_MarkFunc *mark_func)
19017
8.98k
{
19018
8.98k
    JSObject *p = JS_VALUE_GET_OBJ(val);
19019
8.98k
    JSGeneratorData *s = p->u.generator_data;
19020
19021
8.98k
    if (!s || s->state == JS_GENERATOR_STATE_COMPLETED)
19022
0
        return;
19023
8.98k
    async_func_mark(rt, &s->func_state, mark_func);
19024
8.98k
}
19025
19026
/* XXX: use enum */
19027
58
#define GEN_MAGIC_NEXT   0
19028
29
#define GEN_MAGIC_RETURN 1
19029
0
#define GEN_MAGIC_THROW  2
19030
19031
static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
19032
                                 int argc, JSValueConst *argv,
19033
                                 BOOL *pdone, int magic)
19034
58
{
19035
58
    JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR);
19036
58
    JSStackFrame *sf;
19037
58
    JSValue ret, func_ret;
19038
19039
58
    *pdone = TRUE;
19040
58
    if (!s)
19041
0
        return JS_ThrowTypeError(ctx, "not a generator");
19042
58
    sf = &s->func_state.frame;
19043
58
    switch(s->state) {
19044
0
    default:
19045
29
    case JS_GENERATOR_STATE_SUSPENDED_START:
19046
29
        if (magic == GEN_MAGIC_NEXT) {
19047
0
            goto exec_no_arg;
19048
29
        } else {
19049
29
            free_generator_stack(ctx, s);
19050
29
            goto done;
19051
29
        }
19052
0
        break;
19053
0
    case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
19054
0
    case JS_GENERATOR_STATE_SUSPENDED_YIELD:
19055
        /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
19056
0
        ret = JS_DupValue(ctx, argv[0]);
19057
0
        if (magic == GEN_MAGIC_THROW &&
19058
0
            s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {
19059
0
            JS_Throw(ctx, ret);
19060
0
            s->func_state.throw_flag = TRUE;
19061
0
        } else {
19062
0
            sf->cur_sp[-1] = ret;
19063
0
            sf->cur_sp[0] = JS_NewInt32(ctx, magic);
19064
0
            sf->cur_sp++;
19065
0
        exec_no_arg:
19066
0
            s->func_state.throw_flag = FALSE;
19067
0
        }
19068
0
        s->state = JS_GENERATOR_STATE_EXECUTING;
19069
0
        func_ret = async_func_resume(ctx, &s->func_state);
19070
0
        s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD;
19071
0
        if (JS_IsException(func_ret)) {
19072
            /* finalize the execution in case of exception */
19073
0
            free_generator_stack(ctx, s);
19074
0
            return func_ret;
19075
0
        }
19076
0
        if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
19077
            /* get the returned yield value at the top of the stack */
19078
0
            ret = sf->cur_sp[-1];
19079
0
            sf->cur_sp[-1] = JS_UNDEFINED;
19080
0
            if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) {
19081
0
                s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
19082
                /* return (value, done) object */
19083
0
                *pdone = 2;
19084
0
            } else {
19085
0
                *pdone = FALSE;
19086
0
            }
19087
0
        } else {
19088
            /* end of iterator */
19089
0
            ret = sf->cur_sp[-1];
19090
0
            sf->cur_sp[-1] = JS_UNDEFINED;
19091
0
            JS_FreeValue(ctx, func_ret);
19092
0
            free_generator_stack(ctx, s);
19093
0
        }
19094
0
        break;
19095
29
    case JS_GENERATOR_STATE_COMPLETED:
19096
58
    done:
19097
        /* execution is finished */
19098
58
        switch(magic) {
19099
0
        default:
19100
29
        case GEN_MAGIC_NEXT:
19101
29
            ret = JS_UNDEFINED;
19102
29
            break;
19103
29
        case GEN_MAGIC_RETURN:
19104
29
            ret = JS_DupValue(ctx, argv[0]);
19105
29
            break;
19106
0
        case GEN_MAGIC_THROW:
19107
0
            ret = JS_Throw(ctx, JS_DupValue(ctx, argv[0]));
19108
0
            break;
19109
58
        }
19110
58
        break;
19111
58
    case JS_GENERATOR_STATE_EXECUTING:
19112
0
        ret = JS_ThrowTypeError(ctx, "cannot invoke a running generator");
19113
0
        break;
19114
58
    }
19115
58
    return ret;
19116
58
}
19117
19118
static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
19119
                                          JSValueConst this_obj,
19120
                                          int argc, JSValueConst *argv,
19121
                                          int flags)
19122
5.35k
{
19123
5.35k
    JSValue obj, func_ret;
19124
5.35k
    JSGeneratorData *s;
19125
19126
5.35k
    s = js_mallocz(ctx, sizeof(*s));
19127
5.35k
    if (!s)
19128
0
        return JS_EXCEPTION;
19129
5.35k
    s->state = JS_GENERATOR_STATE_SUSPENDED_START;
19130
5.35k
    if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
19131
0
        s->state = JS_GENERATOR_STATE_COMPLETED;
19132
0
        goto fail;
19133
0
    }
19134
19135
    /* execute the function up to 'OP_initial_yield' */
19136
5.35k
    func_ret = async_func_resume(ctx, &s->func_state);
19137
5.35k
    if (JS_IsException(func_ret))
19138
0
        goto fail;
19139
5.35k
    JS_FreeValue(ctx, func_ret);
19140
19141
5.35k
    obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR);
19142
5.35k
    if (JS_IsException(obj))
19143
0
        goto fail;
19144
5.35k
    JS_SetOpaque(obj, s);
19145
5.35k
    return obj;
19146
0
 fail:
19147
0
    free_generator_stack_rt(ctx->rt, s);
19148
0
    js_free(ctx, s);
19149
0
    return JS_EXCEPTION;
19150
5.35k
}
19151
19152
/* AsyncFunction */
19153
19154
static void js_async_function_terminate(JSRuntime *rt, JSAsyncFunctionData *s)
19155
0
{
19156
0
    if (s->is_active) {
19157
0
        async_func_free(rt, &s->func_state);
19158
0
        s->is_active = FALSE;
19159
0
    }
19160
0
}
19161
19162
static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s)
19163
0
{
19164
0
    js_async_function_terminate(rt, s);
19165
0
    JS_FreeValueRT(rt, s->resolving_funcs[0]);
19166
0
    JS_FreeValueRT(rt, s->resolving_funcs[1]);
19167
0
    remove_gc_object(&s->header);
19168
0
    js_free_rt(rt, s);
19169
0
}
19170
19171
static void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s)
19172
0
{
19173
0
    if (--s->header.ref_count == 0) {
19174
0
        js_async_function_free0(rt, s);
19175
0
    }
19176
0
}
19177
19178
static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val)
19179
0
{
19180
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
19181
0
    JSAsyncFunctionData *s = p->u.async_function_data;
19182
0
    if (s) {
19183
0
        js_async_function_free(rt, s);
19184
0
    }
19185
0
}
19186
19187
static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
19188
                                           JS_MarkFunc *mark_func)
19189
0
{
19190
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
19191
0
    JSAsyncFunctionData *s = p->u.async_function_data;
19192
0
    if (s) {
19193
0
        mark_func(rt, &s->header);
19194
0
    }
19195
0
}
19196
19197
static int js_async_function_resolve_create(JSContext *ctx,
19198
                                            JSAsyncFunctionData *s,
19199
                                            JSValue *resolving_funcs)
19200
0
{
19201
0
    int i;
19202
0
    JSObject *p;
19203
19204
0
    for(i = 0; i < 2; i++) {
19205
0
        resolving_funcs[i] =
19206
0
            JS_NewObjectProtoClass(ctx, ctx->function_proto,
19207
0
                                   JS_CLASS_ASYNC_FUNCTION_RESOLVE + i);
19208
0
        if (JS_IsException(resolving_funcs[i])) {
19209
0
            if (i == 1)
19210
0
                JS_FreeValue(ctx, resolving_funcs[0]);
19211
0
            return -1;
19212
0
        }
19213
0
        p = JS_VALUE_GET_OBJ(resolving_funcs[i]);
19214
0
        s->header.ref_count++;
19215
0
        p->u.async_function_data = s;
19216
0
    }
19217
0
    return 0;
19218
0
}
19219
19220
static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s)
19221
0
{
19222
0
    JSValue func_ret, ret2;
19223
19224
0
    func_ret = async_func_resume(ctx, &s->func_state);
19225
0
    if (JS_IsException(func_ret)) {
19226
0
        JSValue error;
19227
0
    fail:
19228
0
        error = JS_GetException(ctx);
19229
0
        ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED,
19230
0
                       1, (JSValueConst *)&error);
19231
0
        JS_FreeValue(ctx, error);
19232
0
        js_async_function_terminate(ctx->rt, s);
19233
0
        JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
19234
0
    } else {
19235
0
        JSValue value;
19236
0
        value = s->func_state.frame.cur_sp[-1];
19237
0
        s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
19238
0
        if (JS_IsUndefined(func_ret)) {
19239
            /* function returned */
19240
0
            ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,
19241
0
                           1, (JSValueConst *)&value);
19242
0
            JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
19243
0
            JS_FreeValue(ctx, value);
19244
0
            js_async_function_terminate(ctx->rt, s);
19245
0
        } else {
19246
0
            JSValue promise, resolving_funcs[2], resolving_funcs1[2];
19247
0
            int i, res;
19248
19249
            /* await */
19250
0
            JS_FreeValue(ctx, func_ret); /* not used */
19251
0
            promise = js_promise_resolve(ctx, ctx->promise_ctor,
19252
0
                                         1, (JSValueConst *)&value, 0);
19253
0
            JS_FreeValue(ctx, value);
19254
0
            if (JS_IsException(promise))
19255
0
                goto fail;
19256
0
            if (js_async_function_resolve_create(ctx, s, resolving_funcs)) {
19257
0
                JS_FreeValue(ctx, promise);
19258
0
                goto fail;
19259
0
            }
19260
19261
            /* Note: no need to create 'thrownawayCapability' as in
19262
               the spec */
19263
0
            for(i = 0; i < 2; i++)
19264
0
                resolving_funcs1[i] = JS_UNDEFINED;
19265
0
            res = perform_promise_then(ctx, promise,
19266
0
                                       (JSValueConst *)resolving_funcs,
19267
0
                                       (JSValueConst *)resolving_funcs1);
19268
0
            JS_FreeValue(ctx, promise);
19269
0
            for(i = 0; i < 2; i++)
19270
0
                JS_FreeValue(ctx, resolving_funcs[i]);
19271
0
            if (res)
19272
0
                goto fail;
19273
0
        }
19274
0
    }
19275
0
}
19276
19277
static JSValue js_async_function_resolve_call(JSContext *ctx,
19278
                                              JSValueConst func_obj,
19279
                                              JSValueConst this_obj,
19280
                                              int argc, JSValueConst *argv,
19281
                                              int flags)
19282
0
{
19283
0
    JSObject *p = JS_VALUE_GET_OBJ(func_obj);
19284
0
    JSAsyncFunctionData *s = p->u.async_function_data;
19285
0
    BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE;
19286
0
    JSValueConst arg;
19287
19288
0
    if (argc > 0)
19289
0
        arg = argv[0];
19290
0
    else
19291
0
        arg = JS_UNDEFINED;
19292
0
    s->func_state.throw_flag = is_reject;
19293
0
    if (is_reject) {
19294
0
        JS_Throw(ctx, JS_DupValue(ctx, arg));
19295
0
    } else {
19296
        /* return value of await */
19297
0
        s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg);
19298
0
    }
19299
0
    js_async_function_resume(ctx, s);
19300
0
    return JS_UNDEFINED;
19301
0
}
19302
19303
static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj,
19304
                                      JSValueConst this_obj,
19305
                                      int argc, JSValueConst *argv, int flags)
19306
0
{
19307
0
    JSValue promise;
19308
0
    JSAsyncFunctionData *s;
19309
19310
0
    s = js_mallocz(ctx, sizeof(*s));
19311
0
    if (!s)
19312
0
        return JS_EXCEPTION;
19313
0
    s->header.ref_count = 1;
19314
0
    add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
19315
0
    s->is_active = FALSE;
19316
0
    s->resolving_funcs[0] = JS_UNDEFINED;
19317
0
    s->resolving_funcs[1] = JS_UNDEFINED;
19318
19319
0
    promise = JS_NewPromiseCapability(ctx, s->resolving_funcs);
19320
0
    if (JS_IsException(promise))
19321
0
        goto fail;
19322
19323
0
    if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
19324
0
    fail:
19325
0
        JS_FreeValue(ctx, promise);
19326
0
        js_async_function_free(ctx->rt, s);
19327
0
        return JS_EXCEPTION;
19328
0
    }
19329
0
    s->is_active = TRUE;
19330
19331
0
    js_async_function_resume(ctx, s);
19332
19333
0
    js_async_function_free(ctx->rt, s);
19334
19335
0
    return promise;
19336
0
}
19337
19338
/* AsyncGenerator */
19339
19340
typedef enum JSAsyncGeneratorStateEnum {
19341
    JS_ASYNC_GENERATOR_STATE_SUSPENDED_START,
19342
    JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD,
19343
    JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
19344
    JS_ASYNC_GENERATOR_STATE_EXECUTING,
19345
    JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN,
19346
    JS_ASYNC_GENERATOR_STATE_COMPLETED,
19347
} JSAsyncGeneratorStateEnum;
19348
19349
typedef struct JSAsyncGeneratorRequest {
19350
    struct list_head link;
19351
    /* completion */
19352
    int completion_type; /* GEN_MAGIC_x */
19353
    JSValue result;
19354
    /* promise capability */
19355
    JSValue promise;
19356
    JSValue resolving_funcs[2];
19357
} JSAsyncGeneratorRequest;
19358
19359
typedef struct JSAsyncGeneratorData {
19360
    JSObject *generator; /* back pointer to the object (const) */
19361
    JSAsyncGeneratorStateEnum state;
19362
    JSAsyncFunctionState func_state;
19363
    struct list_head queue; /* list of JSAsyncGeneratorRequest.link */
19364
} JSAsyncGeneratorData;
19365
19366
static void js_async_generator_free(JSRuntime *rt,
19367
                                    JSAsyncGeneratorData *s)
19368
0
{
19369
0
    struct list_head *el, *el1;
19370
0
    JSAsyncGeneratorRequest *req;
19371
19372
0
    list_for_each_safe(el, el1, &s->queue) {
19373
0
        req = list_entry(el, JSAsyncGeneratorRequest, link);
19374
0
        JS_FreeValueRT(rt, req->result);
19375
0
        JS_FreeValueRT(rt, req->promise);
19376
0
        JS_FreeValueRT(rt, req->resolving_funcs[0]);
19377
0
        JS_FreeValueRT(rt, req->resolving_funcs[1]);
19378
0
        js_free_rt(rt, req);
19379
0
    }
19380
0
    if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
19381
0
        s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
19382
0
        async_func_free(rt, &s->func_state);
19383
0
    }
19384
0
    js_free_rt(rt, s);
19385
0
}
19386
19387
static void js_async_generator_finalizer(JSRuntime *rt, JSValue obj)
19388
0
{
19389
0
    JSAsyncGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_ASYNC_GENERATOR);
19390
19391
0
    if (s) {
19392
0
        js_async_generator_free(rt, s);
19393
0
    }
19394
0
}
19395
19396
static void js_async_generator_mark(JSRuntime *rt, JSValueConst val,
19397
                                    JS_MarkFunc *mark_func)
19398
0
{
19399
0
    JSAsyncGeneratorData *s = JS_GetOpaque(val, JS_CLASS_ASYNC_GENERATOR);
19400
0
    struct list_head *el;
19401
0
    JSAsyncGeneratorRequest *req;
19402
0
    if (s) {
19403
0
        list_for_each(el, &s->queue) {
19404
0
            req = list_entry(el, JSAsyncGeneratorRequest, link);
19405
0
            JS_MarkValue(rt, req->result, mark_func);
19406
0
            JS_MarkValue(rt, req->promise, mark_func);
19407
0
            JS_MarkValue(rt, req->resolving_funcs[0], mark_func);
19408
0
            JS_MarkValue(rt, req->resolving_funcs[1], mark_func);
19409
0
        }
19410
0
        if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
19411
0
            s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
19412
0
            async_func_mark(rt, &s->func_state, mark_func);
19413
0
        }
19414
0
    }
19415
0
}
19416
19417
static JSValue js_async_generator_resolve_function(JSContext *ctx,
19418
                                          JSValueConst this_obj,
19419
                                          int argc, JSValueConst *argv,
19420
                                          int magic, JSValue *func_data);
19421
19422
static int js_async_generator_resolve_function_create(JSContext *ctx,
19423
                                                      JSValueConst generator,
19424
                                                      JSValue *resolving_funcs,
19425
                                                      BOOL is_resume_next)
19426
0
{
19427
0
    int i;
19428
0
    JSValue func;
19429
19430
0
    for(i = 0; i < 2; i++) {
19431
0
        func = JS_NewCFunctionData(ctx, js_async_generator_resolve_function, 1,
19432
0
                                   i + is_resume_next * 2, 1, &generator);
19433
0
        if (JS_IsException(func)) {
19434
0
            if (i == 1)
19435
0
                JS_FreeValue(ctx, resolving_funcs[0]);
19436
0
            return -1;
19437
0
        }
19438
0
        resolving_funcs[i] = func;
19439
0
    }
19440
0
    return 0;
19441
0
}
19442
19443
static int js_async_generator_await(JSContext *ctx,
19444
                                    JSAsyncGeneratorData *s,
19445
                                    JSValueConst value)
19446
0
{
19447
0
    JSValue promise, resolving_funcs[2], resolving_funcs1[2];
19448
0
    int i, res;
19449
19450
0
    promise = js_promise_resolve(ctx, ctx->promise_ctor,
19451
0
                                 1, &value, 0);
19452
0
    if (JS_IsException(promise))
19453
0
        goto fail;
19454
19455
0
    if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator),
19456
0
                                                   resolving_funcs, FALSE)) {
19457
0
        JS_FreeValue(ctx, promise);
19458
0
        goto fail;
19459
0
    }
19460
19461
    /* Note: no need to create 'thrownawayCapability' as in
19462
       the spec */
19463
0
    for(i = 0; i < 2; i++)
19464
0
        resolving_funcs1[i] = JS_UNDEFINED;
19465
0
    res = perform_promise_then(ctx, promise,
19466
0
                               (JSValueConst *)resolving_funcs,
19467
0
                               (JSValueConst *)resolving_funcs1);
19468
0
    JS_FreeValue(ctx, promise);
19469
0
    for(i = 0; i < 2; i++)
19470
0
        JS_FreeValue(ctx, resolving_funcs[i]);
19471
0
    if (res)
19472
0
        goto fail;
19473
0
    return 0;
19474
0
 fail:
19475
0
    return -1;
19476
0
}
19477
19478
static void js_async_generator_resolve_or_reject(JSContext *ctx,
19479
                                                 JSAsyncGeneratorData *s,
19480
                                                 JSValueConst result,
19481
                                                 int is_reject)
19482
0
{
19483
0
    JSAsyncGeneratorRequest *next;
19484
0
    JSValue ret;
19485
19486
0
    next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
19487
0
    list_del(&next->link);
19488
0
    ret = JS_Call(ctx, next->resolving_funcs[is_reject], JS_UNDEFINED, 1,
19489
0
                  &result);
19490
0
    JS_FreeValue(ctx, ret);
19491
0
    JS_FreeValue(ctx, next->result);
19492
0
    JS_FreeValue(ctx, next->promise);
19493
0
    JS_FreeValue(ctx, next->resolving_funcs[0]);
19494
0
    JS_FreeValue(ctx, next->resolving_funcs[1]);
19495
0
    js_free(ctx, next);
19496
0
}
19497
19498
static void js_async_generator_resolve(JSContext *ctx,
19499
                                       JSAsyncGeneratorData *s,
19500
                                       JSValueConst value,
19501
                                       BOOL done)
19502
0
{
19503
0
    JSValue result;
19504
0
    result = js_create_iterator_result(ctx, JS_DupValue(ctx, value), done);
19505
    /* XXX: better exception handling ? */
19506
0
    js_async_generator_resolve_or_reject(ctx, s, result, 0);
19507
0
    JS_FreeValue(ctx, result);
19508
0
 }
19509
19510
static void js_async_generator_reject(JSContext *ctx,
19511
                                       JSAsyncGeneratorData *s,
19512
                                       JSValueConst exception)
19513
0
{
19514
0
    js_async_generator_resolve_or_reject(ctx, s, exception, 1);
19515
0
}
19516
19517
static void js_async_generator_complete(JSContext *ctx,
19518
                                        JSAsyncGeneratorData *s)
19519
0
{
19520
0
    if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) {
19521
0
        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
19522
0
        async_func_free(ctx->rt, &s->func_state);
19523
0
    }
19524
0
}
19525
19526
static int js_async_generator_completed_return(JSContext *ctx,
19527
                                               JSAsyncGeneratorData *s,
19528
                                               JSValueConst value)
19529
0
{
19530
0
    JSValue promise, resolving_funcs[2], resolving_funcs1[2];
19531
0
    int res;
19532
19533
0
    promise = js_promise_resolve(ctx, ctx->promise_ctor,
19534
0
                                 1, (JSValueConst *)&value, 0);
19535
0
    if (JS_IsException(promise))
19536
0
        return -1;
19537
0
    if (js_async_generator_resolve_function_create(ctx,
19538
0
                                                   JS_MKPTR(JS_TAG_OBJECT, s->generator),
19539
0
                                                   resolving_funcs1,
19540
0
                                                   TRUE)) {
19541
0
        JS_FreeValue(ctx, promise);
19542
0
        return -1;
19543
0
    }
19544
0
    resolving_funcs[0] = JS_UNDEFINED;
19545
0
    resolving_funcs[1] = JS_UNDEFINED;
19546
0
    res = perform_promise_then(ctx, promise,
19547
0
                               (JSValueConst *)resolving_funcs1,
19548
0
                               (JSValueConst *)resolving_funcs);
19549
0
    JS_FreeValue(ctx, resolving_funcs1[0]);
19550
0
    JS_FreeValue(ctx, resolving_funcs1[1]);
19551
0
    JS_FreeValue(ctx, promise);
19552
0
    return res;
19553
0
}
19554
19555
static void js_async_generator_resume_next(JSContext *ctx,
19556
                                           JSAsyncGeneratorData *s)
19557
0
{
19558
0
    JSAsyncGeneratorRequest *next;
19559
0
    JSValue func_ret, value;
19560
19561
0
    for(;;) {
19562
0
        if (list_empty(&s->queue))
19563
0
            break;
19564
0
        next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
19565
0
        switch(s->state) {
19566
0
        case JS_ASYNC_GENERATOR_STATE_EXECUTING:
19567
            /* only happens when restarting execution after await() */
19568
0
            goto resume_exec;
19569
0
        case JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN:
19570
0
            goto done;
19571
0
        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_START:
19572
0
            if (next->completion_type == GEN_MAGIC_NEXT) {
19573
0
                goto exec_no_arg;
19574
0
            } else {
19575
0
                js_async_generator_complete(ctx, s);
19576
0
            }
19577
0
            break;
19578
0
        case JS_ASYNC_GENERATOR_STATE_COMPLETED:
19579
0
            if (next->completion_type == GEN_MAGIC_NEXT) {
19580
0
                js_async_generator_resolve(ctx, s, JS_UNDEFINED, TRUE);
19581
0
            } else if (next->completion_type == GEN_MAGIC_RETURN) {
19582
0
                s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN;
19583
0
                js_async_generator_completed_return(ctx, s, next->result);
19584
0
                goto done;
19585
0
            } else {
19586
0
                js_async_generator_reject(ctx, s, next->result);
19587
0
            }
19588
0
            goto done;
19589
0
        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD:
19590
0
        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
19591
0
            value = JS_DupValue(ctx, next->result);
19592
0
            if (next->completion_type == GEN_MAGIC_THROW &&
19593
0
                s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) {
19594
0
                JS_Throw(ctx, value);
19595
0
                s->func_state.throw_flag = TRUE;
19596
0
            } else {
19597
                /* 'yield' returns a value. 'yield *' also returns a value
19598
                   in case the 'throw' method is called */
19599
0
                s->func_state.frame.cur_sp[-1] = value;
19600
0
                s->func_state.frame.cur_sp[0] =
19601
0
                    JS_NewInt32(ctx, next->completion_type);
19602
0
                s->func_state.frame.cur_sp++;
19603
0
            exec_no_arg:
19604
0
                s->func_state.throw_flag = FALSE;
19605
0
            }
19606
0
            s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING;
19607
0
        resume_exec:
19608
0
            func_ret = async_func_resume(ctx, &s->func_state);
19609
0
            if (JS_IsException(func_ret)) {
19610
0
                value = JS_GetException(ctx);
19611
0
                js_async_generator_complete(ctx, s);
19612
0
                js_async_generator_reject(ctx, s, value);
19613
0
                JS_FreeValue(ctx, value);
19614
0
            } else if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
19615
0
                int func_ret_code;
19616
0
                value = s->func_state.frame.cur_sp[-1];
19617
0
                s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
19618
0
                func_ret_code = JS_VALUE_GET_INT(func_ret);
19619
0
                switch(func_ret_code) {
19620
0
                case FUNC_RET_YIELD:
19621
0
                case FUNC_RET_YIELD_STAR:
19622
0
                    if (func_ret_code == FUNC_RET_YIELD_STAR)
19623
0
                        s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
19624
0
                    else
19625
0
                        s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD;
19626
0
                    js_async_generator_resolve(ctx, s, value, FALSE);
19627
0
                    JS_FreeValue(ctx, value);
19628
0
                    break;
19629
0
                case FUNC_RET_AWAIT:
19630
0
                    js_async_generator_await(ctx, s, value);
19631
0
                    JS_FreeValue(ctx, value);
19632
0
                    goto done;
19633
0
                default:
19634
0
                    abort();
19635
0
                }
19636
0
            } else {
19637
0
                assert(JS_IsUndefined(func_ret));
19638
                /* end of function */
19639
0
                value = s->func_state.frame.cur_sp[-1];
19640
0
                s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
19641
0
                js_async_generator_complete(ctx, s);
19642
0
                js_async_generator_resolve(ctx, s, value, TRUE);
19643
0
                JS_FreeValue(ctx, value);
19644
0
            }
19645
0
            break;
19646
0
        default:
19647
0
            abort();
19648
0
        }
19649
0
    }
19650
0
 done: ;
19651
0
}
19652
19653
static JSValue js_async_generator_resolve_function(JSContext *ctx,
19654
                                                   JSValueConst this_obj,
19655
                                                   int argc, JSValueConst *argv,
19656
                                                   int magic, JSValue *func_data)
19657
0
{
19658
0
    BOOL is_reject = magic & 1;
19659
0
    JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR);
19660
0
    JSValueConst arg = argv[0];
19661
19662
    /* XXX: what if s == NULL */
19663
19664
0
    if (magic >= 2) {
19665
        /* resume next case in AWAITING_RETURN state */
19666
0
        assert(s->state == JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN ||
19667
0
               s->state == JS_ASYNC_GENERATOR_STATE_COMPLETED);
19668
0
        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
19669
0
        if (is_reject) {
19670
0
            js_async_generator_reject(ctx, s, arg);
19671
0
        } else {
19672
0
            js_async_generator_resolve(ctx, s, arg, TRUE);
19673
0
        }
19674
0
    } else {
19675
        /* restart function execution after await() */
19676
0
        assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING);
19677
0
        s->func_state.throw_flag = is_reject;
19678
0
        if (is_reject) {
19679
0
            JS_Throw(ctx, JS_DupValue(ctx, arg));
19680
0
        } else {
19681
            /* return value of await */
19682
0
            s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg);
19683
0
        }
19684
0
        js_async_generator_resume_next(ctx, s);
19685
0
    }
19686
0
    return JS_UNDEFINED;
19687
0
}
19688
19689
/* magic = GEN_MAGIC_x */
19690
static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val,
19691
                                       int argc, JSValueConst *argv,
19692
                                       int magic)
19693
0
{
19694
0
    JSAsyncGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_GENERATOR);
19695
0
    JSValue promise, resolving_funcs[2];
19696
0
    JSAsyncGeneratorRequest *req;
19697
19698
0
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
19699
0
    if (JS_IsException(promise))
19700
0
        return JS_EXCEPTION;
19701
0
    if (!s) {
19702
0
        JSValue err, res2;
19703
0
        JS_ThrowTypeError(ctx, "not an AsyncGenerator object");
19704
0
        err = JS_GetException(ctx);
19705
0
        res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
19706
0
                       1, (JSValueConst *)&err);
19707
0
        JS_FreeValue(ctx, err);
19708
0
        JS_FreeValue(ctx, res2);
19709
0
        JS_FreeValue(ctx, resolving_funcs[0]);
19710
0
        JS_FreeValue(ctx, resolving_funcs[1]);
19711
0
        return promise;
19712
0
    }
19713
0
    req = js_mallocz(ctx, sizeof(*req));
19714
0
    if (!req)
19715
0
        goto fail;
19716
0
    req->completion_type = magic;
19717
0
    req->result = JS_DupValue(ctx, argv[0]);
19718
0
    req->promise = JS_DupValue(ctx, promise);
19719
0
    req->resolving_funcs[0] = resolving_funcs[0];
19720
0
    req->resolving_funcs[1] = resolving_funcs[1];
19721
0
    list_add_tail(&req->link, &s->queue);
19722
0
    if (s->state != JS_ASYNC_GENERATOR_STATE_EXECUTING) {
19723
0
        js_async_generator_resume_next(ctx, s);
19724
0
    }
19725
0
    return promise;
19726
0
 fail:
19727
0
    JS_FreeValue(ctx, resolving_funcs[0]);
19728
0
    JS_FreeValue(ctx, resolving_funcs[1]);
19729
0
    JS_FreeValue(ctx, promise);
19730
0
    return JS_EXCEPTION;
19731
0
}
19732
19733
static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst func_obj,
19734
                                                JSValueConst this_obj,
19735
                                                int argc, JSValueConst *argv,
19736
                                                int flags)
19737
0
{
19738
0
    JSValue obj, func_ret;
19739
0
    JSAsyncGeneratorData *s;
19740
19741
0
    s = js_mallocz(ctx, sizeof(*s));
19742
0
    if (!s)
19743
0
        return JS_EXCEPTION;
19744
0
    s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START;
19745
0
    init_list_head(&s->queue);
19746
0
    if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
19747
0
        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
19748
0
        goto fail;
19749
0
    }
19750
19751
    /* execute the function up to 'OP_initial_yield' (no yield nor
19752
       await are possible) */
19753
0
    func_ret = async_func_resume(ctx, &s->func_state);
19754
0
    if (JS_IsException(func_ret))
19755
0
        goto fail;
19756
0
    JS_FreeValue(ctx, func_ret);
19757
19758
0
    obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_ASYNC_GENERATOR);
19759
0
    if (JS_IsException(obj))
19760
0
        goto fail;
19761
0
    s->generator = JS_VALUE_GET_OBJ(obj);
19762
0
    JS_SetOpaque(obj, s);
19763
0
    return obj;
19764
0
 fail:
19765
0
    js_async_generator_free(ctx->rt, s);
19766
0
    return JS_EXCEPTION;
19767
0
}
19768
19769
/* JS parser */
19770
19771
enum {
19772
    TOK_NUMBER = -128,
19773
    TOK_STRING,
19774
    TOK_TEMPLATE,
19775
    TOK_IDENT,
19776
    TOK_REGEXP,
19777
    /* warning: order matters (see js_parse_assign_expr) */
19778
    TOK_MUL_ASSIGN,
19779
    TOK_DIV_ASSIGN,
19780
    TOK_MOD_ASSIGN,
19781
    TOK_PLUS_ASSIGN,
19782
    TOK_MINUS_ASSIGN,
19783
    TOK_SHL_ASSIGN,
19784
    TOK_SAR_ASSIGN,
19785
    TOK_SHR_ASSIGN,
19786
    TOK_AND_ASSIGN,
19787
    TOK_XOR_ASSIGN,
19788
    TOK_OR_ASSIGN,
19789
#ifdef CONFIG_BIGNUM
19790
    TOK_MATH_POW_ASSIGN,
19791
#endif
19792
    TOK_POW_ASSIGN,
19793
    TOK_LAND_ASSIGN,
19794
    TOK_LOR_ASSIGN,
19795
    TOK_DOUBLE_QUESTION_MARK_ASSIGN,
19796
    TOK_DEC,
19797
    TOK_INC,
19798
    TOK_SHL,
19799
    TOK_SAR,
19800
    TOK_SHR,
19801
    TOK_LT,
19802
    TOK_LTE,
19803
    TOK_GT,
19804
    TOK_GTE,
19805
    TOK_EQ,
19806
    TOK_STRICT_EQ,
19807
    TOK_NEQ,
19808
    TOK_STRICT_NEQ,
19809
    TOK_LAND,
19810
    TOK_LOR,
19811
#ifdef CONFIG_BIGNUM
19812
    TOK_MATH_POW,
19813
#endif
19814
    TOK_POW,
19815
    TOK_ARROW,
19816
    TOK_ELLIPSIS,
19817
    TOK_DOUBLE_QUESTION_MARK,
19818
    TOK_QUESTION_MARK_DOT,
19819
    TOK_ERROR,
19820
    TOK_PRIVATE_NAME,
19821
    TOK_EOF,
19822
    /* keywords: WARNING: same order as atoms */
19823
    TOK_NULL, /* must be first */
19824
    TOK_FALSE,
19825
    TOK_TRUE,
19826
    TOK_IF,
19827
    TOK_ELSE,
19828
    TOK_RETURN,
19829
    TOK_VAR,
19830
    TOK_THIS,
19831
    TOK_DELETE,
19832
    TOK_VOID,
19833
    TOK_TYPEOF,
19834
    TOK_NEW,
19835
    TOK_IN,
19836
    TOK_INSTANCEOF,
19837
    TOK_DO,
19838
    TOK_WHILE,
19839
    TOK_FOR,
19840
    TOK_BREAK,
19841
    TOK_CONTINUE,
19842
    TOK_SWITCH,
19843
    TOK_CASE,
19844
    TOK_DEFAULT,
19845
    TOK_THROW,
19846
    TOK_TRY,
19847
    TOK_CATCH,
19848
    TOK_FINALLY,
19849
    TOK_FUNCTION,
19850
    TOK_DEBUGGER,
19851
    TOK_WITH,
19852
    /* FutureReservedWord */
19853
    TOK_CLASS,
19854
    TOK_CONST,
19855
    TOK_ENUM,
19856
    TOK_EXPORT,
19857
    TOK_EXTENDS,
19858
    TOK_IMPORT,
19859
    TOK_SUPER,
19860
    /* FutureReservedWords when parsing strict mode code */
19861
    TOK_IMPLEMENTS,
19862
    TOK_INTERFACE,
19863
    TOK_LET,
19864
    TOK_PACKAGE,
19865
    TOK_PRIVATE,
19866
    TOK_PROTECTED,
19867
    TOK_PUBLIC,
19868
    TOK_STATIC,
19869
    TOK_YIELD,
19870
    TOK_AWAIT, /* must be last */
19871
    TOK_OF,     /* only used for js_parse_skip_parens_token() */
19872
};
19873
19874
4.62M
#define TOK_FIRST_KEYWORD   TOK_NULL
19875
2.12M
#define TOK_LAST_KEYWORD    TOK_AWAIT
19876
19877
/* unicode code points */
19878
#define CP_NBSP 0x00a0
19879
#define CP_BOM  0xfeff
19880
19881
3.25M
#define CP_LS   0x2028
19882
1.62M
#define CP_PS   0x2029
19883
19884
typedef struct BlockEnv {
19885
    struct BlockEnv *prev;
19886
    JSAtom label_name; /* JS_ATOM_NULL if none */
19887
    int label_break; /* -1 if none */
19888
    int label_cont; /* -1 if none */
19889
    int drop_count; /* number of stack elements to drop */
19890
    int label_finally; /* -1 if none */
19891
    int scope_level;
19892
    int has_iterator;
19893
} BlockEnv;
19894
19895
typedef struct JSGlobalVar {
19896
    int cpool_idx; /* if >= 0, index in the constant pool for hoisted
19897
                      function defintion*/
19898
    uint8_t force_init : 1; /* force initialization to undefined */
19899
    uint8_t is_lexical : 1; /* global let/const definition */
19900
    uint8_t is_const   : 1; /* const definition */
19901
    int scope_level;    /* scope of definition */
19902
    JSAtom var_name;  /* variable name */
19903
} JSGlobalVar;
19904
19905
typedef struct RelocEntry {
19906
    struct RelocEntry *next;
19907
    uint32_t addr; /* address to patch */
19908
    int size;   /* address size: 1, 2 or 4 bytes */
19909
} RelocEntry;
19910
19911
typedef struct JumpSlot {
19912
    int op;
19913
    int size;
19914
    int pos;
19915
    int label;
19916
} JumpSlot;
19917
19918
typedef struct LabelSlot {
19919
    int ref_count;
19920
    int pos;    /* phase 1 address, -1 means not resolved yet */
19921
    int pos2;   /* phase 2 address, -1 means not resolved yet */
19922
    int addr;   /* phase 3 address, -1 means not resolved yet */
19923
    RelocEntry *first_reloc;
19924
} LabelSlot;
19925
19926
typedef struct LineNumberSlot {
19927
    uint32_t pc;
19928
    int line_num;
19929
} LineNumberSlot;
19930
19931
typedef enum JSParseFunctionEnum {
19932
    JS_PARSE_FUNC_STATEMENT,
19933
    JS_PARSE_FUNC_VAR,
19934
    JS_PARSE_FUNC_EXPR,
19935
    JS_PARSE_FUNC_ARROW,
19936
    JS_PARSE_FUNC_GETTER,
19937
    JS_PARSE_FUNC_SETTER,
19938
    JS_PARSE_FUNC_METHOD,
19939
    JS_PARSE_FUNC_CLASS_CONSTRUCTOR,
19940
    JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR,
19941
} JSParseFunctionEnum;
19942
19943
typedef enum JSParseExportEnum {
19944
    JS_PARSE_EXPORT_NONE,
19945
    JS_PARSE_EXPORT_NAMED,
19946
    JS_PARSE_EXPORT_DEFAULT,
19947
} JSParseExportEnum;
19948
19949
typedef struct JSFunctionDef {
19950
    JSContext *ctx;
19951
    struct JSFunctionDef *parent;
19952
    int parent_cpool_idx; /* index in the constant pool of the parent
19953
                             or -1 if none */
19954
    int parent_scope_level; /* scope level in parent at point of definition */
19955
    struct list_head child_list; /* list of JSFunctionDef.link */
19956
    struct list_head link;
19957
19958
    BOOL is_eval; /* TRUE if eval code */
19959
    int eval_type; /* only valid if is_eval = TRUE */
19960
    BOOL is_global_var; /* TRUE if variables are not defined locally:
19961
                           eval global, eval module or non strict eval */
19962
    BOOL is_func_expr; /* TRUE if function expression */
19963
    BOOL has_home_object; /* TRUE if the home object is available */
19964
    BOOL has_prototype; /* true if a prototype field is necessary */
19965
    BOOL has_simple_parameter_list;
19966
    BOOL has_parameter_expressions; /* if true, an argument scope is created */
19967
    BOOL has_use_strict; /* to reject directive in special cases */
19968
    BOOL has_eval_call; /* true if the function contains a call to eval() */
19969
    BOOL has_arguments_binding; /* true if the 'arguments' binding is
19970
                                   available in the function */
19971
    BOOL has_this_binding; /* true if the 'this' and new.target binding are
19972
                              available in the function */
19973
    BOOL new_target_allowed; /* true if the 'new.target' does not
19974
                                throw a syntax error */
19975
    BOOL super_call_allowed; /* true if super() is allowed */
19976
    BOOL super_allowed; /* true if super. or super[] is allowed */
19977
    BOOL arguments_allowed; /* true if the 'arguments' identifier is allowed */
19978
    BOOL is_derived_class_constructor;
19979
    BOOL in_function_body;
19980
    BOOL backtrace_barrier;
19981
    JSFunctionKindEnum func_kind : 8;
19982
    JSParseFunctionEnum func_type : 8;
19983
    uint8_t js_mode; /* bitmap of JS_MODE_x */
19984
    JSAtom func_name; /* JS_ATOM_NULL if no name */
19985
19986
    JSVarDef *vars;
19987
    int var_size; /* allocated size for vars[] */
19988
    int var_count;
19989
    JSVarDef *args;
19990
    int arg_size; /* allocated size for args[] */
19991
    int arg_count; /* number of arguments */
19992
    int defined_arg_count;
19993
    int var_object_idx; /* -1 if none */
19994
    int arg_var_object_idx; /* -1 if none (var object for the argument scope) */
19995
    int arguments_var_idx; /* -1 if none */
19996
    int arguments_arg_idx; /* argument variable definition in argument scope, 
19997
                              -1 if none */
19998
    int func_var_idx; /* variable containing the current function (-1
19999
                         if none, only used if is_func_expr is true) */
20000
    int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */
20001
    int this_var_idx; /* variable containg the 'this' value, -1 if none */
20002
    int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */
20003
    int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */
20004
    int home_object_var_idx;
20005
    BOOL need_home_object;
20006
    
20007
    int scope_level;    /* index into fd->scopes if the current lexical scope */
20008
    int scope_first;    /* index into vd->vars of first lexically scoped variable */
20009
    int scope_size;     /* allocated size of fd->scopes array */
20010
    int scope_count;    /* number of entries used in the fd->scopes array */
20011
    JSVarScope *scopes;
20012
    JSVarScope def_scope_array[4];
20013
    int body_scope; /* scope of the body of the function or eval */
20014
20015
    int global_var_count;
20016
    int global_var_size;
20017
    JSGlobalVar *global_vars;
20018
20019
    DynBuf byte_code;
20020
    int last_opcode_pos; /* -1 if no last opcode */
20021
    int last_opcode_line_num;
20022
    BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */
20023
    
20024
    LabelSlot *label_slots;
20025
    int label_size; /* allocated size for label_slots[] */
20026
    int label_count;
20027
    BlockEnv *top_break; /* break/continue label stack */
20028
20029
    /* constant pool (strings, functions, numbers) */
20030
    JSValue *cpool;
20031
    int cpool_count;
20032
    int cpool_size;
20033
20034
    /* list of variables in the closure */
20035
    int closure_var_count;
20036
    int closure_var_size;
20037
    JSClosureVar *closure_var;
20038
20039
    JumpSlot *jump_slots;
20040
    int jump_size;
20041
    int jump_count;
20042
20043
    LineNumberSlot *line_number_slots;
20044
    int line_number_size;
20045
    int line_number_count;
20046
    int line_number_last;
20047
    int line_number_last_pc;
20048
20049
    /* pc2line table */
20050
    JSAtom filename;
20051
    int line_num;
20052
    DynBuf pc2line;
20053
20054
    char *source;  /* raw source, utf-8 encoded */
20055
    int source_len;
20056
20057
    JSModuleDef *module; /* != NULL when parsing a module */
20058
} JSFunctionDef;
20059
20060
typedef struct JSToken {
20061
    int val;
20062
    int line_num;   /* line number of token start */
20063
    const uint8_t *ptr;
20064
    union {
20065
        struct {
20066
            JSValue str;
20067
            int sep;
20068
        } str;
20069
        struct {
20070
            JSValue val;
20071
#ifdef CONFIG_BIGNUM
20072
            slimb_t exponent; /* may be != 0 only if val is a float */
20073
#endif
20074
        } num;
20075
        struct {
20076
            JSAtom atom;
20077
            BOOL has_escape;
20078
            BOOL is_reserved;
20079
        } ident;
20080
        struct {
20081
            JSValue body;
20082
            JSValue flags;
20083
        } regexp;
20084
    } u;
20085
} JSToken;
20086
20087
typedef struct JSParseState {
20088
    JSContext *ctx;
20089
    int last_line_num;  /* line number of last token */
20090
    int line_num;       /* line number of current offset */
20091
    const char *filename;
20092
    JSToken token;
20093
    BOOL got_lf; /* true if got line feed before the current token */
20094
    const uint8_t *last_ptr;
20095
    const uint8_t *buf_ptr;
20096
    const uint8_t *buf_end;
20097
20098
    /* current function code */
20099
    JSFunctionDef *cur_func;
20100
    BOOL is_module; /* parsing a module */
20101
    BOOL allow_html_comments;
20102
    BOOL ext_json; /* true if accepting JSON superset */
20103
} JSParseState;
20104
20105
typedef struct JSOpCode {
20106
#ifdef DUMP_BYTECODE
20107
    const char *name;
20108
#endif
20109
    uint8_t size; /* in bytes */
20110
    /* the opcodes remove n_pop items from the top of the stack, then
20111
       pushes n_push items */
20112
    uint8_t n_pop;
20113
    uint8_t n_push;
20114
    uint8_t fmt;
20115
} JSOpCode;
20116
20117
static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = {
20118
#define FMT(f)
20119
#ifdef DUMP_BYTECODE
20120
#define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f },
20121
#else
20122
#define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f },
20123
#endif
20124
#include "quickjs-opcode.h"
20125
#undef DEF
20126
#undef FMT
20127
};
20128
20129
#if SHORT_OPCODES
20130
/* After the final compilation pass, short opcodes are used. Their
20131
   opcodes overlap with the temporary opcodes which cannot appear in
20132
   the final bytecode. Their description is after the temporary
20133
   opcodes in opcode_info[]. */
20134
#define short_opcode_info(op)           \
20135
9.91M
    opcode_info[(op) >= OP_TEMP_START ? \
20136
9.91M
                (op) + (OP_TEMP_END - OP_TEMP_START) : (op)]
20137
#else
20138
#define short_opcode_info(op) opcode_info[op]
20139
#endif
20140
20141
static __exception int next_token(JSParseState *s);
20142
20143
static void free_token(JSParseState *s, JSToken *token)
20144
3.73M
{
20145
3.73M
    switch(token->val) {
20146
0
#ifdef CONFIG_BIGNUM
20147
65.8k
    case TOK_NUMBER:
20148
65.8k
        JS_FreeValue(s->ctx, token->u.num.val);
20149
65.8k
        break;
20150
0
#endif
20151
21.9k
    case TOK_STRING:
20152
51.9k
    case TOK_TEMPLATE:
20153
51.9k
        JS_FreeValue(s->ctx, token->u.str.str);
20154
51.9k
        break;
20155
18.8k
    case TOK_REGEXP:
20156
18.8k
        JS_FreeValue(s->ctx, token->u.regexp.body);
20157
18.8k
        JS_FreeValue(s->ctx, token->u.regexp.flags);
20158
18.8k
        break;
20159
1.33M
    case TOK_IDENT:
20160
1.34M
    case TOK_PRIVATE_NAME:
20161
1.34M
        JS_FreeAtom(s->ctx, token->u.ident.atom);
20162
1.34M
        break;
20163
2.25M
    default:
20164
2.25M
        if (token->val >= TOK_FIRST_KEYWORD &&
20165
2.25M
            token->val <= TOK_LAST_KEYWORD) {
20166
95.9k
            JS_FreeAtom(s->ctx, token->u.ident.atom);
20167
95.9k
        }
20168
2.25M
        break;
20169
3.73M
    }
20170
3.73M
}
20171
20172
static void __attribute((unused)) dump_token(JSParseState *s,
20173
                                             const JSToken *token)
20174
0
{
20175
0
    switch(token->val) {
20176
0
    case TOK_NUMBER:
20177
0
        {
20178
0
            double d;
20179
0
            JS_ToFloat64(s->ctx, &d, token->u.num.val);  /* no exception possible */
20180
0
            printf("number: %.14g\n", d);
20181
0
        }
20182
0
        break;
20183
0
    case TOK_IDENT:
20184
0
    dump_atom:
20185
0
        {
20186
0
            char buf[ATOM_GET_STR_BUF_SIZE];
20187
0
            printf("ident: '%s'\n",
20188
0
                   JS_AtomGetStr(s->ctx, buf, sizeof(buf), token->u.ident.atom));
20189
0
        }
20190
0
        break;
20191
0
    case TOK_STRING:
20192
0
        {
20193
0
            const char *str;
20194
0
            /* XXX: quote the string */
20195
0
            str = JS_ToCString(s->ctx, token->u.str.str);
20196
0
            printf("string: '%s'\n", str);
20197
0
            JS_FreeCString(s->ctx, str);
20198
0
        }
20199
0
        break;
20200
0
    case TOK_TEMPLATE:
20201
0
        {
20202
0
            const char *str;
20203
0
            str = JS_ToCString(s->ctx, token->u.str.str);
20204
0
            printf("template: `%s`\n", str);
20205
0
            JS_FreeCString(s->ctx, str);
20206
0
        }
20207
0
        break;
20208
0
    case TOK_REGEXP:
20209
0
        {
20210
0
            const char *str, *str2;
20211
0
            str = JS_ToCString(s->ctx, token->u.regexp.body);
20212
0
            str2 = JS_ToCString(s->ctx, token->u.regexp.flags);
20213
0
            printf("regexp: '%s' '%s'\n", str, str2);
20214
0
            JS_FreeCString(s->ctx, str);
20215
0
            JS_FreeCString(s->ctx, str2);
20216
0
        }
20217
0
        break;
20218
0
    case TOK_EOF:
20219
0
        printf("eof\n");
20220
0
        break;
20221
0
    default:
20222
0
        if (s->token.val >= TOK_NULL && s->token.val <= TOK_LAST_KEYWORD) {
20223
0
            goto dump_atom;
20224
0
        } else if (s->token.val >= 256) {
20225
0
            printf("token: %d\n", token->val);
20226
0
        } else {
20227
0
            printf("token: '%c'\n", token->val);
20228
0
        }
20229
0
        break;
20230
0
    }
20231
0
}
20232
20233
int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const char *fmt, ...)
20234
958
{
20235
958
    JSContext *ctx = s->ctx;
20236
958
    va_list ap;
20237
958
    int backtrace_flags;
20238
    
20239
958
    va_start(ap, fmt);
20240
958
    JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE);
20241
958
    va_end(ap);
20242
958
    backtrace_flags = 0;
20243
958
    if (s->cur_func && s->cur_func->backtrace_barrier)
20244
0
        backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
20245
958
    build_backtrace(ctx, ctx->rt->current_exception, s->filename, s->line_num,
20246
958
                    backtrace_flags);
20247
958
    return -1;
20248
958
}
20249
20250
static int js_parse_expect(JSParseState *s, int tok)
20251
128k
{
20252
128k
    if (s->token.val != tok) {
20253
        /* XXX: dump token correctly in all cases */
20254
38
        return js_parse_error(s, "expecting '%c'", tok);
20255
38
    }
20256
128k
    return next_token(s);
20257
128k
}
20258
20259
static int js_parse_expect_semi(JSParseState *s)
20260
125k
{
20261
125k
    if (s->token.val != ';') {
20262
        /* automatic insertion of ';' */
20263
116k
        if (s->token.val == TOK_EOF || s->token.val == '}' || s->got_lf) {
20264
116k
            return 0;
20265
116k
        }
20266
45
        return js_parse_error(s, "expecting '%c'", ';');
20267
116k
    }
20268
8.64k
    return next_token(s);
20269
125k
}
20270
20271
static int js_parse_error_reserved_identifier(JSParseState *s)
20272
0
{
20273
0
    char buf1[ATOM_GET_STR_BUF_SIZE];
20274
0
    return js_parse_error(s, "'%s' is a reserved identifier",
20275
0
                          JS_AtomGetStr(s->ctx, buf1, sizeof(buf1),
20276
0
                                        s->token.u.ident.atom));
20277
0
}
20278
20279
static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
20280
30.0k
{
20281
30.0k
    uint32_t c;
20282
30.0k
    StringBuffer b_s, *b = &b_s;
20283
20284
    /* p points to the first byte of the template part */
20285
30.0k
    if (string_buffer_init(s->ctx, b, 32))
20286
0
        goto fail;
20287
3.04M
    for(;;) {
20288
3.04M
        if (p >= s->buf_end)
20289
0
            goto unexpected_eof;
20290
3.04M
        c = *p++;
20291
3.04M
        if (c == '`') {
20292
            /* template end part */
20293
20.2k
            break;
20294
20.2k
        }
20295
3.02M
        if (c == '$' && *p == '{') {
20296
            /* template start or middle part */
20297
9.74k
            p++;
20298
9.74k
            break;
20299
9.74k
        }
20300
3.01M
        if (c == '\\') {
20301
6.78k
            if (string_buffer_putc8(b, c))
20302
0
                goto fail;
20303
6.78k
            if (p >= s->buf_end)
20304
0
                goto unexpected_eof;
20305
6.78k
            c = *p++;
20306
6.78k
        }
20307
        /* newline sequences are normalized as single '\n' bytes */
20308
3.01M
        if (c == '\r') {
20309
169k
            if (*p == '\n')
20310
542
                p++;
20311
169k
            c = '\n';
20312
169k
        }
20313
3.01M
        if (c == '\n') {
20314
205k
            s->line_num++;
20315
2.80M
        } else if (c >= 0x80) {
20316
4.34k
            const uint8_t *p_next;
20317
4.34k
            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
20318
4.34k
            if (c > 0x10FFFF) {
20319
130
                js_parse_error(s, "invalid UTF-8 sequence");
20320
130
                goto fail;
20321
130
            }
20322
4.21k
            p = p_next;
20323
4.21k
        }
20324
3.01M
        if (string_buffer_putc(b, c))
20325
0
            goto fail;
20326
3.01M
    }
20327
29.9k
    s->token.val = TOK_TEMPLATE;
20328
29.9k
    s->token.u.str.sep = c;
20329
29.9k
    s->token.u.str.str = string_buffer_end(b);
20330
29.9k
    s->buf_ptr = p;
20331
29.9k
    return 0;
20332
20333
0
 unexpected_eof:
20334
0
    js_parse_error(s, "unexpected end of string");
20335
130
 fail:
20336
130
    string_buffer_free(b);
20337
130
    return -1;
20338
0
}
20339
20340
static __exception int js_parse_string(JSParseState *s, int sep,
20341
                                       BOOL do_throw, const uint8_t *p,
20342
                                       JSToken *token, const uint8_t **pp)
20343
41.7k
{
20344
41.7k
    int ret;
20345
41.7k
    uint32_t c;
20346
41.7k
    StringBuffer b_s, *b = &b_s;
20347
20348
    /* string */
20349
41.7k
    if (string_buffer_init(s->ctx, b, 32))
20350
0
        goto fail;
20351
1.98M
    for(;;) {
20352
1.98M
        if (p >= s->buf_end)
20353
3
            goto invalid_char;
20354
1.98M
        c = *p;
20355
1.98M
        if (c < 0x20) {
20356
256k
            if (!s->cur_func) {
20357
0
                if (do_throw)
20358
0
                    js_parse_error(s, "invalid character in a JSON string");
20359
0
                goto fail;
20360
0
            }
20361
256k
            if (sep == '`') {
20362
213k
                if (c == '\r') {
20363
82.6k
                    if (p[1] == '\n')
20364
283
                        p++;
20365
82.6k
                    c = '\n';
20366
82.6k
                }
20367
                /* do not update s->line_num */
20368
213k
            } else if (c == '\n' || c == '\r')
20369
5
                goto invalid_char;
20370
256k
        }
20371
1.98M
        p++;
20372
1.98M
        if (c == sep)
20373
36.1k
            break;
20374
1.94M
        if (c == '$' && *p == '{' && sep == '`') {
20375
            /* template start or middle part */
20376
5.48k
            p++;
20377
5.48k
            break;
20378
5.48k
        }
20379
1.94M
        if (c == '\\') {
20380
4.52k
            c = *p;
20381
            /* XXX: need a specific JSON case to avoid
20382
               accepting invalid escapes */
20383
4.52k
            switch(c) {
20384
205
            case '\0':
20385
205
                if (p >= s->buf_end)
20386
0
                    goto invalid_char;
20387
205
                p++;
20388
205
                break;
20389
0
            case '\'':
20390
4
            case '\"':
20391
2.26k
            case '\\':
20392
2.26k
                p++;
20393
2.26k
                break;
20394
74
            case '\r':  /* accept DOS and MAC newline sequences */
20395
74
                if (p[1] == '\n') {
20396
0
                    p++;
20397
0
                }
20398
                /* fall thru */
20399
292
            case '\n':
20400
                /* ignore escaped newline sequence */
20401
292
                p++;
20402
292
                if (sep != '`')
20403
79
                    s->line_num++;
20404
292
                continue;
20405
1.75k
            default:
20406
1.75k
                if (c >= '0' && c <= '9') {
20407
213
                    if (!s->cur_func)
20408
0
                        goto invalid_escape; /* JSON case */
20409
213
                    if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`')
20410
25
                        goto parse_escape;
20411
188
                    if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) {
20412
167
                        p++;
20413
167
                        c = '\0';
20414
167
                    } else {
20415
21
                        if (c >= '8' || sep == '`') {
20416
                            /* Note: according to ES2021, \8 and \9 are not
20417
                               accepted in strict mode or in templates. */
20418
21
                            goto invalid_escape;
20419
21
                        } else {
20420
0
                            if (do_throw)
20421
0
                                js_parse_error(s, "octal escape sequences are not allowed in strict mode");
20422
0
                        }
20423
0
                        goto fail;
20424
21
                    }
20425
1.54k
                } else if (c >= 0x80) {
20426
11
                    const uint8_t *p_next;
20427
11
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
20428
11
                    if (c > 0x10FFFF) {
20429
0
                        goto invalid_utf8;
20430
0
                    }
20431
11
                    p = p_next;
20432
                    /* LS or PS are skipped */
20433
11
                    if (c == CP_LS || c == CP_PS)
20434
0
                        continue;
20435
1.53k
                } else {
20436
1.55k
                parse_escape:
20437
1.55k
                    ret = lre_parse_escape(&p, TRUE);
20438
1.55k
                    if (ret == -1) {
20439
22
                    invalid_escape:
20440
22
                        if (do_throw)
20441
0
                            js_parse_error(s, "malformed escape sequence in string literal");
20442
22
                        goto fail;
20443
1.55k
                    } else if (ret < 0) {
20444
                        /* ignore the '\' (could output a warning) */
20445
1.45k
                        p++;
20446
1.45k
                    } else {
20447
102
                        c = ret;
20448
102
                    }
20449
1.55k
                }
20450
1.73k
                break;
20451
4.52k
            }
20452
1.93M
        } else if (c >= 0x80) {
20453
2.66k
            const uint8_t *p_next;
20454
2.66k
            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
20455
2.66k
            if (c > 0x10FFFF)
20456
120
                goto invalid_utf8;
20457
2.54k
            p = p_next;
20458
2.54k
        }
20459
1.93M
        if (string_buffer_putc(b, c))
20460
1
            goto fail;
20461
1.93M
    }
20462
41.6k
    token->val = TOK_STRING;
20463
41.6k
    token->u.str.sep = c;
20464
41.6k
    token->u.str.str = string_buffer_end(b);
20465
41.6k
    *pp = p;
20466
41.6k
    return 0;
20467
20468
120
 invalid_utf8:
20469
120
    if (do_throw)
20470
120
        js_parse_error(s, "invalid UTF-8 sequence");
20471
120
    goto fail;
20472
8
 invalid_char:
20473
8
    if (do_throw)
20474
8
        js_parse_error(s, "unexpected end of string");
20475
151
 fail:
20476
151
    string_buffer_free(b);
20477
151
    return -1;
20478
8
}
20479
20480
2.26M
static inline BOOL token_is_pseudo_keyword(JSParseState *s, JSAtom atom) {
20481
2.26M
    return s->token.val == TOK_IDENT && s->token.u.ident.atom == atom &&
20482
2.26M
        !s->token.u.ident.has_escape;
20483
2.26M
}
20484
20485
static __exception int js_parse_regexp(JSParseState *s)
20486
18.8k
{
20487
18.8k
    const uint8_t *p;
20488
18.8k
    BOOL in_class;
20489
18.8k
    StringBuffer b_s, *b = &b_s;
20490
18.8k
    StringBuffer b2_s, *b2 = &b2_s;
20491
18.8k
    uint32_t c;
20492
20493
18.8k
    p = s->buf_ptr;
20494
18.8k
    p++;
20495
18.8k
    in_class = FALSE;
20496
18.8k
    if (string_buffer_init(s->ctx, b, 32))
20497
0
        return -1;
20498
18.8k
    if (string_buffer_init(s->ctx, b2, 1))
20499
0
        goto fail;
20500
941k
    for(;;) {
20501
941k
        if (p >= s->buf_end) {
20502
1
        eof_error:
20503
1
            js_parse_error(s, "unexpected end of regexp");
20504
1
            goto fail;
20505
1
        }
20506
941k
        c = *p++;
20507
941k
        if (c == '\n' || c == '\r') {
20508
4
            goto eol_error;
20509
941k
        } else if (c == '/') {
20510
20.2k
            if (!in_class)
20511
18.8k
                break;
20512
920k
        } else if (c == '[') {
20513
36.0k
            in_class = TRUE;
20514
884k
        } else if (c == ']') {
20515
            /* XXX: incorrect as the first character in a class */
20516
8.00k
            in_class = FALSE;
20517
876k
        } else if (c == '\\') {
20518
65.3k
            if (string_buffer_putc8(b, c))
20519
0
                goto fail;
20520
65.3k
            c = *p++;
20521
65.3k
            if (c == '\n' || c == '\r')
20522
0
                goto eol_error;
20523
65.3k
            else if (c == '\0' && p >= s->buf_end)
20524
0
                goto eof_error;
20525
65.3k
            else if (c >= 0x80) {
20526
198
                const uint8_t *p_next;
20527
198
                c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
20528
198
                if (c > 0x10FFFF) {
20529
0
                    goto invalid_utf8;
20530
0
                }
20531
198
                p = p_next;
20532
198
                if (c == CP_LS || c == CP_PS)
20533
0
                    goto eol_error;
20534
198
            }
20535
811k
        } else if (c >= 0x80) {
20536
2.46k
            const uint8_t *p_next;
20537
2.46k
            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
20538
2.46k
            if (c > 0x10FFFF) {
20539
2
            invalid_utf8:
20540
2
                js_parse_error(s, "invalid UTF-8 sequence");
20541
2
                goto fail;
20542
2
            }
20543
2.46k
            p = p_next;
20544
            /* LS or PS are considered as line terminator */
20545
2.46k
            if (c == CP_LS || c == CP_PS) {
20546
4
            eol_error:
20547
4
                js_parse_error(s, "unexpected line terminator in regexp");
20548
4
                goto fail;
20549
0
            }
20550
2.46k
        }
20551
922k
        if (string_buffer_putc(b, c))
20552
0
            goto fail;
20553
922k
    }
20554
20555
    /* flags */
20556
18.9k
    for(;;) {
20557
18.9k
        const uint8_t *p_next = p;
20558
18.9k
        c = *p_next++;
20559
18.9k
        if (c >= 0x80) {
20560
0
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
20561
0
            if (c > 0x10FFFF) {
20562
0
                goto invalid_utf8;
20563
0
            }
20564
0
        }
20565
18.9k
        if (!lre_js_is_ident_next(c))
20566
18.8k
            break;
20567
120
        if (string_buffer_putc(b2, c))
20568
0
            goto fail;
20569
120
        p = p_next;
20570
120
    }
20571
20572
18.8k
    s->token.val = TOK_REGEXP;
20573
18.8k
    s->token.u.regexp.body = string_buffer_end(b);
20574
18.8k
    s->token.u.regexp.flags = string_buffer_end(b2);
20575
18.8k
    s->buf_ptr = p;
20576
18.8k
    return 0;
20577
7
 fail:
20578
7
    string_buffer_free(b);
20579
7
    string_buffer_free(b2);
20580
7
    return -1;
20581
18.8k
}
20582
20583
static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
20584
                                     char *static_buf)
20585
387
{
20586
387
    char *buf, *new_buf;
20587
387
    size_t size, new_size;
20588
    
20589
387
    buf = *pbuf;
20590
387
    size = *psize;
20591
387
    if (size >= (SIZE_MAX / 3) * 2)
20592
0
        new_size = SIZE_MAX;
20593
387
    else
20594
387
        new_size = size + (size >> 1);
20595
387
    if (buf == static_buf) {
20596
157
        new_buf = js_malloc(ctx, new_size);
20597
157
        if (!new_buf)
20598
0
            return -1;
20599
157
        memcpy(new_buf, buf, size);
20600
230
    } else {
20601
230
        new_buf = js_realloc(ctx, buf, new_size);
20602
230
        if (!new_buf)
20603
0
            return -1;
20604
230
    }
20605
387
    *pbuf = new_buf;
20606
387
    *psize = new_size;
20607
387
    return 0;
20608
387
}
20609
20610
/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
20611
static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
20612
                          BOOL *pident_has_escape, int c, BOOL is_private)
20613
1.44M
{
20614
1.44M
    const uint8_t *p, *p1;
20615
1.44M
    char ident_buf[128], *buf;
20616
1.44M
    size_t ident_size, ident_pos;
20617
1.44M
    JSAtom atom;
20618
    
20619
1.44M
    p = *pp;
20620
1.44M
    buf = ident_buf;
20621
1.44M
    ident_size = sizeof(ident_buf);
20622
1.44M
    ident_pos = 0;
20623
1.44M
    if (is_private)
20624
12.3k
        buf[ident_pos++] = '#';
20625
4.04M
    for(;;) {
20626
4.04M
        p1 = p;
20627
        
20628
4.04M
        if (c < 128) {
20629
4.04M
            buf[ident_pos++] = c;
20630
4.04M
        } else {
20631
2.89k
            ident_pos += unicode_to_utf8((uint8_t*)buf + ident_pos, c);
20632
2.89k
        }
20633
4.04M
        c = *p1++;
20634
4.04M
        if (c == '\\' && *p1 == 'u') {
20635
90
            c = lre_parse_escape(&p1, TRUE);
20636
90
            *pident_has_escape = TRUE;
20637
4.04M
        } else if (c >= 128) {
20638
2.77k
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
20639
2.77k
        }
20640
4.04M
        if (!lre_js_is_ident_next(c))
20641
1.44M
            break;
20642
2.59M
        p = p1;
20643
2.59M
        if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
20644
387
            if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
20645
0
                atom = JS_ATOM_NULL;
20646
0
                goto done;
20647
0
            }
20648
387
        }
20649
2.59M
    }
20650
1.44M
    atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
20651
1.44M
 done:
20652
1.44M
    if (unlikely(buf != ident_buf))
20653
157
        js_free(s->ctx, buf);
20654
1.44M
    *pp = p;
20655
1.44M
    return atom;
20656
1.44M
}
20657
20658
20659
static __exception int next_token(JSParseState *s)
20660
3.72M
{
20661
3.72M
    const uint8_t *p;
20662
3.72M
    int c;
20663
3.72M
    BOOL ident_has_escape;
20664
3.72M
    JSAtom atom;
20665
    
20666
3.72M
    if (js_check_stack_overflow(s->ctx->rt, 0)) {
20667
2
        return js_parse_error(s, "stack overflow");
20668
2
    }
20669
    
20670
3.72M
    free_token(s, &s->token);
20671
20672
3.72M
    p = s->last_ptr = s->buf_ptr;
20673
3.72M
    s->got_lf = FALSE;
20674
3.72M
    s->last_line_num = s->token.line_num;
20675
4.68M
 redo:
20676
4.68M
    s->token.line_num = s->line_num;
20677
4.68M
    s->token.ptr = p;
20678
4.68M
    c = *p;
20679
4.68M
    switch(c) {
20680
35.6k
    case 0:
20681
35.6k
        if (p >= s->buf_end) {
20682
12.8k
            s->token.val = TOK_EOF;
20683
22.8k
        } else {
20684
22.8k
            goto def_token;
20685
22.8k
        }
20686
12.8k
        break;
20687
20.4k
    case '`':
20688
20.4k
        if (js_parse_template_part(s, p + 1))
20689
61
            goto fail;
20690
20.3k
        p = s->buf_ptr;
20691
20.3k
        break;
20692
11.2k
    case '\'':
20693
22.0k
    case '\"':
20694
22.0k
        if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
20695
128
            goto fail;
20696
21.9k
        break;
20697
522k
    case '\r':  /* accept DOS and MAC newline sequences */
20698
522k
        if (p[1] == '\n') {
20699
3.35k
            p++;
20700
3.35k
        }
20701
        /* fall thru */
20702
743k
    case '\n':
20703
743k
        p++;
20704
743k
    line_terminator:
20705
743k
        s->got_lf = TRUE;
20706
743k
        s->line_num++;
20707
743k
        goto redo;
20708
23.4k
    case '\f':
20709
31.8k
    case '\v':
20710
63.9k
    case ' ':
20711
100k
    case '\t':
20712
100k
        p++;
20713
100k
        goto redo;
20714
158k
    case '/':
20715
158k
        if (p[1] == '*') {
20716
            /* comment */
20717
25
            p += 2;
20718
2.43k
            for(;;) {
20719
2.43k
                if (*p == '\0' && p >= s->buf_end) {
20720
1
                    js_parse_error(s, "unexpected end of comment");
20721
1
                    goto fail;
20722
1
                }
20723
2.43k
                if (p[0] == '*' && p[1] == '/') {
20724
24
                    p += 2;
20725
24
                    break;
20726
24
                }
20727
2.40k
                if (*p == '\n') {
20728
95
                    s->line_num++;
20729
95
                    s->got_lf = TRUE; /* considered as LF for ASI */
20730
95
                    p++;
20731
2.31k
                } else if (*p == '\r') {
20732
1
                    s->got_lf = TRUE; /* considered as LF for ASI */
20733
1
                    p++;
20734
2.31k
                } else if (*p >= 0x80) {
20735
258
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
20736
258
                    if (c == CP_LS || c == CP_PS) {
20737
0
                        s->got_lf = TRUE; /* considered as LF for ASI */
20738
258
                    } else if (c == -1) {
20739
257
                        p++; /* skip invalid UTF-8 */
20740
257
                    }
20741
2.05k
                } else {
20742
2.05k
                    p++;
20743
2.05k
                }
20744
2.40k
            }
20745
24
            goto redo;
20746
158k
        } else if (p[1] == '/') {
20747
            /* line comment */
20748
112k
            p += 2;
20749
112k
        skip_line_comment:
20750
7.28M
            for(;;) {
20751
7.28M
                if (*p == '\0' && p >= s->buf_end)
20752
760
                    break;
20753
7.28M
                if (*p == '\r' || *p == '\n')
20754
112k
                    break;
20755
7.17M
                if (*p >= 0x80) {
20756
1.62M
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
20757
                    /* LS or PS are considered as line terminator */
20758
1.62M
                    if (c == CP_LS || c == CP_PS) {
20759
0
                        break;
20760
1.62M
                    } else if (c == -1) {
20761
1.58M
                        p++; /* skip invalid UTF-8 */
20762
1.58M
                    }
20763
5.55M
                } else {
20764
5.55M
                    p++;
20765
5.55M
                }
20766
7.17M
            }
20767
112k
            goto redo;
20768
112k
        } else if (p[1] == '=') {
20769
454
            p += 2;
20770
454
            s->token.val = TOK_DIV_ASSIGN;
20771
45.5k
        } else {
20772
45.5k
            p++;
20773
45.5k
            s->token.val = c;
20774
45.5k
        }
20775
45.9k
        break;
20776
45.9k
    case '\\':
20777
6.22k
        if (p[1] == 'u') {
20778
90
            const uint8_t *p1 = p + 1;
20779
90
            int c1 = lre_parse_escape(&p1, TRUE);
20780
90
            if (c1 >= 0 && lre_js_is_ident_first(c1)) {
20781
0
                c = c1;
20782
0
                p = p1;
20783
0
                ident_has_escape = TRUE;
20784
0
                goto has_ident;
20785
90
            } else {
20786
                /* XXX: syntax error? */
20787
90
            }
20788
90
        }
20789
6.22k
        goto def_token;
20790
492k
    case 'a': case 'b': case 'c': case 'd':
20791
543k
    case 'e': case 'f': case 'g': case 'h':
20792
1.01M
    case 'i': case 'j': case 'k': case 'l':
20793
1.09M
    case 'm': case 'n': case 'o': case 'p':
20794
1.15M
    case 'q': case 'r': case 's': case 't':
20795
1.24M
    case 'u': case 'v': case 'w': case 'x':
20796
1.25M
    case 'y': case 'z': 
20797
1.28M
    case 'A': case 'B': case 'C': case 'D':
20798
1.29M
    case 'E': case 'F': case 'G': case 'H':
20799
1.31M
    case 'I': case 'J': case 'K': case 'L':
20800
1.35M
    case 'M': case 'N': case 'O': case 'P':
20801
1.37M
    case 'Q': case 'R': case 'S': case 'T':
20802
1.40M
    case 'U': case 'V': case 'W': case 'X':
20803
1.42M
    case 'Y': case 'Z': 
20804
1.42M
    case '_':
20805
1.43M
    case '$':
20806
        /* identifier */
20807
1.43M
        p++;
20808
1.43M
        ident_has_escape = FALSE;
20809
1.43M
    has_ident:
20810
1.43M
        atom = parse_ident(s, &p, &ident_has_escape, c, FALSE);
20811
1.43M
        if (atom == JS_ATOM_NULL)
20812
0
            goto fail;
20813
1.43M
        s->token.u.ident.atom = atom;
20814
1.43M
        s->token.u.ident.has_escape = ident_has_escape;
20815
1.43M
        s->token.u.ident.is_reserved = FALSE;
20816
1.43M
        if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
20817
1.43M
            (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&
20818
1.33M
             (s->cur_func->js_mode & JS_MODE_STRICT)) ||
20819
1.43M
            (s->token.u.ident.atom == JS_ATOM_yield &&
20820
1.33M
             ((s->cur_func->func_kind & JS_FUNC_GENERATOR) ||
20821
839
              (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
20822
13
               !s->cur_func->in_function_body && s->cur_func->parent &&
20823
13
               (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||
20824
1.43M
            (s->token.u.ident.atom == JS_ATOM_await &&
20825
1.33M
             (s->is_module ||
20826
0
              (((s->cur_func->func_kind & JS_FUNC_ASYNC) ||
20827
0
                (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
20828
0
                 !s->cur_func->in_function_body && s->cur_func->parent &&
20829
95.9k
                 (s->cur_func->parent->func_kind & JS_FUNC_ASYNC))))))) {
20830
95.9k
                  if (ident_has_escape) {
20831
0
                      s->token.u.ident.is_reserved = TRUE;
20832
0
                      s->token.val = TOK_IDENT;
20833
95.9k
                  } else {
20834
                      /* The keywords atoms are pre allocated */
20835
95.9k
                      s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD;
20836
95.9k
                  }
20837
1.33M
        } else {
20838
1.33M
            s->token.val = TOK_IDENT;
20839
1.33M
        }
20840
1.43M
        break;
20841
12.4k
    case '#':
20842
        /* private name */
20843
12.4k
        {
20844
12.4k
            const uint8_t *p1;
20845
12.4k
            p++;
20846
12.4k
            p1 = p;
20847
12.4k
            c = *p1++;
20848
12.4k
            if (c == '\\' && *p1 == 'u') {
20849
0
                c = lre_parse_escape(&p1, TRUE);
20850
12.4k
            } else if (c >= 128) {
20851
0
                c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
20852
0
            }
20853
12.4k
            if (!lre_js_is_ident_first(c)) {
20854
2
                js_parse_error(s, "invalid first character of private name");
20855
2
                goto fail;
20856
2
            }
20857
12.3k
            p = p1;
20858
12.3k
            ident_has_escape = FALSE; /* not used */
20859
12.3k
            atom = parse_ident(s, &p, &ident_has_escape, c, TRUE);
20860
12.3k
            if (atom == JS_ATOM_NULL)
20861
0
                goto fail;
20862
12.3k
            s->token.u.ident.atom = atom;
20863
12.3k
            s->token.val = TOK_PRIVATE_NAME;
20864
12.3k
        }
20865
0
        break;
20866
52.8k
    case '.':
20867
52.8k
        if (p[1] == '.' && p[2] == '.') {
20868
29.3k
            p += 3;
20869
29.3k
            s->token.val = TOK_ELLIPSIS;
20870
29.3k
            break;
20871
29.3k
        }
20872
23.4k
        if (p[1] >= '0' && p[1] <= '9') {
20873
3.41k
            goto parse_number;
20874
20.0k
        } else {
20875
20.0k
            goto def_token;
20876
20.0k
        }
20877
0
        break;
20878
17.9k
    case '0':
20879
        /* in strict mode, octal literals are not accepted */
20880
17.9k
        if (is_digit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) {
20881
4
            js_parse_error(s, "octal literals are deprecated in strict mode");
20882
4
            goto fail;
20883
4
        }
20884
17.9k
        goto parse_number;
20885
26.6k
    case '1': case '2': case '3': case '4':
20886
40.3k
    case '5': case '6': case '7': case '8':
20887
44.6k
    case '9': 
20888
        /* number */
20889
65.9k
    parse_number:
20890
65.9k
        {
20891
65.9k
            JSValue ret;
20892
65.9k
            const uint8_t *p1;
20893
65.9k
            int flags, radix;
20894
65.9k
            flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |
20895
65.9k
                ATOD_ACCEPT_UNDERSCORES;
20896
65.9k
#ifdef CONFIG_BIGNUM
20897
65.9k
            flags |= ATOD_ACCEPT_SUFFIX;
20898
65.9k
            if (s->cur_func->js_mode & JS_MODE_MATH) {
20899
0
                flags |= ATOD_MODE_BIGINT;
20900
0
                if (s->cur_func->js_mode & JS_MODE_MATH)
20901
0
                    flags |= ATOD_TYPE_BIG_FLOAT;
20902
0
            }
20903
65.9k
#endif
20904
65.9k
            radix = 0;
20905
65.9k
#ifdef CONFIG_BIGNUM
20906
65.9k
            s->token.u.num.exponent = 0;
20907
65.9k
            ret = js_atof2(s->ctx, (const char *)p, (const char **)&p, radix,
20908
65.9k
                           flags, &s->token.u.num.exponent);
20909
#else
20910
            ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
20911
                          flags);
20912
#endif
20913
65.9k
            if (JS_IsException(ret))
20914
0
                goto fail;
20915
            /* reject `10instanceof Number` */
20916
65.9k
            if (JS_VALUE_IS_NAN(ret) ||
20917
65.9k
                lre_js_is_ident_next(unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1))) {
20918
132
                JS_FreeValue(s->ctx, ret);
20919
132
                js_parse_error(s, "invalid number literal");
20920
132
                goto fail;
20921
132
            }
20922
65.8k
            s->token.val = TOK_NUMBER;
20923
65.8k
            s->token.u.num.val = ret;
20924
65.8k
        }
20925
0
        break;
20926
6.01k
    case '*':
20927
6.01k
        if (p[1] == '=') {
20928
577
            p += 2;
20929
577
            s->token.val = TOK_MUL_ASSIGN;
20930
5.43k
        } else if (p[1] == '*') {
20931
334
            if (p[2] == '=') {
20932
0
                p += 3;
20933
0
                s->token.val = TOK_POW_ASSIGN;
20934
334
            } else {
20935
334
                p += 2;
20936
334
                s->token.val = TOK_POW;
20937
334
            }
20938
5.10k
        } else {
20939
5.10k
            goto def_token;
20940
5.10k
        }
20941
911
        break;
20942
5.19k
    case '%':
20943
5.19k
        if (p[1] == '=') {
20944
1
            p += 2;
20945
1
            s->token.val = TOK_MOD_ASSIGN;
20946
5.19k
        } else {
20947
5.19k
            goto def_token;
20948
5.19k
        }
20949
1
        break;
20950
12.9k
    case '+':
20951
12.9k
        if (p[1] == '=') {
20952
248
            p += 2;
20953
248
            s->token.val = TOK_PLUS_ASSIGN;
20954
12.7k
        } else if (p[1] == '+') {
20955
2.91k
            p += 2;
20956
2.91k
            s->token.val = TOK_INC;
20957
9.82k
        } else {
20958
9.82k
            goto def_token;
20959
9.82k
        }
20960
3.16k
        break;
20961
19.3k
    case '-':
20962
19.3k
        if (p[1] == '=') {
20963
2.73k
            p += 2;
20964
2.73k
            s->token.val = TOK_MINUS_ASSIGN;
20965
16.6k
        } else if (p[1] == '-') {
20966
4.37k
            if (s->allow_html_comments &&
20967
4.37k
                p[2] == '>' && s->last_line_num != s->line_num) {
20968
                /* Annex B: `-->` at beginning of line is an html comment end.
20969
                   It extends to the end of the line.
20970
                 */
20971
0
                goto skip_line_comment;
20972
0
            }
20973
4.37k
            p += 2;
20974
4.37k
            s->token.val = TOK_DEC;
20975
12.2k
        } else {
20976
12.2k
            goto def_token;
20977
12.2k
        }
20978
7.10k
        break;
20979
12.2k
    case '<':
20980
12.2k
        if (p[1] == '=') {
20981
8.68k
            p += 2;
20982
8.68k
            s->token.val = TOK_LTE;
20983
8.68k
        } else if (p[1] == '<') {
20984
62
            if (p[2] == '=') {
20985
2
                p += 3;
20986
2
                s->token.val = TOK_SHL_ASSIGN;
20987
60
            } else {
20988
60
                p += 2;
20989
60
                s->token.val = TOK_SHL;
20990
60
            }
20991
3.48k
        } else if (s->allow_html_comments &&
20992
3.48k
                   p[1] == '!' && p[2] == '-' && p[3] == '-') {
20993
            /* Annex B: handle `<!--` single line html comments */
20994
0
            goto skip_line_comment;
20995
3.48k
        } else {
20996
3.48k
            goto def_token;
20997
3.48k
        }
20998
8.74k
        break;
20999
8.74k
    case '>':
21000
5.65k
        if (p[1] == '=') {
21001
869
            p += 2;
21002
869
            s->token.val = TOK_GTE;
21003
4.78k
        } else if (p[1] == '>') {
21004
539
            if (p[2] == '>') {
21005
466
                if (p[3] == '=') {
21006
326
                    p += 4;
21007
326
                    s->token.val = TOK_SHR_ASSIGN;
21008
326
                } else {
21009
140
                    p += 3;
21010
140
                    s->token.val = TOK_SHR;
21011
140
                }
21012
466
            } else if (p[2] == '=') {
21013
10
                p += 3;
21014
10
                s->token.val = TOK_SAR_ASSIGN;
21015
63
            } else {
21016
63
                p += 2;
21017
63
                s->token.val = TOK_SAR;
21018
63
            }
21019
4.24k
        } else {
21020
4.24k
            goto def_token;
21021
4.24k
        }
21022
1.40k
        break;
21023
614k
    case '=':
21024
614k
        if (p[1] == '=') {
21025
2.53k
            if (p[2] == '=') {
21026
905
                p += 3;
21027
905
                s->token.val = TOK_STRICT_EQ;
21028
1.62k
            } else {
21029
1.62k
                p += 2;
21030
1.62k
                s->token.val = TOK_EQ;
21031
1.62k
            }
21032
612k
        } else if (p[1] == '>') {
21033
29.7k
            p += 2;
21034
29.7k
            s->token.val = TOK_ARROW;
21035
582k
        } else {
21036
582k
            goto def_token;
21037
582k
        }
21038
32.2k
        break;
21039
32.2k
    case '!':
21040
8.41k
        if (p[1] == '=') {
21041
1.53k
            if (p[2] == '=') {
21042
277
                p += 3;
21043
277
                s->token.val = TOK_STRICT_NEQ;
21044
1.25k
            } else {
21045
1.25k
                p += 2;
21046
1.25k
                s->token.val = TOK_NEQ;
21047
1.25k
            }
21048
6.88k
        } else {
21049
6.88k
            goto def_token;
21050
6.88k
        }
21051
1.53k
        break;
21052
8.42k
    case '&':
21053
8.42k
        if (p[1] == '=') {
21054
49
            p += 2;
21055
49
            s->token.val = TOK_AND_ASSIGN;
21056
8.37k
        } else if (p[1] == '&') {
21057
456
            if (p[2] == '=') {
21058
0
                p += 3;
21059
0
                s->token.val = TOK_LAND_ASSIGN;
21060
456
            } else {
21061
456
                p += 2;
21062
456
                s->token.val = TOK_LAND;
21063
456
            }
21064
7.91k
        } else {
21065
7.91k
            goto def_token;
21066
7.91k
        }
21067
505
        break;
21068
505
#ifdef CONFIG_BIGNUM
21069
        /* in math mode, '^' is the power operator. '^^' is always the
21070
           xor operator and '**' is always the power operator */
21071
711
    case '^':
21072
711
        if (p[1] == '=') {
21073
343
            p += 2;
21074
343
            if (s->cur_func->js_mode & JS_MODE_MATH)
21075
0
                s->token.val = TOK_MATH_POW_ASSIGN;
21076
343
            else
21077
343
                s->token.val = TOK_XOR_ASSIGN;
21078
368
        } else if (p[1] == '^') {
21079
0
            if (p[2] == '=') {
21080
0
                p += 3;
21081
0
                s->token.val = TOK_XOR_ASSIGN;
21082
0
            } else {
21083
0
                p += 2;
21084
0
                s->token.val = '^';
21085
0
            }
21086
368
        } else {
21087
368
            p++;
21088
368
            if (s->cur_func->js_mode & JS_MODE_MATH)
21089
0
                s->token.val = TOK_MATH_POW;
21090
368
            else
21091
368
                s->token.val = '^';
21092
368
        }
21093
711
        break;
21094
#else
21095
    case '^':
21096
        if (p[1] == '=') {
21097
            p += 2;
21098
            s->token.val = TOK_XOR_ASSIGN;
21099
        } else {
21100
            goto def_token;
21101
        }
21102
        break;
21103
#endif
21104
29.3k
    case '|':
21105
29.3k
        if (p[1] == '=') {
21106
5.91k
            p += 2;
21107
5.91k
            s->token.val = TOK_OR_ASSIGN;
21108
23.4k
        } else if (p[1] == '|') {
21109
21.9k
            if (p[2] == '=') {
21110
21.2k
                p += 3;
21111
21.2k
                s->token.val = TOK_LOR_ASSIGN;
21112
21.2k
            } else {
21113
701
                p += 2;
21114
701
                s->token.val = TOK_LOR;
21115
701
            }
21116
21.9k
        } else {
21117
1.43k
            goto def_token;
21118
1.43k
        }
21119
27.8k
        break;
21120
27.8k
    case '?':
21121
5.06k
        if (p[1] == '?') {
21122
347
            if (p[2] == '=') {
21123
0
                p += 3;
21124
0
                s->token.val = TOK_DOUBLE_QUESTION_MARK_ASSIGN;
21125
347
            } else {
21126
347
                p += 2;
21127
347
                s->token.val = TOK_DOUBLE_QUESTION_MARK;
21128
347
            }
21129
4.71k
        } else if (p[1] == '.' && !(p[2] >= '0' && p[2] <= '9')) {
21130
789
            p += 2;
21131
789
            s->token.val = TOK_QUESTION_MARK_DOT;
21132
3.92k
        } else {
21133
3.92k
            goto def_token;
21134
3.92k
        }
21135
1.13k
        break;
21136
1.31M
    default:
21137
1.31M
        if (c >= 128) {
21138
            /* unicode value */
21139
1.39k
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21140
1.39k
            switch(c) {
21141
1
            case CP_PS:
21142
363
            case CP_LS:
21143
                /* XXX: should avoid incrementing line_number, but
21144
                   needed to handle HTML comments */
21145
363
                goto line_terminator; 
21146
1.03k
            default:
21147
1.03k
                if (lre_is_space(c)) {
21148
35
                    goto redo;
21149
1.00k
                } else if (lre_js_is_ident_first(c)) {
21150
650
                    ident_has_escape = FALSE;
21151
650
                    goto has_ident;
21152
650
                } else {
21153
350
                    js_parse_error(s, "unexpected character");
21154
350
                    goto fail;
21155
350
                }
21156
1.39k
            }
21157
1.39k
        }
21158
2.00M
    def_token:
21159
2.00M
        s->token.val = c;
21160
2.00M
        p++;
21161
2.00M
        break;
21162
4.68M
    }
21163
3.72M
    s->buf_ptr = p;
21164
21165
    //    dump_token(s, &s->token);
21166
3.72M
    return 0;
21167
21168
678
 fail:
21169
678
    s->token.val = TOK_ERROR;
21170
678
    return -1;
21171
4.68M
}
21172
21173
/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
21174
static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
21175
0
{
21176
0
    const uint8_t *p;
21177
0
    char ident_buf[128], *buf;
21178
0
    size_t ident_size, ident_pos;
21179
0
    JSAtom atom;
21180
    
21181
0
    p = *pp;
21182
0
    buf = ident_buf;
21183
0
    ident_size = sizeof(ident_buf);
21184
0
    ident_pos = 0;
21185
0
    for(;;) {
21186
0
        buf[ident_pos++] = c;
21187
0
        c = *p;
21188
0
        if (c >= 128 ||
21189
0
            !((lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1))
21190
0
            break;
21191
0
        p++;
21192
0
        if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
21193
0
            if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
21194
0
                atom = JS_ATOM_NULL;
21195
0
                goto done;
21196
0
            }
21197
0
        }
21198
0
    }
21199
0
    atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
21200
0
 done:
21201
0
    if (unlikely(buf != ident_buf))
21202
0
        js_free(s->ctx, buf);
21203
0
    *pp = p;
21204
0
    return atom;
21205
0
}
21206
21207
static __exception int json_next_token(JSParseState *s)
21208
0
{
21209
0
    const uint8_t *p;
21210
0
    int c;
21211
0
    JSAtom atom;
21212
    
21213
0
    if (js_check_stack_overflow(s->ctx->rt, 0)) {
21214
0
        return js_parse_error(s, "stack overflow");
21215
0
    }
21216
    
21217
0
    free_token(s, &s->token);
21218
21219
0
    p = s->last_ptr = s->buf_ptr;
21220
0
    s->last_line_num = s->token.line_num;
21221
0
 redo:
21222
0
    s->token.line_num = s->line_num;
21223
0
    s->token.ptr = p;
21224
0
    c = *p;
21225
0
    switch(c) {
21226
0
    case 0:
21227
0
        if (p >= s->buf_end) {
21228
0
            s->token.val = TOK_EOF;
21229
0
        } else {
21230
0
            goto def_token;
21231
0
        }
21232
0
        break;
21233
0
    case '\'':
21234
0
        if (!s->ext_json) {
21235
            /* JSON does not accept single quoted strings */
21236
0
            goto def_token;
21237
0
        }
21238
        /* fall through */
21239
0
    case '\"':
21240
0
        if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
21241
0
            goto fail;
21242
0
        break;
21243
0
    case '\r':  /* accept DOS and MAC newline sequences */
21244
0
        if (p[1] == '\n') {
21245
0
            p++;
21246
0
        }
21247
        /* fall thru */
21248
0
    case '\n':
21249
0
        p++;
21250
0
        s->line_num++;
21251
0
        goto redo;
21252
0
    case '\f':
21253
0
    case '\v':
21254
0
        if (!s->ext_json) {
21255
            /* JSONWhitespace does not match <VT>, nor <FF> */
21256
0
            goto def_token;
21257
0
        }
21258
        /* fall through */
21259
0
    case ' ':
21260
0
    case '\t':
21261
0
        p++;
21262
0
        goto redo;
21263
0
    case '/':
21264
0
        if (!s->ext_json) {
21265
            /* JSON does not accept comments */
21266
0
            goto def_token;
21267
0
        }
21268
0
        if (p[1] == '*') {
21269
            /* comment */
21270
0
            p += 2;
21271
0
            for(;;) {
21272
0
                if (*p == '\0' && p >= s->buf_end) {
21273
0
                    js_parse_error(s, "unexpected end of comment");
21274
0
                    goto fail;
21275
0
                }
21276
0
                if (p[0] == '*' && p[1] == '/') {
21277
0
                    p += 2;
21278
0
                    break;
21279
0
                }
21280
0
                if (*p == '\n') {
21281
0
                    s->line_num++;
21282
0
                    p++;
21283
0
                } else if (*p == '\r') {
21284
0
                    p++;
21285
0
                } else if (*p >= 0x80) {
21286
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21287
0
                    if (c == -1) {
21288
0
                        p++; /* skip invalid UTF-8 */
21289
0
                    }
21290
0
                } else {
21291
0
                    p++;
21292
0
                }
21293
0
            }
21294
0
            goto redo;
21295
0
        } else if (p[1] == '/') {
21296
            /* line comment */
21297
0
            p += 2;
21298
0
            for(;;) {
21299
0
                if (*p == '\0' && p >= s->buf_end)
21300
0
                    break;
21301
0
                if (*p == '\r' || *p == '\n')
21302
0
                    break;
21303
0
                if (*p >= 0x80) {
21304
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21305
                    /* LS or PS are considered as line terminator */
21306
0
                    if (c == CP_LS || c == CP_PS) {
21307
0
                        break;
21308
0
                    } else if (c == -1) {
21309
0
                        p++; /* skip invalid UTF-8 */
21310
0
                    }
21311
0
                } else {
21312
0
                    p++;
21313
0
                }
21314
0
            }
21315
0
            goto redo;
21316
0
        } else {
21317
0
            goto def_token;
21318
0
        }
21319
0
        break;
21320
0
    case 'a': case 'b': case 'c': case 'd':
21321
0
    case 'e': case 'f': case 'g': case 'h':
21322
0
    case 'i': case 'j': case 'k': case 'l':
21323
0
    case 'm': case 'n': case 'o': case 'p':
21324
0
    case 'q': case 'r': case 's': case 't':
21325
0
    case 'u': case 'v': case 'w': case 'x':
21326
0
    case 'y': case 'z': 
21327
0
    case 'A': case 'B': case 'C': case 'D':
21328
0
    case 'E': case 'F': case 'G': case 'H':
21329
0
    case 'I': case 'J': case 'K': case 'L':
21330
0
    case 'M': case 'N': case 'O': case 'P':
21331
0
    case 'Q': case 'R': case 'S': case 'T':
21332
0
    case 'U': case 'V': case 'W': case 'X':
21333
0
    case 'Y': case 'Z': 
21334
0
    case '_':
21335
0
    case '$':
21336
        /* identifier : only pure ascii characters are accepted */
21337
0
        p++;
21338
0
        atom = json_parse_ident(s, &p, c);
21339
0
        if (atom == JS_ATOM_NULL)
21340
0
            goto fail;
21341
0
        s->token.u.ident.atom = atom;
21342
0
        s->token.u.ident.has_escape = FALSE;
21343
0
        s->token.u.ident.is_reserved = FALSE;
21344
0
        s->token.val = TOK_IDENT;
21345
0
        break;
21346
0
    case '+':
21347
0
        if (!s->ext_json || !is_digit(p[1]))
21348
0
            goto def_token;
21349
0
        goto parse_number;
21350
0
    case '0':
21351
0
        if (is_digit(p[1]))
21352
0
            goto def_token;
21353
0
        goto parse_number;
21354
0
    case '-':
21355
0
        if (!is_digit(p[1]))
21356
0
            goto def_token;
21357
0
        goto parse_number;
21358
0
    case '1': case '2': case '3': case '4':
21359
0
    case '5': case '6': case '7': case '8':
21360
0
    case '9': 
21361
        /* number */
21362
0
    parse_number:
21363
0
        {
21364
0
            JSValue ret;
21365
0
            int flags, radix;
21366
0
            if (!s->ext_json) {
21367
0
                flags = 0;
21368
0
                radix = 10;
21369
0
            } else {
21370
0
                flags = ATOD_ACCEPT_BIN_OCT;
21371
0
                radix = 0;
21372
0
            }
21373
0
            ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
21374
0
                          flags);
21375
0
            if (JS_IsException(ret))
21376
0
                goto fail;
21377
0
            s->token.val = TOK_NUMBER;
21378
0
            s->token.u.num.val = ret;
21379
0
        }
21380
0
        break;
21381
0
    default:
21382
0
        if (c >= 128) {
21383
0
            js_parse_error(s, "unexpected character");
21384
0
            goto fail;
21385
0
        }
21386
0
    def_token:
21387
0
        s->token.val = c;
21388
0
        p++;
21389
0
        break;
21390
0
    }
21391
0
    s->buf_ptr = p;
21392
21393
    //    dump_token(s, &s->token);
21394
0
    return 0;
21395
21396
0
 fail:
21397
0
    s->token.val = TOK_ERROR;
21398
0
    return -1;
21399
0
}
21400
21401
/* only used for ':' and '=>', 'let' or 'function' look-ahead. *pp is
21402
   only set if TOK_IMPORT is returned */
21403
/* XXX: handle all unicode cases */
21404
static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator)
21405
716k
{
21406
716k
    const uint8_t *p;
21407
716k
    uint32_t c;
21408
    
21409
    /* skip spaces and comments */
21410
716k
    p = *pp;
21411
881k
    for (;;) {
21412
881k
        switch(c = *p++) {
21413
146k
        case '\r':
21414
194k
        case '\n':
21415
194k
            if (no_line_terminator)
21416
40.5k
                return '\n';
21417
153k
            continue;
21418
153k
        case ' ':
21419
3.14k
        case '\t':
21420
5.40k
        case '\v':
21421
9.66k
        case '\f':
21422
9.66k
            continue;
21423
8.44k
        case '/':
21424
8.44k
            if (*p == '/') {
21425
6.45k
                if (no_line_terminator)
21426
5.07k
                    return '\n';
21427
28.4k
                while (*p && *p != '\r' && *p != '\n')
21428
27.0k
                    p++;
21429
1.38k
                continue;
21430
6.45k
            }
21431
1.98k
            if (*p == '*') {
21432
730
                while (*++p) {
21433
696
                    if ((*p == '\r' || *p == '\n') && no_line_terminator)
21434
8
                        return '\n';
21435
688
                    if (*p == '*' && p[1] == '/') {
21436
8
                        p += 2;
21437
8
                        break;
21438
8
                    }
21439
688
                }
21440
42
                continue;
21441
50
            }
21442
1.93k
            break;
21443
271k
        case '=':
21444
271k
            if (*p == '>')
21445
6.14k
                return TOK_ARROW;
21446
265k
            break;
21447
397k
        default:
21448
397k
            if (lre_js_is_ident_first(c)) {
21449
26.2k
                if (c == 'i') {
21450
407
                    if (p[0] == 'n' && !lre_js_is_ident_next(p[1])) {
21451
345
                        return TOK_IN;
21452
345
                    }
21453
62
                    if (p[0] == 'm' && p[1] == 'p' && p[2] == 'o' &&
21454
62
                        p[3] == 'r' && p[4] == 't' &&
21455
62
                        !lre_js_is_ident_next(p[5])) {
21456
0
                        *pp = p + 5;
21457
0
                        return TOK_IMPORT;
21458
0
                    }
21459
25.8k
                } else if (c == 'o' && *p == 'f' && !lre_js_is_ident_next(p[1])) {
21460
222
                    return TOK_OF;
21461
25.6k
                } else if (c == 'e' &&
21462
25.6k
                           p[0] == 'x' && p[1] == 'p' && p[2] == 'o' &&
21463
25.6k
                           p[3] == 'r' && p[4] == 't' &&
21464
25.6k
                           !lre_js_is_ident_next(p[5])) {
21465
0
                    *pp = p + 5;
21466
0
                    return TOK_EXPORT;
21467
25.6k
                } else if (c == 'f' && p[0] == 'u' && p[1] == 'n' &&
21468
25.6k
                         p[2] == 'c' && p[3] == 't' && p[4] == 'i' &&
21469
25.6k
                         p[5] == 'o' && p[6] == 'n' && !lre_js_is_ident_next(p[7])) {
21470
7.05k
                    return TOK_FUNCTION;
21471
7.05k
                }
21472
18.6k
                return TOK_IDENT;
21473
26.2k
            }
21474
371k
            break;
21475
881k
        }
21476
638k
        return c;
21477
881k
    }
21478
716k
}
21479
21480
static int peek_token(JSParseState *s, BOOL no_line_terminator)
21481
716k
{
21482
716k
    const uint8_t *p = s->buf_ptr;
21483
716k
    return simple_next_token(&p, no_line_terminator);
21484
716k
}
21485
21486
/* return true if 'input' contains the source of a module
21487
   (heuristic). 'input' must be a zero terminated.
21488
21489
   Heuristic: skip comments and expect 'import' keyword not followed
21490
   by '(' or '.' or export keyword.
21491
*/
21492
BOOL JS_DetectModule(const char *input, size_t input_len)
21493
0
{
21494
0
    const uint8_t *p = (const uint8_t *)input;
21495
0
    int tok;
21496
0
    switch(simple_next_token(&p, FALSE)) {
21497
0
    case TOK_IMPORT:
21498
0
        tok = simple_next_token(&p, FALSE);
21499
0
        return (tok != '.' && tok != '(');
21500
0
    case TOK_EXPORT:
21501
0
        return TRUE;
21502
0
    default:
21503
0
        return FALSE;
21504
0
    }
21505
0
}
21506
21507
924k
static inline int get_prev_opcode(JSFunctionDef *fd) {
21508
924k
    if (fd->last_opcode_pos < 0)
21509
205
        return OP_invalid;
21510
924k
    else
21511
924k
        return fd->byte_code.buf[fd->last_opcode_pos];
21512
924k
}
21513
21514
245k
static BOOL js_is_live_code(JSParseState *s) {
21515
245k
    switch (get_prev_opcode(s->cur_func)) {
21516
0
    case OP_tail_call:
21517
0
    case OP_tail_call_method:
21518
94
    case OP_return:
21519
100
    case OP_return_undef:
21520
103
    case OP_return_async:
21521
1.05k
    case OP_throw:
21522
1.05k
    case OP_throw_error:
21523
1.05k
    case OP_goto:
21524
1.05k
#if SHORT_OPCODES
21525
1.05k
    case OP_goto8:
21526
1.05k
    case OP_goto16:
21527
1.05k
#endif
21528
1.05k
    case OP_ret:
21529
1.05k
        return FALSE;
21530
244k
    default:
21531
244k
        return TRUE;
21532
245k
    }
21533
245k
}
21534
21535
static void emit_u8(JSParseState *s, uint8_t val)
21536
31.1k
{
21537
31.1k
    dbuf_putc(&s->cur_func->byte_code, val);
21538
31.1k
}
21539
21540
static void emit_u16(JSParseState *s, uint16_t val)
21541
1.42M
{
21542
1.42M
    dbuf_put_u16(&s->cur_func->byte_code, val);
21543
1.42M
}
21544
21545
static void emit_u32(JSParseState *s, uint32_t val)
21546
2.42M
{
21547
2.42M
    dbuf_put_u32(&s->cur_func->byte_code, val);
21548
2.42M
}
21549
21550
static void emit_op(JSParseState *s, uint8_t val)
21551
3.94M
{
21552
3.94M
    JSFunctionDef *fd = s->cur_func;
21553
3.94M
    DynBuf *bc = &fd->byte_code;
21554
21555
    /* Use the line number of the last token used, not the next token,
21556
       nor the current offset in the source file.
21557
     */
21558
3.94M
    if (unlikely(fd->last_opcode_line_num != s->last_line_num)) {
21559
213k
        dbuf_putc(bc, OP_line_num);
21560
213k
        dbuf_put_u32(bc, s->last_line_num);
21561
213k
        fd->last_opcode_line_num = s->last_line_num;
21562
213k
    }
21563
3.94M
    fd->last_opcode_pos = bc->size;
21564
3.94M
    dbuf_putc(bc, val);
21565
3.94M
}
21566
21567
static void emit_atom(JSParseState *s, JSAtom name)
21568
518k
{
21569
518k
    emit_u32(s, JS_DupAtom(s->ctx, name));
21570
518k
}
21571
21572
static int update_label(JSFunctionDef *s, int label, int delta)
21573
5.49M
{
21574
5.49M
    LabelSlot *ls;
21575
21576
5.49M
    assert(label >= 0 && label < s->label_count);
21577
5.49M
    ls = &s->label_slots[label];
21578
5.49M
    ls->ref_count += delta;
21579
5.49M
    assert(ls->ref_count >= 0);
21580
5.49M
    return ls->ref_count;
21581
5.49M
}
21582
21583
static int new_label_fd(JSFunctionDef *fd, int label)
21584
2.14M
{
21585
2.14M
    LabelSlot *ls;
21586
21587
2.14M
    if (label < 0) {
21588
948k
        if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
21589
948k
                            sizeof(fd->label_slots[0]),
21590
948k
                            &fd->label_size, fd->label_count + 1))
21591
0
            return -1;
21592
948k
        label = fd->label_count++;
21593
948k
        ls = &fd->label_slots[label];
21594
948k
        ls->ref_count = 0;
21595
948k
        ls->pos = -1;
21596
948k
        ls->pos2 = -1;
21597
948k
        ls->addr = -1;
21598
948k
        ls->first_reloc = NULL;
21599
948k
    }
21600
2.14M
    return label;
21601
2.14M
}
21602
21603
static int new_label(JSParseState *s)
21604
548k
{
21605
548k
    return new_label_fd(s->cur_func, -1);
21606
548k
}
21607
21608
/* return the label ID offset */
21609
static int emit_label(JSParseState *s, int label)
21610
545k
{
21611
545k
    if (label >= 0) {
21612
545k
        emit_op(s, OP_label);
21613
545k
        emit_u32(s, label);
21614
545k
        s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
21615
545k
        return s->cur_func->byte_code.size - 4;
21616
545k
    } else {
21617
0
        return -1;
21618
0
    }
21619
545k
}
21620
21621
/* return label or -1 if dead code */
21622
static int emit_goto(JSParseState *s, int opcode, int label)
21623
224k
{
21624
224k
    if (js_is_live_code(s)) {
21625
223k
        if (label < 0)
21626
113k
            label = new_label(s);
21627
223k
        emit_op(s, opcode);
21628
223k
        emit_u32(s, label);
21629
223k
        s->cur_func->label_slots[label].ref_count++;
21630
223k
        return label;
21631
223k
    }
21632
1.00k
    return -1;
21633
224k
}
21634
21635
/* return the constant pool index. 'val' is not duplicated. */
21636
static int cpool_add(JSParseState *s, JSValue val)
21637
80.1k
{
21638
80.1k
    JSFunctionDef *fd = s->cur_func;
21639
    
21640
80.1k
    if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]),
21641
80.1k
                        &fd->cpool_size, fd->cpool_count + 1))
21642
0
        return -1;
21643
80.1k
    fd->cpool[fd->cpool_count++] = val;
21644
80.1k
    return fd->cpool_count - 1;
21645
80.1k
}
21646
21647
static __exception int emit_push_const(JSParseState *s, JSValueConst val,
21648
                                       BOOL as_atom)
21649
52.6k
{
21650
52.6k
    int idx;
21651
21652
52.6k
    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING && as_atom) {
21653
15.1k
        JSAtom atom;
21654
        /* warning: JS_NewAtomStr frees the string value */
21655
15.1k
        JS_DupValue(s->ctx, val);
21656
15.1k
        atom = JS_NewAtomStr(s->ctx, JS_VALUE_GET_STRING(val));
21657
15.1k
        if (atom != JS_ATOM_NULL && !__JS_AtomIsTaggedInt(atom)) {
21658
15.1k
            emit_op(s, OP_push_atom_value);
21659
15.1k
            emit_u32(s, atom);
21660
15.1k
            return 0;
21661
15.1k
        }
21662
15.1k
    }
21663
21664
37.4k
    idx = cpool_add(s, JS_DupValue(s->ctx, val));
21665
37.4k
    if (idx < 0)
21666
0
        return -1;
21667
37.4k
    emit_op(s, OP_push_const);
21668
37.4k
    emit_u32(s, idx);
21669
37.4k
    return 0;
21670
37.4k
}
21671
21672
/* return the variable index or -1 if not found,
21673
   add ARGUMENT_VAR_OFFSET for argument variables */
21674
static int find_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21675
651k
{
21676
651k
    int i;
21677
739k
    for(i = fd->arg_count; i-- > 0;) {
21678
103k
        if (fd->args[i].var_name == name)
21679
15.0k
            return i | ARGUMENT_VAR_OFFSET;
21680
103k
    }
21681
636k
    return -1;
21682
651k
}
21683
21684
static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21685
676k
{
21686
676k
    int i;
21687
22.4M
    for(i = fd->var_count; i-- > 0;) {
21688
21.8M
        if (fd->vars[i].var_name == name && fd->vars[i].scope_level == 0)
21689
25.3k
            return i;
21690
21.8M
    }
21691
650k
    return find_arg(ctx, fd, name);
21692
676k
}
21693
21694
/* find a variable declaration in a given scope */
21695
static int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd,
21696
                             JSAtom name, int scope_level)
21697
0
{
21698
0
    int scope_idx;
21699
0
    for(scope_idx = fd->scopes[scope_level].first; scope_idx >= 0;
21700
0
        scope_idx = fd->vars[scope_idx].scope_next) {
21701
0
        if (fd->vars[scope_idx].scope_level != scope_level)
21702
0
            break;
21703
0
        if (fd->vars[scope_idx].var_name == name)
21704
0
            return scope_idx;
21705
0
    }
21706
0
    return -1;
21707
0
}
21708
21709
/* return true if scope == parent_scope or if scope is a child of
21710
   parent_scope */
21711
static BOOL is_child_scope(JSContext *ctx, JSFunctionDef *fd,
21712
                           int scope, int parent_scope)
21713
1.43k
{
21714
3.27k
    while (scope >= 0) {
21715
1.84k
        if (scope == parent_scope)
21716
0
            return TRUE;
21717
1.84k
        scope = fd->scopes[scope].parent;
21718
1.84k
    }
21719
1.43k
    return FALSE;
21720
1.43k
}
21721
21722
/* find a 'var' declaration in the same scope or a child scope */
21723
static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd,
21724
                                   JSAtom name, int scope_level)
21725
37.5k
{
21726
37.5k
    int i;
21727
6.39M
    for(i = 0; i < fd->var_count; i++) {
21728
6.35M
        JSVarDef *vd = &fd->vars[i];
21729
6.35M
        if (vd->var_name == name && vd->scope_level == 0) {
21730
506
            if (is_child_scope(ctx, fd, vd->scope_next,
21731
506
                               scope_level))
21732
0
                return i;
21733
506
        }
21734
6.35M
    }
21735
37.5k
    return -1;
21736
37.5k
}
21737
21738
21739
static JSGlobalVar *find_global_var(JSFunctionDef *fd, JSAtom name)
21740
55.1k
{
21741
55.1k
    int i;
21742
278k
    for(i = 0; i < fd->global_var_count; i++) {
21743
245k
        JSGlobalVar *hf = &fd->global_vars[i];
21744
245k
        if (hf->var_name == name)
21745
22.2k
            return hf;
21746
245k
    }
21747
32.8k
    return NULL;
21748
21749
55.1k
}
21750
21751
static JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name)
21752
26.7k
{
21753
26.7k
    JSGlobalVar *hf = find_global_var(fd, name);
21754
26.7k
    if (hf && hf->is_lexical)
21755
54
        return hf;
21756
26.6k
    else
21757
26.6k
        return NULL;
21758
26.7k
}
21759
21760
static int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
21761
                             int scope_idx, BOOL check_catch_var)
21762
54.0k
{
21763
124k
    while (scope_idx >= 0) {
21764
72.4k
        JSVarDef *vd = &fd->vars[scope_idx];
21765
72.4k
        if (vd->var_name == name &&
21766
72.4k
            (vd->is_lexical || (vd->var_kind == JS_VAR_CATCH &&
21767
0
                                check_catch_var)))
21768
1.91k
            return scope_idx;
21769
70.5k
        scope_idx = vd->scope_next;
21770
70.5k
    }
21771
21772
52.1k
    if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_GLOBAL) {
21773
26.7k
        if (find_lexical_global_var(fd, name))
21774
54
            return GLOBAL_VAR_OFFSET;
21775
26.7k
    }
21776
52.1k
    return -1;
21777
52.1k
}
21778
21779
86.4k
static int push_scope(JSParseState *s) {
21780
86.4k
    if (s->cur_func) {
21781
86.4k
        JSFunctionDef *fd = s->cur_func;
21782
86.4k
        int scope = fd->scope_count;
21783
        /* XXX: should check for scope overflow */
21784
86.4k
        if ((fd->scope_count + 1) > fd->scope_size) {
21785
3.19k
            int new_size;
21786
3.19k
            size_t slack;
21787
3.19k
            JSVarScope *new_buf;
21788
            /* XXX: potential arithmetic overflow */
21789
3.19k
            new_size = max_int(fd->scope_count + 1, fd->scope_size * 3 / 2);
21790
3.19k
            if (fd->scopes == fd->def_scope_array) {
21791
916
                new_buf = js_realloc2(s->ctx, NULL, new_size * sizeof(*fd->scopes), &slack);
21792
916
                if (!new_buf)
21793
0
                    return -1;
21794
916
                memcpy(new_buf, fd->scopes, fd->scope_count * sizeof(*fd->scopes));
21795
2.27k
            } else {
21796
2.27k
                new_buf = js_realloc2(s->ctx, fd->scopes, new_size * sizeof(*fd->scopes), &slack);
21797
2.27k
                if (!new_buf)
21798
0
                    return -1;
21799
2.27k
            }
21800
3.19k
            new_size += slack / sizeof(*new_buf);
21801
3.19k
            fd->scopes = new_buf;
21802
3.19k
            fd->scope_size = new_size;
21803
3.19k
        }
21804
86.4k
        fd->scope_count++;
21805
86.4k
        fd->scopes[scope].parent = fd->scope_level;
21806
86.4k
        fd->scopes[scope].first = fd->scope_first;
21807
86.4k
        emit_op(s, OP_enter_scope);
21808
86.4k
        emit_u16(s, scope);
21809
86.4k
        return fd->scope_level = scope;
21810
86.4k
    }
21811
0
    return 0;
21812
86.4k
}
21813
21814
static int get_first_lexical_var(JSFunctionDef *fd, int scope)
21815
45.7k
{
21816
157k
    while (scope >= 0) {
21817
133k
        int scope_idx = fd->scopes[scope].first;
21818
133k
        if (scope_idx >= 0)
21819
21.7k
            return scope_idx;
21820
111k
        scope = fd->scopes[scope].parent;
21821
111k
    }
21822
24.0k
    return -1;
21823
45.7k
}
21824
21825
45.7k
static void pop_scope(JSParseState *s) {
21826
45.7k
    if (s->cur_func) {
21827
        /* disable scoped variables */
21828
45.7k
        JSFunctionDef *fd = s->cur_func;
21829
45.7k
        int scope = fd->scope_level;
21830
45.7k
        emit_op(s, OP_leave_scope);
21831
45.7k
        emit_u16(s, scope);
21832
45.7k
        fd->scope_level = fd->scopes[scope].parent;
21833
45.7k
        fd->scope_first = get_first_lexical_var(fd, fd->scope_level);
21834
45.7k
    }
21835
45.7k
}
21836
21837
static void close_scopes(JSParseState *s, int scope, int scope_stop)
21838
13.6k
{
21839
27.3k
    while (scope > scope_stop) {
21840
13.6k
        emit_op(s, OP_leave_scope);
21841
13.6k
        emit_u16(s, scope);
21842
13.6k
        scope = s->cur_func->scopes[scope].parent;
21843
13.6k
    }
21844
13.6k
}
21845
21846
/* return the variable index or -1 if error */
21847
static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21848
93.7k
{
21849
93.7k
    JSVarDef *vd;
21850
21851
    /* the local variable indexes are currently stored on 16 bits */
21852
93.7k
    if (fd->var_count >= JS_MAX_LOCAL_VARS) {
21853
0
        JS_ThrowInternalError(ctx, "too many local variables");
21854
0
        return -1;
21855
0
    }
21856
93.7k
    if (js_resize_array(ctx, (void **)&fd->vars, sizeof(fd->vars[0]),
21857
93.7k
                        &fd->var_size, fd->var_count + 1))
21858
0
        return -1;
21859
93.7k
    vd = &fd->vars[fd->var_count++];
21860
93.7k
    memset(vd, 0, sizeof(*vd));
21861
93.7k
    vd->var_name = JS_DupAtom(ctx, name);
21862
93.7k
    vd->func_pool_idx = -1;
21863
93.7k
    return fd->var_count - 1;
21864
93.7k
}
21865
21866
static int add_scope_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
21867
                         JSVarKindEnum var_kind)
21868
59.2k
{
21869
59.2k
    int idx = add_var(ctx, fd, name);
21870
59.2k
    if (idx >= 0) {
21871
59.2k
        JSVarDef *vd = &fd->vars[idx];
21872
59.2k
        vd->var_kind = var_kind;
21873
59.2k
        vd->scope_level = fd->scope_level;
21874
59.2k
        vd->scope_next = fd->scope_first;
21875
59.2k
        fd->scopes[fd->scope_level].first = idx;
21876
59.2k
        fd->scope_first = idx;
21877
59.2k
    }
21878
59.2k
    return idx;
21879
59.2k
}
21880
21881
static int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21882
141
{
21883
141
    int idx = fd->func_var_idx;
21884
141
    if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) {
21885
138
        fd->func_var_idx = idx;
21886
138
        fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME;
21887
138
        if (fd->js_mode & JS_MODE_STRICT)
21888
16
            fd->vars[idx].is_const = TRUE;
21889
138
    }
21890
141
    return idx;
21891
141
}
21892
21893
static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd)
21894
9
{
21895
9
    int idx = fd->arguments_var_idx;
21896
9
    if (idx < 0 && (idx = add_var(ctx, fd, JS_ATOM_arguments)) >= 0) {
21897
6
        fd->arguments_var_idx = idx;
21898
6
    }
21899
9
    return idx;
21900
9
}
21901
21902
/* add an argument definition in the argument scope. Only needed when
21903
   "eval()" may be called in the argument scope. Return 0 if OK. */
21904
static int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd)
21905
0
{
21906
0
    int idx;
21907
0
    if (fd->arguments_arg_idx < 0) {
21908
0
        idx = find_var_in_scope(ctx, fd, JS_ATOM_arguments, ARG_SCOPE_INDEX);
21909
0
        if (idx < 0) {
21910
            /* XXX: the scope links are not fully updated. May be an
21911
               issue if there are child scopes of the argument
21912
               scope */
21913
0
            idx = add_var(ctx, fd, JS_ATOM_arguments);
21914
0
            if (idx < 0)
21915
0
                return -1;
21916
0
            fd->vars[idx].scope_next = fd->scopes[ARG_SCOPE_INDEX].first;
21917
0
            fd->scopes[ARG_SCOPE_INDEX].first = idx;
21918
0
            fd->vars[idx].scope_level = ARG_SCOPE_INDEX;
21919
0
            fd->vars[idx].is_lexical = TRUE;
21920
21921
0
            fd->arguments_arg_idx = idx;
21922
0
        }
21923
0
    }
21924
0
    return 0;
21925
0
}
21926
21927
static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21928
18.4k
{
21929
18.4k
    JSVarDef *vd;
21930
21931
    /* the local variable indexes are currently stored on 16 bits */
21932
18.4k
    if (fd->arg_count >= JS_MAX_LOCAL_VARS) {
21933
0
        JS_ThrowInternalError(ctx, "too many arguments");
21934
0
        return -1;
21935
0
    }
21936
18.4k
    if (js_resize_array(ctx, (void **)&fd->args, sizeof(fd->args[0]),
21937
18.4k
                        &fd->arg_size, fd->arg_count + 1))
21938
0
        return -1;
21939
18.4k
    vd = &fd->args[fd->arg_count++];
21940
18.4k
    memset(vd, 0, sizeof(*vd));
21941
18.4k
    vd->var_name = JS_DupAtom(ctx, name);
21942
18.4k
    vd->func_pool_idx = -1;
21943
18.4k
    return fd->arg_count - 1;
21944
18.4k
}
21945
21946
/* add a global variable definition */
21947
static JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s,
21948
                                     JSAtom name)
21949
16.5k
{
21950
16.5k
    JSGlobalVar *hf;
21951
21952
16.5k
    if (js_resize_array(ctx, (void **)&s->global_vars,
21953
16.5k
                        sizeof(s->global_vars[0]),
21954
16.5k
                        &s->global_var_size, s->global_var_count + 1))
21955
0
        return NULL;
21956
16.5k
    hf = &s->global_vars[s->global_var_count++];
21957
16.5k
    hf->cpool_idx = -1;
21958
16.5k
    hf->force_init = FALSE;
21959
16.5k
    hf->is_lexical = FALSE;
21960
16.5k
    hf->is_const = FALSE;
21961
16.5k
    hf->scope_level = s->scope_level;
21962
16.5k
    hf->var_name = JS_DupAtom(ctx, name);
21963
16.5k
    return hf;
21964
16.5k
}
21965
21966
typedef enum {
21967
    JS_VAR_DEF_WITH,
21968
    JS_VAR_DEF_LET,
21969
    JS_VAR_DEF_CONST,
21970
    JS_VAR_DEF_FUNCTION_DECL, /* function declaration */
21971
    JS_VAR_DEF_NEW_FUNCTION_DECL, /* async/generator function declaration */
21972
    JS_VAR_DEF_CATCH,
21973
    JS_VAR_DEF_VAR,
21974
} JSVarDefEnum;
21975
21976
static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
21977
                      JSVarDefEnum var_def_type)
21978
63.8k
{
21979
63.8k
    JSContext *ctx = s->ctx;
21980
63.8k
    JSVarDef *vd;
21981
63.8k
    int idx;
21982
21983
63.8k
    switch (var_def_type) {
21984
11.2k
    case JS_VAR_DEF_WITH:
21985
11.2k
        idx = add_scope_var(ctx, fd, name, JS_VAR_NORMAL);
21986
11.2k
        break;
21987
21988
15.2k
    case JS_VAR_DEF_LET:
21989
36.0k
    case JS_VAR_DEF_CONST:
21990
37.5k
    case JS_VAR_DEF_FUNCTION_DECL:
21991
37.5k
    case JS_VAR_DEF_NEW_FUNCTION_DECL:
21992
37.5k
        idx = find_lexical_decl(ctx, fd, name, fd->scope_first, TRUE);
21993
37.5k
        if (idx >= 0) {
21994
1.13k
            if (idx < GLOBAL_VAR_OFFSET) {
21995
1.07k
                if (fd->vars[idx].scope_level == fd->scope_level) {
21996
                    /* same scope: in non strict mode, functions
21997
                       can be redefined (annex B.3.3.4). */
21998
351
                    if (!(!(fd->js_mode & JS_MODE_STRICT) &&
21999
351
                          var_def_type == JS_VAR_DEF_FUNCTION_DECL &&
22000
351
                          fd->vars[idx].var_kind == JS_VAR_FUNCTION_DECL)) {
22001
0
                        goto redef_lex_error;
22002
0
                    }
22003
727
                } else if (fd->vars[idx].var_kind == JS_VAR_CATCH && (fd->vars[idx].scope_level + 2) == fd->scope_level) {
22004
0
                    goto redef_lex_error;
22005
0
                }
22006
1.07k
            } else {
22007
54
                if (fd->scope_level == fd->body_scope) {
22008
0
                redef_lex_error:
22009
                    /* redefining a scoped var in the same scope: error */
22010
0
                    return js_parse_error(s, "invalid redefinition of lexical identifier");
22011
0
                }
22012
54
            }
22013
1.13k
        }
22014
37.5k
        if (var_def_type != JS_VAR_DEF_FUNCTION_DECL &&
22015
37.5k
            var_def_type != JS_VAR_DEF_NEW_FUNCTION_DECL &&
22016
37.5k
            fd->scope_level == fd->body_scope &&
22017
37.5k
            find_arg(ctx, fd, name) >= 0) {
22018
            /* lexical variable redefines a parameter name */
22019
0
            return js_parse_error(s, "invalid redefinition of parameter name");
22020
0
        }
22021
22022
37.5k
        if (find_var_in_child_scope(ctx, fd, name, fd->scope_level) >= 0) {
22023
0
            return js_parse_error(s, "invalid redefinition of a variable");
22024
0
        }
22025
        
22026
37.5k
        if (fd->is_global_var) {
22027
17.3k
            JSGlobalVar *hf;
22028
17.3k
            hf = find_global_var(fd, name);
22029
17.3k
            if (hf && is_child_scope(ctx, fd, hf->scope_level,
22030
924
                                     fd->scope_level)) {
22031
0
                return js_parse_error(s, "invalid redefinition of global identifier");
22032
0
            }
22033
17.3k
        }
22034
        
22035
37.5k
        if (fd->is_eval &&
22036
37.5k
            (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
22037
17.3k
             fd->eval_type == JS_EVAL_TYPE_MODULE) &&
22038
37.5k
            fd->scope_level == fd->body_scope) {
22039
15
            JSGlobalVar *hf;
22040
15
            hf = add_global_var(s->ctx, fd, name);
22041
15
            if (!hf)
22042
0
                return -1;
22043
15
            hf->is_lexical = TRUE;
22044
15
            hf->is_const = (var_def_type == JS_VAR_DEF_CONST);
22045
15
            idx = GLOBAL_VAR_OFFSET;
22046
37.5k
        } else {
22047
37.5k
            JSVarKindEnum var_kind;
22048
37.5k
            if (var_def_type == JS_VAR_DEF_FUNCTION_DECL)
22049
1.44k
                var_kind = JS_VAR_FUNCTION_DECL;
22050
36.1k
            else if (var_def_type == JS_VAR_DEF_NEW_FUNCTION_DECL)
22051
49
                var_kind = JS_VAR_NEW_FUNCTION_DECL;
22052
36.0k
            else
22053
36.0k
                var_kind = JS_VAR_NORMAL;
22054
37.5k
            idx = add_scope_var(ctx, fd, name, var_kind);
22055
37.5k
            if (idx >= 0) {
22056
37.5k
                vd = &fd->vars[idx];
22057
37.5k
                vd->is_lexical = 1;
22058
37.5k
                vd->is_const = (var_def_type == JS_VAR_DEF_CONST);
22059
37.5k
            }
22060
37.5k
        }
22061
37.5k
        break;
22062
22063
37.5k
    case JS_VAR_DEF_CATCH:
22064
0
        idx = add_scope_var(ctx, fd, name, JS_VAR_CATCH);
22065
0
        break;
22066
22067
14.9k
    case JS_VAR_DEF_VAR:
22068
14.9k
        if (find_lexical_decl(ctx, fd, name, fd->scope_first,
22069
14.9k
                              FALSE) >= 0) {
22070
0
       invalid_lexical_redefinition:
22071
            /* error to redefine a var that inside a lexical scope */
22072
0
            return js_parse_error(s, "invalid redefinition of lexical identifier");
22073
0
        }
22074
14.9k
        if (fd->is_global_var) {
22075
11.0k
            JSGlobalVar *hf;
22076
11.0k
            hf = find_global_var(fd, name);
22077
11.0k
            if (hf && hf->is_lexical && hf->scope_level == fd->scope_level &&
22078
11.0k
                fd->eval_type == JS_EVAL_TYPE_MODULE) {
22079
0
                goto invalid_lexical_redefinition;
22080
0
            }
22081
11.0k
            hf = add_global_var(s->ctx, fd, name);
22082
11.0k
            if (!hf)
22083
0
                return -1;
22084
11.0k
            idx = GLOBAL_VAR_OFFSET;
22085
11.0k
        } else {
22086
            /* if the variable already exists, don't add it again  */
22087
3.94k
            idx = find_var(ctx, fd, name);
22088
3.94k
            if (idx >= 0)
22089
2.98k
                break;
22090
960
            idx = add_var(ctx, fd, name);
22091
960
            if (idx >= 0) {
22092
960
                if (name == JS_ATOM_arguments && fd->has_arguments_binding)
22093
0
                    fd->arguments_var_idx = idx;
22094
960
                fd->vars[idx].scope_next = fd->scope_level;
22095
960
            }
22096
960
        }
22097
11.9k
        break;
22098
11.9k
    default:
22099
0
        abort();
22100
63.8k
    }
22101
63.8k
    return idx;
22102
63.8k
}
22103
22104
/* add a private field variable in the current scope */
22105
static int add_private_class_field(JSParseState *s, JSFunctionDef *fd,
22106
                                   JSAtom name, JSVarKindEnum var_kind)
22107
10.3k
{
22108
10.3k
    JSContext *ctx = s->ctx;
22109
10.3k
    JSVarDef *vd;
22110
10.3k
    int idx;
22111
22112
10.3k
    idx = add_scope_var(ctx, fd, name, var_kind);
22113
10.3k
    if (idx < 0)
22114
0
        return idx;
22115
10.3k
    vd = &fd->vars[idx];
22116
10.3k
    vd->is_lexical = 1;
22117
10.3k
    vd->is_const = 1;
22118
10.3k
    return idx;
22119
10.3k
}
22120
22121
static __exception int js_parse_expr(JSParseState *s);
22122
static __exception int js_parse_function_decl(JSParseState *s,
22123
                                              JSParseFunctionEnum func_type,
22124
                                              JSFunctionKindEnum func_kind,
22125
                                              JSAtom func_name, const uint8_t *ptr,
22126
                                              int start_line);
22127
static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s);
22128
static __exception int js_parse_function_decl2(JSParseState *s,
22129
                                               JSParseFunctionEnum func_type,
22130
                                               JSFunctionKindEnum func_kind,
22131
                                               JSAtom func_name,
22132
                                               const uint8_t *ptr,
22133
                                               int function_line_num,
22134
                                               JSParseExportEnum export_flag,
22135
                                               JSFunctionDef **pfd);
22136
static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);
22137
static __exception int js_parse_assign_expr(JSParseState *s);
22138
static __exception int js_parse_unary(JSParseState *s, int parse_flags);
22139
static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
22140
                             JSAtom label_name,
22141
                             int label_break, int label_cont,
22142
                             int drop_count);
22143
static void pop_break_entry(JSFunctionDef *fd);
22144
static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
22145
                                       JSAtom local_name, JSAtom export_name,
22146
                                       JSExportTypeEnum export_type);
22147
22148
/* Note: all the fields are already sealed except length */
22149
static int seal_template_obj(JSContext *ctx, JSValueConst obj)
22150
20.3k
{
22151
20.3k
    JSObject *p;
22152
20.3k
    JSShapeProperty *prs;
22153
22154
20.3k
    p = JS_VALUE_GET_OBJ(obj);
22155
20.3k
    prs = find_own_property1(p, JS_ATOM_length);
22156
20.3k
    if (prs) {
22157
20.3k
        if (js_update_property_flags(ctx, p, &prs,
22158
20.3k
                                     prs->flags & ~(JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)))
22159
0
            return -1;
22160
20.3k
    }
22161
20.3k
    p->extensible = FALSE;
22162
20.3k
    return 0;
22163
20.3k
}
22164
22165
static __exception int js_parse_template(JSParseState *s, int call, int *argc)
22166
14.2k
{
22167
14.2k
    JSContext *ctx = s->ctx;
22168
14.2k
    JSValue raw_array, template_object;
22169
14.2k
    JSToken cooked;
22170
14.2k
    int depth, ret;
22171
22172
14.2k
    raw_array = JS_UNDEFINED; /* avoid warning */
22173
14.2k
    template_object = JS_UNDEFINED; /* avoid warning */
22174
14.2k
    if (call) {
22175
        /* Create a template object: an array of cooked strings */
22176
        /* Create an array of raw strings and store it to the raw property */
22177
10.1k
        template_object = JS_NewArray(ctx);
22178
10.1k
        if (JS_IsException(template_object))
22179
0
            return -1;
22180
        //        pool_idx = s->cur_func->cpool_count;
22181
10.1k
        ret = emit_push_const(s, template_object, 0);
22182
10.1k
        JS_FreeValue(ctx, template_object);
22183
10.1k
        if (ret)
22184
0
            return -1;
22185
10.1k
        raw_array = JS_NewArray(ctx);
22186
10.1k
        if (JS_IsException(raw_array))
22187
0
            return -1;
22188
10.1k
        if (JS_DefinePropertyValue(ctx, template_object, JS_ATOM_raw,
22189
10.1k
                                   raw_array, JS_PROP_THROW) < 0) {
22190
0
            return -1;
22191
0
        }
22192
10.1k
    }
22193
22194
14.2k
    depth = 0;
22195
19.6k
    while (s->token.val == TOK_TEMPLATE) {
22196
19.6k
        const uint8_t *p = s->token.ptr + 1;
22197
19.6k
        cooked = s->token;
22198
19.6k
        if (call) {
22199
10.5k
            if (JS_DefinePropertyValueUint32(ctx, raw_array, depth,
22200
10.5k
                                             JS_DupValue(ctx, s->token.u.str.str),
22201
10.5k
                                             JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
22202
0
                return -1;
22203
0
            }
22204
            /* re-parse the string with escape sequences but do not throw a
22205
               syntax error if it contains invalid sequences
22206
             */
22207
10.5k
            if (js_parse_string(s, '`', FALSE, p, &cooked, &p)) {
22208
23
                cooked.u.str.str = JS_UNDEFINED;
22209
23
            }
22210
10.5k
            if (JS_DefinePropertyValueUint32(ctx, template_object, depth,
22211
10.5k
                                             cooked.u.str.str,
22212
10.5k
                                             JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
22213
0
                return -1;
22214
0
            }
22215
10.5k
        } else {
22216
9.15k
            JSString *str;
22217
            /* re-parse the string with escape sequences and throw a
22218
               syntax error if it contains invalid sequences
22219
             */
22220
9.15k
            JS_FreeValue(ctx, s->token.u.str.str);
22221
9.15k
            s->token.u.str.str = JS_UNDEFINED;
22222
9.15k
            if (js_parse_string(s, '`', TRUE, p, &cooked, &p))
22223
0
                return -1;
22224
9.15k
            str = JS_VALUE_GET_STRING(cooked.u.str.str);
22225
9.15k
            if (str->len != 0 || depth == 0) {
22226
7.50k
                ret = emit_push_const(s, cooked.u.str.str, 1);
22227
7.50k
                JS_FreeValue(s->ctx, cooked.u.str.str);
22228
7.50k
                if (ret)
22229
0
                    return -1;
22230
7.50k
                if (depth == 0) {
22231
4.04k
                    if (s->token.u.str.sep == '`')
22232
3.94k
                        goto done1;
22233
103
                    emit_op(s, OP_get_field2);
22234
103
                    emit_atom(s, JS_ATOM_concat);
22235
103
                }
22236
3.56k
                depth++;
22237
3.56k
            } else {
22238
1.64k
                JS_FreeValue(s->ctx, cooked.u.str.str);
22239
1.64k
            }
22240
9.15k
        }
22241
15.7k
        if (s->token.u.str.sep == '`')
22242
10.2k
            goto done;
22243
5.49k
        if (next_token(s))
22244
1
            return -1;
22245
5.49k
        if (js_parse_expr(s))
22246
66
            return -1;
22247
5.42k
        depth++;
22248
5.42k
        if (s->token.val != '}') {
22249
1
            return js_parse_error(s, "expected '}' after template expression");
22250
1
        }
22251
        /* XXX: should convert to string at this stage? */
22252
5.42k
        free_token(s, &s->token);
22253
        /* Resume TOK_TEMPLATE parsing (s->token.line_num and
22254
         * s->token.ptr are OK) */
22255
5.42k
        s->got_lf = FALSE;
22256
5.42k
        s->last_line_num = s->token.line_num;
22257
5.42k
        if (js_parse_template_part(s, s->buf_ptr))
22258
2
            return -1;
22259
5.42k
    }
22260
0
    return js_parse_expect(s, TOK_TEMPLATE);
22261
22262
10.2k
 done:
22263
10.2k
    if (call) {
22264
        /* Seal the objects */
22265
10.1k
        seal_template_obj(ctx, raw_array);
22266
10.1k
        seal_template_obj(ctx, template_object);
22267
10.1k
        *argc = depth + 1;
22268
10.1k
    } else {
22269
35
        emit_op(s, OP_call_method);
22270
35
        emit_u16(s, depth - 1);
22271
35
    }
22272
14.1k
 done1:
22273
14.1k
    return next_token(s);
22274
10.2k
}
22275
22276
22277
187k
#define PROP_TYPE_IDENT 0
22278
41.4k
#define PROP_TYPE_VAR   1
22279
51.1k
#define PROP_TYPE_GET   2
22280
25.5k
#define PROP_TYPE_SET   3
22281
1.84k
#define PROP_TYPE_STAR  4
22282
1.77k
#define PROP_TYPE_ASYNC 5
22283
1.75k
#define PROP_TYPE_ASYNC_STAR 6
22284
22285
60.9k
#define PROP_TYPE_PRIVATE (1 << 4)
22286
22287
static BOOL token_is_ident(int tok)
22288
39.6k
{
22289
    /* Accept keywords and reserved words as property names */
22290
39.6k
    return (tok == TOK_IDENT ||
22291
39.6k
            (tok >= TOK_FIRST_KEYWORD &&
22292
14.6k
             tok <= TOK_LAST_KEYWORD));
22293
39.6k
}
22294
22295
/* if the property is an expression, name = JS_ATOM_NULL */
22296
static int __exception js_parse_property_name(JSParseState *s,
22297
                                              JSAtom *pname,
22298
                                              BOOL allow_method, BOOL allow_var,
22299
                                              BOOL allow_private)
22300
31.8k
{
22301
31.8k
    int is_private = 0;
22302
31.8k
    BOOL is_non_reserved_ident;
22303
31.8k
    JSAtom name;
22304
31.8k
    int prop_type;
22305
    
22306
31.8k
    prop_type = PROP_TYPE_IDENT;
22307
31.8k
    if (allow_method) {
22308
26.0k
        if (token_is_pseudo_keyword(s, JS_ATOM_get)
22309
26.0k
        ||  token_is_pseudo_keyword(s, JS_ATOM_set)) {
22310
            /* get x(), set x() */
22311
3
            name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
22312
3
            if (next_token(s))
22313
0
                goto fail1;
22314
3
            if (s->token.val == ':' || s->token.val == ',' ||
22315
3
                s->token.val == '}' || s->token.val == '(') {
22316
3
                is_non_reserved_ident = TRUE;
22317
3
                goto ident_found;
22318
3
            }
22319
0
            prop_type = PROP_TYPE_GET + (name == JS_ATOM_set);
22320
0
            JS_FreeAtom(s->ctx, name);
22321
25.9k
        } else if (s->token.val == '*') {
22322
46
            if (next_token(s))
22323
0
                goto fail;
22324
46
            prop_type = PROP_TYPE_STAR;
22325
25.9k
        } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
22326
25.9k
                   peek_token(s, TRUE) != '\n') {
22327
36
            name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
22328
36
            if (next_token(s))
22329
0
                goto fail1;
22330
36
            if (s->token.val == ':' || s->token.val == ',' ||
22331
36
                s->token.val == '}' || s->token.val == '(') {
22332
20
                is_non_reserved_ident = TRUE;
22333
20
                goto ident_found;
22334
20
            }
22335
16
            JS_FreeAtom(s->ctx, name);
22336
16
            if (s->token.val == '*') {
22337
0
                if (next_token(s))
22338
0
                    goto fail;
22339
0
                prop_type = PROP_TYPE_ASYNC_STAR;
22340
16
            } else {
22341
16
                prop_type = PROP_TYPE_ASYNC;
22342
16
            }
22343
16
        }
22344
26.0k
    }
22345
22346
31.8k
    if (token_is_ident(s->token.val)) {
22347
        /* variable can only be a non-reserved identifier */
22348
18.4k
        is_non_reserved_ident =
22349
18.4k
            (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved);
22350
        /* keywords and reserved words have a valid atom */
22351
18.4k
        name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
22352
18.4k
        if (next_token(s))
22353
4
            goto fail1;
22354
18.4k
    ident_found:
22355
18.4k
        if (is_non_reserved_ident &&
22356
18.4k
            prop_type == PROP_TYPE_IDENT && allow_var) {
22357
4.78k
            if (!(s->token.val == ':' ||
22358
4.78k
                  (s->token.val == '(' && allow_method))) {
22359
4.46k
                prop_type = PROP_TYPE_VAR;
22360
4.46k
            }
22361
4.78k
        }
22362
18.4k
    } else if (s->token.val == TOK_STRING) {
22363
17
        name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
22364
17
        if (name == JS_ATOM_NULL)
22365
0
            goto fail;
22366
17
        if (next_token(s))
22367
0
            goto fail1;
22368
13.3k
    } else if (s->token.val == TOK_NUMBER) {
22369
2.73k
        JSValue val;
22370
2.73k
        val = s->token.u.num.val;
22371
2.73k
#ifdef CONFIG_BIGNUM
22372
2.73k
        if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
22373
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
22374
0
            val = s->ctx->rt->bigfloat_ops.
22375
0
                mul_pow10_to_float64(s->ctx, &p->num,
22376
0
                                     s->token.u.num.exponent);
22377
0
            if (JS_IsException(val))
22378
0
                goto fail;
22379
0
            name = JS_ValueToAtom(s->ctx, val);
22380
0
            JS_FreeValue(s->ctx, val);
22381
0
        } else
22382
2.73k
#endif
22383
2.73k
        {
22384
2.73k
            name = JS_ValueToAtom(s->ctx, val);
22385
2.73k
        }
22386
2.73k
        if (name == JS_ATOM_NULL)
22387
0
            goto fail;
22388
2.73k
        if (next_token(s))
22389
0
            goto fail1;
22390
10.6k
    } else if (s->token.val == '[') {
22391
259
        if (next_token(s))
22392
0
            goto fail;
22393
259
        if (js_parse_expr(s))
22394
26
            goto fail;
22395
233
        if (js_parse_expect(s, ']'))
22396
1
            goto fail;
22397
232
        name = JS_ATOM_NULL;
22398
10.4k
    } else if (s->token.val == TOK_PRIVATE_NAME && allow_private) {
22399
10.3k
        name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
22400
10.3k
        if (next_token(s))
22401
0
            goto fail1;
22402
10.3k
        is_private = PROP_TYPE_PRIVATE;
22403
10.3k
    } else {
22404
12
        goto invalid_prop;
22405
12
    }
22406
31.8k
    if (prop_type != PROP_TYPE_IDENT && prop_type != PROP_TYPE_VAR &&
22407
31.8k
        s->token.val != '(') {
22408
0
        JS_FreeAtom(s->ctx, name);
22409
12
    invalid_prop:
22410
12
        js_parse_error(s, "invalid property name");
22411
12
        goto fail;
22412
0
    }
22413
31.8k
    *pname = name;
22414
31.8k
    return prop_type | is_private;
22415
4
 fail1:
22416
4
    JS_FreeAtom(s->ctx, name);
22417
43
 fail:
22418
43
    *pname = JS_ATOM_NULL;
22419
43
    return -1;
22420
4
}
22421
22422
typedef struct JSParsePos {
22423
    int last_line_num;
22424
    int line_num;
22425
    BOOL got_lf;
22426
    const uint8_t *ptr;
22427
} JSParsePos;
22428
22429
static int js_parse_get_pos(JSParseState *s, JSParsePos *sp)
22430
95.0k
{
22431
95.0k
    sp->last_line_num = s->last_line_num;
22432
95.0k
    sp->line_num = s->token.line_num;
22433
95.0k
    sp->ptr = s->token.ptr;
22434
95.0k
    sp->got_lf = s->got_lf;
22435
95.0k
    return 0;
22436
95.0k
}
22437
22438
static __exception int js_parse_seek_token(JSParseState *s, const JSParsePos *sp)
22439
95.0k
{
22440
95.0k
    s->token.line_num = sp->last_line_num;
22441
95.0k
    s->line_num = sp->line_num;
22442
95.0k
    s->buf_ptr = sp->ptr;
22443
95.0k
    s->got_lf = sp->got_lf;
22444
95.0k
    return next_token(s);
22445
95.0k
}
22446
22447
/* return TRUE if a regexp literal is allowed after this token */
22448
static BOOL is_regexp_allowed(int tok)
22449
30.9k
{
22450
30.9k
    switch (tok) {
22451
4
    case TOK_NUMBER:
22452
9.09k
    case TOK_STRING:
22453
9.24k
    case TOK_REGEXP:
22454
9.24k
    case TOK_DEC:
22455
9.24k
    case TOK_INC:
22456
9.27k
    case TOK_NULL:
22457
9.27k
    case TOK_FALSE:
22458
9.27k
    case TOK_TRUE:
22459
9.27k
    case TOK_THIS:
22460
9.77k
    case ')':
22461
10.0k
    case ']':
22462
10.0k
    case '}': /* XXX: regexp may occur after */
22463
19.6k
    case TOK_IDENT:
22464
19.6k
        return FALSE;
22465
11.3k
    default:
22466
11.3k
        return TRUE;
22467
30.9k
    }
22468
30.9k
}
22469
22470
16.4k
#define SKIP_HAS_SEMI       (1 << 0)
22471
39.3k
#define SKIP_HAS_ELLIPSIS   (1 << 1)
22472
262k
#define SKIP_HAS_ASSIGNMENT (1 << 2)
22473
22474
/* XXX: improve speed with early bailout */
22475
/* XXX: no longer works if regexps are present. Could use previous
22476
   regexp parsing heuristics to handle most cases */
22477
static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_terminator)
22478
81.2k
{
22479
81.2k
    char state[256];
22480
81.2k
    size_t level = 0;
22481
81.2k
    JSParsePos pos;
22482
81.2k
    int last_tok, tok = TOK_EOF;
22483
81.2k
    int c, tok_len, bits = 0;
22484
22485
    /* protect from underflow */
22486
81.2k
    state[level++] = 0;
22487
22488
81.2k
    js_parse_get_pos(s, &pos);
22489
81.2k
    last_tok = 0;
22490
1.71M
    for (;;) {
22491
1.71M
        switch(s->token.val) {
22492
86.7k
        case '(':
22493
184k
        case '[':
22494
230k
        case '{':
22495
230k
            if (level >= sizeof(state))
22496
7
                goto done;
22497
230k
            state[level++] = s->token.val;
22498
230k
            break;
22499
73.4k
        case ')':
22500
73.4k
            if (state[--level] != '(')
22501
1
                goto done;
22502
73.4k
            break;
22503
82.3k
        case ']':
22504
82.3k
            if (state[--level] != '[')
22505
0
                goto done;
22506
82.3k
            break;
22507
82.3k
        case '}':
22508
26.7k
            c = state[--level];
22509
26.7k
            if (c == '`') {
22510
                /* continue the parsing of the template */
22511
4.24k
                free_token(s, &s->token);
22512
                /* Resume TOK_TEMPLATE parsing (s->token.line_num and
22513
                 * s->token.ptr are OK) */
22514
4.24k
                s->got_lf = FALSE;
22515
4.24k
                s->last_line_num = s->token.line_num;
22516
4.24k
                if (js_parse_template_part(s, s->buf_ptr))
22517
67
                    goto done;
22518
4.18k
                goto handle_template;
22519
22.4k
            } else if (c != '{') {
22520
102
                goto done;
22521
102
            }
22522
22.3k
            break;
22523
22.3k
        case TOK_TEMPLATE:
22524
10.2k
        handle_template:
22525
10.2k
            if (s->token.u.str.sep != '`') {
22526
                /* '${' inside the template : closing '}' and continue
22527
                   parsing the template */
22528
4.24k
                if (level >= sizeof(state))
22529
0
                    goto done;
22530
4.24k
                state[level++] = '`';
22531
4.24k
            } 
22532
10.2k
            break;
22533
10.2k
        case TOK_EOF:
22534
371
            goto done;
22535
20.2k
        case ';':
22536
20.2k
            if (level == 2) {
22537
9.36k
                bits |= SKIP_HAS_SEMI;
22538
9.36k
            }
22539
20.2k
            break;
22540
24.0k
        case TOK_ELLIPSIS:
22541
24.0k
            if (level == 2) {
22542
4.93k
                bits |= SKIP_HAS_ELLIPSIS;
22543
4.93k
            }
22544
24.0k
            break;
22545
235k
        case '=':
22546
235k
            bits |= SKIP_HAS_ASSIGNMENT;
22547
235k
            break;
22548
            
22549
0
        case TOK_DIV_ASSIGN:
22550
0
            tok_len = 2;
22551
0
            goto parse_regexp;
22552
30.9k
        case '/':
22553
30.9k
            tok_len = 1;
22554
30.9k
        parse_regexp:
22555
30.9k
            if (is_regexp_allowed(last_tok)) {
22556
11.3k
                s->buf_ptr -= tok_len;
22557
11.3k
                if (js_parse_regexp(s)) {
22558
                    /* XXX: should clear the exception */
22559
1
                    goto done;
22560
1
                }
22561
11.3k
            }
22562
30.9k
            break;
22563
1.71M
        }
22564
        /* last_tok is only used to recognize regexps */
22565
1.71M
        if (s->token.val == TOK_IDENT &&
22566
1.71M
            (token_is_pseudo_keyword(s, JS_ATOM_of) ||
22567
586k
             token_is_pseudo_keyword(s, JS_ATOM_yield))) {
22568
413
            last_tok = TOK_OF;
22569
1.71M
        } else {
22570
1.71M
            last_tok = s->token.val;
22571
1.71M
        }
22572
1.71M
        if (next_token(s)) {
22573
            /* XXX: should clear the exception generated by next_token() */
22574
605
            break;
22575
605
        }
22576
1.71M
        if (level <= 1) {
22577
80.1k
            tok = s->token.val;
22578
80.1k
            if (token_is_pseudo_keyword(s, JS_ATOM_of))
22579
0
                tok = TOK_OF;
22580
80.1k
            if (no_line_terminator && s->last_line_num != s->token.line_num)
22581
309
                tok = '\n';
22582
80.1k
            break;
22583
80.1k
        }
22584
1.71M
    }
22585
81.2k
 done:
22586
81.2k
    if (pbits) {
22587
76.2k
        *pbits = bits;
22588
76.2k
    }
22589
81.2k
    if (js_parse_seek_token(s, &pos))
22590
1
        return -1;
22591
81.2k
    return tok;
22592
81.2k
}
22593
22594
static void set_object_name(JSParseState *s, JSAtom name)
22595
310k
{
22596
310k
    JSFunctionDef *fd = s->cur_func;
22597
310k
    int opcode;
22598
22599
310k
    opcode = get_prev_opcode(fd);
22600
310k
    if (opcode == OP_set_name) {
22601
        /* XXX: should free atom after OP_set_name? */
22602
6.78k
        fd->byte_code.size = fd->last_opcode_pos;
22603
6.78k
        fd->last_opcode_pos = -1;
22604
6.78k
        emit_op(s, OP_set_name);
22605
6.78k
        emit_atom(s, name);
22606
303k
    } else if (opcode == OP_set_class_name) {
22607
159
        int define_class_pos;
22608
159
        JSAtom atom;
22609
159
        define_class_pos = fd->last_opcode_pos + 1 -
22610
159
            get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
22611
159
        assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
22612
        /* for consistency we free the previous atom which is
22613
           JS_ATOM_empty_string */
22614
159
        atom = get_u32(fd->byte_code.buf + define_class_pos + 1);
22615
159
        JS_FreeAtom(s->ctx, atom);
22616
159
        put_u32(fd->byte_code.buf + define_class_pos + 1,
22617
159
                JS_DupAtom(s->ctx, name));
22618
159
        fd->last_opcode_pos = -1;
22619
159
    }
22620
310k
}
22621
22622
static void set_object_name_computed(JSParseState *s)
22623
10.2k
{
22624
10.2k
    JSFunctionDef *fd = s->cur_func;
22625
10.2k
    int opcode;
22626
22627
10.2k
    opcode = get_prev_opcode(fd);
22628
10.2k
    if (opcode == OP_set_name) {
22629
        /* XXX: should free atom after OP_set_name? */
22630
3
        fd->byte_code.size = fd->last_opcode_pos;
22631
3
        fd->last_opcode_pos = -1;
22632
3
        emit_op(s, OP_set_name_computed);
22633
10.2k
    } else if (opcode == OP_set_class_name) {
22634
55
        int define_class_pos;
22635
55
        define_class_pos = fd->last_opcode_pos + 1 -
22636
55
            get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
22637
55
        assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
22638
55
        fd->byte_code.buf[define_class_pos] = OP_define_class_computed;
22639
55
        fd->last_opcode_pos = -1;
22640
55
    }
22641
10.2k
}
22642
22643
static __exception int js_parse_object_literal(JSParseState *s)
22644
2.37k
{
22645
2.37k
    JSAtom name = JS_ATOM_NULL;
22646
2.37k
    const uint8_t *start_ptr;
22647
2.37k
    int start_line, prop_type;
22648
2.37k
    BOOL has_proto;
22649
22650
2.37k
    if (next_token(s))
22651
0
        goto fail;
22652
    /* XXX: add an initial length that will be patched back */
22653
2.37k
    emit_op(s, OP_object);
22654
2.37k
    has_proto = FALSE;
22655
2.38k
    while (s->token.val != '}') {
22656
        /* specific case for getter/setter */
22657
1.70k
        start_ptr = s->token.ptr;
22658
1.70k
        start_line = s->token.line_num;
22659
22660
1.70k
        if (s->token.val == TOK_ELLIPSIS) {
22661
1.00k
            if (next_token(s))
22662
0
                return -1;
22663
1.00k
            if (js_parse_assign_expr(s))
22664
7
                return -1;
22665
997
            emit_op(s, OP_null);  /* dummy excludeList */
22666
997
            emit_op(s, OP_copy_data_properties);
22667
997
            emit_u8(s, 2 | (1 << 2) | (0 << 5));
22668
997
            emit_op(s, OP_drop); /* pop excludeList */
22669
997
            emit_op(s, OP_drop); /* pop src object */
22670
997
            goto next;
22671
1.00k
        }
22672
22673
700
        prop_type = js_parse_property_name(s, &name, TRUE, TRUE, FALSE);
22674
700
        if (prop_type < 0)
22675
30
            goto fail;
22676
22677
670
        if (prop_type == PROP_TYPE_VAR) {
22678
            /* shortcut for x: x */
22679
349
            emit_op(s, OP_scope_get_var);
22680
349
            emit_atom(s, name);
22681
349
            emit_u16(s, s->cur_func->scope_level);
22682
349
            emit_op(s, OP_define_field);
22683
349
            emit_atom(s, name);
22684
349
        } else if (s->token.val == '(') {
22685
279
            BOOL is_getset = (prop_type == PROP_TYPE_GET ||
22686
279
                              prop_type == PROP_TYPE_SET);
22687
279
            JSParseFunctionEnum func_type;
22688
279
            JSFunctionKindEnum func_kind;
22689
279
            int op_flags;
22690
22691
279
            func_kind = JS_FUNC_NORMAL;
22692
279
            if (is_getset) {
22693
0
                func_type = JS_PARSE_FUNC_GETTER + prop_type - PROP_TYPE_GET;
22694
279
            } else {
22695
279
                func_type = JS_PARSE_FUNC_METHOD;
22696
279
                if (prop_type == PROP_TYPE_STAR)
22697
0
                    func_kind = JS_FUNC_GENERATOR;
22698
279
                else if (prop_type == PROP_TYPE_ASYNC)
22699
0
                    func_kind = JS_FUNC_ASYNC;
22700
279
                else if (prop_type == PROP_TYPE_ASYNC_STAR)
22701
0
                    func_kind = JS_FUNC_ASYNC_GENERATOR;
22702
279
            }
22703
279
            if (js_parse_function_decl(s, func_type, func_kind, JS_ATOM_NULL,
22704
279
                                       start_ptr, start_line))
22705
255
                goto fail;
22706
24
            if (name == JS_ATOM_NULL) {
22707
0
                emit_op(s, OP_define_method_computed);
22708
24
            } else {
22709
24
                emit_op(s, OP_define_method);
22710
24
                emit_atom(s, name);
22711
24
            }
22712
24
            if (is_getset) {
22713
0
                op_flags = OP_DEFINE_METHOD_GETTER +
22714
0
                    prop_type - PROP_TYPE_GET;
22715
24
            } else {
22716
24
                op_flags = OP_DEFINE_METHOD_METHOD;
22717
24
            }
22718
24
            emit_u8(s, op_flags | OP_DEFINE_METHOD_ENUMERABLE);
22719
42
        } else {
22720
42
            if (js_parse_expect(s, ':'))
22721
2
                goto fail;
22722
40
            if (js_parse_assign_expr(s))
22723
40
                goto fail;
22724
0
            if (name == JS_ATOM_NULL) {
22725
0
                set_object_name_computed(s);
22726
0
                emit_op(s, OP_define_array_el);
22727
0
                emit_op(s, OP_drop);
22728
0
            } else if (name == JS_ATOM___proto__) {
22729
0
                if (has_proto) {
22730
0
                    js_parse_error(s, "duplicate __proto__ property name");
22731
0
                    goto fail;
22732
0
                }
22733
0
                emit_op(s, OP_set_proto);
22734
0
                has_proto = TRUE;
22735
0
            } else {
22736
0
                set_object_name(s, name);
22737
0
                emit_op(s, OP_define_field);
22738
0
                emit_atom(s, name);
22739
0
            }
22740
0
        }
22741
373
        JS_FreeAtom(s->ctx, name);
22742
1.37k
    next:
22743
1.37k
        name = JS_ATOM_NULL;
22744
1.37k
        if (s->token.val != ',')
22745
1.36k
            break;
22746
7
        if (next_token(s))
22747
0
            goto fail;
22748
7
    }
22749
2.04k
    if (js_parse_expect(s, '}'))
22750
3
        goto fail;
22751
2.03k
    return 0;
22752
330
 fail:
22753
330
    JS_FreeAtom(s->ctx, name);
22754
330
    return -1;
22755
2.04k
}
22756
22757
/* allow the 'in' binary operator */
22758
213k
#define PF_IN_ACCEPTED  (1 << 0) 
22759
/* allow function calls parsing in js_parse_postfix_expr() */
22760
1.57M
#define PF_POSTFIX_CALL (1 << 1) 
22761
/* allow arrow functions parsing in js_parse_postfix_expr() */
22762
2.98M
#define PF_ARROW_FUNC   (1 << 2) 
22763
/* allow the exponentiation operator in js_parse_unary() */
22764
1.56M
#define PF_POW_ALLOWED  (1 << 3) 
22765
/* forbid the exponentiation operator in js_parse_unary() */
22766
809k
#define PF_POW_FORBIDDEN (1 << 4) 
22767
22768
static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
22769
22770
static __exception int js_parse_left_hand_side_expr(JSParseState *s)
22771
13.0k
{
22772
13.0k
    return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
22773
13.0k
}
22774
22775
/* XXX: could generate specific bytecode */
22776
static __exception int js_parse_class_default_ctor(JSParseState *s,
22777
                                                   BOOL has_super,
22778
                                                   JSFunctionDef **pfd)
22779
11.1k
{
22780
11.1k
    JSParsePos pos;
22781
11.1k
    const char *str;
22782
11.1k
    int ret, line_num;
22783
11.1k
    JSParseFunctionEnum func_type;
22784
11.1k
    const uint8_t *saved_buf_end;
22785
    
22786
11.1k
    js_parse_get_pos(s, &pos);
22787
11.1k
    if (has_super) {
22788
        /* spec change: no argument evaluation */
22789
0
        str = "(){super(...arguments);}";
22790
0
        func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
22791
11.1k
    } else {
22792
11.1k
        str = "(){}";
22793
11.1k
        func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
22794
11.1k
    }
22795
11.1k
    line_num = s->token.line_num;
22796
11.1k
    saved_buf_end = s->buf_end;
22797
11.1k
    s->buf_ptr = (uint8_t *)str;
22798
11.1k
    s->buf_end = (uint8_t *)(str + strlen(str));
22799
11.1k
    ret = next_token(s);
22800
11.1k
    if (!ret) {
22801
11.1k
        ret = js_parse_function_decl2(s, func_type, JS_FUNC_NORMAL,
22802
11.1k
                                      JS_ATOM_NULL, (uint8_t *)str,
22803
11.1k
                                      line_num, JS_PARSE_EXPORT_NONE, pfd);
22804
11.1k
    }
22805
11.1k
    s->buf_end = saved_buf_end;
22806
11.1k
    ret |= js_parse_seek_token(s, &pos);
22807
11.1k
    return ret;
22808
11.1k
}
22809
22810
/* find field in the current scope */
22811
static int find_private_class_field(JSContext *ctx, JSFunctionDef *fd,
22812
                                    JSAtom name, int scope_level)
22813
10.3k
{
22814
10.3k
    int idx;
22815
10.3k
    idx = fd->scopes[scope_level].first;
22816
12.0k
    while (idx != -1) {
22817
9.10k
        if (fd->vars[idx].scope_level != scope_level)
22818
7.49k
            break;
22819
1.61k
        if (fd->vars[idx].var_name == name)
22820
2
            return idx;
22821
1.61k
        idx = fd->vars[idx].scope_next;
22822
1.61k
    }
22823
10.3k
    return -1;
22824
10.3k
}
22825
22826
/* initialize the class fields, called by the constructor. Note:
22827
   super() can be called in an arrow function, so <this> and
22828
   <class_fields_init> can be variable references */
22829
static void emit_class_field_init(JSParseState *s)
22830
11.1k
{
22831
11.1k
    int label_next;
22832
    
22833
11.1k
    emit_op(s, OP_scope_get_var);
22834
11.1k
    emit_atom(s, JS_ATOM_class_fields_init);
22835
11.1k
    emit_u16(s, s->cur_func->scope_level);
22836
22837
    /* no need to call the class field initializer if not defined */
22838
11.1k
    emit_op(s, OP_dup);
22839
11.1k
    label_next = emit_goto(s, OP_if_false, -1);
22840
    
22841
11.1k
    emit_op(s, OP_scope_get_var);
22842
11.1k
    emit_atom(s, JS_ATOM_this);
22843
11.1k
    emit_u16(s, 0);
22844
    
22845
11.1k
    emit_op(s, OP_swap);
22846
    
22847
11.1k
    emit_op(s, OP_call_method);
22848
11.1k
    emit_u16(s, 0);
22849
22850
11.1k
    emit_label(s, label_next);
22851
11.1k
    emit_op(s, OP_drop);
22852
11.1k
}
22853
22854
/* build a private setter function name from the private getter name */
22855
static JSAtom get_private_setter_name(JSContext *ctx, JSAtom name)
22856
0
{
22857
0
    return js_atom_concat_str(ctx, name, "<set>");
22858
0
}
22859
22860
typedef struct {
22861
    JSFunctionDef *fields_init_fd;
22862
    int computed_fields_count;
22863
    BOOL has_brand;
22864
    int brand_push_pos;
22865
} ClassFieldsDef;
22866
22867
static __exception int emit_class_init_start(JSParseState *s,
22868
                                             ClassFieldsDef *cf)
22869
10.4k
{
22870
10.4k
    int label_add_brand;
22871
    
22872
10.4k
    cf->fields_init_fd = js_parse_function_class_fields_init(s);
22873
10.4k
    if (!cf->fields_init_fd)
22874
0
        return -1;
22875
22876
10.4k
    s->cur_func = cf->fields_init_fd;
22877
    
22878
    /* XXX: would be better to add the code only if needed, maybe in a
22879
       later pass */
22880
10.4k
    emit_op(s, OP_push_false); /* will be patched later */
22881
10.4k
    cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos;
22882
10.4k
    label_add_brand = emit_goto(s, OP_if_false, -1);
22883
    
22884
10.4k
    emit_op(s, OP_scope_get_var);
22885
10.4k
    emit_atom(s, JS_ATOM_this);
22886
10.4k
    emit_u16(s, 0);
22887
    
22888
10.4k
    emit_op(s, OP_scope_get_var);
22889
10.4k
    emit_atom(s, JS_ATOM_home_object);
22890
10.4k
    emit_u16(s, 0);
22891
    
22892
10.4k
    emit_op(s, OP_add_brand);
22893
    
22894
10.4k
    emit_label(s, label_add_brand);
22895
22896
10.4k
    s->cur_func = s->cur_func->parent;
22897
10.4k
    return 0;
22898
10.4k
}
22899
22900
static __exception int add_brand(JSParseState *s, ClassFieldsDef *cf)
22901
313
{
22902
313
    if (!cf->has_brand) {
22903
        /* define the brand field in 'this' of the initializer */
22904
255
        if (!cf->fields_init_fd) {
22905
213
            if (emit_class_init_start(s, cf))
22906
0
                return -1;
22907
213
        }
22908
        /* patch the start of the function to enable the OP_add_brand code */
22909
255
        cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true;
22910
        
22911
255
        cf->has_brand = TRUE;
22912
255
    }
22913
313
    return 0;
22914
313
}
22915
22916
static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf)
22917
10.2k
{
22918
10.2k
    int cpool_idx;
22919
        
22920
10.2k
    s->cur_func = cf->fields_init_fd;
22921
10.2k
    emit_op(s, OP_return_undef);
22922
10.2k
    s->cur_func = s->cur_func->parent;
22923
    
22924
10.2k
    cpool_idx = cpool_add(s, JS_NULL);
22925
10.2k
    cf->fields_init_fd->parent_cpool_idx = cpool_idx;
22926
10.2k
    emit_op(s, OP_fclosure);
22927
10.2k
    emit_u32(s, cpool_idx);
22928
10.2k
    emit_op(s, OP_set_home_object);
22929
10.2k
}
22930
22931
22932
static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
22933
                                      JSParseExportEnum export_flag)
22934
11.3k
{
22935
11.3k
    JSContext *ctx = s->ctx;
22936
11.3k
    JSFunctionDef *fd = s->cur_func;
22937
11.3k
    JSAtom name = JS_ATOM_NULL, class_name = JS_ATOM_NULL, class_name1;
22938
11.3k
    JSAtom class_var_name = JS_ATOM_NULL;
22939
11.3k
    JSFunctionDef *method_fd, *ctor_fd;
22940
11.3k
    int saved_js_mode, class_name_var_idx, prop_type, ctor_cpool_offset;
22941
11.3k
    int class_flags = 0, i, define_class_offset;
22942
11.3k
    BOOL is_static, is_private;
22943
11.3k
    const uint8_t *class_start_ptr = s->token.ptr;
22944
11.3k
    const uint8_t *start_ptr;
22945
11.3k
    ClassFieldsDef class_fields[2];
22946
        
22947
    /* classes are parsed and executed in strict mode */
22948
11.3k
    saved_js_mode = fd->js_mode;
22949
11.3k
    fd->js_mode |= JS_MODE_STRICT;
22950
11.3k
    if (next_token(s))
22951
0
        goto fail;
22952
11.3k
    if (s->token.val == TOK_IDENT) {
22953
9.48k
        if (s->token.u.ident.is_reserved) {
22954
0
            js_parse_error_reserved_identifier(s);
22955
0
            goto fail;
22956
0
        }
22957
9.48k
        class_name = JS_DupAtom(ctx, s->token.u.ident.atom);
22958
9.48k
        if (next_token(s))
22959
0
            goto fail;
22960
9.48k
    } else if (!is_class_expr && export_flag != JS_PARSE_EXPORT_DEFAULT) {
22961
0
        js_parse_error(s, "class statement requires a name");
22962
0
        goto fail;
22963
0
    }
22964
11.3k
    if (!is_class_expr) {
22965
31
        if (class_name == JS_ATOM_NULL)
22966
0
            class_var_name = JS_ATOM__default_; /* export default */
22967
31
        else
22968
31
            class_var_name = class_name;
22969
31
        class_var_name = JS_DupAtom(ctx, class_var_name);
22970
31
    }
22971
22972
11.3k
    push_scope(s);
22973
22974
11.3k
    if (s->token.val == TOK_EXTENDS) {
22975
0
        class_flags = JS_DEFINE_CLASS_HAS_HERITAGE;
22976
0
        if (next_token(s))
22977
0
            goto fail;
22978
0
        if (js_parse_left_hand_side_expr(s))
22979
0
            goto fail;
22980
11.3k
    } else {
22981
11.3k
        emit_op(s, OP_undefined);
22982
11.3k
    }
22983
22984
    /* add a 'const' definition for the class name */
22985
11.3k
    if (class_name != JS_ATOM_NULL) {
22986
9.48k
        class_name_var_idx = define_var(s, fd, class_name, JS_VAR_DEF_CONST);
22987
9.48k
        if (class_name_var_idx < 0)
22988
0
            goto fail;
22989
9.48k
    }
22990
22991
11.3k
    if (js_parse_expect(s, '{'))
22992
2
        goto fail;
22993
22994
    /* this scope contains the private fields */
22995
11.3k
    push_scope(s);
22996
22997
11.3k
    emit_op(s, OP_push_const);
22998
11.3k
    ctor_cpool_offset = fd->byte_code.size;
22999
11.3k
    emit_u32(s, 0); /* will be patched at the end of the class parsing */
23000
23001
11.3k
    if (class_name == JS_ATOM_NULL) {
23002
1.87k
        if (class_var_name != JS_ATOM_NULL)
23003
0
            class_name1 = JS_ATOM_default;
23004
1.87k
        else
23005
1.87k
            class_name1 = JS_ATOM_empty_string;
23006
9.48k
    } else {
23007
9.48k
        class_name1 = class_name;
23008
9.48k
    }
23009
    
23010
11.3k
    emit_op(s, OP_define_class);
23011
11.3k
    emit_atom(s, class_name1);
23012
11.3k
    emit_u8(s, class_flags);
23013
11.3k
    define_class_offset = fd->last_opcode_pos;
23014
23015
34.0k
    for(i = 0; i < 2; i++) {
23016
22.7k
        ClassFieldsDef *cf = &class_fields[i];
23017
22.7k
        cf->fields_init_fd = NULL;
23018
22.7k
        cf->computed_fields_count = 0;
23019
22.7k
        cf->has_brand = FALSE;
23020
22.7k
    }
23021
    
23022
11.3k
    ctor_fd = NULL;
23023
44.3k
    while (s->token.val != '}') {
23024
33.2k
        if (s->token.val == ';') {
23025
7.92k
            if (next_token(s))
23026
0
                goto fail;
23027
7.92k
            continue;
23028
7.92k
        }
23029
25.3k
        is_static = (s->token.val == TOK_STATIC);
23030
25.3k
        prop_type = -1;
23031
25.3k
        if (is_static) {
23032
0
            if (next_token(s))
23033
0
                goto fail;
23034
            /* allow "static" field name */
23035
0
            if (s->token.val == ';' || s->token.val == '=') {
23036
0
                is_static = FALSE;
23037
0
                name = JS_DupAtom(ctx, JS_ATOM_static);
23038
0
                prop_type = PROP_TYPE_IDENT;
23039
0
            }
23040
0
        }
23041
25.3k
        if (is_static)
23042
0
            emit_op(s, OP_swap);
23043
25.3k
        start_ptr = s->token.ptr;
23044
25.3k
        if (prop_type < 0) {
23045
25.3k
            prop_type = js_parse_property_name(s, &name, TRUE, FALSE, TRUE);
23046
25.3k
            if (prop_type < 0)
23047
13
                goto fail;
23048
25.3k
        }
23049
25.2k
        is_private = prop_type & PROP_TYPE_PRIVATE;
23050
25.2k
        prop_type &= ~PROP_TYPE_PRIVATE;
23051
        
23052
25.2k
        if ((name == JS_ATOM_constructor && !is_static &&
23053
25.2k
             prop_type != PROP_TYPE_IDENT) ||
23054
25.2k
            (name == JS_ATOM_prototype && is_static) ||
23055
25.2k
            name == JS_ATOM_hash_constructor) {
23056
0
            js_parse_error(s, "invalid method name");
23057
0
            goto fail;
23058
0
        }
23059
25.2k
        if (prop_type == PROP_TYPE_GET || prop_type == PROP_TYPE_SET) {
23060
0
            BOOL is_set = prop_type - PROP_TYPE_GET;
23061
0
            JSFunctionDef *method_fd;
23062
23063
0
            if (is_private) {
23064
0
                int idx, var_kind;
23065
0
                idx = find_private_class_field(ctx, fd, name, fd->scope_level);
23066
0
                if (idx >= 0) {
23067
0
                    var_kind = fd->vars[idx].var_kind;
23068
0
                    if (var_kind == JS_VAR_PRIVATE_FIELD ||
23069
0
                        var_kind == JS_VAR_PRIVATE_METHOD ||
23070
0
                        var_kind == JS_VAR_PRIVATE_GETTER_SETTER ||
23071
0
                        var_kind == (JS_VAR_PRIVATE_GETTER + is_set)) {
23072
0
                        goto private_field_already_defined;
23073
0
                    }
23074
0
                    fd->vars[idx].var_kind = JS_VAR_PRIVATE_GETTER_SETTER;
23075
0
                } else {
23076
0
                    if (add_private_class_field(s, fd, name,
23077
0
                                                JS_VAR_PRIVATE_GETTER + is_set) < 0)
23078
0
                        goto fail;
23079
0
                }
23080
0
                if (add_brand(s, &class_fields[is_static]) < 0)
23081
0
                    goto fail;
23082
0
            }
23083
23084
0
            if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set,
23085
0
                                        JS_FUNC_NORMAL, JS_ATOM_NULL,
23086
0
                                        start_ptr, s->token.line_num,
23087
0
                                        JS_PARSE_EXPORT_NONE, &method_fd))
23088
0
                goto fail;
23089
0
            if (is_private) {
23090
0
                method_fd->need_home_object = TRUE; /* needed for brand check */
23091
0
                emit_op(s, OP_set_home_object);
23092
                /* XXX: missing function name */
23093
0
                emit_op(s, OP_scope_put_var_init);
23094
0
                if (is_set) {
23095
0
                    JSAtom setter_name;
23096
0
                    int ret;
23097
                    
23098
0
                    setter_name = get_private_setter_name(ctx, name);
23099
0
                    if (setter_name == JS_ATOM_NULL)
23100
0
                        goto fail;
23101
0
                    emit_atom(s, setter_name);
23102
0
                    ret = add_private_class_field(s, fd, setter_name,
23103
0
                                                  JS_VAR_PRIVATE_SETTER);
23104
0
                    JS_FreeAtom(ctx, setter_name);
23105
0
                    if (ret < 0)
23106
0
                        goto fail;
23107
0
                } else {
23108
0
                    emit_atom(s, name);
23109
0
                }
23110
0
                emit_u16(s, s->cur_func->scope_level);
23111
0
            } else {
23112
0
                if (name == JS_ATOM_NULL) {
23113
0
                    emit_op(s, OP_define_method_computed);
23114
0
                } else {
23115
0
                    emit_op(s, OP_define_method);
23116
0
                    emit_atom(s, name);
23117
0
                }
23118
0
                emit_u8(s, OP_DEFINE_METHOD_GETTER + is_set);
23119
0
            }
23120
25.2k
        } else if (prop_type == PROP_TYPE_IDENT && s->token.val != '(') {
23121
23.7k
            ClassFieldsDef *cf = &class_fields[is_static];
23122
23.7k
            JSAtom field_var_name = JS_ATOM_NULL;
23123
            
23124
            /* class field */
23125
23126
            /* XXX: spec: not consistent with method name checks */
23127
23.7k
            if (name == JS_ATOM_constructor || name == JS_ATOM_prototype) {
23128
0
                js_parse_error(s, "invalid field name");
23129
0
                goto fail;
23130
0
            }
23131
            
23132
23.7k
            if (is_private) {
23133
10.0k
                if (find_private_class_field(ctx, fd, name,
23134
10.0k
                                             fd->scope_level) >= 0) {
23135
2
                    goto private_field_already_defined;
23136
2
                }
23137
10.0k
                if (add_private_class_field(s, fd, name,
23138
10.0k
                                            JS_VAR_PRIVATE_FIELD) < 0)
23139
0
                    goto fail;
23140
10.0k
                emit_op(s, OP_private_symbol);
23141
10.0k
                emit_atom(s, name);
23142
10.0k
                emit_op(s, OP_scope_put_var_init);
23143
10.0k
                emit_atom(s, name);
23144
10.0k
                emit_u16(s, s->cur_func->scope_level);
23145
10.0k
            }
23146
23147
23.7k
            if (!cf->fields_init_fd) {
23148
10.2k
                if (emit_class_init_start(s, cf))
23149
0
                    goto fail;
23150
10.2k
            }
23151
23.7k
            if (name == JS_ATOM_NULL ) {
23152
                /* save the computed field name into a variable */
23153
222
                field_var_name = js_atom_concat_num(ctx, JS_ATOM_computed_field + is_static, cf->computed_fields_count);
23154
222
                if (field_var_name == JS_ATOM_NULL)
23155
0
                    goto fail;
23156
222
                if (define_var(s, fd, field_var_name, JS_VAR_DEF_CONST) < 0) {
23157
0
                    JS_FreeAtom(ctx, field_var_name);
23158
0
                    goto fail;
23159
0
                }
23160
222
                emit_op(s, OP_to_propkey);
23161
222
                emit_op(s, OP_scope_put_var_init);
23162
222
                emit_atom(s, field_var_name);
23163
222
                emit_u16(s, s->cur_func->scope_level);
23164
222
            }
23165
23.7k
            s->cur_func = cf->fields_init_fd;
23166
23.7k
            emit_op(s, OP_scope_get_var);
23167
23.7k
            emit_atom(s, JS_ATOM_this);
23168
23.7k
            emit_u16(s, 0);
23169
23170
23.7k
            if (name == JS_ATOM_NULL) {
23171
222
                emit_op(s, OP_scope_get_var);
23172
222
                emit_atom(s, field_var_name);
23173
222
                emit_u16(s, s->cur_func->scope_level);
23174
222
                cf->computed_fields_count++;
23175
222
                JS_FreeAtom(ctx, field_var_name);
23176
23.5k
            } else if (is_private) {
23177
10.0k
                emit_op(s, OP_scope_get_var);
23178
10.0k
                emit_atom(s, name);
23179
10.0k
                emit_u16(s, s->cur_func->scope_level);
23180
10.0k
            }
23181
            
23182
23.7k
            if (s->token.val == '=') {
23183
2.54k
                if (next_token(s))
23184
0
                    goto fail;
23185
2.54k
                if (js_parse_assign_expr(s))
23186
190
                    goto fail;
23187
21.2k
            } else {
23188
21.2k
                emit_op(s, OP_undefined);
23189
21.2k
            }
23190
23.5k
            if (is_private) {
23191
10.0k
                set_object_name_computed(s);
23192
10.0k
                emit_op(s, OP_define_private_field);
23193
13.5k
            } else if (name == JS_ATOM_NULL) {
23194
222
                set_object_name_computed(s);
23195
222
                emit_op(s, OP_define_array_el);
23196
222
                emit_op(s, OP_drop);
23197
13.2k
            } else {
23198
13.2k
                set_object_name(s, name);
23199
13.2k
                emit_op(s, OP_define_field);
23200
13.2k
                emit_atom(s, name);
23201
13.2k
            }
23202
23.5k
            s->cur_func = s->cur_func->parent;
23203
23.5k
            if (js_parse_expect_semi(s))
23204
8
                goto fail;
23205
23.5k
        } else {
23206
1.52k
            JSParseFunctionEnum func_type;
23207
1.52k
            JSFunctionKindEnum func_kind;
23208
            
23209
1.52k
            func_type = JS_PARSE_FUNC_METHOD;
23210
1.52k
            func_kind = JS_FUNC_NORMAL;
23211
1.52k
            if (prop_type == PROP_TYPE_STAR) {
23212
46
                func_kind = JS_FUNC_GENERATOR;
23213
1.47k
            } else if (prop_type == PROP_TYPE_ASYNC) {
23214
0
                func_kind = JS_FUNC_ASYNC;
23215
1.47k
            } else if (prop_type == PROP_TYPE_ASYNC_STAR) {
23216
0
                func_kind = JS_FUNC_ASYNC_GENERATOR;
23217
1.47k
            } else if (name == JS_ATOM_constructor && !is_static) {
23218
0
                if (ctor_fd) {
23219
0
                    js_parse_error(s, "property constructor appears more than once");
23220
0
                    goto fail;
23221
0
                }
23222
0
                if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE)
23223
0
                    func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
23224
0
                else
23225
0
                    func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
23226
0
            }
23227
1.52k
            if (is_private) {
23228
313
                if (add_brand(s, &class_fields[is_static]) < 0)
23229
0
                    goto fail;
23230
313
            }
23231
1.52k
            if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, start_ptr, s->token.line_num, JS_PARSE_EXPORT_NONE, &method_fd))
23232
6
                goto fail;
23233
1.51k
            if (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR ||
23234
1.51k
                func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
23235
0
                ctor_fd = method_fd;
23236
1.51k
            } else if (is_private) {
23237
313
                method_fd->need_home_object = TRUE; /* needed for brand check */
23238
313
                if (find_private_class_field(ctx, fd, name,
23239
313
                                             fd->scope_level) >= 0) {
23240
2
                private_field_already_defined:
23241
2
                    js_parse_error(s, "private class field is already defined");
23242
2
                    goto fail;
23243
0
                }
23244
313
                if (add_private_class_field(s, fd, name,
23245
313
                                            JS_VAR_PRIVATE_METHOD) < 0)
23246
0
                    goto fail;
23247
313
                emit_op(s, OP_set_home_object);
23248
313
                emit_op(s, OP_set_name);
23249
313
                emit_atom(s, name);
23250
313
                emit_op(s, OP_scope_put_var_init);
23251
313
                emit_atom(s, name);
23252
313
                emit_u16(s, s->cur_func->scope_level);
23253
1.20k
            } else {
23254
1.20k
                if (name == JS_ATOM_NULL) {
23255
10
                    emit_op(s, OP_define_method_computed);
23256
1.19k
                } else {
23257
1.19k
                    emit_op(s, OP_define_method);
23258
1.19k
                    emit_atom(s, name);
23259
1.19k
                }
23260
1.20k
                emit_u8(s, OP_DEFINE_METHOD_METHOD);
23261
1.20k
            }
23262
1.51k
        }
23263
25.0k
        if (is_static)
23264
0
            emit_op(s, OP_swap);
23265
25.0k
        JS_FreeAtom(ctx, name);
23266
25.0k
        name = JS_ATOM_NULL;
23267
25.0k
    }
23268
23269
11.1k
    if (s->token.val != '}') {
23270
0
        js_parse_error(s, "expecting '%c'", '}');
23271
0
        goto fail;
23272
0
    }
23273
23274
11.1k
    if (!ctor_fd) {
23275
11.1k
        if (js_parse_class_default_ctor(s, class_flags & JS_DEFINE_CLASS_HAS_HERITAGE, &ctor_fd))
23276
2
            goto fail;
23277
11.1k
    }
23278
    /* patch the constant pool index for the constructor */
23279
11.1k
    put_u32(fd->byte_code.buf + ctor_cpool_offset, ctor_fd->parent_cpool_idx);
23280
23281
    /* store the class source code in the constructor. */
23282
11.1k
    if (!(fd->js_mode & JS_MODE_STRIP)) {
23283
10.3k
        js_free(ctx, ctor_fd->source);
23284
10.3k
        ctor_fd->source_len = s->buf_ptr - class_start_ptr;
23285
10.3k
        ctor_fd->source = js_strndup(ctx, (const char *)class_start_ptr,
23286
10.3k
                                     ctor_fd->source_len);
23287
10.3k
        if (!ctor_fd->source)
23288
0
            goto fail;
23289
10.3k
    }
23290
23291
    /* consume the '}' */
23292
11.1k
    if (next_token(s))
23293
0
        goto fail;
23294
23295
    /* store the function to initialize the fields to that it can be
23296
       referenced by the constructor */
23297
11.1k
    {
23298
11.1k
        ClassFieldsDef *cf = &class_fields[0];
23299
11.1k
        int var_idx;
23300
        
23301
11.1k
        var_idx = define_var(s, fd, JS_ATOM_class_fields_init,
23302
11.1k
                             JS_VAR_DEF_CONST);
23303
11.1k
        if (var_idx < 0)
23304
0
            goto fail;
23305
11.1k
        if (cf->fields_init_fd) {
23306
10.2k
            emit_class_init_end(s, cf);
23307
10.2k
        } else {
23308
895
            emit_op(s, OP_undefined);
23309
895
        }
23310
11.1k
        emit_op(s, OP_scope_put_var_init);
23311
11.1k
        emit_atom(s, JS_ATOM_class_fields_init);
23312
11.1k
        emit_u16(s, s->cur_func->scope_level);
23313
11.1k
    }
23314
23315
    /* drop the prototype */
23316
0
    emit_op(s, OP_drop);
23317
23318
    /* initialize the static fields */
23319
11.1k
    if (class_fields[1].fields_init_fd != NULL) {
23320
0
        ClassFieldsDef *cf = &class_fields[1];
23321
0
        emit_op(s, OP_dup);
23322
0
        emit_class_init_end(s, cf);
23323
0
        emit_op(s, OP_call_method);
23324
0
        emit_u16(s, 0);
23325
0
        emit_op(s, OP_drop);
23326
0
    }
23327
    
23328
11.1k
    if (class_name != JS_ATOM_NULL) {
23329
        /* store the class name in the scoped class name variable (it
23330
           is independent from the class statement variable
23331
           definition) */
23332
9.45k
        emit_op(s, OP_dup);
23333
9.45k
        emit_op(s, OP_scope_put_var_init);
23334
9.45k
        emit_atom(s, class_name);
23335
9.45k
        emit_u16(s, fd->scope_level);
23336
9.45k
    }
23337
11.1k
    pop_scope(s);
23338
11.1k
    pop_scope(s);
23339
23340
    /* the class statements have a block level scope */
23341
11.1k
    if (class_var_name != JS_ATOM_NULL) {
23342
29
        if (define_var(s, fd, class_var_name, JS_VAR_DEF_LET) < 0)
23343
0
            goto fail;
23344
29
        emit_op(s, OP_scope_put_var_init);
23345
29
        emit_atom(s, class_var_name);
23346
29
        emit_u16(s, fd->scope_level);
23347
11.1k
    } else {
23348
11.1k
        if (class_name == JS_ATOM_NULL) {
23349
            /* cannot use OP_set_name because the name of the class
23350
               must be defined before the static initializers are
23351
               executed */
23352
1.68k
            emit_op(s, OP_set_class_name);
23353
1.68k
            emit_u32(s, fd->last_opcode_pos + 1 - define_class_offset);
23354
1.68k
        }
23355
11.1k
    }
23356
23357
11.1k
    if (export_flag != JS_PARSE_EXPORT_NONE) {
23358
0
        if (!add_export_entry(s, fd->module,
23359
0
                              class_var_name,
23360
0
                              export_flag == JS_PARSE_EXPORT_NAMED ? class_var_name : JS_ATOM_default,
23361
0
                              JS_EXPORT_TYPE_LOCAL))
23362
0
            goto fail;
23363
0
    }
23364
23365
11.1k
    JS_FreeAtom(ctx, class_name);
23366
11.1k
    JS_FreeAtom(ctx, class_var_name);
23367
11.1k
    fd->js_mode = saved_js_mode;
23368
11.1k
    return 0;
23369
223
 fail:
23370
223
    JS_FreeAtom(ctx, name);
23371
223
    JS_FreeAtom(ctx, class_name);
23372
223
    JS_FreeAtom(ctx, class_var_name);
23373
223
    fd->js_mode = saved_js_mode;
23374
223
    return -1;
23375
11.1k
}
23376
23377
static __exception int js_parse_array_literal(JSParseState *s)
23378
4.91k
{
23379
4.91k
    uint32_t idx;
23380
4.91k
    BOOL need_length;
23381
23382
4.91k
    if (next_token(s))
23383
1
        return -1;
23384
    /* small regular arrays are created on the stack */
23385
4.91k
    idx = 0;
23386
7.62k
    while (s->token.val != ']' && idx < 32) {
23387
4.66k
        if (s->token.val == ',' || s->token.val == TOK_ELLIPSIS)
23388
1.62k
            break;
23389
3.03k
        if (js_parse_assign_expr(s))
23390
317
            return -1;
23391
2.71k
        idx++;
23392
        /* accept trailing comma */
23393
2.71k
        if (s->token.val == ',') {
23394
1.76k
            if (next_token(s))
23395
0
                return -1;
23396
1.76k
        } else
23397
952
        if (s->token.val != ']')
23398
2
            goto done;
23399
2.71k
    }
23400
4.59k
    emit_op(s, OP_array_from);
23401
4.59k
    emit_u16(s, idx);
23402
23403
    /* larger arrays and holes are handled with explicit indices */
23404
4.59k
    need_length = FALSE;
23405
13.9k
    while (s->token.val != ']' && idx < 0x7fffffff) {
23406
9.66k
        if (s->token.val == TOK_ELLIPSIS)
23407
242
            break;
23408
9.42k
        need_length = TRUE;
23409
9.42k
        if (s->token.val != ',') {
23410
8.03k
            if (js_parse_assign_expr(s))
23411
57
                return -1;
23412
7.97k
            emit_op(s, OP_define_field);
23413
7.97k
            emit_u32(s, __JS_AtomFromUInt32(idx));
23414
7.97k
            need_length = FALSE;
23415
7.97k
        }
23416
9.36k
        idx++;
23417
        /* accept trailing comma */
23418
9.36k
        if (s->token.val == ',') {
23419
8.15k
            if (next_token(s))
23420
0
                return -1;
23421
8.15k
        }
23422
9.36k
    }
23423
4.53k
    if (s->token.val == ']') {
23424
4.29k
        if (need_length) {
23425
            /* Set the length: Cannot use OP_define_field because
23426
               length is not configurable */
23427
1.32k
            emit_op(s, OP_dup);
23428
1.32k
            emit_op(s, OP_push_i32);
23429
1.32k
            emit_u32(s, idx);
23430
1.32k
            emit_op(s, OP_put_field);
23431
1.32k
            emit_atom(s, JS_ATOM_length);
23432
1.32k
        }
23433
4.29k
        goto done;
23434
4.29k
    }
23435
23436
    /* huge arrays and spread elements require a dynamic index on the stack */
23437
242
    emit_op(s, OP_push_i32);
23438
242
    emit_u32(s, idx);
23439
23440
    /* stack has array, index */
23441
286
    while (s->token.val != ']') {
23442
273
        if (s->token.val == TOK_ELLIPSIS) {
23443
242
            if (next_token(s))
23444
0
                return -1;
23445
242
            if (js_parse_assign_expr(s))
23446
0
                return -1;
23447
242
#if 1
23448
242
            emit_op(s, OP_append);
23449
#else
23450
            int label_next, label_done;
23451
            label_next = new_label(s);
23452
            label_done = new_label(s);
23453
            /* enumerate object */
23454
            emit_op(s, OP_for_of_start);
23455
            emit_op(s, OP_rot5l);
23456
            emit_op(s, OP_rot5l);
23457
            emit_label(s, label_next);
23458
            /* on stack: enum_rec array idx */
23459
            emit_op(s, OP_for_of_next);
23460
            emit_u8(s, 2);
23461
            emit_goto(s, OP_if_true, label_done);
23462
            /* append element */
23463
            /* enum_rec array idx val -> enum_rec array new_idx */
23464
            emit_op(s, OP_define_array_el);
23465
            emit_op(s, OP_inc);
23466
            emit_goto(s, OP_goto, label_next);
23467
            emit_label(s, label_done);
23468
            /* close enumeration */
23469
            emit_op(s, OP_drop); /* drop undef val */
23470
            emit_op(s, OP_nip1); /* drop enum_rec */
23471
            emit_op(s, OP_nip1);
23472
            emit_op(s, OP_nip1);
23473
#endif
23474
242
        } else {
23475
31
            need_length = TRUE;
23476
31
            if (s->token.val != ',') {
23477
15
                if (js_parse_assign_expr(s))
23478
0
                    return -1;
23479
                /* a idx val */
23480
15
                emit_op(s, OP_define_array_el);
23481
15
                need_length = FALSE;
23482
15
            }
23483
31
            emit_op(s, OP_inc);
23484
31
        }
23485
273
        if (s->token.val != ',')
23486
229
            break;
23487
44
        if (next_token(s))
23488
0
            return -1;
23489
44
    }
23490
242
    if (need_length) {
23491
        /* Set the length: cannot use OP_define_field because
23492
           length is not configurable */
23493
15
        emit_op(s, OP_dup1);    /* array length - array array length */
23494
15
        emit_op(s, OP_put_field);
23495
15
        emit_atom(s, JS_ATOM_length);
23496
227
    } else {
23497
227
        emit_op(s, OP_drop);    /* array length - array */
23498
227
    }
23499
4.53k
done:
23500
4.53k
    return js_parse_expect(s, ']');
23501
242
}
23502
23503
/* XXX: remove */
23504
static BOOL has_with_scope(JSFunctionDef *s, int scope_level)
23505
13.9k
{
23506
    /* check if scope chain contains a with statement */
23507
42.2k
    while (s) {
23508
31.1k
        int scope_idx = s->scopes[scope_level].first;
23509
44.7k
        while (scope_idx >= 0) {
23510
16.4k
            JSVarDef *vd = &s->vars[scope_idx];
23511
23512
16.4k
            if (vd->var_name == JS_ATOM__with_)
23513
2.90k
                return TRUE;
23514
13.5k
            scope_idx = vd->scope_next;
23515
13.5k
        }
23516
        /* check parent scopes */
23517
28.2k
        scope_level = s->parent_scope_level;
23518
28.2k
        s = s->parent;
23519
28.2k
    }
23520
11.0k
    return FALSE;
23521
13.9k
}
23522
23523
static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
23524
                                  JSAtom *pname, int *plabel, int *pdepth, BOOL keep,
23525
                                  int tok)
23526
324k
{
23527
324k
    JSFunctionDef *fd;
23528
324k
    int opcode, scope, label, depth;
23529
324k
    JSAtom name;
23530
23531
    /* we check the last opcode to get the lvalue type */
23532
324k
    fd = s->cur_func;
23533
324k
    scope = 0;
23534
324k
    name = JS_ATOM_NULL;
23535
324k
    label = -1;
23536
324k
    depth = 0;
23537
324k
    switch(opcode = get_prev_opcode(fd)) {
23538
321k
    case OP_scope_get_var:
23539
321k
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
23540
321k
        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
23541
321k
        if ((name == JS_ATOM_arguments || name == JS_ATOM_eval) &&
23542
321k
            (fd->js_mode & JS_MODE_STRICT)) {
23543
0
            return js_parse_error(s, "invalid lvalue in strict mode");
23544
0
        }
23545
321k
        if (name == JS_ATOM_this || name == JS_ATOM_new_target)
23546
0
            goto invalid_lvalue;
23547
321k
        depth = 2;  /* will generate OP_get_ref_value */
23548
321k
        break;
23549
2.75k
    case OP_get_field:
23550
2.75k
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
23551
2.75k
        depth = 1;
23552
2.75k
        break;
23553
22
    case OP_scope_get_private_field:
23554
22
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
23555
22
        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
23556
22
        depth = 1;
23557
22
        break;
23558
326
    case OP_get_array_el:
23559
326
        depth = 2;
23560
326
        break;
23561
0
    case OP_get_super_value:
23562
0
        depth = 3;
23563
0
        break;
23564
15
    default:
23565
15
    invalid_lvalue:
23566
15
        if (tok == TOK_FOR) {
23567
0
            return js_parse_error(s, "invalid for in/of left hand-side");
23568
15
        } else if (tok == TOK_INC || tok == TOK_DEC) {
23569
0
            return js_parse_error(s, "invalid increment/decrement operand");
23570
15
        } else if (tok == '[' || tok == '{') {
23571
0
            return js_parse_error(s, "invalid destructuring target");
23572
15
        } else {
23573
15
            return js_parse_error(s, "invalid assignment left-hand side");
23574
15
        }
23575
324k
    }
23576
    /* remove the last opcode */
23577
324k
    fd->byte_code.size = fd->last_opcode_pos;
23578
324k
    fd->last_opcode_pos = -1;
23579
23580
324k
    if (keep) {
23581
        /* get the value but keep the object/fields on the stack */
23582
35.0k
        switch(opcode) {
23583
34.5k
        case OP_scope_get_var:
23584
34.5k
            label = new_label(s);
23585
34.5k
            emit_op(s, OP_scope_make_ref);
23586
34.5k
            emit_atom(s, name);
23587
34.5k
            emit_u32(s, label);
23588
34.5k
            emit_u16(s, scope);
23589
34.5k
            update_label(fd, label, 1);
23590
34.5k
            emit_op(s, OP_get_ref_value);
23591
34.5k
            opcode = OP_get_ref_value;
23592
34.5k
            break;
23593
362
        case OP_get_field:
23594
362
            emit_op(s, OP_get_field2);
23595
362
            emit_atom(s, name);
23596
362
            break;
23597
0
        case OP_scope_get_private_field:
23598
0
            emit_op(s, OP_scope_get_private_field2);
23599
0
            emit_atom(s, name);
23600
0
            emit_u16(s, scope);
23601
0
            break;
23602
132
        case OP_get_array_el:
23603
            /* XXX: replace by a single opcode ? */
23604
132
            emit_op(s, OP_to_propkey2);
23605
132
            emit_op(s, OP_dup2);
23606
132
            emit_op(s, OP_get_array_el);
23607
132
            break;
23608
0
        case OP_get_super_value:
23609
0
            emit_op(s, OP_to_propkey);
23610
0
            emit_op(s, OP_dup3);
23611
0
            emit_op(s, OP_get_super_value);
23612
0
            break;
23613
0
        default:
23614
0
            abort();
23615
35.0k
        }
23616
289k
    } else {
23617
289k
        switch(opcode) {
23618
286k
        case OP_scope_get_var:
23619
286k
            label = new_label(s);
23620
286k
            emit_op(s, OP_scope_make_ref);
23621
286k
            emit_atom(s, name);
23622
286k
            emit_u32(s, label);
23623
286k
            emit_u16(s, scope);
23624
286k
            update_label(fd, label, 1);
23625
286k
            opcode = OP_get_ref_value;
23626
286k
            break;
23627
194
        case OP_get_array_el:
23628
194
            emit_op(s, OP_to_propkey2);
23629
194
            break;
23630
0
        case OP_get_super_value:
23631
0
            emit_op(s, OP_to_propkey);
23632
0
            break;
23633
289k
        }
23634
289k
    }
23635
23636
324k
    *popcode = opcode;
23637
324k
    *pscope = scope;
23638
    /* name has refcount for OP_get_field and OP_get_ref_value,
23639
       and JS_ATOM_NULL for other opcodes */
23640
324k
    *pname = name;
23641
324k
    *plabel = label;
23642
324k
    if (pdepth)
23643
36.6k
        *pdepth = depth;
23644
324k
    return 0;
23645
324k
}
23646
23647
typedef enum {
23648
    PUT_LVALUE_NOKEEP, /* [depth] v -> */
23649
    PUT_LVALUE_NOKEEP_DEPTH, /* [depth] v -> , keep depth (currently
23650
                                just disable optimizations) */
23651
    PUT_LVALUE_KEEP_TOP,  /* [depth] v -> v */
23652
    PUT_LVALUE_KEEP_SECOND, /* [depth] v0 v -> v0 */
23653
    PUT_LVALUE_NOKEEP_BOTTOM, /* v [depth] -> */
23654
} PutLValueEnum;
23655
23656
/* name has a live reference. 'is_let' is only used with opcode =
23657
   OP_scope_get_var which is never generated by get_lvalue(). */
23658
static void put_lvalue(JSParseState *s, int opcode, int scope,
23659
                       JSAtom name, int label, PutLValueEnum special,
23660
                       BOOL is_let)
23661
328k
{
23662
328k
    switch(opcode) {
23663
2.74k
    case OP_get_field:
23664
2.76k
    case OP_scope_get_private_field:
23665
        /* depth = 1 */
23666
2.76k
        switch(special) {
23667
0
        case PUT_LVALUE_NOKEEP:
23668
452
        case PUT_LVALUE_NOKEEP_DEPTH:
23669
452
            break;
23670
2.08k
        case PUT_LVALUE_KEEP_TOP:
23671
2.08k
            emit_op(s, OP_insert2); /* obj v -> v obj v */
23672
2.08k
            break;
23673
230
        case PUT_LVALUE_KEEP_SECOND:
23674
230
            emit_op(s, OP_perm3); /* obj v0 v -> v0 obj v */
23675
230
            break;
23676
0
        case PUT_LVALUE_NOKEEP_BOTTOM:
23677
0
            emit_op(s, OP_swap);
23678
0
            break;
23679
0
        default:
23680
0
            abort();
23681
2.76k
        }
23682
2.76k
        break;
23683
2.76k
    case OP_get_array_el:
23684
320k
    case OP_get_ref_value:
23685
        /* depth = 2 */
23686
320k
        if (opcode == OP_get_ref_value) {
23687
320k
            JS_FreeAtom(s->ctx, name);
23688
320k
            emit_label(s, label);
23689
320k
        }
23690
320k
        switch(special) {
23691
9.03k
        case PUT_LVALUE_NOKEEP:
23692
9.03k
            emit_op(s, OP_nop); /* will trigger optimization */
23693
9.03k
            break;
23694
36.2k
        case PUT_LVALUE_NOKEEP_DEPTH:
23695
36.2k
            break;
23696
269k
        case PUT_LVALUE_KEEP_TOP:
23697
269k
            emit_op(s, OP_insert3); /* obj prop v -> v obj prop v */
23698
269k
            break;
23699
5.00k
        case PUT_LVALUE_KEEP_SECOND:
23700
5.00k
            emit_op(s, OP_perm4); /* obj prop v0 v -> v0 obj prop v */
23701
5.00k
            break;
23702
1.23k
        case PUT_LVALUE_NOKEEP_BOTTOM:
23703
1.23k
            emit_op(s, OP_rot3l);
23704
1.23k
            break;
23705
0
        default:
23706
0
            abort();
23707
320k
        }
23708
320k
        break;
23709
320k
    case OP_get_super_value:
23710
        /* depth = 3 */
23711
0
        switch(special) {
23712
0
        case PUT_LVALUE_NOKEEP:
23713
0
        case PUT_LVALUE_NOKEEP_DEPTH:
23714
0
            break;
23715
0
        case PUT_LVALUE_KEEP_TOP:
23716
0
            emit_op(s, OP_insert4); /* this obj prop v -> v this obj prop v */
23717
0
            break;
23718
0
        case PUT_LVALUE_KEEP_SECOND:
23719
0
            emit_op(s, OP_perm5); /* this obj prop v0 v -> v0 this obj prop v */
23720
0
            break;
23721
0
        case PUT_LVALUE_NOKEEP_BOTTOM:
23722
0
            emit_op(s, OP_rot4l);
23723
0
            break;
23724
0
        default:
23725
0
            abort();
23726
0
        }
23727
0
        break;
23728
5.06k
    default:
23729
5.06k
        break;
23730
328k
    }
23731
    
23732
328k
    switch(opcode) {
23733
5.06k
    case OP_scope_get_var:  /* val -- */
23734
5.06k
        assert(special == PUT_LVALUE_NOKEEP ||
23735
5.06k
               special == PUT_LVALUE_NOKEEP_DEPTH);
23736
5.06k
        emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var);
23737
5.06k
        emit_u32(s, name);  /* has refcount */
23738
5.06k
        emit_u16(s, scope);
23739
5.06k
        break;
23740
2.74k
    case OP_get_field:
23741
2.74k
        emit_op(s, OP_put_field);
23742
2.74k
        emit_u32(s, name);  /* name has refcount */
23743
2.74k
        break;
23744
22
    case OP_scope_get_private_field:
23745
22
        emit_op(s, OP_scope_put_private_field);
23746
22
        emit_u32(s, name);  /* name has refcount */
23747
22
        emit_u16(s, scope);
23748
22
        break;
23749
285
    case OP_get_array_el:
23750
285
        emit_op(s, OP_put_array_el);
23751
285
        break;
23752
320k
    case OP_get_ref_value:
23753
320k
        emit_op(s, OP_put_ref_value);
23754
320k
        break;
23755
0
    case OP_get_super_value:
23756
0
        emit_op(s, OP_put_super_value);
23757
0
        break;
23758
0
    default:
23759
0
        abort();
23760
328k
    }
23761
328k
}
23762
23763
static __exception int js_parse_expr_paren(JSParseState *s)
23764
16.9k
{
23765
16.9k
    if (js_parse_expect(s, '('))
23766
2
        return -1;
23767
16.9k
    if (js_parse_expr(s))
23768
432
        return -1;
23769
16.5k
    if (js_parse_expect(s, ')'))
23770
9
        return -1;
23771
16.5k
    return 0;
23772
16.5k
}
23773
23774
static int js_unsupported_keyword(JSParseState *s, JSAtom atom)
23775
0
{
23776
0
    char buf[ATOM_GET_STR_BUF_SIZE];
23777
0
    return js_parse_error(s, "unsupported keyword: %s",
23778
0
                          JS_AtomGetStr(s->ctx, buf, sizeof(buf), atom));
23779
0
}
23780
23781
static __exception int js_define_var(JSParseState *s, JSAtom name, int tok)
23782
17.9k
{
23783
17.9k
    JSFunctionDef *fd = s->cur_func;
23784
17.9k
    JSVarDefEnum var_def_type;
23785
    
23786
17.9k
    if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
23787
0
        return js_parse_error(s, "yield is a reserved identifier");
23788
0
    }
23789
17.9k
    if ((name == JS_ATOM_arguments || name == JS_ATOM_eval)
23790
17.9k
    &&  (fd->js_mode & JS_MODE_STRICT)) {
23791
0
        return js_parse_error(s, "invalid variable name in strict mode");
23792
0
    }
23793
17.9k
    if ((name == JS_ATOM_let || name == JS_ATOM_undefined)
23794
17.9k
    &&  (tok == TOK_LET || tok == TOK_CONST)) {
23795
0
        return js_parse_error(s, "invalid lexical variable name");
23796
0
    }
23797
17.9k
    switch(tok) {
23798
6.10k
    case TOK_LET:
23799
6.10k
        var_def_type = JS_VAR_DEF_LET;
23800
6.10k
        break;
23801
0
    case TOK_CONST:
23802
0
        var_def_type = JS_VAR_DEF_CONST;
23803
0
        break;
23804
11.8k
    case TOK_VAR:
23805
11.8k
        var_def_type = JS_VAR_DEF_VAR;
23806
11.8k
        break;
23807
0
    case TOK_CATCH:
23808
0
        var_def_type = JS_VAR_DEF_CATCH;
23809
0
        break;
23810
0
    default:
23811
0
        abort();
23812
17.9k
    }
23813
17.9k
    if (define_var(s, fd, name, var_def_type) < 0)
23814
0
        return -1;
23815
17.9k
    return 0;
23816
17.9k
}
23817
23818
static void js_emit_spread_code(JSParseState *s, int depth)
23819
1.35k
{
23820
1.35k
    int label_rest_next, label_rest_done;
23821
23822
    /* XXX: could check if enum object is an actual array and optimize
23823
       slice extraction. enumeration record and target array are in a
23824
       different order from OP_append case. */
23825
    /* enum_rec xxx -- enum_rec xxx array 0 */
23826
1.35k
    emit_op(s, OP_array_from);
23827
1.35k
    emit_u16(s, 0);
23828
1.35k
    emit_op(s, OP_push_i32);
23829
1.35k
    emit_u32(s, 0);
23830
1.35k
    emit_label(s, label_rest_next = new_label(s));
23831
1.35k
    emit_op(s, OP_for_of_next);
23832
1.35k
    emit_u8(s, 2 + depth);
23833
1.35k
    label_rest_done = emit_goto(s, OP_if_true, -1);
23834
    /* array idx val -- array idx */
23835
1.35k
    emit_op(s, OP_define_array_el);
23836
1.35k
    emit_op(s, OP_inc);
23837
1.35k
    emit_goto(s, OP_goto, label_rest_next);
23838
1.35k
    emit_label(s, label_rest_done);
23839
    /* enum_rec xxx array idx undef -- enum_rec xxx array */
23840
1.35k
    emit_op(s, OP_drop);
23841
1.35k
    emit_op(s, OP_drop);
23842
1.35k
}
23843
23844
static int js_parse_check_duplicate_parameter(JSParseState *s, JSAtom name)
23845
5.12k
{
23846
    /* Check for duplicate parameter names */
23847
5.12k
    JSFunctionDef *fd = s->cur_func;
23848
5.12k
    int i;
23849
17.8k
    for (i = 0; i < fd->arg_count; i++) {
23850
12.7k
        if (fd->args[i].var_name == name)
23851
0
            goto duplicate;
23852
12.7k
    }
23853
20.9k
    for (i = 0; i < fd->var_count; i++) {
23854
15.8k
        if (fd->vars[i].var_name == name)
23855
1
            goto duplicate;
23856
15.8k
    }
23857
5.12k
    return 0;
23858
23859
1
duplicate:
23860
1
    return js_parse_error(s, "duplicate parameter names not allowed in this context");
23861
5.12k
}
23862
23863
static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg)
23864
4.57k
{
23865
4.57k
    JSAtom name;
23866
23867
4.57k
    if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
23868
4.57k
    ||  ((s->cur_func->js_mode & JS_MODE_STRICT) &&
23869
4.57k
         (s->token.u.ident.atom == JS_ATOM_eval || s->token.u.ident.atom == JS_ATOM_arguments))) {
23870
1
        js_parse_error(s, "invalid destructuring target");
23871
1
        return JS_ATOM_NULL;
23872
1
    }
23873
4.57k
    name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
23874
4.57k
    if (is_arg && js_parse_check_duplicate_parameter(s, name))
23875
0
        goto fail;
23876
4.57k
    if (next_token(s))
23877
0
        goto fail;
23878
23879
4.57k
    return name;
23880
0
fail:
23881
0
    JS_FreeAtom(s->ctx, name);
23882
0
    return JS_ATOM_NULL;
23883
4.57k
}
23884
23885
/* Return -1 if error, 0 if no initializer, 1 if an initializer is
23886
   present at the top level. */
23887
static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
23888
                                        int hasval, int has_ellipsis,
23889
                                        BOOL allow_initializer)
23890
34.4k
{
23891
34.4k
    int label_parse, label_assign, label_done, label_lvalue, depth_lvalue;
23892
34.4k
    int start_addr, assign_addr;
23893
34.4k
    JSAtom prop_name, var_name;
23894
34.4k
    int opcode, scope, tok1, skip_bits;
23895
34.4k
    BOOL has_initializer;
23896
    
23897
34.4k
    if (has_ellipsis < 0) {
23898
        /* pre-parse destructuration target for spread detection */
23899
1.91k
        js_parse_skip_parens_token(s, &skip_bits, FALSE);
23900
1.91k
        has_ellipsis = skip_bits & SKIP_HAS_ELLIPSIS;
23901
1.91k
    }
23902
23903
34.4k
    label_parse = new_label(s);
23904
34.4k
    label_assign = new_label(s);
23905
23906
34.4k
    start_addr = s->cur_func->byte_code.size;
23907
34.4k
    if (hasval) {
23908
        /* consume value from the stack */
23909
3.06k
        emit_op(s, OP_dup);
23910
3.06k
        emit_op(s, OP_undefined);
23911
3.06k
        emit_op(s, OP_strict_eq);
23912
3.06k
        emit_goto(s, OP_if_true, label_parse);
23913
3.06k
        emit_label(s, label_assign);
23914
31.3k
    } else {
23915
31.3k
        emit_goto(s, OP_goto, label_parse);
23916
31.3k
        emit_label(s, label_assign);
23917
        /* leave value on the stack */
23918
31.3k
        emit_op(s, OP_dup);
23919
31.3k
    }
23920
34.4k
    assign_addr = s->cur_func->byte_code.size;
23921
34.4k
    if (s->token.val == '{') {
23922
7.22k
        if (next_token(s))
23923
0
            return -1;
23924
        /* throw an exception if the value cannot be converted to an object */
23925
7.22k
        emit_op(s, OP_to_object);
23926
7.22k
        if (has_ellipsis) {
23927
            /* add excludeList on stack just below src object */
23928
2.18k
            emit_op(s, OP_object);
23929
2.18k
            emit_op(s, OP_swap);
23930
2.18k
        }
23931
8.26k
        while (s->token.val != '}') {
23932
8.07k
            int prop_type;
23933
8.07k
            if (s->token.val == TOK_ELLIPSIS) {
23934
2.18k
                if (!has_ellipsis) {
23935
0
                    JS_ThrowInternalError(s->ctx, "unexpected ellipsis token");
23936
0
                    return -1;
23937
0
                }
23938
2.18k
                if (next_token(s))
23939
0
                    return -1;
23940
2.18k
                if (tok) {
23941
10
                    var_name = js_parse_destructuring_var(s, tok, is_arg);
23942
10
                    if (var_name == JS_ATOM_NULL)
23943
0
                        return -1;
23944
10
                    opcode = OP_scope_get_var;
23945
10
                    scope = s->cur_func->scope_level;
23946
10
                    label_lvalue = -1;
23947
10
                    depth_lvalue = 0;
23948
2.17k
                } else {
23949
2.17k
                    if (js_parse_left_hand_side_expr(s))
23950
0
                        return -1;
23951
23952
2.17k
                    if (get_lvalue(s, &opcode, &scope, &var_name,
23953
2.17k
                                   &label_lvalue, &depth_lvalue, FALSE, '{'))
23954
0
                        return -1;
23955
2.17k
                }
23956
2.18k
                if (s->token.val != '}') {
23957
0
                    js_parse_error(s, "assignment rest property must be last");
23958
0
                    goto var_error;
23959
0
                }
23960
2.18k
                emit_op(s, OP_object);  /* target */
23961
2.18k
                emit_op(s, OP_copy_data_properties);
23962
2.18k
                emit_u8(s, 0 | ((depth_lvalue + 1) << 2) | ((depth_lvalue + 2) << 5));
23963
2.18k
                goto set_val;
23964
2.18k
            }
23965
5.89k
            prop_type = js_parse_property_name(s, &prop_name, FALSE, TRUE, FALSE);
23966
5.89k
            if (prop_type < 0)
23967
0
                return -1;
23968
5.89k
            var_name = JS_ATOM_NULL;
23969
5.89k
            opcode = OP_scope_get_var;
23970
5.89k
            scope = s->cur_func->scope_level;
23971
5.89k
            label_lvalue = -1;
23972
5.89k
            depth_lvalue = 0;
23973
5.89k
            if (prop_type == PROP_TYPE_IDENT) {
23974
1.77k
                if (next_token(s))
23975
0
                    goto prop_error;
23976
1.77k
                if ((s->token.val == '[' || s->token.val == '{')
23977
1.77k
                    &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
23978
0
                         tok1 == '=' || tok1 == '}')) {
23979
0
                    if (prop_name == JS_ATOM_NULL) {
23980
                        /* computed property name on stack */
23981
0
                        if (has_ellipsis) {
23982
                            /* define the property in excludeList */
23983
0
                            emit_op(s, OP_to_propkey); /* avoid calling ToString twice */
23984
0
                            emit_op(s, OP_perm3); /* TOS: src excludeList prop */
23985
0
                            emit_op(s, OP_null); /* TOS: src excludeList prop null */
23986
0
                            emit_op(s, OP_define_array_el); /* TOS: src excludeList prop */
23987
0
                            emit_op(s, OP_perm3); /* TOS: excludeList src prop */
23988
0
                        }
23989
                        /* get the computed property from the source object */
23990
0
                        emit_op(s, OP_get_array_el2);
23991
0
                    } else {
23992
                        /* named property */
23993
0
                        if (has_ellipsis) {
23994
                            /* define the property in excludeList */
23995
0
                            emit_op(s, OP_swap); /* TOS: src excludeList */
23996
0
                            emit_op(s, OP_null); /* TOS: src excludeList null */
23997
0
                            emit_op(s, OP_define_field); /* TOS: src excludeList */
23998
0
                            emit_atom(s, prop_name);
23999
0
                            emit_op(s, OP_swap); /* TOS: excludeList src */
24000
0
                        }
24001
                        /* get the named property from the source object */
24002
0
                        emit_op(s, OP_get_field2);
24003
0
                        emit_u32(s, prop_name);
24004
0
                    }
24005
0
                    if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE) < 0)
24006
0
                        return -1;
24007
0
                    if (s->token.val == '}')
24008
0
                        break;
24009
                    /* accept a trailing comma before the '}' */
24010
0
                    if (js_parse_expect(s, ','))
24011
0
                        return -1;
24012
0
                    continue;
24013
0
                }
24014
1.77k
                if (prop_name == JS_ATOM_NULL) {
24015
0
                    emit_op(s, OP_to_propkey2);
24016
0
                    if (has_ellipsis) {
24017
                        /* define the property in excludeList */
24018
0
                        emit_op(s, OP_perm3);
24019
0
                        emit_op(s, OP_null);
24020
0
                        emit_op(s, OP_define_array_el);
24021
0
                        emit_op(s, OP_perm3);
24022
0
                    }
24023
                    /* source prop -- source source prop */
24024
0
                    emit_op(s, OP_dup1);
24025
1.77k
                } else {
24026
1.77k
                    if (has_ellipsis) {
24027
                        /* define the property in excludeList */
24028
3
                        emit_op(s, OP_swap);
24029
3
                        emit_op(s, OP_null);
24030
3
                        emit_op(s, OP_define_field);
24031
3
                        emit_atom(s, prop_name);
24032
3
                        emit_op(s, OP_swap);
24033
3
                    }
24034
                    /* source -- source source */
24035
1.77k
                    emit_op(s, OP_dup);
24036
1.77k
                }
24037
1.77k
                if (tok) {
24038
379
                    var_name = js_parse_destructuring_var(s, tok, is_arg);
24039
379
                    if (var_name == JS_ATOM_NULL)
24040
0
                        goto prop_error;
24041
1.40k
                } else {
24042
1.40k
                    if (js_parse_left_hand_side_expr(s))
24043
0
                        goto prop_error;
24044
5.01k
                lvalue:
24045
5.01k
                    if (get_lvalue(s, &opcode, &scope, &var_name,
24046
5.01k
                                   &label_lvalue, &depth_lvalue, FALSE, '{'))
24047
0
                        goto prop_error;
24048
                    /* swap ref and lvalue object if any */
24049
5.01k
                    if (prop_name == JS_ATOM_NULL) {
24050
0
                        switch(depth_lvalue) {
24051
0
                        case 1:
24052
                            /* source prop x -> x source prop */
24053
0
                            emit_op(s, OP_rot3r);
24054
0
                            break;
24055
0
                        case 2:
24056
                            /* source prop x y -> x y source prop */
24057
0
                            emit_op(s, OP_swap2);   /* t p2 s p1 */
24058
0
                            break;
24059
0
                        case 3:
24060
                            /* source prop x y z -> x y z source prop */
24061
0
                            emit_op(s, OP_rot5l);
24062
0
                            emit_op(s, OP_rot5l);
24063
0
                            break;
24064
0
                        }
24065
5.01k
                    } else {
24066
5.01k
                        switch(depth_lvalue) {
24067
452
                        case 1:
24068
                            /* source x -> x source */
24069
452
                            emit_op(s, OP_swap);
24070
452
                            break;
24071
4.56k
                        case 2:
24072
                            /* source x y -> x y source */
24073
4.56k
                            emit_op(s, OP_rot3l);
24074
4.56k
                            break;
24075
0
                        case 3:
24076
                            /* source x y z -> x y z source */
24077
0
                            emit_op(s, OP_rot4l);
24078
0
                            break;
24079
5.01k
                        }
24080
5.01k
                    }
24081
5.01k
                }
24082
5.39k
                if (prop_name == JS_ATOM_NULL) {
24083
                    /* computed property name on stack */
24084
                    /* XXX: should have OP_get_array_el2x with depth */
24085
                    /* source prop -- val */
24086
0
                    emit_op(s, OP_get_array_el);
24087
5.39k
                } else {
24088
                    /* named property */
24089
                    /* XXX: should have OP_get_field2x with depth */
24090
                    /* source -- val */
24091
5.39k
                    emit_op(s, OP_get_field);
24092
5.39k
                    emit_u32(s, prop_name);
24093
5.39k
                }
24094
5.39k
            } else {
24095
                /* prop_type = PROP_TYPE_VAR, cannot be a computed property */
24096
4.11k
                if (is_arg && js_parse_check_duplicate_parameter(s, prop_name))
24097
1
                    goto prop_error;
24098
4.11k
                if ((s->cur_func->js_mode & JS_MODE_STRICT) &&
24099
4.11k
                    (prop_name == JS_ATOM_eval || prop_name == JS_ATOM_arguments)) {
24100
1
                    js_parse_error(s, "invalid destructuring target");
24101
1
                    goto prop_error;
24102
1
                }
24103
4.11k
                if (has_ellipsis) {
24104
                    /* define the property in excludeList */
24105
93
                    emit_op(s, OP_swap);
24106
93
                    emit_op(s, OP_null);
24107
93
                    emit_op(s, OP_define_field);
24108
93
                    emit_atom(s, prop_name);
24109
93
                    emit_op(s, OP_swap);
24110
93
                }
24111
4.11k
                if (!tok || tok == TOK_VAR) {
24112
                    /* generate reference */
24113
                    /* source -- source source */
24114
3.61k
                    emit_op(s, OP_dup);
24115
3.61k
                    emit_op(s, OP_scope_get_var);
24116
3.61k
                    emit_atom(s, prop_name);
24117
3.61k
                    emit_u16(s, s->cur_func->scope_level);
24118
3.61k
                    goto lvalue;
24119
3.61k
                }
24120
494
                var_name = JS_DupAtom(s->ctx, prop_name);
24121
                /* source -- source val */
24122
494
                emit_op(s, OP_get_field2);
24123
494
                emit_u32(s, prop_name);
24124
494
            }
24125
8.07k
        set_val:
24126
8.07k
            if (tok) {
24127
1.75k
                if (js_define_var(s, var_name, tok))
24128
0
                    goto var_error;
24129
1.75k
                scope = s->cur_func->scope_level;
24130
1.75k
            }
24131
8.07k
            if (s->token.val == '=') {  /* handle optional default value */
24132
2.72k
                int label_hasval;
24133
2.72k
                emit_op(s, OP_dup);
24134
2.72k
                emit_op(s, OP_undefined);
24135
2.72k
                emit_op(s, OP_strict_eq);
24136
2.72k
                label_hasval = emit_goto(s, OP_if_false, -1);
24137
2.72k
                if (next_token(s))
24138
0
                    goto var_error;
24139
2.72k
                emit_op(s, OP_drop);
24140
2.72k
                if (js_parse_assign_expr(s))
24141
0
                    goto var_error;
24142
2.72k
                if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
24143
2.72k
                    set_object_name(s, var_name);
24144
2.72k
                emit_label(s, label_hasval);
24145
2.72k
            }
24146
            /* store value into lvalue object */
24147
8.07k
            put_lvalue(s, opcode, scope, var_name, label_lvalue,
24148
8.07k
                       PUT_LVALUE_NOKEEP_DEPTH,
24149
8.07k
                       (tok == TOK_CONST || tok == TOK_LET));
24150
8.07k
            if (s->token.val == '}')
24151
7.03k
                break;
24152
            /* accept a trailing comma before the '}' */
24153
1.03k
            if (js_parse_expect(s, ','))
24154
1
                return -1;
24155
1.03k
        }
24156
        /* drop the source object */
24157
7.22k
        emit_op(s, OP_drop);
24158
7.22k
        if (has_ellipsis) {
24159
2.18k
            emit_op(s, OP_drop); /* pop excludeList */
24160
2.18k
        }
24161
7.22k
        if (next_token(s))
24162
0
            return -1;
24163
27.1k
    } else if (s->token.val == '[') {
24164
27.1k
        BOOL has_spread;
24165
27.1k
        int enum_depth;
24166
27.1k
        BlockEnv block_env;
24167
24168
27.1k
        if (next_token(s))
24169
0
            return -1;
24170
        /* the block environment is only needed in generators in case
24171
           'yield' triggers a 'return' */
24172
27.1k
        push_break_entry(s->cur_func, &block_env,
24173
27.1k
                         JS_ATOM_NULL, -1, -1, 2);
24174
27.1k
        block_env.has_iterator = TRUE;
24175
27.1k
        emit_op(s, OP_for_of_start);
24176
27.1k
        has_spread = FALSE;
24177
31.6k
        while (s->token.val != ']') {
24178
            /* get the next value */
24179
14.5k
            if (s->token.val == TOK_ELLIPSIS) {
24180
1.35k
                if (next_token(s))
24181
0
                    return -1;
24182
1.35k
                if (s->token.val == ',' || s->token.val == ']')
24183
0
                    return js_parse_error(s, "missing binding pattern...");
24184
1.35k
                has_spread = TRUE;
24185
1.35k
            }
24186
14.5k
            if (s->token.val == ',') {
24187
                /* do nothing, skip the value, has_spread is false */
24188
1.19k
                emit_op(s, OP_for_of_next);
24189
1.19k
                emit_u8(s, 0);
24190
1.19k
                emit_op(s, OP_drop);
24191
1.19k
                emit_op(s, OP_drop);
24192
13.3k
            } else if ((s->token.val == '[' || s->token.val == '{')
24193
13.3k
                   &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
24194
879
                        tok1 == '=' || tok1 == ']')) {
24195
866
                if (has_spread) {
24196
768
                    if (tok1 == '=')
24197
0
                        return js_parse_error(s, "rest element cannot have a default value");
24198
768
                    js_emit_spread_code(s, 0);
24199
768
                } else {
24200
98
                    emit_op(s, OP_for_of_next);
24201
98
                    emit_u8(s, 0);
24202
98
                    emit_op(s, OP_drop);
24203
98
                }
24204
866
                if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
24205
61
                    return -1;
24206
12.4k
            } else {
24207
12.4k
                var_name = JS_ATOM_NULL;
24208
12.4k
                enum_depth = 0;
24209
12.4k
                if (tok) {
24210
4.18k
                    var_name = js_parse_destructuring_var(s, tok, is_arg);
24211
4.18k
                    if (var_name == JS_ATOM_NULL)
24212
1
                        goto var_error;
24213
4.18k
                    if (js_define_var(s, var_name, tok))
24214
0
                        goto var_error;
24215
4.18k
                    opcode = OP_scope_get_var;
24216
4.18k
                    scope = s->cur_func->scope_level;
24217
8.27k
                } else {
24218
8.27k
                    if (js_parse_left_hand_side_expr(s))
24219
1
                        return -1;
24220
8.27k
                    if (get_lvalue(s, &opcode, &scope, &var_name,
24221
8.27k
                                   &label_lvalue, &enum_depth, FALSE, '[')) {
24222
0
                        return -1;
24223
0
                    }
24224
8.27k
                }
24225
12.4k
                if (has_spread) {
24226
583
                    js_emit_spread_code(s, enum_depth);
24227
11.8k
                } else {
24228
11.8k
                    emit_op(s, OP_for_of_next);
24229
11.8k
                    emit_u8(s, enum_depth);
24230
11.8k
                    emit_op(s, OP_drop);
24231
11.8k
                }
24232
12.4k
                if (s->token.val == '=' && !has_spread) {
24233
                    /* handle optional default value */
24234
97
                    int label_hasval;
24235
97
                    emit_op(s, OP_dup);
24236
97
                    emit_op(s, OP_undefined);
24237
97
                    emit_op(s, OP_strict_eq);
24238
97
                    label_hasval = emit_goto(s, OP_if_false, -1);
24239
97
                    if (next_token(s))
24240
0
                        goto var_error;
24241
97
                    emit_op(s, OP_drop);
24242
97
                    if (js_parse_assign_expr(s))
24243
0
                        goto var_error;
24244
97
                    if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
24245
84
                        set_object_name(s, var_name);
24246
97
                    emit_label(s, label_hasval);
24247
97
                }
24248
                /* store value into lvalue object */
24249
12.4k
                put_lvalue(s, opcode, scope, var_name,
24250
12.4k
                           label_lvalue, PUT_LVALUE_NOKEEP_DEPTH,
24251
12.4k
                           (tok == TOK_CONST || tok == TOK_LET));
24252
12.4k
            }
24253
14.4k
            if (s->token.val == ']')
24254
10.0k
                break;
24255
4.46k
            if (has_spread)
24256
0
                return js_parse_error(s, "rest element must be the last one");
24257
            /* accept a trailing comma before the ']' */
24258
4.46k
            if (js_parse_expect(s, ','))
24259
3
                return -1;
24260
4.46k
        }
24261
        /* close iterator object:
24262
           if completed, enum_obj has been replaced by undefined */
24263
27.1k
        emit_op(s, OP_iterator_close);
24264
27.1k
        pop_break_entry(s->cur_func);
24265
27.1k
        if (next_token(s))
24266
0
            return -1;
24267
27.1k
    } else {
24268
0
        return js_parse_error(s, "invalid assignment syntax");
24269
0
    }
24270
34.3k
    if (s->token.val == '=' && allow_initializer) {
24271
32.9k
        label_done = emit_goto(s, OP_goto, -1);
24272
32.9k
        if (next_token(s))
24273
1
            return -1;
24274
32.9k
        emit_label(s, label_parse);
24275
32.9k
        if (hasval)
24276
1.60k
            emit_op(s, OP_drop);
24277
32.9k
        if (js_parse_assign_expr(s))
24278
277
            return -1;
24279
32.6k
        emit_goto(s, OP_goto, label_assign);
24280
32.6k
        emit_label(s, label_done);
24281
32.6k
        has_initializer = TRUE;
24282
32.6k
    } else {
24283
        /* normally hasval is true except if
24284
           js_parse_skip_parens_token() was wrong in the parsing */
24285
        //        assert(hasval);
24286
1.39k
        if (!hasval) {
24287
0
            js_parse_error(s, "too complicated destructuring expression");
24288
0
            return -1;
24289
0
        }
24290
        /* remove test and decrement label ref count */
24291
1.39k
        memset(s->cur_func->byte_code.buf + start_addr, OP_nop,
24292
1.39k
               assign_addr - start_addr);
24293
1.39k
        s->cur_func->label_slots[label_parse].ref_count--;
24294
1.39k
        has_initializer = FALSE;
24295
1.39k
    }
24296
34.0k
    return has_initializer;
24297
24298
2
 prop_error:
24299
2
    JS_FreeAtom(s->ctx, prop_name);
24300
3
 var_error:
24301
3
    JS_FreeAtom(s->ctx, var_name);
24302
3
    return -1;
24303
2
}
24304
24305
typedef enum FuncCallType {
24306
    FUNC_CALL_NORMAL,
24307
    FUNC_CALL_NEW,
24308
    FUNC_CALL_SUPER_CTOR,
24309
    FUNC_CALL_TEMPLATE,
24310
} FuncCallType;
24311
24312
static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
24313
                                int drop_count)
24314
609
{
24315
609
    int label_next, i;
24316
609
    if (*poptional_chaining_label < 0)
24317
255
        *poptional_chaining_label = new_label(s);
24318
   /* XXX: could be more efficient with a specific opcode */
24319
609
    emit_op(s, OP_dup);
24320
609
    emit_op(s, OP_is_undefined_or_null);
24321
609
    label_next = emit_goto(s, OP_if_false, -1);
24322
1.21k
    for(i = 0; i < drop_count; i++)
24323
610
        emit_op(s, OP_drop);
24324
609
    emit_op(s, OP_undefined);
24325
609
    emit_goto(s, OP_goto, *poptional_chaining_label);
24326
609
    emit_label(s, label_next);
24327
609
}
24328
24329
/* allowed parse_flags: PF_POSTFIX_CALL, PF_ARROW_FUNC */
24330
static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
24331
786k
{
24332
786k
    FuncCallType call_type;
24333
786k
    int optional_chaining_label;
24334
786k
    BOOL accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0;
24335
    
24336
786k
    call_type = FUNC_CALL_NORMAL;
24337
786k
    switch(s->token.val) {
24338
40.5k
    case TOK_NUMBER:
24339
40.5k
        {
24340
40.5k
            JSValue val;
24341
40.5k
            val = s->token.u.num.val;
24342
24343
40.5k
            if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
24344
28.2k
                emit_op(s, OP_push_i32);
24345
28.2k
                emit_u32(s, JS_VALUE_GET_INT(val));
24346
28.2k
            } else
24347
12.2k
#ifdef CONFIG_BIGNUM
24348
12.2k
            if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
24349
0
                slimb_t e;
24350
0
                int ret;
24351
24352
                /* need a runtime conversion */
24353
                /* XXX: could add a cache and/or do it once at
24354
                   the start of the function */
24355
0
                if (emit_push_const(s, val, 0) < 0)
24356
0
                    return -1;
24357
0
                e = s->token.u.num.exponent;
24358
0
                if (e == (int32_t)e) {
24359
0
                    emit_op(s, OP_push_i32);
24360
0
                    emit_u32(s, e);
24361
0
                } else {
24362
0
                    val = JS_NewBigInt64_1(s->ctx, e);
24363
0
                    if (JS_IsException(val))
24364
0
                        return -1;
24365
0
                    ret = emit_push_const(s, val, 0);
24366
0
                    JS_FreeValue(s->ctx, val);
24367
0
                    if (ret < 0)
24368
0
                        return -1;
24369
0
                }
24370
0
                emit_op(s, OP_mul_pow10);
24371
0
            } else
24372
12.2k
#endif
24373
12.2k
            {
24374
12.2k
                if (emit_push_const(s, val, 0) < 0)
24375
0
                    return -1;
24376
12.2k
            }
24377
40.5k
        }
24378
40.5k
        if (next_token(s))
24379
1
            return -1;
24380
40.5k
        break;
24381
40.5k
    case TOK_TEMPLATE:
24382
4.04k
        if (js_parse_template(s, 0, NULL))
24383
68
            return -1;
24384
3.97k
        break;
24385
7.67k
    case TOK_STRING:
24386
7.67k
        if (emit_push_const(s, s->token.u.str.str, 1))
24387
0
            return -1;
24388
7.67k
        if (next_token(s))
24389
1
            return -1;
24390
7.67k
        break;
24391
        
24392
7.67k
    case TOK_DIV_ASSIGN:
24393
307
        s->buf_ptr -= 2;
24394
307
        goto parse_regexp;
24395
7.21k
    case '/':
24396
7.21k
        s->buf_ptr--;
24397
7.52k
    parse_regexp:
24398
7.52k
        {
24399
7.52k
            JSValue str;
24400
7.52k
            int ret, backtrace_flags;
24401
7.52k
            if (!s->ctx->compile_regexp)
24402
0
                return js_parse_error(s, "RegExp are not supported");
24403
            /* the previous token is '/' or '/=', so no need to free */
24404
7.52k
            if (js_parse_regexp(s))
24405
6
                return -1;
24406
7.51k
            ret = emit_push_const(s, s->token.u.regexp.body, 0);
24407
7.51k
            str = s->ctx->compile_regexp(s->ctx, s->token.u.regexp.body,
24408
7.51k
                                         s->token.u.regexp.flags);
24409
7.51k
            if (JS_IsException(str)) {
24410
                /* add the line number info */
24411
78
                backtrace_flags = 0;
24412
78
                if (s->cur_func && s->cur_func->backtrace_barrier)
24413
0
                    backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
24414
78
                build_backtrace(s->ctx, s->ctx->rt->current_exception,
24415
78
                                s->filename, s->token.line_num,
24416
78
                                backtrace_flags);
24417
78
                return -1;
24418
78
            }
24419
7.44k
            ret = emit_push_const(s, str, 0);
24420
7.44k
            JS_FreeValue(s->ctx, str);
24421
7.44k
            if (ret)
24422
0
                return -1;
24423
            /* we use a specific opcode to be sure the correct
24424
               function is called (otherwise the bytecode would have
24425
               to be verified by the RegExp constructor) */
24426
7.44k
            emit_op(s, OP_regexp);
24427
7.44k
            if (next_token(s))
24428
2
                return -1;
24429
7.44k
        }
24430
7.43k
        break;
24431
7.43k
    case '(':
24432
5.32k
        if ((parse_flags & PF_ARROW_FUNC) &&
24433
5.32k
            js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
24434
3.94k
            if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
24435
3.94k
                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
24436
3.94k
                                       s->token.ptr, s->token.line_num))
24437
194
                return -1;
24438
3.94k
        } else {
24439
1.37k
            if (js_parse_expr_paren(s))
24440
435
                return -1;
24441
1.37k
        }
24442
4.69k
        break;
24443
4.69k
    case TOK_FUNCTION:
24444
720
        if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
24445
720
                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
24446
720
                                   s->token.ptr, s->token.line_num))
24447
30
            return -1;
24448
690
        break;
24449
11.3k
    case TOK_CLASS:
24450
11.3k
        if (js_parse_class(s, TRUE, JS_PARSE_EXPORT_NONE))
24451
221
            return -1;
24452
11.1k
        break;
24453
11.1k
    case TOK_NULL:
24454
524
        if (next_token(s))
24455
0
            return -1;
24456
524
        emit_op(s, OP_null);
24457
524
        break;
24458
952
    case TOK_THIS:
24459
952
        if (next_token(s))
24460
1
            return -1;
24461
951
        emit_op(s, OP_scope_get_var);
24462
951
        emit_atom(s, JS_ATOM_this);
24463
951
        emit_u16(s, 0);
24464
951
        break;
24465
0
    case TOK_FALSE:
24466
0
        if (next_token(s))
24467
0
            return -1;
24468
0
        emit_op(s, OP_push_false);
24469
0
        break;
24470
0
    case TOK_TRUE:
24471
0
        if (next_token(s))
24472
0
            return -1;
24473
0
        emit_op(s, OP_push_true);
24474
0
        break;
24475
667k
    case TOK_IDENT:
24476
667k
        {
24477
667k
            JSAtom name;
24478
667k
            if (s->token.u.ident.is_reserved) {
24479
0
                return js_parse_error_reserved_identifier(s);
24480
0
            }
24481
667k
            if ((parse_flags & PF_ARROW_FUNC) &&
24482
667k
                peek_token(s, TRUE) == TOK_ARROW) {
24483
5.72k
                if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
24484
5.72k
                                           JS_FUNC_NORMAL, JS_ATOM_NULL,
24485
5.72k
                                           s->token.ptr, s->token.line_num))
24486
106
                    return -1;
24487
662k
            } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
24488
662k
                       peek_token(s, TRUE) != '\n') {
24489
0
                const uint8_t *source_ptr;
24490
0
                int source_line_num;
24491
24492
0
                source_ptr = s->token.ptr;
24493
0
                source_line_num = s->token.line_num;
24494
0
                if (next_token(s))
24495
0
                    return -1;
24496
0
                if (s->token.val == TOK_FUNCTION) {
24497
0
                    if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
24498
0
                                               JS_FUNC_ASYNC, JS_ATOM_NULL,
24499
0
                                               source_ptr, source_line_num))
24500
0
                        return -1;
24501
0
                } else if ((parse_flags & PF_ARROW_FUNC) &&
24502
0
                           ((s->token.val == '(' &&
24503
0
                             js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||
24504
0
                            (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
24505
0
                             peek_token(s, TRUE) == TOK_ARROW))) {
24506
0
                    if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
24507
0
                                               JS_FUNC_ASYNC, JS_ATOM_NULL,
24508
0
                                               source_ptr, source_line_num))
24509
0
                        return -1;
24510
0
                } else {
24511
0
                    name = JS_DupAtom(s->ctx, JS_ATOM_async);
24512
0
                    goto do_get_var;
24513
0
                }
24514
662k
            } else {
24515
662k
                if (s->token.u.ident.atom == JS_ATOM_arguments &&
24516
662k
                    !s->cur_func->arguments_allowed) {
24517
0
                    js_parse_error(s, "'arguments' identifier is not allowed in class field initializer");
24518
0
                    return -1;
24519
0
                }
24520
662k
                name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
24521
662k
                if (next_token(s))  /* update line number before emitting code */
24522
33
                    return -1;
24523
662k
            do_get_var:
24524
662k
                emit_op(s, OP_scope_get_var);
24525
662k
                emit_u32(s, name);
24526
662k
                emit_u16(s, s->cur_func->scope_level);
24527
662k
            }
24528
667k
        }
24529
667k
        break;
24530
667k
    case '{':
24531
38.6k
    case '[':
24532
38.6k
        {
24533
38.6k
            int skip_bits;
24534
38.6k
            if (js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
24535
31.3k
                if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
24536
161
                    return -1;
24537
31.3k
            } else {
24538
7.28k
                if (s->token.val == '{') {
24539
2.37k
                    if (js_parse_object_literal(s))
24540
337
                        return -1;
24541
4.91k
                } else {
24542
4.91k
                    if (js_parse_array_literal(s))
24543
379
                        return -1;
24544
4.91k
                }
24545
7.28k
            }
24546
38.6k
        }
24547
37.7k
        break;
24548
37.7k
    case TOK_NEW:
24549
1.61k
        if (next_token(s))
24550
0
            return -1;
24551
1.61k
        if (s->token.val == '.') {
24552
0
            if (next_token(s))
24553
0
                return -1;
24554
0
            if (!token_is_pseudo_keyword(s, JS_ATOM_target))
24555
0
                return js_parse_error(s, "expecting target");
24556
0
            if (!s->cur_func->new_target_allowed)
24557
0
                return js_parse_error(s, "new.target only allowed within functions");
24558
0
            if (next_token(s))
24559
0
                return -1;
24560
0
            emit_op(s, OP_scope_get_var);
24561
0
            emit_atom(s, JS_ATOM_new_target);
24562
0
            emit_u16(s, 0);
24563
1.61k
        } else {
24564
1.61k
            if (js_parse_postfix_expr(s, 0))
24565
166
                return -1;
24566
1.44k
            accept_lparen = TRUE;
24567
1.44k
            if (s->token.val != '(') {
24568
                /* new operator on an object */
24569
1.37k
                emit_op(s, OP_dup);
24570
1.37k
                emit_op(s, OP_call_constructor);
24571
1.37k
                emit_u16(s, 0);
24572
1.37k
            } else {
24573
72
                call_type = FUNC_CALL_NEW;
24574
72
            }
24575
1.44k
        }
24576
1.44k
        break;
24577
1.44k
    case TOK_SUPER:
24578
0
        if (next_token(s))
24579
0
            return -1;
24580
0
        if (s->token.val == '(') {
24581
0
            if (!s->cur_func->super_call_allowed)
24582
0
                return js_parse_error(s, "super() is only valid in a derived class constructor");
24583
0
            call_type = FUNC_CALL_SUPER_CTOR;
24584
0
        } else if (s->token.val == '.' || s->token.val == '[') {
24585
0
            if (!s->cur_func->super_allowed)
24586
0
                return js_parse_error(s, "'super' is only valid in a method");
24587
0
            emit_op(s, OP_scope_get_var);
24588
0
            emit_atom(s, JS_ATOM_this);
24589
0
            emit_u16(s, 0);
24590
0
            emit_op(s, OP_scope_get_var);
24591
0
            emit_atom(s, JS_ATOM_home_object);
24592
0
            emit_u16(s, 0);
24593
0
            emit_op(s, OP_get_super);
24594
0
        } else {
24595
0
            return js_parse_error(s, "invalid use of 'super'");
24596
0
        }
24597
0
        break;
24598
19
    case TOK_IMPORT:
24599
19
        if (next_token(s))
24600
0
            return -1;
24601
19
        if (s->token.val == '.') {
24602
0
            if (next_token(s))
24603
0
                return -1;
24604
0
            if (!token_is_pseudo_keyword(s, JS_ATOM_meta))
24605
0
                return js_parse_error(s, "meta expected");
24606
0
            if (!s->is_module)
24607
0
                return js_parse_error(s, "import.meta only valid in module code");
24608
0
            if (next_token(s))
24609
0
                return -1;
24610
0
            emit_op(s, OP_special_object);
24611
0
            emit_u8(s, OP_SPECIAL_OBJECT_IMPORT_META);
24612
19
        } else {
24613
19
            if (js_parse_expect(s, '('))
24614
0
                return -1;
24615
19
            if (!accept_lparen)
24616
0
                return js_parse_error(s, "invalid use of 'import()'");
24617
19
            if (js_parse_assign_expr(s))
24618
0
                return -1;
24619
19
            if (js_parse_expect(s, ')'))
24620
0
                return -1;
24621
19
            emit_op(s, OP_import);
24622
19
        }
24623
19
        break;
24624
74
    default:
24625
74
        return js_parse_error(s, "unexpected token in expression: '%.*s'",
24626
74
                              (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
24627
786k
    }
24628
24629
784k
    optional_chaining_label = -1;
24630
814k
    for(;;) {
24631
814k
        JSFunctionDef *fd = s->cur_func;
24632
814k
        BOOL has_optional_chain = FALSE;
24633
        
24634
814k
        if (s->token.val == TOK_QUESTION_MARK_DOT) {
24635
            /* optional chaining */
24636
609
            if (next_token(s))
24637
0
                return -1;
24638
609
            has_optional_chain = TRUE;
24639
609
            if (s->token.val == '(' && accept_lparen) {
24640
540
                goto parse_func_call;
24641
540
            } else if (s->token.val == '[') {
24642
0
                goto parse_array_access;
24643
69
            } else {
24644
69
                goto parse_property;
24645
69
            }
24646
813k
        } else if (s->token.val == TOK_TEMPLATE &&
24647
813k
                   call_type == FUNC_CALL_NORMAL) {
24648
10.1k
            if (optional_chaining_label >= 0) {
24649
0
                return js_parse_error(s, "template literal cannot appear in an optional chain");
24650
0
            }
24651
10.1k
            call_type = FUNC_CALL_TEMPLATE;
24652
10.1k
            goto parse_func_call2;
24653
803k
        } else if (s->token.val == '(' && accept_lparen) {
24654
9.46k
            int opcode, arg_count, drop_count;
24655
24656
            /* function call */
24657
10.0k
        parse_func_call:
24658
10.0k
            if (next_token(s))
24659
1
                return -1;
24660
24661
10.0k
            if (call_type == FUNC_CALL_NORMAL) {
24662
20.1k
            parse_func_call2:
24663
20.1k
                switch(opcode = get_prev_opcode(fd)) {
24664
226
                case OP_get_field:
24665
                    /* keep the object on the stack */
24666
226
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
24667
226
                    drop_count = 2;
24668
226
                    break;
24669
174
                case OP_scope_get_private_field:
24670
                    /* keep the object on the stack */
24671
174
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2;
24672
174
                    drop_count = 2;
24673
174
                    break;
24674
65
                case OP_get_array_el:
24675
                    /* keep the object on the stack */
24676
65
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
24677
65
                    drop_count = 2;
24678
65
                    break;
24679
14.0k
                case OP_scope_get_var:
24680
14.0k
                    {
24681
14.0k
                        JSAtom name;
24682
14.0k
                        int scope;
24683
14.0k
                        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
24684
14.0k
                        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
24685
14.0k
                        if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL && !has_optional_chain) {
24686
                            /* direct 'eval' */
24687
45
                            opcode = OP_eval;
24688
13.9k
                        } else {
24689
                            /* verify if function name resolves to a simple
24690
                               get_loc/get_arg: a function call inside a `with`
24691
                               statement can resolve to a method call of the
24692
                               `with` context object
24693
                             */
24694
                            /* XXX: always generate the OP_scope_get_ref
24695
                               and remove it in variable resolution
24696
                               pass ? */
24697
13.9k
                            if (has_with_scope(fd, scope)) {
24698
2.90k
                                opcode = OP_scope_get_ref;
24699
2.90k
                                fd->byte_code.buf[fd->last_opcode_pos] = opcode;
24700
2.90k
                            }
24701
13.9k
                        }
24702
14.0k
                        drop_count = 1;
24703
14.0k
                    }
24704
14.0k
                    break;
24705
0
                case OP_get_super_value:
24706
0
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el;
24707
                    /* on stack: this func_obj */
24708
0
                    opcode = OP_get_array_el;
24709
0
                    drop_count = 2;
24710
0
                    break;
24711
5.64k
                default:
24712
5.64k
                    opcode = OP_invalid;
24713
5.64k
                    drop_count = 1;
24714
5.64k
                    break;
24715
20.1k
                }
24716
20.1k
                if (has_optional_chain) {
24717
540
                    optional_chain_test(s, &optional_chaining_label,
24718
540
                                        drop_count);
24719
540
                }
24720
20.1k
            } else {
24721
72
                opcode = OP_invalid;
24722
72
            }
24723
24724
20.2k
            if (call_type == FUNC_CALL_TEMPLATE) {
24725
10.1k
                if (js_parse_template(s, 1, &arg_count))
24726
2
                    return -1;
24727
10.1k
                goto emit_func_call;
24728
10.1k
            } else if (call_type == FUNC_CALL_SUPER_CTOR) {
24729
0
                emit_op(s, OP_scope_get_var);
24730
0
                emit_atom(s, JS_ATOM_this_active_func);
24731
0
                emit_u16(s, 0);
24732
24733
0
                emit_op(s, OP_get_super);
24734
24735
0
                emit_op(s, OP_scope_get_var);
24736
0
                emit_atom(s, JS_ATOM_new_target);
24737
0
                emit_u16(s, 0);
24738
10.0k
            } else if (call_type == FUNC_CALL_NEW) {
24739
72
                emit_op(s, OP_dup); /* new.target = function */
24740
72
            }
24741
24742
            /* parse arguments */
24743
10.0k
            arg_count = 0;
24744
10.0k
            while (s->token.val != ')') {
24745
3.41k
                if (arg_count >= 65535) {
24746
0
                    return js_parse_error(s, "Too many call arguments");
24747
0
                }
24748
3.41k
                if (s->token.val == TOK_ELLIPSIS)
24749
554
                    break;
24750
2.85k
                if (js_parse_assign_expr(s))
24751
203
                    return -1;
24752
2.65k
                arg_count++;
24753
2.65k
                if (s->token.val == ')')
24754
2.63k
                    break;
24755
                /* accept a trailing comma before the ')' */
24756
19
                if (js_parse_expect(s, ','))
24757
4
                    return -1;
24758
19
            }
24759
9.80k
            if (s->token.val == TOK_ELLIPSIS) {
24760
554
                emit_op(s, OP_array_from);
24761
554
                emit_u16(s, arg_count);
24762
554
                emit_op(s, OP_push_i32);
24763
554
                emit_u32(s, arg_count);
24764
24765
                /* on stack: array idx */
24766
667
                while (s->token.val != ')') {
24767
629
                    if (s->token.val == TOK_ELLIPSIS) {
24768
554
                        if (next_token(s))
24769
0
                            return -1;
24770
554
                        if (js_parse_assign_expr(s))
24771
18
                            return -1;
24772
536
#if 1
24773
                        /* XXX: could pass is_last indicator? */
24774
536
                        emit_op(s, OP_append);
24775
#else
24776
                        int label_next, label_done;
24777
                        label_next = new_label(s);
24778
                        label_done = new_label(s);
24779
                        /* push enumerate object below array/idx pair */
24780
                        emit_op(s, OP_for_of_start);
24781
                        emit_op(s, OP_rot5l);
24782
                        emit_op(s, OP_rot5l);
24783
                        emit_label(s, label_next);
24784
                        /* on stack: enum_rec array idx */
24785
                        emit_op(s, OP_for_of_next);
24786
                        emit_u8(s, 2);
24787
                        emit_goto(s, OP_if_true, label_done);
24788
                        /* append element */
24789
                        /* enum_rec array idx val -> enum_rec array new_idx */
24790
                        emit_op(s, OP_define_array_el);
24791
                        emit_op(s, OP_inc);
24792
                        emit_goto(s, OP_goto, label_next);
24793
                        emit_label(s, label_done);
24794
                        /* close enumeration, drop enum_rec and idx */
24795
                        emit_op(s, OP_drop); /* drop undef */
24796
                        emit_op(s, OP_nip1); /* drop enum_rec */
24797
                        emit_op(s, OP_nip1);
24798
                        emit_op(s, OP_nip1);
24799
#endif
24800
536
                    } else {
24801
75
                        if (js_parse_assign_expr(s))
24802
40
                            return -1;
24803
                        /* array idx val */
24804
35
                        emit_op(s, OP_define_array_el);
24805
35
                        emit_op(s, OP_inc);
24806
35
                    }
24807
571
                    if (s->token.val == ')')
24808
457
                        break;
24809
                    /* accept a trailing comma before the ')' */
24810
114
                    if (js_parse_expect(s, ','))
24811
1
                        return -1;
24812
114
                }
24813
495
                if (next_token(s))
24814
0
                    return -1;
24815
                /* drop the index */
24816
495
                emit_op(s, OP_drop);
24817
24818
                /* apply function call */
24819
495
                switch(opcode) {
24820
1
                case OP_get_field:
24821
1
                case OP_scope_get_private_field:
24822
1
                case OP_get_array_el:
24823
96
                case OP_scope_get_ref:
24824
                    /* obj func array -> func obj array */
24825
96
                    emit_op(s, OP_perm3);
24826
96
                    emit_op(s, OP_apply);
24827
96
                    emit_u16(s, call_type == FUNC_CALL_NEW);
24828
96
                    break;
24829
0
                case OP_eval:
24830
0
                    emit_op(s, OP_apply_eval);
24831
0
                    emit_u16(s, fd->scope_level);
24832
0
                    fd->has_eval_call = TRUE;
24833
0
                    break;
24834
399
                default:
24835
399
                    if (call_type == FUNC_CALL_SUPER_CTOR) {
24836
0
                        emit_op(s, OP_apply);
24837
0
                        emit_u16(s, 1);
24838
                        /* set the 'this' value */
24839
0
                        emit_op(s, OP_dup);
24840
0
                        emit_op(s, OP_scope_put_var_init);
24841
0
                        emit_atom(s, JS_ATOM_this);
24842
0
                        emit_u16(s, 0);
24843
24844
0
                        emit_class_field_init(s);
24845
399
                    } else if (call_type == FUNC_CALL_NEW) {
24846
                        /* obj func array -> func obj array */
24847
0
                        emit_op(s, OP_perm3);
24848
0
                        emit_op(s, OP_apply);
24849
0
                        emit_u16(s, 1);
24850
399
                    } else {
24851
                        /* func array -> func undef array */
24852
399
                        emit_op(s, OP_undefined);
24853
399
                        emit_op(s, OP_swap);
24854
399
                        emit_op(s, OP_apply);
24855
399
                        emit_u16(s, 0);
24856
399
                    }
24857
399
                    break;
24858
495
                }
24859
9.24k
            } else {
24860
9.24k
                if (next_token(s))
24861
0
                    return -1;
24862
19.4k
            emit_func_call:
24863
19.4k
                switch(opcode) {
24864
222
                case OP_get_field:
24865
371
                case OP_scope_get_private_field:
24866
436
                case OP_get_array_el:
24867
3.22k
                case OP_scope_get_ref:
24868
3.22k
                    emit_op(s, OP_call_method);
24869
3.22k
                    emit_u16(s, arg_count);
24870
3.22k
                    break;
24871
45
                case OP_eval:
24872
45
                    emit_op(s, OP_eval);
24873
45
                    emit_u16(s, arg_count);
24874
45
                    emit_u16(s, fd->scope_level);
24875
45
                    fd->has_eval_call = TRUE;
24876
45
                    break;
24877
16.1k
                default:
24878
16.1k
                    if (call_type == FUNC_CALL_SUPER_CTOR) {
24879
0
                        emit_op(s, OP_call_constructor);
24880
0
                        emit_u16(s, arg_count);
24881
24882
                        /* set the 'this' value */
24883
0
                        emit_op(s, OP_dup);
24884
0
                        emit_op(s, OP_scope_put_var_init);
24885
0
                        emit_atom(s, JS_ATOM_this);
24886
0
                        emit_u16(s, 0);
24887
24888
0
                        emit_class_field_init(s);
24889
16.1k
                    } else if (call_type == FUNC_CALL_NEW) {
24890
72
                        emit_op(s, OP_call_constructor);
24891
72
                        emit_u16(s, arg_count);
24892
16.1k
                    } else {
24893
16.1k
                        emit_op(s, OP_call);
24894
16.1k
                        emit_u16(s, arg_count);
24895
16.1k
                    }
24896
16.1k
                    break;
24897
19.4k
                }
24898
19.4k
            }
24899
19.9k
            call_type = FUNC_CALL_NORMAL;
24900
793k
        } else if (s->token.val == '.') {
24901
7.94k
            if (next_token(s))
24902
0
                return -1;
24903
8.01k
        parse_property:
24904
8.01k
            if (s->token.val == TOK_PRIVATE_NAME) {
24905
                /* private class field */
24906
284
                if (get_prev_opcode(fd) == OP_get_super) {
24907
0
                    return js_parse_error(s, "private class field forbidden after super");
24908
0
                }
24909
284
                if (has_optional_chain) {
24910
0
                    optional_chain_test(s, &optional_chaining_label, 1);
24911
0
                }
24912
284
                emit_op(s, OP_scope_get_private_field);
24913
284
                emit_atom(s, s->token.u.ident.atom);
24914
284
                emit_u16(s, s->cur_func->scope_level);
24915
7.73k
            } else {
24916
7.73k
                if (!token_is_ident(s->token.val)) {
24917
2
                    return js_parse_error(s, "expecting field name");
24918
2
                }
24919
7.72k
                if (get_prev_opcode(fd) == OP_get_super) {
24920
0
                    JSValue val;
24921
0
                    int ret;
24922
0
                    val = JS_AtomToValue(s->ctx, s->token.u.ident.atom);
24923
0
                    ret = emit_push_const(s, val, 1);
24924
0
                    JS_FreeValue(s->ctx, val);
24925
0
                    if (ret)
24926
0
                        return -1;
24927
0
                    emit_op(s, OP_get_super_value);
24928
7.72k
                } else {
24929
7.72k
                    if (has_optional_chain) {
24930
69
                        optional_chain_test(s, &optional_chaining_label, 1);
24931
69
                    }
24932
7.72k
                    emit_op(s, OP_get_field);
24933
7.72k
                    emit_atom(s, s->token.u.ident.atom);
24934
7.72k
                }
24935
7.72k
            }
24936
8.01k
            if (next_token(s))
24937
2
                return -1;
24938
786k
        } else if (s->token.val == '[') {
24939
1.91k
            int prev_op;
24940
24941
1.91k
        parse_array_access:
24942
1.91k
            prev_op = get_prev_opcode(fd);
24943
1.91k
            if (has_optional_chain) {
24944
0
                optional_chain_test(s, &optional_chaining_label, 1);
24945
0
            }
24946
1.91k
            if (next_token(s))
24947
1
                return -1;
24948
1.91k
            if (js_parse_expr(s))
24949
29
                return -1;
24950
1.88k
            if (js_parse_expect(s, ']'))
24951
3
                return -1;
24952
1.88k
            if (prev_op == OP_get_super) {
24953
0
                emit_op(s, OP_get_super_value);
24954
1.88k
            } else {
24955
1.88k
                emit_op(s, OP_get_array_el);
24956
1.88k
            }
24957
784k
        } else {
24958
784k
            break;
24959
784k
        }
24960
814k
    }
24961
784k
    if (optional_chaining_label >= 0)
24962
217
        emit_label(s, optional_chaining_label);
24963
784k
    return 0;
24964
784k
}
24965
24966
static __exception int js_parse_delete(JSParseState *s)
24967
2.95k
{
24968
2.95k
    JSFunctionDef *fd = s->cur_func;
24969
2.95k
    JSAtom name;
24970
2.95k
    int opcode;
24971
24972
2.95k
    if (next_token(s))
24973
0
        return -1;
24974
2.95k
    if (js_parse_unary(s, PF_POW_FORBIDDEN))
24975
12
        return -1;
24976
2.94k
    switch(opcode = get_prev_opcode(fd)) {
24977
8
    case OP_get_field:
24978
8
        {
24979
8
            JSValue val;
24980
8
            int ret;
24981
24982
8
            name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
24983
8
            fd->byte_code.size = fd->last_opcode_pos;
24984
8
            fd->last_opcode_pos = -1;
24985
8
            val = JS_AtomToValue(s->ctx, name);
24986
8
            ret = emit_push_const(s, val, 1);
24987
8
            JS_FreeValue(s->ctx, val);
24988
8
            JS_FreeAtom(s->ctx, name);
24989
8
            if (ret)
24990
0
                return ret;
24991
8
        }
24992
8
        goto do_delete;
24993
1.32k
    case OP_get_array_el:
24994
1.32k
        fd->byte_code.size = fd->last_opcode_pos;
24995
1.32k
        fd->last_opcode_pos = -1;
24996
1.33k
    do_delete:
24997
1.33k
        emit_op(s, OP_delete);
24998
1.33k
        break;
24999
1.36k
    case OP_scope_get_var:
25000
        /* 'delete this': this is not a reference */
25001
1.36k
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
25002
1.36k
        if (name == JS_ATOM_this || name == JS_ATOM_new_target)
25003
0
            goto ret_true;
25004
1.36k
        if (fd->js_mode & JS_MODE_STRICT) {
25005
1
            return js_parse_error(s, "cannot delete a direct reference in strict mode");
25006
1.36k
        } else {
25007
1.36k
            fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_delete_var;
25008
1.36k
        }
25009
1.36k
        break;
25010
1.36k
    case OP_scope_get_private_field:
25011
0
        return js_parse_error(s, "cannot delete a private class field");
25012
0
    case OP_get_super_value:
25013
0
        emit_op(s, OP_throw_error);
25014
0
        emit_atom(s, JS_ATOM_NULL);
25015
0
        emit_u8(s, JS_THROW_ERROR_DELETE_SUPER);
25016
0
        break;
25017
239
    default:
25018
239
    ret_true:
25019
239
        emit_op(s, OP_drop);
25020
239
        emit_op(s, OP_push_true);
25021
239
        break;
25022
2.94k
    }
25023
2.94k
    return 0;
25024
2.94k
}
25025
25026
/* allowed parse_flags: PF_ARROW_FUNC, PF_POW_ALLOWED, PF_POW_FORBIDDEN */
25027
static __exception int js_parse_unary(JSParseState *s, int parse_flags)
25028
791k
{
25029
791k
    int op;
25030
25031
791k
    switch(s->token.val) {
25032
2.37k
    case '+':
25033
4.60k
    case '-':
25034
9.44k
    case '!':
25035
15.3k
    case '~':
25036
16.3k
    case TOK_VOID:
25037
16.3k
        op = s->token.val;
25038
16.3k
        if (next_token(s))
25039
0
            return -1;
25040
16.3k
        if (js_parse_unary(s, PF_POW_FORBIDDEN))
25041
94
            return -1;
25042
16.2k
        switch(op) {
25043
2.21k
        case '-':
25044
2.21k
            emit_op(s, OP_neg);
25045
2.21k
            break;
25046
2.31k
        case '+':
25047
2.31k
            emit_op(s, OP_plus);
25048
2.31k
            break;
25049
4.84k
        case '!':
25050
4.84k
            emit_op(s, OP_lnot);
25051
4.84k
            break;
25052
5.88k
        case '~':
25053
5.88k
            emit_op(s, OP_not);
25054
5.88k
            break;
25055
956
        case TOK_VOID:
25056
956
            emit_op(s, OP_drop);
25057
956
            emit_op(s, OP_undefined);
25058
956
            break;
25059
0
        default:
25060
0
            abort();
25061
16.2k
        }
25062
16.2k
        parse_flags = 0;
25063
16.2k
        break;
25064
6
    case TOK_DEC:
25065
216
    case TOK_INC:
25066
216
        {
25067
216
            int opcode, op, scope, label;
25068
216
            JSAtom name;
25069
216
            op = s->token.val;
25070
216
            if (next_token(s))
25071
0
                return -1;
25072
216
            if (js_parse_unary(s, 0))
25073
0
                return -1;
25074
216
            if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
25075
0
                return -1;
25076
216
            emit_op(s, OP_dec + op - TOK_DEC);
25077
216
            put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP,
25078
216
                       FALSE);
25079
216
        }
25080
0
        break;
25081
259
    case TOK_TYPEOF:
25082
259
        {
25083
259
            JSFunctionDef *fd;
25084
259
            if (next_token(s))
25085
0
                return -1;
25086
259
            if (js_parse_unary(s, PF_POW_FORBIDDEN))
25087
1
                return -1;
25088
            /* reference access should not return an exception, so we
25089
               patch the get_var */
25090
258
            fd = s->cur_func;
25091
258
            if (get_prev_opcode(fd) == OP_scope_get_var) {
25092
103
                fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef;
25093
103
            }
25094
258
            emit_op(s, OP_typeof);
25095
258
            parse_flags = 0;
25096
258
        }
25097
0
        break;
25098
2.95k
    case TOK_DELETE:
25099
2.95k
        if (js_parse_delete(s))
25100
13
            return -1;
25101
2.94k
        parse_flags = 0;
25102
2.94k
        break;
25103
0
    case TOK_AWAIT:
25104
0
        if (!(s->cur_func->func_kind & JS_FUNC_ASYNC))
25105
0
            return js_parse_error(s, "unexpected 'await' keyword");
25106
0
        if (!s->cur_func->in_function_body)
25107
0
            return js_parse_error(s, "await in default expression");
25108
0
        if (next_token(s))
25109
0
            return -1;
25110
0
        if (js_parse_unary(s, PF_POW_FORBIDDEN))
25111
0
            return -1;
25112
0
        emit_op(s, OP_await);
25113
0
        parse_flags = 0;
25114
0
        break;
25115
772k
    default:
25116
772k
        if (js_parse_postfix_expr(s, (parse_flags & PF_ARROW_FUNC) |
25117
772k
                                  PF_POSTFIX_CALL))
25118
2.43k
            return -1;
25119
769k
        if (!s->got_lf &&
25120
769k
            (s->token.val == TOK_DEC || s->token.val == TOK_INC)) {
25121
5.23k
            int opcode, op, scope, label;
25122
5.23k
            JSAtom name;
25123
5.23k
            op = s->token.val;
25124
5.23k
            if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
25125
0
                return -1;
25126
5.23k
            emit_op(s, OP_post_dec + op - TOK_DEC);
25127
5.23k
            put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND,
25128
5.23k
                       FALSE);
25129
5.23k
            if (next_token(s))
25130
1
                return -1;        
25131
5.23k
        }
25132
769k
        break;
25133
791k
    }
25134
789k
    if (parse_flags & (PF_POW_ALLOWED | PF_POW_FORBIDDEN)) {
25135
769k
#ifdef CONFIG_BIGNUM
25136
769k
        if (s->token.val == TOK_POW || s->token.val == TOK_MATH_POW) {
25137
            /* Extended exponentiation syntax rules: we extend the ES7
25138
               grammar in order to have more intuitive semantics:
25139
               -2**2 evaluates to -4. */
25140
334
            if (!(s->cur_func->js_mode & JS_MODE_MATH)) {
25141
334
                if (parse_flags & PF_POW_FORBIDDEN) {
25142
0
                    JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
25143
0
                    return -1;
25144
0
                }
25145
334
            }
25146
334
            if (next_token(s))
25147
0
                return -1;
25148
334
            if (js_parse_unary(s, PF_POW_ALLOWED))
25149
0
                return -1;
25150
334
            emit_op(s, OP_pow);
25151
334
        }
25152
#else
25153
        if (s->token.val == TOK_POW) {
25154
            /* Strict ES7 exponentiation syntax rules: To solve
25155
               conficting semantics between different implementations
25156
               regarding the precedence of prefix operators and the
25157
               postifx exponential, ES7 specifies that -2**2 is a
25158
               syntax error. */
25159
            if (parse_flags & PF_POW_FORBIDDEN) {
25160
                JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
25161
                return -1;
25162
            }
25163
            if (next_token(s))
25164
                return -1;
25165
            if (js_parse_unary(s, PF_POW_ALLOWED))
25166
                return -1;
25167
            emit_op(s, OP_pow);
25168
        }
25169
#endif
25170
769k
    }
25171
789k
    return 0;
25172
789k
}
25173
25174
/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
25175
static __exception int js_parse_expr_binary(JSParseState *s, int level,
25176
                                            int parse_flags)
25177
6.71M
{
25178
6.71M
    int op, opcode;
25179
25180
6.71M
    if (level == 0) {
25181
771k
        return js_parse_unary(s, (parse_flags & PF_ARROW_FUNC) |
25182
771k
                              PF_POW_ALLOWED);
25183
771k
    }
25184
5.93M
    if (js_parse_expr_binary(s, level - 1, parse_flags))
25185
19.2k
        return -1;
25186
5.96M
    for(;;) {
25187
5.96M
        op = s->token.val;
25188
5.96M
        switch(level) {
25189
769k
        case 1:
25190
769k
            switch(op) {
25191
1.74k
            case '*':
25192
1.74k
                opcode = OP_mul;
25193
1.74k
                break;
25194
5.99k
            case '/':
25195
5.99k
                opcode = OP_div;
25196
5.99k
                break;
25197
137
            case '%':
25198
137
#ifdef CONFIG_BIGNUM
25199
137
                if (s->cur_func->js_mode & JS_MODE_MATH)
25200
0
                    opcode = OP_math_mod;
25201
137
                else
25202
137
#endif
25203
137
                    opcode = OP_mod;
25204
137
                break;
25205
761k
            default:
25206
761k
                return 0;
25207
769k
            }
25208
7.87k
            break;
25209
761k
        case 2:
25210
761k
            switch(op) {
25211
5.48k
            case '+':
25212
5.48k
                opcode = OP_add;
25213
5.48k
                break;
25214
5.81k
            case '-':
25215
5.81k
                opcode = OP_sub;
25216
5.81k
                break;
25217
750k
            default:
25218
750k
                return 0;
25219
761k
            }
25220
11.3k
            break;
25221
750k
        case 3:
25222
750k
            switch(op) {
25223
2
            case TOK_SHL:
25224
2
                opcode = OP_shl;
25225
2
                break;
25226
11
            case TOK_SAR:
25227
11
                opcode = OP_sar;
25228
11
                break;
25229
0
            case TOK_SHR:
25230
0
                opcode = OP_shr;
25231
0
                break;
25232
750k
            default:
25233
750k
                return 0;
25234
750k
            }
25235
13
            break;
25236
750k
        case 4:
25237
750k
            switch(op) {
25238
2.13k
            case '<':
25239
2.13k
                opcode = OP_lt;
25240
2.13k
                break;
25241
3.99k
            case '>':
25242
3.99k
                opcode = OP_gt;
25243
3.99k
                break;
25244
5.74k
            case TOK_LTE:
25245
5.74k
                opcode = OP_lte;
25246
5.74k
                break;
25247
841
            case TOK_GTE:
25248
841
                opcode = OP_gte;
25249
841
                break;
25250
0
            case TOK_INSTANCEOF:
25251
0
                opcode = OP_instanceof;
25252
0
                break;
25253
268
            case TOK_IN:
25254
268
                if (parse_flags & PF_IN_ACCEPTED) {
25255
268
                    opcode = OP_in;
25256
268
                } else {
25257
0
                    return 0;
25258
0
                }
25259
268
                break;
25260
737k
            default:
25261
737k
                return 0;
25262
750k
            }
25263
12.9k
            break;
25264
737k
        case 5:
25265
737k
            switch(op) {
25266
1.02k
            case TOK_EQ:
25267
1.02k
                opcode = OP_eq;
25268
1.02k
                break;
25269
783
            case TOK_NEQ:
25270
783
                opcode = OP_neq;
25271
783
                break;
25272
518
            case TOK_STRICT_EQ:
25273
518
                opcode = OP_strict_eq;
25274
518
                break;
25275
106
            case TOK_STRICT_NEQ:
25276
106
                opcode = OP_strict_neq;
25277
106
                break;
25278
734k
            default:
25279
734k
                return 0;
25280
737k
            }
25281
2.43k
            break;
25282
734k
        case 6:
25283
734k
            switch(op) {
25284
5.20k
            case '&':
25285
5.20k
                opcode = OP_and;
25286
5.20k
                break;
25287
729k
            default:
25288
729k
                return 0;
25289
734k
            }
25290
5.20k
            break;
25291
729k
        case 7:
25292
729k
            switch(op) {
25293
324
            case '^':
25294
324
                opcode = OP_xor;
25295
324
                break;
25296
729k
            default:
25297
729k
                return 0;
25298
729k
            }
25299
324
            break;
25300
729k
        case 8:
25301
729k
            switch(op) {
25302
894
            case '|':
25303
894
                opcode = OP_or;
25304
894
                break;
25305
728k
            default:
25306
728k
                return 0;
25307
729k
            }
25308
894
            break;
25309
894
        default:
25310
0
            abort();
25311
5.96M
        }
25312
41.0k
        if (next_token(s))
25313
10
            return -1;
25314
41.0k
        if (js_parse_expr_binary(s, level - 1, parse_flags & ~PF_ARROW_FUNC))
25315
306
            return -1;
25316
40.7k
        emit_op(s, opcode);
25317
40.7k
    }
25318
0
    return 0;
25319
5.92M
}
25320
25321
/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
25322
static __exception int js_parse_logical_and_or(JSParseState *s, int op,
25323
                                               int parse_flags)
25324
1.45M
{
25325
1.45M
    int label1;
25326
25327
1.45M
    if (op == TOK_LAND) {
25328
730k
        if (js_parse_expr_binary(s, 8, parse_flags))
25329
2.44k
            return -1;
25330
730k
    } else {
25331
729k
        if (js_parse_logical_and_or(s, TOK_LAND, parse_flags))
25332
2.44k
            return -1;
25333
729k
    }
25334
1.45M
    if (s->token.val == op) {
25335
530
        label1 = new_label(s);
25336
25337
981
        for(;;) {
25338
981
            if (next_token(s))
25339
0
                return -1;
25340
981
            emit_op(s, OP_dup);
25341
981
            emit_goto(s, op == TOK_LAND ? OP_if_false : OP_if_true, label1);
25342
981
            emit_op(s, OP_drop);
25343
25344
981
            if (op == TOK_LAND) {
25345
282
                if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
25346
0
                    return -1;
25347
699
            } else {
25348
699
                if (js_parse_logical_and_or(s, TOK_LAND,
25349
699
                                            parse_flags & ~PF_ARROW_FUNC))
25350
0
                    return -1;
25351
699
            }
25352
981
            if (s->token.val != op) {
25353
530
                if (s->token.val == TOK_DOUBLE_QUESTION_MARK)
25354
0
                    return js_parse_error(s, "cannot mix ?? with && or ||");
25355
530
                break;
25356
530
            }
25357
981
        }
25358
25359
530
        emit_label(s, label1);
25360
530
    }
25361
1.45M
    return 0;
25362
1.45M
}
25363
25364
static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
25365
729k
{
25366
729k
    int label1;
25367
    
25368
729k
    if (js_parse_logical_and_or(s, TOK_LOR, parse_flags))
25369
2.44k
        return -1;
25370
726k
    if (s->token.val == TOK_DOUBLE_QUESTION_MARK) {
25371
294
        label1 = new_label(s);
25372
342
        for(;;) {
25373
342
            if (next_token(s))
25374
0
                return -1;
25375
            
25376
342
            emit_op(s, OP_dup);
25377
342
            emit_op(s, OP_is_undefined_or_null);
25378
342
            emit_goto(s, OP_if_false, label1);
25379
342
            emit_op(s, OP_drop);
25380
            
25381
342
            if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
25382
2
                return -1;
25383
340
            if (s->token.val != TOK_DOUBLE_QUESTION_MARK)
25384
292
                break;
25385
340
        }
25386
292
        emit_label(s, label1);
25387
292
    }
25388
726k
    return 0;
25389
726k
}
25390
25391
/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
25392
static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
25393
729k
{
25394
729k
    int label1, label2;
25395
25396
729k
    if (js_parse_coalesce_expr(s, parse_flags))
25397
2.44k
        return -1;
25398
726k
    if (s->token.val == '?') {
25399
3.62k
        if (next_token(s))
25400
0
            return -1;
25401
3.62k
        label1 = emit_goto(s, OP_if_false, -1);
25402
25403
3.62k
        if (js_parse_assign_expr(s))
25404
2
            return -1;
25405
3.62k
        if (js_parse_expect(s, ':'))
25406
2
            return -1;
25407
25408
3.62k
        label2 = emit_goto(s, OP_goto, -1);
25409
25410
3.62k
        emit_label(s, label1);
25411
25412
3.62k
        if (js_parse_assign_expr2(s, parse_flags & PF_IN_ACCEPTED))
25413
21
            return -1;
25414
25415
3.60k
        emit_label(s, label2);
25416
3.60k
    }
25417
726k
    return 0;
25418
726k
}
25419
25420
static void emit_return(JSParseState *s, BOOL hasval);
25421
25422
/* allowed parse_flags: PF_IN_ACCEPTED */
25423
static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
25424
729k
{
25425
729k
    int opcode, op, scope;
25426
729k
    JSAtom name0 = JS_ATOM_NULL;
25427
729k
    JSAtom name;
25428
25429
729k
    if (s->token.val == TOK_YIELD) {
25430
193
        BOOL is_star = FALSE, is_async;
25431
        
25432
193
        if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR))
25433
0
            return js_parse_error(s, "unexpected 'yield' keyword");
25434
193
        if (!s->cur_func->in_function_body)
25435
0
            return js_parse_error(s, "yield in default expression");
25436
193
        if (next_token(s))
25437
0
            return -1;
25438
        /* XXX: is there a better method to detect 'yield' without
25439
           parameters ? */
25440
193
        if (s->token.val != ';' && s->token.val != ')' &&
25441
193
            s->token.val != ']' && s->token.val != '}' &&
25442
193
            s->token.val != ',' && s->token.val != ':' && !s->got_lf) {
25443
193
            if (s->token.val == '*') {
25444
193
                is_star = TRUE;
25445
193
                if (next_token(s))
25446
0
                    return -1;
25447
193
            }
25448
193
            if (js_parse_assign_expr2(s, parse_flags))
25449
0
                return -1;
25450
193
        } else {
25451
0
            emit_op(s, OP_undefined);
25452
0
        }
25453
193
        is_async = (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR);
25454
25455
193
        if (is_star) {
25456
193
            int label_loop, label_return, label_next;
25457
193
            int label_return1, label_yield, label_throw, label_throw1;
25458
193
            int label_throw2;
25459
25460
193
            label_loop = new_label(s);
25461
193
            label_yield = new_label(s);
25462
25463
193
            emit_op(s, is_async ? OP_for_await_of_start : OP_for_of_start);
25464
25465
            /* remove the catch offset (XXX: could avoid pushing back
25466
               undefined) */
25467
193
            emit_op(s, OP_drop);
25468
193
            emit_op(s, OP_undefined);
25469
            
25470
193
            emit_op(s, OP_undefined); /* initial value */
25471
            
25472
193
            emit_label(s, label_loop);
25473
193
            emit_op(s, OP_iterator_next);
25474
193
            if (is_async)
25475
0
                emit_op(s, OP_await);
25476
193
            emit_op(s, OP_iterator_check_object);
25477
193
            emit_op(s, OP_get_field2);
25478
193
            emit_atom(s, JS_ATOM_done);
25479
193
            label_next = emit_goto(s, OP_if_true, -1); /* end of loop */
25480
193
            emit_label(s, label_yield);
25481
193
            if (is_async) {
25482
                /* OP_async_yield_star takes the value as parameter */
25483
0
                emit_op(s, OP_get_field);
25484
0
                emit_atom(s, JS_ATOM_value);
25485
0
                emit_op(s, OP_await);
25486
0
                emit_op(s, OP_async_yield_star);
25487
193
            } else {
25488
                /* OP_yield_star takes (value, done) as parameter */
25489
193
                emit_op(s, OP_yield_star);
25490
193
            }
25491
193
            emit_op(s, OP_dup);
25492
193
            label_return = emit_goto(s, OP_if_true, -1);
25493
193
            emit_op(s, OP_drop);
25494
193
            emit_goto(s, OP_goto, label_loop);
25495
            
25496
193
            emit_label(s, label_return);
25497
193
            emit_op(s, OP_push_i32);
25498
193
            emit_u32(s, 2);
25499
193
            emit_op(s, OP_strict_eq);
25500
193
            label_throw = emit_goto(s, OP_if_true, -1);
25501
            
25502
            /* return handling */
25503
193
            if (is_async)
25504
0
                emit_op(s, OP_await);
25505
193
            emit_op(s, OP_iterator_call);
25506
193
            emit_u8(s, 0);
25507
193
            label_return1 = emit_goto(s, OP_if_true, -1);
25508
193
            if (is_async)
25509
0
                emit_op(s, OP_await);
25510
193
            emit_op(s, OP_iterator_check_object);
25511
193
            emit_op(s, OP_get_field2);
25512
193
            emit_atom(s, JS_ATOM_done);
25513
193
            emit_goto(s, OP_if_false, label_yield);
25514
25515
193
            emit_op(s, OP_get_field);
25516
193
            emit_atom(s, JS_ATOM_value);
25517
            
25518
193
            emit_label(s, label_return1);
25519
193
            emit_op(s, OP_nip);
25520
193
            emit_op(s, OP_nip);
25521
193
            emit_op(s, OP_nip);
25522
193
            emit_return(s, TRUE);
25523
            
25524
            /* throw handling */
25525
193
            emit_label(s, label_throw);
25526
193
            emit_op(s, OP_iterator_call);
25527
193
            emit_u8(s, 1);
25528
193
            label_throw1 = emit_goto(s, OP_if_true, -1);
25529
193
            if (is_async)
25530
0
                emit_op(s, OP_await);
25531
193
            emit_op(s, OP_iterator_check_object);
25532
193
            emit_op(s, OP_get_field2);
25533
193
            emit_atom(s, JS_ATOM_done);
25534
193
            emit_goto(s, OP_if_false, label_yield);
25535
193
            emit_goto(s, OP_goto, label_next);
25536
            /* close the iterator and throw a type error exception */
25537
193
            emit_label(s, label_throw1);
25538
193
            emit_op(s, OP_iterator_call);
25539
193
            emit_u8(s, 2);
25540
193
            label_throw2 = emit_goto(s, OP_if_true, -1);
25541
193
            if (is_async)
25542
0
                emit_op(s, OP_await);
25543
193
            emit_label(s, label_throw2);
25544
25545
193
            emit_op(s, OP_throw_error);
25546
193
            emit_atom(s, JS_ATOM_NULL);
25547
193
            emit_u8(s, JS_THROW_ERROR_ITERATOR_THROW);
25548
            
25549
193
            emit_label(s, label_next);
25550
193
            emit_op(s, OP_get_field);
25551
193
            emit_atom(s, JS_ATOM_value);
25552
193
            emit_op(s, OP_nip); /* keep the value associated with
25553
                                   done = true */
25554
193
            emit_op(s, OP_nip);
25555
193
            emit_op(s, OP_nip);
25556
193
        } else {
25557
0
            int label_next;
25558
            
25559
0
            if (is_async)
25560
0
                emit_op(s, OP_await);
25561
0
            emit_op(s, OP_yield);
25562
0
            label_next = emit_goto(s, OP_if_false, -1);
25563
0
            emit_return(s, TRUE);
25564
0
            emit_label(s, label_next);
25565
0
        }
25566
193
        return 0;
25567
193
    }
25568
729k
    if (s->token.val == TOK_IDENT) {
25569
        /* name0 is used to check for OP_set_name pattern, not duplicated */
25570
635k
        name0 = s->token.u.ident.atom;
25571
635k
    }
25572
729k
    if (js_parse_cond_expr(s, parse_flags | PF_ARROW_FUNC))
25573
2.46k
        return -1;
25574
25575
726k
    op = s->token.val;
25576
726k
    if (op == '=' || (op >= TOK_MUL_ASSIGN && op <= TOK_POW_ASSIGN)) {
25577
271k
        int label;
25578
271k
        if (next_token(s))
25579
0
            return -1;
25580
271k
        if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
25581
15
            return -1;
25582
25583
271k
        if (js_parse_assign_expr2(s, parse_flags)) {
25584
572
            JS_FreeAtom(s->ctx, name);
25585
572
            return -1;
25586
572
        }
25587
25588
271k
        if (op == '=') {
25589
262k
            if (opcode == OP_get_ref_value && name == name0) {
25590
260k
                set_object_name(s, name);
25591
260k
            }
25592
262k
        } else {
25593
8.32k
            static const uint8_t assign_opcodes[] = {
25594
8.32k
                OP_mul, OP_div, OP_mod, OP_add, OP_sub,
25595
8.32k
                OP_shl, OP_sar, OP_shr, OP_and, OP_xor, OP_or,
25596
8.32k
#ifdef CONFIG_BIGNUM
25597
8.32k
                OP_pow,
25598
8.32k
#endif
25599
8.32k
                OP_pow,
25600
8.32k
            };
25601
8.32k
            op = assign_opcodes[op - TOK_MUL_ASSIGN];
25602
8.32k
#ifdef CONFIG_BIGNUM
25603
8.32k
            if (s->cur_func->js_mode & JS_MODE_MATH) {
25604
0
                if (op == OP_mod)
25605
0
                    op = OP_math_mod;
25606
0
            }
25607
8.32k
#endif
25608
8.32k
            emit_op(s, op);
25609
8.32k
        }
25610
271k
        put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE);
25611
455k
    } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) {
25612
21.2k
        int label, label1, depth_lvalue, label2;
25613
        
25614
21.2k
        if (next_token(s))
25615
0
            return -1;
25616
21.2k
        if (get_lvalue(s, &opcode, &scope, &name, &label,
25617
21.2k
                       &depth_lvalue, TRUE, op) < 0)
25618
0
            return -1;
25619
25620
21.2k
        emit_op(s, OP_dup);
25621
21.2k
        if (op == TOK_DOUBLE_QUESTION_MARK_ASSIGN)
25622
0
            emit_op(s, OP_is_undefined_or_null);
25623
21.2k
        label1 = emit_goto(s, op == TOK_LOR_ASSIGN ? OP_if_true : OP_if_false,
25624
21.2k
                           -1);
25625
21.2k
        emit_op(s, OP_drop);
25626
        
25627
21.2k
        if (js_parse_assign_expr2(s, parse_flags)) {
25628
1
            JS_FreeAtom(s->ctx, name);
25629
1
            return -1;
25630
1
        }
25631
25632
21.2k
        if (opcode == OP_get_ref_value && name == name0) {
25633
21.2k
            set_object_name(s, name);
25634
21.2k
        }
25635
        
25636
21.2k
        switch(depth_lvalue) {
25637
0
        case 1:
25638
0
            emit_op(s, OP_insert2);
25639
0
            break;
25640
21.2k
        case 2:
25641
21.2k
            emit_op(s, OP_insert3);
25642
21.2k
            break;
25643
0
        case 3:
25644
0
            emit_op(s, OP_insert4);
25645
0
            break;
25646
0
        default:
25647
0
            abort();
25648
21.2k
        }
25649
25650
        /* XXX: we disable the OP_put_ref_value optimization by not
25651
           using put_lvalue() otherwise depth_lvalue is not correct */
25652
21.2k
        put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH,
25653
21.2k
                   FALSE);
25654
21.2k
        label2 = emit_goto(s, OP_goto, -1);
25655
        
25656
21.2k
        emit_label(s, label1);
25657
25658
        /* remove the lvalue stack entries */
25659
63.6k
        while (depth_lvalue != 0) {
25660
42.4k
            emit_op(s, OP_nip);
25661
42.4k
            depth_lvalue--;
25662
42.4k
        }
25663
25664
21.2k
        emit_label(s, label2);
25665
21.2k
    }
25666
726k
    return 0;
25667
726k
}
25668
25669
static __exception int js_parse_assign_expr(JSParseState *s)
25670
72.4k
{
25671
72.4k
    return js_parse_assign_expr2(s, PF_IN_ACCEPTED);
25672
72.4k
}
25673
25674
/* allowed parse_flags: PF_IN_ACCEPTED */
25675
static __exception int js_parse_expr2(JSParseState *s, int parse_flags)
25676
141k
{
25677
141k
    BOOL comma = FALSE;
25678
351k
    for(;;) {
25679
351k
        if (js_parse_assign_expr2(s, parse_flags))
25680
1.17k
            return -1;
25681
349k
        if (comma) {
25682
            /* prevent get_lvalue from using the last expression
25683
               as an lvalue. This also prevents the conversion of
25684
               of get_var to get_ref for method lookup in function
25685
               call inside `with` statement.
25686
             */
25687
209k
            s->cur_func->last_opcode_pos = -1;
25688
209k
        }
25689
349k
        if (s->token.val != ',')
25690
140k
            break;
25691
209k
        comma = TRUE;
25692
209k
        if (next_token(s))
25693
0
            return -1;
25694
209k
        emit_op(s, OP_drop);
25695
209k
    }
25696
140k
    return 0;
25697
141k
}
25698
25699
static __exception int js_parse_expr(JSParseState *s)
25700
136k
{
25701
136k
    return js_parse_expr2(s, PF_IN_ACCEPTED);
25702
136k
}
25703
25704
static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
25705
                             JSAtom label_name,
25706
                             int label_break, int label_cont,
25707
                             int drop_count)
25708
41.5k
{
25709
41.5k
    be->prev = fd->top_break;
25710
41.5k
    fd->top_break = be;
25711
41.5k
    be->label_name = label_name;
25712
41.5k
    be->label_break = label_break;
25713
41.5k
    be->label_cont = label_cont;
25714
41.5k
    be->drop_count = drop_count;
25715
41.5k
    be->label_finally = -1;
25716
41.5k
    be->scope_level = fd->scope_level;
25717
41.5k
    be->has_iterator = FALSE;
25718
41.5k
}
25719
25720
static void pop_break_entry(JSFunctionDef *fd)
25721
40.8k
{
25722
40.8k
    BlockEnv *be;
25723
40.8k
    be = fd->top_break;
25724
40.8k
    fd->top_break = be->prev;
25725
40.8k
}
25726
25727
static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
25728
0
{
25729
0
    BlockEnv *top;
25730
0
    int i, scope_level;
25731
25732
0
    scope_level = s->cur_func->scope_level;
25733
0
    top = s->cur_func->top_break;
25734
0
    while (top != NULL) {
25735
0
        close_scopes(s, scope_level, top->scope_level);
25736
0
        scope_level = top->scope_level;
25737
0
        if (is_cont &&
25738
0
            top->label_cont != -1 &&
25739
0
            (name == JS_ATOM_NULL || top->label_name == name)) {
25740
            /* continue stays inside the same block */
25741
0
            emit_goto(s, OP_goto, top->label_cont);
25742
0
            return 0;
25743
0
        }
25744
0
        if (!is_cont &&
25745
0
            top->label_break != -1 &&
25746
0
            (name == JS_ATOM_NULL || top->label_name == name)) {
25747
0
            emit_goto(s, OP_goto, top->label_break);
25748
0
            return 0;
25749
0
        }
25750
0
        i = 0;
25751
0
        if (top->has_iterator) {
25752
0
            emit_op(s, OP_iterator_close);
25753
0
            i += 3;
25754
0
        }
25755
0
        for(; i < top->drop_count; i++)
25756
0
            emit_op(s, OP_drop);
25757
0
        if (top->label_finally != -1) {
25758
            /* must push dummy value to keep same stack depth */
25759
0
            emit_op(s, OP_undefined);
25760
0
            emit_goto(s, OP_gosub, top->label_finally);
25761
0
            emit_op(s, OP_drop);
25762
0
        }
25763
0
        top = top->prev;
25764
0
    }
25765
0
    if (name == JS_ATOM_NULL) {
25766
0
        if (is_cont)
25767
0
            return js_parse_error(s, "continue must be inside loop");
25768
0
        else
25769
0
            return js_parse_error(s, "break must be inside loop or switch");
25770
0
    } else {
25771
0
        return js_parse_error(s, "break/continue label not found");
25772
0
    }
25773
0
}
25774
25775
/* execute the finally blocks before return */
25776
static void emit_return(JSParseState *s, BOOL hasval)
25777
22.3k
{
25778
22.3k
    BlockEnv *top;
25779
22.3k
    int drop_count;
25780
25781
22.3k
    drop_count = 0;
25782
22.3k
    top = s->cur_func->top_break;
25783
30.9k
    while (top != NULL) {
25784
        /* XXX: emit the appropriate OP_leave_scope opcodes? Probably not
25785
           required as all local variables will be closed upon returning
25786
           from JS_CallInternal, but not in the same order. */
25787
8.63k
        if (top->has_iterator) {
25788
            /* with 'yield', the exact number of OP_drop to emit is
25789
               unknown, so we use a specific operation to look for
25790
               the catch offset */
25791
0
            if (!hasval) {
25792
0
                emit_op(s, OP_undefined);
25793
0
                hasval = TRUE;
25794
0
            }
25795
0
            emit_op(s, OP_iterator_close_return);
25796
0
            if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
25797
0
                int label_next, label_next2;
25798
25799
0
                emit_op(s, OP_drop); /* catch offset */
25800
0
                emit_op(s, OP_drop); /* next */
25801
0
                emit_op(s, OP_get_field2);
25802
0
                emit_atom(s, JS_ATOM_return);
25803
                /* stack: iter_obj return_func */
25804
0
                emit_op(s, OP_dup);
25805
0
                emit_op(s, OP_is_undefined_or_null);
25806
0
                label_next = emit_goto(s, OP_if_true, -1);
25807
0
                emit_op(s, OP_call_method);
25808
0
                emit_u16(s, 0);
25809
0
                emit_op(s, OP_iterator_check_object);
25810
0
                emit_op(s, OP_await);
25811
0
                label_next2 = emit_goto(s, OP_goto, -1);
25812
0
                emit_label(s, label_next);
25813
0
                emit_op(s, OP_drop);
25814
0
                emit_label(s, label_next2);
25815
0
                emit_op(s, OP_drop);
25816
0
            } else {
25817
0
                emit_op(s, OP_iterator_close);
25818
0
            }
25819
0
            drop_count = -3;
25820
0
        }
25821
8.63k
        drop_count += top->drop_count;
25822
8.63k
        if (top->label_finally != -1) {
25823
17.2k
            while(drop_count) {
25824
                /* must keep the stack top if hasval */
25825
8.63k
                emit_op(s, hasval ? OP_nip : OP_drop);
25826
8.63k
                drop_count--;
25827
8.63k
            }
25828
8.61k
            if (!hasval) {
25829
                /* must push return value to keep same stack size */
25830
645
                emit_op(s, OP_undefined);
25831
645
                hasval = TRUE;
25832
645
            }
25833
8.61k
            emit_goto(s, OP_gosub, top->label_finally);
25834
8.61k
        }
25835
8.63k
        top = top->prev;
25836
8.63k
    }
25837
22.3k
    if (s->cur_func->is_derived_class_constructor) {
25838
0
        int label_return;
25839
25840
        /* 'this' can be uninitialized, so it may be accessed only if
25841
           the derived class constructor does not return an object */
25842
0
        if (hasval) {
25843
0
            emit_op(s, OP_check_ctor_return);
25844
0
            label_return = emit_goto(s, OP_if_false, -1);
25845
0
            emit_op(s, OP_drop);
25846
0
        } else {
25847
0
            label_return = -1;
25848
0
        }
25849
25850
        /* XXX: if this is not initialized, should throw the
25851
           ReferenceError in the caller realm */
25852
0
        emit_op(s, OP_scope_get_var);
25853
0
        emit_atom(s, JS_ATOM_this);
25854
0
        emit_u16(s, 0);
25855
25856
0
        emit_label(s, label_return);
25857
0
        emit_op(s, OP_return);
25858
22.3k
    } else if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
25859
602
        if (!hasval) {
25860
393
            emit_op(s, OP_undefined);
25861
393
        } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
25862
0
            emit_op(s, OP_await);
25863
0
        }
25864
602
        emit_op(s, OP_return_async);
25865
21.6k
    } else {
25866
21.6k
        emit_op(s, hasval ? OP_return : OP_return_undef);
25867
21.6k
    }
25868
22.3k
}
25869
25870
123k
#define DECL_MASK_FUNC  (1 << 0) /* allow normal function declaration */
25871
/* ored with DECL_MASK_FUNC if function declarations are allowed with a label */
25872
124k
#define DECL_MASK_FUNC_WITH_LABEL (1 << 1)
25873
126k
#define DECL_MASK_OTHER (1 << 2) /* all other declarations */
25874
117k
#define DECL_MASK_ALL   (DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL | DECL_MASK_OTHER)
25875
25876
static __exception int js_parse_statement_or_decl(JSParseState *s,
25877
                                                  int decl_mask);
25878
25879
static __exception int js_parse_statement(JSParseState *s)
25880
22.1k
{
25881
22.1k
    return js_parse_statement_or_decl(s, 0);
25882
22.1k
}
25883
25884
static __exception int js_parse_block(JSParseState *s)
25885
6.44k
{
25886
6.44k
    if (js_parse_expect(s, '{'))
25887
0
        return -1;
25888
6.44k
    if (s->token.val != '}') {
25889
6.16k
        push_scope(s);
25890
14.4k
        for(;;) {
25891
14.4k
            if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
25892
972
                return -1;
25893
13.4k
            if (s->token.val == '}')
25894
5.19k
                break;
25895
13.4k
        }
25896
5.19k
        pop_scope(s);
25897
5.19k
    }
25898
5.47k
    if (next_token(s))
25899
0
        return -1;
25900
5.47k
    return 0;
25901
5.47k
}
25902
25903
/* allowed parse_flags: PF_IN_ACCEPTED */
25904
static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
25905
                                    BOOL export_flag)
25906
1.16k
{
25907
1.16k
    JSContext *ctx = s->ctx;
25908
1.16k
    JSFunctionDef *fd = s->cur_func;
25909
1.16k
    JSAtom name = JS_ATOM_NULL;
25910
25911
11.1k
    for (;;) {
25912
11.1k
        if (s->token.val == TOK_IDENT) {
25913
10.8k
            if (s->token.u.ident.is_reserved) {
25914
0
                return js_parse_error_reserved_identifier(s);
25915
0
            }
25916
10.8k
            name = JS_DupAtom(ctx, s->token.u.ident.atom);
25917
10.8k
            if (name == JS_ATOM_let && (tok == TOK_LET || tok == TOK_CONST)) {
25918
0
                js_parse_error(s, "'let' is not a valid lexical identifier");
25919
0
                goto var_error;
25920
0
            }
25921
10.8k
            if (next_token(s))
25922
1
                goto var_error;
25923
10.8k
            if (js_define_var(s, name, tok))
25924
0
                goto var_error;
25925
10.8k
            if (export_flag) {
25926
0
                if (!add_export_entry(s, s->cur_func->module, name, name,
25927
0
                                      JS_EXPORT_TYPE_LOCAL))
25928
0
                    goto var_error;
25929
0
            }
25930
25931
10.8k
            if (s->token.val == '=') {
25932
9.15k
                if (next_token(s))
25933
0
                    goto var_error;
25934
9.15k
                if (tok == TOK_VAR) {
25935
                    /* Must make a reference for proper `with` semantics */
25936
9.03k
                    int opcode, scope, label;
25937
9.03k
                    JSAtom name1;
25938
25939
9.03k
                    emit_op(s, OP_scope_get_var);
25940
9.03k
                    emit_atom(s, name);
25941
9.03k
                    emit_u16(s, fd->scope_level);
25942
9.03k
                    if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0)
25943
0
                        goto var_error;
25944
9.03k
                    if (js_parse_assign_expr2(s, parse_flags)) {
25945
4
                        JS_FreeAtom(ctx, name1);
25946
4
                        goto var_error;
25947
4
                    }
25948
9.03k
                    set_object_name(s, name);
25949
9.03k
                    put_lvalue(s, opcode, scope, name1, label,
25950
9.03k
                               PUT_LVALUE_NOKEEP, FALSE);
25951
9.03k
                } else {
25952
121
                    if (js_parse_assign_expr2(s, parse_flags))
25953
9
                        goto var_error;
25954
112
                    set_object_name(s, name);
25955
112
                    emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
25956
112
                        OP_scope_put_var_init : OP_scope_put_var);
25957
112
                    emit_atom(s, name);
25958
112
                    emit_u16(s, fd->scope_level);
25959
112
                }
25960
9.15k
            } else {
25961
1.69k
                if (tok == TOK_CONST) {
25962
0
                    js_parse_error(s, "missing initializer for const variable");
25963
0
                    goto var_error;
25964
0
                }
25965
1.69k
                if (tok == TOK_LET) {
25966
                    /* initialize lexical variable upon entering its scope */
25967
218
                    emit_op(s, OP_undefined);
25968
218
                    emit_op(s, OP_scope_put_var_init);
25969
218
                    emit_atom(s, name);
25970
218
                    emit_u16(s, fd->scope_level);
25971
218
                }
25972
1.69k
            }
25973
10.8k
            JS_FreeAtom(ctx, name);
25974
10.8k
        } else {
25975
291
            int skip_bits;
25976
291
            if ((s->token.val == '[' || s->token.val == '{')
25977
291
            &&  js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
25978
289
                emit_op(s, OP_undefined);
25979
289
                if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
25980
121
                    return -1;
25981
289
            } else {
25982
2
                return js_parse_error(s, "variable name expected");
25983
2
            }
25984
291
        }
25985
11.0k
        if (s->token.val != ',')
25986
1.02k
            break;
25987
9.97k
        if (next_token(s))
25988
1
            return -1;
25989
9.97k
    }
25990
1.02k
    return 0;
25991
25992
14
 var_error:
25993
14
    JS_FreeAtom(ctx, name);
25994
14
    return -1;
25995
1.16k
}
25996
25997
/* test if the current token is a label. Use simplistic look-ahead scanner */
25998
static BOOL is_label(JSParseState *s)
25999
144k
{
26000
144k
    return (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
26001
144k
            peek_token(s, FALSE) == ':');
26002
144k
}
26003
26004
/* test if the current token is a let keyword. Use simplistic look-ahead scanner */
26005
static int is_let(JSParseState *s, int decl_mask)
26006
83.2k
{
26007
83.2k
    int res = FALSE;
26008
26009
83.2k
    if (token_is_pseudo_keyword(s, JS_ATOM_let)) {
26010
2.16k
#if 1
26011
2.16k
        JSParsePos pos;
26012
2.16k
        js_parse_get_pos(s, &pos);
26013
2.16k
        for (;;) {
26014
2.16k
            if (next_token(s)) {
26015
0
                res = -1;
26016
0
                break;
26017
0
            }
26018
2.16k
            if (s->token.val == '[') {
26019
                /* let [ is a syntax restriction:
26020
                   it never introduces an ExpressionStatement */
26021
0
                res = TRUE;
26022
0
                break;
26023
0
            }
26024
2.16k
            if (s->token.val == '{' ||
26025
2.16k
                (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) ||
26026
2.16k
                s->token.val == TOK_LET ||
26027
2.16k
                s->token.val == TOK_YIELD ||
26028
2.16k
                s->token.val == TOK_AWAIT) {
26029
                /* Check for possible ASI if not scanning for Declaration */
26030
                /* XXX: should also check that `{` introduces a BindingPattern,
26031
                   but Firefox does not and rejects eval("let=1;let\n{if(1)2;}") */
26032
1.27k
                if (s->last_line_num == s->token.line_num || (decl_mask & DECL_MASK_OTHER)) {
26033
1.27k
                    res = TRUE;
26034
1.27k
                    break;
26035
1.27k
                }
26036
0
                break;
26037
1.27k
            }
26038
893
            break;
26039
2.16k
        }
26040
2.16k
        if (js_parse_seek_token(s, &pos)) {
26041
0
            res = -1;
26042
0
        }
26043
#else
26044
        int tok = peek_token(s, TRUE);
26045
        if (tok == '{' || tok == TOK_IDENT || peek_token(s, FALSE) == '[') {
26046
            res = TRUE;
26047
        }
26048
#endif
26049
2.16k
    }
26050
83.2k
    return res;
26051
83.2k
}
26052
26053
/* XXX: handle IteratorClose when exiting the loop before the
26054
   enumeration is done */
26055
static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
26056
                                          BOOL is_async)
26057
2.38k
{
26058
2.38k
    JSContext *ctx = s->ctx;
26059
2.38k
    JSFunctionDef *fd = s->cur_func;
26060
2.38k
    JSAtom var_name;
26061
2.38k
    BOOL has_initializer, is_for_of, has_destructuring;
26062
2.38k
    int tok, tok1, opcode, scope, block_scope_level;
26063
2.38k
    int label_next, label_expr, label_cont, label_body, label_break;
26064
2.38k
    int pos_next, pos_expr;
26065
2.38k
    BlockEnv break_entry;
26066
26067
2.38k
    has_initializer = FALSE;
26068
2.38k
    has_destructuring = FALSE;
26069
2.38k
    is_for_of = FALSE;
26070
2.38k
    block_scope_level = fd->scope_level;
26071
2.38k
    label_cont = new_label(s);
26072
2.38k
    label_body = new_label(s);
26073
2.38k
    label_break = new_label(s);
26074
2.38k
    label_next = new_label(s);
26075
26076
    /* create scope for the lexical variables declared in the enumeration
26077
       expressions. XXX: Not completely correct because of weird capturing
26078
       semantics in `for (i of o) a.push(function(){return i})` */
26079
2.38k
    push_scope(s);
26080
26081
    /* local for_in scope starts here so individual elements
26082
       can be closed in statement. */
26083
2.38k
    push_break_entry(s->cur_func, &break_entry,
26084
2.38k
                     label_name, label_break, label_cont, 1);
26085
2.38k
    break_entry.scope_level = block_scope_level;
26086
26087
2.38k
    label_expr = emit_goto(s, OP_goto, -1);
26088
26089
2.38k
    pos_next = s->cur_func->byte_code.size;
26090
2.38k
    emit_label(s, label_next);
26091
26092
2.38k
    tok = s->token.val;
26093
2.38k
    switch (is_let(s, DECL_MASK_OTHER)) {
26094
1.13k
    case TRUE:
26095
1.13k
        tok = TOK_LET;
26096
1.13k
        break;
26097
1.24k
    case FALSE:
26098
1.24k
        break;
26099
0
    default:
26100
0
        return -1;
26101
2.38k
    }
26102
2.38k
    if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
26103
1.15k
        if (next_token(s))
26104
0
            return -1;
26105
26106
1.15k
        if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
26107
1
            if (s->token.val == '[' || s->token.val == '{') {
26108
1
                if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE) < 0)
26109
1
                    return -1;
26110
0
                has_destructuring = TRUE;
26111
0
            } else {
26112
0
                return js_parse_error(s, "variable name expected");
26113
0
            }
26114
0
            var_name = JS_ATOM_NULL;
26115
1.15k
        } else {
26116
1.15k
            var_name = JS_DupAtom(ctx, s->token.u.ident.atom);
26117
1.15k
            if (next_token(s)) {
26118
0
                JS_FreeAtom(s->ctx, var_name);
26119
0
                return -1;
26120
0
            }
26121
1.15k
            if (js_define_var(s, var_name, tok)) {
26122
0
                JS_FreeAtom(s->ctx, var_name);
26123
0
                return -1;
26124
0
            }
26125
1.15k
            emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
26126
1.15k
                    OP_scope_put_var_init : OP_scope_put_var);
26127
1.15k
            emit_atom(s, var_name);
26128
1.15k
            emit_u16(s, fd->scope_level);
26129
1.15k
        }
26130
1.23k
    } else {
26131
1.23k
        int skip_bits;
26132
1.23k
        if ((s->token.val == '[' || s->token.val == '{')
26133
1.23k
        &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) {
26134
0
            if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
26135
0
                return -1;
26136
1.23k
        } else {
26137
1.23k
            int lvalue_label;
26138
1.23k
            if (js_parse_left_hand_side_expr(s))
26139
2
                return -1;
26140
1.23k
            if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label,
26141
1.23k
                           NULL, FALSE, TOK_FOR))
26142
0
                return -1;
26143
1.23k
            put_lvalue(s, opcode, scope, var_name, lvalue_label,
26144
1.23k
                       PUT_LVALUE_NOKEEP_BOTTOM, FALSE);
26145
1.23k
        }
26146
1.23k
        var_name = JS_ATOM_NULL;
26147
1.23k
    }
26148
2.38k
    emit_goto(s, OP_goto, label_body);
26149
26150
2.38k
    pos_expr = s->cur_func->byte_code.size;
26151
2.38k
    emit_label(s, label_expr);
26152
2.38k
    if (s->token.val == '=') {
26153
        /* XXX: potential scoping issue if inside `with` statement */
26154
0
        has_initializer = TRUE;
26155
        /* parse and evaluate initializer prior to evaluating the
26156
           object (only used with "for in" with a non lexical variable
26157
           in non strict mode */
26158
0
        if (next_token(s) || js_parse_assign_expr2(s, 0)) {
26159
0
            JS_FreeAtom(ctx, var_name);
26160
0
            return -1;
26161
0
        }
26162
0
        if (var_name != JS_ATOM_NULL) {
26163
0
            emit_op(s, OP_scope_put_var);
26164
0
            emit_atom(s, var_name);
26165
0
            emit_u16(s, fd->scope_level);
26166
0
        }
26167
0
    }
26168
2.38k
    JS_FreeAtom(ctx, var_name);
26169
26170
2.38k
    if (token_is_pseudo_keyword(s, JS_ATOM_of)) {
26171
104
        break_entry.has_iterator = is_for_of = TRUE;
26172
104
        break_entry.drop_count += 2;
26173
104
        if (has_initializer)
26174
0
            goto initializer_error;
26175
2.27k
    } else if (s->token.val == TOK_IN) {
26176
2.27k
        if (is_async)
26177
0
            return js_parse_error(s, "'for await' loop should be used with 'of'");
26178
2.27k
        if (has_initializer &&
26179
2.27k
            (tok != TOK_VAR || (fd->js_mode & JS_MODE_STRICT) ||
26180
0
             has_destructuring)) {
26181
0
        initializer_error:
26182
0
            return js_parse_error(s, "a declaration in the head of a for-%s loop can't have an initializer",
26183
0
                                  is_for_of ? "of" : "in");
26184
0
        }
26185
2.27k
    } else {
26186
2
        return js_parse_error(s, "expected 'of' or 'in' in for control expression");
26187
2
    }
26188
2.38k
    if (next_token(s))
26189
0
        return -1;
26190
2.38k
    if (is_for_of) {
26191
104
        if (js_parse_assign_expr(s))
26192
0
            return -1;
26193
2.27k
    } else {
26194
2.27k
        if (js_parse_expr(s))
26195
0
            return -1;
26196
2.27k
    }
26197
    /* close the scope after having evaluated the expression so that
26198
       the TDZ values are in the closures */
26199
2.38k
    close_scopes(s, s->cur_func->scope_level, block_scope_level);
26200
2.38k
    if (is_for_of) {
26201
104
        if (is_async)
26202
0
            emit_op(s, OP_for_await_of_start);
26203
104
        else
26204
104
            emit_op(s, OP_for_of_start);
26205
        /* on stack: enum_rec */
26206
2.27k
    } else {
26207
2.27k
        emit_op(s, OP_for_in_start);
26208
        /* on stack: enum_obj */
26209
2.27k
    }
26210
2.38k
    emit_goto(s, OP_goto, label_cont);
26211
26212
2.38k
    if (js_parse_expect(s, ')'))
26213
1
        return -1;
26214
26215
2.38k
    if (OPTIMIZE) {
26216
        /* move the `next` code here */
26217
2.38k
        DynBuf *bc = &s->cur_func->byte_code;
26218
2.38k
        int chunk_size = pos_expr - pos_next;
26219
2.38k
        int offset = bc->size - pos_next;
26220
2.38k
        int i;
26221
2.38k
        dbuf_realloc(bc, bc->size + chunk_size);
26222
2.38k
        dbuf_put(bc, bc->buf + pos_next, chunk_size);
26223
2.38k
        memset(bc->buf + pos_next, OP_nop, chunk_size);
26224
        /* `next` part ends with a goto */
26225
2.38k
        s->cur_func->last_opcode_pos = bc->size - 5;
26226
        /* relocate labels */
26227
16.0k
        for (i = label_cont; i < s->cur_func->label_count; i++) {
26228
13.6k
            LabelSlot *ls = &s->cur_func->label_slots[i];
26229
13.6k
            if (ls->pos >= pos_next && ls->pos < pos_expr)
26230
3.61k
                ls->pos += offset;
26231
13.6k
        }
26232
2.38k
    }
26233
26234
2.38k
    emit_label(s, label_body);
26235
2.38k
    if (js_parse_statement(s))
26236
240
        return -1;
26237
26238
2.14k
    close_scopes(s, s->cur_func->scope_level, block_scope_level);
26239
26240
2.14k
    emit_label(s, label_cont);
26241
2.14k
    if (is_for_of) {
26242
71
        if (is_async) {
26243
            /* call the next method */
26244
            /* stack: iter_obj next catch_offset */
26245
0
            emit_op(s, OP_dup3);
26246
0
            emit_op(s, OP_drop);
26247
0
            emit_op(s, OP_call_method);
26248
0
            emit_u16(s, 0);
26249
            /* get the result of the promise */
26250
0
            emit_op(s, OP_await);
26251
            /* unwrap the value and done values */
26252
0
            emit_op(s, OP_iterator_get_value_done);
26253
71
        } else {
26254
71
            emit_op(s, OP_for_of_next);
26255
71
            emit_u8(s, 0);
26256
71
        }
26257
2.06k
    } else {
26258
2.06k
        emit_op(s, OP_for_in_next);
26259
2.06k
    }
26260
    /* on stack: enum_rec / enum_obj value bool */
26261
2.14k
    emit_goto(s, OP_if_false, label_next);
26262
    /* drop the undefined value from for_xx_next */
26263
2.14k
    emit_op(s, OP_drop);
26264
26265
2.14k
    emit_label(s, label_break);
26266
2.14k
    if (is_for_of) {
26267
        /* close and drop enum_rec */
26268
71
        emit_op(s, OP_iterator_close);
26269
2.06k
    } else {
26270
2.06k
        emit_op(s, OP_drop);
26271
2.06k
    }
26272
2.14k
    pop_break_entry(s->cur_func);
26273
2.14k
    pop_scope(s);
26274
2.14k
    return 0;
26275
2.38k
}
26276
26277
static void set_eval_ret_undefined(JSParseState *s)
26278
22.8k
{
26279
22.8k
    if (s->cur_func->eval_ret_idx >= 0) {
26280
20.1k
        emit_op(s, OP_undefined);
26281
20.1k
        emit_op(s, OP_put_loc);
26282
20.1k
        emit_u16(s, s->cur_func->eval_ret_idx);
26283
20.1k
    }
26284
22.8k
}
26285
26286
static __exception int js_parse_statement_or_decl(JSParseState *s,
26287
                                                  int decl_mask)
26288
144k
{
26289
144k
    JSContext *ctx = s->ctx;
26290
144k
    JSAtom label_name;
26291
144k
    int tok;
26292
26293
    /* specific label handling */
26294
    /* XXX: support multiple labels on loop statements */
26295
144k
    label_name = JS_ATOM_NULL;
26296
144k
    if (is_label(s)) {
26297
4.03k
        BlockEnv *be;
26298
26299
4.03k
        label_name = JS_DupAtom(ctx, s->token.u.ident.atom);
26300
26301
4.29k
        for (be = s->cur_func->top_break; be; be = be->prev) {
26302
260
            if (be->label_name == label_name) {
26303
0
                js_parse_error(s, "duplicate label name");
26304
0
                goto fail;
26305
0
            }
26306
260
        }
26307
26308
4.03k
        if (next_token(s))
26309
0
            goto fail;
26310
4.03k
        if (js_parse_expect(s, ':'))
26311
0
            goto fail;
26312
4.03k
        if (s->token.val != TOK_FOR
26313
4.03k
        &&  s->token.val != TOK_DO
26314
4.03k
        &&  s->token.val != TOK_WHILE) {
26315
            /* labelled regular statement */
26316
3.43k
            int label_break, mask;
26317
3.43k
            BlockEnv break_entry;
26318
26319
3.43k
            label_break = new_label(s);
26320
3.43k
            push_break_entry(s->cur_func, &break_entry,
26321
3.43k
                             label_name, label_break, -1, 0);
26322
3.43k
            if (!(s->cur_func->js_mode & JS_MODE_STRICT) &&
26323
3.43k
                (decl_mask & DECL_MASK_FUNC_WITH_LABEL)) {
26324
3.01k
                mask = DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL;
26325
3.01k
            } else {
26326
414
                mask = 0;
26327
414
            }
26328
3.43k
            if (js_parse_statement_or_decl(s, mask))
26329
8
                goto fail;
26330
3.42k
            emit_label(s, label_break);
26331
3.42k
            pop_break_entry(s->cur_func);
26332
3.42k
            goto done;
26333
3.43k
        }
26334
4.03k
    }
26335
26336
140k
    switch(tok = s->token.val) {
26337
6.30k
    case '{':
26338
6.30k
        if (js_parse_block(s))
26339
856
            goto fail;
26340
5.45k
        break;
26341
5.45k
    case TOK_RETURN:
26342
799
        if (s->cur_func->is_eval) {
26343
0
            js_parse_error(s, "return not in a function");
26344
0
            goto fail;
26345
0
        }
26346
799
        if (next_token(s))
26347
0
            goto fail;
26348
799
        if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) {
26349
79
            if (js_parse_expr(s))
26350
0
                goto fail;
26351
79
            emit_return(s, TRUE);
26352
720
        } else {
26353
720
            emit_return(s, FALSE);
26354
720
        }
26355
799
        if (js_parse_expect_semi(s))
26356
0
            goto fail;
26357
799
        break;
26358
2.29k
    case TOK_THROW:
26359
2.29k
        if (next_token(s))
26360
0
            goto fail;
26361
2.29k
        if (s->got_lf) {
26362
0
            js_parse_error(s, "line terminator not allowed after throw");
26363
0
            goto fail;
26364
0
        }
26365
2.29k
        if (js_parse_expr(s))
26366
2
            goto fail;
26367
2.29k
        emit_op(s, OP_throw);
26368
2.29k
        if (js_parse_expect_semi(s))
26369
0
            goto fail;
26370
2.29k
        break;
26371
2.29k
    case TOK_LET:
26372
5
    case TOK_CONST:
26373
137
    haslet:
26374
137
        if (!(decl_mask & DECL_MASK_OTHER)) {
26375
0
            js_parse_error(s, "lexical declarations can't appear in single-statement context");
26376
0
            goto fail;
26377
0
        }
26378
        /* fall thru */
26379
1.16k
    case TOK_VAR:
26380
1.16k
        if (next_token(s))
26381
0
            goto fail;
26382
1.16k
        if (js_parse_var(s, TRUE, tok, FALSE))
26383
138
            goto fail;
26384
1.02k
        if (js_parse_expect_semi(s))
26385
1
            goto fail;
26386
1.02k
        break;
26387
1.02k
    case TOK_IF:
26388
578
        {
26389
578
            int label1, label2, mask;
26390
578
            if (next_token(s))
26391
0
                goto fail;
26392
            /* create a new scope for `let f;if(1) function f(){}` */
26393
578
            push_scope(s);
26394
578
            set_eval_ret_undefined(s);
26395
578
            if (js_parse_expr_paren(s))
26396
2
                goto fail;
26397
576
            label1 = emit_goto(s, OP_if_false, -1);
26398
576
            if (s->cur_func->js_mode & JS_MODE_STRICT)
26399
14
                mask = 0;
26400
562
            else
26401
562
                mask = DECL_MASK_FUNC; /* Annex B.3.4 */
26402
26403
576
            if (js_parse_statement_or_decl(s, mask))
26404
100
                goto fail;
26405
26406
476
            if (s->token.val == TOK_ELSE) {
26407
0
                label2 = emit_goto(s, OP_goto, -1);
26408
0
                if (next_token(s))
26409
0
                    goto fail;
26410
26411
0
                emit_label(s, label1);
26412
0
                if (js_parse_statement_or_decl(s, mask))
26413
0
                    goto fail;
26414
26415
0
                label1 = label2;
26416
0
            }
26417
476
            emit_label(s, label1);
26418
476
            pop_scope(s);
26419
476
        }
26420
0
        break;
26421
3.62k
    case TOK_WHILE:
26422
3.62k
        {
26423
3.62k
            int label_cont, label_break;
26424
3.62k
            BlockEnv break_entry;
26425
26426
3.62k
            label_cont = new_label(s);
26427
3.62k
            label_break = new_label(s);
26428
26429
3.62k
            push_break_entry(s->cur_func, &break_entry,
26430
3.62k
                             label_name, label_break, label_cont, 0);
26431
26432
3.62k
            if (next_token(s))
26433
0
                goto fail;
26434
26435
3.62k
            set_eval_ret_undefined(s);
26436
26437
3.62k
            emit_label(s, label_cont);
26438
3.62k
            if (js_parse_expr_paren(s))
26439
0
                goto fail;
26440
3.62k
            emit_goto(s, OP_if_false, label_break);
26441
26442
3.62k
            if (js_parse_statement(s))
26443
34
                goto fail;
26444
3.58k
            emit_goto(s, OP_goto, label_cont);
26445
26446
3.58k
            emit_label(s, label_break);
26447
26448
3.58k
            pop_break_entry(s->cur_func);
26449
3.58k
        }
26450
0
        break;
26451
118
    case TOK_DO:
26452
118
        {
26453
118
            int label_cont, label_break, label1;
26454
118
            BlockEnv break_entry;
26455
26456
118
            label_cont = new_label(s);
26457
118
            label_break = new_label(s);
26458
118
            label1 = new_label(s);
26459
26460
118
            push_break_entry(s->cur_func, &break_entry,
26461
118
                             label_name, label_break, label_cont, 0);
26462
26463
118
            if (next_token(s))
26464
0
                goto fail;
26465
26466
118
            emit_label(s, label1);
26467
26468
118
            set_eval_ret_undefined(s);
26469
26470
118
            if (js_parse_statement(s))
26471
6
                goto fail;
26472
26473
112
            emit_label(s, label_cont);
26474
112
            if (js_parse_expect(s, TOK_WHILE))
26475
0
                goto fail;
26476
112
            if (js_parse_expr_paren(s))
26477
0
                goto fail;
26478
            /* Insert semicolon if missing */
26479
112
            if (s->token.val == ';') {
26480
4
                if (next_token(s))
26481
0
                    goto fail;
26482
4
            }
26483
112
            emit_goto(s, OP_if_true, label1);
26484
26485
112
            emit_label(s, label_break);
26486
26487
112
            pop_break_entry(s->cur_func);
26488
112
        }
26489
0
        break;
26490
7.07k
    case TOK_FOR:
26491
7.07k
        {
26492
7.07k
            int label_cont, label_break, label_body, label_test;
26493
7.07k
            int pos_cont, pos_body, block_scope_level;
26494
7.07k
            BlockEnv break_entry;
26495
7.07k
            int tok, bits;
26496
7.07k
            BOOL is_async;
26497
26498
7.07k
            if (next_token(s))
26499
0
                goto fail;
26500
26501
7.07k
            set_eval_ret_undefined(s);
26502
7.07k
            bits = 0;
26503
7.07k
            is_async = FALSE;
26504
7.07k
            if (s->token.val == '(') {
26505
7.07k
                js_parse_skip_parens_token(s, &bits, FALSE);
26506
7.07k
            } else if (s->token.val == TOK_AWAIT) {
26507
0
                if (!(s->cur_func->func_kind & JS_FUNC_ASYNC)) {
26508
0
                    js_parse_error(s, "for await is only valid in asynchronous functions");
26509
0
                    goto fail;
26510
0
                }
26511
0
                is_async = TRUE;
26512
0
                if (next_token(s))
26513
0
                    goto fail;
26514
0
            }
26515
7.07k
            if (js_parse_expect(s, '('))
26516
0
                goto fail;
26517
26518
7.07k
            if (!(bits & SKIP_HAS_SEMI)) {
26519
                /* parse for/in or for/of */
26520
2.38k
                if (js_parse_for_in_of(s, label_name, is_async))
26521
246
                    goto fail;
26522
2.14k
                break;
26523
2.38k
            }
26524
4.68k
            block_scope_level = s->cur_func->scope_level;
26525
26526
            /* create scope for the lexical variables declared in the initial,
26527
               test and increment expressions */
26528
4.68k
            push_scope(s);
26529
            /* initial expression */
26530
4.68k
            tok = s->token.val;
26531
4.68k
            if (tok != ';') {
26532
4.68k
                switch (is_let(s, DECL_MASK_OTHER)) {
26533
0
                case TRUE:
26534
0
                    tok = TOK_LET;
26535
0
                    break;
26536
4.68k
                case FALSE:
26537
4.68k
                    break;
26538
0
                default:
26539
0
                    goto fail;
26540
4.68k
                }
26541
4.68k
                if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
26542
0
                    if (next_token(s))
26543
0
                        goto fail;
26544
0
                    if (js_parse_var(s, FALSE, tok, FALSE))
26545
0
                        goto fail;
26546
4.68k
                } else {
26547
4.68k
                    if (js_parse_expr2(s, FALSE))
26548
1
                        goto fail;
26549
4.68k
                    emit_op(s, OP_drop);
26550
4.68k
                }
26551
26552
                /* close the closures before the first iteration */
26553
4.68k
                close_scopes(s, s->cur_func->scope_level, block_scope_level);
26554
4.68k
            }
26555
4.68k
            if (js_parse_expect(s, ';'))
26556
0
                goto fail;
26557
26558
4.68k
            label_test = new_label(s);
26559
4.68k
            label_cont = new_label(s);
26560
4.68k
            label_body = new_label(s);
26561
4.68k
            label_break = new_label(s);
26562
26563
4.68k
            push_break_entry(s->cur_func, &break_entry,
26564
4.68k
                             label_name, label_break, label_cont, 0);
26565
26566
            /* test expression */
26567
4.68k
            if (s->token.val == ';') {
26568
                /* no test expression */
26569
1
                label_test = label_body;
26570
4.68k
            } else {
26571
4.68k
                emit_label(s, label_test);
26572
4.68k
                if (js_parse_expr(s))
26573
0
                    goto fail;
26574
4.68k
                emit_goto(s, OP_if_false, label_break);
26575
4.68k
            }
26576
4.68k
            if (js_parse_expect(s, ';'))
26577
1
                goto fail;
26578
26579
4.68k
            if (s->token.val == ')') {
26580
                /* no end expression */
26581
69
                break_entry.label_cont = label_cont = label_test;
26582
69
                pos_cont = 0; /* avoid warning */
26583
4.61k
            } else {
26584
                /* skip the end expression */
26585
4.61k
                emit_goto(s, OP_goto, label_body);
26586
26587
4.61k
                pos_cont = s->cur_func->byte_code.size;
26588
4.61k
                emit_label(s, label_cont);
26589
4.61k
                if (js_parse_expr(s))
26590
0
                    goto fail;
26591
4.61k
                emit_op(s, OP_drop);
26592
4.61k
                if (label_test != label_body)
26593
4.61k
                    emit_goto(s, OP_goto, label_test);
26594
4.61k
            }
26595
4.68k
            if (js_parse_expect(s, ')'))
26596
1
                goto fail;
26597
26598
4.68k
            pos_body = s->cur_func->byte_code.size;
26599
4.68k
            emit_label(s, label_body);
26600
4.68k
            if (js_parse_statement(s))
26601
211
                goto fail;
26602
26603
            /* close the closures before the next iteration */
26604
            /* XXX: check continue case */
26605
4.47k
            close_scopes(s, s->cur_func->scope_level, block_scope_level);
26606
26607
4.47k
            if (OPTIMIZE && label_test != label_body && label_cont != label_test) {
26608
                /* move the increment code here */
26609
4.40k
                DynBuf *bc = &s->cur_func->byte_code;
26610
4.40k
                int chunk_size = pos_body - pos_cont;
26611
4.40k
                int offset = bc->size - pos_cont;
26612
4.40k
                int i;
26613
4.40k
                dbuf_realloc(bc, bc->size + chunk_size);
26614
4.40k
                dbuf_put(bc, bc->buf + pos_cont, chunk_size);
26615
4.40k
                memset(bc->buf + pos_cont, OP_nop, chunk_size);
26616
                /* increment part ends with a goto */
26617
4.40k
                s->cur_func->last_opcode_pos = bc->size - 5;
26618
                /* relocate labels */
26619
253k
                for (i = label_cont; i < s->cur_func->label_count; i++) {
26620
249k
                    LabelSlot *ls = &s->cur_func->label_slots[i];
26621
249k
                    if (ls->pos >= pos_cont && ls->pos < pos_body)
26622
6.06k
                        ls->pos += offset;
26623
249k
                }
26624
4.40k
            } else {
26625
66
                emit_goto(s, OP_goto, label_cont);
26626
66
            }
26627
26628
4.47k
            emit_label(s, label_break);
26629
26630
4.47k
            pop_break_entry(s->cur_func);
26631
4.47k
            pop_scope(s);
26632
4.47k
        }
26633
0
        break;
26634
0
    case TOK_BREAK:
26635
0
    case TOK_CONTINUE:
26636
0
        {
26637
0
            int is_cont = s->token.val - TOK_BREAK;
26638
0
            int label;
26639
26640
0
            if (next_token(s))
26641
0
                goto fail;
26642
0
            if (!s->got_lf && s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
26643
0
                label = s->token.u.ident.atom;
26644
0
            else
26645
0
                label = JS_ATOM_NULL;
26646
0
            if (emit_break(s, label, is_cont))
26647
0
                goto fail;
26648
0
            if (label != JS_ATOM_NULL) {
26649
0
                if (next_token(s))
26650
0
                    goto fail;
26651
0
            }
26652
0
            if (js_parse_expect_semi(s))
26653
0
                goto fail;
26654
0
        }
26655
0
        break;
26656
0
    case TOK_SWITCH:
26657
0
        {
26658
0
            int label_case, label_break, label1;
26659
0
            int default_label_pos;
26660
0
            BlockEnv break_entry;
26661
26662
0
            if (next_token(s))
26663
0
                goto fail;
26664
26665
0
            set_eval_ret_undefined(s);
26666
0
            if (js_parse_expr_paren(s))
26667
0
                goto fail;
26668
26669
0
            push_scope(s);
26670
0
            label_break = new_label(s);
26671
0
            push_break_entry(s->cur_func, &break_entry,
26672
0
                             label_name, label_break, -1, 1);
26673
26674
0
            if (js_parse_expect(s, '{'))
26675
0
                goto fail;
26676
26677
0
            default_label_pos = -1;
26678
0
            label_case = -1;
26679
0
            while (s->token.val != '}') {
26680
0
                if (s->token.val == TOK_CASE) {
26681
0
                    label1 = -1;
26682
0
                    if (label_case >= 0) {
26683
                        /* skip the case if needed */
26684
0
                        label1 = emit_goto(s, OP_goto, -1);
26685
0
                    }
26686
0
                    emit_label(s, label_case);
26687
0
                    label_case = -1;
26688
0
                    for (;;) {
26689
                        /* parse a sequence of case clauses */
26690
0
                        if (next_token(s))
26691
0
                            goto fail;
26692
0
                        emit_op(s, OP_dup);
26693
0
                        if (js_parse_expr(s))
26694
0
                            goto fail;
26695
0
                        if (js_parse_expect(s, ':'))
26696
0
                            goto fail;
26697
0
                        emit_op(s, OP_strict_eq);
26698
0
                        if (s->token.val == TOK_CASE) {
26699
0
                            label1 = emit_goto(s, OP_if_true, label1);
26700
0
                        } else {
26701
0
                            label_case = emit_goto(s, OP_if_false, -1);
26702
0
                            emit_label(s, label1);
26703
0
                            break;
26704
0
                        }
26705
0
                    }
26706
0
                } else if (s->token.val == TOK_DEFAULT) {
26707
0
                    if (next_token(s))
26708
0
                        goto fail;
26709
0
                    if (js_parse_expect(s, ':'))
26710
0
                        goto fail;
26711
0
                    if (default_label_pos >= 0) {
26712
0
                        js_parse_error(s, "duplicate default");
26713
0
                        goto fail;
26714
0
                    }
26715
0
                    if (label_case < 0) {
26716
                        /* falling thru direct from switch expression */
26717
0
                        label_case = emit_goto(s, OP_goto, -1);
26718
0
                    }
26719
                    /* Emit a dummy label opcode. Label will be patched after
26720
                       the end of the switch body. Do not use emit_label(s, 0)
26721
                       because it would clobber label 0 address, preventing
26722
                       proper optimizer operation.
26723
                     */
26724
0
                    emit_op(s, OP_label);
26725
0
                    emit_u32(s, 0);
26726
0
                    default_label_pos = s->cur_func->byte_code.size - 4;
26727
0
                } else {
26728
0
                    if (label_case < 0) {
26729
                        /* falling thru direct from switch expression */
26730
0
                        js_parse_error(s, "invalid switch statement");
26731
0
                        goto fail;
26732
0
                    }
26733
0
                    if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
26734
0
                        goto fail;
26735
0
                }
26736
0
            }
26737
0
            if (js_parse_expect(s, '}'))
26738
0
                goto fail;
26739
0
            if (default_label_pos >= 0) {
26740
                /* Ugly patch for the the `default` label, shameful and risky */
26741
0
                put_u32(s->cur_func->byte_code.buf + default_label_pos,
26742
0
                        label_case);
26743
0
                s->cur_func->label_slots[label_case].pos = default_label_pos + 4;
26744
0
            } else {
26745
0
                emit_label(s, label_case);
26746
0
            }
26747
0
            emit_label(s, label_break);
26748
0
            emit_op(s, OP_drop); /* drop the switch expression */
26749
26750
0
            pop_break_entry(s->cur_func);
26751
0
            pop_scope(s);
26752
0
        }
26753
0
        break;
26754
123
    case TOK_TRY:
26755
123
        {
26756
123
            int label_catch, label_catch2, label_finally, label_end;
26757
123
            JSAtom name;
26758
123
            BlockEnv block_env;
26759
26760
123
            set_eval_ret_undefined(s);
26761
123
            if (next_token(s))
26762
0
                goto fail;
26763
123
            label_catch = new_label(s);
26764
123
            label_catch2 = new_label(s);
26765
123
            label_finally = new_label(s);
26766
123
            label_end = new_label(s);
26767
26768
123
            emit_goto(s, OP_catch, label_catch);
26769
26770
123
            push_break_entry(s->cur_func, &block_env,
26771
123
                             JS_ATOM_NULL, -1, -1, 1);
26772
123
            block_env.label_finally = label_finally;
26773
26774
123
            if (js_parse_block(s))
26775
112
                goto fail;
26776
26777
11
            pop_break_entry(s->cur_func);
26778
26779
11
            if (js_is_live_code(s)) {
26780
                /* drop the catch offset */
26781
11
                emit_op(s, OP_drop);
26782
                /* must push dummy value to keep same stack size */
26783
11
                emit_op(s, OP_undefined);
26784
11
                emit_goto(s, OP_gosub, label_finally);
26785
11
                emit_op(s, OP_drop);
26786
26787
11
                emit_goto(s, OP_goto, label_end);
26788
11
            }
26789
26790
11
            if (s->token.val == TOK_CATCH) {
26791
11
                if (next_token(s))
26792
0
                    goto fail;
26793
26794
11
                push_scope(s);  /* catch variable */
26795
11
                emit_label(s, label_catch);
26796
26797
11
                if (s->token.val == '{') {
26798
                    /* support optional-catch-binding feature */
26799
11
                    emit_op(s, OP_drop);    /* pop the exception object */
26800
11
                } else {
26801
0
                    if (js_parse_expect(s, '('))
26802
0
                        goto fail;
26803
0
                    if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
26804
0
                        if (s->token.val == '[' || s->token.val == '{') {
26805
                            /* XXX: TOK_LET is not completely correct */
26806
0
                            if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE) < 0)
26807
0
                                goto fail;
26808
0
                        } else {
26809
0
                            js_parse_error(s, "identifier expected");
26810
0
                            goto fail;
26811
0
                        }
26812
0
                    } else {
26813
0
                        name = JS_DupAtom(ctx, s->token.u.ident.atom);
26814
0
                        if (next_token(s)
26815
0
                        ||  js_define_var(s, name, TOK_CATCH) < 0) {
26816
0
                            JS_FreeAtom(ctx, name);
26817
0
                            goto fail;
26818
0
                        }
26819
                        /* store the exception value in the catch variable */
26820
0
                        emit_op(s, OP_scope_put_var);
26821
0
                        emit_u32(s, name);
26822
0
                        emit_u16(s, s->cur_func->scope_level);
26823
0
                    }
26824
0
                    if (js_parse_expect(s, ')'))
26825
0
                        goto fail;
26826
0
                }
26827
                /* XXX: should keep the address to nop it out if there is no finally block */
26828
11
                emit_goto(s, OP_catch, label_catch2);
26829
26830
11
                push_scope(s);  /* catch block */
26831
11
                push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
26832
11
                                 -1, -1, 1);
26833
11
                block_env.label_finally = label_finally;
26834
26835
11
                if (js_parse_block(s))
26836
4
                    goto fail;
26837
26838
7
                pop_break_entry(s->cur_func);
26839
7
                pop_scope(s);  /* catch block */
26840
7
                pop_scope(s);  /* catch variable */
26841
26842
7
                if (js_is_live_code(s)) {
26843
                    /* drop the catch2 offset */
26844
7
                    emit_op(s, OP_drop);
26845
                    /* XXX: should keep the address to nop it out if there is no finally block */
26846
                    /* must push dummy value to keep same stack size */
26847
7
                    emit_op(s, OP_undefined);
26848
7
                    emit_goto(s, OP_gosub, label_finally);
26849
7
                    emit_op(s, OP_drop);
26850
7
                    emit_goto(s, OP_goto, label_end);
26851
7
                }
26852
                /* catch exceptions thrown in the catch block to execute the
26853
                 * finally clause and rethrow the exception */
26854
7
                emit_label(s, label_catch2);
26855
                /* catch value is at TOS, no need to push undefined */
26856
7
                emit_goto(s, OP_gosub, label_finally);
26857
7
                emit_op(s, OP_throw);
26858
26859
7
            } else if (s->token.val == TOK_FINALLY) {
26860
                /* finally without catch : execute the finally clause
26861
                 * and rethrow the exception */
26862
0
                emit_label(s, label_catch);
26863
                /* catch value is at TOS, no need to push undefined */
26864
0
                emit_goto(s, OP_gosub, label_finally);
26865
0
                emit_op(s, OP_throw);
26866
0
            } else {
26867
0
                js_parse_error(s, "expecting catch or finally");
26868
0
                goto fail;
26869
0
            }
26870
7
            emit_label(s, label_finally);
26871
7
            if (s->token.val == TOK_FINALLY) {
26872
0
                int saved_eval_ret_idx = 0; /* avoid warning */
26873
                
26874
0
                if (next_token(s))
26875
0
                    goto fail;
26876
                /* on the stack: ret_value gosub_ret_value */
26877
0
                push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
26878
0
                                 -1, -1, 2);
26879
26880
0
                if (s->cur_func->eval_ret_idx >= 0) {
26881
                    /* 'finally' updates eval_ret only if not a normal
26882
                       termination */
26883
0
                    saved_eval_ret_idx =
26884
0
                        add_var(s->ctx, s->cur_func, JS_ATOM__ret_);
26885
0
                    if (saved_eval_ret_idx < 0)
26886
0
                        goto fail;
26887
0
                    emit_op(s, OP_get_loc);
26888
0
                    emit_u16(s, s->cur_func->eval_ret_idx);
26889
0
                    emit_op(s, OP_put_loc);
26890
0
                    emit_u16(s, saved_eval_ret_idx);
26891
0
                    set_eval_ret_undefined(s);
26892
0
                }
26893
                
26894
0
                if (js_parse_block(s))
26895
0
                    goto fail;
26896
26897
0
                if (s->cur_func->eval_ret_idx >= 0) {
26898
0
                    emit_op(s, OP_get_loc);
26899
0
                    emit_u16(s, saved_eval_ret_idx);
26900
0
                    emit_op(s, OP_put_loc);
26901
0
                    emit_u16(s, s->cur_func->eval_ret_idx);
26902
0
                }
26903
0
                pop_break_entry(s->cur_func);
26904
0
            }
26905
7
            emit_op(s, OP_ret);
26906
7
            emit_label(s, label_end);
26907
7
        }
26908
0
        break;
26909
7.19k
    case ';':
26910
        /* empty statement */
26911
7.19k
        if (next_token(s))
26912
0
            goto fail;
26913
7.19k
        break;
26914
11.3k
    case TOK_WITH:
26915
11.3k
        if (s->cur_func->js_mode & JS_MODE_STRICT) {
26916
0
            js_parse_error(s, "invalid keyword: with");
26917
0
            goto fail;
26918
11.3k
        } else {
26919
11.3k
            int with_idx;
26920
26921
11.3k
            if (next_token(s))
26922
0
                goto fail;
26923
26924
11.3k
            if (js_parse_expr_paren(s))
26925
6
                goto fail;
26926
26927
11.2k
            push_scope(s);
26928
11.2k
            with_idx = define_var(s, s->cur_func, JS_ATOM__with_,
26929
11.2k
                                  JS_VAR_DEF_WITH);
26930
11.2k
            if (with_idx < 0)
26931
0
                goto fail;
26932
11.2k
            emit_op(s, OP_to_object);
26933
11.2k
            emit_op(s, OP_put_loc);
26934
11.2k
            emit_u16(s, with_idx);
26935
26936
11.2k
            set_eval_ret_undefined(s);
26937
11.2k
            if (js_parse_statement(s))
26938
106
                goto fail;
26939
26940
            /* Popping scope drops lexical context for the with object variable */
26941
11.1k
            pop_scope(s);
26942
11.1k
        }
26943
11.1k
        break;
26944
11.1k
    case TOK_FUNCTION:
26945
        /* ES6 Annex B.3.2 and B.3.3 semantics */
26946
1.60k
        if (!(decl_mask & DECL_MASK_FUNC))
26947
2
            goto func_decl_error;
26948
1.60k
        if (!(decl_mask & DECL_MASK_OTHER) && peek_token(s, FALSE) == '*')
26949
0
            goto func_decl_error;
26950
1.60k
        goto parse_func_var;
26951
76.1k
    case TOK_IDENT:
26952
76.1k
        if (s->token.u.ident.is_reserved) {
26953
0
            js_parse_error_reserved_identifier(s);
26954
0
            goto fail;
26955
0
        }
26956
        /* Determine if `let` introduces a Declaration or an ExpressionStatement */
26957
76.1k
        switch (is_let(s, decl_mask)) {
26958
132
        case TRUE:
26959
132
            tok = TOK_LET;
26960
132
            goto haslet;
26961
76.0k
        case FALSE:
26962
76.0k
            break;
26963
0
        default:
26964
0
            goto fail;
26965
76.1k
        }
26966
76.0k
        if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
26967
76.0k
            peek_token(s, TRUE) == TOK_FUNCTION) {
26968
0
            if (!(decl_mask & DECL_MASK_OTHER)) {
26969
2
            func_decl_error:
26970
2
                js_parse_error(s, "function declarations can't appear in single-statement context");
26971
2
                goto fail;
26972
0
            }
26973
1.60k
        parse_func_var:
26974
1.60k
            if (js_parse_function_decl(s, JS_PARSE_FUNC_VAR,
26975
1.60k
                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
26976
1.60k
                                       s->token.ptr, s->token.line_num))
26977
98
                goto fail;
26978
1.50k
            break;
26979
1.60k
        }
26980
76.0k
        goto hasexpr;
26981
26982
76.0k
    case TOK_CLASS:
26983
31
        if (!(decl_mask & DECL_MASK_OTHER)) {
26984
0
            js_parse_error(s, "class declarations can't appear in single-statement context");
26985
0
            goto fail;
26986
0
        }
26987
31
        if (js_parse_class(s, FALSE, JS_PARSE_EXPORT_NONE))
26988
2
            return -1;
26989
29
        break;
26990
26991
29
    case TOK_DEBUGGER:
26992
        /* currently no debugger, so just skip the keyword */
26993
0
        if (next_token(s))
26994
0
            goto fail;
26995
0
        if (js_parse_expect_semi(s))
26996
0
            goto fail;
26997
0
        break;
26998
        
26999
0
    case TOK_ENUM:
27000
0
    case TOK_EXPORT:
27001
0
    case TOK_EXTENDS:
27002
0
        js_unsupported_keyword(s, s->token.u.ident.atom);
27003
0
        goto fail;
27004
27005
22.3k
    default:
27006
98.3k
    hasexpr:
27007
98.3k
        if (js_parse_expr(s))
27008
618
            goto fail;
27009
97.7k
        if (s->cur_func->eval_ret_idx >= 0) {
27010
            /* store the expression value so that it can be returned
27011
               by eval() */
27012
60.6k
            emit_op(s, OP_put_loc);
27013
60.6k
            emit_u16(s, s->cur_func->eval_ret_idx);
27014
60.6k
        } else {
27015
37.0k
            emit_op(s, OP_drop); /* drop the result */
27016
37.0k
        }
27017
97.7k
        if (js_parse_expect_semi(s))
27018
36
            goto fail;
27019
97.7k
        break;
27020
140k
    }
27021
141k
done:
27022
141k
    JS_FreeAtom(ctx, label_name);
27023
141k
    return 0;
27024
2.58k
fail:
27025
2.58k
    JS_FreeAtom(ctx, label_name);
27026
2.58k
    return -1;
27027
140k
}
27028
27029
/* 'name' is freed */
27030
static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
27031
1.41k
{
27032
1.41k
    JSModuleDef *m;
27033
1.41k
    m = js_mallocz(ctx, sizeof(*m));
27034
1.41k
    if (!m) {
27035
0
        JS_FreeAtom(ctx, name);
27036
0
        return NULL;
27037
0
    }
27038
1.41k
    m->header.ref_count = 1;
27039
1.41k
    m->module_name = name;
27040
1.41k
    m->module_ns = JS_UNDEFINED;
27041
1.41k
    m->func_obj = JS_UNDEFINED;
27042
1.41k
    m->eval_exception = JS_UNDEFINED;
27043
1.41k
    m->meta_obj = JS_UNDEFINED;
27044
1.41k
    list_add_tail(&m->link, &ctx->loaded_modules);
27045
1.41k
    return m;
27046
1.41k
}
27047
27048
static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
27049
                               JS_MarkFunc *mark_func)
27050
1.70k
{
27051
1.70k
    int i;
27052
27053
1.70k
    for(i = 0; i < m->export_entries_count; i++) {
27054
0
        JSExportEntry *me = &m->export_entries[i];
27055
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL &&
27056
0
            me->u.local.var_ref) {
27057
0
            mark_func(rt, &me->u.local.var_ref->header);
27058
0
        }
27059
0
    }
27060
27061
1.70k
    JS_MarkValue(rt, m->module_ns, mark_func);
27062
1.70k
    JS_MarkValue(rt, m->func_obj, mark_func);
27063
1.70k
    JS_MarkValue(rt, m->eval_exception, mark_func);
27064
1.70k
    JS_MarkValue(rt, m->meta_obj, mark_func);
27065
1.70k
}
27066
27067
static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
27068
1.29k
{
27069
1.29k
    int i;
27070
27071
1.29k
    JS_FreeAtom(ctx, m->module_name);
27072
27073
1.29k
    for(i = 0; i < m->req_module_entries_count; i++) {
27074
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
27075
0
        JS_FreeAtom(ctx, rme->module_name);
27076
0
    }
27077
1.29k
    js_free(ctx, m->req_module_entries);
27078
27079
1.29k
    for(i = 0; i < m->export_entries_count; i++) {
27080
0
        JSExportEntry *me = &m->export_entries[i];
27081
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL)
27082
0
            free_var_ref(ctx->rt, me->u.local.var_ref);
27083
0
        JS_FreeAtom(ctx, me->export_name);
27084
0
        JS_FreeAtom(ctx, me->local_name);
27085
0
    }
27086
1.29k
    js_free(ctx, m->export_entries);
27087
27088
1.29k
    js_free(ctx, m->star_export_entries);
27089
27090
1.29k
    for(i = 0; i < m->import_entries_count; i++) {
27091
0
        JSImportEntry *mi = &m->import_entries[i];
27092
0
        JS_FreeAtom(ctx, mi->import_name);
27093
0
    }
27094
1.29k
    js_free(ctx, m->import_entries);
27095
27096
1.29k
    JS_FreeValue(ctx, m->module_ns);
27097
1.29k
    JS_FreeValue(ctx, m->func_obj);
27098
1.29k
    JS_FreeValue(ctx, m->eval_exception);
27099
1.29k
    JS_FreeValue(ctx, m->meta_obj);
27100
1.29k
    list_del(&m->link);
27101
1.29k
    js_free(ctx, m);
27102
1.29k
}
27103
27104
static int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
27105
                                JSAtom module_name)
27106
0
{
27107
0
    JSReqModuleEntry *rme;
27108
0
    int i;
27109
27110
    /* no need to add the module request if it is already present */
27111
0
    for(i = 0; i < m->req_module_entries_count; i++) {
27112
0
        rme = &m->req_module_entries[i];
27113
0
        if (rme->module_name == module_name)
27114
0
            return i;
27115
0
    }
27116
27117
0
    if (js_resize_array(ctx, (void **)&m->req_module_entries,
27118
0
                        sizeof(JSReqModuleEntry),
27119
0
                        &m->req_module_entries_size,
27120
0
                        m->req_module_entries_count + 1))
27121
0
        return -1;
27122
0
    rme = &m->req_module_entries[m->req_module_entries_count++];
27123
0
    rme->module_name = JS_DupAtom(ctx, module_name);
27124
0
    rme->module = NULL;
27125
0
    return i;
27126
0
}
27127
27128
static JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m,
27129
                                        JSAtom export_name)
27130
0
{
27131
0
    JSExportEntry *me;
27132
0
    int i;
27133
0
    for(i = 0; i < m->export_entries_count; i++) {
27134
0
        me = &m->export_entries[i];
27135
0
        if (me->export_name == export_name)
27136
0
            return me;
27137
0
    }
27138
0
    return NULL;
27139
0
}
27140
27141
static JSExportEntry *add_export_entry2(JSContext *ctx,
27142
                                        JSParseState *s, JSModuleDef *m,
27143
                                       JSAtom local_name, JSAtom export_name,
27144
                                       JSExportTypeEnum export_type)
27145
0
{
27146
0
    JSExportEntry *me;
27147
27148
0
    if (find_export_entry(ctx, m, export_name)) {
27149
0
        char buf1[ATOM_GET_STR_BUF_SIZE];
27150
0
        if (s) {
27151
0
            js_parse_error(s, "duplicate exported name '%s'",
27152
0
                           JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name));
27153
0
        } else {
27154
0
            JS_ThrowSyntaxErrorAtom(ctx, "duplicate exported name '%s'", export_name);
27155
0
        }
27156
0
        return NULL;
27157
0
    }
27158
27159
0
    if (js_resize_array(ctx, (void **)&m->export_entries,
27160
0
                        sizeof(JSExportEntry),
27161
0
                        &m->export_entries_size,
27162
0
                        m->export_entries_count + 1))
27163
0
        return NULL;
27164
0
    me = &m->export_entries[m->export_entries_count++];
27165
0
    memset(me, 0, sizeof(*me));
27166
0
    me->local_name = JS_DupAtom(ctx, local_name);
27167
0
    me->export_name = JS_DupAtom(ctx, export_name);
27168
0
    me->export_type = export_type;
27169
0
    return me;
27170
0
}
27171
27172
static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
27173
                                       JSAtom local_name, JSAtom export_name,
27174
                                       JSExportTypeEnum export_type)
27175
0
{
27176
0
    return add_export_entry2(s->ctx, s, m, local_name, export_name,
27177
0
                             export_type);
27178
0
}
27179
27180
static int add_star_export_entry(JSContext *ctx, JSModuleDef *m,
27181
                                 int req_module_idx)
27182
0
{
27183
0
    JSStarExportEntry *se;
27184
27185
0
    if (js_resize_array(ctx, (void **)&m->star_export_entries,
27186
0
                        sizeof(JSStarExportEntry),
27187
0
                        &m->star_export_entries_size,
27188
0
                        m->star_export_entries_count + 1))
27189
0
        return -1;
27190
0
    se = &m->star_export_entries[m->star_export_entries_count++];
27191
0
    se->req_module_idx = req_module_idx;
27192
0
    return 0;
27193
0
}
27194
27195
/* create a C module */
27196
JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
27197
                           JSModuleInitFunc *func)
27198
0
{
27199
0
    JSModuleDef *m;
27200
0
    JSAtom name;
27201
0
    name = JS_NewAtom(ctx, name_str);
27202
0
    if (name == JS_ATOM_NULL)
27203
0
        return NULL;
27204
0
    m = js_new_module_def(ctx, name);
27205
0
    m->init_func = func;
27206
0
    return m;
27207
0
}
27208
27209
int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name)
27210
0
{
27211
0
    JSExportEntry *me;
27212
0
    JSAtom name;
27213
0
    name = JS_NewAtom(ctx, export_name);
27214
0
    if (name == JS_ATOM_NULL)
27215
0
        return -1;
27216
0
    me = add_export_entry2(ctx, NULL, m, JS_ATOM_NULL, name,
27217
0
                           JS_EXPORT_TYPE_LOCAL);
27218
0
    JS_FreeAtom(ctx, name);
27219
0
    if (!me)
27220
0
        return -1;
27221
0
    else
27222
0
        return 0;
27223
0
}
27224
27225
int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
27226
                       JSValue val)
27227
0
{
27228
0
    JSExportEntry *me;
27229
0
    JSAtom name;
27230
0
    name = JS_NewAtom(ctx, export_name);
27231
0
    if (name == JS_ATOM_NULL)
27232
0
        goto fail;
27233
0
    me = find_export_entry(ctx, m, name);
27234
0
    JS_FreeAtom(ctx, name);
27235
0
    if (!me)
27236
0
        goto fail;
27237
0
    set_value(ctx, me->u.local.var_ref->pvalue, val);
27238
0
    return 0;
27239
0
 fail:
27240
0
    JS_FreeValue(ctx, val);
27241
0
    return -1;
27242
0
}
27243
27244
void JS_SetModuleLoaderFunc(JSRuntime *rt,
27245
                            JSModuleNormalizeFunc *module_normalize,
27246
                            JSModuleLoaderFunc *module_loader, void *opaque)
27247
2
{
27248
2
    rt->module_normalize_func = module_normalize;
27249
2
    rt->module_loader_func = module_loader;
27250
2
    rt->module_loader_opaque = opaque;
27251
2
}
27252
27253
/* default module filename normalizer */
27254
static char *js_default_module_normalize_name(JSContext *ctx,
27255
                                              const char *base_name,
27256
                                              const char *name)
27257
109k
{
27258
109k
    char *filename, *p;
27259
109k
    const char *r;
27260
109k
    int len;
27261
27262
109k
    if (name[0] != '.') {
27263
        /* if no initial dot, the module name is not modified */
27264
109k
        return js_strdup(ctx, name);
27265
109k
    }
27266
27267
0
    p = strrchr(base_name, '/');
27268
0
    if (p)
27269
0
        len = p - base_name;
27270
0
    else
27271
0
        len = 0;
27272
27273
0
    filename = js_malloc(ctx, len + strlen(name) + 1 + 1);
27274
0
    if (!filename)
27275
0
        return NULL;
27276
0
    memcpy(filename, base_name, len);
27277
0
    filename[len] = '\0';
27278
27279
    /* we only normalize the leading '..' or '.' */
27280
0
    r = name;
27281
0
    for(;;) {
27282
0
        if (r[0] == '.' && r[1] == '/') {
27283
0
            r += 2;
27284
0
        } else if (r[0] == '.' && r[1] == '.' && r[2] == '/') {
27285
            /* remove the last path element of filename, except if "."
27286
               or ".." */
27287
0
            if (filename[0] == '\0')
27288
0
                break;
27289
0
            p = strrchr(filename, '/');
27290
0
            if (!p)
27291
0
                p = filename;
27292
0
            else
27293
0
                p++;
27294
0
            if (!strcmp(p, ".") || !strcmp(p, ".."))
27295
0
                break;
27296
0
            if (p > filename)
27297
0
                p--;
27298
0
            *p = '\0';
27299
0
            r += 3;
27300
0
        } else {
27301
0
            break;
27302
0
        }
27303
0
    }
27304
0
    if (filename[0] != '\0')
27305
0
        strcat(filename, "/");
27306
0
    strcat(filename, r);
27307
    //    printf("normalize: %s %s -> %s\n", base_name, name, filename);
27308
0
    return filename;
27309
0
}
27310
27311
static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name)
27312
109k
{
27313
109k
    struct list_head *el;
27314
109k
    JSModuleDef *m;
27315
    
27316
    /* first look at the loaded modules */
27317
8.52M
    list_for_each(el, &ctx->loaded_modules) {
27318
8.52M
        m = list_entry(el, JSModuleDef, link);
27319
8.52M
        if (m->module_name == name)
27320
0
            return m;
27321
8.52M
    }
27322
109k
    return NULL;
27323
109k
}
27324
27325
/* return NULL in case of exception (e.g. module could not be loaded) */
27326
static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx,
27327
                                                    const char *base_cname,
27328
                                                    const char *cname1)
27329
109k
{
27330
109k
    JSRuntime *rt = ctx->rt;
27331
109k
    JSModuleDef *m;
27332
109k
    char *cname;
27333
109k
    JSAtom module_name;
27334
27335
109k
    if (!rt->module_normalize_func) {
27336
109k
        cname = js_default_module_normalize_name(ctx, base_cname, cname1);
27337
109k
    } else {
27338
0
        cname = rt->module_normalize_func(ctx, base_cname, cname1,
27339
0
                                          rt->module_loader_opaque);
27340
0
    }
27341
109k
    if (!cname)
27342
0
        return NULL;
27343
27344
109k
    module_name = JS_NewAtom(ctx, cname);
27345
109k
    if (module_name == JS_ATOM_NULL) {
27346
0
        js_free(ctx, cname);
27347
0
        return NULL;
27348
0
    }
27349
27350
    /* first look at the loaded modules */
27351
109k
    m = js_find_loaded_module(ctx, module_name);
27352
109k
    if (m) {
27353
0
        js_free(ctx, cname);
27354
0
        JS_FreeAtom(ctx, module_name);
27355
0
        return m;
27356
0
    }
27357
27358
109k
    JS_FreeAtom(ctx, module_name);
27359
27360
    /* load the module */
27361
109k
    if (!rt->module_loader_func) {
27362
        /* XXX: use a syntax error ? */
27363
0
        JS_ThrowReferenceError(ctx, "could not load module '%s'",
27364
0
                               cname);
27365
0
        js_free(ctx, cname);
27366
0
        return NULL;
27367
0
    }
27368
27369
109k
    m = rt->module_loader_func(ctx, cname, rt->module_loader_opaque);
27370
109k
    js_free(ctx, cname);
27371
109k
    return m;
27372
109k
}
27373
27374
static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx,
27375
                                                    JSAtom base_module_name,
27376
                                                    JSAtom module_name1)
27377
0
{
27378
0
    const char *base_cname, *cname;
27379
0
    JSModuleDef *m;
27380
    
27381
0
    base_cname = JS_AtomToCString(ctx, base_module_name);
27382
0
    if (!base_cname)
27383
0
        return NULL;
27384
0
    cname = JS_AtomToCString(ctx, module_name1);
27385
0
    if (!cname) {
27386
0
        JS_FreeCString(ctx, base_cname);
27387
0
        return NULL;
27388
0
    }
27389
0
    m = js_host_resolve_imported_module(ctx, base_cname, cname);
27390
0
    JS_FreeCString(ctx, base_cname);
27391
0
    JS_FreeCString(ctx, cname);
27392
0
    return m;
27393
0
}
27394
27395
typedef struct JSResolveEntry {
27396
    JSModuleDef *module;
27397
    JSAtom name;
27398
} JSResolveEntry;
27399
27400
typedef struct JSResolveState {
27401
    JSResolveEntry *array;
27402
    int size;
27403
    int count;
27404
} JSResolveState;
27405
27406
static int find_resolve_entry(JSResolveState *s,
27407
                              JSModuleDef *m, JSAtom name)
27408
0
{
27409
0
    int i;
27410
0
    for(i = 0; i < s->count; i++) {
27411
0
        JSResolveEntry *re = &s->array[i];
27412
0
        if (re->module == m && re->name == name)
27413
0
            return i;
27414
0
    }
27415
0
    return -1;
27416
0
}
27417
27418
static int add_resolve_entry(JSContext *ctx, JSResolveState *s,
27419
                             JSModuleDef *m, JSAtom name)
27420
0
{
27421
0
    JSResolveEntry *re;
27422
27423
0
    if (js_resize_array(ctx, (void **)&s->array,
27424
0
                        sizeof(JSResolveEntry),
27425
0
                        &s->size, s->count + 1))
27426
0
        return -1;
27427
0
    re = &s->array[s->count++];
27428
0
    re->module = m;
27429
0
    re->name = JS_DupAtom(ctx, name);
27430
0
    return 0;
27431
0
}
27432
27433
typedef enum JSResolveResultEnum {
27434
    JS_RESOLVE_RES_EXCEPTION = -1, /* memory alloc error */
27435
    JS_RESOLVE_RES_FOUND = 0,
27436
    JS_RESOLVE_RES_NOT_FOUND,
27437
    JS_RESOLVE_RES_CIRCULAR,
27438
    JS_RESOLVE_RES_AMBIGUOUS,
27439
} JSResolveResultEnum;
27440
27441
static JSResolveResultEnum js_resolve_export1(JSContext *ctx,
27442
                                              JSModuleDef **pmodule,
27443
                                              JSExportEntry **pme,
27444
                                              JSModuleDef *m,
27445
                                              JSAtom export_name,
27446
                                              JSResolveState *s)
27447
0
{
27448
0
    JSExportEntry *me;
27449
27450
0
    *pmodule = NULL;
27451
0
    *pme = NULL;
27452
0
    if (find_resolve_entry(s, m, export_name) >= 0)
27453
0
        return JS_RESOLVE_RES_CIRCULAR;
27454
0
    if (add_resolve_entry(ctx, s, m, export_name) < 0)
27455
0
        return JS_RESOLVE_RES_EXCEPTION;
27456
0
    me = find_export_entry(ctx, m, export_name);
27457
0
    if (me) {
27458
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
27459
            /* local export */
27460
0
            *pmodule = m;
27461
0
            *pme = me;
27462
0
            return JS_RESOLVE_RES_FOUND;
27463
0
        } else {
27464
            /* indirect export */
27465
0
            JSModuleDef *m1;
27466
0
            m1 = m->req_module_entries[me->u.req_module_idx].module;
27467
0
            if (me->local_name == JS_ATOM__star_) {
27468
                /* export ns from */
27469
0
                *pmodule = m;
27470
0
                *pme = me;
27471
0
                return JS_RESOLVE_RES_FOUND;
27472
0
            } else {
27473
0
                return js_resolve_export1(ctx, pmodule, pme, m1,
27474
0
                                          me->local_name, s);
27475
0
            }
27476
0
        }
27477
0
    } else {
27478
0
        if (export_name != JS_ATOM_default) {
27479
            /* not found in direct or indirect exports: try star exports */
27480
0
            int i;
27481
27482
0
            for(i = 0; i < m->star_export_entries_count; i++) {
27483
0
                JSStarExportEntry *se = &m->star_export_entries[i];
27484
0
                JSModuleDef *m1, *res_m;
27485
0
                JSExportEntry *res_me;
27486
0
                JSResolveResultEnum ret;
27487
27488
0
                m1 = m->req_module_entries[se->req_module_idx].module;
27489
0
                ret = js_resolve_export1(ctx, &res_m, &res_me, m1,
27490
0
                                         export_name, s);
27491
0
                if (ret == JS_RESOLVE_RES_AMBIGUOUS ||
27492
0
                    ret == JS_RESOLVE_RES_EXCEPTION) {
27493
0
                    return ret;
27494
0
                } else if (ret == JS_RESOLVE_RES_FOUND) {
27495
0
                    if (*pme != NULL) {
27496
0
                        if (*pmodule != res_m ||
27497
0
                            res_me->local_name != (*pme)->local_name) {
27498
0
                            *pmodule = NULL;
27499
0
                            *pme = NULL;
27500
0
                            return JS_RESOLVE_RES_AMBIGUOUS;
27501
0
                        }
27502
0
                    } else {
27503
0
                        *pmodule = res_m;
27504
0
                        *pme = res_me;
27505
0
                    }
27506
0
                }
27507
0
            }
27508
0
            if (*pme != NULL)
27509
0
                return JS_RESOLVE_RES_FOUND;
27510
0
        }
27511
0
        return JS_RESOLVE_RES_NOT_FOUND;
27512
0
    }
27513
0
}
27514
27515
/* If the return value is JS_RESOLVE_RES_FOUND, return the module
27516
  (*pmodule) and the corresponding local export entry
27517
  (*pme). Otherwise return (NULL, NULL) */
27518
static JSResolveResultEnum js_resolve_export(JSContext *ctx,
27519
                                             JSModuleDef **pmodule,
27520
                                             JSExportEntry **pme,
27521
                                             JSModuleDef *m,
27522
                                             JSAtom export_name)
27523
0
{
27524
0
    JSResolveState ss, *s = &ss;
27525
0
    int i;
27526
0
    JSResolveResultEnum ret;
27527
27528
0
    s->array = NULL;
27529
0
    s->size = 0;
27530
0
    s->count = 0;
27531
27532
0
    ret = js_resolve_export1(ctx, pmodule, pme, m, export_name, s);
27533
27534
0
    for(i = 0; i < s->count; i++)
27535
0
        JS_FreeAtom(ctx, s->array[i].name);
27536
0
    js_free(ctx, s->array);
27537
27538
0
    return ret;
27539
0
}
27540
27541
static void js_resolve_export_throw_error(JSContext *ctx,
27542
                                          JSResolveResultEnum res,
27543
                                          JSModuleDef *m, JSAtom export_name)
27544
0
{
27545
0
    char buf1[ATOM_GET_STR_BUF_SIZE];
27546
0
    char buf2[ATOM_GET_STR_BUF_SIZE];
27547
0
    switch(res) {
27548
0
    case JS_RESOLVE_RES_EXCEPTION:
27549
0
        break;
27550
0
    default:
27551
0
    case JS_RESOLVE_RES_NOT_FOUND:
27552
0
        JS_ThrowSyntaxError(ctx, "Could not find export '%s' in module '%s'",
27553
0
                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
27554
0
                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
27555
0
        break;
27556
0
    case JS_RESOLVE_RES_CIRCULAR:
27557
0
        JS_ThrowSyntaxError(ctx, "circular reference when looking for export '%s' in module '%s'",
27558
0
                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
27559
0
                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
27560
0
        break;
27561
0
    case JS_RESOLVE_RES_AMBIGUOUS:
27562
0
        JS_ThrowSyntaxError(ctx, "export '%s' in module '%s' is ambiguous",
27563
0
                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
27564
0
                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
27565
0
        break;
27566
0
    }
27567
0
}
27568
27569
27570
typedef enum {
27571
    EXPORTED_NAME_AMBIGUOUS,
27572
    EXPORTED_NAME_NORMAL,
27573
    EXPORTED_NAME_NS,
27574
} ExportedNameEntryEnum;
27575
27576
typedef struct ExportedNameEntry {
27577
    JSAtom export_name;
27578
    ExportedNameEntryEnum export_type;
27579
    union {
27580
        JSExportEntry *me; /* using when the list is built */
27581
        JSVarRef *var_ref; /* EXPORTED_NAME_NORMAL */
27582
        JSModuleDef *module; /* for EXPORTED_NAME_NS */
27583
    } u;
27584
} ExportedNameEntry;
27585
27586
typedef struct GetExportNamesState {
27587
    JSModuleDef **modules;
27588
    int modules_size;
27589
    int modules_count;
27590
27591
    ExportedNameEntry *exported_names;
27592
    int exported_names_size;
27593
    int exported_names_count;
27594
} GetExportNamesState;
27595
27596
static int find_exported_name(GetExportNamesState *s, JSAtom name)
27597
0
{
27598
0
    int i;
27599
0
    for(i = 0; i < s->exported_names_count; i++) {
27600
0
        if (s->exported_names[i].export_name == name)
27601
0
            return i;
27602
0
    }
27603
0
    return -1;
27604
0
}
27605
27606
static __exception int get_exported_names(JSContext *ctx,
27607
                                          GetExportNamesState *s,
27608
                                          JSModuleDef *m, BOOL from_star)
27609
0
{
27610
0
    ExportedNameEntry *en;
27611
0
    int i, j;
27612
27613
    /* check circular reference */
27614
0
    for(i = 0; i < s->modules_count; i++) {
27615
0
        if (s->modules[i] == m)
27616
0
            return 0;
27617
0
    }
27618
0
    if (js_resize_array(ctx, (void **)&s->modules, sizeof(s->modules[0]),
27619
0
                        &s->modules_size, s->modules_count + 1))
27620
0
        return -1;
27621
0
    s->modules[s->modules_count++] = m;
27622
27623
0
    for(i = 0; i < m->export_entries_count; i++) {
27624
0
        JSExportEntry *me = &m->export_entries[i];
27625
0
        if (from_star && me->export_name == JS_ATOM_default)
27626
0
            continue;
27627
0
        j = find_exported_name(s, me->export_name);
27628
0
        if (j < 0) {
27629
0
            if (js_resize_array(ctx, (void **)&s->exported_names, sizeof(s->exported_names[0]),
27630
0
                                &s->exported_names_size,
27631
0
                                s->exported_names_count + 1))
27632
0
                return -1;
27633
0
            en = &s->exported_names[s->exported_names_count++];
27634
0
            en->export_name = me->export_name;
27635
            /* avoid a second lookup for simple module exports */
27636
0
            if (from_star || me->export_type != JS_EXPORT_TYPE_LOCAL)
27637
0
                en->u.me = NULL;
27638
0
            else
27639
0
                en->u.me = me;
27640
0
        } else {
27641
0
            en = &s->exported_names[j];
27642
0
            en->u.me = NULL;
27643
0
        }
27644
0
    }
27645
0
    for(i = 0; i < m->star_export_entries_count; i++) {
27646
0
        JSStarExportEntry *se = &m->star_export_entries[i];
27647
0
        JSModuleDef *m1;
27648
0
        m1 = m->req_module_entries[se->req_module_idx].module;
27649
0
        if (get_exported_names(ctx, s, m1, TRUE))
27650
0
            return -1;
27651
0
    }
27652
0
    return 0;
27653
0
}
27654
27655
/* Unfortunately, the spec gives a different behavior from GetOwnProperty ! */
27656
static int js_module_ns_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
27657
0
{
27658
0
    return (find_own_property1(JS_VALUE_GET_OBJ(obj), atom) != NULL);
27659
0
}
27660
27661
static const JSClassExoticMethods js_module_ns_exotic_methods = {
27662
    .has_property = js_module_ns_has,
27663
};
27664
27665
static int exported_names_cmp(const void *p1, const void *p2, void *opaque)
27666
0
{
27667
0
    JSContext *ctx = opaque;
27668
0
    const ExportedNameEntry *me1 = p1;
27669
0
    const ExportedNameEntry *me2 = p2;
27670
0
    JSValue str1, str2;
27671
0
    int ret;
27672
27673
    /* XXX: should avoid allocation memory in atom comparison */
27674
0
    str1 = JS_AtomToString(ctx, me1->export_name);
27675
0
    str2 = JS_AtomToString(ctx, me2->export_name);
27676
0
    if (JS_IsException(str1) || JS_IsException(str2)) {
27677
        /* XXX: raise an error ? */
27678
0
        ret = 0;
27679
0
    } else {
27680
0
        ret = js_string_compare(ctx, JS_VALUE_GET_STRING(str1),
27681
0
                                JS_VALUE_GET_STRING(str2));
27682
0
    }
27683
0
    JS_FreeValue(ctx, str1);
27684
0
    JS_FreeValue(ctx, str2);
27685
0
    return ret;
27686
0
}
27687
27688
static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m);
27689
27690
static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
27691
                                     void *opaque)
27692
0
{
27693
0
    JSModuleDef *m = opaque;
27694
0
    return js_get_module_ns(ctx, m);
27695
0
}
27696
27697
static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
27698
0
{
27699
0
    JSValue obj;
27700
0
    JSObject *p;
27701
0
    GetExportNamesState s_s, *s = &s_s;
27702
0
    int i, ret;
27703
0
    JSProperty *pr;
27704
27705
0
    obj = JS_NewObjectClass(ctx, JS_CLASS_MODULE_NS);
27706
0
    if (JS_IsException(obj))
27707
0
        return obj;
27708
0
    p = JS_VALUE_GET_OBJ(obj);
27709
27710
0
    memset(s, 0, sizeof(*s));
27711
0
    ret = get_exported_names(ctx, s, m, FALSE);
27712
0
    js_free(ctx, s->modules);
27713
0
    if (ret)
27714
0
        goto fail;
27715
27716
    /* Resolve the exported names. The ambiguous exports are removed */
27717
0
    for(i = 0; i < s->exported_names_count; i++) {
27718
0
        ExportedNameEntry *en = &s->exported_names[i];
27719
0
        JSResolveResultEnum res;
27720
0
        JSExportEntry *res_me;
27721
0
        JSModuleDef *res_m;
27722
27723
0
        if (en->u.me) {
27724
0
            res_me = en->u.me; /* fast case: no resolution needed */
27725
0
            res_m = m;
27726
0
            res = JS_RESOLVE_RES_FOUND;
27727
0
        } else {
27728
0
            res = js_resolve_export(ctx, &res_m, &res_me, m,
27729
0
                                    en->export_name);
27730
0
        }
27731
0
        if (res != JS_RESOLVE_RES_FOUND) {
27732
0
            if (res != JS_RESOLVE_RES_AMBIGUOUS) {
27733
0
                js_resolve_export_throw_error(ctx, res, m, en->export_name);
27734
0
                goto fail;
27735
0
            }
27736
0
            en->export_type = EXPORTED_NAME_AMBIGUOUS;
27737
0
        } else {
27738
0
            if (res_me->local_name == JS_ATOM__star_) {
27739
0
                en->export_type = EXPORTED_NAME_NS;
27740
0
                en->u.module = res_m->req_module_entries[res_me->u.req_module_idx].module;
27741
0
            } else {
27742
0
                en->export_type = EXPORTED_NAME_NORMAL;
27743
0
                if (res_me->u.local.var_ref) {
27744
0
                    en->u.var_ref = res_me->u.local.var_ref;
27745
0
                } else {
27746
0
                    JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
27747
0
                    p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
27748
0
                    en->u.var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
27749
0
                }
27750
0
            }
27751
0
        }
27752
0
    }
27753
27754
    /* sort the exported names */
27755
0
    rqsort(s->exported_names, s->exported_names_count,
27756
0
           sizeof(s->exported_names[0]), exported_names_cmp, ctx);
27757
27758
0
    for(i = 0; i < s->exported_names_count; i++) {
27759
0
        ExportedNameEntry *en = &s->exported_names[i];
27760
0
        switch(en->export_type) {
27761
0
        case EXPORTED_NAME_NORMAL:
27762
0
            {
27763
0
                JSVarRef *var_ref = en->u.var_ref;
27764
0
                pr = add_property(ctx, p, en->export_name,
27765
0
                                  JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
27766
0
                                  JS_PROP_VARREF);
27767
0
                if (!pr)
27768
0
                    goto fail;
27769
0
                var_ref->header.ref_count++;
27770
0
                pr->u.var_ref = var_ref;
27771
0
            }
27772
0
            break;
27773
0
        case EXPORTED_NAME_NS:
27774
            /* the exported namespace must be created on demand */
27775
0
            if (JS_DefineAutoInitProperty(ctx, obj,
27776
0
                                          en->export_name,
27777
0
                                          JS_AUTOINIT_ID_MODULE_NS,
27778
0
                                          en->u.module, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
27779
0
                goto fail;
27780
0
            break;
27781
0
        default:
27782
0
            break;
27783
0
        }
27784
0
    }
27785
27786
0
    js_free(ctx, s->exported_names);
27787
27788
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_toStringTag,
27789
0
                           JS_AtomToString(ctx, JS_ATOM_Module),
27790
0
                           0);
27791
27792
0
    p->extensible = FALSE;
27793
0
    return obj;
27794
0
 fail:
27795
0
    js_free(ctx, s->exported_names);
27796
0
    JS_FreeValue(ctx, obj);
27797
0
    return JS_EXCEPTION;
27798
0
}
27799
27800
static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m)
27801
0
{
27802
0
    if (JS_IsUndefined(m->module_ns)) {
27803
0
        JSValue val;
27804
0
        val = js_build_module_ns(ctx, m);
27805
0
        if (JS_IsException(val))
27806
0
            return JS_EXCEPTION;
27807
0
        m->module_ns = val;
27808
0
    }
27809
0
    return JS_DupValue(ctx, m->module_ns);
27810
0
}
27811
27812
/* Load all the required modules for module 'm' */
27813
static int js_resolve_module(JSContext *ctx, JSModuleDef *m)
27814
242
{
27815
242
    int i;
27816
242
    JSModuleDef *m1;
27817
27818
242
    if (m->resolved)
27819
0
        return 0;
27820
#ifdef DUMP_MODULE_RESOLVE
27821
    {
27822
        char buf1[ATOM_GET_STR_BUF_SIZE];
27823
        printf("resolving module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
27824
    }
27825
#endif
27826
242
    m->resolved = TRUE;
27827
    /* resolve each requested module */
27828
242
    for(i = 0; i < m->req_module_entries_count; i++) {
27829
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
27830
0
        m1 = js_host_resolve_imported_module_atom(ctx, m->module_name,
27831
0
                                                  rme->module_name);
27832
0
        if (!m1)
27833
0
            return -1;
27834
0
        rme->module = m1;
27835
        /* already done in js_host_resolve_imported_module() except if
27836
           the module was loaded with JS_EvalBinary() */
27837
0
        if (js_resolve_module(ctx, m1) < 0)
27838
0
            return -1;
27839
0
    }
27840
242
    return 0;
27841
242
}
27842
27843
static JSVarRef *js_create_module_var(JSContext *ctx, BOOL is_lexical)
27844
544
{
27845
544
    JSVarRef *var_ref;
27846
544
    var_ref = js_malloc(ctx, sizeof(JSVarRef));
27847
544
    if (!var_ref)
27848
1
        return NULL;
27849
543
    var_ref->header.ref_count = 1;
27850
543
    if (is_lexical)
27851
5
        var_ref->value = JS_UNINITIALIZED;
27852
538
    else
27853
538
        var_ref->value = JS_UNDEFINED;
27854
543
    var_ref->pvalue = &var_ref->value;
27855
543
    var_ref->is_detached = TRUE;
27856
543
    add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
27857
543
    return var_ref;
27858
544
}
27859
27860
/* Create the <eval> function associated with the module */
27861
static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
27862
120
{
27863
120
    JSFunctionBytecode *b;
27864
120
    int i;
27865
120
    JSVarRef **var_refs;
27866
120
    JSValue func_obj, bfunc;
27867
120
    JSObject *p;
27868
27869
120
    bfunc = m->func_obj;
27870
120
    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
27871
120
                                      JS_CLASS_BYTECODE_FUNCTION);
27872
27873
120
    if (JS_IsException(func_obj))
27874
0
        return -1;
27875
120
    b = JS_VALUE_GET_PTR(bfunc);
27876
27877
120
    p = JS_VALUE_GET_OBJ(func_obj);
27878
120
    p->u.func.function_bytecode = b;
27879
120
    b->header.ref_count++;
27880
120
    p->u.func.home_object = NULL;
27881
120
    p->u.func.var_refs = NULL;
27882
120
    if (b->closure_var_count) {
27883
24
        var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
27884
24
        if (!var_refs)
27885
0
            goto fail;
27886
24
        p->u.func.var_refs = var_refs;
27887
27888
        /* create the global variables. The other variables are
27889
           imported from other modules */
27890
567
        for(i = 0; i < b->closure_var_count; i++) {
27891
544
            JSClosureVar *cv = &b->closure_var[i];
27892
544
            JSVarRef *var_ref;
27893
544
            if (cv->is_local) {
27894
544
                var_ref = js_create_module_var(ctx, cv->is_lexical);
27895
544
                if (!var_ref)
27896
1
                    goto fail;
27897
#ifdef DUMP_MODULE_RESOLVE
27898
                printf("local %d: %p\n", i, var_ref);
27899
#endif
27900
543
                var_refs[i] = var_ref;
27901
543
            }
27902
544
        }
27903
24
    }
27904
119
    m->func_obj = func_obj;
27905
119
    JS_FreeValue(ctx, bfunc);
27906
119
    return 0;
27907
1
 fail:
27908
1
    JS_FreeValue(ctx, func_obj);
27909
1
    return -1;
27910
120
}
27911
27912
/* must be done before js_link_module() because of cyclic references */
27913
static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
27914
120
{
27915
120
    BOOL is_c_module;
27916
120
    int i;
27917
120
    JSVarRef *var_ref;
27918
    
27919
120
    if (m->func_created)
27920
0
        return 0;
27921
27922
120
    is_c_module = (m->init_func != NULL);
27923
27924
120
    if (is_c_module) {
27925
        /* initialize the exported variables */
27926
0
        for(i = 0; i < m->export_entries_count; i++) {
27927
0
            JSExportEntry *me = &m->export_entries[i];
27928
0
            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
27929
0
                var_ref = js_create_module_var(ctx, FALSE);
27930
0
                if (!var_ref)
27931
0
                    return -1;
27932
0
                me->u.local.var_ref = var_ref;
27933
0
            }
27934
0
        }
27935
120
    } else {
27936
120
        if (js_create_module_bytecode_function(ctx, m))
27937
1
            return -1;
27938
120
    }
27939
119
    m->func_created = TRUE;
27940
27941
    /* do it on the dependencies */
27942
    
27943
119
    for(i = 0; i < m->req_module_entries_count; i++) {
27944
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
27945
0
        if (js_create_module_function(ctx, rme->module) < 0)
27946
0
            return -1;
27947
0
    }
27948
27949
119
    return 0;
27950
119
}    
27951
27952
    
27953
/* Prepare a module to be executed by resolving all the imported
27954
   variables. */
27955
static int js_link_module(JSContext *ctx, JSModuleDef *m)
27956
119
{
27957
119
    int i;
27958
119
    JSImportEntry *mi;
27959
119
    JSModuleDef *m1;
27960
119
    JSVarRef **var_refs, *var_ref;
27961
119
    JSObject *p;
27962
119
    BOOL is_c_module;
27963
119
    JSValue ret_val;
27964
    
27965
119
    if (m->instantiated)
27966
0
        return 0;
27967
119
    m->instantiated = TRUE;
27968
27969
#ifdef DUMP_MODULE_RESOLVE
27970
    {
27971
        char buf1[ATOM_GET_STR_BUF_SIZE];
27972
        printf("start instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
27973
    }
27974
#endif
27975
27976
119
    for(i = 0; i < m->req_module_entries_count; i++) {
27977
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
27978
0
        if (js_link_module(ctx, rme->module) < 0)
27979
0
            goto fail;
27980
0
    }
27981
27982
#ifdef DUMP_MODULE_RESOLVE
27983
    {
27984
        char buf1[ATOM_GET_STR_BUF_SIZE];
27985
        printf("instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
27986
    }
27987
#endif
27988
    /* check the indirect exports */
27989
119
    for(i = 0; i < m->export_entries_count; i++) {
27990
0
        JSExportEntry *me = &m->export_entries[i];
27991
0
        if (me->export_type == JS_EXPORT_TYPE_INDIRECT &&
27992
0
            me->local_name != JS_ATOM__star_) {
27993
0
            JSResolveResultEnum ret;
27994
0
            JSExportEntry *res_me;
27995
0
            JSModuleDef *res_m, *m1;
27996
0
            m1 = m->req_module_entries[me->u.req_module_idx].module;
27997
0
            ret = js_resolve_export(ctx, &res_m, &res_me, m1, me->local_name);
27998
0
            if (ret != JS_RESOLVE_RES_FOUND) {
27999
0
                js_resolve_export_throw_error(ctx, ret, m, me->export_name);
28000
0
                goto fail;
28001
0
            }
28002
0
        }
28003
0
    }
28004
28005
#ifdef DUMP_MODULE_RESOLVE
28006
    {
28007
        printf("exported bindings:\n");
28008
        for(i = 0; i < m->export_entries_count; i++) {
28009
            JSExportEntry *me = &m->export_entries[i];
28010
            printf(" name="); print_atom(ctx, me->export_name);
28011
            printf(" local="); print_atom(ctx, me->local_name);
28012
            printf(" type=%d idx=%d\n", me->export_type, me->u.local.var_idx);
28013
        }
28014
    }
28015
#endif
28016
28017
119
    is_c_module = (m->init_func != NULL);
28018
28019
119
    if (!is_c_module) {
28020
119
        p = JS_VALUE_GET_OBJ(m->func_obj);
28021
119
        var_refs = p->u.func.var_refs;
28022
28023
119
        for(i = 0; i < m->import_entries_count; i++) {
28024
0
            mi = &m->import_entries[i];
28025
#ifdef DUMP_MODULE_RESOLVE
28026
            printf("import var_idx=%d name=", mi->var_idx);
28027
            print_atom(ctx, mi->import_name);
28028
            printf(": ");
28029
#endif
28030
0
            m1 = m->req_module_entries[mi->req_module_idx].module;
28031
0
            if (mi->import_name == JS_ATOM__star_) {
28032
0
                JSValue val;
28033
                /* name space import */
28034
0
                val = js_get_module_ns(ctx, m1);
28035
0
                if (JS_IsException(val))
28036
0
                    goto fail;
28037
0
                set_value(ctx, &var_refs[mi->var_idx]->value, val);
28038
#ifdef DUMP_MODULE_RESOLVE
28039
                printf("namespace\n");
28040
#endif
28041
0
            } else {
28042
0
                JSResolveResultEnum ret;
28043
0
                JSExportEntry *res_me;
28044
0
                JSModuleDef *res_m;
28045
0
                JSObject *p1;
28046
28047
0
                ret = js_resolve_export(ctx, &res_m,
28048
0
                                        &res_me, m1, mi->import_name);
28049
0
                if (ret != JS_RESOLVE_RES_FOUND) {
28050
0
                    js_resolve_export_throw_error(ctx, ret, m1, mi->import_name);
28051
0
                    goto fail;
28052
0
                }
28053
0
                if (res_me->local_name == JS_ATOM__star_) {
28054
0
                    JSValue val;
28055
0
                    JSModuleDef *m2;
28056
                    /* name space import from */
28057
0
                    m2 = res_m->req_module_entries[res_me->u.req_module_idx].module;
28058
0
                    val = js_get_module_ns(ctx, m2);
28059
0
                    if (JS_IsException(val))
28060
0
                        goto fail;
28061
0
                    var_ref = js_create_module_var(ctx, TRUE);
28062
0
                    if (!var_ref) {
28063
0
                        JS_FreeValue(ctx, val);
28064
0
                        goto fail;
28065
0
                    }
28066
0
                    set_value(ctx, &var_ref->value, val);
28067
0
                    var_refs[mi->var_idx] = var_ref;
28068
#ifdef DUMP_MODULE_RESOLVE
28069
                    printf("namespace from\n");
28070
#endif
28071
0
                } else {
28072
0
                    var_ref = res_me->u.local.var_ref;
28073
0
                    if (!var_ref) {
28074
0
                        p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
28075
0
                        var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
28076
0
                    }
28077
0
                    var_ref->header.ref_count++;
28078
0
                    var_refs[mi->var_idx] = var_ref;
28079
#ifdef DUMP_MODULE_RESOLVE
28080
                    printf("local export (var_ref=%p)\n", var_ref);
28081
#endif
28082
0
                }
28083
0
            }
28084
0
        }
28085
28086
        /* keep the exported variables in the module export entries (they
28087
           are used when the eval function is deleted and cannot be
28088
           initialized before in case imports are exported) */
28089
119
        for(i = 0; i < m->export_entries_count; i++) {
28090
0
            JSExportEntry *me = &m->export_entries[i];
28091
0
            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
28092
0
                var_ref = var_refs[me->u.local.var_idx];
28093
0
                var_ref->header.ref_count++;
28094
0
                me->u.local.var_ref = var_ref;
28095
0
            }
28096
0
        }
28097
28098
        /* initialize the global variables */
28099
119
        ret_val = JS_Call(ctx, m->func_obj, JS_TRUE, 0, NULL);
28100
119
        if (JS_IsException(ret_val))
28101
0
            goto fail;
28102
119
        JS_FreeValue(ctx, ret_val);
28103
119
    }
28104
28105
#ifdef DUMP_MODULE_RESOLVE
28106
    printf("done instantiate\n");
28107
#endif
28108
119
    return 0;
28109
0
 fail:
28110
0
    return -1;
28111
119
}
28112
28113
/* return JS_ATOM_NULL if the name cannot be found. Only works with
28114
   not striped bytecode functions. */
28115
JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
28116
208k
{
28117
208k
    JSStackFrame *sf;
28118
208k
    JSFunctionBytecode *b;
28119
208k
    JSObject *p;
28120
    /* XXX: currently we just use the filename of the englobing
28121
       function. It does not work for eval(). Need to add a
28122
       ScriptOrModule info in JSFunctionBytecode */
28123
208k
    sf = ctx->rt->current_stack_frame;
28124
208k
    if (!sf)
28125
0
        return JS_ATOM_NULL;
28126
208k
    while (n_stack_levels-- > 0) {
28127
0
        sf = sf->prev_frame;
28128
0
        if (!sf)
28129
0
            return JS_ATOM_NULL;
28130
0
    }
28131
208k
    if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT)
28132
0
        return JS_ATOM_NULL;
28133
208k
    p = JS_VALUE_GET_OBJ(sf->cur_func);
28134
208k
    if (!js_class_has_bytecode(p->class_id))
28135
0
        return JS_ATOM_NULL;
28136
208k
    b = p->u.func.function_bytecode;
28137
208k
    if (!b->has_debug)
28138
71
        return JS_ATOM_NULL;
28139
208k
    return JS_DupAtom(ctx, b->debug.filename);
28140
208k
}
28141
28142
JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m)
28143
120
{
28144
120
    return JS_DupAtom(ctx, m->module_name);
28145
120
}
28146
28147
JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m)
28148
120
{
28149
120
    JSValue obj;
28150
    /* allocate meta_obj only if requested to save memory */
28151
120
    obj = m->meta_obj;
28152
120
    if (JS_IsUndefined(obj)) {
28153
120
        obj = JS_NewObjectProto(ctx, JS_NULL);
28154
120
        if (JS_IsException(obj))
28155
0
            return JS_EXCEPTION;
28156
120
        m->meta_obj = obj;
28157
120
    }
28158
120
    return JS_DupValue(ctx, obj);
28159
120
}
28160
28161
static JSValue js_import_meta(JSContext *ctx)
28162
0
{
28163
0
    JSAtom filename;
28164
0
    JSModuleDef *m;
28165
    
28166
0
    filename = JS_GetScriptOrModuleName(ctx, 0);
28167
0
    if (filename == JS_ATOM_NULL)
28168
0
        goto fail;
28169
28170
    /* XXX: inefficient, need to add a module or script pointer in
28171
       JSFunctionBytecode */
28172
0
    m = js_find_loaded_module(ctx, filename);
28173
0
    JS_FreeAtom(ctx, filename);
28174
0
    if (!m) {
28175
0
    fail:
28176
0
        JS_ThrowTypeError(ctx, "import.meta not supported in this context");
28177
0
        return JS_EXCEPTION;
28178
0
    }
28179
0
    return JS_GetImportMeta(ctx, m);
28180
0
}
28181
28182
/* used by os.Worker() and import() */
28183
JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
28184
                          const char *filename)
28185
109k
{
28186
109k
    JSModuleDef *m;
28187
109k
    JSValue ret, func_obj;
28188
    
28189
109k
    m = js_host_resolve_imported_module(ctx, basename, filename);
28190
109k
    if (!m)
28191
109k
        return NULL;
28192
    
28193
0
    if (js_resolve_module(ctx, m) < 0) {
28194
0
        js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
28195
0
        return NULL;
28196
0
    }
28197
28198
    /* Evaluate the module code */
28199
0
    func_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
28200
0
    ret = JS_EvalFunction(ctx, func_obj);
28201
0
    if (JS_IsException(ret))
28202
0
        return NULL;
28203
0
    JS_FreeValue(ctx, ret);
28204
0
    return m;
28205
0
}
28206
28207
static JSValue js_dynamic_import_job(JSContext *ctx,
28208
                                     int argc, JSValueConst *argv)
28209
109k
{
28210
109k
    JSValueConst *resolving_funcs = argv;
28211
109k
    JSValueConst basename_val = argv[2];
28212
109k
    JSValueConst specifier = argv[3];
28213
109k
    JSModuleDef *m;
28214
109k
    const char *basename = NULL, *filename;
28215
109k
    JSValue ret, err, ns;
28216
28217
109k
    if (!JS_IsString(basename_val)) {
28218
71
        JS_ThrowTypeError(ctx, "no function filename for import()");
28219
71
        goto exception;
28220
71
    }
28221
109k
    basename = JS_ToCString(ctx, basename_val);
28222
109k
    if (!basename)
28223
0
        goto exception;
28224
28225
109k
    filename = JS_ToCString(ctx, specifier);
28226
109k
    if (!filename)
28227
0
        goto exception;
28228
                     
28229
109k
    m = JS_RunModule(ctx, basename, filename);
28230
109k
    JS_FreeCString(ctx, filename);
28231
109k
    if (!m)
28232
109k
        goto exception;
28233
28234
    /* return the module namespace */
28235
0
    ns = js_get_module_ns(ctx, m);
28236
0
    if (JS_IsException(ns))
28237
0
        goto exception;
28238
28239
0
    ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
28240
0
                   1, (JSValueConst *)&ns);
28241
0
    JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
28242
0
    JS_FreeValue(ctx, ns);
28243
0
    JS_FreeCString(ctx, basename);
28244
0
    return JS_UNDEFINED;
28245
109k
 exception:
28246
28247
109k
    err = JS_GetException(ctx);
28248
109k
    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
28249
109k
                   1, (JSValueConst *)&err);
28250
109k
    JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
28251
109k
    JS_FreeValue(ctx, err);
28252
109k
    JS_FreeCString(ctx, basename);
28253
109k
    return JS_UNDEFINED;
28254
0
}
28255
28256
static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
28257
208k
{
28258
208k
    JSAtom basename;
28259
208k
    JSValue promise, resolving_funcs[2], basename_val;
28260
208k
    JSValueConst args[4];
28261
28262
208k
    basename = JS_GetScriptOrModuleName(ctx, 0);
28263
208k
    if (basename == JS_ATOM_NULL)
28264
71
        basename_val = JS_NULL;
28265
208k
    else
28266
208k
        basename_val = JS_AtomToValue(ctx, basename);
28267
208k
    JS_FreeAtom(ctx, basename);
28268
208k
    if (JS_IsException(basename_val))
28269
0
        return basename_val;
28270
    
28271
208k
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
28272
208k
    if (JS_IsException(promise)) {
28273
4
        JS_FreeValue(ctx, basename_val);
28274
4
        return promise;
28275
4
    }
28276
28277
208k
    args[0] = resolving_funcs[0];
28278
208k
    args[1] = resolving_funcs[1];
28279
208k
    args[2] = basename_val;
28280
208k
    args[3] = specifier;
28281
    
28282
208k
    JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args);
28283
28284
208k
    JS_FreeValue(ctx, basename_val);
28285
208k
    JS_FreeValue(ctx, resolving_funcs[0]);
28286
208k
    JS_FreeValue(ctx, resolving_funcs[1]);
28287
208k
    return promise;
28288
208k
}
28289
28290
/* Run the <eval> function of the module and of all its requested
28291
   modules. */
28292
static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
28293
119
{
28294
119
    JSModuleDef *m1;
28295
119
    int i;
28296
119
    JSValue ret_val;
28297
28298
119
    if (m->eval_mark)
28299
0
        return JS_UNDEFINED; /* avoid cycles */
28300
28301
119
    if (m->evaluated) {
28302
        /* if the module was already evaluated, rethrow the exception
28303
           it raised */
28304
0
        if (m->eval_has_exception) {
28305
0
            return JS_Throw(ctx, JS_DupValue(ctx, m->eval_exception));
28306
0
        } else {
28307
0
            return JS_UNDEFINED;
28308
0
        }
28309
0
    }
28310
28311
119
    m->eval_mark = TRUE;
28312
28313
119
    for(i = 0; i < m->req_module_entries_count; i++) {
28314
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
28315
0
        m1 = rme->module;
28316
0
        if (!m1->eval_mark) {
28317
0
            ret_val = js_evaluate_module(ctx, m1);
28318
0
            if (JS_IsException(ret_val)) {
28319
0
                m->eval_mark = FALSE;
28320
0
                return ret_val;
28321
0
            }
28322
0
            JS_FreeValue(ctx, ret_val);
28323
0
        }
28324
0
    }
28325
28326
119
    if (m->init_func) {
28327
        /* C module init */
28328
0
        if (m->init_func(ctx, m) < 0)
28329
0
            ret_val = JS_EXCEPTION;
28330
0
        else
28331
0
            ret_val = JS_UNDEFINED;
28332
119
    } else {
28333
119
        ret_val = JS_CallFree(ctx, m->func_obj, JS_UNDEFINED, 0, NULL);
28334
119
        m->func_obj = JS_UNDEFINED;
28335
119
    }
28336
119
    if (JS_IsException(ret_val)) {
28337
        /* save the thrown exception value */
28338
51
        m->eval_has_exception = TRUE;
28339
51
        m->eval_exception = JS_DupValue(ctx, ctx->rt->current_exception);
28340
51
    }
28341
119
    m->eval_mark = FALSE;
28342
119
    m->evaluated = TRUE;
28343
119
    return ret_val;
28344
119
}
28345
28346
static __exception JSAtom js_parse_from_clause(JSParseState *s)
28347
0
{
28348
0
    JSAtom module_name;
28349
0
    if (!token_is_pseudo_keyword(s, JS_ATOM_from)) {
28350
0
        js_parse_error(s, "from clause expected");
28351
0
        return JS_ATOM_NULL;
28352
0
    }
28353
0
    if (next_token(s))
28354
0
        return JS_ATOM_NULL;
28355
0
    if (s->token.val != TOK_STRING) {
28356
0
        js_parse_error(s, "string expected");
28357
0
        return JS_ATOM_NULL;
28358
0
    }
28359
0
    module_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
28360
0
    if (module_name == JS_ATOM_NULL)
28361
0
        return JS_ATOM_NULL;
28362
0
    if (next_token(s)) {
28363
0
        JS_FreeAtom(s->ctx, module_name);
28364
0
        return JS_ATOM_NULL;
28365
0
    }
28366
0
    return module_name;
28367
0
}
28368
28369
static __exception int js_parse_export(JSParseState *s)
28370
0
{
28371
0
    JSContext *ctx = s->ctx;
28372
0
    JSModuleDef *m = s->cur_func->module;
28373
0
    JSAtom local_name, export_name;
28374
0
    int first_export, idx, i, tok;
28375
0
    JSAtom module_name;
28376
0
    JSExportEntry *me;
28377
28378
0
    if (next_token(s))
28379
0
        return -1;
28380
28381
0
    tok = s->token.val;
28382
0
    if (tok == TOK_CLASS) {
28383
0
        return js_parse_class(s, FALSE, JS_PARSE_EXPORT_NAMED);
28384
0
    } else if (tok == TOK_FUNCTION ||
28385
0
               (token_is_pseudo_keyword(s, JS_ATOM_async) &&
28386
0
                peek_token(s, TRUE) == TOK_FUNCTION)) {
28387
0
        return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
28388
0
                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
28389
0
                                       s->token.ptr, s->token.line_num,
28390
0
                                       JS_PARSE_EXPORT_NAMED, NULL);
28391
0
    }
28392
28393
0
    if (next_token(s))
28394
0
        return -1;
28395
28396
0
    switch(tok) {
28397
0
    case '{':
28398
0
        first_export = m->export_entries_count;
28399
0
        while (s->token.val != '}') {
28400
0
            if (!token_is_ident(s->token.val)) {
28401
0
                js_parse_error(s, "identifier expected");
28402
0
                return -1;
28403
0
            }
28404
0
            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28405
0
            export_name = JS_ATOM_NULL;
28406
0
            if (next_token(s))
28407
0
                goto fail;
28408
0
            if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
28409
0
                if (next_token(s))
28410
0
                    goto fail;
28411
0
                if (!token_is_ident(s->token.val)) {
28412
0
                    js_parse_error(s, "identifier expected");
28413
0
                    goto fail;
28414
0
                }
28415
0
                export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28416
0
                if (next_token(s)) {
28417
0
                fail:
28418
0
                    JS_FreeAtom(ctx, local_name);
28419
0
                fail1:
28420
0
                    JS_FreeAtom(ctx, export_name);
28421
0
                    return -1;
28422
0
                }
28423
0
            } else {
28424
0
                export_name = JS_DupAtom(ctx, local_name);
28425
0
            }
28426
0
            me = add_export_entry(s, m, local_name, export_name,
28427
0
                                  JS_EXPORT_TYPE_LOCAL);
28428
0
            JS_FreeAtom(ctx, local_name);
28429
0
            JS_FreeAtom(ctx, export_name);
28430
0
            if (!me)
28431
0
                return -1;
28432
0
            if (s->token.val != ',')
28433
0
                break;
28434
0
            if (next_token(s))
28435
0
                return -1;
28436
0
        }
28437
0
        if (js_parse_expect(s, '}'))
28438
0
            return -1;
28439
0
        if (token_is_pseudo_keyword(s, JS_ATOM_from)) {
28440
0
            module_name = js_parse_from_clause(s);
28441
0
            if (module_name == JS_ATOM_NULL)
28442
0
                return -1;
28443
0
            idx = add_req_module_entry(ctx, m, module_name);
28444
0
            JS_FreeAtom(ctx, module_name);
28445
0
            if (idx < 0)
28446
0
                return -1;
28447
0
            for(i = first_export; i < m->export_entries_count; i++) {
28448
0
                me = &m->export_entries[i];
28449
0
                me->export_type = JS_EXPORT_TYPE_INDIRECT;
28450
0
                me->u.req_module_idx = idx;
28451
0
            }
28452
0
        }
28453
0
        break;
28454
0
    case '*':
28455
0
        if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
28456
            /* export ns from */
28457
0
            if (next_token(s))
28458
0
                return -1;
28459
0
            if (!token_is_ident(s->token.val)) {
28460
0
                js_parse_error(s, "identifier expected");
28461
0
                return -1;
28462
0
            }
28463
0
            export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28464
0
            if (next_token(s))
28465
0
                goto fail1;
28466
0
            module_name = js_parse_from_clause(s);
28467
0
            if (module_name == JS_ATOM_NULL)
28468
0
                goto fail1;
28469
0
            idx = add_req_module_entry(ctx, m, module_name);
28470
0
            JS_FreeAtom(ctx, module_name);
28471
0
            if (idx < 0)
28472
0
                goto fail1;
28473
0
            me = add_export_entry(s, m, JS_ATOM__star_, export_name,
28474
0
                                  JS_EXPORT_TYPE_INDIRECT);
28475
0
            JS_FreeAtom(ctx, export_name);
28476
0
            if (!me)
28477
0
                return -1;
28478
0
            me->u.req_module_idx = idx;
28479
0
        } else {
28480
0
            module_name = js_parse_from_clause(s);
28481
0
            if (module_name == JS_ATOM_NULL)
28482
0
                return -1;
28483
0
            idx = add_req_module_entry(ctx, m, module_name);
28484
0
            JS_FreeAtom(ctx, module_name);
28485
0
            if (idx < 0)
28486
0
                return -1;
28487
0
            if (add_star_export_entry(ctx, m, idx) < 0)
28488
0
                return -1;
28489
0
        }
28490
0
        break;
28491
0
    case TOK_DEFAULT:
28492
0
        if (s->token.val == TOK_CLASS) {
28493
0
            return js_parse_class(s, FALSE, JS_PARSE_EXPORT_DEFAULT);
28494
0
        } else if (s->token.val == TOK_FUNCTION ||
28495
0
                   (token_is_pseudo_keyword(s, JS_ATOM_async) &&
28496
0
                    peek_token(s, TRUE) == TOK_FUNCTION)) {
28497
0
            return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
28498
0
                                           JS_FUNC_NORMAL, JS_ATOM_NULL,
28499
0
                                           s->token.ptr, s->token.line_num,
28500
0
                                           JS_PARSE_EXPORT_DEFAULT, NULL);
28501
0
        } else {
28502
0
            if (js_parse_assign_expr(s))
28503
0
                return -1;
28504
0
        }
28505
        /* set the name of anonymous functions */
28506
0
        set_object_name(s, JS_ATOM_default);
28507
28508
        /* store the value in the _default_ global variable and export
28509
           it */
28510
0
        local_name = JS_ATOM__default_;
28511
0
        if (define_var(s, s->cur_func, local_name, JS_VAR_DEF_LET) < 0)
28512
0
            return -1;
28513
0
        emit_op(s, OP_scope_put_var_init);
28514
0
        emit_atom(s, local_name);
28515
0
        emit_u16(s, 0);
28516
28517
0
        if (!add_export_entry(s, m, local_name, JS_ATOM_default,
28518
0
                              JS_EXPORT_TYPE_LOCAL))
28519
0
            return -1;
28520
0
        break;
28521
0
    case TOK_VAR:
28522
0
    case TOK_LET:
28523
0
    case TOK_CONST:
28524
0
        return js_parse_var(s, TRUE, tok, TRUE);
28525
0
    default:
28526
0
        return js_parse_error(s, "invalid export syntax");
28527
0
    }
28528
0
    return js_parse_expect_semi(s);
28529
0
}
28530
28531
static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
28532
                           BOOL is_local, BOOL is_arg,
28533
                           int var_idx, JSAtom var_name,
28534
                           BOOL is_const, BOOL is_lexical,
28535
                           JSVarKindEnum var_kind);
28536
28537
static int add_import(JSParseState *s, JSModuleDef *m,
28538
                      JSAtom local_name, JSAtom import_name)
28539
0
{
28540
0
    JSContext *ctx = s->ctx;
28541
0
    int i, var_idx;
28542
0
    JSImportEntry *mi;
28543
0
    BOOL is_local;
28544
28545
0
    if (local_name == JS_ATOM_arguments || local_name == JS_ATOM_eval)
28546
0
        return js_parse_error(s, "invalid import binding");
28547
28548
0
    if (local_name != JS_ATOM_default) {
28549
0
        for (i = 0; i < s->cur_func->closure_var_count; i++) {
28550
0
            if (s->cur_func->closure_var[i].var_name == local_name)
28551
0
                return js_parse_error(s, "duplicate import binding");
28552
0
        }
28553
0
    }
28554
28555
0
    is_local = (import_name == JS_ATOM__star_);
28556
0
    var_idx = add_closure_var(ctx, s->cur_func, is_local, FALSE,
28557
0
                              m->import_entries_count,
28558
0
                              local_name, TRUE, TRUE, FALSE);
28559
0
    if (var_idx < 0)
28560
0
        return -1;
28561
0
    if (js_resize_array(ctx, (void **)&m->import_entries,
28562
0
                        sizeof(JSImportEntry),
28563
0
                        &m->import_entries_size,
28564
0
                        m->import_entries_count + 1))
28565
0
        return -1;
28566
0
    mi = &m->import_entries[m->import_entries_count++];
28567
0
    mi->import_name = JS_DupAtom(ctx, import_name);
28568
0
    mi->var_idx = var_idx;
28569
0
    return 0;
28570
0
}
28571
28572
static __exception int js_parse_import(JSParseState *s)
28573
0
{
28574
0
    JSContext *ctx = s->ctx;
28575
0
    JSModuleDef *m = s->cur_func->module;
28576
0
    JSAtom local_name, import_name, module_name;
28577
0
    int first_import, i, idx;
28578
28579
0
    if (next_token(s))
28580
0
        return -1;
28581
28582
0
    first_import = m->import_entries_count;
28583
0
    if (s->token.val == TOK_STRING) {
28584
0
        module_name = JS_ValueToAtom(ctx, s->token.u.str.str);
28585
0
        if (module_name == JS_ATOM_NULL)
28586
0
            return -1;
28587
0
        if (next_token(s)) {
28588
0
            JS_FreeAtom(ctx, module_name);
28589
0
            return -1;
28590
0
        }
28591
0
    } else {
28592
0
        if (s->token.val == TOK_IDENT) {
28593
0
            if (s->token.u.ident.is_reserved) {
28594
0
                return js_parse_error_reserved_identifier(s);
28595
0
            }
28596
            /* "default" import */
28597
0
            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28598
0
            import_name = JS_ATOM_default;
28599
0
            if (next_token(s))
28600
0
                goto fail;
28601
0
            if (add_import(s, m, local_name, import_name))
28602
0
                goto fail;
28603
0
            JS_FreeAtom(ctx, local_name);
28604
28605
0
            if (s->token.val != ',')
28606
0
                goto end_import_clause;
28607
0
            if (next_token(s))
28608
0
                return -1;
28609
0
        }
28610
28611
0
        if (s->token.val == '*') {
28612
            /* name space import */
28613
0
            if (next_token(s))
28614
0
                return -1;
28615
0
            if (!token_is_pseudo_keyword(s, JS_ATOM_as))
28616
0
                return js_parse_error(s, "expecting 'as'");
28617
0
            if (next_token(s))
28618
0
                return -1;
28619
0
            if (!token_is_ident(s->token.val)) {
28620
0
                js_parse_error(s, "identifier expected");
28621
0
                return -1;
28622
0
            }
28623
0
            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28624
0
            import_name = JS_ATOM__star_;
28625
0
            if (next_token(s))
28626
0
                goto fail;
28627
0
            if (add_import(s, m, local_name, import_name))
28628
0
                goto fail;
28629
0
            JS_FreeAtom(ctx, local_name);
28630
0
        } else if (s->token.val == '{') {
28631
0
            if (next_token(s))
28632
0
                return -1;
28633
28634
0
            while (s->token.val != '}') {
28635
0
                if (!token_is_ident(s->token.val)) {
28636
0
                    js_parse_error(s, "identifier expected");
28637
0
                    return -1;
28638
0
                }
28639
0
                import_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28640
0
                local_name = JS_ATOM_NULL;
28641
0
                if (next_token(s))
28642
0
                    goto fail;
28643
0
                if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
28644
0
                    if (next_token(s))
28645
0
                        goto fail;
28646
0
                    if (!token_is_ident(s->token.val)) {
28647
0
                        js_parse_error(s, "identifier expected");
28648
0
                        goto fail;
28649
0
                    }
28650
0
                    local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28651
0
                    if (next_token(s)) {
28652
0
                    fail:
28653
0
                        JS_FreeAtom(ctx, local_name);
28654
0
                        JS_FreeAtom(ctx, import_name);
28655
0
                        return -1;
28656
0
                    }
28657
0
                } else {
28658
0
                    local_name = JS_DupAtom(ctx, import_name);
28659
0
                }
28660
0
                if (add_import(s, m, local_name, import_name))
28661
0
                    goto fail;
28662
0
                JS_FreeAtom(ctx, local_name);
28663
0
                JS_FreeAtom(ctx, import_name);
28664
0
                if (s->token.val != ',')
28665
0
                    break;
28666
0
                if (next_token(s))
28667
0
                    return -1;
28668
0
            }
28669
0
            if (js_parse_expect(s, '}'))
28670
0
                return -1;
28671
0
        }
28672
0
    end_import_clause:
28673
0
        module_name = js_parse_from_clause(s);
28674
0
        if (module_name == JS_ATOM_NULL)
28675
0
            return -1;
28676
0
    }
28677
0
    idx = add_req_module_entry(ctx, m, module_name);
28678
0
    JS_FreeAtom(ctx, module_name);
28679
0
    if (idx < 0)
28680
0
        return -1;
28681
0
    for(i = first_import; i < m->import_entries_count; i++)
28682
0
        m->import_entries[i].req_module_idx = idx;
28683
28684
0
    return js_parse_expect_semi(s);
28685
0
}
28686
28687
static __exception int js_parse_source_element(JSParseState *s)
28688
111k
{
28689
111k
    JSFunctionDef *fd = s->cur_func;
28690
111k
    int tok;
28691
    
28692
111k
    if (s->token.val == TOK_FUNCTION ||
28693
111k
        (token_is_pseudo_keyword(s, JS_ATOM_async) &&
28694
103k
         peek_token(s, TRUE) == TOK_FUNCTION)) {
28695
8.28k
        if (js_parse_function_decl(s, JS_PARSE_FUNC_STATEMENT,
28696
8.28k
                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
28697
8.28k
                                   s->token.ptr, s->token.line_num))
28698
87
            return -1;
28699
103k
    } else if (s->token.val == TOK_EXPORT && fd->module) {
28700
0
        if (js_parse_export(s))
28701
0
            return -1;
28702
103k
    } else if (s->token.val == TOK_IMPORT && fd->module &&
28703
103k
               ((tok = peek_token(s, FALSE)) != '(' && tok != '.'))  {
28704
        /* the peek_token is needed to avoid confusion with ImportCall
28705
           (dynamic import) or import.meta */
28706
0
        if (js_parse_import(s))
28707
0
            return -1;
28708
103k
    } else {
28709
103k
        if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
28710
914
            return -1;
28711
103k
    }
28712
110k
    return 0;
28713
111k
}
28714
28715
static JSFunctionDef *js_new_function_def(JSContext *ctx,
28716
                                          JSFunctionDef *parent,
28717
                                          BOOL is_eval,
28718
                                          BOOL is_func_expr,
28719
                                          const char *filename, int line_num)
28720
46.3k
{
28721
46.3k
    JSFunctionDef *fd;
28722
28723
46.3k
    fd = js_mallocz(ctx, sizeof(*fd));
28724
46.3k
    if (!fd)
28725
1.11k
        return NULL;
28726
28727
45.2k
    fd->ctx = ctx;
28728
45.2k
    init_list_head(&fd->child_list);
28729
28730
    /* insert in parent list */
28731
45.2k
    fd->parent = parent;
28732
45.2k
    fd->parent_cpool_idx = -1;
28733
45.2k
    if (parent) {
28734
43.6k
        list_add_tail(&fd->link, &parent->child_list);
28735
43.6k
        fd->js_mode = parent->js_mode;
28736
43.6k
        fd->parent_scope_level = parent->scope_level;
28737
43.6k
    }
28738
28739
45.2k
    fd->is_eval = is_eval;
28740
45.2k
    fd->is_func_expr = is_func_expr;
28741
45.2k
    js_dbuf_init(ctx, &fd->byte_code);
28742
45.2k
    fd->last_opcode_pos = -1;
28743
45.2k
    fd->func_name = JS_ATOM_NULL;
28744
45.2k
    fd->var_object_idx = -1;
28745
45.2k
    fd->arg_var_object_idx = -1;
28746
45.2k
    fd->arguments_var_idx = -1;
28747
45.2k
    fd->arguments_arg_idx = -1;
28748
45.2k
    fd->func_var_idx = -1;
28749
45.2k
    fd->eval_ret_idx = -1;
28750
45.2k
    fd->this_var_idx = -1;
28751
45.2k
    fd->new_target_var_idx = -1;
28752
45.2k
    fd->this_active_func_var_idx = -1;
28753
45.2k
    fd->home_object_var_idx = -1;
28754
28755
    /* XXX: should distinguish arg, var and var object and body scopes */
28756
45.2k
    fd->scopes = fd->def_scope_array;
28757
45.2k
    fd->scope_size = countof(fd->def_scope_array);
28758
45.2k
    fd->scope_count = 1;
28759
45.2k
    fd->scopes[0].first = -1;
28760
45.2k
    fd->scopes[0].parent = -1;
28761
45.2k
    fd->scope_level = 0;  /* 0: var/arg scope */
28762
45.2k
    fd->scope_first = -1;
28763
45.2k
    fd->body_scope = -1;
28764
28765
45.2k
    fd->filename = JS_NewAtom(ctx, filename);
28766
45.2k
    fd->line_num = line_num;
28767
28768
45.2k
    js_dbuf_init(ctx, &fd->pc2line);
28769
    //fd->pc2line_last_line_num = line_num;
28770
    //fd->pc2line_last_pc = 0;
28771
45.2k
    fd->last_opcode_line_num = line_num;
28772
28773
45.2k
    return fd;
28774
46.3k
}
28775
28776
static void free_bytecode_atoms(JSRuntime *rt,
28777
                                const uint8_t *bc_buf, int bc_len,
28778
                                BOOL use_short_opcodes)
28779
43.6k
{
28780
43.6k
    int pos, len, op;
28781
43.6k
    JSAtom atom;
28782
43.6k
    const JSOpCode *oi;
28783
    
28784
43.6k
    pos = 0;
28785
5.94M
    while (pos < bc_len) {
28786
5.90M
        op = bc_buf[pos];
28787
5.90M
        if (use_short_opcodes)
28788
4.93M
            oi = &short_opcode_info(op);
28789
970k
        else
28790
970k
            oi = &opcode_info[op];
28791
            
28792
5.90M
        len = oi->size;
28793
5.90M
        switch(oi->fmt) {
28794
581k
        case OP_FMT_atom:
28795
610k
        case OP_FMT_atom_u8:
28796
719k
        case OP_FMT_atom_u16:
28797
2.29M
        case OP_FMT_atom_label_u8:
28798
2.34M
        case OP_FMT_atom_label_u16:
28799
2.34M
            atom = get_u32(bc_buf + pos + 1);
28800
2.34M
            JS_FreeAtomRT(rt, atom);
28801
2.34M
            break;
28802
3.55M
        default:
28803
3.55M
            break;
28804
5.90M
        }
28805
5.90M
        pos += len;
28806
5.90M
    }
28807
43.6k
}
28808
28809
static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd)
28810
13.5k
{
28811
13.5k
    int i;
28812
13.5k
    struct list_head *el, *el1;
28813
28814
    /* free the child functions */
28815
13.5k
    list_for_each_safe(el, el1, &fd->child_list) {
28816
12.4k
        JSFunctionDef *fd1;
28817
12.4k
        fd1 = list_entry(el, JSFunctionDef, link);
28818
12.4k
        js_free_function_def(ctx, fd1);
28819
12.4k
    }
28820
28821
13.5k
    free_bytecode_atoms(ctx->rt, fd->byte_code.buf, fd->byte_code.size,
28822
13.5k
                        fd->use_short_opcodes);
28823
13.5k
    dbuf_free(&fd->byte_code);
28824
13.5k
    js_free(ctx, fd->jump_slots);
28825
13.5k
    js_free(ctx, fd->label_slots);
28826
13.5k
    js_free(ctx, fd->line_number_slots);
28827
28828
35.3k
    for(i = 0; i < fd->cpool_count; i++) {
28829
21.7k
        JS_FreeValue(ctx, fd->cpool[i]);
28830
21.7k
    }
28831
13.5k
    js_free(ctx, fd->cpool);
28832
28833
13.5k
    JS_FreeAtom(ctx, fd->func_name);
28834
28835
27.2k
    for(i = 0; i < fd->var_count; i++) {
28836
13.6k
        JS_FreeAtom(ctx, fd->vars[i].var_name);
28837
13.6k
    }
28838
13.5k
    js_free(ctx, fd->vars);
28839
18.6k
    for(i = 0; i < fd->arg_count; i++) {
28840
5.07k
        JS_FreeAtom(ctx, fd->args[i].var_name);
28841
5.07k
    }
28842
13.5k
    js_free(ctx, fd->args);
28843
28844
20.9k
    for(i = 0; i < fd->global_var_count; i++) {
28845
7.38k
        JS_FreeAtom(ctx, fd->global_vars[i].var_name);
28846
7.38k
    }
28847
13.5k
    js_free(ctx, fd->global_vars);
28848
28849
13.6k
    for(i = 0; i < fd->closure_var_count; i++) {
28850
17
        JSClosureVar *cv = &fd->closure_var[i];
28851
17
        JS_FreeAtom(ctx, cv->var_name);
28852
17
    }
28853
13.5k
    js_free(ctx, fd->closure_var);
28854
28855
13.5k
    if (fd->scopes != fd->def_scope_array)
28856
424
        js_free(ctx, fd->scopes);
28857
28858
13.5k
    JS_FreeAtom(ctx, fd->filename);
28859
13.5k
    dbuf_free(&fd->pc2line);
28860
28861
13.5k
    js_free(ctx, fd->source);
28862
28863
13.5k
    if (fd->parent) {
28864
        /* remove in parent list */
28865
13.2k
        list_del(&fd->link);
28866
13.2k
    }
28867
13.5k
    js_free(ctx, fd);
28868
13.5k
}
28869
28870
#ifdef DUMP_BYTECODE
28871
static const char *skip_lines(const char *p, int n) {
28872
    while (n-- > 0 && *p) {
28873
        while (*p && *p++ != '\n')
28874
            continue;
28875
    }
28876
    return p;
28877
}
28878
28879
static void print_lines(const char *source, int line, int line1) {
28880
    const char *s = source;
28881
    const char *p = skip_lines(s, line);
28882
    if (*p) {
28883
        while (line++ < line1) {
28884
            p = skip_lines(s = p, 1);
28885
            printf(";; %.*s", (int)(p - s), s);
28886
            if (!*p) {
28887
                if (p[-1] != '\n')
28888
                    printf("\n");
28889
                break;
28890
            }
28891
        }
28892
    }
28893
}
28894
28895
static void dump_byte_code(JSContext *ctx, int pass,
28896
                           const uint8_t *tab, int len,
28897
                           const JSVarDef *args, int arg_count,
28898
                           const JSVarDef *vars, int var_count,
28899
                           const JSClosureVar *closure_var, int closure_var_count,
28900
                           const JSValue *cpool, uint32_t cpool_count,
28901
                           const char *source, int line_num,
28902
                           const LabelSlot *label_slots, JSFunctionBytecode *b)
28903
{
28904
    const JSOpCode *oi;
28905
    int pos, pos_next, op, size, idx, addr, line, line1, in_source;
28906
    uint8_t *bits = js_mallocz(ctx, len * sizeof(*bits));
28907
    BOOL use_short_opcodes = (b != NULL);
28908
28909
    /* scan for jump targets */
28910
    for (pos = 0; pos < len; pos = pos_next) {
28911
        op = tab[pos];
28912
        if (use_short_opcodes)
28913
            oi = &short_opcode_info(op);
28914
        else
28915
            oi = &opcode_info[op];
28916
        pos_next = pos + oi->size;
28917
        if (op < OP_COUNT) {
28918
            switch (oi->fmt) {
28919
#if SHORT_OPCODES
28920
            case OP_FMT_label8:
28921
                pos++;
28922
                addr = (int8_t)tab[pos];
28923
                goto has_addr;
28924
            case OP_FMT_label16:
28925
                pos++;
28926
                addr = (int16_t)get_u16(tab + pos);
28927
                goto has_addr;
28928
#endif
28929
            case OP_FMT_atom_label_u8:
28930
            case OP_FMT_atom_label_u16:
28931
                pos += 4;
28932
                /* fall thru */
28933
            case OP_FMT_label:
28934
            case OP_FMT_label_u16:
28935
                pos++;
28936
                addr = get_u32(tab + pos);
28937
                goto has_addr;
28938
            has_addr:
28939
                if (pass == 1)
28940
                    addr = label_slots[addr].pos;
28941
                if (pass == 2)
28942
                    addr = label_slots[addr].pos2;
28943
                if (pass == 3)
28944
                    addr += pos;
28945
                if (addr >= 0 && addr < len)
28946
                    bits[addr] |= 1;
28947
                break;
28948
            }
28949
        }
28950
    }
28951
    in_source = 0;
28952
    if (source) {
28953
        /* Always print first line: needed if single line */
28954
        print_lines(source, 0, 1);
28955
        in_source = 1;
28956
    }
28957
    line1 = line = 1;
28958
    pos = 0;
28959
    while (pos < len) {
28960
        op = tab[pos];
28961
        if (source) {
28962
            if (b) {
28963
                line1 = find_line_num(ctx, b, pos) - line_num + 1;
28964
            } else if (op == OP_line_num) {
28965
                line1 = get_u32(tab + pos + 1) - line_num + 1;
28966
            }
28967
            if (line1 > line) {
28968
                if (!in_source)
28969
                    printf("\n");
28970
                in_source = 1;
28971
                print_lines(source, line, line1);
28972
                line = line1;
28973
                //bits[pos] |= 2;
28974
            }
28975
        }
28976
        if (in_source)
28977
            printf("\n");
28978
        in_source = 0;
28979
        if (op >= OP_COUNT) {
28980
            printf("invalid opcode (0x%02x)\n", op);
28981
            pos++;
28982
            continue;
28983
        }
28984
        if (use_short_opcodes)
28985
            oi = &short_opcode_info(op);
28986
        else
28987
            oi = &opcode_info[op];
28988
        size = oi->size;
28989
        if (pos + size > len) {
28990
            printf("truncated opcode (0x%02x)\n", op);
28991
            break;
28992
        }
28993
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 16)
28994
        {
28995
            int i, x, x0;
28996
            x = x0 = printf("%5d ", pos);
28997
            for (i = 0; i < size; i++) {
28998
                if (i == 6) {
28999
                    printf("\n%*s", x = x0, "");
29000
                }
29001
                x += printf(" %02X", tab[pos + i]);
29002
            }
29003
            printf("%*s", x0 + 20 - x, "");
29004
        }
29005
#endif
29006
        if (bits[pos]) {
29007
            printf("%5d:  ", pos);
29008
        } else {
29009
            printf("        ");
29010
        }
29011
        printf("%s", oi->name);
29012
        pos++;
29013
        switch(oi->fmt) {
29014
        case OP_FMT_none_int:
29015
            printf(" %d", op - OP_push_0);
29016
            break;
29017
        case OP_FMT_npopx:
29018
            printf(" %d", op - OP_call0);
29019
            break;
29020
        case OP_FMT_u8:
29021
            printf(" %u", get_u8(tab + pos));
29022
            break;
29023
        case OP_FMT_i8:
29024
            printf(" %d", get_i8(tab + pos));
29025
            break;
29026
        case OP_FMT_u16:
29027
        case OP_FMT_npop:
29028
            printf(" %u", get_u16(tab + pos));
29029
            break;
29030
        case OP_FMT_npop_u16:
29031
            printf(" %u,%u", get_u16(tab + pos), get_u16(tab + pos + 2));
29032
            break;
29033
        case OP_FMT_i16:
29034
            printf(" %d", get_i16(tab + pos));
29035
            break;
29036
        case OP_FMT_i32:
29037
            printf(" %d", get_i32(tab + pos));
29038
            break;
29039
        case OP_FMT_u32:
29040
            printf(" %u", get_u32(tab + pos));
29041
            break;
29042
#if SHORT_OPCODES
29043
        case OP_FMT_label8:
29044
            addr = get_i8(tab + pos);
29045
            goto has_addr1;
29046
        case OP_FMT_label16:
29047
            addr = get_i16(tab + pos);
29048
            goto has_addr1;
29049
#endif
29050
        case OP_FMT_label:
29051
            addr = get_u32(tab + pos);
29052
            goto has_addr1;
29053
        has_addr1:
29054
            if (pass == 1)
29055
                printf(" %u:%u", addr, label_slots[addr].pos);
29056
            if (pass == 2)
29057
                printf(" %u:%u", addr, label_slots[addr].pos2);
29058
            if (pass == 3)
29059
                printf(" %u", addr + pos);
29060
            break;
29061
        case OP_FMT_label_u16:
29062
            addr = get_u32(tab + pos);
29063
            if (pass == 1)
29064
                printf(" %u:%u", addr, label_slots[addr].pos);
29065
            if (pass == 2)
29066
                printf(" %u:%u", addr, label_slots[addr].pos2);
29067
            if (pass == 3)
29068
                printf(" %u", addr + pos);
29069
            printf(",%u", get_u16(tab + pos + 4));
29070
            break;
29071
#if SHORT_OPCODES
29072
        case OP_FMT_const8:
29073
            idx = get_u8(tab + pos);
29074
            goto has_pool_idx;
29075
#endif
29076
        case OP_FMT_const:
29077
            idx = get_u32(tab + pos);
29078
            goto has_pool_idx;
29079
        has_pool_idx:
29080
            printf(" %u: ", idx);
29081
            if (idx < cpool_count) {
29082
                JS_DumpValue(ctx, cpool[idx]);
29083
            }
29084
            break;
29085
        case OP_FMT_atom:
29086
            printf(" ");
29087
            print_atom(ctx, get_u32(tab + pos));
29088
            break;
29089
        case OP_FMT_atom_u8:
29090
            printf(" ");
29091
            print_atom(ctx, get_u32(tab + pos));
29092
            printf(",%d", get_u8(tab + pos + 4));
29093
            break;
29094
        case OP_FMT_atom_u16:
29095
            printf(" ");
29096
            print_atom(ctx, get_u32(tab + pos));
29097
            printf(",%d", get_u16(tab + pos + 4));
29098
            break;
29099
        case OP_FMT_atom_label_u8:
29100
        case OP_FMT_atom_label_u16:
29101
            printf(" ");
29102
            print_atom(ctx, get_u32(tab + pos));
29103
            addr = get_u32(tab + pos + 4);
29104
            if (pass == 1)
29105
                printf(",%u:%u", addr, label_slots[addr].pos);
29106
            if (pass == 2)
29107
                printf(",%u:%u", addr, label_slots[addr].pos2);
29108
            if (pass == 3)
29109
                printf(",%u", addr + pos + 4);
29110
            if (oi->fmt == OP_FMT_atom_label_u8)
29111
                printf(",%u", get_u8(tab + pos + 8));
29112
            else
29113
                printf(",%u", get_u16(tab + pos + 8));
29114
            break;
29115
        case OP_FMT_none_loc:
29116
            idx = (op - OP_get_loc0) % 4;
29117
            goto has_loc;
29118
        case OP_FMT_loc8:
29119
            idx = get_u8(tab + pos);
29120
            goto has_loc;
29121
        case OP_FMT_loc:
29122
            idx = get_u16(tab + pos);
29123
        has_loc:
29124
            printf(" %d: ", idx);
29125
            if (idx < var_count) {
29126
                print_atom(ctx, vars[idx].var_name);
29127
            }
29128
            break;
29129
        case OP_FMT_none_arg:
29130
            idx = (op - OP_get_arg0) % 4;
29131
            goto has_arg;
29132
        case OP_FMT_arg:
29133
            idx = get_u16(tab + pos);
29134
        has_arg:
29135
            printf(" %d: ", idx);
29136
            if (idx < arg_count) {
29137
                print_atom(ctx, args[idx].var_name);
29138
            }
29139
            break;
29140
        case OP_FMT_none_var_ref:
29141
            idx = (op - OP_get_var_ref0) % 4;
29142
            goto has_var_ref;
29143
        case OP_FMT_var_ref:
29144
            idx = get_u16(tab + pos);
29145
        has_var_ref:
29146
            printf(" %d: ", idx);
29147
            if (idx < closure_var_count) {
29148
                print_atom(ctx, closure_var[idx].var_name);
29149
            }
29150
            break;
29151
        default:
29152
            break;
29153
        }
29154
        printf("\n");
29155
        pos += oi->size - 1;
29156
    }
29157
    if (source) {
29158
        if (!in_source)
29159
            printf("\n");
29160
        print_lines(source, line, INT32_MAX);
29161
    }
29162
    js_free(ctx, bits);
29163
}
29164
29165
static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int len,
29166
                                                 int line_num)
29167
{
29168
    const uint8_t *p_end, *p_next, *p;
29169
    int pc, v;
29170
    unsigned int op;
29171
29172
    if (len <= 0)
29173
        return;
29174
29175
    printf("%5s %5s\n", "PC", "LINE");
29176
29177
    p = buf;
29178
    p_end = buf + len;
29179
    pc = 0;
29180
    while (p < p_end) {
29181
        op = *p++;
29182
        if (op == 0) {
29183
            v = unicode_from_utf8(p, p_end - p, &p_next);
29184
            if (v < 0)
29185
                goto fail;
29186
            pc += v;
29187
            p = p_next;
29188
            v = unicode_from_utf8(p, p_end - p, &p_next);
29189
            if (v < 0) {
29190
            fail:
29191
                printf("invalid pc2line encode pos=%d\n", (int)(p - buf));
29192
                return;
29193
            }
29194
            if (!(v & 1)) {
29195
                v = v >> 1;
29196
            } else {
29197
                v = -(v >> 1) - 1;
29198
            }
29199
            line_num += v;
29200
            p = p_next;
29201
        } else {
29202
            op -= PC2LINE_OP_FIRST;
29203
            pc += (op / PC2LINE_RANGE);
29204
            line_num += (op % PC2LINE_RANGE) + PC2LINE_BASE;
29205
        }
29206
        printf("%5d %5d\n", pc, line_num);
29207
    }
29208
}
29209
29210
static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionBytecode *b)
29211
{
29212
    int i;
29213
    char atom_buf[ATOM_GET_STR_BUF_SIZE];
29214
    const char *str;
29215
29216
    if (b->has_debug && b->debug.filename != JS_ATOM_NULL) {
29217
        str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->debug.filename);
29218
        printf("%s:%d: ", str, b->debug.line_num);
29219
    }
29220
29221
    str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name);
29222
    printf("function: %s%s\n", &"*"[b->func_kind != JS_FUNC_GENERATOR], str);
29223
    if (b->js_mode) {
29224
        printf("  mode:");
29225
        if (b->js_mode & JS_MODE_STRICT)
29226
            printf(" strict");
29227
#ifdef CONFIG_BIGNUM
29228
        if (b->js_mode & JS_MODE_MATH)
29229
            printf(" math");
29230
#endif
29231
        printf("\n");
29232
    }
29233
    if (b->arg_count && b->vardefs) {
29234
        printf("  args:");
29235
        for(i = 0; i < b->arg_count; i++) {
29236
            printf(" %s", JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf),
29237
                                        b->vardefs[i].var_name));
29238
        }
29239
        printf("\n");
29240
    }
29241
    if (b->var_count && b->vardefs) {
29242
        printf("  locals:\n");
29243
        for(i = 0; i < b->var_count; i++) {
29244
            JSVarDef *vd = &b->vardefs[b->arg_count + i];
29245
            printf("%5d: %s %s", i,
29246
                   vd->var_kind == JS_VAR_CATCH ? "catch" :
29247
                   (vd->var_kind == JS_VAR_FUNCTION_DECL ||
29248
                    vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) ? "function" :
29249
                   vd->is_const ? "const" :
29250
                   vd->is_lexical ? "let" : "var",
29251
                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), vd->var_name));
29252
            if (vd->scope_level)
29253
                printf(" [level:%d next:%d]", vd->scope_level, vd->scope_next);
29254
            printf("\n");
29255
        }
29256
    }
29257
    if (b->closure_var_count) {
29258
        printf("  closure vars:\n");
29259
        for(i = 0; i < b->closure_var_count; i++) {
29260
            JSClosureVar *cv = &b->closure_var[i];
29261
            printf("%5d: %s %s:%s%d %s\n", i,
29262
                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), cv->var_name),
29263
                   cv->is_local ? "local" : "parent",
29264
                   cv->is_arg ? "arg" : "loc", cv->var_idx,
29265
                   cv->is_const ? "const" :
29266
                   cv->is_lexical ? "let" : "var");
29267
        }
29268
    }
29269
    printf("  stack_size: %d\n", b->stack_size);
29270
    printf("  opcodes:\n");
29271
    dump_byte_code(ctx, 3, b->byte_code_buf, b->byte_code_len,
29272
                   b->vardefs, b->arg_count,
29273
                   b->vardefs ? b->vardefs + b->arg_count : NULL, b->var_count,
29274
                   b->closure_var, b->closure_var_count,
29275
                   b->cpool, b->cpool_count,
29276
                   b->has_debug ? b->debug.source : NULL,
29277
                   b->has_debug ? b->debug.line_num : -1, NULL, b);
29278
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32)
29279
    if (b->has_debug)
29280
        dump_pc2line(ctx, b->debug.pc2line_buf, b->debug.pc2line_len, b->debug.line_num);
29281
#endif
29282
    printf("\n");
29283
}
29284
#endif
29285
29286
static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
29287
                           BOOL is_local, BOOL is_arg,
29288
                           int var_idx, JSAtom var_name,
29289
                           BOOL is_const, BOOL is_lexical,
29290
                           JSVarKindEnum var_kind)
29291
27.9k
{
29292
27.9k
    JSClosureVar *cv;
29293
29294
    /* the closure variable indexes are currently stored on 16 bits */
29295
27.9k
    if (s->closure_var_count >= JS_MAX_LOCAL_VARS) {
29296
0
        JS_ThrowInternalError(ctx, "too many closure variables");
29297
0
        return -1;
29298
0
    }
29299
29300
27.9k
    if (js_resize_array(ctx, (void **)&s->closure_var,
29301
27.9k
                        sizeof(s->closure_var[0]),
29302
27.9k
                        &s->closure_var_size, s->closure_var_count + 1))
29303
1
        return -1;
29304
27.9k
    cv = &s->closure_var[s->closure_var_count++];
29305
27.9k
    cv->is_local = is_local;
29306
27.9k
    cv->is_arg = is_arg;
29307
27.9k
    cv->is_const = is_const;
29308
27.9k
    cv->is_lexical = is_lexical;
29309
27.9k
    cv->var_kind = var_kind;
29310
27.9k
    cv->var_idx = var_idx;
29311
27.9k
    cv->var_name = JS_DupAtom(ctx, var_name);
29312
27.9k
    return s->closure_var_count - 1;
29313
27.9k
}
29314
29315
static int find_closure_var(JSContext *ctx, JSFunctionDef *s,
29316
                            JSAtom var_name)
29317
0
{
29318
0
    int i;
29319
0
    for(i = 0; i < s->closure_var_count; i++) {
29320
0
        JSClosureVar *cv = &s->closure_var[i];
29321
0
        if (cv->var_name == var_name)
29322
0
            return i;
29323
0
    }
29324
0
    return -1;
29325
0
}
29326
29327
/* 'fd' must be a parent of 's'. Create in 's' a closure referencing a
29328
   local variable (is_local = TRUE) or a closure (is_local = FALSE) in
29329
   'fd' */
29330
static int get_closure_var2(JSContext *ctx, JSFunctionDef *s,
29331
                            JSFunctionDef *fd, BOOL is_local,
29332
                            BOOL is_arg, int var_idx, JSAtom var_name,
29333
                            BOOL is_const, BOOL is_lexical,
29334
                            JSVarKindEnum var_kind)
29335
37.3k
{
29336
37.3k
    int i;
29337
29338
37.3k
    if (fd != s->parent) {
29339
5.82k
        var_idx = get_closure_var2(ctx, s->parent, fd, is_local,
29340
5.82k
                                   is_arg, var_idx, var_name,
29341
5.82k
                                   is_const, is_lexical, var_kind);
29342
5.82k
        if (var_idx < 0)
29343
0
            return -1;
29344
5.82k
        is_local = FALSE;
29345
5.82k
    }
29346
74.8k
    for(i = 0; i < s->closure_var_count; i++) {
29347
47.5k
        JSClosureVar *cv = &s->closure_var[i];
29348
47.5k
        if (cv->var_idx == var_idx && cv->is_arg == is_arg &&
29349
47.5k
            cv->is_local == is_local)
29350
10.0k
            return i;
29351
47.5k
    }
29352
27.2k
    return add_closure_var(ctx, s, is_local, is_arg, var_idx, var_name,
29353
27.2k
                           is_const, is_lexical, var_kind);
29354
37.3k
}
29355
29356
static int get_closure_var(JSContext *ctx, JSFunctionDef *s,
29357
                           JSFunctionDef *fd, BOOL is_arg,
29358
                           int var_idx, JSAtom var_name,
29359
                           BOOL is_const, BOOL is_lexical,
29360
                           JSVarKindEnum var_kind)
29361
31.3k
{
29362
31.3k
    return get_closure_var2(ctx, s, fd, TRUE, is_arg,
29363
31.3k
                            var_idx, var_name, is_const, is_lexical,
29364
31.3k
                            var_kind);
29365
31.3k
}
29366
29367
static int get_with_scope_opcode(int op)
29368
1.59M
{
29369
1.59M
    if (op == OP_scope_get_var_undef)
29370
0
        return OP_with_get_var;
29371
1.59M
    else
29372
1.59M
        return OP_with_get_var + (op - OP_scope_get_var);
29373
1.59M
}
29374
29375
static BOOL can_opt_put_ref_value(const uint8_t *bc_buf, int pos)
29376
7.28k
{
29377
7.28k
    int opcode = bc_buf[pos];
29378
7.28k
    return (bc_buf[pos + 1] == OP_put_ref_value &&
29379
7.28k
            (opcode == OP_insert3 ||
29380
6.89k
             opcode == OP_perm4 ||
29381
6.89k
             opcode == OP_nop ||
29382
6.89k
             opcode == OP_rot3l));
29383
7.28k
}
29384
29385
static BOOL can_opt_put_global_ref_value(const uint8_t *bc_buf, int pos)
29386
64.7k
{
29387
64.7k
    int opcode = bc_buf[pos];
29388
64.7k
    return (bc_buf[pos + 1] == OP_put_ref_value &&
29389
64.7k
            (opcode == OP_insert3 ||
29390
41.1k
             opcode == OP_perm4 ||
29391
41.1k
             opcode == OP_nop ||
29392
41.1k
             opcode == OP_rot3l));
29393
64.7k
}
29394
29395
static int optimize_scope_make_ref(JSContext *ctx, JSFunctionDef *s,
29396
                                   DynBuf *bc, uint8_t *bc_buf,
29397
                                   LabelSlot *ls, int pos_next,
29398
                                   int get_op, int var_idx)
29399
6.89k
{
29400
6.89k
    int label_pos, end_pos, pos;
29401
29402
    /* XXX: should optimize `loc(a) += expr` as `expr add_loc(a)`
29403
       but only if expr does not modify `a`.
29404
       should scan the code between pos_next and label_pos
29405
       for operations that can potentially change `a`:
29406
       OP_scope_make_ref(a), function calls, jumps and gosub.
29407
     */
29408
    /* replace the reference get/put with normal variable
29409
       accesses */
29410
6.89k
    if (bc_buf[pos_next] == OP_get_ref_value) {
29411
2.66k
        dbuf_putc(bc, get_op);
29412
2.66k
        dbuf_put_u16(bc, var_idx);
29413
2.66k
        pos_next++;
29414
2.66k
    }
29415
    /* remove the OP_label to make room for replacement */
29416
    /* label should have a refcount of 0 anyway */
29417
    /* XXX: should avoid this patch by inserting nops in phase 1 */
29418
6.89k
    label_pos = ls->pos;
29419
6.89k
    pos = label_pos - 5;
29420
6.89k
    assert(bc_buf[pos] == OP_label);
29421
    /* label points to an instruction pair:
29422
       - insert3 / put_ref_value
29423
       - perm4 / put_ref_value
29424
       - rot3l / put_ref_value
29425
       - nop / put_ref_value
29426
     */
29427
6.89k
    end_pos = label_pos + 2;
29428
6.89k
    if (bc_buf[label_pos] == OP_insert3)
29429
5.10k
        bc_buf[pos++] = OP_dup;
29430
6.89k
    bc_buf[pos] = get_op + 1;
29431
6.89k
    put_u16(bc_buf + pos + 1, var_idx);
29432
6.89k
    pos += 3;
29433
    /* pad with OP_nop */
29434
29.3k
    while (pos < end_pos)
29435
22.4k
        bc_buf[pos++] = OP_nop;
29436
6.89k
    return pos_next;
29437
6.89k
}
29438
29439
static int optimize_scope_make_global_ref(JSContext *ctx, JSFunctionDef *s,
29440
                                          DynBuf *bc, uint8_t *bc_buf,
29441
                                          LabelSlot *ls, int pos_next,
29442
                                          JSAtom var_name)
29443
41.1k
{
29444
41.1k
    int label_pos, end_pos, pos, op;
29445
41.1k
    BOOL is_strict;
29446
41.1k
    is_strict = ((s->js_mode & JS_MODE_STRICT) != 0);
29447
29448
    /* replace the reference get/put with normal variable
29449
       accesses */
29450
41.1k
    if (is_strict) {
29451
        /* need to check if the variable exists before evaluating the right
29452
           expression */
29453
        /* XXX: need an extra OP_true if destructuring an array */
29454
3.45k
        dbuf_putc(bc, OP_check_var);
29455
3.45k
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29456
37.6k
    } else {
29457
        /* XXX: need 2 extra OP_true if destructuring an array */
29458
37.6k
    }
29459
41.1k
    if (bc_buf[pos_next] == OP_get_ref_value) {
29460
6.63k
        dbuf_putc(bc, OP_get_var);
29461
6.63k
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29462
6.63k
        pos_next++;
29463
6.63k
    }
29464
    /* remove the OP_label to make room for replacement */
29465
    /* label should have a refcount of 0 anyway */
29466
    /* XXX: should have emitted several OP_nop to avoid this kludge */
29467
41.1k
    label_pos = ls->pos;
29468
41.1k
    pos = label_pos - 5;
29469
41.1k
    assert(bc_buf[pos] == OP_label);
29470
41.1k
    end_pos = label_pos + 2;
29471
41.1k
    op = bc_buf[label_pos];
29472
41.1k
    if (is_strict) {
29473
3.45k
        if (op != OP_nop) {
29474
2.47k
            switch(op) {
29475
2.37k
            case OP_insert3:
29476
2.37k
                op = OP_insert2;
29477
2.37k
                break;
29478
44
            case OP_perm4:
29479
44
                op = OP_perm3;
29480
44
                break;
29481
56
            case OP_rot3l:
29482
56
                op = OP_swap;
29483
56
                break;
29484
0
            default:
29485
0
                abort();
29486
2.47k
            }
29487
2.47k
            bc_buf[pos++] = op;
29488
2.47k
        }
29489
37.6k
    } else {
29490
37.6k
        if (op == OP_insert3)
29491
30.2k
            bc_buf[pos++] = OP_dup;
29492
37.6k
    }
29493
41.1k
    if (is_strict) {
29494
3.45k
        bc_buf[pos] = OP_put_var_strict;
29495
        /* XXX: need 1 extra OP_drop if destructuring an array */
29496
37.6k
    } else {
29497
37.6k
        bc_buf[pos] = OP_put_var;
29498
        /* XXX: need 2 extra OP_drop if destructuring an array */
29499
37.6k
    }
29500
41.1k
    put_u32(bc_buf + pos + 1, JS_DupAtom(ctx, var_name));
29501
41.1k
    pos += 5;
29502
    /* pad with OP_nop */
29503
90.5k
    while (pos < end_pos)
29504
49.4k
        bc_buf[pos++] = OP_nop;
29505
41.1k
    return pos_next;
29506
41.1k
}
29507
29508
static int add_var_this(JSContext *ctx, JSFunctionDef *fd)
29509
18.5k
{
29510
18.5k
    int idx;
29511
18.5k
    idx = add_var(ctx, fd, JS_ATOM_this);
29512
18.5k
    if (idx >= 0 && fd->is_derived_class_constructor) {
29513
0
        JSVarDef *vd = &fd->vars[idx];
29514
        /* XXX: should have is_this flag or var type */
29515
0
        vd->is_lexical = 1; /* used to trigger 'uninitialized' checks
29516
                               in a derived class constructor */
29517
0
    }
29518
18.5k
    return idx;
29519
18.5k
}
29520
29521
static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s,
29522
                               JSAtom var_name)
29523
27.3k
{
29524
27.3k
    int var_idx;
29525
29526
27.3k
    if (!s->has_this_binding)
29527
87
        return -1;
29528
27.2k
    switch(var_name) {
29529
8.78k
    case JS_ATOM_home_object:
29530
        /* 'home_object' pseudo variable */
29531
8.78k
        if (s->home_object_var_idx < 0)
29532
8.78k
            s->home_object_var_idx = add_var(ctx, s, var_name);
29533
8.78k
        var_idx = s->home_object_var_idx;
29534
8.78k
        break;
29535
0
    case JS_ATOM_this_active_func:
29536
        /* 'this.active_func' pseudo variable */
29537
0
        if (s->this_active_func_var_idx < 0)
29538
0
            s->this_active_func_var_idx = add_var(ctx, s, var_name);
29539
0
        var_idx = s->this_active_func_var_idx;
29540
0
        break;
29541
0
    case JS_ATOM_new_target:
29542
        /* 'new.target' pseudo variable */
29543
0
        if (s->new_target_var_idx < 0)
29544
0
            s->new_target_var_idx = add_var(ctx, s, var_name);
29545
0
        var_idx = s->new_target_var_idx;
29546
0
        break;
29547
18.4k
    case JS_ATOM_this:
29548
        /* 'this' pseudo variable */
29549
18.4k
        if (s->this_var_idx < 0)
29550
18.4k
            s->this_var_idx = add_var_this(ctx, s);
29551
18.4k
        var_idx = s->this_var_idx;
29552
18.4k
        break;
29553
0
    default:
29554
0
        var_idx = -1;
29555
0
        break;
29556
27.2k
    }
29557
27.2k
    return var_idx;
29558
27.2k
}
29559
29560
/* test if 'var_name' is in the variable object on the stack. If is it
29561
   the case, handle it and jump to 'label_done' */
29562
static void var_object_test(JSContext *ctx, JSFunctionDef *s,
29563
                            JSAtom var_name, int op, DynBuf *bc,
29564
                            int *plabel_done, BOOL is_with)
29565
1.59M
{
29566
1.59M
    dbuf_putc(bc, get_with_scope_opcode(op));
29567
1.59M
    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29568
1.59M
    *plabel_done = new_label_fd(s, *plabel_done);
29569
1.59M
    dbuf_put_u32(bc, *plabel_done);
29570
1.59M
    dbuf_putc(bc, is_with);
29571
1.59M
    update_label(s, *plabel_done, 1);
29572
1.59M
    s->jump_size++;
29573
1.59M
}
29574
    
29575
/* return the position of the next opcode */
29576
static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
29577
                             JSAtom var_name, int scope_level, int op,
29578
                             DynBuf *bc, uint8_t *bc_buf,
29579
                             LabelSlot *ls, int pos_next)
29580
647k
{
29581
647k
    int idx, var_idx, is_put;
29582
647k
    int label_done;
29583
647k
    JSFunctionDef *fd;
29584
647k
    JSVarDef *vd;
29585
647k
    BOOL is_pseudo_var, is_arg_scope;
29586
29587
647k
    label_done = -1;
29588
29589
    /* XXX: could be simpler to use a specific function to
29590
       resolve the pseudo variables */
29591
647k
    is_pseudo_var = (var_name == JS_ATOM_home_object ||
29592
647k
                     var_name == JS_ATOM_this_active_func ||
29593
647k
                     var_name == JS_ATOM_new_target ||
29594
647k
                     var_name == JS_ATOM_this);
29595
29596
    /* resolve local scoped variables */
29597
647k
    var_idx = -1;
29598
2.32M
    for (idx = s->scopes[scope_level].first; idx >= 0;) {
29599
1.72M
        vd = &s->vars[idx];
29600
1.72M
        if (vd->var_name == var_name) {
29601
47.5k
            if (op == OP_scope_put_var || op == OP_scope_make_ref) {
29602
5.00k
                if (vd->is_const) {
29603
0
                    dbuf_putc(bc, OP_throw_error);
29604
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29605
0
                    dbuf_putc(bc, JS_THROW_VAR_RO);
29606
0
                    goto done;
29607
0
                }
29608
5.00k
            }
29609
47.5k
            var_idx = idx;
29610
47.5k
            break;
29611
47.5k
        } else
29612
1.67M
        if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
29613
1.58M
            dbuf_putc(bc, OP_get_loc);
29614
1.58M
            dbuf_put_u16(bc, idx);
29615
1.58M
            var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
29616
1.58M
        }
29617
1.67M
        idx = vd->scope_next;
29618
1.67M
    }
29619
647k
    is_arg_scope = (idx == ARG_SCOPE_END);
29620
647k
    if (var_idx < 0) {
29621
        /* argument scope: variables are not visible but pseudo
29622
           variables are visible */
29623
599k
        if (!is_arg_scope) {
29624
595k
            var_idx = find_var(ctx, s, var_name);
29625
595k
        }
29626
29627
599k
        if (var_idx < 0 && is_pseudo_var)
29628
27.3k
            var_idx = resolve_pseudo_var(ctx, s, var_name);
29629
29630
599k
        if (var_idx < 0 && var_name == JS_ATOM_arguments &&
29631
599k
            s->has_arguments_binding) {
29632
            /* 'arguments' pseudo variable */
29633
0
            var_idx = add_arguments_var(ctx, s);
29634
0
        }
29635
599k
        if (var_idx < 0 && s->is_func_expr && var_name == s->func_name) {
29636
            /* add a new variable with the function name */
29637
80
            var_idx = add_func_var(ctx, s, var_name);
29638
80
        }
29639
599k
    }
29640
647k
    if (var_idx >= 0) {
29641
98.7k
        if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
29642
98.7k
            !(var_idx & ARGUMENT_VAR_OFFSET) &&
29643
98.7k
            s->vars[var_idx].is_const) {
29644
            /* only happens when assigning a function expression name
29645
               in strict mode */
29646
8
            dbuf_putc(bc, OP_throw_error);
29647
8
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29648
8
            dbuf_putc(bc, JS_THROW_VAR_RO);
29649
8
            goto done;
29650
8
        }
29651
        /* OP_scope_put_var_init is only used to initialize a
29652
           lexical variable, so it is never used in a with or var object. It
29653
           can be used with a closure (module global variable case). */
29654
98.7k
        switch (op) {
29655
3.71k
        case OP_scope_make_ref:
29656
3.71k
            if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
29657
3.71k
                s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
29658
                /* Create a dummy object reference for the func_var */
29659
6
                dbuf_putc(bc, OP_object);
29660
6
                dbuf_putc(bc, OP_get_loc);
29661
6
                dbuf_put_u16(bc, var_idx);
29662
6
                dbuf_putc(bc, OP_define_field);
29663
6
                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29664
6
                dbuf_putc(bc, OP_push_atom_value);
29665
6
                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29666
6
            } else
29667
3.70k
            if (label_done == -1 && can_opt_put_ref_value(bc_buf, ls->pos)) {
29668
2.56k
                int get_op;
29669
2.56k
                if (var_idx & ARGUMENT_VAR_OFFSET) {
29670
1.09k
                    get_op = OP_get_arg;
29671
1.09k
                    var_idx -= ARGUMENT_VAR_OFFSET;
29672
1.47k
                } else {
29673
1.47k
                    if (s->vars[var_idx].is_lexical)
29674
373
                        get_op = OP_get_loc_check;
29675
1.10k
                    else
29676
1.10k
                        get_op = OP_get_loc;
29677
1.47k
                }
29678
2.56k
                pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
29679
2.56k
                                                   pos_next, get_op, var_idx);
29680
2.56k
            } else {
29681
                /* Create a dummy object with a named slot that is
29682
                   a reference to the local variable */
29683
1.13k
                if (var_idx & ARGUMENT_VAR_OFFSET) {
29684
166
                    dbuf_putc(bc, OP_make_arg_ref);
29685
166
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29686
166
                    dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
29687
973
                } else {
29688
973
                    dbuf_putc(bc, OP_make_loc_ref);
29689
973
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29690
973
                    dbuf_put_u16(bc, var_idx);
29691
973
                }
29692
1.13k
            }
29693
3.71k
            break;
29694
275
        case OP_scope_get_ref:
29695
275
            dbuf_putc(bc, OP_undefined);
29696
            /* fall thru */
29697
278
        case OP_scope_get_var_undef:
29698
53.6k
        case OP_scope_get_var:
29699
57.0k
        case OP_scope_put_var:
29700
95.0k
        case OP_scope_put_var_init:
29701
95.0k
            is_put = (op == OP_scope_put_var || op == OP_scope_put_var_init);
29702
95.0k
            if (var_idx & ARGUMENT_VAR_OFFSET) {
29703
609
                dbuf_putc(bc, OP_get_arg + is_put);
29704
609
                dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
29705
94.4k
            } else {
29706
94.4k
                if (is_put) {
29707
41.4k
                    if (s->vars[var_idx].is_lexical) {
29708
37.9k
                        if (op == OP_scope_put_var_init) {
29709
                            /* 'this' can only be initialized once */
29710
37.9k
                            if (var_name == JS_ATOM_this)
29711
0
                                dbuf_putc(bc, OP_put_loc_check_init);
29712
37.9k
                            else
29713
37.9k
                                dbuf_putc(bc, OP_put_loc);
29714
37.9k
                        } else {
29715
0
                            dbuf_putc(bc, OP_put_loc_check);
29716
0
                        }
29717
37.9k
                    } else {
29718
3.46k
                        dbuf_putc(bc, OP_put_loc);
29719
3.46k
                    }
29720
53.0k
                } else {
29721
53.0k
                    if (s->vars[var_idx].is_lexical) {
29722
4.54k
                        dbuf_putc(bc, OP_get_loc_check);
29723
48.4k
                    } else {
29724
48.4k
                        dbuf_putc(bc, OP_get_loc);
29725
48.4k
                    }
29726
53.0k
                }
29727
94.4k
                dbuf_put_u16(bc, var_idx);
29728
94.4k
            }
29729
95.0k
            break;
29730
0
        case OP_scope_delete_var:
29731
0
            dbuf_putc(bc, OP_push_false);
29732
0
            break;
29733
98.7k
        }
29734
98.7k
        goto done;
29735
98.7k
    }
29736
    /* check eval object */
29737
548k
    if (!is_arg_scope && s->var_object_idx >= 0 && !is_pseudo_var) {
29738
618
        dbuf_putc(bc, OP_get_loc);
29739
618
        dbuf_put_u16(bc, s->var_object_idx);
29740
618
        var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
29741
618
    }
29742
    /* check eval object in argument scope */
29743
548k
    if (s->arg_var_object_idx >= 0 && !is_pseudo_var) {
29744
0
        dbuf_putc(bc, OP_get_loc);
29745
0
        dbuf_put_u16(bc, s->arg_var_object_idx);
29746
0
        var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
29747
0
    }
29748
29749
    /* check parent scopes */
29750
574k
    for (fd = s; fd->parent;) {
29751
81.9k
        scope_level = fd->parent_scope_level;
29752
81.9k
        fd = fd->parent;
29753
125k
        for (idx = fd->scopes[scope_level].first; idx >= 0;) {
29754
63.1k
            vd = &fd->vars[idx];
29755
63.1k
            if (vd->var_name == var_name) {
29756
19.5k
                if (op == OP_scope_put_var || op == OP_scope_make_ref) {
29757
441
                    if (vd->is_const) {
29758
33
                        dbuf_putc(bc, OP_throw_error);
29759
33
                        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29760
33
                        dbuf_putc(bc, JS_THROW_VAR_RO);
29761
33
                        goto done;
29762
33
                    }
29763
441
                }
29764
19.4k
                var_idx = idx;
29765
19.4k
                break;
29766
43.6k
            } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
29767
7.68k
                vd->is_captured = 1;
29768
7.68k
                idx = get_closure_var(ctx, s, fd, FALSE, idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
29769
7.68k
                if (idx >= 0) {
29770
7.68k
                    dbuf_putc(bc, OP_get_var_ref);
29771
7.68k
                    dbuf_put_u16(bc, idx);
29772
7.68k
                    var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
29773
7.68k
                }
29774
7.68k
            }
29775
43.6k
            idx = vd->scope_next;
29776
43.6k
        }
29777
81.9k
        is_arg_scope = (idx == ARG_SCOPE_END);
29778
81.9k
        if (var_idx >= 0)
29779
19.4k
            break;
29780
        
29781
62.4k
        if (!is_arg_scope) {
29782
61.8k
            var_idx = find_var(ctx, fd, var_name);
29783
61.8k
            if (var_idx >= 0)
29784
4.09k
                break;
29785
61.8k
        }
29786
58.3k
        if (is_pseudo_var) {
29787
34
            var_idx = resolve_pseudo_var(ctx, fd, var_name);
29788
34
            if (var_idx >= 0)
29789
20
                break;
29790
34
        }
29791
58.3k
        if (var_name == JS_ATOM_arguments && fd->has_arguments_binding) {
29792
0
            var_idx = add_arguments_var(ctx, fd);
29793
0
            break;
29794
0
        }
29795
58.3k
        if (fd->is_func_expr && fd->func_name == var_name) {
29796
            /* add a new variable with the function name */
29797
52
            var_idx = add_func_var(ctx, fd, var_name);
29798
52
            break;
29799
52
        }
29800
29801
        /* check eval object */
29802
58.2k
        if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
29803
18
            vd = &fd->vars[fd->var_object_idx];
29804
18
            vd->is_captured = 1;
29805
18
            idx = get_closure_var(ctx, s, fd, FALSE,
29806
18
                                  fd->var_object_idx, vd->var_name,
29807
18
                                  FALSE, FALSE, JS_VAR_NORMAL);
29808
18
            dbuf_putc(bc, OP_get_var_ref);
29809
18
            dbuf_put_u16(bc, idx);
29810
18
            var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
29811
18
        }
29812
29813
        /* check eval object in argument scope */
29814
58.2k
        if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
29815
0
            vd = &fd->vars[fd->arg_var_object_idx];
29816
0
            vd->is_captured = 1;
29817
0
            idx = get_closure_var(ctx, s, fd, FALSE,
29818
0
                                  fd->arg_var_object_idx, vd->var_name,
29819
0
                                  FALSE, FALSE, JS_VAR_NORMAL);
29820
0
            dbuf_putc(bc, OP_get_var_ref);
29821
0
            dbuf_put_u16(bc, idx);
29822
0
            var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
29823
0
        }
29824
        
29825
58.2k
        if (fd->is_eval)
29826
32.6k
            break; /* it it necessarily the top level function */
29827
58.2k
    }
29828
29829
    /* check direct eval scope (in the closure of the eval function
29830
       which is necessarily at the top level) */
29831
548k
    if (!fd)
29832
0
        fd = s;
29833
548k
    if (var_idx < 0 && fd->is_eval) {
29834
524k
        int idx1;
29835
539k
        for (idx1 = 0; idx1 < fd->closure_var_count; idx1++) {
29836
16.0k
            JSClosureVar *cv = &fd->closure_var[idx1];
29837
16.0k
            if (var_name == cv->var_name) {
29838
1.44k
                if (fd != s) {
29839
128
                    idx = get_closure_var2(ctx, s, fd,
29840
128
                                           FALSE,
29841
128
                                           cv->is_arg, idx1,
29842
128
                                           cv->var_name, cv->is_const,
29843
128
                                           cv->is_lexical, cv->var_kind);
29844
1.32k
                } else {
29845
1.32k
                    idx = idx1;
29846
1.32k
                }
29847
1.44k
                goto has_idx;
29848
14.5k
            } else if ((cv->var_name == JS_ATOM__var_ ||
29849
14.5k
                        cv->var_name == JS_ATOM__arg_var_ ||
29850
14.5k
                        cv->var_name == JS_ATOM__with_) && !is_pseudo_var) {
29851
0
                int is_with = (cv->var_name == JS_ATOM__with_);
29852
0
                if (fd != s) {
29853
0
                    idx = get_closure_var2(ctx, s, fd,
29854
0
                                           FALSE,
29855
0
                                           cv->is_arg, idx1,
29856
0
                                           cv->var_name, FALSE, FALSE,
29857
0
                                           JS_VAR_NORMAL);
29858
0
                } else {
29859
0
                    idx = idx1;
29860
0
                }
29861
0
                dbuf_putc(bc, OP_get_var_ref);
29862
0
                dbuf_put_u16(bc, idx);
29863
0
                var_object_test(ctx, s, var_name, op, bc, &label_done, is_with);
29864
0
            }
29865
16.0k
        }
29866
524k
    }
29867
29868
547k
    if (var_idx >= 0) {
29869
        /* find the corresponding closure variable */
29870
23.6k
        if (var_idx & ARGUMENT_VAR_OFFSET) {
29871
3.78k
            fd->args[var_idx - ARGUMENT_VAR_OFFSET].is_captured = 1;
29872
3.78k
            idx = get_closure_var(ctx, s, fd,
29873
3.78k
                                  TRUE, var_idx - ARGUMENT_VAR_OFFSET,
29874
3.78k
                                  var_name, FALSE, FALSE, JS_VAR_NORMAL);
29875
19.8k
        } else {
29876
19.8k
            fd->vars[var_idx].is_captured = 1;
29877
19.8k
            idx = get_closure_var(ctx, s, fd,
29878
19.8k
                                  FALSE, var_idx,
29879
19.8k
                                  var_name,
29880
19.8k
                                  fd->vars[var_idx].is_const,
29881
19.8k
                                  fd->vars[var_idx].is_lexical,
29882
19.8k
                                  fd->vars[var_idx].var_kind);
29883
19.8k
        }
29884
23.6k
        if (idx >= 0) {
29885
25.1k
        has_idx:
29886
25.1k
            if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
29887
25.1k
                s->closure_var[idx].is_const) {
29888
0
                dbuf_putc(bc, OP_throw_error);
29889
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29890
0
                dbuf_putc(bc, JS_THROW_VAR_RO);
29891
0
                goto done;
29892
0
            }
29893
25.1k
            switch (op) {
29894
4.88k
            case OP_scope_make_ref:
29895
4.88k
                if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
29896
                    /* Create a dummy object reference for the func_var */
29897
121
                    dbuf_putc(bc, OP_object);
29898
121
                    dbuf_putc(bc, OP_get_var_ref);
29899
121
                    dbuf_put_u16(bc, idx);
29900
121
                    dbuf_putc(bc, OP_define_field);
29901
121
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29902
121
                    dbuf_putc(bc, OP_push_atom_value);
29903
121
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29904
121
                } else
29905
4.76k
                if (label_done == -1 &&
29906
4.76k
                    can_opt_put_ref_value(bc_buf, ls->pos)) {
29907
4.32k
                    int get_op;
29908
4.32k
                    if (s->closure_var[idx].is_lexical)
29909
137
                        get_op = OP_get_var_ref_check;
29910
4.19k
                    else
29911
4.19k
                        get_op = OP_get_var_ref;
29912
4.32k
                    pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
29913
4.32k
                                                       pos_next,
29914
4.32k
                                                       get_op, idx);
29915
4.32k
                } else {
29916
                    /* Create a dummy object with a named slot that is
29917
                       a reference to the closure variable */
29918
435
                    dbuf_putc(bc, OP_make_var_ref_ref);
29919
435
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29920
435
                    dbuf_put_u16(bc, idx);
29921
435
                }
29922
4.88k
                break;
29923
268
            case OP_scope_get_ref:
29924
                /* XXX: should create a dummy object with a named slot that is
29925
                   a reference to the closure variable */
29926
268
                dbuf_putc(bc, OP_undefined);
29927
                /* fall thru */
29928
278
            case OP_scope_get_var_undef:
29929
20.2k
            case OP_scope_get_var:
29930
20.2k
            case OP_scope_put_var:
29931
20.2k
            case OP_scope_put_var_init:
29932
20.2k
                is_put = (op == OP_scope_put_var ||
29933
20.2k
                          op == OP_scope_put_var_init);
29934
20.2k
                if (is_put) {
29935
5
                    if (s->closure_var[idx].is_lexical) {
29936
5
                        if (op == OP_scope_put_var_init) {
29937
                            /* 'this' can only be initialized once */
29938
5
                            if (var_name == JS_ATOM_this)
29939
0
                                dbuf_putc(bc, OP_put_var_ref_check_init);
29940
5
                            else
29941
5
                                dbuf_putc(bc, OP_put_var_ref);
29942
5
                        } else {
29943
0
                            dbuf_putc(bc, OP_put_var_ref_check);
29944
0
                        }
29945
5
                    } else {
29946
0
                        dbuf_putc(bc, OP_put_var_ref);
29947
0
                    }
29948
20.2k
                } else {
29949
20.2k
                    if (s->closure_var[idx].is_lexical) {
29950
19.1k
                        dbuf_putc(bc, OP_get_var_ref_check);
29951
19.1k
                    } else {
29952
1.05k
                        dbuf_putc(bc, OP_get_var_ref);
29953
1.05k
                    }
29954
20.2k
                }
29955
20.2k
                dbuf_put_u16(bc, idx);
29956
20.2k
                break;
29957
0
            case OP_scope_delete_var:
29958
0
                dbuf_putc(bc, OP_push_false);
29959
0
                break;
29960
25.1k
            }
29961
25.1k
            goto done;
29962
25.1k
        }
29963
23.6k
    }
29964
29965
    /* global variable access */
29966
29967
523k
    switch (op) {
29968
258k
    case OP_scope_make_ref:
29969
258k
        if (label_done == -1 && can_opt_put_global_ref_value(bc_buf, ls->pos)) {
29970
41.1k
            pos_next = optimize_scope_make_global_ref(ctx, s, bc, bc_buf, ls,
29971
41.1k
                                                      pos_next, var_name);
29972
217k
        } else {
29973
217k
            dbuf_putc(bc, OP_make_var_ref);
29974
217k
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29975
217k
        }
29976
258k
        break;
29977
1.33k
    case OP_scope_get_ref:
29978
        /* XXX: should create a dummy object with a named slot that is
29979
           a reference to the global variable */
29980
1.33k
        dbuf_putc(bc, OP_undefined);
29981
1.33k
        dbuf_putc(bc, OP_get_var);
29982
1.33k
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29983
1.33k
        break;
29984
87
    case OP_scope_get_var_undef:
29985
262k
    case OP_scope_get_var:
29986
262k
    case OP_scope_put_var:
29987
262k
        dbuf_putc(bc, OP_get_var_undef + (op - OP_scope_get_var_undef));
29988
262k
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29989
262k
        break;
29990
10
    case OP_scope_put_var_init:
29991
10
        dbuf_putc(bc, OP_put_var_init);
29992
10
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29993
10
        break;
29994
1.25k
    case OP_scope_delete_var:
29995
1.25k
        dbuf_putc(bc, OP_delete_var);
29996
1.25k
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29997
1.25k
        break;
29998
523k
    }
29999
647k
done:
30000
647k
    if (label_done >= 0) {
30001
399k
        dbuf_putc(bc, OP_label);
30002
399k
        dbuf_put_u32(bc, label_done);
30003
399k
        s->label_slots[label_done].pos2 = bc->size;
30004
399k
    }
30005
647k
    return pos_next;
30006
523k
}
30007
30008
/* search in all scopes */
30009
static int find_private_class_field_all(JSContext *ctx, JSFunctionDef *fd,
30010
                                        JSAtom name, int scope_level)
30011
14
{
30012
14
    int idx;
30013
30014
14
    idx = fd->scopes[scope_level].first;
30015
32
    while (idx >= 0) {
30016
21
        if (fd->vars[idx].var_name == name)
30017
3
            return idx;
30018
18
        idx = fd->vars[idx].scope_next;
30019
18
    }
30020
11
    return -1;
30021
14
}
30022
30023
static void get_loc_or_ref(DynBuf *bc, BOOL is_ref, int idx)
30024
3
{
30025
    /* if the field is not initialized, the error is catched when
30026
       accessing it */
30027
3
    if (is_ref) 
30028
3
        dbuf_putc(bc, OP_get_var_ref);
30029
0
    else
30030
0
        dbuf_putc(bc, OP_get_loc);
30031
3
    dbuf_put_u16(bc, idx);
30032
3
}
30033
30034
static int resolve_scope_private_field1(JSContext *ctx,
30035
                                        BOOL *pis_ref, int *pvar_kind,
30036
                                        JSFunctionDef *s,
30037
                                        JSAtom var_name, int scope_level)
30038
5
{
30039
5
    int idx, var_kind;
30040
5
    JSFunctionDef *fd;
30041
5
    BOOL is_ref;
30042
    
30043
5
    fd = s;
30044
5
    is_ref = FALSE;
30045
14
    for(;;) {
30046
14
        idx = find_private_class_field_all(ctx, fd, var_name, scope_level);
30047
14
        if (idx >= 0) {
30048
3
            var_kind = fd->vars[idx].var_kind;
30049
3
            if (is_ref) {
30050
3
                idx = get_closure_var(ctx, s, fd, FALSE, idx, var_name,
30051
3
                                      TRUE, TRUE, JS_VAR_NORMAL);
30052
3
                if (idx < 0)
30053
0
                    return -1;
30054
3
            }
30055
3
            break;
30056
3
        }
30057
11
        scope_level = fd->parent_scope_level;
30058
11
        if (!fd->parent) {
30059
2
            if (fd->is_eval) {
30060
                /* closure of the eval function (top level) */
30061
2
                for (idx = 0; idx < fd->closure_var_count; idx++) {
30062
0
                    JSClosureVar *cv = &fd->closure_var[idx];
30063
0
                    if (cv->var_name == var_name) {
30064
0
                        var_kind = cv->var_kind;
30065
0
                        is_ref = TRUE;
30066
0
                        if (fd != s) {
30067
0
                            idx = get_closure_var2(ctx, s, fd,
30068
0
                                                   FALSE,
30069
0
                                                   cv->is_arg, idx,
30070
0
                                                   cv->var_name, cv->is_const,
30071
0
                                                   cv->is_lexical,
30072
0
                                                   cv->var_kind);
30073
0
                            if (idx < 0)
30074
0
                                return -1;
30075
0
                        }
30076
0
                        goto done;
30077
0
                    }
30078
0
                }
30079
2
            }
30080
            /* XXX: no line number info */
30081
2
            JS_ThrowSyntaxErrorAtom(ctx, "undefined private field '%s'",
30082
2
                                    var_name);
30083
2
            return -1;
30084
9
        } else {
30085
9
            fd = fd->parent;
30086
9
        }
30087
9
        is_ref = TRUE;
30088
9
    }
30089
3
 done:
30090
3
    *pis_ref = is_ref;
30091
3
    *pvar_kind = var_kind;
30092
3
    return idx;
30093
5
}
30094
30095
/* return 0 if OK or -1 if the private field could not be resolved */
30096
static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
30097
                                       JSAtom var_name, int scope_level, int op,
30098
                                       DynBuf *bc)
30099
5
{
30100
5
    int idx, var_kind;
30101
5
    BOOL is_ref;
30102
30103
5
    idx = resolve_scope_private_field1(ctx, &is_ref, &var_kind, s,
30104
5
                                       var_name, scope_level);
30105
5
    if (idx < 0)
30106
2
        return -1;
30107
3
    assert(var_kind != JS_VAR_NORMAL);
30108
3
    switch (op) {
30109
3
    case OP_scope_get_private_field:
30110
3
    case OP_scope_get_private_field2:
30111
3
        switch(var_kind) {
30112
3
        case JS_VAR_PRIVATE_FIELD:
30113
3
            if (op == OP_scope_get_private_field2)
30114
0
                dbuf_putc(bc, OP_dup);
30115
3
            get_loc_or_ref(bc, is_ref, idx);
30116
3
            dbuf_putc(bc, OP_get_private_field);
30117
3
            break;
30118
0
        case JS_VAR_PRIVATE_METHOD:
30119
0
            get_loc_or_ref(bc, is_ref, idx);
30120
0
            dbuf_putc(bc, OP_check_brand);
30121
0
            if (op != OP_scope_get_private_field2)
30122
0
                dbuf_putc(bc, OP_nip);
30123
0
            break;
30124
0
        case JS_VAR_PRIVATE_GETTER:
30125
0
        case JS_VAR_PRIVATE_GETTER_SETTER:
30126
0
            if (op == OP_scope_get_private_field2)
30127
0
                dbuf_putc(bc, OP_dup);
30128
0
            get_loc_or_ref(bc, is_ref, idx);
30129
0
            dbuf_putc(bc, OP_check_brand);
30130
0
            dbuf_putc(bc, OP_call_method);
30131
0
            dbuf_put_u16(bc, 0);
30132
0
            break;
30133
0
        case JS_VAR_PRIVATE_SETTER:
30134
            /* XXX: add clearer error message */
30135
0
            dbuf_putc(bc, OP_throw_error);
30136
0
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30137
0
            dbuf_putc(bc, JS_THROW_VAR_RO);
30138
0
            break;
30139
0
        default:
30140
0
            abort();
30141
3
        }
30142
3
        break;
30143
3
    case OP_scope_put_private_field:
30144
0
        switch(var_kind) {
30145
0
        case JS_VAR_PRIVATE_FIELD:
30146
0
            get_loc_or_ref(bc, is_ref, idx);
30147
0
            dbuf_putc(bc, OP_put_private_field);
30148
0
            break;
30149
0
        case JS_VAR_PRIVATE_METHOD:
30150
0
        case JS_VAR_PRIVATE_GETTER:
30151
            /* XXX: add clearer error message */
30152
0
            dbuf_putc(bc, OP_throw_error);
30153
0
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30154
0
            dbuf_putc(bc, JS_THROW_VAR_RO);
30155
0
            break;
30156
0
        case JS_VAR_PRIVATE_SETTER:
30157
0
        case JS_VAR_PRIVATE_GETTER_SETTER:
30158
0
            {
30159
0
                JSAtom setter_name = get_private_setter_name(ctx, var_name);
30160
0
                if (setter_name == JS_ATOM_NULL)
30161
0
                    return -1;
30162
0
                idx = resolve_scope_private_field1(ctx, &is_ref,
30163
0
                                                   &var_kind, s,
30164
0
                                                   setter_name, scope_level);
30165
0
                JS_FreeAtom(ctx, setter_name);
30166
0
                if (idx < 0)
30167
0
                    return -1;
30168
0
                assert(var_kind == JS_VAR_PRIVATE_SETTER);
30169
0
                get_loc_or_ref(bc, is_ref, idx);
30170
0
                dbuf_putc(bc, OP_swap);
30171
                /* obj func value */
30172
0
                dbuf_putc(bc, OP_rot3r);
30173
                /* value obj func */
30174
0
                dbuf_putc(bc, OP_check_brand);
30175
0
                dbuf_putc(bc, OP_rot3l);
30176
                /* obj func value */
30177
0
                dbuf_putc(bc, OP_call_method);
30178
0
                dbuf_put_u16(bc, 1);
30179
0
            }
30180
0
            break;
30181
0
        default:
30182
0
            abort();
30183
0
        }
30184
0
        break;
30185
0
    default:
30186
0
        abort();
30187
3
    }
30188
3
    return 0;
30189
3
}
30190
30191
static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,
30192
                                         int scope_level)
30193
43
{
30194
43
    int idx;
30195
43
    JSVarDef *vd;
30196
30197
43
    for (idx = s->scopes[scope_level].first; idx >= 0;) {
30198
0
        vd = &s->vars[idx];
30199
0
        vd->is_captured = 1;
30200
0
        idx = vd->scope_next;
30201
0
    }
30202
43
}
30203
30204
/* XXX: should handle the argument scope generically */
30205
static BOOL is_var_in_arg_scope(const JSVarDef *vd)
30206
0
{
30207
0
    return (vd->var_name == JS_ATOM_home_object ||
30208
0
            vd->var_name == JS_ATOM_this_active_func ||
30209
0
            vd->var_name == JS_ATOM_new_target ||
30210
0
            vd->var_name == JS_ATOM_this ||
30211
0
            vd->var_name == JS_ATOM__arg_var_ ||
30212
0
            vd->var_kind == JS_VAR_FUNCTION_NAME);
30213
0
}
30214
30215
static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
30216
18
{
30217
18
    JSFunctionDef *fd;
30218
18
    JSVarDef *vd;
30219
18
    int i, scope_level, scope_idx;
30220
18
    BOOL has_arguments_binding, has_this_binding, is_arg_scope;
30221
30222
    /* in non strict mode, variables are created in the caller's
30223
       environment object */
30224
18
    if (!s->is_eval && !(s->js_mode & JS_MODE_STRICT)) {
30225
9
        s->var_object_idx = add_var(ctx, s, JS_ATOM__var_);
30226
9
        if (s->has_parameter_expressions) {
30227
            /* an additional variable object is needed for the
30228
               argument scope */
30229
0
            s->arg_var_object_idx = add_var(ctx, s, JS_ATOM__arg_var_);
30230
0
        }
30231
9
    }
30232
30233
    /* eval can potentially use 'arguments' so we must define it */
30234
18
    has_this_binding = s->has_this_binding;
30235
18
    if (has_this_binding) {
30236
14
        if (s->this_var_idx < 0)
30237
14
            s->this_var_idx = add_var_this(ctx, s);
30238
14
        if (s->new_target_var_idx < 0)
30239
14
            s->new_target_var_idx = add_var(ctx, s, JS_ATOM_new_target);
30240
14
        if (s->is_derived_class_constructor && s->this_active_func_var_idx < 0)
30241
0
            s->this_active_func_var_idx = add_var(ctx, s, JS_ATOM_this_active_func);
30242
14
        if (s->has_home_object && s->home_object_var_idx < 0)
30243
0
            s->home_object_var_idx = add_var(ctx, s, JS_ATOM_home_object);
30244
14
    }
30245
18
    has_arguments_binding = s->has_arguments_binding;
30246
18
    if (has_arguments_binding) {
30247
5
        add_arguments_var(ctx, s);
30248
        /* also add an arguments binding in the argument scope to
30249
           raise an error if a direct eval in the argument scope tries
30250
           to redefine it */
30251
5
        if (s->has_parameter_expressions && !(s->js_mode & JS_MODE_STRICT))
30252
0
            add_arguments_arg(ctx, s);
30253
5
    }
30254
18
    if (s->is_func_expr && s->func_name != JS_ATOM_NULL)
30255
5
        add_func_var(ctx, s, s->func_name);
30256
30257
    /* eval can use all the variables of the enclosing functions, so
30258
       they must be all put in the closure. The closure variables are
30259
       ordered by scope. It works only because no closure are created
30260
       before. */
30261
18
    assert(s->is_eval || s->closure_var_count == 0);
30262
30263
    /* XXX: inefficient, but eval performance is less critical */
30264
18
    fd = s;
30265
31
    for(;;) {
30266
31
        scope_level = fd->parent_scope_level;
30267
31
        fd = fd->parent;
30268
31
        if (!fd)
30269
18
            break;
30270
        /* add 'this' if it was not previously added */
30271
13
        if (!has_this_binding && fd->has_this_binding) {
30272
4
            if (fd->this_var_idx < 0)
30273
1
                fd->this_var_idx = add_var_this(ctx, fd);
30274
4
            if (fd->new_target_var_idx < 0)
30275
1
                fd->new_target_var_idx = add_var(ctx, fd, JS_ATOM_new_target);
30276
4
            if (fd->is_derived_class_constructor && fd->this_active_func_var_idx < 0)
30277
0
                fd->this_active_func_var_idx = add_var(ctx, fd, JS_ATOM_this_active_func);
30278
4
            if (fd->has_home_object && fd->home_object_var_idx < 0)
30279
0
                fd->home_object_var_idx = add_var(ctx, fd, JS_ATOM_home_object);
30280
4
            has_this_binding = TRUE;
30281
4
        }
30282
        /* add 'arguments' if it was not previously added */
30283
13
        if (!has_arguments_binding && fd->has_arguments_binding) {
30284
4
            add_arguments_var(ctx, fd);
30285
4
            has_arguments_binding = TRUE;
30286
4
        }
30287
        /* add function name */
30288
13
        if (fd->is_func_expr && fd->func_name != JS_ATOM_NULL)
30289
4
            add_func_var(ctx, fd, fd->func_name);
30290
30291
        /* add lexical variables */
30292
13
        scope_idx = fd->scopes[scope_level].first;
30293
13
        while (scope_idx >= 0) {
30294
0
            vd = &fd->vars[scope_idx];
30295
0
            vd->is_captured = 1;
30296
0
            get_closure_var(ctx, s, fd, FALSE, scope_idx,
30297
0
                            vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);
30298
0
            scope_idx = vd->scope_next;
30299
0
        }
30300
13
        is_arg_scope = (scope_idx == ARG_SCOPE_END);
30301
13
        if (!is_arg_scope) {
30302
            /* add unscoped variables */
30303
13
            for(i = 0; i < fd->arg_count; i++) {
30304
0
                vd = &fd->args[i];
30305
0
                if (vd->var_name != JS_ATOM_NULL) {
30306
0
                    get_closure_var(ctx, s, fd,
30307
0
                                    TRUE, i, vd->var_name, FALSE, FALSE,
30308
0
                                    JS_VAR_NORMAL);
30309
0
                }
30310
0
            }
30311
58
            for(i = 0; i < fd->var_count; i++) {
30312
45
                vd = &fd->vars[i];
30313
                /* do not close top level last result */
30314
45
                if (vd->scope_level == 0 &&
30315
45
                    vd->var_name != JS_ATOM__ret_ &&
30316
45
                    vd->var_name != JS_ATOM_NULL) {
30317
27
                    get_closure_var(ctx, s, fd,
30318
27
                                    FALSE, i, vd->var_name, FALSE, FALSE,
30319
27
                                    JS_VAR_NORMAL);
30320
27
                }
30321
45
            }
30322
13
        } else {
30323
0
            for(i = 0; i < fd->var_count; i++) {
30324
0
                vd = &fd->vars[i];
30325
                /* do not close top level last result */
30326
0
                if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
30327
0
                    get_closure_var(ctx, s, fd,
30328
0
                                    FALSE, i, vd->var_name, FALSE, FALSE,
30329
0
                                    JS_VAR_NORMAL);
30330
0
                }
30331
0
            }
30332
0
        }
30333
13
        if (fd->is_eval) {
30334
9
            int idx;
30335
            /* add direct eval variables (we are necessarily at the
30336
               top level) */
30337
9
            for (idx = 0; idx < fd->closure_var_count; idx++) {
30338
0
                JSClosureVar *cv = &fd->closure_var[idx];
30339
0
                get_closure_var2(ctx, s, fd,
30340
0
                                 FALSE, cv->is_arg,
30341
0
                                 idx, cv->var_name, cv->is_const,
30342
0
                                 cv->is_lexical, cv->var_kind);
30343
0
            }
30344
9
        }
30345
13
    }
30346
18
}
30347
30348
static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
30349
                                 JSVarDef *vd, int var_idx)
30350
1.07k
{
30351
1.07k
    cv->is_local = TRUE;
30352
1.07k
    cv->is_arg = FALSE;
30353
1.07k
    cv->is_const = vd->is_const;
30354
1.07k
    cv->is_lexical = vd->is_lexical;
30355
1.07k
    cv->var_kind = vd->var_kind;
30356
1.07k
    cv->var_idx = var_idx;
30357
1.07k
    cv->var_name = JS_DupAtom(ctx, vd->var_name);
30358
1.07k
}
30359
30360
/* for direct eval compilation: add references to the variables of the
30361
   calling function */
30362
static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
30363
                                             JSFunctionBytecode *b, int scope_idx)
30364
534
{
30365
534
    int i, count;
30366
534
    JSVarDef *vd;
30367
534
    BOOL is_arg_scope;
30368
    
30369
534
    count = b->arg_count + b->var_count + b->closure_var_count;
30370
534
    s->closure_var = NULL;
30371
534
    s->closure_var_count = 0;
30372
534
    s->closure_var_size = count;
30373
534
    if (count == 0)
30374
0
        return 0;
30375
534
    s->closure_var = js_malloc(ctx, sizeof(s->closure_var[0]) * count);
30376
534
    if (!s->closure_var)
30377
0
        return -1;
30378
    /* Add lexical variables in scope at the point of evaluation */
30379
534
    for (i = scope_idx; i >= 0;) {
30380
0
        vd = &b->vardefs[b->arg_count + i];
30381
0
        if (vd->scope_level > 0) {
30382
0
            JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
30383
0
            set_closure_from_var(ctx, cv, vd, i);
30384
0
        }
30385
0
        i = vd->scope_next;
30386
0
    }
30387
534
    is_arg_scope = (i == ARG_SCOPE_END);
30388
534
    if (!is_arg_scope) {
30389
        /* Add argument variables */
30390
534
        for(i = 0; i < b->arg_count; i++) {
30391
0
            JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
30392
0
            vd = &b->vardefs[i];
30393
0
            cv->is_local = TRUE;
30394
0
            cv->is_arg = TRUE;
30395
0
            cv->is_const = FALSE;
30396
0
            cv->is_lexical = FALSE;
30397
0
            cv->var_kind = JS_VAR_NORMAL;
30398
0
            cv->var_idx = i;
30399
0
            cv->var_name = JS_DupAtom(ctx, vd->var_name);
30400
0
        }
30401
        /* Add local non lexical variables */
30402
1.61k
        for(i = 0; i < b->var_count; i++) {
30403
1.07k
            vd = &b->vardefs[b->arg_count + i];
30404
1.07k
            if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) {
30405
1.07k
                JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
30406
1.07k
                set_closure_from_var(ctx, cv, vd, i);
30407
1.07k
            }
30408
1.07k
        }
30409
534
    } else {
30410
        /* only add pseudo variables */
30411
0
        for(i = 0; i < b->var_count; i++) {
30412
0
            vd = &b->vardefs[b->arg_count + i];
30413
0
            if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
30414
0
                JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
30415
0
                set_closure_from_var(ctx, cv, vd, i);
30416
0
            }
30417
0
        }
30418
0
    }
30419
598
    for(i = 0; i < b->closure_var_count; i++) {
30420
64
        JSClosureVar *cv0 = &b->closure_var[i];
30421
64
        JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
30422
64
        cv->is_local = FALSE;
30423
64
        cv->is_arg = cv0->is_arg;
30424
64
        cv->is_const = cv0->is_const;
30425
64
        cv->is_lexical = cv0->is_lexical;
30426
64
        cv->var_kind = cv0->var_kind;
30427
64
        cv->var_idx = i;
30428
64
        cv->var_name = JS_DupAtom(ctx, cv0->var_name);
30429
64
    }
30430
534
    return 0;
30431
534
}
30432
30433
typedef struct CodeContext {
30434
    const uint8_t *bc_buf; /* code buffer */
30435
    int bc_len;   /* length of the code buffer */
30436
    int pos;      /* position past the matched code pattern */
30437
    int line_num; /* last visited OP_line_num parameter or -1 */
30438
    int op;
30439
    int idx;
30440
    int label;
30441
    int val;
30442
    JSAtom atom;
30443
} CodeContext;
30444
30445
2.64M
#define M2(op1, op2)            ((op1) | ((op2) << 8))
30446
1.19M
#define M3(op1, op2, op3)       ((op1) | ((op2) << 8) | ((op3) << 16))
30447
545
#define M4(op1, op2, op3, op4)  ((op1) | ((op2) << 8) | ((op3) << 16) | ((op4) << 24))
30448
30449
static BOOL code_match(CodeContext *s, int pos, ...)
30450
6.55M
{
30451
6.55M
    const uint8_t *tab = s->bc_buf;
30452
6.55M
    int op, len, op1, line_num, pos_next;
30453
6.55M
    va_list ap;
30454
6.55M
    BOOL ret = FALSE;
30455
30456
6.55M
    line_num = -1;
30457
6.55M
    va_start(ap, pos);
30458
30459
7.04M
    for(;;) {
30460
7.04M
        op1 = va_arg(ap, int);
30461
7.04M
        if (op1 == -1) {
30462
258k
            s->pos = pos;
30463
258k
            s->line_num = line_num;
30464
258k
            ret = TRUE;
30465
258k
            break;
30466
258k
        }
30467
6.86M
        for (;;) {
30468
6.86M
            if (pos >= s->bc_len)
30469
0
                goto done;
30470
6.86M
            op = tab[pos];
30471
6.86M
            len = opcode_info[op].size;
30472
6.86M
            pos_next = pos + len;
30473
6.86M
            if (pos_next > s->bc_len)
30474
0
                goto done;
30475
6.86M
            if (op == OP_line_num) {
30476
84.2k
                line_num = get_u32(tab + pos + 1);
30477
84.2k
                pos = pos_next;
30478
6.78M
            } else {
30479
6.78M
                break;
30480
6.78M
            }
30481
6.86M
        }
30482
6.78M
        if (op != op1) {
30483
6.54M
            if (op1 == (uint8_t)op1 || !op)
30484
2.74M
                break;
30485
3.79M
            if (op != (uint8_t)op1
30486
3.79M
            &&  op != (uint8_t)(op1 >> 8)
30487
3.79M
            &&  op != (uint8_t)(op1 >> 16)
30488
3.79M
            &&  op != (uint8_t)(op1 >> 24)) {
30489
3.53M
                break;
30490
3.53M
            }
30491
252k
            s->op = op;
30492
252k
        }
30493
30494
494k
        pos++;
30495
494k
        switch(opcode_info[op].fmt) {
30496
0
        case OP_FMT_loc8:
30497
0
        case OP_FMT_u8:
30498
0
            {
30499
0
                int idx = tab[pos];
30500
0
                int arg = va_arg(ap, int);
30501
0
                if (arg == -1) {
30502
0
                    s->idx = idx;
30503
0
                } else {
30504
0
                    if (arg != idx)
30505
0
                        goto done;
30506
0
                }
30507
0
                break;
30508
0
            }
30509
0
        case OP_FMT_u16:
30510
0
        case OP_FMT_npop:
30511
19.1k
        case OP_FMT_loc:
30512
23.0k
        case OP_FMT_arg:
30513
27.3k
        case OP_FMT_var_ref:
30514
27.3k
            {
30515
27.3k
                int idx = get_u16(tab + pos);
30516
27.3k
                int arg = va_arg(ap, int);
30517
27.3k
                if (arg == -1) {
30518
16.7k
                    s->idx = idx;
30519
16.7k
                } else {
30520
10.5k
                    if (arg != idx)
30521
8.02k
                        goto done;
30522
10.5k
                }
30523
19.2k
                break;
30524
27.3k
            }
30525
19.2k
        case OP_FMT_i32:
30526
4
        case OP_FMT_u32:
30527
42.2k
        case OP_FMT_label:
30528
42.2k
        case OP_FMT_const:
30529
42.2k
            {
30530
42.2k
                s->label = get_u32(tab + pos);
30531
42.2k
                break;
30532
42.2k
            }
30533
0
        case OP_FMT_label_u16:
30534
0
            {
30535
0
                s->label = get_u32(tab + pos);
30536
0
                s->val = get_u16(tab + pos + 4);
30537
0
                break;
30538
42.2k
            }
30539
4.26k
        case OP_FMT_atom:
30540
4.26k
            {
30541
4.26k
                s->atom = get_u32(tab + pos);
30542
4.26k
                break;
30543
42.2k
            }
30544
0
        case OP_FMT_atom_u8:
30545
0
            {
30546
0
                s->atom = get_u32(tab + pos);
30547
0
                s->val = get_u8(tab + pos + 4);
30548
0
                break;
30549
42.2k
            }
30550
0
        case OP_FMT_atom_u16:
30551
0
            {
30552
0
                s->atom = get_u32(tab + pos);
30553
0
                s->val = get_u16(tab + pos + 4);
30554
0
                break;
30555
42.2k
            }
30556
0
        case OP_FMT_atom_label_u8:
30557
0
            {
30558
0
                s->atom = get_u32(tab + pos);
30559
0
                s->label = get_u32(tab + pos + 4);
30560
0
                s->val = get_u8(tab + pos + 8);
30561
0
                break;
30562
42.2k
            }
30563
420k
        default:
30564
420k
            break;
30565
494k
        }
30566
486k
        pos = pos_next;
30567
486k
    }
30568
6.55M
 done:
30569
6.55M
    va_end(ap);
30570
6.55M
    return ret;
30571
6.55M
}
30572
30573
static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, DynBuf *bc)
30574
22.8k
{
30575
22.8k
    int i, idx, label_next = -1;
30576
30577
    /* add the hoisted functions in arguments and local variables */
30578
36.2k
    for(i = 0; i < s->arg_count; i++) {
30579
13.3k
        JSVarDef *vd = &s->args[i];
30580
13.3k
        if (vd->func_pool_idx >= 0) {
30581
3
            dbuf_putc(bc, OP_fclosure);
30582
3
            dbuf_put_u32(bc, vd->func_pool_idx);
30583
3
            dbuf_putc(bc, OP_put_arg);
30584
3
            dbuf_put_u16(bc, i);
30585
3
        }
30586
13.3k
    }
30587
81.5k
    for(i = 0; i < s->var_count; i++) {
30588
58.6k
        JSVarDef *vd = &s->vars[i];
30589
58.6k
        if (vd->scope_level == 0 && vd->func_pool_idx >= 0) {
30590
88
            dbuf_putc(bc, OP_fclosure);
30591
88
            dbuf_put_u32(bc, vd->func_pool_idx);
30592
88
            dbuf_putc(bc, OP_put_loc);
30593
88
            dbuf_put_u16(bc, i);
30594
88
        }
30595
58.6k
    }
30596
30597
    /* the module global variables must be initialized before
30598
       evaluating the module so that the exported functions are
30599
       visible if there are cyclic module references */
30600
22.8k
    if (s->module) {
30601
122
        label_next = new_label_fd(s, -1);
30602
        
30603
        /* if 'this' is true, initialize the global variables and return */
30604
122
        dbuf_putc(bc, OP_push_this);
30605
122
        dbuf_putc(bc, OP_if_false);
30606
122
        dbuf_put_u32(bc, label_next);
30607
122
        update_label(s, label_next, 1);
30608
122
        s->jump_size++;
30609
122
    }
30610
    
30611
    /* add the global variables (only happens if s->is_global_var is
30612
       true) */
30613
32.1k
    for(i = 0; i < s->global_var_count; i++) {
30614
9.20k
        JSGlobalVar *hf = &s->global_vars[i];
30615
9.20k
        int has_closure = 0;
30616
9.20k
        BOOL force_init = hf->force_init;
30617
        /* we are in an eval, so the closure contains all the
30618
           enclosing variables */
30619
        /* If the outer function has a variable environment,
30620
           create a property for the variable there */
30621
14.0k
        for(idx = 0; idx < s->closure_var_count; idx++) {
30622
5.49k
            JSClosureVar *cv = &s->closure_var[idx];
30623
5.49k
            if (cv->var_name == hf->var_name) {
30624
607
                has_closure = 2;
30625
607
                force_init = FALSE;
30626
607
                break;
30627
607
            }
30628
4.88k
            if (cv->var_name == JS_ATOM__var_ ||
30629
4.88k
                cv->var_name == JS_ATOM__arg_var_) {
30630
0
                dbuf_putc(bc, OP_get_var_ref);
30631
0
                dbuf_put_u16(bc, idx);
30632
0
                has_closure = 1;
30633
0
                force_init = TRUE;
30634
0
                break;
30635
0
            }
30636
4.88k
        }
30637
9.20k
        if (!has_closure) {
30638
8.60k
            int flags;
30639
            
30640
8.60k
            flags = 0;
30641
8.60k
            if (s->eval_type != JS_EVAL_TYPE_GLOBAL)
30642
0
                flags |= JS_PROP_CONFIGURABLE;
30643
8.60k
            if (hf->cpool_idx >= 0 && !hf->is_lexical) {
30644
                /* global function definitions need a specific handling */
30645
971
                dbuf_putc(bc, OP_fclosure);
30646
971
                dbuf_put_u32(bc, hf->cpool_idx);
30647
                
30648
971
                dbuf_putc(bc, OP_define_func);
30649
971
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
30650
971
                dbuf_putc(bc, flags);
30651
                
30652
971
                goto done_global_var;
30653
7.63k
            } else {
30654
7.63k
                if (hf->is_lexical) {
30655
5
                    flags |= DEFINE_GLOBAL_LEX_VAR;
30656
5
                    if (!hf->is_const)
30657
5
                        flags |= JS_PROP_WRITABLE;
30658
5
                }
30659
7.63k
                dbuf_putc(bc, OP_define_var);
30660
7.63k
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
30661
7.63k
                dbuf_putc(bc, flags);
30662
7.63k
            }
30663
8.60k
        }
30664
8.23k
        if (hf->cpool_idx >= 0 || force_init) {
30665
0
            if (hf->cpool_idx >= 0) {
30666
0
                dbuf_putc(bc, OP_fclosure);
30667
0
                dbuf_put_u32(bc, hf->cpool_idx);
30668
0
                if (hf->var_name == JS_ATOM__default_) {
30669
                    /* set default export function name */
30670
0
                    dbuf_putc(bc, OP_set_name);
30671
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, JS_ATOM_default));
30672
0
                }
30673
0
            } else {
30674
0
                dbuf_putc(bc, OP_undefined);
30675
0
            }
30676
0
            if (has_closure == 2) {
30677
0
                dbuf_putc(bc, OP_put_var_ref);
30678
0
                dbuf_put_u16(bc, idx);
30679
0
            } else if (has_closure == 1) {
30680
0
                dbuf_putc(bc, OP_define_field);
30681
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
30682
0
                dbuf_putc(bc, OP_drop);
30683
0
            } else {
30684
                /* XXX: Check if variable is writable and enumerable */
30685
0
                dbuf_putc(bc, OP_put_var);
30686
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
30687
0
            }
30688
0
        }
30689
9.20k
    done_global_var:
30690
9.20k
        JS_FreeAtom(ctx, hf->var_name);
30691
9.20k
    }
30692
30693
22.8k
    if (s->module) {
30694
122
        dbuf_putc(bc, OP_return_undef);
30695
        
30696
122
        dbuf_putc(bc, OP_label);
30697
122
        dbuf_put_u32(bc, label_next);
30698
122
        s->label_slots[label_next].pos2 = bc->size;
30699
122
    }
30700
30701
22.8k
    js_free(ctx, s->global_vars);
30702
22.8k
    s->global_vars = NULL;
30703
22.8k
    s->global_var_count = 0;
30704
22.8k
    s->global_var_size = 0;
30705
22.8k
}
30706
30707
static int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len,
30708
                          int pos, int *linep)
30709
195k
{
30710
195k
    int op, len, label;
30711
30712
505k
    for (; pos < bc_len; pos += len) {
30713
442k
        op = bc_buf[pos];
30714
442k
        len = opcode_info[op].size;
30715
442k
        if (op == OP_line_num) {
30716
7.60k
            *linep = get_u32(bc_buf + pos + 1);
30717
7.60k
        } else
30718
435k
        if (op == OP_label) {
30719
153k
            label = get_u32(bc_buf + pos + 1);
30720
153k
            if (update_label(s, label, 0) > 0)
30721
133k
                break;
30722
#if 0
30723
            if (s->label_slots[label].first_reloc) {
30724
                printf("line %d: unreferenced label %d:%d has relocations\n",
30725
                       *linep, label, s->label_slots[label].pos2);
30726
            }
30727
#endif
30728
20.7k
            assert(s->label_slots[label].first_reloc == NULL);
30729
281k
        } else {
30730
            /* XXX: output a warning for unreachable code? */
30731
281k
            JSAtom atom;
30732
281k
            switch(opcode_info[op].fmt) {
30733
17.5k
            case OP_FMT_label:
30734
17.5k
            case OP_FMT_label_u16:
30735
17.5k
                label = get_u32(bc_buf + pos + 1);
30736
17.5k
                update_label(s, label, -1);
30737
17.5k
                break;
30738
18.4k
            case OP_FMT_atom_label_u8:
30739
18.8k
            case OP_FMT_atom_label_u16:
30740
18.8k
                label = get_u32(bc_buf + pos + 5);
30741
18.8k
                update_label(s, label, -1);
30742
                /* fall thru */
30743
36.3k
            case OP_FMT_atom:
30744
36.5k
            case OP_FMT_atom_u8:
30745
38.0k
            case OP_FMT_atom_u16:
30746
38.0k
                atom = get_u32(bc_buf + pos + 1);
30747
38.0k
                JS_FreeAtom(s->ctx, atom);
30748
38.0k
                break;
30749
225k
            default:
30750
225k
                break;
30751
281k
            }
30752
281k
        }
30753
442k
    }
30754
195k
    return pos;
30755
195k
}
30756
30757
static int get_label_pos(JSFunctionDef *s, int label)
30758
18.1k
{
30759
18.1k
    int i, pos;
30760
18.1k
    for (i = 0; i < 20; i++) {
30761
18.1k
        pos = s->label_slots[label].pos;
30762
18.1k
        for (;;) {
30763
18.1k
            switch (s->byte_code.buf[pos]) {
30764
0
            case OP_line_num:
30765
8
            case OP_label:
30766
8
                pos += 5;
30767
8
                continue;
30768
0
            case OP_goto:
30769
0
                label = get_u32(s->byte_code.buf + pos + 1);
30770
0
                break;
30771
18.1k
            default:
30772
18.1k
                return pos;
30773
18.1k
            }
30774
0
            break;
30775
18.1k
        }
30776
18.1k
    }
30777
0
    return pos;
30778
18.1k
}
30779
30780
/* convert global variable accesses to local variables or closure
30781
   variables when necessary */
30782
static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
30783
31.6k
{
30784
31.6k
    int pos, pos_next, bc_len, op, len, i, idx, line_num;
30785
31.6k
    uint8_t *bc_buf;
30786
31.6k
    JSAtom var_name;
30787
31.6k
    DynBuf bc_out;
30788
31.6k
    CodeContext cc;
30789
31.6k
    int scope;
30790
30791
31.6k
    cc.bc_buf = bc_buf = s->byte_code.buf;
30792
31.6k
    cc.bc_len = bc_len = s->byte_code.size;
30793
31.6k
    js_dbuf_init(ctx, &bc_out);
30794
30795
    /* first pass for runtime checks (must be done before the
30796
       variables are created) */
30797
40.8k
    for(i = 0; i < s->global_var_count; i++) {
30798
9.20k
        JSGlobalVar *hf = &s->global_vars[i];
30799
9.20k
        int flags;
30800
        
30801
        /* check if global variable (XXX: simplify) */
30802
14.0k
        for(idx = 0; idx < s->closure_var_count; idx++) {
30803
5.49k
            JSClosureVar *cv = &s->closure_var[idx];
30804
5.49k
            if (cv->var_name == hf->var_name) {
30805
607
                if (s->eval_type == JS_EVAL_TYPE_DIRECT &&
30806
607
                    cv->is_lexical) {
30807
                    /* Check if a lexical variable is
30808
                       redefined as 'var'. XXX: Could abort
30809
                       compilation here, but for consistency
30810
                       with the other checks, we delay the
30811
                       error generation. */
30812
0
                    dbuf_putc(&bc_out, OP_throw_error);
30813
0
                    dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
30814
0
                    dbuf_putc(&bc_out, JS_THROW_VAR_REDECL);
30815
0
                }
30816
607
                goto next;
30817
607
            }
30818
4.88k
            if (cv->var_name == JS_ATOM__var_ ||
30819
4.88k
                cv->var_name == JS_ATOM__arg_var_)
30820
0
                goto next;
30821
4.88k
        }
30822
        
30823
8.60k
        dbuf_putc(&bc_out, OP_check_define_var);
30824
8.60k
        dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
30825
8.60k
        flags = 0;
30826
8.60k
        if (hf->is_lexical)
30827
5
            flags |= DEFINE_GLOBAL_LEX_VAR;
30828
8.60k
        if (hf->cpool_idx >= 0)
30829
971
            flags |= DEFINE_GLOBAL_FUNC_VAR;
30830
8.60k
        dbuf_putc(&bc_out, flags);
30831
9.20k
    next: ;
30832
9.20k
    }
30833
30834
31.6k
    line_num = 0; /* avoid warning */
30835
2.55M
    for (pos = 0; pos < bc_len; pos = pos_next) {
30836
2.52M
        op = bc_buf[pos];
30837
2.52M
        len = opcode_info[op].size;
30838
2.52M
        pos_next = pos + len;
30839
2.52M
        switch(op) {
30840
133k
        case OP_line_num:
30841
133k
            line_num = get_u32(bc_buf + pos + 1);
30842
133k
            s->line_number_size++;
30843
133k
            goto no_change;
30844
30845
43
        case OP_eval: /* convert scope index to adjusted variable index */
30846
43
            {
30847
43
                int call_argc = get_u16(bc_buf + pos + 1);
30848
43
                scope = get_u16(bc_buf + pos + 1 + 2);
30849
43
                mark_eval_captured_variables(ctx, s, scope);
30850
43
                dbuf_putc(&bc_out, op);
30851
43
                dbuf_put_u16(&bc_out, call_argc);
30852
43
                dbuf_put_u16(&bc_out, s->scopes[scope].first + 1);
30853
43
            }
30854
43
            break;
30855
0
        case OP_apply_eval: /* convert scope index to adjusted variable index */
30856
0
            scope = get_u16(bc_buf + pos + 1);
30857
0
            mark_eval_captured_variables(ctx, s, scope);
30858
0
            dbuf_putc(&bc_out, op);
30859
0
            dbuf_put_u16(&bc_out, s->scopes[scope].first + 1);
30860
0
            break;
30861
100
        case OP_scope_get_var_undef:
30862
335k
        case OP_scope_get_var:
30863
339k
        case OP_scope_put_var:
30864
340k
        case OP_scope_delete_var:
30865
342k
        case OP_scope_get_ref:
30866
380k
        case OP_scope_put_var_init:
30867
380k
            var_name = get_u32(bc_buf + pos + 1);
30868
380k
            scope = get_u16(bc_buf + pos + 5);
30869
380k
            pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
30870
380k
                                         NULL, NULL, pos_next);
30871
380k
            JS_FreeAtom(ctx, var_name);
30872
380k
            break;
30873
266k
        case OP_scope_make_ref:
30874
266k
            {
30875
266k
                int label;
30876
266k
                LabelSlot *ls;
30877
266k
                var_name = get_u32(bc_buf + pos + 1);
30878
266k
                label = get_u32(bc_buf + pos + 5);
30879
266k
                scope = get_u16(bc_buf + pos + 9);
30880
266k
                ls = &s->label_slots[label];
30881
266k
                ls->ref_count--;  /* always remove label reference */
30882
266k
                pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
30883
266k
                                             bc_buf, ls, pos_next);
30884
266k
                JS_FreeAtom(ctx, var_name);
30885
266k
            }
30886
266k
            break;
30887
3
        case OP_scope_get_private_field:
30888
3
        case OP_scope_get_private_field2:
30889
5
        case OP_scope_put_private_field:
30890
5
            {
30891
5
                int ret;
30892
5
                var_name = get_u32(bc_buf + pos + 1);
30893
5
                scope = get_u16(bc_buf + pos + 5);
30894
5
                ret = resolve_scope_private_field(ctx, s, var_name, scope, op, &bc_out);
30895
5
                if (ret < 0)
30896
2
                    goto fail;
30897
3
                JS_FreeAtom(ctx, var_name);
30898
3
            }
30899
0
            break;
30900
0
        case OP_gosub:
30901
0
            s->jump_size++;
30902
0
            if (OPTIMIZE) {
30903
                /* remove calls to empty finalizers  */
30904
0
                int label;
30905
0
                LabelSlot *ls;
30906
30907
0
                label = get_u32(bc_buf + pos + 1);
30908
0
                assert(label >= 0 && label < s->label_count);
30909
0
                ls = &s->label_slots[label];
30910
0
                if (code_match(&cc, ls->pos, OP_ret, -1)) {
30911
0
                    ls->ref_count--;
30912
0
                    break;
30913
0
                }
30914
0
            }
30915
0
            goto no_change;
30916
102k
        case OP_drop:
30917
102k
            if (0) {
30918
                /* remove drops before return_undef */
30919
                /* do not perform this optimization in pass2 because
30920
                   it breaks patterns recognised in resolve_labels */
30921
0
                int pos1 = pos_next;
30922
0
                int line1 = line_num;
30923
0
                while (code_match(&cc, pos1, OP_drop, -1)) {
30924
0
                    if (cc.line_num >= 0) line1 = cc.line_num;
30925
0
                    pos1 = cc.pos;
30926
0
                }
30927
0
                if (code_match(&cc, pos1, OP_return_undef, -1)) {
30928
0
                    pos_next = pos1;
30929
0
                    if (line1 != -1 && line1 != line_num) {
30930
0
                        line_num = line1;
30931
0
                        s->line_number_size++;
30932
0
                        dbuf_putc(&bc_out, OP_line_num);
30933
0
                        dbuf_put_u32(&bc_out, line_num);
30934
0
                    }
30935
0
                    break;
30936
0
                }
30937
0
            }
30938
102k
            goto no_change;
30939
210k
        case OP_insert3:
30940
210k
            if (OPTIMIZE) {
30941
                /* Transformation: insert3 put_array_el|put_ref_value drop -> put_array_el|put_ref_value */
30942
210k
                if (code_match(&cc, pos_next, M2(OP_put_array_el, OP_put_ref_value), OP_drop, -1)) {
30943
179k
                    dbuf_putc(&bc_out, cc.op);
30944
179k
                    pos_next = cc.pos;
30945
179k
                    if (cc.line_num != -1 && cc.line_num != line_num) {
30946
0
                        line_num = cc.line_num;
30947
0
                        s->line_number_size++;
30948
0
                        dbuf_putc(&bc_out, OP_line_num);
30949
0
                        dbuf_put_u32(&bc_out, line_num);
30950
0
                    }
30951
179k
                    break;
30952
179k
                }
30953
210k
            }
30954
30.8k
            goto no_change;
30955
30956
72.6k
        case OP_goto:
30957
72.6k
            s->jump_size++;
30958
            /* fall thru */
30959
72.6k
        case OP_tail_call:
30960
72.6k
        case OP_tail_call_method:
30961
82.1k
        case OP_return:
30962
103k
        case OP_return_undef:
30963
105k
        case OP_throw:
30964
105k
        case OP_throw_error:
30965
105k
        case OP_ret:
30966
105k
            if (OPTIMIZE) {
30967
                /* remove dead code */
30968
105k
                int line = -1;
30969
105k
                dbuf_put(&bc_out, bc_buf + pos, len);
30970
105k
                pos = skip_dead_code(s, bc_buf, bc_len, pos + len, &line);
30971
105k
                pos_next = pos;
30972
105k
                if (pos < bc_len && line >= 0 && line_num != line) {
30973
1.98k
                    line_num = line;
30974
1.98k
                    s->line_number_size++;
30975
1.98k
                    dbuf_putc(&bc_out, OP_line_num);
30976
1.98k
                    dbuf_put_u32(&bc_out, line_num);
30977
1.98k
                }
30978
105k
                break;
30979
105k
            }
30980
0
            goto no_change;
30981
30982
353k
        case OP_label:
30983
353k
            {
30984
353k
                int label;
30985
353k
                LabelSlot *ls;
30986
30987
353k
                label = get_u32(bc_buf + pos + 1);
30988
353k
                assert(label >= 0 && label < s->label_count);
30989
353k
                ls = &s->label_slots[label];
30990
353k
                ls->pos2 = bc_out.size + opcode_info[op].size;
30991
353k
            }
30992
0
            goto no_change;
30993
30994
62.3k
        case OP_enter_scope:
30995
62.3k
            {
30996
62.3k
                int scope_idx, scope = get_u16(bc_buf + pos + 1);
30997
30998
62.3k
                if (scope == s->body_scope) {
30999
22.8k
                    instantiate_hoisted_definitions(ctx, s, &bc_out);
31000
22.8k
                }
31001
31002
110k
                for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
31003
67.9k
                    JSVarDef *vd = &s->vars[scope_idx];
31004
67.9k
                    if (vd->scope_level == scope) {
31005
48.0k
                        if (scope_idx != s->arguments_arg_idx) {
31006
48.0k
                            if (vd->var_kind == JS_VAR_FUNCTION_DECL ||
31007
48.0k
                                vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) {
31008
                                /* Initialize lexical variable upon entering scope */
31009
48
                                dbuf_putc(&bc_out, OP_fclosure);
31010
48
                                dbuf_put_u32(&bc_out, vd->func_pool_idx);
31011
48
                                dbuf_putc(&bc_out, OP_put_loc);
31012
48
                                dbuf_put_u16(&bc_out, scope_idx);
31013
47.9k
                            } else {
31014
                                /* XXX: should check if variable can be used
31015
                                   before initialization */
31016
47.9k
                                dbuf_putc(&bc_out, OP_set_loc_uninitialized);
31017
47.9k
                                dbuf_put_u16(&bc_out, scope_idx);
31018
47.9k
                            }
31019
48.0k
                        }
31020
48.0k
                        scope_idx = vd->scope_next;
31021
48.0k
                    } else {
31022
19.9k
                        break;
31023
19.9k
                    }
31024
67.9k
                }
31025
62.3k
            }
31026
62.3k
            break;
31027
31028
51.1k
        case OP_leave_scope:
31029
51.1k
            {
31030
51.1k
                int scope_idx, scope = get_u16(bc_buf + pos + 1);
31031
31032
100k
                for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
31033
72.2k
                    JSVarDef *vd = &s->vars[scope_idx];
31034
72.2k
                    if (vd->scope_level == scope) {
31035
49.8k
                        if (vd->is_captured) {
31036
20.1k
                            dbuf_putc(&bc_out, OP_close_loc);
31037
20.1k
                            dbuf_put_u16(&bc_out, scope_idx);
31038
20.1k
                        }
31039
49.8k
                        scope_idx = vd->scope_next;
31040
49.8k
                    } else {
31041
22.3k
                        break;
31042
22.3k
                    }
31043
72.2k
                }
31044
51.1k
            }
31045
51.1k
            break;
31046
31047
9.01k
        case OP_set_name:
31048
9.01k
            {
31049
                /* remove dummy set_name opcodes */
31050
9.01k
                JSAtom name = get_u32(bc_buf + pos + 1);
31051
9.01k
                if (name == JS_ATOM_NULL)
31052
3.10k
                    break;
31053
9.01k
            }
31054
5.91k
            goto no_change;
31055
31056
34.1k
        case OP_if_false:
31057
54.9k
        case OP_if_true:
31058
54.9k
        case OP_catch:
31059
54.9k
            s->jump_size++;
31060
54.9k
            goto no_change;
31061
31062
97.5k
        case OP_dup:
31063
97.5k
            if (OPTIMIZE) {
31064
                /* Transformation: dup if_false(l1) drop, l1: if_false(l2) -> if_false(l2) */
31065
                /* Transformation: dup if_true(l1) drop, l1: if_true(l2) -> if_true(l2) */
31066
97.5k
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), OP_drop, -1)) {
31067
18.1k
                    int lab0, lab1, op1, pos1, line1, pos2;
31068
18.1k
                    lab0 = lab1 = cc.label;
31069
18.1k
                    assert(lab1 >= 0 && lab1 < s->label_count);
31070
18.1k
                    op1 = cc.op;
31071
18.1k
                    pos1 = cc.pos;
31072
18.1k
                    line1 = cc.line_num;
31073
18.1k
                    while (code_match(&cc, (pos2 = get_label_pos(s, lab1)), OP_dup, op1, OP_drop, -1)) {
31074
0
                        lab1 = cc.label;
31075
0
                    }
31076
18.1k
                    if (code_match(&cc, pos2, op1, -1)) {
31077
0
                        s->jump_size++;
31078
0
                        update_label(s, lab0, -1);
31079
0
                        update_label(s, cc.label, +1);
31080
0
                        dbuf_putc(&bc_out, op1);
31081
0
                        dbuf_put_u32(&bc_out, cc.label);
31082
0
                        pos_next = pos1;
31083
0
                        if (line1 != -1 && line1 != line_num) {
31084
0
                            line_num = line1;
31085
0
                            s->line_number_size++;
31086
0
                            dbuf_putc(&bc_out, OP_line_num);
31087
0
                            dbuf_put_u32(&bc_out, line_num);
31088
0
                        }
31089
0
                        break;
31090
0
                    }
31091
18.1k
                }
31092
97.5k
            }
31093
97.5k
            goto no_change;
31094
31095
97.5k
        case OP_nop:
31096
            /* remove erased code */
31097
83.7k
            break;
31098
1.19k
        case OP_set_class_name:
31099
            /* only used during parsing */
31100
1.19k
            break;
31101
            
31102
609k
        default:
31103
1.38M
        no_change:
31104
1.38M
            dbuf_put(&bc_out, bc_buf + pos, len);
31105
1.38M
            break;
31106
2.52M
        }
31107
2.52M
    }
31108
31109
    /* set the new byte code */
31110
31.6k
    dbuf_free(&s->byte_code);
31111
31.6k
    s->byte_code = bc_out;
31112
31.6k
    if (dbuf_error(&s->byte_code)) {
31113
0
        JS_ThrowOutOfMemory(ctx);
31114
0
        return -1;
31115
0
    }
31116
31.6k
    return 0;
31117
2
 fail:
31118
    /* continue the copy to keep the atom refcounts consistent */
31119
    /* XXX: find a better solution ? */
31120
2.90k
    for (; pos < bc_len; pos = pos_next) {
31121
2.90k
        op = bc_buf[pos];
31122
2.90k
        len = opcode_info[op].size;
31123
2.90k
        pos_next = pos + len;
31124
2.90k
        dbuf_put(&bc_out, bc_buf + pos, len);
31125
2.90k
    }
31126
2
    dbuf_free(&s->byte_code);
31127
2
    s->byte_code = bc_out;
31128
2
    return -1;
31129
31.6k
}
31130
31131
/* the pc2line table gives a line number for each PC value */
31132
static void add_pc2line_info(JSFunctionDef *s, uint32_t pc, int line_num)
31133
4.89M
{
31134
4.89M
    if (s->line_number_slots != NULL
31135
4.89M
    &&  s->line_number_count < s->line_number_size
31136
4.89M
    &&  pc >= s->line_number_last_pc
31137
4.89M
    &&  line_num != s->line_number_last) {
31138
106k
        s->line_number_slots[s->line_number_count].pc = pc;
31139
106k
        s->line_number_slots[s->line_number_count].line_num = line_num;
31140
106k
        s->line_number_count++;
31141
106k
        s->line_number_last_pc = pc;
31142
106k
        s->line_number_last = line_num;
31143
106k
    }
31144
4.89M
}
31145
31146
static void compute_pc2line_info(JSFunctionDef *s)
31147
31.6k
{
31148
31.6k
    if (!(s->js_mode & JS_MODE_STRIP) && s->line_number_slots) {
31149
15.1k
        int last_line_num = s->line_num;
31150
15.1k
        uint32_t last_pc = 0;
31151
15.1k
        int i;
31152
31153
15.1k
        js_dbuf_init(s->ctx, &s->pc2line);
31154
121k
        for (i = 0; i < s->line_number_count; i++) {
31155
106k
            uint32_t pc = s->line_number_slots[i].pc;
31156
106k
            int line_num = s->line_number_slots[i].line_num;
31157
106k
            int diff_pc, diff_line;
31158
31159
106k
            if (line_num < 0)
31160
0
                continue;
31161
31162
106k
            diff_pc = pc - last_pc;
31163
106k
            diff_line = line_num - last_line_num;
31164
106k
            if (diff_line == 0 || diff_pc < 0)
31165
0
                continue;
31166
31167
106k
            if (diff_line >= PC2LINE_BASE &&
31168
106k
                diff_line < PC2LINE_BASE + PC2LINE_RANGE &&
31169
106k
                diff_pc <= PC2LINE_DIFF_PC_MAX) {
31170
73.7k
                dbuf_putc(&s->pc2line, (diff_line - PC2LINE_BASE) +
31171
73.7k
                          diff_pc * PC2LINE_RANGE + PC2LINE_OP_FIRST);
31172
73.7k
            } else {
31173
                /* longer encoding */
31174
32.8k
                dbuf_putc(&s->pc2line, 0);
31175
32.8k
                dbuf_put_leb128(&s->pc2line, diff_pc);
31176
32.8k
                dbuf_put_sleb128(&s->pc2line, diff_line);
31177
32.8k
            }
31178
106k
            last_pc = pc;
31179
106k
            last_line_num = line_num;
31180
106k
        }
31181
15.1k
    }
31182
31.6k
}
31183
31184
static RelocEntry *add_reloc(JSContext *ctx, LabelSlot *ls, uint32_t addr, int size)
31185
1.65M
{
31186
1.65M
    RelocEntry *re;
31187
1.65M
    re = js_malloc(ctx, sizeof(*re));
31188
1.65M
    if (!re)
31189
0
        return NULL;
31190
1.65M
    re->addr = addr;
31191
1.65M
    re->size = size;
31192
1.65M
    re->next = ls->first_reloc;
31193
1.65M
    ls->first_reloc = re;
31194
1.65M
    return re;
31195
1.65M
}
31196
31197
static BOOL code_has_label(CodeContext *s, int pos, int label)
31198
115k
{
31199
187k
    while (pos < s->bc_len) {
31200
187k
        int op = s->bc_buf[pos];
31201
187k
        if (op == OP_line_num) {
31202
12.6k
            pos += 5;
31203
12.6k
            continue;
31204
12.6k
        }
31205
174k
        if (op == OP_label) {
31206
66.7k
            int lab = get_u32(s->bc_buf + pos + 1);
31207
66.7k
            if (lab == label)
31208
7.35k
                return TRUE;
31209
59.4k
            pos += 5;
31210
59.4k
            continue;
31211
66.7k
        }
31212
108k
        if (op == OP_goto) {
31213
16.6k
            int lab = get_u32(s->bc_buf + pos + 1);
31214
16.6k
            if (lab == label)
31215
1.02k
                return TRUE;
31216
16.6k
        }
31217
107k
        break;
31218
108k
    }
31219
107k
    return FALSE;
31220
115k
}
31221
31222
/* return the target label, following the OP_goto jumps
31223
   the first opcode at destination is stored in *pop
31224
 */
31225
static int find_jump_target(JSFunctionDef *s, int label, int *pop, int *pline)
31226
1.68M
{
31227
1.68M
    int i, pos, op;
31228
31229
1.68M
    update_label(s, label, -1);
31230
1.70M
    for (i = 0; i < 10; i++) {
31231
1.70M
        assert(label >= 0 && label < s->label_count);
31232
1.70M
        pos = s->label_slots[label].pos2;
31233
1.92M
        for (;;) {
31234
1.92M
            switch(op = s->byte_code.buf[pos]) {
31235
14.1k
            case OP_line_num:
31236
14.1k
                if (pline)
31237
7.33k
                    *pline = get_u32(s->byte_code.buf + pos + 1);
31238
                /* fall thru */
31239
221k
            case OP_label:
31240
221k
                pos += opcode_info[op].size;
31241
221k
                continue;
31242
14.7k
            case OP_goto:
31243
14.7k
                label = get_u32(s->byte_code.buf + pos + 1);
31244
14.7k
                break;
31245
19.6k
            case OP_drop:
31246
                /* ignore drop opcodes if followed by OP_return_undef */
31247
20.6k
                while (s->byte_code.buf[++pos] == OP_drop)
31248
1.00k
                    continue;
31249
19.6k
                if (s->byte_code.buf[pos] == OP_return_undef)
31250
9.72k
                    op = OP_return_undef;
31251
                /* fall thru */
31252
1.68M
            default:
31253
1.68M
                goto done;
31254
1.92M
            }
31255
14.7k
            break;
31256
1.92M
        }
31257
1.70M
    }
31258
    /* cycle detected, could issue a warning */
31259
1.68M
 done:
31260
1.68M
    *pop = op;
31261
1.68M
    update_label(s, label, +1);
31262
1.68M
    return label;
31263
1.68M
}
31264
31265
static void push_short_int(DynBuf *bc_out, int val)
31266
15.4k
{
31267
15.4k
#if SHORT_OPCODES
31268
15.4k
    if (val >= -1 && val <= 7) {
31269
9.71k
        dbuf_putc(bc_out, OP_push_0 + val);
31270
9.71k
        return;
31271
9.71k
    }
31272
5.73k
    if (val == (int8_t)val) {
31273
1.90k
        dbuf_putc(bc_out, OP_push_i8);
31274
1.90k
        dbuf_putc(bc_out, val);
31275
1.90k
        return;
31276
1.90k
    }
31277
3.83k
    if (val == (int16_t)val) {
31278
1.92k
        dbuf_putc(bc_out, OP_push_i16);
31279
1.92k
        dbuf_put_u16(bc_out, val);
31280
1.92k
        return;
31281
1.92k
    }
31282
1.91k
#endif
31283
1.91k
    dbuf_putc(bc_out, OP_push_i32);
31284
1.91k
    dbuf_put_u32(bc_out, val);
31285
1.91k
}
31286
31287
static void put_short_code(DynBuf *bc_out, int op, int idx)
31288
1.27M
{
31289
1.27M
#if SHORT_OPCODES
31290
1.27M
    if (idx < 4) {
31291
550k
        switch (op) {
31292
418k
        case OP_get_loc:
31293
418k
            dbuf_putc(bc_out, OP_get_loc0 + idx);
31294
418k
            return;
31295
86.4k
        case OP_put_loc:
31296
86.4k
            dbuf_putc(bc_out, OP_put_loc0 + idx);
31297
86.4k
            return;
31298
1.56k
        case OP_set_loc:
31299
1.56k
            dbuf_putc(bc_out, OP_set_loc0 + idx);
31300
1.56k
            return;
31301
9.14k
        case OP_get_arg:
31302
9.14k
            dbuf_putc(bc_out, OP_get_arg0 + idx);
31303
9.14k
            return;
31304
274
        case OP_put_arg:
31305
274
            dbuf_putc(bc_out, OP_put_arg0 + idx);
31306
274
            return;
31307
3.44k
        case OP_set_arg:
31308
3.44k
            dbuf_putc(bc_out, OP_set_arg0 + idx);
31309
3.44k
            return;
31310
8.31k
        case OP_get_var_ref:
31311
8.31k
            dbuf_putc(bc_out, OP_get_var_ref0 + idx);
31312
8.31k
            return;
31313
716
        case OP_put_var_ref:
31314
716
            dbuf_putc(bc_out, OP_put_var_ref0 + idx);
31315
716
            return;
31316
3.18k
        case OP_set_var_ref:
31317
3.18k
            dbuf_putc(bc_out, OP_set_var_ref0 + idx);
31318
3.18k
            return;
31319
6.90k
        case OP_call:
31320
6.90k
            dbuf_putc(bc_out, OP_call0 + idx);
31321
6.90k
            return;
31322
550k
        }
31323
550k
    }
31324
738k
    if (idx < 256) {
31325
726k
        switch (op) {
31326
682k
        case OP_get_loc:
31327
682k
            dbuf_putc(bc_out, OP_get_loc8);
31328
682k
            dbuf_putc(bc_out, idx);
31329
682k
            return;
31330
23.1k
        case OP_put_loc:
31331
23.1k
            dbuf_putc(bc_out, OP_put_loc8);
31332
23.1k
            dbuf_putc(bc_out, idx);
31333
23.1k
            return;
31334
5.95k
        case OP_set_loc:
31335
5.95k
            dbuf_putc(bc_out, OP_set_loc8);
31336
5.95k
            dbuf_putc(bc_out, idx);
31337
5.95k
            return;
31338
726k
        }
31339
726k
    }
31340
26.7k
#endif
31341
26.7k
    dbuf_putc(bc_out, op);
31342
26.7k
    dbuf_put_u16(bc_out, idx);
31343
26.7k
}
31344
31345
/* peephole optimizations and resolve goto/labels */
31346
static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
31347
31.6k
{
31348
31.6k
    int pos, pos_next, bc_len, op, op1, len, i, line_num;
31349
31.6k
    const uint8_t *bc_buf;
31350
31.6k
    DynBuf bc_out;
31351
31.6k
    LabelSlot *label_slots, *ls;
31352
31.6k
    RelocEntry *re, *re_next;
31353
31.6k
    CodeContext cc;
31354
31.6k
    int label;
31355
31.6k
#if SHORT_OPCODES
31356
31.6k
    JumpSlot *jp;
31357
31.6k
#endif
31358
31359
31.6k
    label_slots = s->label_slots;
31360
31361
31.6k
    line_num = s->line_num;
31362
31363
31.6k
    cc.bc_buf = bc_buf = s->byte_code.buf;
31364
31.6k
    cc.bc_len = bc_len = s->byte_code.size;
31365
31.6k
    js_dbuf_init(ctx, &bc_out);
31366
31367
31.6k
#if SHORT_OPCODES
31368
31.6k
    if (s->jump_size) {
31369
23.4k
        s->jump_slots = js_mallocz(s->ctx, sizeof(*s->jump_slots) * s->jump_size);
31370
23.4k
        if (s->jump_slots == NULL)
31371
0
            return -1;
31372
23.4k
    }
31373
31.6k
#endif
31374
    /* XXX: Should skip this phase if not generating SHORT_OPCODES */
31375
31.6k
    if (s->line_number_size && !(s->js_mode & JS_MODE_STRIP)) {
31376
15.1k
        s->line_number_slots = js_mallocz(s->ctx, sizeof(*s->line_number_slots) * s->line_number_size);
31377
15.1k
        if (s->line_number_slots == NULL)
31378
0
            return -1;
31379
15.1k
        s->line_number_last = s->line_num;
31380
15.1k
        s->line_number_last_pc = 0;
31381
15.1k
    }
31382
31383
    /* initialize the 'home_object' variable if needed */
31384
31.6k
    if (s->home_object_var_idx >= 0) {
31385
8.78k
        dbuf_putc(&bc_out, OP_special_object);
31386
8.78k
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_HOME_OBJECT);
31387
8.78k
        put_short_code(&bc_out, OP_put_loc, s->home_object_var_idx);
31388
8.78k
    }
31389
    /* initialize the 'this.active_func' variable if needed */
31390
31.6k
    if (s->this_active_func_var_idx >= 0) {
31391
0
        dbuf_putc(&bc_out, OP_special_object);
31392
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
31393
0
        put_short_code(&bc_out, OP_put_loc, s->this_active_func_var_idx);
31394
0
    }
31395
    /* initialize the 'new.target' variable if needed */
31396
31.6k
    if (s->new_target_var_idx >= 0) {
31397
15
        dbuf_putc(&bc_out, OP_special_object);
31398
15
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_NEW_TARGET);
31399
15
        put_short_code(&bc_out, OP_put_loc, s->new_target_var_idx);
31400
15
    }
31401
    /* initialize the 'this' variable if needed. In a derived class
31402
       constructor, this is initially uninitialized. */
31403
31.6k
    if (s->this_var_idx >= 0) {
31404
18.5k
        if (s->is_derived_class_constructor) {
31405
0
            dbuf_putc(&bc_out, OP_set_loc_uninitialized);
31406
0
            dbuf_put_u16(&bc_out, s->this_var_idx);
31407
18.5k
        } else {
31408
18.5k
            dbuf_putc(&bc_out, OP_push_this);
31409
18.5k
            put_short_code(&bc_out, OP_put_loc, s->this_var_idx);
31410
18.5k
        }
31411
18.5k
    }
31412
    /* initialize the 'arguments' variable if needed */
31413
31.6k
    if (s->arguments_var_idx >= 0) {
31414
6
        if ((s->js_mode & JS_MODE_STRICT) || !s->has_simple_parameter_list) {
31415
0
            dbuf_putc(&bc_out, OP_special_object);
31416
0
            dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_ARGUMENTS);
31417
6
        } else {
31418
6
            dbuf_putc(&bc_out, OP_special_object);
31419
6
            dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS);
31420
6
        }
31421
6
        if (s->arguments_arg_idx >= 0)
31422
0
            put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);
31423
6
        put_short_code(&bc_out, OP_put_loc, s->arguments_var_idx);
31424
6
    }
31425
    /* initialize a reference to the current function if needed */
31426
31.6k
    if (s->func_var_idx >= 0) {
31427
138
        dbuf_putc(&bc_out, OP_special_object);
31428
138
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
31429
138
        put_short_code(&bc_out, OP_put_loc, s->func_var_idx);
31430
138
    }
31431
    /* initialize the variable environment object if needed */
31432
31.6k
    if (s->var_object_idx >= 0) {
31433
9
        dbuf_putc(&bc_out, OP_special_object);
31434
9
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
31435
9
        put_short_code(&bc_out, OP_put_loc, s->var_object_idx);
31436
9
    }
31437
31.6k
    if (s->arg_var_object_idx >= 0) {
31438
0
        dbuf_putc(&bc_out, OP_special_object);
31439
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
31440
0
        put_short_code(&bc_out, OP_put_loc, s->arg_var_object_idx);
31441
0
    }
31442
31443
5.81M
    for (pos = 0; pos < bc_len; pos = pos_next) {
31444
5.78M
        int val;
31445
5.78M
        op = bc_buf[pos];
31446
5.78M
        len = opcode_info[op].size;
31447
5.78M
        pos_next = pos + len;
31448
5.78M
        switch(op) {
31449
121k
        case OP_line_num:
31450
            /* line number info (for debug). We put it in a separate
31451
               compressed table to reduce memory usage and get better
31452
               performance */
31453
121k
            line_num = get_u32(bc_buf + pos + 1);
31454
121k
            break;
31455
31456
733k
        case OP_label:
31457
733k
            {
31458
733k
                label = get_u32(bc_buf + pos + 1);
31459
733k
                assert(label >= 0 && label < s->label_count);
31460
733k
                ls = &label_slots[label];
31461
733k
                assert(ls->addr == -1);
31462
733k
                ls->addr = bc_out.size;
31463
                /* resolve the relocation entries */
31464
2.38M
                for(re = ls->first_reloc; re != NULL; re = re_next) {
31465
1.65M
                    int diff = ls->addr - re->addr;
31466
1.65M
                    re_next = re->next;
31467
1.65M
                    switch (re->size) {
31468
1.59M
                    case 4:
31469
1.59M
                        put_u32(bc_out.buf + re->addr, diff);
31470
1.59M
                        break;
31471
5.15k
                    case 2:
31472
5.15k
                        assert(diff == (int16_t)diff);
31473
5.15k
                        put_u16(bc_out.buf + re->addr, diff);
31474
5.15k
                        break;
31475
58.1k
                    case 1:
31476
58.1k
                        assert(diff == (int8_t)diff);
31477
58.1k
                        put_u8(bc_out.buf + re->addr, diff);
31478
58.1k
                        break;
31479
1.65M
                    }
31480
1.65M
                    js_free(ctx, re);
31481
1.65M
                }
31482
733k
                ls->first_reloc = NULL;
31483
733k
            }
31484
0
            break;
31485
31486
7.19k
        case OP_call:
31487
18.9k
        case OP_call_method:
31488
18.9k
            {
31489
                /* detect and transform tail calls */
31490
18.9k
                int argc;
31491
18.9k
                argc = get_u16(bc_buf + pos + 1);
31492
18.9k
                if (code_match(&cc, pos_next, OP_return, -1)) {
31493
648
                    if (cc.line_num >= 0) line_num = cc.line_num;
31494
648
                    add_pc2line_info(s, bc_out.size, line_num);
31495
648
                    put_short_code(&bc_out, op + 1, argc);
31496
648
                    pos_next = skip_dead_code(s, bc_buf, bc_len, cc.pos, &line_num);
31497
648
                    break;
31498
648
                }
31499
18.3k
                add_pc2line_info(s, bc_out.size, line_num);
31500
18.3k
                put_short_code(&bc_out, op, argc);
31501
18.3k
                break;
31502
18.9k
            }
31503
0
            goto no_change;
31504
31505
8.77k
        case OP_return:
31506
30.1k
        case OP_return_undef:
31507
31.0k
        case OP_return_async:
31508
31.1k
        case OP_throw:
31509
31.3k
        case OP_throw_error:
31510
31.3k
            pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
31511
31.3k
            goto no_change;
31512
31513
57.2k
        case OP_goto:
31514
57.2k
            label = get_u32(bc_buf + pos + 1);
31515
66.0k
        has_goto:
31516
66.0k
            if (OPTIMIZE) {
31517
66.0k
                int line1 = -1;
31518
                /* Use custom matcher because multiple labels can follow */
31519
66.0k
                label = find_jump_target(s, label, &op1, &line1);
31520
66.0k
                if (code_has_label(&cc, pos_next, label)) {
31521
                    /* jump to next instruction: remove jump */
31522
7.62k
                    update_label(s, label, -1);
31523
7.62k
                    break;
31524
7.62k
                }
31525
58.3k
                if (op1 == OP_return || op1 == OP_return_undef || op1 == OP_throw) {
31526
                    /* jump to return/throw: remove jump, append return/throw */
31527
                    /* updating the line number obfuscates assembly listing */
31528
                    //if (line1 >= 0) line_num = line1;
31529
1.44k
                    update_label(s, label, -1);
31530
1.44k
                    add_pc2line_info(s, bc_out.size, line_num);
31531
1.44k
                    dbuf_putc(&bc_out, op1);
31532
1.44k
                    pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
31533
1.44k
                    break;
31534
1.44k
                }
31535
                /* XXX: should duplicate single instructions followed by goto or return */
31536
                /* For example, can match one of these followed by return:
31537
                   push_i32 / push_const / push_atom_value / get_var /
31538
                   undefined / null / push_false / push_true / get_ref_value /
31539
                   get_loc / get_arg / get_var_ref
31540
                 */
31541
58.3k
            }
31542
56.9k
            goto has_label;
31543
31544
56.9k
        case OP_gosub:
31545
0
            label = get_u32(bc_buf + pos + 1);
31546
0
            if (0 && OPTIMIZE) {
31547
0
                label = find_jump_target(s, label, &op1, NULL);
31548
0
                if (op1 == OP_ret) {
31549
0
                    update_label(s, label, -1);
31550
                    /* empty finally clause: remove gosub */
31551
0
                    break;
31552
0
                }
31553
0
            }
31554
0
            goto has_label;
31555
31556
0
        case OP_catch:
31557
0
            label = get_u32(bc_buf + pos + 1);
31558
0
            goto has_label;
31559
31560
20.8k
        case OP_if_true:
31561
44.4k
        case OP_if_false:
31562
44.4k
            label = get_u32(bc_buf + pos + 1);
31563
44.4k
            if (OPTIMIZE) {
31564
44.4k
                label = find_jump_target(s, label, &op1, NULL);
31565
                /* transform if_false/if_true(l1) label(l1) -> drop label(l1) */
31566
44.4k
                if (code_has_label(&cc, pos_next, label)) {
31567
159
                    update_label(s, label, -1);
31568
159
                    dbuf_putc(&bc_out, OP_drop);
31569
159
                    break;
31570
159
                }
31571
                /* transform if_false(l1) goto(l2) label(l1) -> if_false(l2) label(l1) */
31572
44.3k
                if (code_match(&cc, pos_next, OP_goto, -1)) {
31573
5.00k
                    int pos1 = cc.pos;
31574
5.00k
                    int line1 = cc.line_num;
31575
5.00k
                    if (code_has_label(&cc, pos1, label)) {
31576
597
                        if (line1 >= 0) line_num = line1;
31577
597
                        pos_next = pos1;
31578
597
                        update_label(s, label, -1);
31579
597
                        label = cc.label;
31580
597
                        op ^= OP_if_true ^ OP_if_false;
31581
597
                    }
31582
5.00k
                }
31583
44.3k
            }
31584
101k
        has_label:
31585
101k
            add_pc2line_info(s, bc_out.size, line_num);
31586
101k
            if (op == OP_goto) {
31587
56.9k
                pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
31588
56.9k
            }
31589
101k
            assert(label >= 0 && label < s->label_count);
31590
101k
            ls = &label_slots[label];
31591
101k
#if SHORT_OPCODES
31592
101k
            jp = &s->jump_slots[s->jump_count++];
31593
101k
            jp->op = op;
31594
101k
            jp->size = 4;
31595
101k
            jp->pos = bc_out.size + 1;
31596
101k
            jp->label = label;
31597
31598
101k
            if (ls->addr == -1) {
31599
79.4k
                int diff = ls->pos2 - pos - 1;
31600
79.4k
                if (diff < 128 && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
31601
58.1k
                    jp->size = 1;
31602
58.1k
                    jp->op = OP_if_false8 + (op - OP_if_false);
31603
58.1k
                    dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
31604
58.1k
                    dbuf_putc(&bc_out, 0);
31605
58.1k
                    if (!add_reloc(ctx, ls, bc_out.size - 1, 1))
31606
0
                        goto fail;
31607
58.1k
                    break;
31608
58.1k
                }
31609
21.3k
                if (diff < 32768 && op == OP_goto) {
31610
5.15k
                    jp->size = 2;
31611
5.15k
                    jp->op = OP_goto16;
31612
5.15k
                    dbuf_putc(&bc_out, OP_goto16);
31613
5.15k
                    dbuf_put_u16(&bc_out, 0);
31614
5.15k
                    if (!add_reloc(ctx, ls, bc_out.size - 2, 2))
31615
0
                        goto fail;
31616
5.15k
                    break;
31617
5.15k
                }
31618
21.7k
            } else {
31619
21.7k
                int diff = ls->addr - bc_out.size - 1;
31620
21.7k
                if (diff == (int8_t)diff && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
31621
18.1k
                    jp->size = 1;
31622
18.1k
                    jp->op = OP_if_false8 + (op - OP_if_false);
31623
18.1k
                    dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
31624
18.1k
                    dbuf_putc(&bc_out, diff);
31625
18.1k
                    break;
31626
18.1k
                }
31627
3.64k
                if (diff == (int16_t)diff && op == OP_goto) {
31628
2.66k
                    jp->size = 2;
31629
2.66k
                    jp->op = OP_goto16;
31630
2.66k
                    dbuf_putc(&bc_out, OP_goto16);
31631
2.66k
                    dbuf_put_u16(&bc_out, diff);
31632
2.66k
                    break;
31633
2.66k
                }
31634
3.64k
            }
31635
17.2k
#endif
31636
17.2k
            dbuf_putc(&bc_out, op);
31637
17.2k
            dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
31638
17.2k
            if (ls->addr == -1) {
31639
                /* unresolved yet: create a new relocation entry */
31640
16.2k
                if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
31641
0
                    goto fail;
31642
16.2k
            }
31643
17.2k
            break;
31644
982k
        case OP_with_get_var:
31645
982k
        case OP_with_put_var:
31646
982k
        case OP_with_delete_var:
31647
1.57M
        case OP_with_make_ref:
31648
1.57M
        case OP_with_get_ref:
31649
1.57M
        case OP_with_get_ref_undef:
31650
1.57M
            {
31651
1.57M
                JSAtom atom;
31652
1.57M
                int is_with;
31653
31654
1.57M
                atom = get_u32(bc_buf + pos + 1);
31655
1.57M
                label = get_u32(bc_buf + pos + 5);
31656
1.57M
                is_with = bc_buf[pos + 9];
31657
1.57M
                if (OPTIMIZE) {
31658
1.57M
                    label = find_jump_target(s, label, &op1, NULL);
31659
1.57M
                }
31660
1.57M
                assert(label >= 0 && label < s->label_count);
31661
1.57M
                ls = &label_slots[label];
31662
1.57M
                add_pc2line_info(s, bc_out.size, line_num);
31663
1.57M
#if SHORT_OPCODES
31664
1.57M
                jp = &s->jump_slots[s->jump_count++];
31665
1.57M
                jp->op = op;
31666
1.57M
                jp->size = 4;
31667
1.57M
                jp->pos = bc_out.size + 5;
31668
1.57M
                jp->label = label;
31669
1.57M
#endif
31670
1.57M
                dbuf_putc(&bc_out, op);
31671
1.57M
                dbuf_put_u32(&bc_out, atom);
31672
1.57M
                dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
31673
1.57M
                if (ls->addr == -1) {
31674
                    /* unresolved yet: create a new relocation entry */
31675
1.57M
                    if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
31676
0
                        goto fail;
31677
1.57M
                }
31678
1.57M
                dbuf_putc(&bc_out, is_with);
31679
1.57M
            }
31680
0
            break;
31681
31682
92.5k
        case OP_drop:
31683
92.5k
            if (OPTIMIZE) {
31684
                /* remove useless drops before return */
31685
92.5k
                if (code_match(&cc, pos_next, OP_return_undef, -1)) {
31686
12.4k
                    if (cc.line_num >= 0) line_num = cc.line_num;
31687
12.4k
                    break;
31688
12.4k
                }
31689
92.5k
            }
31690
80.1k
            goto no_change;
31691
31692
80.1k
        case OP_null:
31693
1.30k
#if SHORT_OPCODES
31694
1.30k
            if (OPTIMIZE) {
31695
                /* transform null strict_eq into is_null */
31696
1.30k
                if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
31697
433
                    if (cc.line_num >= 0) line_num = cc.line_num;
31698
433
                    add_pc2line_info(s, bc_out.size, line_num);
31699
433
                    dbuf_putc(&bc_out, OP_is_null);
31700
433
                    pos_next = cc.pos;
31701
433
                    break;
31702
433
                }
31703
                /* transform null strict_neq if_false/if_true -> is_null if_true/if_false */
31704
874
                if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
31705
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
31706
0
                    add_pc2line_info(s, bc_out.size, line_num);
31707
0
                    dbuf_putc(&bc_out, OP_is_null);
31708
0
                    pos_next = cc.pos;
31709
0
                    label = cc.label;
31710
0
                    op = cc.op ^ OP_if_false ^ OP_if_true;
31711
0
                    goto has_label;
31712
0
                }
31713
874
            }
31714
874
#endif
31715
            /* fall thru */
31716
9.50k
        case OP_push_false:
31717
9.84k
        case OP_push_true:
31718
9.84k
            if (OPTIMIZE) {
31719
9.84k
                val = (op == OP_push_true);
31720
9.84k
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
31721
9.35k
                has_constant_test:
31722
9.35k
                    if (cc.line_num >= 0) line_num = cc.line_num;
31723
9.35k
                    if (val == cc.op - OP_if_false) {
31724
                        /* transform null if_false(l1) -> goto l1 */
31725
                        /* transform false if_false(l1) -> goto l1 */
31726
                        /* transform true if_true(l1) -> goto l1 */
31727
8.81k
                        pos_next = cc.pos;
31728
8.81k
                        op = OP_goto;
31729
8.81k
                        label = cc.label;
31730
8.81k
                        goto has_goto;
31731
8.81k
                    } else {
31732
                        /* transform null if_true(l1) -> nop */
31733
                        /* transform false if_true(l1) -> nop */
31734
                        /* transform true if_false(l1) -> nop */
31735
545
                        pos_next = cc.pos;
31736
545
                        update_label(s, cc.label, -1);
31737
545
                        break;
31738
545
                    }
31739
9.35k
                }
31740
9.84k
            }
31741
1.05k
            goto no_change;
31742
31743
21.4k
        case OP_push_i32:
31744
21.4k
            if (OPTIMIZE) {
31745
                /* transform i32(val) neg -> i32(-val) */
31746
21.4k
                val = get_i32(bc_buf + pos + 1);
31747
21.4k
                if ((val != INT32_MIN && val != 0)
31748
21.4k
                &&  code_match(&cc, pos_next, OP_neg, -1)) {
31749
387
                    if (cc.line_num >= 0) line_num = cc.line_num;
31750
387
                    if (code_match(&cc, cc.pos, OP_drop, -1)) {
31751
114
                        if (cc.line_num >= 0) line_num = cc.line_num;
31752
273
                    } else {
31753
273
                        add_pc2line_info(s, bc_out.size, line_num);
31754
273
                        push_short_int(&bc_out, -val);
31755
273
                    }
31756
387
                    pos_next = cc.pos;
31757
387
                    break;
31758
387
                }
31759
                /* remove push/drop pairs generated by the parser */
31760
21.0k
                if (code_match(&cc, pos_next, OP_drop, -1)) {
31761
5.39k
                    if (cc.line_num >= 0) line_num = cc.line_num;
31762
5.39k
                    pos_next = cc.pos;
31763
5.39k
                    break;
31764
5.39k
                }
31765
                /* Optimize constant tests: `if (0)`, `if (1)`, `if (!0)`... */
31766
15.6k
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
31767
503
                    val = (val != 0);
31768
503
                    goto has_constant_test;
31769
503
                }
31770
15.1k
                add_pc2line_info(s, bc_out.size, line_num);
31771
15.1k
                push_short_int(&bc_out, val);
31772
15.1k
                break;
31773
15.6k
            }
31774
0
            goto no_change;
31775
31776
0
#if SHORT_OPCODES
31777
37.9k
        case OP_push_const:
31778
56.8k
        case OP_fclosure:
31779
56.8k
            if (OPTIMIZE) {
31780
56.8k
                int idx = get_u32(bc_buf + pos + 1);
31781
56.8k
                if (idx < 256) {
31782
42.7k
                    add_pc2line_info(s, bc_out.size, line_num);
31783
42.7k
                    dbuf_putc(&bc_out, OP_push_const8 + op - OP_push_const);
31784
42.7k
                    dbuf_putc(&bc_out, idx);
31785
42.7k
                    break;
31786
42.7k
                }
31787
56.8k
            }
31788
14.1k
            goto no_change;
31789
31790
14.1k
        case OP_get_field:
31791
5.81k
            if (OPTIMIZE) {
31792
5.81k
                JSAtom atom = get_u32(bc_buf + pos + 1);
31793
5.81k
                if (atom == JS_ATOM_length) {
31794
0
                    JS_FreeAtom(ctx, atom);
31795
0
                    add_pc2line_info(s, bc_out.size, line_num);
31796
0
                    dbuf_putc(&bc_out, OP_get_length);
31797
0
                    break;
31798
0
                }
31799
5.81k
            }
31800
5.81k
            goto no_change;
31801
5.81k
#endif
31802
11.2k
        case OP_push_atom_value:
31803
11.2k
            if (OPTIMIZE) {
31804
11.2k
                JSAtom atom = get_u32(bc_buf + pos + 1);
31805
                /* remove push/drop pairs generated by the parser */
31806
11.2k
                if (code_match(&cc, pos_next, OP_drop, -1)) {
31807
1.46k
                    JS_FreeAtom(ctx, atom);
31808
1.46k
                    if (cc.line_num >= 0) line_num = cc.line_num;
31809
1.46k
                    pos_next = cc.pos;
31810
1.46k
                    break;
31811
1.46k
                }
31812
9.76k
#if SHORT_OPCODES
31813
9.76k
                if (atom == JS_ATOM_empty_string) {
31814
4.83k
                    JS_FreeAtom(ctx, atom);
31815
4.83k
                    add_pc2line_info(s, bc_out.size, line_num);
31816
4.83k
                    dbuf_putc(&bc_out, OP_push_empty_string);
31817
4.83k
                    break;
31818
4.83k
                }
31819
9.76k
#endif
31820
9.76k
            }
31821
4.93k
            goto no_change;
31822
31823
4.93k
        case OP_to_propkey:
31824
295
        case OP_to_propkey2:
31825
295
            if (OPTIMIZE) {
31826
                /* remove redundant to_propkey/to_propkey2 opcodes when storing simple data */
31827
295
                if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_put_array_el, -1)
31828
295
                ||  code_match(&cc, pos_next, M3(OP_push_i32, OP_push_const, OP_push_atom_value), OP_put_array_el, -1)
31829
295
                ||  code_match(&cc, pos_next, M4(OP_undefined, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) {
31830
0
                    break;
31831
0
                }
31832
295
            }
31833
295
            goto no_change;
31834
31835
52.7k
        case OP_undefined:
31836
52.7k
            if (OPTIMIZE) {
31837
                /* remove push/drop pairs generated by the parser */
31838
52.7k
                if (code_match(&cc, pos_next, OP_drop, -1)) {
31839
423
                    if (cc.line_num >= 0) line_num = cc.line_num;
31840
423
                    pos_next = cc.pos;
31841
423
                    break;
31842
423
                }
31843
                /* transform undefined return -> return_undefined */
31844
52.3k
                if (code_match(&cc, pos_next, OP_return, -1)) {
31845
92
                    if (cc.line_num >= 0) line_num = cc.line_num;
31846
92
                    add_pc2line_info(s, bc_out.size, line_num);
31847
92
                    dbuf_putc(&bc_out, OP_return_undef);
31848
92
                    pos_next = cc.pos;
31849
92
                    break;
31850
92
                }
31851
                /* transform undefined if_true(l1)/if_false(l1) -> nop/goto(l1) */
31852
52.2k
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
31853
68
                    val = 0;
31854
68
                    goto has_constant_test;
31855
68
                }
31856
52.1k
#if SHORT_OPCODES
31857
                /* transform undefined strict_eq -> is_undefined */
31858
52.1k
                if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
31859
5.24k
                    if (cc.line_num >= 0) line_num = cc.line_num;
31860
5.24k
                    add_pc2line_info(s, bc_out.size, line_num);
31861
5.24k
                    dbuf_putc(&bc_out, OP_is_undefined);
31862
5.24k
                    pos_next = cc.pos;
31863
5.24k
                    break;
31864
5.24k
                }
31865
                /* transform undefined strict_neq if_false/if_true -> is_undefined if_true/if_false */
31866
46.9k
                if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
31867
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
31868
0
                    add_pc2line_info(s, bc_out.size, line_num);
31869
0
                    dbuf_putc(&bc_out, OP_is_undefined);
31870
0
                    pos_next = cc.pos;
31871
0
                    label = cc.label;
31872
0
                    op = cc.op ^ OP_if_false ^ OP_if_true;
31873
0
                    goto has_label;
31874
0
                }
31875
46.9k
#endif
31876
46.9k
            }
31877
46.9k
            goto no_change;
31878
31879
46.9k
        case OP_insert2:
31880
3.94k
            if (OPTIMIZE) {
31881
                /* Transformation:
31882
                   insert2 put_field(a) drop -> put_field(a)
31883
                   insert2 put_var_strict(a) drop -> put_var_strict(a)
31884
                */
31885
3.94k
                if (code_match(&cc, pos_next, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
31886
170
                    if (cc.line_num >= 0) line_num = cc.line_num;
31887
170
                    add_pc2line_info(s, bc_out.size, line_num);
31888
170
                    dbuf_putc(&bc_out, cc.op);
31889
170
                    dbuf_put_u32(&bc_out, cc.atom);
31890
170
                    pos_next = cc.pos;
31891
170
                    break;
31892
170
                }
31893
3.94k
            }
31894
3.77k
            goto no_change;
31895
31896
95.2k
        case OP_dup:
31897
95.2k
            if (OPTIMIZE) {
31898
                /* Transformation: dup put_x(n) drop -> put_x(n) */
31899
95.2k
                int op1, line2 = -1;
31900
                /* Transformation: dup put_x(n) -> set_x(n) */
31901
95.2k
                if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, -1)) {
31902
15.6k
                    if (cc.line_num >= 0) line_num = cc.line_num;
31903
15.6k
                    op1 = cc.op + 1;  /* put_x -> set_x */
31904
15.6k
                    pos_next = cc.pos;
31905
15.6k
                    if (code_match(&cc, cc.pos, OP_drop, -1)) {
31906
158
                        if (cc.line_num >= 0) line_num = cc.line_num;
31907
158
                        op1 -= 1; /* set_x drop -> put_x */
31908
158
                        pos_next = cc.pos;
31909
158
                        if (code_match(&cc, cc.pos, op1 - 1, cc.idx, -1)) {
31910
51
                            line2 = cc.line_num; /* delay line number update */
31911
51
                            op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
31912
51
                            pos_next = cc.pos;
31913
51
                        }
31914
158
                    }
31915
15.6k
                    add_pc2line_info(s, bc_out.size, line_num);
31916
15.6k
                    put_short_code(&bc_out, op1, cc.idx);
31917
15.6k
                    if (line2 >= 0) line_num = line2;
31918
15.6k
                    break;
31919
15.6k
                }
31920
95.2k
            }
31921
79.6k
            goto no_change;
31922
31923
1.60M
        case OP_get_loc:
31924
1.60M
            if (OPTIMIZE) {
31925
                /* transformation:
31926
                   get_loc(n) post_dec put_loc(n) drop -> dec_loc(n)
31927
                   get_loc(n) post_inc put_loc(n) drop -> inc_loc(n)
31928
                   get_loc(n) dec dup put_loc(n) drop -> dec_loc(n)
31929
                   get_loc(n) inc dup put_loc(n) drop -> inc_loc(n)
31930
                 */
31931
1.60M
                int idx;
31932
1.60M
                idx = get_u16(bc_buf + pos + 1);
31933
1.60M
                if (idx >= 256)
31934
498k
                    goto no_change;
31935
1.10M
                if (code_match(&cc, pos_next, M2(OP_post_dec, OP_post_inc), OP_put_loc, idx, OP_drop, -1) ||
31936
1.10M
                    code_match(&cc, pos_next, M2(OP_dec, OP_inc), OP_dup, OP_put_loc, idx, OP_drop, -1)) {
31937
533
                    if (cc.line_num >= 0) line_num = cc.line_num;
31938
533
                    add_pc2line_info(s, bc_out.size, line_num);
31939
533
                    dbuf_putc(&bc_out, (cc.op == OP_inc || cc.op == OP_post_inc) ? OP_inc_loc : OP_dec_loc);
31940
533
                    dbuf_putc(&bc_out, idx);
31941
533
                    pos_next = cc.pos;
31942
533
                    break;
31943
533
                }
31944
                /* transformation:
31945
                   get_loc(n) push_atom_value(x) add dup put_loc(n) drop -> push_atom_value(x) add_loc(n)
31946
                 */
31947
1.10M
                if (code_match(&cc, pos_next, OP_push_atom_value, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
31948
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
31949
0
                    add_pc2line_info(s, bc_out.size, line_num);
31950
0
#if SHORT_OPCODES
31951
0
                    if (cc.atom == JS_ATOM_empty_string) {
31952
0
                        JS_FreeAtom(ctx, cc.atom);
31953
0
                        dbuf_putc(&bc_out, OP_push_empty_string);
31954
0
                    } else
31955
0
#endif
31956
0
                    {
31957
0
                        dbuf_putc(&bc_out, OP_push_atom_value);
31958
0
                        dbuf_put_u32(&bc_out, cc.atom);
31959
0
                    }
31960
0
                    dbuf_putc(&bc_out, OP_add_loc);
31961
0
                    dbuf_putc(&bc_out, idx);
31962
0
                    pos_next = cc.pos;
31963
0
                    break;
31964
0
                }
31965
                /* transformation:
31966
                   get_loc(n) push_i32(x) add dup put_loc(n) drop -> push_i32(x) add_loc(n)
31967
                 */
31968
1.10M
                if (code_match(&cc, pos_next, OP_push_i32, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
31969
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
31970
0
                    add_pc2line_info(s, bc_out.size, line_num);
31971
0
                    push_short_int(&bc_out, cc.label);
31972
0
                    dbuf_putc(&bc_out, OP_add_loc);
31973
0
                    dbuf_putc(&bc_out, idx);
31974
0
                    pos_next = cc.pos;
31975
0
                    break;
31976
0
                }
31977
                /* transformation: XXX: also do these:
31978
                   get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x) add_loc(n)
31979
                   get_loc(n) get_arg(x) add dup put_loc(n) drop -> get_arg(x) add_loc(n)
31980
                   get_loc(n) get_var_ref(x) add dup put_loc(n) drop -> get_var_ref(x) add_loc(n)
31981
                 */
31982
1.10M
                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)) {
31983
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
31984
0
                    add_pc2line_info(s, bc_out.size, line_num);
31985
0
                    put_short_code(&bc_out, cc.op, cc.idx);
31986
0
                    dbuf_putc(&bc_out, OP_add_loc);
31987
0
                    dbuf_putc(&bc_out, idx);
31988
0
                    pos_next = cc.pos;
31989
0
                    break;
31990
0
                }
31991
1.10M
                add_pc2line_info(s, bc_out.size, line_num);
31992
1.10M
                put_short_code(&bc_out, op, idx);
31993
1.10M
                break;
31994
1.10M
            }
31995
0
            goto no_change;
31996
0
#if SHORT_OPCODES
31997
9.26k
        case OP_get_arg:
31998
19.5k
        case OP_get_var_ref:
31999
19.5k
            if (OPTIMIZE) {
32000
19.5k
                int idx;
32001
19.5k
                idx = get_u16(bc_buf + pos + 1);
32002
19.5k
                add_pc2line_info(s, bc_out.size, line_num);
32003
19.5k
                put_short_code(&bc_out, op, idx);
32004
19.5k
                break;
32005
19.5k
            }
32006
0
            goto no_change;
32007
0
#endif
32008
92.9k
        case OP_put_loc:
32009
93.1k
        case OP_put_arg:
32010
93.8k
        case OP_put_var_ref:
32011
93.8k
            if (OPTIMIZE) {
32012
                /* transformation: put_x(n) get_x(n) -> set_x(n) */
32013
93.8k
                int idx;
32014
93.8k
                idx = get_u16(bc_buf + pos + 1);
32015
93.8k
                if (code_match(&cc, pos_next, op - 1, idx, -1)) {
32016
1.80k
                    if (cc.line_num >= 0) line_num = cc.line_num;
32017
1.80k
                    add_pc2line_info(s, bc_out.size, line_num);
32018
1.80k
                    put_short_code(&bc_out, op + 1, idx);
32019
1.80k
                    pos_next = cc.pos;
32020
1.80k
                    break;
32021
1.80k
                }
32022
92.0k
                add_pc2line_info(s, bc_out.size, line_num);
32023
92.0k
                put_short_code(&bc_out, op, idx);
32024
92.0k
                break;
32025
93.8k
            }
32026
0
            goto no_change;
32027
32028
716
        case OP_post_inc:
32029
3.14k
        case OP_post_dec:
32030
3.14k
            if (OPTIMIZE) {
32031
                /* transformation:
32032
                   post_inc put_x drop -> inc put_x
32033
                   post_inc perm3 put_field drop -> inc put_field
32034
                   post_inc perm3 put_var_strict drop -> inc put_var_strict
32035
                   post_inc perm4 put_array_el drop -> inc put_array_el
32036
                 */
32037
3.14k
                int op1, idx;
32038
3.14k
                if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, OP_drop, -1)) {
32039
293
                    if (cc.line_num >= 0) line_num = cc.line_num;
32040
293
                    op1 = cc.op;
32041
293
                    idx = cc.idx;
32042
293
                    pos_next = cc.pos;
32043
293
                    if (code_match(&cc, cc.pos, op1 - 1, idx, -1)) {
32044
125
                        if (cc.line_num >= 0) line_num = cc.line_num;
32045
125
                        op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
32046
125
                        pos_next = cc.pos;
32047
125
                    }
32048
293
                    add_pc2line_info(s, bc_out.size, line_num);
32049
293
                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
32050
293
                    put_short_code(&bc_out, op1, idx);
32051
293
                    break;
32052
293
                }
32053
2.85k
                if (code_match(&cc, pos_next, OP_perm3, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
32054
150
                    if (cc.line_num >= 0) line_num = cc.line_num;
32055
150
                    add_pc2line_info(s, bc_out.size, line_num);
32056
150
                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
32057
150
                    dbuf_putc(&bc_out, cc.op);
32058
150
                    dbuf_put_u32(&bc_out, cc.atom);
32059
150
                    pos_next = cc.pos;
32060
150
                    break;
32061
150
                }
32062
2.70k
                if (code_match(&cc, pos_next, OP_perm4, OP_put_array_el, OP_drop, -1)) {
32063
115
                    if (cc.line_num >= 0) line_num = cc.line_num;
32064
115
                    add_pc2line_info(s, bc_out.size, line_num);
32065
115
                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
32066
115
                    dbuf_putc(&bc_out, OP_put_array_el);
32067
115
                    pos_next = cc.pos;
32068
115
                    break;
32069
115
                }
32070
2.70k
            }
32071
2.58k
            goto no_change;
32072
32073
2.58k
#if SHORT_OPCODES
32074
2.58k
        case OP_typeof:
32075
250
            if (OPTIMIZE) {
32076
                /* simplify typeof tests */
32077
250
                if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) {
32078
89
                    if (cc.line_num >= 0) line_num = cc.line_num;
32079
89
                    int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq;
32080
89
                    int op2 = -1;
32081
89
                    switch (cc.atom) {
32082
8
                    case JS_ATOM_undefined:
32083
8
                        op2 = OP_typeof_is_undefined;
32084
8
                        break;
32085
0
                    case JS_ATOM_function:
32086
0
                        op2 = OP_typeof_is_function;
32087
0
                        break;
32088
89
                    }
32089
89
                    if (op2 >= 0) {
32090
                        /* transform typeof(s) == "<type>" into is_<type> */
32091
8
                        if (op1 == OP_strict_eq) {
32092
0
                            add_pc2line_info(s, bc_out.size, line_num);
32093
0
                            dbuf_putc(&bc_out, op2);
32094
0
                            JS_FreeAtom(ctx, cc.atom);
32095
0
                            pos_next = cc.pos;
32096
0
                            break;
32097
0
                        }
32098
8
                        if (op1 == OP_strict_neq && code_match(&cc, cc.pos, OP_if_false, -1)) {
32099
                            /* transform typeof(s) != "<type>" if_false into is_<type> if_true */
32100
0
                            if (cc.line_num >= 0) line_num = cc.line_num;
32101
0
                            add_pc2line_info(s, bc_out.size, line_num);
32102
0
                            dbuf_putc(&bc_out, op2);
32103
0
                            JS_FreeAtom(ctx, cc.atom);
32104
0
                            pos_next = cc.pos;
32105
0
                            label = cc.label;
32106
0
                            op = OP_if_true;
32107
0
                            goto has_label;
32108
0
                        }
32109
8
                    }
32110
89
                }
32111
250
            }
32112
250
            goto no_change;
32113
250
#endif
32114
32115
1.13M
        default:
32116
1.90M
        no_change:
32117
1.90M
            add_pc2line_info(s, bc_out.size, line_num);
32118
1.90M
            dbuf_put(&bc_out, bc_buf + pos, len);
32119
1.90M
            break;
32120
5.78M
        }
32121
5.78M
    }
32122
32123
    /* check that there were no missing labels */
32124
835k
    for(i = 0; i < s->label_count; i++) {
32125
803k
        assert(label_slots[i].first_reloc == NULL);
32126
803k
    }
32127
31.6k
#if SHORT_OPCODES
32128
31.6k
    if (OPTIMIZE) {
32129
        /* more jump optimizations */
32130
31.6k
        int patch_offsets = 0;
32131
1.71M
        for (i = 0, jp = s->jump_slots; i < s->jump_count; i++, jp++) {
32132
1.67M
            LabelSlot *ls;
32133
1.67M
            JumpSlot *jp1;
32134
1.67M
            int j, pos, diff, delta;
32135
32136
1.67M
            delta = 3;
32137
1.67M
            switch (op = jp->op) {
32138
7.81k
            case OP_goto16:
32139
7.81k
                delta = 1;
32140
                /* fall thru */
32141
12.4k
            case OP_if_false:
32142
24.6k
            case OP_if_true:
32143
25.0k
            case OP_goto:
32144
25.0k
                pos = jp->pos;
32145
25.0k
                diff = s->label_slots[jp->label].addr - pos;
32146
25.0k
                if (diff >= -128 && diff <= 127 + delta) {
32147
                    //put_u8(bc_out.buf + pos, diff);
32148
10.4k
                    jp->size = 1;
32149
10.4k
                    if (op == OP_goto16) {
32150
2.64k
                        bc_out.buf[pos - 1] = jp->op = OP_goto8;
32151
7.76k
                    } else {
32152
7.76k
                        bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false);
32153
7.76k
                    }
32154
10.4k
                    goto shrink;
32155
10.4k
                } else
32156
14.6k
                if (diff == (int16_t)diff && op == OP_goto) {
32157
                    //put_u16(bc_out.buf + pos, diff);
32158
77
                    jp->size = 2;
32159
77
                    delta = 2;
32160
77
                    bc_out.buf[pos - 1] = jp->op = OP_goto16;
32161
10.4k
                shrink:
32162
                    /* XXX: should reduce complexity, using 2 finger copy scheme */
32163
10.4k
                    memmove(bc_out.buf + pos + jp->size, bc_out.buf + pos + jp->size + delta,
32164
10.4k
                            bc_out.size - pos - jp->size - delta);
32165
10.4k
                    bc_out.size -= delta;
32166
10.4k
                    patch_offsets++;
32167
77.2M
                    for (j = 0, ls = s->label_slots; j < s->label_count; j++, ls++) {
32168
77.2M
                        if (ls->addr > pos)
32169
30.3M
                            ls->addr -= delta;
32170
77.2M
                    }
32171
21.6M
                    for (j = i + 1, jp1 = jp + 1; j < s->jump_count; j++, jp1++) {
32172
21.6M
                        if (jp1->pos > pos)
32173
21.6M
                            jp1->pos -= delta;
32174
21.6M
                    }
32175
8.80M
                    for (j = 0; j < s->line_number_count; j++) {
32176
8.79M
                        if (s->line_number_slots[j].pc > pos)
32177
4.39M
                            s->line_number_slots[j].pc -= delta;
32178
8.79M
                    }
32179
10.4k
                    continue;
32180
77
                }
32181
14.5k
                break;
32182
1.67M
            }
32183
1.67M
        }
32184
31.6k
        if (patch_offsets) {
32185
365
            JumpSlot *jp1;
32186
365
            int j;
32187
1.35M
            for (j = 0, jp1 = s->jump_slots; j < s->jump_count; j++, jp1++) {
32188
1.35M
                int diff1 = s->label_slots[jp1->label].addr - jp1->pos;
32189
1.35M
                switch (jp1->size) {
32190
56.7k
                case 1:
32191
56.7k
                    put_u8(bc_out.buf + jp1->pos, diff1);
32192
56.7k
                    break;
32193
4.98k
                case 2:
32194
4.98k
                    put_u16(bc_out.buf + jp1->pos, diff1);
32195
4.98k
                    break;
32196
1.29M
                case 4:
32197
1.29M
                    put_u32(bc_out.buf + jp1->pos, diff1);
32198
1.29M
                    break;
32199
1.35M
                }
32200
1.35M
            }
32201
365
        }
32202
31.6k
    }
32203
31.6k
    js_free(ctx, s->jump_slots);
32204
31.6k
    s->jump_slots = NULL;
32205
31.6k
#endif
32206
31.6k
    js_free(ctx, s->label_slots);
32207
31.6k
    s->label_slots = NULL;
32208
    /* XXX: should delay until copying to runtime bytecode function */
32209
31.6k
    compute_pc2line_info(s);
32210
31.6k
    js_free(ctx, s->line_number_slots);
32211
31.6k
    s->line_number_slots = NULL;
32212
    /* set the new byte code */
32213
31.6k
    dbuf_free(&s->byte_code);
32214
31.6k
    s->byte_code = bc_out;
32215
31.6k
    s->use_short_opcodes = TRUE;
32216
31.6k
    if (dbuf_error(&s->byte_code)) {
32217
0
        JS_ThrowOutOfMemory(ctx);
32218
0
        return -1;
32219
0
    }
32220
31.6k
    return 0;
32221
0
 fail:
32222
    /* XXX: not safe */
32223
0
    dbuf_free(&bc_out);
32224
0
    return -1;
32225
31.6k
}
32226
32227
/* compute the maximum stack size needed by the function */
32228
32229
typedef struct StackSizeState {
32230
    int bc_len;
32231
    int stack_len_max;
32232
    uint16_t *stack_level_tab;
32233
    int *pc_stack;
32234
    int pc_stack_len;
32235
    int pc_stack_size;
32236
} StackSizeState;
32237
32238
/* 'op' is only used for error indication */
32239
static __exception int ss_check(JSContext *ctx, StackSizeState *s,
32240
                                int pos, int op, int stack_len)
32241
6.54M
{
32242
6.54M
    if ((unsigned)pos >= s->bc_len) {
32243
0
        JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
32244
0
        return -1;
32245
0
    }
32246
6.54M
    if (stack_len > s->stack_len_max) {
32247
1.90k
        s->stack_len_max = stack_len;
32248
1.90k
        if (s->stack_len_max > JS_STACK_SIZE_MAX) {
32249
0
            JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
32250
0
            return -1;
32251
0
        }
32252
1.90k
    }
32253
6.54M
    if (s->stack_level_tab[pos] != 0xffff) {
32254
        /* already explored: check that the stack size is consistent */
32255
1.61M
        if (s->stack_level_tab[pos] != stack_len) {
32256
5
            JS_ThrowInternalError(ctx, "unconsistent stack size: %d %d (pc=%d)",
32257
5
                                  s->stack_level_tab[pos], stack_len, pos);
32258
5
            return -1;
32259
1.61M
        } else {
32260
1.61M
            return 0;
32261
1.61M
        }
32262
1.61M
    }
32263
32264
    /* mark as explored and store the stack size */
32265
4.92M
    s->stack_level_tab[pos] = stack_len;
32266
32267
    /* queue the new PC to explore */
32268
4.92M
    if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]),
32269
4.92M
                        &s->pc_stack_size, s->pc_stack_len + 1))
32270
0
        return -1;
32271
4.92M
    s->pc_stack[s->pc_stack_len++] = pos;
32272
4.92M
    return 0;
32273
4.92M
}
32274
32275
static __exception int compute_stack_size(JSContext *ctx,
32276
                                          JSFunctionDef *fd,
32277
                                          int *pstack_size)
32278
31.6k
{
32279
31.6k
    StackSizeState s_s, *s = &s_s;
32280
31.6k
    int i, diff, n_pop, pos_next, stack_len, pos, op;
32281
31.6k
    const JSOpCode *oi;
32282
31.6k
    const uint8_t *bc_buf;
32283
32284
31.6k
    bc_buf = fd->byte_code.buf;
32285
31.6k
    s->bc_len = fd->byte_code.size;
32286
    /* bc_len > 0 */
32287
31.6k
    s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) *
32288
31.6k
                                   s->bc_len);
32289
31.6k
    if (!s->stack_level_tab)
32290
0
        return -1;
32291
23.7M
    for(i = 0; i < s->bc_len; i++)
32292
23.7M
        s->stack_level_tab[i] = 0xffff;
32293
31.6k
    s->stack_len_max = 0;
32294
31.6k
    s->pc_stack = NULL;
32295
31.6k
    s->pc_stack_len = 0;
32296
31.6k
    s->pc_stack_size = 0;
32297
32298
    /* breadth-first graph exploration */
32299
31.6k
    if (ss_check(ctx, s, 0, OP_invalid, 0))
32300
0
        goto fail;
32301
32302
4.95M
    while (s->pc_stack_len > 0) {
32303
4.92M
        pos = s->pc_stack[--s->pc_stack_len];
32304
4.92M
        stack_len = s->stack_level_tab[pos];
32305
4.92M
        op = bc_buf[pos];
32306
4.92M
        if (op == 0 || op >= OP_COUNT) {
32307
0
            JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos);
32308
0
            goto fail;
32309
0
        }
32310
4.92M
        oi = &short_opcode_info(op);
32311
4.92M
        pos_next = pos + oi->size;
32312
4.92M
        if (pos_next > s->bc_len) {
32313
0
            JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
32314
0
            goto fail;
32315
0
        }
32316
4.92M
        n_pop = oi->n_pop;
32317
        /* call pops a variable number of arguments */
32318
4.92M
        if (oi->fmt == OP_FMT_npop || oi->fmt == OP_FMT_npop_u16) {
32319
16.1k
            n_pop += get_u16(bc_buf + pos + 1);
32320
4.90M
        } else {
32321
4.90M
#if SHORT_OPCODES
32322
4.90M
            if (oi->fmt == OP_FMT_npopx) {
32323
6.77k
                n_pop += op - OP_call0;
32324
6.77k
            }
32325
4.90M
#endif
32326
4.90M
        }
32327
32328
4.92M
        if (stack_len < n_pop) {
32329
0
            JS_ThrowInternalError(ctx, "stack underflow (op=%d, pc=%d)", op, pos);
32330
0
            goto fail;
32331
0
        }
32332
4.92M
        stack_len += oi->n_push - n_pop;
32333
4.92M
        if (stack_len > s->stack_len_max) {
32334
87.2k
            s->stack_len_max = stack_len;
32335
87.2k
            if (s->stack_len_max > JS_STACK_SIZE_MAX) {
32336
0
                JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
32337
0
                goto fail;
32338
0
            }
32339
87.2k
        }
32340
4.92M
        switch(op) {
32341
295
        case OP_tail_call:
32342
648
        case OP_tail_call_method:
32343
9.70k
        case OP_return:
32344
31.1k
        case OP_return_undef:
32345
32.1k
        case OP_return_async:
32346
32.2k
        case OP_throw:
32347
32.4k
        case OP_throw_error:
32348
32.4k
        case OP_ret:
32349
32.4k
            goto done_insn;
32350
296
        case OP_goto:
32351
296
            diff = get_u32(bc_buf + pos + 1);
32352
296
            pos_next = pos + 1 + diff;
32353
296
            break;
32354
0
#if SHORT_OPCODES
32355
5.21k
        case OP_goto16:
32356
5.21k
            diff = (int16_t)get_u16(bc_buf + pos + 1);
32357
5.21k
            pos_next = pos + 1 + diff;
32358
5.21k
            break;
32359
49.0k
        case OP_goto8:
32360
49.0k
            diff = (int8_t)bc_buf[pos + 1];
32361
49.0k
            pos_next = pos + 1 + diff;
32362
49.0k
            break;
32363
13.9k
        case OP_if_true8:
32364
32.3k
        case OP_if_false8:
32365
32.3k
            diff = (int8_t)bc_buf[pos + 1];
32366
32.3k
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
32367
0
                goto fail;
32368
32.3k
            break;
32369
32.3k
#endif
32370
32.3k
        case OP_if_true:
32371
9.07k
        case OP_if_false:
32372
9.07k
        case OP_catch:
32373
9.07k
            diff = get_u32(bc_buf + pos + 1);
32374
9.07k
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
32375
0
                goto fail;
32376
9.07k
            break;
32377
9.07k
        case OP_gosub:
32378
0
            diff = get_u32(bc_buf + pos + 1);
32379
0
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1))
32380
0
                goto fail;
32381
0
            break;
32382
982k
        case OP_with_get_var:
32383
982k
        case OP_with_delete_var:
32384
982k
            diff = get_u32(bc_buf + pos + 5);
32385
982k
            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1))
32386
0
                goto fail;
32387
982k
            break;
32388
982k
        case OP_with_make_ref:
32389
594k
        case OP_with_get_ref:
32390
594k
        case OP_with_get_ref_undef:
32391
594k
            diff = get_u32(bc_buf + pos + 5);
32392
594k
            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2))
32393
0
                goto fail;
32394
594k
            break;
32395
594k
        case OP_with_put_var:
32396
0
            diff = get_u32(bc_buf + pos + 5);
32397
0
            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1))
32398
0
                goto fail;
32399
0
            break;
32400
32401
3.21M
        default:
32402
3.21M
            break;
32403
4.92M
        }
32404
4.89M
        if (ss_check(ctx, s, pos_next, op, stack_len))
32405
5
            goto fail;
32406
4.92M
    done_insn: ;
32407
4.92M
    }
32408
31.6k
    js_free(ctx, s->stack_level_tab);
32409
31.6k
    js_free(ctx, s->pc_stack);
32410
31.6k
    *pstack_size = s->stack_len_max;
32411
31.6k
    return 0;
32412
5
 fail:
32413
5
    js_free(ctx, s->stack_level_tab);
32414
5
    js_free(ctx, s->pc_stack);
32415
5
    *pstack_size = 0;
32416
5
    return -1;
32417
31.6k
}
32418
32419
static int add_module_variables(JSContext *ctx, JSFunctionDef *fd)
32420
123
{
32421
123
    int i, idx;
32422
123
    JSModuleDef *m = fd->module;
32423
123
    JSExportEntry *me;
32424
123
    JSGlobalVar *hf;
32425
32426
    /* The imported global variables were added as closure variables
32427
       in js_parse_import(). We add here the module global
32428
       variables. */
32429
32430
747
    for(i = 0; i < fd->global_var_count; i++) {
32431
625
        hf = &fd->global_vars[i];
32432
625
        if (add_closure_var(ctx, fd, TRUE, FALSE, i, hf->var_name, hf->is_const,
32433
625
                            hf->is_lexical, FALSE) < 0)
32434
1
            return -1;
32435
625
    }
32436
32437
    /* resolve the variable names of the local exports */
32438
122
    for(i = 0; i < m->export_entries_count; i++) {
32439
0
        me = &m->export_entries[i];
32440
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
32441
0
            idx = find_closure_var(ctx, fd, me->local_name);
32442
0
            if (idx < 0) {
32443
0
                JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does not exist",
32444
0
                                        me->local_name);
32445
0
                return -1;
32446
0
            }
32447
0
            me->u.local.var_idx = idx;
32448
0
        }
32449
0
    }
32450
122
    return 0;
32451
122
}
32452
32453
/* create a function object from a function definition. The function
32454
   definition is freed. All the child functions are also created. It
32455
   must be done this way to resolve all the variables. */
32456
static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
32457
31.6k
{
32458
31.6k
    JSValue func_obj;
32459
31.6k
    JSFunctionBytecode *b;
32460
31.6k
    struct list_head *el, *el1;
32461
31.6k
    int stack_size, scope, idx;
32462
31.6k
    int function_size, byte_code_offset, cpool_offset;
32463
31.6k
    int closure_var_offset, vardefs_offset;
32464
32465
    /* recompute scope linkage */
32466
126k
    for (scope = 0; scope < fd->scope_count; scope++) {
32467
94.6k
        fd->scopes[scope].first = -1;
32468
94.6k
    }
32469
31.6k
    if (fd->has_parameter_expressions) {
32470
        /* special end of variable list marker for the argument scope */
32471
3.08k
        fd->scopes[ARG_SCOPE_INDEX].first = ARG_SCOPE_END;
32472
3.08k
    }
32473
85.0k
    for (idx = 0; idx < fd->var_count; idx++) {
32474
53.3k
        JSVarDef *vd = &fd->vars[idx];
32475
53.3k
        vd->scope_next = fd->scopes[vd->scope_level].first;
32476
53.3k
        fd->scopes[vd->scope_level].first = idx;
32477
53.3k
    }
32478
71.5k
    for (scope = 2; scope < fd->scope_count; scope++) {
32479
39.8k
        JSVarScope *sd = &fd->scopes[scope];
32480
39.8k
        if (sd->first < 0)
32481
10.7k
            sd->first = fd->scopes[sd->parent].first;
32482
39.8k
    }
32483
85.0k
    for (idx = 0; idx < fd->var_count; idx++) {
32484
53.3k
        JSVarDef *vd = &fd->vars[idx];
32485
53.3k
        if (vd->scope_next < 0 && vd->scope_level > 1) {
32486
29.1k
            scope = fd->scopes[vd->scope_level].parent;
32487
29.1k
            vd->scope_next = fd->scopes[scope].first;
32488
29.1k
        }
32489
53.3k
    }
32490
32491
    /* if the function contains an eval call, the closure variables
32492
       are used to compile the eval and they must be ordered by scope,
32493
       so it is necessary to create the closure variables before any
32494
       other variable lookup is done. */
32495
31.6k
    if (fd->has_eval_call)
32496
18
        add_eval_variables(ctx, fd);
32497
32498
    /* add the module global variables in the closure */
32499
31.6k
    if (fd->module) {
32500
123
        if (add_module_variables(ctx, fd))
32501
1
            goto fail;
32502
123
    }
32503
32504
    /* first create all the child functions */
32505
31.6k
    list_for_each_safe(el, el1, &fd->child_list) {
32506
30.4k
        JSFunctionDef *fd1;
32507
30.4k
        int cpool_idx;
32508
32509
30.4k
        fd1 = list_entry(el, JSFunctionDef, link);
32510
30.4k
        cpool_idx = fd1->parent_cpool_idx;
32511
30.4k
        func_obj = js_create_function(ctx, fd1);
32512
30.4k
        if (JS_IsException(func_obj))
32513
5
            goto fail;
32514
        /* save it in the constant pool */
32515
30.4k
        assert(cpool_idx >= 0);
32516
30.4k
        fd->cpool[cpool_idx] = func_obj;
32517
30.4k
    }
32518
32519
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 4)
32520
    if (!(fd->js_mode & JS_MODE_STRIP)) {
32521
        printf("pass 1\n");
32522
        dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size,
32523
                       fd->args, fd->arg_count, fd->vars, fd->var_count,
32524
                       fd->closure_var, fd->closure_var_count,
32525
                       fd->cpool, fd->cpool_count, fd->source, fd->line_num,
32526
                       fd->label_slots, NULL);
32527
        printf("\n");
32528
    }
32529
#endif
32530
32531
31.6k
    if (resolve_variables(ctx, fd))
32532
2
        goto fail;
32533
32534
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 2)
32535
    if (!(fd->js_mode & JS_MODE_STRIP)) {
32536
        printf("pass 2\n");
32537
        dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size,
32538
                       fd->args, fd->arg_count, fd->vars, fd->var_count,
32539
                       fd->closure_var, fd->closure_var_count,
32540
                       fd->cpool, fd->cpool_count, fd->source, fd->line_num,
32541
                       fd->label_slots, NULL);
32542
        printf("\n");
32543
    }
32544
#endif
32545
32546
31.6k
    if (resolve_labels(ctx, fd))
32547
0
        goto fail;
32548
32549
31.6k
    if (compute_stack_size(ctx, fd, &stack_size) < 0)
32550
5
        goto fail;
32551
32552
31.6k
    if (fd->js_mode & JS_MODE_STRIP) {
32553
2.89k
        function_size = offsetof(JSFunctionBytecode, debug);
32554
28.7k
    } else {
32555
28.7k
        function_size = sizeof(*b);
32556
28.7k
    }
32557
31.6k
    cpool_offset = function_size;
32558
31.6k
    function_size += fd->cpool_count * sizeof(*fd->cpool);
32559
31.6k
    vardefs_offset = function_size;
32560
31.6k
    if (!(fd->js_mode & JS_MODE_STRIP) || fd->has_eval_call) {
32561
28.7k
        function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs);
32562
28.7k
    }
32563
31.6k
    closure_var_offset = function_size;
32564
31.6k
    function_size += fd->closure_var_count * sizeof(*fd->closure_var);
32565
31.6k
    byte_code_offset = function_size;
32566
31.6k
    function_size += fd->byte_code.size;
32567
32568
31.6k
    b = js_mallocz(ctx, function_size);
32569
31.6k
    if (!b)
32570
0
        goto fail;
32571
31.6k
    b->header.ref_count = 1;
32572
32573
31.6k
    b->byte_code_buf = (void *)((uint8_t*)b + byte_code_offset);
32574
31.6k
    b->byte_code_len = fd->byte_code.size;
32575
31.6k
    memcpy(b->byte_code_buf, fd->byte_code.buf, fd->byte_code.size);
32576
31.6k
    js_free(ctx, fd->byte_code.buf);
32577
31.6k
    fd->byte_code.buf = NULL;
32578
32579
31.6k
    b->func_name = fd->func_name;
32580
31.6k
    if (fd->arg_count + fd->var_count > 0) {
32581
27.7k
        if ((fd->js_mode & JS_MODE_STRIP) && !fd->has_eval_call) {
32582
            /* Strip variable definitions not needed at runtime */
32583
2.48k
            int i;
32584
10.9k
            for(i = 0; i < fd->var_count; i++) {
32585
8.49k
                JS_FreeAtom(ctx, fd->vars[i].var_name);
32586
8.49k
            }
32587
4.80k
            for(i = 0; i < fd->arg_count; i++) {
32588
2.32k
                JS_FreeAtom(ctx, fd->args[i].var_name);
32589
2.32k
            }
32590
5.01k
            for(i = 0; i < fd->closure_var_count; i++) {
32591
2.53k
                JS_FreeAtom(ctx, fd->closure_var[i].var_name);
32592
2.53k
                fd->closure_var[i].var_name = JS_ATOM_NULL;
32593
2.53k
            }
32594
25.3k
        } else {
32595
25.3k
            b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
32596
25.3k
            memcpy(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
32597
25.3k
            memcpy(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
32598
25.3k
        }
32599
27.7k
        b->var_count = fd->var_count;
32600
27.7k
        b->arg_count = fd->arg_count;
32601
27.7k
        b->defined_arg_count = fd->defined_arg_count;
32602
27.7k
        js_free(ctx, fd->args);
32603
27.7k
        js_free(ctx, fd->vars);
32604
27.7k
    }
32605
31.6k
    b->cpool_count = fd->cpool_count;
32606
31.6k
    if (b->cpool_count) {
32607
4.55k
        b->cpool = (void *)((uint8_t*)b + cpool_offset);
32608
4.55k
        memcpy(b->cpool, fd->cpool, b->cpool_count * sizeof(*b->cpool));
32609
4.55k
    }
32610
31.6k
    js_free(ctx, fd->cpool);
32611
31.6k
    fd->cpool = NULL;
32612
32613
31.6k
    b->stack_size = stack_size;
32614
32615
31.6k
    if (fd->js_mode & JS_MODE_STRIP) {
32616
2.89k
        JS_FreeAtom(ctx, fd->filename);
32617
2.89k
        dbuf_free(&fd->pc2line);    // probably useless
32618
28.7k
    } else {
32619
        /* XXX: source and pc2line info should be packed at the end of the
32620
           JSFunctionBytecode structure, avoiding allocation overhead
32621
         */
32622
28.7k
        b->has_debug = 1;
32623
28.7k
        b->debug.filename = fd->filename;
32624
28.7k
        b->debug.line_num = fd->line_num;
32625
32626
        //DynBuf pc2line;
32627
        //compute_pc2line_info(fd, &pc2line);
32628
        //js_free(ctx, fd->line_number_slots)
32629
28.7k
        b->debug.pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size);
32630
28.7k
        if (!b->debug.pc2line_buf)
32631
14.1k
            b->debug.pc2line_buf = fd->pc2line.buf;
32632
28.7k
        b->debug.pc2line_len = fd->pc2line.size;
32633
28.7k
        b->debug.source = fd->source;
32634
28.7k
        b->debug.source_len = fd->source_len;
32635
28.7k
    }
32636
31.6k
    if (fd->scopes != fd->def_scope_array)
32637
492
        js_free(ctx, fd->scopes);
32638
32639
31.6k
    b->closure_var_count = fd->closure_var_count;
32640
31.6k
    if (b->closure_var_count) {
32641
21.6k
        b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
32642
21.6k
        memcpy(b->closure_var, fd->closure_var, b->closure_var_count * sizeof(*b->closure_var));
32643
21.6k
    }
32644
31.6k
    js_free(ctx, fd->closure_var);
32645
31.6k
    fd->closure_var = NULL;
32646
32647
31.6k
    b->has_prototype = fd->has_prototype;
32648
31.6k
    b->has_simple_parameter_list = fd->has_simple_parameter_list;
32649
31.6k
    b->js_mode = fd->js_mode;
32650
31.6k
    b->is_derived_class_constructor = fd->is_derived_class_constructor;
32651
31.6k
    b->func_kind = fd->func_kind;
32652
31.6k
    b->need_home_object = (fd->home_object_var_idx >= 0 ||
32653
31.6k
                           fd->need_home_object);
32654
31.6k
    b->new_target_allowed = fd->new_target_allowed;
32655
31.6k
    b->super_call_allowed = fd->super_call_allowed;
32656
31.6k
    b->super_allowed = fd->super_allowed;
32657
31.6k
    b->arguments_allowed = fd->arguments_allowed;
32658
31.6k
    b->backtrace_barrier = fd->backtrace_barrier;
32659
31.6k
    b->realm = JS_DupContext(ctx);
32660
32661
31.6k
    add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
32662
    
32663
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 1)
32664
    if (!(fd->js_mode & JS_MODE_STRIP)) {
32665
        js_dump_function_bytecode(ctx, b);
32666
    }
32667
#endif
32668
32669
31.6k
    if (fd->parent) {
32670
        /* remove from parent list */
32671
30.4k
        list_del(&fd->link);
32672
30.4k
    }
32673
32674
31.6k
    js_free(ctx, fd);
32675
31.6k
    return JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
32676
13
 fail:
32677
13
    js_free_function_def(ctx, fd);
32678
13
    return JS_EXCEPTION;
32679
31.6k
}
32680
32681
static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)
32682
30.0k
{
32683
30.0k
    int i;
32684
32685
#if 0
32686
    {
32687
        char buf[ATOM_GET_STR_BUF_SIZE];
32688
        printf("freeing %s\n",
32689
               JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
32690
    }
32691
#endif
32692
30.0k
    free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE);
32693
32694
30.0k
    if (b->vardefs) {
32695
101k
        for(i = 0; i < b->arg_count + b->var_count; i++) {
32696
78.0k
            JS_FreeAtomRT(rt, b->vardefs[i].var_name);
32697
78.0k
        }
32698
23.6k
    }
32699
88.0k
    for(i = 0; i < b->cpool_count; i++)
32700
57.9k
        JS_FreeValueRT(rt, b->cpool[i]);
32701
32702
57.5k
    for(i = 0; i < b->closure_var_count; i++) {
32703
27.5k
        JSClosureVar *cv = &b->closure_var[i];
32704
27.5k
        JS_FreeAtomRT(rt, cv->var_name);
32705
27.5k
    }
32706
30.0k
    if (b->realm)
32707
30.0k
        JS_FreeContext(b->realm);
32708
32709
30.0k
    JS_FreeAtomRT(rt, b->func_name);
32710
30.0k
    if (b->has_debug) {
32711
27.1k
        JS_FreeAtomRT(rt, b->debug.filename);
32712
27.1k
        js_free_rt(rt, b->debug.pc2line_buf);
32713
27.1k
        js_free_rt(rt, b->debug.source);
32714
27.1k
    }
32715
32716
30.0k
    remove_gc_object(&b->header);
32717
30.0k
    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && b->header.ref_count != 0) {
32718
14.7k
        list_add_tail(&b->header.link, &rt->gc_zero_ref_count_list);
32719
15.3k
    } else {
32720
15.3k
        js_free_rt(rt, b);
32721
15.3k
    }
32722
30.0k
}
32723
32724
static __exception int js_parse_directives(JSParseState *s)
32725
23.6k
{
32726
23.6k
    char str[20];
32727
23.6k
    JSParsePos pos;
32728
23.6k
    BOOL has_semi;
32729
32730
23.6k
    if (s->token.val != TOK_STRING)
32731
23.1k
        return 0;
32732
32733
449
    js_parse_get_pos(s, &pos);
32734
32735
790
    while(s->token.val == TOK_STRING) {
32736
        /* Copy actual source string representation */
32737
509
        snprintf(str, sizeof str, "%.*s",
32738
509
                 (int)(s->buf_ptr - s->token.ptr - 2), s->token.ptr + 1);
32739
32740
509
        if (next_token(s))
32741
0
            return -1;
32742
32743
509
        has_semi = FALSE;
32744
509
        switch (s->token.val) {
32745
4
        case ';':
32746
4
            if (next_token(s))
32747
0
                return -1;
32748
4
            has_semi = TRUE;
32749
4
            break;
32750
16
        case '}':
32751
16
        case TOK_EOF:
32752
16
            has_semi = TRUE;
32753
16
            break;
32754
11
        case TOK_NUMBER:
32755
71
        case TOK_STRING:
32756
86
        case TOK_TEMPLATE:
32757
252
        case TOK_IDENT:
32758
252
        case TOK_REGEXP:
32759
252
        case TOK_DEC:
32760
252
        case TOK_INC:
32761
263
        case TOK_NULL:
32762
263
        case TOK_FALSE:
32763
263
        case TOK_TRUE:
32764
272
        case TOK_IF:
32765
289
        case TOK_RETURN:
32766
289
        case TOK_VAR:
32767
289
        case TOK_THIS:
32768
290
        case TOK_DELETE:
32769
290
        case TOK_TYPEOF:
32770
290
        case TOK_NEW:
32771
290
        case TOK_DO:
32772
296
        case TOK_WHILE:
32773
307
        case TOK_FOR:
32774
307
        case TOK_SWITCH:
32775
307
        case TOK_THROW:
32776
307
        case TOK_TRY:
32777
308
        case TOK_FUNCTION:
32778
308
        case TOK_DEBUGGER:
32779
308
        case TOK_WITH:
32780
321
        case TOK_CLASS:
32781
321
        case TOK_CONST:
32782
321
        case TOK_ENUM:
32783
321
        case TOK_EXPORT:
32784
321
        case TOK_IMPORT:
32785
321
        case TOK_SUPER:
32786
321
        case TOK_INTERFACE:
32787
321
        case TOK_LET:
32788
321
        case TOK_PACKAGE:
32789
321
        case TOK_PRIVATE:
32790
321
        case TOK_PROTECTED:
32791
321
        case TOK_PUBLIC:
32792
321
        case TOK_STATIC:
32793
            /* automatic insertion of ';' */
32794
321
            if (s->got_lf)
32795
321
                has_semi = TRUE;
32796
321
            break;
32797
168
        default:
32798
168
            break;
32799
509
        }
32800
509
        if (!has_semi)
32801
168
            break;
32802
341
        if (!strcmp(str, "use strict")) {
32803
19
            s->cur_func->has_use_strict = TRUE;
32804
19
            s->cur_func->js_mode |= JS_MODE_STRICT;
32805
19
        }
32806
322
#if !defined(DUMP_BYTECODE) || !(DUMP_BYTECODE & 8)
32807
322
        else if (!strcmp(str, "use strip")) {
32808
118
            s->cur_func->js_mode |= JS_MODE_STRIP;
32809
118
        }
32810
204
#endif
32811
204
#ifdef CONFIG_BIGNUM
32812
204
        else if (s->ctx->bignum_ext && !strcmp(str, "use math")) {
32813
0
            s->cur_func->js_mode |= JS_MODE_MATH;
32814
0
        }
32815
341
#endif
32816
341
    }
32817
449
    return js_parse_seek_token(s, &pos);
32818
449
}
32819
32820
static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
32821
                                         JSAtom func_name)
32822
33.1k
{
32823
33.1k
    JSAtom name;
32824
33.1k
    int i, idx;
32825
32826
33.1k
    if (fd->js_mode & JS_MODE_STRICT) {
32827
13.7k
        if (!fd->has_simple_parameter_list && fd->has_use_strict) {
32828
0
            return js_parse_error(s, "\"use strict\" not allowed in function with default or destructuring parameter");
32829
0
        }
32830
13.7k
        if (func_name == JS_ATOM_eval || func_name == JS_ATOM_arguments) {
32831
0
            return js_parse_error(s, "invalid function name in strict code");
32832
0
        }
32833
15.5k
        for (idx = 0; idx < fd->arg_count; idx++) {
32834
1.81k
            name = fd->args[idx].var_name;
32835
32836
1.81k
            if (name == JS_ATOM_eval || name == JS_ATOM_arguments) {
32837
0
                return js_parse_error(s, "invalid argument name in strict code");
32838
0
            }
32839
1.81k
        }
32840
13.7k
    }
32841
    /* check async_generator case */
32842
33.1k
    if ((fd->js_mode & JS_MODE_STRICT)
32843
33.1k
    ||  !fd->has_simple_parameter_list
32844
33.1k
    ||  (fd->func_type == JS_PARSE_FUNC_METHOD && fd->func_kind == JS_FUNC_ASYNC)
32845
33.1k
    ||  fd->func_type == JS_PARSE_FUNC_ARROW
32846
33.1k
    ||  fd->func_type == JS_PARSE_FUNC_METHOD) {
32847
40.7k
        for (idx = 0; idx < fd->arg_count; idx++) {
32848
17.6k
            name = fd->args[idx].var_name;
32849
17.6k
            if (name != JS_ATOM_NULL) {
32850
26.2k
                for (i = 0; i < idx; i++) {
32851
10.5k
                    if (fd->args[i].var_name == name)
32852
0
                        goto duplicate;
32853
10.5k
                }
32854
                /* Check if argument name duplicates a destructuring parameter */
32855
                /* XXX: should have a flag for such variables */
32856
61.3k
                for (i = 0; i < fd->var_count; i++) {
32857
45.6k
                    if (fd->vars[i].var_name == name &&
32858
45.6k
                        fd->vars[i].scope_level == 0)
32859
0
                        goto duplicate;
32860
45.6k
                }
32861
15.6k
            }
32862
17.6k
        }
32863
23.1k
    }
32864
33.1k
    return 0;
32865
32866
0
duplicate:
32867
0
    return js_parse_error(s, "duplicate argument names not allowed in this context");
32868
33.1k
}
32869
32870
/* create a function to initialize class fields */
32871
static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s)
32872
10.4k
{
32873
10.4k
    JSFunctionDef *fd;
32874
    
32875
10.4k
    fd = js_new_function_def(s->ctx, s->cur_func, FALSE, FALSE,
32876
10.4k
                             s->filename, 0);
32877
10.4k
    if (!fd)
32878
0
        return NULL;
32879
10.4k
    fd->func_name = JS_ATOM_NULL;
32880
10.4k
    fd->has_prototype = FALSE;
32881
10.4k
    fd->has_home_object = TRUE;
32882
    
32883
10.4k
    fd->has_arguments_binding = FALSE;
32884
10.4k
    fd->has_this_binding = TRUE;
32885
10.4k
    fd->is_derived_class_constructor = FALSE;
32886
10.4k
    fd->new_target_allowed = TRUE;
32887
10.4k
    fd->super_call_allowed = FALSE;
32888
10.4k
    fd->super_allowed = fd->has_home_object;
32889
10.4k
    fd->arguments_allowed = FALSE;
32890
    
32891
10.4k
    fd->func_kind = JS_FUNC_NORMAL;
32892
10.4k
    fd->func_type = JS_PARSE_FUNC_METHOD;
32893
10.4k
    return fd;
32894
10.4k
}
32895
32896
/* func_name must be JS_ATOM_NULL for JS_PARSE_FUNC_STATEMENT and
32897
   JS_PARSE_FUNC_EXPR, JS_PARSE_FUNC_ARROW and JS_PARSE_FUNC_VAR */
32898
static __exception int js_parse_function_decl2(JSParseState *s,
32899
                                               JSParseFunctionEnum func_type,
32900
                                               JSFunctionKindEnum func_kind,
32901
                                               JSAtom func_name,
32902
                                               const uint8_t *ptr,
32903
                                               int function_line_num,
32904
                                               JSParseExportEnum export_flag,
32905
                                               JSFunctionDef **pfd)
32906
33.2k
{
32907
33.2k
    JSContext *ctx = s->ctx;
32908
33.2k
    JSFunctionDef *fd = s->cur_func;
32909
33.2k
    BOOL is_expr;
32910
33.2k
    int func_idx, lexical_func_idx = -1;
32911
33.2k
    BOOL has_opt_arg;
32912
33.2k
    BOOL create_func_var = FALSE;
32913
32914
33.2k
    is_expr = (func_type != JS_PARSE_FUNC_STATEMENT &&
32915
33.2k
               func_type != JS_PARSE_FUNC_VAR);
32916
32917
33.2k
    if (func_type == JS_PARSE_FUNC_STATEMENT ||
32918
33.2k
        func_type == JS_PARSE_FUNC_VAR ||
32919
33.2k
        func_type == JS_PARSE_FUNC_EXPR) {
32920
10.6k
        if (func_kind == JS_FUNC_NORMAL &&
32921
10.6k
            token_is_pseudo_keyword(s, JS_ATOM_async) &&
32922
10.6k
            peek_token(s, TRUE) != '\n') {
32923
0
            if (next_token(s))
32924
0
                return -1;
32925
0
            func_kind = JS_FUNC_ASYNC;
32926
0
        }
32927
10.6k
        if (next_token(s))
32928
0
            return -1;
32929
10.6k
        if (s->token.val == '*') {
32930
1.03k
            if (next_token(s))
32931
0
                return -1;
32932
1.03k
            func_kind |= JS_FUNC_GENERATOR;
32933
1.03k
        }
32934
32935
10.6k
        if (s->token.val == TOK_IDENT) {
32936
10.3k
            if (s->token.u.ident.is_reserved ||
32937
10.3k
                (s->token.u.ident.atom == JS_ATOM_yield &&
32938
10.3k
                 func_type == JS_PARSE_FUNC_EXPR &&
32939
10.3k
                 (func_kind & JS_FUNC_GENERATOR)) ||
32940
10.3k
                (s->token.u.ident.atom == JS_ATOM_await &&
32941
10.3k
                 func_type == JS_PARSE_FUNC_EXPR &&
32942
10.3k
                 (func_kind & JS_FUNC_ASYNC))) {
32943
0
                return js_parse_error_reserved_identifier(s);
32944
0
            }
32945
10.3k
        }
32946
10.6k
        if (s->token.val == TOK_IDENT ||
32947
10.6k
            (((s->token.val == TOK_YIELD && !(fd->js_mode & JS_MODE_STRICT)) ||
32948
258
             (s->token.val == TOK_AWAIT && !s->is_module)) &&
32949
10.3k
             func_type == JS_PARSE_FUNC_EXPR)) {
32950
10.3k
            func_name = JS_DupAtom(ctx, s->token.u.ident.atom);
32951
10.3k
            if (next_token(s)) {
32952
2
                JS_FreeAtom(ctx, func_name);
32953
2
                return -1;
32954
2
            }
32955
10.3k
        } else {
32956
258
            if (func_type != JS_PARSE_FUNC_EXPR &&
32957
258
                export_flag != JS_PARSE_EXPORT_DEFAULT) {
32958
2
                return js_parse_error(s, "function name expected");
32959
2
            }
32960
258
        }
32961
22.6k
    } else if (func_type != JS_PARSE_FUNC_ARROW) {
32962
12.9k
        func_name = JS_DupAtom(ctx, func_name);
32963
12.9k
    }
32964
32965
33.2k
    if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_MODULE &&
32966
33.2k
        (func_type == JS_PARSE_FUNC_STATEMENT || func_type == JS_PARSE_FUNC_VAR)) {
32967
0
        JSGlobalVar *hf;
32968
0
        hf = find_global_var(fd, func_name);
32969
        /* XXX: should check scope chain */
32970
0
        if (hf && hf->scope_level == fd->scope_level) {
32971
0
            js_parse_error(s, "invalid redefinition of global identifier in module code");
32972
0
            JS_FreeAtom(ctx, func_name);
32973
0
            return -1;
32974
0
        }
32975
0
    }
32976
32977
33.2k
    if (func_type == JS_PARSE_FUNC_VAR) {
32978
1.60k
        if (!(fd->js_mode & JS_MODE_STRICT)
32979
1.60k
        && func_kind == JS_FUNC_NORMAL
32980
1.60k
        &&  find_lexical_decl(ctx, fd, func_name, fd->scope_first, FALSE) < 0
32981
1.60k
        &&  !((func_idx = find_var(ctx, fd, func_name)) >= 0 && (func_idx & ARGUMENT_VAR_OFFSET))
32982
1.60k
        &&  !(func_name == JS_ATOM_arguments && fd->has_arguments_binding)) {
32983
699
            create_func_var = TRUE;
32984
699
        }
32985
        /* Create the lexical name here so that the function closure
32986
           contains it */
32987
1.60k
        if (fd->is_eval &&
32988
1.60k
            (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
32989
977
             fd->eval_type == JS_EVAL_TYPE_MODULE) &&
32990
1.60k
            fd->scope_level == fd->body_scope) {
32991
            /* avoid creating a lexical variable in the global
32992
               scope. XXX: check annex B */
32993
107
            JSGlobalVar *hf;
32994
107
            hf = find_global_var(fd, func_name);
32995
            /* XXX: should check scope chain */
32996
107
            if (hf && hf->scope_level == fd->scope_level) {
32997
0
                js_parse_error(s, "invalid redefinition of global identifier");
32998
0
                JS_FreeAtom(ctx, func_name);
32999
0
                return -1;
33000
0
            }
33001
1.49k
        } else {
33002
            /* Always create a lexical name, fail if at the same scope as
33003
               existing name */
33004
            /* Lexical variable will be initialized upon entering scope */
33005
1.49k
            lexical_func_idx = define_var(s, fd, func_name,
33006
1.49k
                                          func_kind != JS_FUNC_NORMAL ?
33007
49
                                          JS_VAR_DEF_NEW_FUNCTION_DECL :
33008
1.49k
                                          JS_VAR_DEF_FUNCTION_DECL);
33009
1.49k
            if (lexical_func_idx < 0) {
33010
0
                JS_FreeAtom(ctx, func_name);
33011
0
                return -1;
33012
0
            }
33013
1.49k
        }
33014
1.60k
    }
33015
33016
33.2k
    fd = js_new_function_def(ctx, fd, FALSE, is_expr,
33017
33.2k
                             s->filename, function_line_num);
33018
33.2k
    if (!fd) {
33019
2
        JS_FreeAtom(ctx, func_name);
33020
2
        return -1;
33021
2
    }
33022
33.2k
    if (pfd)
33023
12.6k
        *pfd = fd;
33024
33.2k
    s->cur_func = fd;
33025
33.2k
    fd->func_name = func_name;
33026
    /* XXX: test !fd->is_generator is always false */
33027
33.2k
    fd->has_prototype = (func_type == JS_PARSE_FUNC_STATEMENT ||
33028
33.2k
                         func_type == JS_PARSE_FUNC_VAR ||
33029
33.2k
                         func_type == JS_PARSE_FUNC_EXPR) &&
33030
33.2k
                        func_kind == JS_FUNC_NORMAL;
33031
33.2k
    fd->has_home_object = (func_type == JS_PARSE_FUNC_METHOD ||
33032
33.2k
                           func_type == JS_PARSE_FUNC_GETTER ||
33033
33.2k
                           func_type == JS_PARSE_FUNC_SETTER ||
33034
33.2k
                           func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
33035
33.2k
                           func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
33036
33.2k
    fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW);
33037
33.2k
    fd->has_this_binding = fd->has_arguments_binding;
33038
33.2k
    fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
33039
33.2k
    if (func_type == JS_PARSE_FUNC_ARROW) {
33040
9.66k
        fd->new_target_allowed = fd->parent->new_target_allowed;
33041
9.66k
        fd->super_call_allowed = fd->parent->super_call_allowed;
33042
9.66k
        fd->super_allowed = fd->parent->super_allowed;
33043
9.66k
        fd->arguments_allowed = fd->parent->arguments_allowed;
33044
23.5k
    } else {
33045
23.5k
        fd->new_target_allowed = TRUE;
33046
23.5k
        fd->super_call_allowed = fd->is_derived_class_constructor;
33047
23.5k
        fd->super_allowed = fd->has_home_object;
33048
23.5k
        fd->arguments_allowed = TRUE;
33049
23.5k
    }
33050
33051
    /* fd->in_function_body == FALSE prevents yield/await during the parsing
33052
       of the arguments in generator/async functions. They are parsed as
33053
       regular identifiers for other function kinds. */
33054
33.2k
    fd->func_kind = func_kind;
33055
33.2k
    fd->func_type = func_type;
33056
33057
33.2k
    if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
33058
33.2k
        func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
33059
        /* error if not invoked as a constructor */
33060
11.1k
        emit_op(s, OP_check_ctor);
33061
11.1k
    }
33062
33063
33.2k
    if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
33064
11.1k
        emit_class_field_init(s);
33065
11.1k
    }
33066
    
33067
    /* parse arguments */
33068
33.2k
    fd->has_simple_parameter_list = TRUE;
33069
33.2k
    fd->has_parameter_expressions = FALSE;
33070
33.2k
    has_opt_arg = FALSE;
33071
33.2k
    if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) {
33072
5.72k
        JSAtom name;
33073
5.72k
        if (s->token.u.ident.is_reserved) {
33074
0
            js_parse_error_reserved_identifier(s);
33075
0
            goto fail;
33076
0
        }
33077
5.72k
        name = s->token.u.ident.atom;
33078
5.72k
        if (add_arg(ctx, fd, name) < 0)
33079
0
            goto fail;
33080
5.72k
        fd->defined_arg_count = 1;
33081
27.4k
    } else {
33082
27.4k
        if (s->token.val == '(') {
33083
27.4k
            int skip_bits;
33084
            /* if there is an '=' inside the parameter list, we
33085
               consider there is a parameter expression inside */
33086
27.4k
            js_parse_skip_parens_token(s, &skip_bits, FALSE);
33087
27.4k
            if (skip_bits & SKIP_HAS_ASSIGNMENT)
33088
3.78k
                fd->has_parameter_expressions = TRUE;
33089
27.4k
            if (next_token(s))
33090
0
                goto fail;
33091
27.4k
        } else {
33092
5
            if (js_parse_expect(s, '('))
33093
5
                goto fail;
33094
5
        }
33095
33096
27.4k
        if (fd->has_parameter_expressions) {
33097
3.78k
            fd->scope_level = -1; /* force no parent scope */
33098
3.78k
            if (push_scope(s) < 0)
33099
0
                return -1;
33100
3.78k
        }
33101
        
33102
36.5k
        while (s->token.val != ')') {
33103
12.7k
            JSAtom name;
33104
12.7k
            BOOL rest = FALSE;
33105
12.7k
            int idx, has_initializer;
33106
33107
12.7k
            if (s->token.val == TOK_ELLIPSIS) {
33108
4
                fd->has_simple_parameter_list = FALSE;
33109
4
                rest = TRUE;
33110
4
                if (next_token(s))
33111
0
                    goto fail;
33112
4
            }
33113
12.7k
            if (s->token.val == '[' || s->token.val == '{') {
33114
1.91k
                fd->has_simple_parameter_list = FALSE;
33115
1.91k
                if (rest) {
33116
0
                    emit_op(s, OP_rest);
33117
0
                    emit_u16(s, fd->arg_count);
33118
1.91k
                } else {
33119
                    /* unnamed arg for destructuring */
33120
1.91k
                    idx = add_arg(ctx, fd, JS_ATOM_NULL);
33121
1.91k
                    emit_op(s, OP_get_arg);
33122
1.91k
                    emit_u16(s, idx);
33123
1.91k
                }
33124
1.91k
                has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE);
33125
1.91k
                if (has_initializer < 0)
33126
3
                    goto fail;
33127
1.90k
                if (has_initializer)
33128
1.31k
                    has_opt_arg = TRUE;
33129
1.90k
                if (!has_opt_arg)
33130
593
                    fd->defined_arg_count++;
33131
10.8k
            } else if (s->token.val == TOK_IDENT) {
33132
10.7k
                if (s->token.u.ident.is_reserved) {
33133
0
                    js_parse_error_reserved_identifier(s);
33134
0
                    goto fail;
33135
0
                }
33136
10.7k
                name = s->token.u.ident.atom;
33137
10.7k
                if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
33138
0
                    js_parse_error_reserved_identifier(s);
33139
0
                    goto fail;
33140
0
                }
33141
10.7k
                if (fd->has_parameter_expressions) {
33142
9.12k
                    if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0)
33143
0
                        goto fail;
33144
9.12k
                }
33145
                /* XXX: could avoid allocating an argument if rest is true */
33146
10.7k
                idx = add_arg(ctx, fd, name);
33147
10.7k
                if (idx < 0)
33148
0
                    goto fail;
33149
10.7k
                if (next_token(s))
33150
0
                    goto fail;
33151
10.7k
                if (rest) {
33152
4
                    emit_op(s, OP_rest);
33153
4
                    emit_u16(s, idx);
33154
4
                    if (fd->has_parameter_expressions) {
33155
0
                        emit_op(s, OP_dup);
33156
0
                        emit_op(s, OP_scope_put_var_init);
33157
0
                        emit_atom(s, name);
33158
0
                        emit_u16(s, fd->scope_level);
33159
0
                    }
33160
4
                    emit_op(s, OP_put_arg);
33161
4
                    emit_u16(s, idx);
33162
4
                    fd->has_simple_parameter_list = FALSE;
33163
4
                    has_opt_arg = TRUE;
33164
10.7k
                } else if (s->token.val == '=') {
33165
3.36k
                    int label;
33166
                    
33167
3.36k
                    fd->has_simple_parameter_list = FALSE;
33168
3.36k
                    has_opt_arg = TRUE;
33169
33170
3.36k
                    if (next_token(s))
33171
0
                        goto fail;
33172
33173
3.36k
                    label = new_label(s);
33174
3.36k
                    emit_op(s, OP_get_arg);
33175
3.36k
                    emit_u16(s, idx);
33176
3.36k
                    emit_op(s, OP_dup);
33177
3.36k
                    emit_op(s, OP_undefined);
33178
3.36k
                    emit_op(s, OP_strict_eq);
33179
3.36k
                    emit_goto(s, OP_if_false, label);
33180
3.36k
                    emit_op(s, OP_drop);
33181
3.36k
                    if (js_parse_assign_expr(s))
33182
1
                        goto fail;
33183
3.36k
                    set_object_name(s, name);
33184
3.36k
                    emit_op(s, OP_dup);
33185
3.36k
                    emit_op(s, OP_put_arg);
33186
3.36k
                    emit_u16(s, idx);
33187
3.36k
                    emit_label(s, label);
33188
3.36k
                    emit_op(s, OP_scope_put_var_init);
33189
3.36k
                    emit_atom(s, name);
33190
3.36k
                    emit_u16(s, fd->scope_level);
33191
7.42k
                } else {
33192
7.42k
                    if (!has_opt_arg) {
33193
5.95k
                        fd->defined_arg_count++;
33194
5.95k
                    }
33195
7.42k
                    if (fd->has_parameter_expressions) {
33196
                        /* copy the argument to the argument scope */
33197
5.75k
                        emit_op(s, OP_get_arg);
33198
5.75k
                        emit_u16(s, idx);
33199
5.75k
                        emit_op(s, OP_scope_put_var_init);
33200
5.75k
                        emit_atom(s, name);
33201
5.75k
                        emit_u16(s, fd->scope_level);
33202
5.75k
                    }
33203
7.42k
                }
33204
10.7k
            } else {
33205
1
                js_parse_error(s, "missing formal parameter");
33206
1
                goto fail;
33207
1
            }
33208
12.7k
            if (rest && s->token.val != ')') {
33209
0
                js_parse_expect(s, ')');
33210
0
                goto fail;
33211
0
            }
33212
12.7k
            if (s->token.val == ')')
33213
3.63k
                break;
33214
9.07k
            if (js_parse_expect(s, ','))
33215
1
                goto fail;
33216
9.07k
        }
33217
27.4k
        if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) ||
33218
27.4k
            (func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) {
33219
0
            js_parse_error(s, "invalid number of arguments for getter or setter");
33220
0
            goto fail;
33221
0
        }
33222
27.4k
    }
33223
33224
33.1k
    if (fd->has_parameter_expressions) {
33225
3.78k
        int idx;
33226
33227
        /* Copy the variables in the argument scope to the variable
33228
           scope (see FunctionDeclarationInstantiation() in spec). The
33229
           normal arguments are already present, so no need to copy
33230
           them. */
33231
3.78k
        idx = fd->scopes[fd->scope_level].first;
33232
17.5k
        while (idx >= 0) {
33233
13.7k
            JSVarDef *vd = &fd->vars[idx];
33234
13.7k
            if (vd->scope_level != fd->scope_level)
33235
0
                break;
33236
13.7k
            if (find_var(ctx, fd, vd->var_name) < 0) {
33237
4.60k
                if (add_var(ctx, fd, vd->var_name) < 0)
33238
0
                    goto fail;
33239
4.60k
                vd = &fd->vars[idx]; /* fd->vars may have been reallocated */
33240
4.60k
                emit_op(s, OP_scope_get_var);
33241
4.60k
                emit_atom(s, vd->var_name);
33242
4.60k
                emit_u16(s, fd->scope_level);
33243
4.60k
                emit_op(s, OP_scope_put_var);
33244
4.60k
                emit_atom(s, vd->var_name);
33245
4.60k
                emit_u16(s, 0);
33246
4.60k
            }
33247
13.7k
            idx = vd->scope_next;
33248
13.7k
        }
33249
        
33250
        /* the argument scope has no parent, hence we don't use pop_scope(s) */
33251
3.78k
        emit_op(s, OP_leave_scope);
33252
3.78k
        emit_u16(s, fd->scope_level);
33253
33254
        /* set the variable scope as the current scope */
33255
3.78k
        fd->scope_level = 0;
33256
3.78k
        fd->scope_first = fd->scopes[fd->scope_level].first;
33257
3.78k
    }
33258
    
33259
33.1k
    if (next_token(s))
33260
0
        goto fail;
33261
33262
    /* generator function: yield after the parameters are evaluated */
33263
33.1k
    if (func_kind == JS_FUNC_GENERATOR ||
33264
33.1k
        func_kind == JS_FUNC_ASYNC_GENERATOR)
33265
1.08k
        emit_op(s, OP_initial_yield);
33266
33267
    /* in generators, yield expression is forbidden during the parsing
33268
       of the arguments */
33269
33.1k
    fd->in_function_body = TRUE;
33270
33.1k
    push_scope(s);  /* enter body scope */
33271
33.1k
    fd->body_scope = fd->scope_level;
33272
33273
33.1k
    if (s->token.val == TOK_ARROW) {
33274
11.5k
        if (next_token(s))
33275
0
            goto fail;
33276
33277
11.5k
        if (s->token.val != '{') {
33278
11.1k
            if (js_parse_function_check_names(s, fd, func_name))
33279
0
                goto fail;
33280
33281
11.1k
            if (js_parse_assign_expr(s))
33282
122
                goto fail;
33283
33284
11.0k
            if (func_kind != JS_FUNC_NORMAL)
33285
642
                emit_op(s, OP_return_async);
33286
10.4k
            else
33287
10.4k
                emit_op(s, OP_return);
33288
33289
11.0k
            if (!(fd->js_mode & JS_MODE_STRIP)) {
33290
                /* save the function source code */
33291
                /* the end of the function source code is after the last
33292
                   token of the function source stored into s->last_ptr */
33293
9.69k
                fd->source_len = s->last_ptr - ptr;
33294
9.69k
                fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
33295
9.69k
                if (!fd->source)
33296
0
                    goto fail;
33297
9.69k
            }
33298
11.0k
            goto done;
33299
11.0k
        }
33300
11.5k
    }
33301
33302
21.9k
    if (js_parse_expect(s, '{'))
33303
1
        goto fail;
33304
33305
21.9k
    if (js_parse_directives(s))
33306
0
        goto fail;
33307
33308
    /* in strict_mode, check function and argument names */
33309
21.9k
    if (js_parse_function_check_names(s, fd, func_name))
33310
0
        goto fail;
33311
33312
62.7k
    while (s->token.val != '}') {
33313
41.4k
        if (js_parse_source_element(s))
33314
638
            goto fail;
33315
41.4k
    }
33316
21.3k
    if (!(fd->js_mode & JS_MODE_STRIP)) {
33317
        /* save the function source code */
33318
20.3k
        fd->source_len = s->buf_ptr - ptr;
33319
20.3k
        fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
33320
20.3k
        if (!fd->source)
33321
0
            goto fail;
33322
20.3k
    }
33323
33324
21.3k
    if (next_token(s)) {
33325
        /* consume the '}' */
33326
0
        goto fail;
33327
0
    }
33328
33329
    /* in case there is no return, add one */
33330
21.3k
    if (js_is_live_code(s)) {
33331
21.3k
        emit_return(s, FALSE);
33332
21.3k
    }
33333
32.4k
done:
33334
32.4k
    s->cur_func = fd->parent;
33335
33336
    /* create the function object */
33337
32.4k
    {
33338
32.4k
        int idx;
33339
32.4k
        JSAtom func_name = fd->func_name;
33340
33341
        /* the real object will be set at the end of the compilation */
33342
32.4k
        idx = cpool_add(s, JS_NULL);
33343
32.4k
        fd->parent_cpool_idx = idx;
33344
33345
32.4k
        if (is_expr) {
33346
            /* for constructors, no code needs to be generated here */
33347
22.7k
            if (func_type != JS_PARSE_FUNC_CLASS_CONSTRUCTOR &&
33348
22.7k
                func_type != JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
33349
                /* OP_fclosure creates the function object from the bytecode
33350
                   and adds the scope information */
33351
11.5k
                emit_op(s, OP_fclosure);
33352
11.5k
                emit_u32(s, idx);
33353
11.5k
                if (func_name == JS_ATOM_NULL) {
33354
11.1k
                    emit_op(s, OP_set_name);
33355
11.1k
                    emit_u32(s, JS_ATOM_NULL);
33356
11.1k
                }
33357
11.5k
            }
33358
22.7k
        } else if (func_type == JS_PARSE_FUNC_VAR) {
33359
1.50k
            emit_op(s, OP_fclosure);
33360
1.50k
            emit_u32(s, idx);
33361
1.50k
            if (create_func_var) {
33362
678
                if (s->cur_func->is_global_var) {
33363
496
                    JSGlobalVar *hf;
33364
                    /* the global variable must be defined at the start of the
33365
                       function */
33366
496
                    hf = add_global_var(ctx, s->cur_func, func_name);
33367
496
                    if (!hf)
33368
0
                        goto fail;
33369
                    /* it is considered as defined at the top level
33370
                       (needed for annex B.3.3.4 and B.3.3.5
33371
                       checks) */
33372
496
                    hf->scope_level = 0; 
33373
496
                    hf->force_init = ((s->cur_func->js_mode & JS_MODE_STRICT) != 0);
33374
                    /* store directly into global var, bypass lexical scope */
33375
496
                    emit_op(s, OP_dup);
33376
496
                    emit_op(s, OP_scope_put_var);
33377
496
                    emit_atom(s, func_name);
33378
496
                    emit_u16(s, 0);
33379
496
                } else {
33380
                    /* do not call define_var to bypass lexical scope check */
33381
182
                    func_idx = find_var(ctx, s->cur_func, func_name);
33382
182
                    if (func_idx < 0) {
33383
46
                        func_idx = add_var(ctx, s->cur_func, func_name);
33384
46
                        if (func_idx < 0)
33385
0
                            goto fail;
33386
46
                    }
33387
                    /* store directly into local var, bypass lexical catch scope */
33388
182
                    emit_op(s, OP_dup);
33389
182
                    emit_op(s, OP_scope_put_var);
33390
182
                    emit_atom(s, func_name);
33391
182
                    emit_u16(s, 0);
33392
182
                }
33393
678
            }
33394
1.50k
            if (lexical_func_idx >= 0) {
33395
                /* lexical variable will be initialized upon entering scope */
33396
1.39k
                s->cur_func->vars[lexical_func_idx].func_pool_idx = idx;
33397
1.39k
                emit_op(s, OP_drop);
33398
1.39k
            } else {
33399
                /* store function object into its lexical name */
33400
                /* XXX: could use OP_put_loc directly */
33401
107
                emit_op(s, OP_scope_put_var_init);
33402
107
                emit_atom(s, func_name);
33403
107
                emit_u16(s, s->cur_func->scope_level);
33404
107
            }
33405
8.19k
        } else {
33406
8.19k
            if (!s->cur_func->is_global_var) {
33407
3.12k
                int var_idx = define_var(s, s->cur_func, func_name, JS_VAR_DEF_VAR);
33408
33409
3.12k
                if (var_idx < 0)
33410
0
                    goto fail;
33411
                /* the variable will be assigned at the top of the function */
33412
3.12k
                if (var_idx & ARGUMENT_VAR_OFFSET) {
33413
278
                    s->cur_func->args[var_idx - ARGUMENT_VAR_OFFSET].func_pool_idx = idx;
33414
2.85k
                } else {
33415
2.85k
                    s->cur_func->vars[var_idx].func_pool_idx = idx;
33416
2.85k
                }
33417
5.06k
            } else {
33418
5.06k
                JSAtom func_var_name;
33419
5.06k
                JSGlobalVar *hf;
33420
5.06k
                if (func_name == JS_ATOM_NULL)
33421
0
                    func_var_name = JS_ATOM__default_; /* export default */
33422
5.06k
                else
33423
5.06k
                    func_var_name = func_name;
33424
                /* the variable will be assigned at the top of the function */
33425
5.06k
                hf = add_global_var(ctx, s->cur_func, func_var_name);
33426
5.06k
                if (!hf)
33427
0
                    goto fail;
33428
5.06k
                hf->cpool_idx = idx;
33429
5.06k
                if (export_flag != JS_PARSE_EXPORT_NONE) {
33430
0
                    if (!add_export_entry(s, s->cur_func->module, func_var_name,
33431
0
                                          export_flag == JS_PARSE_EXPORT_NAMED ? func_var_name : JS_ATOM_default, JS_EXPORT_TYPE_LOCAL))
33432
0
                        goto fail;
33433
0
                }
33434
5.06k
            }
33435
8.19k
        }
33436
32.4k
    }
33437
32.4k
    return 0;
33438
772
 fail:
33439
772
    s->cur_func = fd->parent;
33440
772
    js_free_function_def(ctx, fd);
33441
772
    if (pfd)
33442
6
        *pfd = NULL;
33443
772
    return -1;
33444
32.4k
}
33445
33446
static __exception int js_parse_function_decl(JSParseState *s,
33447
                                              JSParseFunctionEnum func_type,
33448
                                              JSFunctionKindEnum func_kind,
33449
                                              JSAtom func_name,
33450
                                              const uint8_t *ptr,
33451
                                              int function_line_num)
33452
20.5k
{
33453
20.5k
    return js_parse_function_decl2(s, func_type, func_kind, func_name, ptr,
33454
20.5k
                                   function_line_num, JS_PARSE_EXPORT_NONE,
33455
20.5k
                                   NULL);
33456
20.5k
}
33457
33458
static __exception int js_parse_program(JSParseState *s)
33459
1.60k
{
33460
1.60k
    JSFunctionDef *fd = s->cur_func;
33461
1.60k
    int idx;
33462
33463
1.60k
    if (next_token(s))
33464
1
        return -1;
33465
33466
1.60k
    if (js_parse_directives(s))
33467
0
        return -1;
33468
33469
1.60k
    fd->is_global_var = (fd->eval_type == JS_EVAL_TYPE_GLOBAL) ||
33470
1.60k
        (fd->eval_type == JS_EVAL_TYPE_MODULE) ||
33471
1.60k
        !(fd->js_mode & JS_MODE_STRICT);
33472
33473
1.60k
    if (!s->is_module) {
33474
        /* hidden variable for the return value */
33475
1.42k
        fd->eval_ret_idx = idx = add_var(s->ctx, fd, JS_ATOM__ret_);
33476
1.42k
        if (idx < 0)
33477
0
            return -1;
33478
1.42k
    }
33479
33480
71.6k
    while (s->token.val != TOK_EOF) {
33481
70.3k
        if (js_parse_source_element(s))
33482
363
            return -1;
33483
70.3k
    }
33484
33485
1.24k
    if (!s->is_module) {
33486
        /* return the value of the hidden variable eval_ret_idx  */
33487
1.11k
        emit_op(s, OP_get_loc);
33488
1.11k
        emit_u16(s, fd->eval_ret_idx);
33489
33490
1.11k
        emit_op(s, OP_return);
33491
1.11k
    } else {
33492
123
        emit_op(s, OP_return_undef);
33493
123
    }
33494
33495
1.24k
    return 0;
33496
1.60k
}
33497
33498
static void js_parse_init(JSContext *ctx, JSParseState *s,
33499
                          const char *input, size_t input_len,
33500
                          const char *filename)
33501
2.72k
{
33502
2.72k
    memset(s, 0, sizeof(*s));
33503
2.72k
    s->ctx = ctx;
33504
2.72k
    s->filename = filename;
33505
2.72k
    s->line_num = 1;
33506
2.72k
    s->buf_ptr = (const uint8_t *)input;
33507
2.72k
    s->buf_end = s->buf_ptr + input_len;
33508
2.72k
    s->token.val = ' ';
33509
2.72k
    s->token.line_num = 1;
33510
2.72k
}
33511
33512
static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,
33513
                                       JSValueConst this_obj,
33514
                                       JSVarRef **var_refs, JSStackFrame *sf)
33515
1.23k
{
33516
1.23k
    JSValue ret_val;
33517
1.23k
    uint32_t tag;
33518
33519
1.23k
    tag = JS_VALUE_GET_TAG(fun_obj);
33520
1.23k
    if (tag == JS_TAG_FUNCTION_BYTECODE) {
33521
1.11k
        fun_obj = js_closure(ctx, fun_obj, var_refs, sf);
33522
1.11k
        ret_val = JS_CallFree(ctx, fun_obj, this_obj, 0, NULL);
33523
1.11k
    } else if (tag == JS_TAG_MODULE) {
33524
120
        JSModuleDef *m;
33525
120
        m = JS_VALUE_GET_PTR(fun_obj);
33526
        /* the module refcount should be >= 2 */
33527
120
        JS_FreeValue(ctx, fun_obj);
33528
120
        if (js_create_module_function(ctx, m) < 0)
33529
1
            goto fail;
33530
119
        if (js_link_module(ctx, m) < 0)
33531
0
            goto fail;
33532
119
        ret_val = js_evaluate_module(ctx, m);
33533
119
        if (JS_IsException(ret_val)) {
33534
52
        fail:
33535
52
            js_free_modules(ctx, JS_FREE_MODULE_NOT_EVALUATED);
33536
52
            return JS_EXCEPTION;
33537
51
        }
33538
119
    } else {
33539
0
        JS_FreeValue(ctx, fun_obj);
33540
0
        ret_val = JS_ThrowTypeError(ctx, "bytecode function expected");
33541
0
    }
33542
1.18k
    return ret_val;
33543
1.23k
}
33544
33545
JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj)
33546
120
{
33547
120
    return JS_EvalFunctionInternal(ctx, fun_obj, ctx->global_obj, NULL, NULL);
33548
120
}
33549
33550
static void skip_shebang(JSParseState *s)
33551
2.72k
{
33552
2.72k
    const uint8_t *p = s->buf_ptr;
33553
2.72k
    int c;
33554
33555
2.72k
    if (p[0] == '#' && p[1] == '!') {
33556
23
        p += 2;
33557
1.57k
        while (p < s->buf_end) {
33558
1.57k
            if (*p == '\n' || *p == '\r') {
33559
23
                break;
33560
1.55k
            } else if (*p >= 0x80) {
33561
427
                c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
33562
427
                if (c == CP_LS || c == CP_PS) {
33563
0
                    break;
33564
427
                } else if (c == -1) {
33565
406
                    p++; /* skip invalid UTF-8 */
33566
406
                }
33567
1.12k
            } else {
33568
1.12k
                p++;
33569
1.12k
            }
33570
1.57k
        }
33571
23
        s->buf_ptr = p;
33572
23
    }
33573
2.72k
}
33574
33575
/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
33576
static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
33577
                                 const char *input, size_t input_len,
33578
                                 const char *filename, int flags, int scope_idx)
33579
2.72k
{
33580
2.72k
    JSParseState s1, *s = &s1;
33581
2.72k
    int err, js_mode, eval_type;
33582
2.72k
    JSValue fun_obj, ret_val;
33583
2.72k
    JSStackFrame *sf;
33584
2.72k
    JSVarRef **var_refs;
33585
2.72k
    JSFunctionBytecode *b;
33586
2.72k
    JSFunctionDef *fd;
33587
2.72k
    JSModuleDef *m;
33588
33589
2.72k
    js_parse_init(ctx, s, input, input_len, filename);
33590
2.72k
    skip_shebang(s);
33591
33592
2.72k
    eval_type = flags & JS_EVAL_TYPE_MASK;
33593
2.72k
    m = NULL;
33594
2.72k
    if (eval_type == JS_EVAL_TYPE_DIRECT) {
33595
534
        JSObject *p;
33596
534
        sf = ctx->rt->current_stack_frame;
33597
534
        assert(sf != NULL);
33598
534
        assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT);
33599
534
        p = JS_VALUE_GET_OBJ(sf->cur_func);
33600
534
        assert(js_class_has_bytecode(p->class_id));
33601
534
        b = p->u.func.function_bytecode;
33602
534
        var_refs = p->u.func.var_refs;
33603
534
        js_mode = b->js_mode;
33604
2.18k
    } else {
33605
2.18k
        sf = NULL;
33606
2.18k
        b = NULL;
33607
2.18k
        var_refs = NULL;
33608
2.18k
        js_mode = 0;
33609
2.18k
        if (flags & JS_EVAL_FLAG_STRICT)
33610
0
            js_mode |= JS_MODE_STRICT;
33611
2.18k
        if (flags & JS_EVAL_FLAG_STRIP)
33612
0
            js_mode |= JS_MODE_STRIP;
33613
2.18k
        if (eval_type == JS_EVAL_TYPE_MODULE) {
33614
1.29k
            JSAtom module_name = JS_NewAtom(ctx, filename);
33615
1.29k
            if (module_name == JS_ATOM_NULL)
33616
0
                return JS_EXCEPTION;
33617
1.29k
            m = js_new_module_def(ctx, module_name);
33618
1.29k
            if (!m)
33619
0
                return JS_EXCEPTION;
33620
1.29k
            js_mode |= JS_MODE_STRICT;
33621
1.29k
        }
33622
2.18k
    }
33623
2.72k
    fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename, 1);
33624
2.72k
    if (!fd)
33625
1.11k
        goto fail1;
33626
1.60k
    s->cur_func = fd;
33627
1.60k
    fd->eval_type = eval_type;
33628
1.60k
    fd->has_this_binding = (eval_type != JS_EVAL_TYPE_DIRECT);
33629
1.60k
    fd->backtrace_barrier = ((flags & JS_EVAL_FLAG_BACKTRACE_BARRIER) != 0);
33630
1.60k
    if (eval_type == JS_EVAL_TYPE_DIRECT) {
33631
534
        fd->new_target_allowed = b->new_target_allowed;
33632
534
        fd->super_call_allowed = b->super_call_allowed;
33633
534
        fd->super_allowed = b->super_allowed;
33634
534
        fd->arguments_allowed = b->arguments_allowed;
33635
1.07k
    } else {
33636
1.07k
        fd->new_target_allowed = FALSE;
33637
1.07k
        fd->super_call_allowed = FALSE;
33638
1.07k
        fd->super_allowed = FALSE;
33639
1.07k
        fd->arguments_allowed = TRUE;
33640
1.07k
    }
33641
1.60k
    fd->js_mode = js_mode;
33642
1.60k
    fd->func_name = JS_DupAtom(ctx, JS_ATOM__eval_);
33643
1.60k
    if (b) {
33644
534
        if (add_closure_variables(ctx, fd, b, scope_idx))
33645
0
            goto fail;
33646
534
    }
33647
1.60k
    fd->module = m;
33648
1.60k
    s->is_module = (m != NULL);
33649
1.60k
    s->allow_html_comments = !s->is_module;
33650
33651
1.60k
    push_scope(s); /* body scope */
33652
1.60k
    fd->body_scope = fd->scope_level;
33653
    
33654
1.60k
    err = js_parse_program(s);
33655
1.60k
    if (err) {
33656
364
    fail:
33657
364
        free_token(s, &s->token);
33658
364
        js_free_function_def(ctx, fd);
33659
364
        goto fail1;
33660
364
    }
33661
33662
    /* create the function object and all the enclosed functions */
33663
1.24k
    fun_obj = js_create_function(ctx, fd);
33664
1.24k
    if (JS_IsException(fun_obj))
33665
8
        goto fail1;
33666
    /* Could add a flag to avoid resolution if necessary */
33667
1.23k
    if (m) {
33668
122
        m->func_obj = fun_obj;
33669
122
        if (js_resolve_module(ctx, m) < 0)
33670
0
            goto fail1;
33671
122
        fun_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
33672
122
    }
33673
1.23k
    if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {
33674
122
        ret_val = fun_obj;
33675
1.11k
    } else {
33676
1.11k
        ret_val = JS_EvalFunctionInternal(ctx, fun_obj, this_obj, var_refs, sf);
33677
1.11k
    }
33678
1.23k
    return ret_val;
33679
1.48k
 fail1:
33680
    /* XXX: should free all the unresolved dependencies */
33681
1.48k
    if (m)
33682
1.17k
        js_free_module_def(ctx, m);
33683
1.48k
    return JS_EXCEPTION;
33684
1.23k
}
33685
33686
/* the indirection is needed to make 'eval' optional */
33687
static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
33688
                               const char *input, size_t input_len,
33689
                               const char *filename, int flags, int scope_idx)
33690
2.72k
{
33691
2.72k
    if (unlikely(!ctx->eval_internal)) {
33692
0
        return JS_ThrowTypeError(ctx, "eval is not supported");
33693
0
    }
33694
2.72k
    return ctx->eval_internal(ctx, this_obj, input, input_len, filename,
33695
2.72k
                              flags, scope_idx);
33696
2.72k
}
33697
33698
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
33699
                             JSValueConst val, int flags, int scope_idx)
33700
557
{
33701
557
    JSValue ret;
33702
557
    const char *str;
33703
557
    size_t len;
33704
33705
557
    if (!JS_IsString(val))
33706
8
        return JS_DupValue(ctx, val);
33707
549
    str = JS_ToCStringLen(ctx, &len, val);
33708
549
    if (!str)
33709
0
        return JS_EXCEPTION;
33710
549
    ret = JS_EvalInternal(ctx, this_obj, str, len, "<input>", flags, scope_idx);
33711
549
    JS_FreeCString(ctx, str);
33712
549
    return ret;
33713
33714
549
}
33715
33716
JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
33717
                    const char *input, size_t input_len,
33718
                    const char *filename, int eval_flags)
33719
2.17k
{
33720
2.17k
    int eval_type = eval_flags & JS_EVAL_TYPE_MASK;
33721
2.17k
    JSValue ret;
33722
33723
2.17k
    assert(eval_type == JS_EVAL_TYPE_GLOBAL ||
33724
2.17k
           eval_type == JS_EVAL_TYPE_MODULE);
33725
2.17k
    ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename,
33726
2.17k
                          eval_flags, -1);
33727
2.17k
    return ret;
33728
2.17k
}
33729
33730
JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
33731
                const char *filename, int eval_flags)
33732
2.17k
{
33733
2.17k
    return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename,
33734
2.17k
                       eval_flags);
33735
2.17k
}
33736
33737
int JS_ResolveModule(JSContext *ctx, JSValueConst obj)
33738
120
{
33739
120
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
33740
120
        JSModuleDef *m = JS_VALUE_GET_PTR(obj);
33741
120
        if (js_resolve_module(ctx, m) < 0) {
33742
0
            js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
33743
0
            return -1;
33744
0
        }
33745
120
    }
33746
120
    return 0;
33747
120
}
33748
33749
/*******************************************************************/
33750
/* object list */
33751
33752
typedef struct {
33753
    JSObject *obj;
33754
    uint32_t hash_next; /* -1 if no next entry */
33755
} JSObjectListEntry;
33756
33757
/* XXX: reuse it to optimize weak references */
33758
typedef struct {
33759
    JSObjectListEntry *object_tab;
33760
    int object_count;
33761
    int object_size;
33762
    uint32_t *hash_table;
33763
    uint32_t hash_size;
33764
} JSObjectList;
33765
33766
static void js_object_list_init(JSObjectList *s)
33767
122
{
33768
122
    memset(s, 0, sizeof(*s));
33769
122
}
33770
33771
static uint32_t js_object_list_get_hash(JSObject *p, uint32_t hash_size)
33772
0
{
33773
0
    return ((uintptr_t)p * 3163) & (hash_size - 1);
33774
0
}
33775
33776
static int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s,
33777
                                 uint32_t new_hash_size)
33778
0
{
33779
0
    JSObjectListEntry *e;
33780
0
    uint32_t i, h, *new_hash_table;
33781
33782
0
    new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size);
33783
0
    if (!new_hash_table)
33784
0
        return -1;
33785
0
    js_free(ctx, s->hash_table);
33786
0
    s->hash_table = new_hash_table;
33787
0
    s->hash_size = new_hash_size;
33788
    
33789
0
    for(i = 0; i < s->hash_size; i++) {
33790
0
        s->hash_table[i] = -1;
33791
0
    }
33792
0
    for(i = 0; i < s->object_count; i++) {
33793
0
        e = &s->object_tab[i];
33794
0
        h = js_object_list_get_hash(e->obj, s->hash_size); 
33795
0
        e->hash_next = s->hash_table[h];
33796
0
        s->hash_table[h] = i;
33797
0
    }
33798
0
    return 0;
33799
0
}
33800
33801
/* the reference count of 'obj' is not modified. Return 0 if OK, -1 if
33802
   memory error */
33803
static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj)
33804
0
{
33805
0
    JSObjectListEntry *e;
33806
0
    uint32_t h, new_hash_size;
33807
    
33808
0
    if (js_resize_array(ctx, (void *)&s->object_tab,
33809
0
                        sizeof(s->object_tab[0]),
33810
0
                        &s->object_size, s->object_count + 1))
33811
0
        return -1;
33812
0
    if (unlikely((s->object_count + 1) >= s->hash_size)) {
33813
0
        new_hash_size = max_uint32(s->hash_size, 4);
33814
0
        while (new_hash_size <= s->object_count)
33815
0
            new_hash_size *= 2;
33816
0
        if (js_object_list_resize_hash(ctx, s, new_hash_size))
33817
0
            return -1;
33818
0
    }
33819
0
    e = &s->object_tab[s->object_count++];
33820
0
    h = js_object_list_get_hash(obj, s->hash_size); 
33821
0
    e->obj = obj;
33822
0
    e->hash_next = s->hash_table[h];
33823
0
    s->hash_table[h] = s->object_count - 1;
33824
0
    return 0;
33825
0
}
33826
33827
/* return -1 if not present or the object index */
33828
static int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj)
33829
0
{
33830
0
    JSObjectListEntry *e;
33831
0
    uint32_t h, p;
33832
33833
    /* must test empty size because there is no hash table */
33834
0
    if (s->object_count == 0)
33835
0
        return -1;
33836
0
    h = js_object_list_get_hash(obj, s->hash_size); 
33837
0
    p = s->hash_table[h];
33838
0
    while (p != -1) {
33839
0
        e = &s->object_tab[p];
33840
0
        if (e->obj == obj)
33841
0
            return p;
33842
0
        p = e->hash_next;
33843
0
    }
33844
0
    return -1;
33845
0
}
33846
33847
static void js_object_list_end(JSContext *ctx, JSObjectList *s)
33848
122
{
33849
122
    js_free(ctx, s->object_tab);
33850
122
    js_free(ctx, s->hash_table);
33851
122
}
33852
33853
/*******************************************************************/
33854
/* binary object writer & reader */
33855
33856
typedef enum BCTagEnum {
33857
    BC_TAG_NULL = 1,
33858
    BC_TAG_UNDEFINED,
33859
    BC_TAG_BOOL_FALSE,
33860
    BC_TAG_BOOL_TRUE,
33861
    BC_TAG_INT32,
33862
    BC_TAG_FLOAT64,
33863
    BC_TAG_STRING,
33864
    BC_TAG_OBJECT,
33865
    BC_TAG_ARRAY,
33866
    BC_TAG_BIG_INT,
33867
    BC_TAG_BIG_FLOAT,
33868
    BC_TAG_BIG_DECIMAL,
33869
    BC_TAG_TEMPLATE_OBJECT,
33870
    BC_TAG_FUNCTION_BYTECODE,
33871
    BC_TAG_MODULE,
33872
    BC_TAG_TYPED_ARRAY,
33873
    BC_TAG_ARRAY_BUFFER,
33874
    BC_TAG_SHARED_ARRAY_BUFFER,
33875
    BC_TAG_DATE,
33876
    BC_TAG_OBJECT_VALUE,
33877
    BC_TAG_OBJECT_REFERENCE,
33878
} BCTagEnum;
33879
33880
#ifdef CONFIG_BIGNUM
33881
243
#define BC_BASE_VERSION 2
33882
#else
33883
#define BC_BASE_VERSION 1
33884
#endif
33885
0
#define BC_BE_VERSION 0x40
33886
#ifdef WORDS_BIGENDIAN
33887
#define BC_VERSION (BC_BASE_VERSION | BC_BE_VERSION)
33888
#else
33889
243
#define BC_VERSION BC_BASE_VERSION
33890
#endif
33891
33892
typedef struct BCWriterState {
33893
    JSContext *ctx;
33894
    DynBuf dbuf;
33895
    BOOL byte_swap : 8;
33896
    BOOL allow_bytecode : 8;
33897
    BOOL allow_sab : 8;
33898
    BOOL allow_reference : 8;
33899
    uint32_t first_atom;
33900
    uint32_t *atom_to_idx;
33901
    int atom_to_idx_size;
33902
    JSAtom *idx_to_atom;
33903
    int idx_to_atom_count;
33904
    int idx_to_atom_size;
33905
    uint8_t **sab_tab;
33906
    int sab_tab_len;
33907
    int sab_tab_size;
33908
    /* list of referenced objects (used if allow_reference = TRUE) */
33909
    JSObjectList object_list;
33910
} BCWriterState;
33911
33912
#ifdef DUMP_READ_OBJECT
33913
static const char * const bc_tag_str[] = {
33914
    "invalid",
33915
    "null",
33916
    "undefined",
33917
    "false",
33918
    "true",
33919
    "int32",
33920
    "float64",
33921
    "string",
33922
    "object",
33923
    "array",
33924
    "bigint",
33925
    "bigfloat",
33926
    "bigdecimal",
33927
    "template",
33928
    "function",
33929
    "module",
33930
    "TypedArray",
33931
    "ArrayBuffer",
33932
    "SharedArrayBuffer",
33933
    "Date",
33934
    "ObjectValue",
33935
    "ObjectReference",
33936
};
33937
#endif
33938
33939
static void bc_put_u8(BCWriterState *s, uint8_t v)
33940
6.40k
{
33941
6.40k
    dbuf_putc(&s->dbuf, v);
33942
6.40k
}
33943
33944
static void bc_put_u16(BCWriterState *s, uint16_t v)
33945
15.2k
{
33946
15.2k
    if (s->byte_swap)
33947
0
        v = bswap16(v);
33948
15.2k
    dbuf_put_u16(&s->dbuf, v);
33949
15.2k
}
33950
33951
static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
33952
0
{
33953
0
    if (s->byte_swap)
33954
0
        v = bswap32(v);
33955
0
    dbuf_put_u32(&s->dbuf, v);
33956
0
}
33957
33958
static void bc_put_u64(BCWriterState *s, uint64_t v)
33959
87
{
33960
87
    if (s->byte_swap)
33961
0
        v = bswap64(v);
33962
87
    dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v));
33963
87
}
33964
33965
static void bc_put_leb128(BCWriterState *s, uint32_t v)
33966
14.4k
{
33967
14.4k
    dbuf_put_leb128(&s->dbuf, v);
33968
14.4k
}
33969
33970
static void bc_put_sleb128(BCWriterState *s, int32_t v)
33971
257
{
33972
257
    dbuf_put_sleb128(&s->dbuf, v);
33973
257
}
33974
33975
static void bc_set_flags(uint32_t *pflags, int *pidx, uint32_t val, int n)
33976
13.1k
{
33977
13.1k
    *pflags = *pflags | (val << *pidx);
33978
13.1k
    *pidx += n;
33979
13.1k
}
33980
33981
static int bc_atom_to_idx(BCWriterState *s, uint32_t *pres, JSAtom atom)
33982
5.68k
{
33983
5.68k
    uint32_t v;
33984
33985
5.68k
    if (atom < s->first_atom || __JS_AtomIsTaggedInt(atom)) {
33986
1.85k
        *pres = atom;
33987
1.85k
        return 0;
33988
1.85k
    }
33989
3.83k
    atom -= s->first_atom;
33990
3.83k
    if (atom < s->atom_to_idx_size && s->atom_to_idx[atom] != 0) {
33991
3.22k
        *pres = s->atom_to_idx[atom];
33992
3.22k
        return 0;
33993
3.22k
    }
33994
616
    if (atom >= s->atom_to_idx_size) {
33995
219
        int old_size, i;
33996
219
        old_size = s->atom_to_idx_size;
33997
219
        if (js_resize_array(s->ctx, (void **)&s->atom_to_idx,
33998
219
                            sizeof(s->atom_to_idx[0]), &s->atom_to_idx_size,
33999
219
                            atom + 1))
34000
2
            return -1;
34001
        /* XXX: could add a specific js_resize_array() function to do it */
34002
44.5k
        for(i = old_size; i < s->atom_to_idx_size; i++)
34003
44.3k
            s->atom_to_idx[i] = 0;
34004
217
    }
34005
614
    if (js_resize_array(s->ctx, (void **)&s->idx_to_atom,
34006
614
                        sizeof(s->idx_to_atom[0]),
34007
614
                        &s->idx_to_atom_size, s->idx_to_atom_count + 1))
34008
0
        goto fail;
34009
34010
614
    v = s->idx_to_atom_count++;
34011
614
    s->idx_to_atom[v] = atom + s->first_atom;
34012
614
    v += s->first_atom;
34013
614
    s->atom_to_idx[atom] = v;
34014
614
    *pres = v;
34015
614
    return 0;
34016
0
 fail:
34017
0
    *pres = 0;
34018
0
    return -1;
34019
614
}
34020
34021
static int bc_put_atom(BCWriterState *s, JSAtom atom)
34022
2.75k
{
34023
2.75k
    uint32_t v;
34024
34025
2.75k
    if (__JS_AtomIsTaggedInt(atom)) {
34026
0
        v = (__JS_AtomToUInt32(atom) << 1) | 1;
34027
2.75k
    } else {
34028
2.75k
        if (bc_atom_to_idx(s, &v, atom))
34029
2
            return -1;
34030
2.75k
        v <<= 1;
34031
2.75k
    }
34032
2.75k
    bc_put_leb128(s, v);
34033
2.75k
    return 0;
34034
2.75k
}
34035
34036
static void bc_byte_swap(uint8_t *bc_buf, int bc_len)
34037
0
{
34038
0
    int pos, len, op, fmt;
34039
34040
0
    pos = 0;
34041
0
    while (pos < bc_len) {
34042
0
        op = bc_buf[pos];
34043
0
        len = short_opcode_info(op).size;
34044
0
        fmt = short_opcode_info(op).fmt;
34045
0
        switch(fmt) {
34046
0
        case OP_FMT_u16:
34047
0
        case OP_FMT_i16:
34048
0
        case OP_FMT_label16:
34049
0
        case OP_FMT_npop:
34050
0
        case OP_FMT_loc:
34051
0
        case OP_FMT_arg:
34052
0
        case OP_FMT_var_ref:
34053
0
            put_u16(bc_buf + pos + 1,
34054
0
                    bswap16(get_u16(bc_buf + pos + 1)));
34055
0
            break;
34056
0
        case OP_FMT_i32:
34057
0
        case OP_FMT_u32:
34058
0
        case OP_FMT_const:
34059
0
        case OP_FMT_label:
34060
0
        case OP_FMT_atom:
34061
0
        case OP_FMT_atom_u8:
34062
0
            put_u32(bc_buf + pos + 1,
34063
0
                    bswap32(get_u32(bc_buf + pos + 1)));
34064
0
            break;
34065
0
        case OP_FMT_atom_u16:
34066
0
        case OP_FMT_label_u16:
34067
0
            put_u32(bc_buf + pos + 1,
34068
0
                    bswap32(get_u32(bc_buf + pos + 1)));
34069
0
            put_u16(bc_buf + pos + 1 + 4,
34070
0
                    bswap16(get_u16(bc_buf + pos + 1 + 4)));
34071
0
            break;
34072
0
        case OP_FMT_atom_label_u8:
34073
0
        case OP_FMT_atom_label_u16:
34074
0
            put_u32(bc_buf + pos + 1,
34075
0
                    bswap32(get_u32(bc_buf + pos + 1)));
34076
0
            put_u32(bc_buf + pos + 1 + 4,
34077
0
                    bswap32(get_u32(bc_buf + pos + 1 + 4)));
34078
0
            if (fmt == OP_FMT_atom_label_u16) {
34079
0
                put_u16(bc_buf + pos + 1 + 4 + 4,
34080
0
                        bswap16(get_u16(bc_buf + pos + 1 + 4 + 4)));
34081
0
            }
34082
0
            break;
34083
0
        case OP_FMT_npop_u16:
34084
0
            put_u16(bc_buf + pos + 1,
34085
0
                    bswap16(get_u16(bc_buf + pos + 1)));
34086
0
            put_u16(bc_buf + pos + 1 + 2,
34087
0
                    bswap16(get_u16(bc_buf + pos + 1 + 2)));
34088
0
            break;
34089
0
        default:
34090
0
            break;
34091
0
        }
34092
0
        pos += len;
34093
0
    }
34094
0
}
34095
34096
static int JS_WriteFunctionBytecode(BCWriterState *s,
34097
                                    const uint8_t *bc_buf1, int bc_len)
34098
542
{
34099
542
    int pos, len, op;
34100
542
    JSAtom atom;
34101
542
    uint8_t *bc_buf;
34102
542
    uint32_t val;
34103
34104
542
    bc_buf = js_malloc(s->ctx, bc_len);
34105
542
    if (!bc_buf)
34106
0
        return -1;
34107
542
    memcpy(bc_buf, bc_buf1, bc_len);
34108
34109
542
    pos = 0;
34110
15.7k
    while (pos < bc_len) {
34111
15.1k
        op = bc_buf[pos];
34112
15.1k
        len = short_opcode_info(op).size;
34113
15.1k
        switch(short_opcode_info(op).fmt) {
34114
2.69k
        case OP_FMT_atom:
34115
2.80k
        case OP_FMT_atom_u8:
34116
2.93k
        case OP_FMT_atom_u16:
34117
2.93k
        case OP_FMT_atom_label_u8:
34118
2.93k
        case OP_FMT_atom_label_u16:
34119
2.93k
            atom = get_u32(bc_buf + pos + 1);
34120
2.93k
            if (bc_atom_to_idx(s, &val, atom))
34121
0
                goto fail;
34122
2.93k
            put_u32(bc_buf + pos + 1, val);
34123
2.93k
            break;
34124
12.2k
        default:
34125
12.2k
            break;
34126
15.1k
        }
34127
15.1k
        pos += len;
34128
15.1k
    }
34129
34130
542
    if (s->byte_swap)
34131
0
        bc_byte_swap(bc_buf, bc_len);
34132
34133
542
    dbuf_put(&s->dbuf, bc_buf, bc_len);
34134
34135
542
    js_free(s->ctx, bc_buf);
34136
542
    return 0;
34137
0
 fail:
34138
0
    js_free(s->ctx, bc_buf);
34139
0
    return -1;
34140
542
}
34141
34142
static void JS_WriteString(BCWriterState *s, JSString *p)
34143
1.98k
{
34144
1.98k
    int i;
34145
1.98k
    bc_put_leb128(s, ((uint32_t)p->len << 1) | p->is_wide_char);
34146
1.98k
    if (p->is_wide_char) {
34147
14.8k
        for(i = 0; i < p->len; i++)
34148
14.7k
            bc_put_u16(s, p->u.str16[i]);
34149
1.88k
    } else {
34150
1.88k
        dbuf_put(&s->dbuf, p->u.str8, p->len);
34151
1.88k
    }
34152
1.98k
}
34153
34154
#ifdef CONFIG_BIGNUM
34155
static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj)
34156
257
{
34157
257
    uint32_t tag, tag1;
34158
257
    int64_t e;
34159
257
    JSBigFloat *bf = JS_VALUE_GET_PTR(obj);
34160
257
    bf_t *a = &bf->num;
34161
257
    size_t len, i, n1, j;
34162
257
    limb_t v;
34163
34164
257
    tag = JS_VALUE_GET_TAG(obj);
34165
257
    switch(tag) {
34166
257
    case JS_TAG_BIG_INT:
34167
257
        tag1 = BC_TAG_BIG_INT;
34168
257
        break;
34169
0
    case JS_TAG_BIG_FLOAT:
34170
0
        tag1 = BC_TAG_BIG_FLOAT;
34171
0
        break;
34172
0
    case JS_TAG_BIG_DECIMAL:
34173
0
        tag1 = BC_TAG_BIG_DECIMAL;
34174
0
        break;
34175
0
    default:
34176
0
        abort();
34177
257
    }
34178
257
    bc_put_u8(s, tag1);
34179
34180
    /* sign + exponent */
34181
257
    if (a->expn == BF_EXP_ZERO)
34182
0
        e = 0;
34183
257
    else if (a->expn == BF_EXP_INF)
34184
0
        e = 1;
34185
257
    else if (a->expn == BF_EXP_NAN)
34186
0
        e = 2;
34187
257
    else if (a->expn >= 0)
34188
257
        e = a->expn + 3;
34189
0
    else
34190
0
        e = a->expn;
34191
257
    e = (e << 1) | a->sign;
34192
257
    if (e < INT32_MIN || e > INT32_MAX) {
34193
0
        JS_ThrowInternalError(s->ctx, "bignum exponent is too large");
34194
0
        return -1;
34195
0
    }
34196
257
    bc_put_sleb128(s, e);
34197
34198
    /* mantissa */
34199
257
    if (a->len != 0) {
34200
257
        if (tag != JS_TAG_BIG_DECIMAL) {
34201
257
            i = 0;
34202
257
            while (i < a->len && a->tab[i] == 0)
34203
0
                i++;
34204
257
            assert(i < a->len);
34205
257
            v = a->tab[i];
34206
257
            n1 = sizeof(limb_t);
34207
1.69k
            while ((v & 0xff) == 0) {
34208
1.44k
                n1--;
34209
1.44k
                v >>= 8;
34210
1.44k
            }
34211
257
            i++;
34212
257
            len = (a->len - i) * sizeof(limb_t) + n1;
34213
257
            if (len > INT32_MAX) {
34214
0
                JS_ThrowInternalError(s->ctx, "bignum is too large");
34215
0
                return -1;
34216
0
            }
34217
257
            bc_put_leb128(s, len);
34218
            /* always saved in byte based little endian representation */
34219
872
            for(j = 0; j < n1; j++) {
34220
615
                dbuf_putc(&s->dbuf, v >> (j * 8));
34221
615
            }
34222
539
            for(; i < a->len; i++) {
34223
282
                limb_t v = a->tab[i];
34224
#if LIMB_BITS == 32
34225
#ifdef WORDS_BIGENDIAN
34226
                v = bswap32(v);
34227
#endif
34228
                dbuf_put_u32(&s->dbuf, v);
34229
#else
34230
#ifdef WORDS_BIGENDIAN
34231
                v = bswap64(v);
34232
#endif
34233
282
                dbuf_put_u64(&s->dbuf, v);
34234
282
#endif
34235
282
            }
34236
257
        } else {
34237
0
            int bpos, d;
34238
0
            uint8_t v8;
34239
0
            size_t i0;
34240
            
34241
            /* little endian BCD */
34242
0
            i = 0;
34243
0
            while (i < a->len && a->tab[i] == 0)
34244
0
                i++;
34245
0
            assert(i < a->len);
34246
0
            len = a->len * LIMB_DIGITS;
34247
0
            v = a->tab[i];
34248
0
            j = 0;
34249
0
            while ((v % 10) == 0) {
34250
0
                j++;
34251
0
                v /= 10;
34252
0
            }
34253
0
            len -= j;
34254
0
            assert(len > 0);
34255
0
            if (len > INT32_MAX) {
34256
0
                JS_ThrowInternalError(s->ctx, "bignum is too large");
34257
0
                return -1;
34258
0
            }
34259
0
            bc_put_leb128(s, len);
34260
            
34261
0
            bpos = 0;
34262
0
            v8 = 0;
34263
0
            i0 = i;
34264
0
            for(; i < a->len; i++) {
34265
0
                if (i != i0) {
34266
0
                    v = a->tab[i];
34267
0
                    j = 0;
34268
0
                }
34269
0
                for(; j < LIMB_DIGITS; j++) {
34270
0
                    d = v % 10;
34271
0
                    v /= 10;
34272
0
                    if (bpos == 0) {
34273
0
                        v8 = d;
34274
0
                        bpos = 1;
34275
0
                    } else {
34276
0
                        dbuf_putc(&s->dbuf, v8 | (d << 4));
34277
0
                        bpos = 0;
34278
0
                    }
34279
0
                }
34280
0
            }
34281
            /* flush the last digit */
34282
0
            if (bpos) {
34283
0
                dbuf_putc(&s->dbuf, v8);
34284
0
            }
34285
0
        }
34286
257
    }
34287
257
    return 0;
34288
257
}
34289
#endif /* CONFIG_BIGNUM */
34290
34291
static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj);
34292
34293
static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
34294
542
{
34295
542
    JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj);
34296
542
    uint32_t flags;
34297
542
    int idx, i;
34298
    
34299
542
    bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE);
34300
542
    flags = idx = 0;
34301
542
    bc_set_flags(&flags, &idx, b->has_prototype, 1);
34302
542
    bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1);
34303
542
    bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1);
34304
542
    bc_set_flags(&flags, &idx, b->need_home_object, 1);
34305
542
    bc_set_flags(&flags, &idx, b->func_kind, 2);
34306
542
    bc_set_flags(&flags, &idx, b->new_target_allowed, 1);
34307
542
    bc_set_flags(&flags, &idx, b->super_call_allowed, 1);
34308
542
    bc_set_flags(&flags, &idx, b->super_allowed, 1);
34309
542
    bc_set_flags(&flags, &idx, b->arguments_allowed, 1);
34310
542
    bc_set_flags(&flags, &idx, b->has_debug, 1);
34311
542
    bc_set_flags(&flags, &idx, b->backtrace_barrier, 1);
34312
542
    assert(idx <= 16);
34313
542
    bc_put_u16(s, flags);
34314
542
    bc_put_u8(s, b->js_mode);
34315
542
    bc_put_atom(s, b->func_name);
34316
    
34317
542
    bc_put_leb128(s, b->arg_count);
34318
542
    bc_put_leb128(s, b->var_count);
34319
542
    bc_put_leb128(s, b->defined_arg_count);
34320
542
    bc_put_leb128(s, b->stack_size);
34321
542
    bc_put_leb128(s, b->closure_var_count);
34322
542
    bc_put_leb128(s, b->cpool_count);
34323
542
    bc_put_leb128(s, b->byte_code_len);
34324
542
    if (b->vardefs) {
34325
        /* XXX: this field is redundant */
34326
414
        bc_put_leb128(s, b->arg_count + b->var_count);
34327
1.10k
        for(i = 0; i < b->arg_count + b->var_count; i++) {
34328
686
            JSVarDef *vd = &b->vardefs[i];
34329
686
            bc_put_atom(s, vd->var_name);
34330
686
            bc_put_leb128(s, vd->scope_level);
34331
686
            bc_put_leb128(s, vd->scope_next + 1);
34332
686
            flags = idx = 0;
34333
686
            bc_set_flags(&flags, &idx, vd->var_kind, 4);
34334
686
            bc_set_flags(&flags, &idx, vd->is_const, 1);
34335
686
            bc_set_flags(&flags, &idx, vd->is_lexical, 1);
34336
686
            bc_set_flags(&flags, &idx, vd->is_captured, 1);
34337
686
            assert(idx <= 8);
34338
686
            bc_put_u8(s, flags);
34339
686
        }
34340
414
    } else {
34341
128
        bc_put_leb128(s, 0);
34342
128
    }
34343
    
34344
1.42k
    for(i = 0; i < b->closure_var_count; i++) {
34345
884
        JSClosureVar *cv = &b->closure_var[i];
34346
884
        bc_put_atom(s, cv->var_name);
34347
884
        bc_put_leb128(s, cv->var_idx);
34348
884
        flags = idx = 0;
34349
884
        bc_set_flags(&flags, &idx, cv->is_local, 1);
34350
884
        bc_set_flags(&flags, &idx, cv->is_arg, 1);
34351
884
        bc_set_flags(&flags, &idx, cv->is_const, 1);
34352
884
        bc_set_flags(&flags, &idx, cv->is_lexical, 1);
34353
884
        bc_set_flags(&flags, &idx, cv->var_kind, 4);
34354
884
        assert(idx <= 8);
34355
884
        bc_put_u8(s, flags);
34356
884
    }
34357
    
34358
542
    if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len))
34359
0
        goto fail;
34360
    
34361
542
    if (b->has_debug) {
34362
518
        bc_put_atom(s, b->debug.filename);
34363
518
        bc_put_leb128(s, b->debug.line_num);
34364
518
        bc_put_leb128(s, b->debug.pc2line_len);
34365
518
        dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len);
34366
518
    }
34367
    
34368
2.05k
    for(i = 0; i < b->cpool_count; i++) {
34369
1.51k
        if (JS_WriteObjectRec(s, b->cpool[i]))
34370
0
            goto fail;
34371
1.51k
    }
34372
542
    return 0;
34373
0
 fail:
34374
0
    return -1;
34375
542
}
34376
34377
static int JS_WriteModule(BCWriterState *s, JSValueConst obj)
34378
122
{
34379
122
    JSModuleDef *m = JS_VALUE_GET_PTR(obj);
34380
122
    int i;
34381
    
34382
122
    bc_put_u8(s, BC_TAG_MODULE);
34383
122
    bc_put_atom(s, m->module_name);
34384
    
34385
122
    bc_put_leb128(s, m->req_module_entries_count);
34386
122
    for(i = 0; i < m->req_module_entries_count; i++) {
34387
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
34388
0
        bc_put_atom(s, rme->module_name);
34389
0
    }
34390
    
34391
122
    bc_put_leb128(s, m->export_entries_count);
34392
122
    for(i = 0; i < m->export_entries_count; i++) {
34393
0
        JSExportEntry *me = &m->export_entries[i];
34394
0
        bc_put_u8(s, me->export_type);
34395
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
34396
0
            bc_put_leb128(s, me->u.local.var_idx);
34397
0
        } else {
34398
0
            bc_put_leb128(s, me->u.req_module_idx);
34399
0
            bc_put_atom(s, me->local_name);
34400
0
        }
34401
0
        bc_put_atom(s, me->export_name);
34402
0
    }
34403
    
34404
122
    bc_put_leb128(s, m->star_export_entries_count);
34405
122
    for(i = 0; i < m->star_export_entries_count; i++) {
34406
0
        JSStarExportEntry *se = &m->star_export_entries[i];
34407
0
        bc_put_leb128(s, se->req_module_idx);
34408
0
    }
34409
    
34410
122
    bc_put_leb128(s, m->import_entries_count);
34411
122
    for(i = 0; i < m->import_entries_count; i++) {
34412
0
        JSImportEntry *mi = &m->import_entries[i];
34413
0
        bc_put_leb128(s, mi->var_idx);
34414
0
        bc_put_atom(s, mi->import_name);
34415
0
        bc_put_leb128(s, mi->req_module_idx);
34416
0
    }
34417
    
34418
122
    if (JS_WriteObjectRec(s, m->func_obj))
34419
0
        goto fail;
34420
122
    return 0;
34421
0
 fail:
34422
0
    return -1;
34423
122
}
34424
34425
static int JS_WriteArray(BCWriterState *s, JSValueConst obj)
34426
1.18k
{
34427
1.18k
    JSObject *p = JS_VALUE_GET_OBJ(obj);
34428
1.18k
    uint32_t i, len;
34429
1.18k
    JSValue val;
34430
1.18k
    int ret;
34431
1.18k
    BOOL is_template;
34432
    
34433
1.18k
    if (s->allow_bytecode && !p->extensible) {
34434
        /* not extensible array: we consider it is a
34435
           template when we are saving bytecode */
34436
1.18k
        bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT);
34437
1.18k
        is_template = TRUE;
34438
1.18k
    } else {
34439
0
        bc_put_u8(s, BC_TAG_ARRAY);
34440
0
        is_template = FALSE;
34441
0
    }
34442
1.18k
    if (js_get_length32(s->ctx, &len, obj))
34443
0
        goto fail1;
34444
1.18k
    bc_put_leb128(s, len);
34445
2.40k
    for(i = 0; i < len; i++) {
34446
1.22k
        val = JS_GetPropertyUint32(s->ctx, obj, i);
34447
1.22k
        if (JS_IsException(val))
34448
0
            goto fail1;
34449
1.22k
        ret = JS_WriteObjectRec(s, val);
34450
1.22k
        JS_FreeValue(s->ctx, val);
34451
1.22k
        if (ret)
34452
0
            goto fail1;
34453
1.22k
    }
34454
1.18k
    if (is_template) {
34455
1.18k
        val = JS_GetProperty(s->ctx, obj, JS_ATOM_raw);
34456
1.18k
        if (JS_IsException(val))
34457
0
            goto fail1;
34458
1.18k
        ret = JS_WriteObjectRec(s, val);
34459
1.18k
        JS_FreeValue(s->ctx, val);
34460
1.18k
        if (ret)
34461
0
            goto fail1;
34462
1.18k
    }
34463
1.18k
    return 0;
34464
0
 fail1:
34465
0
    return -1;
34466
1.18k
}
34467
34468
static int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj)
34469
0
{
34470
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
34471
0
    uint32_t i, prop_count;
34472
0
    JSShape *sh;
34473
0
    JSShapeProperty *pr;
34474
0
    int pass;
34475
0
    JSAtom atom;
34476
34477
0
    bc_put_u8(s, BC_TAG_OBJECT);
34478
0
    prop_count = 0;
34479
0
    sh = p->shape;
34480
0
    for(pass = 0; pass < 2; pass++) {
34481
0
        if (pass == 1)
34482
0
            bc_put_leb128(s, prop_count);
34483
0
        for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
34484
0
            atom = pr->atom;
34485
0
            if (atom != JS_ATOM_NULL &&
34486
0
                JS_AtomIsString(s->ctx, atom) &&
34487
0
                (pr->flags & JS_PROP_ENUMERABLE)) {
34488
0
                if (pr->flags & JS_PROP_TMASK) {
34489
0
                    JS_ThrowTypeError(s->ctx, "only value properties are supported");
34490
0
                    goto fail;
34491
0
                }
34492
0
                if (pass == 0) {
34493
0
                    prop_count++;
34494
0
                } else {
34495
0
                    bc_put_atom(s, atom);
34496
0
                    if (JS_WriteObjectRec(s, p->prop[i].u.value))
34497
0
                        goto fail;
34498
0
                }
34499
0
            }
34500
0
        }
34501
0
    }
34502
0
    return 0;
34503
0
 fail:
34504
0
    return -1;
34505
0
}
34506
34507
static int JS_WriteTypedArray(BCWriterState *s, JSValueConst obj)
34508
0
{
34509
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
34510
0
    JSTypedArray *ta = p->u.typed_array;
34511
34512
0
    bc_put_u8(s, BC_TAG_TYPED_ARRAY);
34513
0
    bc_put_u8(s, p->class_id - JS_CLASS_UINT8C_ARRAY);
34514
0
    bc_put_leb128(s, p->u.array.count);
34515
0
    bc_put_leb128(s, ta->offset);
34516
0
    if (JS_WriteObjectRec(s, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)))
34517
0
        return -1;
34518
0
    return 0;
34519
0
}
34520
34521
static int JS_WriteArrayBuffer(BCWriterState *s, JSValueConst obj)
34522
0
{
34523
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
34524
0
    JSArrayBuffer *abuf = p->u.array_buffer;
34525
0
    if (abuf->detached) {
34526
0
        JS_ThrowTypeErrorDetachedArrayBuffer(s->ctx);
34527
0
        return -1;
34528
0
    }
34529
0
    bc_put_u8(s, BC_TAG_ARRAY_BUFFER);
34530
0
    bc_put_leb128(s, abuf->byte_length);
34531
0
    dbuf_put(&s->dbuf, abuf->data, abuf->byte_length);
34532
0
    return 0;
34533
0
}
34534
34535
static int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValueConst obj)
34536
0
{
34537
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
34538
0
    JSArrayBuffer *abuf = p->u.array_buffer;
34539
0
    assert(!abuf->detached); /* SharedArrayBuffer are never detached */
34540
0
    bc_put_u8(s, BC_TAG_SHARED_ARRAY_BUFFER);
34541
0
    bc_put_leb128(s, abuf->byte_length);
34542
0
    bc_put_u64(s, (uintptr_t)abuf->data);
34543
0
    if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]),
34544
0
                        &s->sab_tab_size, s->sab_tab_len + 1))
34545
0
        return -1;
34546
    /* keep the SAB pointer so that the user can clone it or free it */
34547
0
    s->sab_tab[s->sab_tab_len++] = abuf->data;
34548
0
    return 0;
34549
0
}
34550
34551
static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
34552
4.16k
{
34553
4.16k
    uint32_t tag;
34554
34555
4.16k
    if (js_check_stack_overflow(s->ctx->rt, 0)) {
34556
0
        JS_ThrowStackOverflow(s->ctx);
34557
0
        return -1;
34558
0
    }
34559
34560
4.16k
    tag = JS_VALUE_GET_NORM_TAG(obj);
34561
4.16k
    switch(tag) {
34562
0
    case JS_TAG_NULL:
34563
0
        bc_put_u8(s, BC_TAG_NULL);
34564
0
        break;
34565
603
    case JS_TAG_UNDEFINED:
34566
603
        bc_put_u8(s, BC_TAG_UNDEFINED);
34567
603
        break;
34568
0
    case JS_TAG_BOOL:
34569
0
        bc_put_u8(s, BC_TAG_BOOL_FALSE + JS_VALUE_GET_INT(obj));
34570
0
        break;
34571
0
    case JS_TAG_INT:
34572
0
        bc_put_u8(s, BC_TAG_INT32);
34573
0
        bc_put_sleb128(s, JS_VALUE_GET_INT(obj));
34574
0
        break;
34575
87
    case JS_TAG_FLOAT64:
34576
87
        {
34577
87
            JSFloat64Union u;
34578
87
            bc_put_u8(s, BC_TAG_FLOAT64);
34579
87
            u.d = JS_VALUE_GET_FLOAT64(obj);
34580
87
            bc_put_u64(s, u.u64);
34581
87
        }
34582
87
        break;
34583
1.36k
    case JS_TAG_STRING:
34584
1.36k
        {
34585
1.36k
            JSString *p = JS_VALUE_GET_STRING(obj);
34586
1.36k
            bc_put_u8(s, BC_TAG_STRING);
34587
1.36k
            JS_WriteString(s, p);
34588
1.36k
        }
34589
1.36k
        break;
34590
542
    case JS_TAG_FUNCTION_BYTECODE:
34591
542
        if (!s->allow_bytecode)
34592
0
            goto invalid_tag;
34593
542
        if (JS_WriteFunctionTag(s, obj))
34594
0
            goto fail;
34595
542
        break;
34596
542
    case JS_TAG_MODULE:
34597
122
        if (!s->allow_bytecode)
34598
0
            goto invalid_tag;
34599
122
        if (JS_WriteModule(s, obj))
34600
0
            goto fail;
34601
122
        break;
34602
1.18k
    case JS_TAG_OBJECT:
34603
1.18k
        {
34604
1.18k
            JSObject *p = JS_VALUE_GET_OBJ(obj);
34605
1.18k
            int ret, idx;
34606
            
34607
1.18k
            if (s->allow_reference) {
34608
0
                idx = js_object_list_find(s->ctx, &s->object_list, p);
34609
0
                if (idx >= 0) {
34610
0
                    bc_put_u8(s, BC_TAG_OBJECT_REFERENCE);
34611
0
                    bc_put_leb128(s, idx);
34612
0
                    break;
34613
0
                } else {
34614
0
                    if (js_object_list_add(s->ctx, &s->object_list, p))
34615
0
                        goto fail;
34616
0
                }
34617
1.18k
            } else {
34618
1.18k
                if (p->tmp_mark) {
34619
0
                    JS_ThrowTypeError(s->ctx, "circular reference");
34620
0
                    goto fail;
34621
0
                }
34622
1.18k
                p->tmp_mark = 1;
34623
1.18k
            }
34624
1.18k
            switch(p->class_id) {
34625
1.18k
            case JS_CLASS_ARRAY:
34626
1.18k
                ret = JS_WriteArray(s, obj);
34627
1.18k
                break;
34628
0
            case JS_CLASS_OBJECT:
34629
0
                ret = JS_WriteObjectTag(s, obj);
34630
0
                break;
34631
0
            case JS_CLASS_ARRAY_BUFFER:
34632
0
                ret = JS_WriteArrayBuffer(s, obj);
34633
0
                break;
34634
0
            case JS_CLASS_SHARED_ARRAY_BUFFER:
34635
0
                if (!s->allow_sab)
34636
0
                    goto invalid_tag;
34637
0
                ret = JS_WriteSharedArrayBuffer(s, obj);
34638
0
                break;
34639
0
            case JS_CLASS_DATE:
34640
0
                bc_put_u8(s, BC_TAG_DATE);
34641
0
                ret = JS_WriteObjectRec(s, p->u.object_data);
34642
0
                break;
34643
0
            case JS_CLASS_NUMBER:
34644
0
            case JS_CLASS_STRING:
34645
0
            case JS_CLASS_BOOLEAN:
34646
0
#ifdef CONFIG_BIGNUM
34647
0
            case JS_CLASS_BIG_INT:
34648
0
            case JS_CLASS_BIG_FLOAT:
34649
0
            case JS_CLASS_BIG_DECIMAL:
34650
0
#endif
34651
0
                bc_put_u8(s, BC_TAG_OBJECT_VALUE);
34652
0
                ret = JS_WriteObjectRec(s, p->u.object_data);
34653
0
                break;
34654
0
            default:
34655
0
                if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
34656
0
                    p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
34657
0
                    ret = JS_WriteTypedArray(s, obj);
34658
0
                } else {
34659
0
                    JS_ThrowTypeError(s->ctx, "unsupported object class");
34660
0
                    ret = -1;
34661
0
                }
34662
0
                break;
34663
1.18k
            }
34664
1.18k
            p->tmp_mark = 0;
34665
1.18k
            if (ret)
34666
0
                goto fail;
34667
1.18k
        }
34668
1.18k
        break;
34669
1.18k
#ifdef CONFIG_BIGNUM
34670
1.18k
    case JS_TAG_BIG_INT:
34671
257
    case JS_TAG_BIG_FLOAT:
34672
257
    case JS_TAG_BIG_DECIMAL:
34673
257
        if (JS_WriteBigNum(s, obj))
34674
0
            goto fail;
34675
257
        break;
34676
257
#endif
34677
257
    default:
34678
0
    invalid_tag:
34679
0
        JS_ThrowInternalError(s->ctx, "unsupported tag (%d)", tag);
34680
0
        goto fail;
34681
4.16k
    }
34682
4.16k
    return 0;
34683
34684
0
 fail:
34685
0
    return -1;
34686
4.16k
}
34687
34688
/* create the atom table */
34689
static int JS_WriteObjectAtoms(BCWriterState *s)
34690
122
{
34691
122
    JSRuntime *rt = s->ctx->rt;
34692
122
    DynBuf dbuf1;
34693
122
    int i, atoms_size;
34694
122
    uint8_t version;
34695
34696
122
    dbuf1 = s->dbuf;
34697
122
    js_dbuf_init(s->ctx, &s->dbuf);
34698
34699
122
    version = BC_VERSION;
34700
122
    if (s->byte_swap)
34701
0
        version ^= BC_BE_VERSION;
34702
122
    bc_put_u8(s, version);
34703
34704
122
    bc_put_leb128(s, s->idx_to_atom_count);
34705
736
    for(i = 0; i < s->idx_to_atom_count; i++) {
34706
614
        JSAtomStruct *p = rt->atom_array[s->idx_to_atom[i]];
34707
614
        JS_WriteString(s, p);
34708
614
    }
34709
    /* XXX: should check for OOM in above phase */
34710
34711
    /* move the atoms at the start */
34712
    /* XXX: could just append dbuf1 data, but it uses more memory if
34713
       dbuf1 is larger than dbuf */
34714
122
    atoms_size = s->dbuf.size;
34715
122
    if (dbuf_realloc(&dbuf1, dbuf1.size + atoms_size))
34716
1
        goto fail;
34717
121
    memmove(dbuf1.buf + atoms_size, dbuf1.buf, dbuf1.size);
34718
121
    memcpy(dbuf1.buf, s->dbuf.buf, atoms_size);
34719
121
    dbuf1.size += atoms_size;
34720
121
    dbuf_free(&s->dbuf);
34721
121
    s->dbuf = dbuf1;
34722
121
    return 0;
34723
1
 fail:
34724
1
    dbuf_free(&dbuf1);
34725
1
    return -1;
34726
122
}
34727
34728
uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
34729
                         int flags, uint8_t ***psab_tab, size_t *psab_tab_len)
34730
122
{
34731
122
    BCWriterState ss, *s = &ss;
34732
34733
122
    memset(s, 0, sizeof(*s));
34734
122
    s->ctx = ctx;
34735
    /* XXX: byte swapped output is untested */
34736
122
    s->byte_swap = ((flags & JS_WRITE_OBJ_BSWAP) != 0);
34737
122
    s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);
34738
122
    s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
34739
122
    s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0);
34740
    /* XXX: could use a different version when bytecode is included */
34741
122
    if (s->allow_bytecode)
34742
122
        s->first_atom = JS_ATOM_END;
34743
0
    else
34744
0
        s->first_atom = 1;
34745
122
    js_dbuf_init(ctx, &s->dbuf);
34746
122
    js_object_list_init(&s->object_list);
34747
    
34748
122
    if (JS_WriteObjectRec(s, obj))
34749
0
        goto fail;
34750
122
    if (JS_WriteObjectAtoms(s))
34751
1
        goto fail;
34752
121
    js_object_list_end(ctx, &s->object_list);
34753
121
    js_free(ctx, s->atom_to_idx);
34754
121
    js_free(ctx, s->idx_to_atom);
34755
121
    *psize = s->dbuf.size;
34756
121
    if (psab_tab)
34757
0
        *psab_tab = s->sab_tab;
34758
121
    if (psab_tab_len)
34759
0
        *psab_tab_len = s->sab_tab_len;
34760
121
    return s->dbuf.buf;
34761
1
 fail:
34762
1
    js_object_list_end(ctx, &s->object_list);
34763
1
    js_free(ctx, s->atom_to_idx);
34764
1
    js_free(ctx, s->idx_to_atom);
34765
1
    dbuf_free(&s->dbuf);
34766
1
    *psize = 0;
34767
1
    if (psab_tab)
34768
0
        *psab_tab = NULL;
34769
1
    if (psab_tab_len)
34770
0
        *psab_tab_len = 0;
34771
1
    return NULL;
34772
122
}
34773
34774
uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
34775
                        int flags)
34776
122
{
34777
122
    return JS_WriteObject2(ctx, psize, obj, flags, NULL, NULL);
34778
122
}
34779
34780
typedef struct BCReaderState {
34781
    JSContext *ctx;
34782
    const uint8_t *buf_start, *ptr, *buf_end;
34783
    uint32_t first_atom;
34784
    uint32_t idx_to_atom_count;
34785
    JSAtom *idx_to_atom;
34786
    int error_state;
34787
    BOOL allow_sab : 8;
34788
    BOOL allow_bytecode : 8;
34789
    BOOL is_rom_data : 8;
34790
    BOOL allow_reference : 8;
34791
    /* object references */
34792
    JSObject **objects;
34793
    int objects_count;
34794
    int objects_size;
34795
    
34796
#ifdef DUMP_READ_OBJECT
34797
    const uint8_t *ptr_last;
34798
    int level;
34799
#endif
34800
} BCReaderState;
34801
34802
#ifdef DUMP_READ_OBJECT
34803
static void __attribute__((format(printf, 2, 3))) bc_read_trace(BCReaderState *s, const char *fmt, ...) {
34804
    va_list ap;
34805
    int i, n, n0;
34806
34807
    if (!s->ptr_last)
34808
        s->ptr_last = s->buf_start;
34809
34810
    n = n0 = 0;
34811
    if (s->ptr > s->ptr_last || s->ptr == s->buf_start) {
34812
        n0 = printf("%04x: ", (int)(s->ptr_last - s->buf_start));
34813
        n += n0;
34814
    }
34815
    for (i = 0; s->ptr_last < s->ptr; i++) {
34816
        if ((i & 7) == 0 && i > 0) {
34817
            printf("\n%*s", n0, "");
34818
            n = n0;
34819
        }
34820
        n += printf(" %02x", *s->ptr_last++);
34821
    }
34822
    if (*fmt == '}')
34823
        s->level--;
34824
    if (n < 32 + s->level * 2) {
34825
        printf("%*s", 32 + s->level * 2 - n, "");
34826
    }
34827
    va_start(ap, fmt);
34828
    vfprintf(stdout, fmt, ap);
34829
    va_end(ap);
34830
    if (strchr(fmt, '{'))
34831
        s->level++;
34832
}
34833
#else
34834
#define bc_read_trace(...)
34835
#endif
34836
34837
static int bc_read_error_end(BCReaderState *s)
34838
0
{
34839
0
    if (!s->error_state) {
34840
0
        JS_ThrowSyntaxError(s->ctx, "read after the end of the buffer");
34841
0
    }
34842
0
    return s->error_state = -1;
34843
0
}
34844
34845
static int bc_get_u8(BCReaderState *s, uint8_t *pval)
34846
6.62k
{
34847
6.62k
    if (unlikely(s->buf_end - s->ptr < 1)) {
34848
0
        *pval = 0; /* avoid warning */
34849
0
        return bc_read_error_end(s);
34850
0
    }
34851
6.62k
    *pval = *s->ptr++;
34852
6.62k
    return 0;
34853
6.62k
}
34854
34855
static int bc_get_u16(BCReaderState *s, uint16_t *pval)
34856
541
{
34857
541
    if (unlikely(s->buf_end - s->ptr < 2)) {
34858
0
        *pval = 0; /* avoid warning */
34859
0
        return bc_read_error_end(s);
34860
0
    }
34861
541
    *pval = get_u16(s->ptr);
34862
541
    s->ptr += 2;
34863
541
    return 0;
34864
541
}
34865
34866
static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
34867
0
{
34868
0
    if (unlikely(s->buf_end - s->ptr < 4)) {
34869
0
        *pval = 0; /* avoid warning */
34870
0
        return bc_read_error_end(s);
34871
0
    }
34872
0
    *pval = get_u32(s->ptr);
34873
0
    s->ptr += 4;
34874
0
    return 0;
34875
0
}
34876
34877
static int bc_get_u64(BCReaderState *s, uint64_t *pval)
34878
379
{
34879
379
    if (unlikely(s->buf_end - s->ptr < 8)) {
34880
0
        *pval = 0; /* avoid warning */
34881
0
        return bc_read_error_end(s);
34882
0
    }
34883
379
    *pval = get_u64(s->ptr);
34884
379
    s->ptr += 8;
34885
379
    return 0;
34886
379
}
34887
34888
static int bc_get_leb128(BCReaderState *s, uint32_t *pval)
34889
14.2k
{
34890
14.2k
    int ret;
34891
14.2k
    ret = get_leb128(pval, s->ptr, s->buf_end);
34892
14.2k
    if (unlikely(ret < 0))
34893
0
        return bc_read_error_end(s);
34894
14.2k
    s->ptr += ret;
34895
14.2k
    return 0;
34896
14.2k
}
34897
34898
static int bc_get_sleb128(BCReaderState *s, int32_t *pval)
34899
111
{
34900
111
    int ret;
34901
111
    ret = get_sleb128(pval, s->ptr, s->buf_end);
34902
111
    if (unlikely(ret < 0))
34903
0
        return bc_read_error_end(s);
34904
111
    s->ptr += ret;
34905
111
    return 0;
34906
111
}
34907
34908
/* XXX: used to read an `int` with a positive value */
34909
static int bc_get_leb128_int(BCReaderState *s, int *pval)
34910
5.93k
{
34911
5.93k
    return bc_get_leb128(s, (uint32_t *)pval);
34912
5.93k
}
34913
34914
static int bc_get_leb128_u16(BCReaderState *s, uint16_t *pval)
34915
2.16k
{
34916
2.16k
    uint32_t val;
34917
2.16k
    if (bc_get_leb128(s, &val)) {
34918
0
        *pval = 0;
34919
0
        return -1;
34920
0
    }
34921
2.16k
    *pval = val;
34922
2.16k
    return 0;
34923
2.16k
}
34924
34925
static int bc_get_buf(BCReaderState *s, uint8_t *buf, uint32_t buf_len)
34926
787
{
34927
787
    if (buf_len != 0) {
34928
787
        if (unlikely(!buf || s->buf_end - s->ptr < buf_len))
34929
0
            return bc_read_error_end(s);
34930
787
        memcpy(buf, s->ptr, buf_len);
34931
787
        s->ptr += buf_len;
34932
787
    }
34933
787
    return 0;
34934
787
}
34935
34936
static int bc_idx_to_atom(BCReaderState *s, JSAtom *patom, uint32_t idx)
34937
5.68k
{
34938
5.68k
    JSAtom atom;
34939
34940
5.68k
    if (__JS_AtomIsTaggedInt(idx)) {
34941
269
        atom = idx;
34942
5.41k
    } else if (idx < s->first_atom) {
34943
1.57k
        atom = JS_DupAtom(s->ctx, idx);
34944
3.83k
    } else {
34945
3.83k
        idx -= s->first_atom;
34946
3.83k
        if (idx >= s->idx_to_atom_count) {
34947
0
            JS_ThrowSyntaxError(s->ctx, "invalid atom index (pos=%u)",
34948
0
                                (unsigned int)(s->ptr - s->buf_start));
34949
0
            *patom = JS_ATOM_NULL;
34950
0
            return s->error_state = -1;
34951
0
        }
34952
3.83k
        atom = JS_DupAtom(s->ctx, s->idx_to_atom[idx]);
34953
3.83k
    }
34954
5.68k
    *patom = atom;
34955
5.68k
    return 0;
34956
5.68k
}
34957
34958
static int bc_get_atom(BCReaderState *s, JSAtom *patom)
34959
2.74k
{
34960
2.74k
    uint32_t v;
34961
2.74k
    if (bc_get_leb128(s, &v))
34962
0
        return -1;
34963
2.74k
    if (v & 1) {
34964
0
        *patom = __JS_AtomFromUInt32(v >> 1);
34965
0
        return 0;
34966
2.74k
    } else {
34967
2.74k
        return bc_idx_to_atom(s, patom, v >> 1);
34968
2.74k
    }
34969
2.74k
}
34970
34971
static JSString *JS_ReadString(BCReaderState *s)
34972
1.98k
{
34973
1.98k
    uint32_t len;
34974
1.98k
    size_t size;
34975
1.98k
    BOOL is_wide_char;
34976
1.98k
    JSString *p;
34977
34978
1.98k
    if (bc_get_leb128(s, &len))
34979
0
        return NULL;
34980
1.98k
    is_wide_char = len & 1;
34981
1.98k
    len >>= 1;
34982
1.98k
    p = js_alloc_string(s->ctx, len, is_wide_char);
34983
1.98k
    if (!p) {
34984
0
        s->error_state = -1;
34985
0
        return NULL;
34986
0
    }
34987
1.98k
    size = (size_t)len << is_wide_char;
34988
1.98k
    if ((s->buf_end - s->ptr) < size) {
34989
0
        bc_read_error_end(s);
34990
0
        js_free_string(s->ctx->rt, p);
34991
0
        return NULL;
34992
0
    }
34993
1.98k
    memcpy(p->u.str8, s->ptr, size);
34994
1.98k
    s->ptr += size;
34995
1.98k
    if (!is_wide_char) {
34996
1.87k
        p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */
34997
1.87k
    }
34998
#ifdef DUMP_READ_OBJECT
34999
    JS_DumpString(s->ctx->rt, p); printf("\n");
35000
#endif
35001
1.98k
    return p;
35002
1.98k
}
35003
35004
static uint32_t bc_get_flags(uint32_t flags, int *pidx, int n)
35005
13.1k
{
35006
13.1k
    uint32_t val;
35007
    /* XXX: this does not work for n == 32 */
35008
13.1k
    val = (flags >> *pidx) & ((1U << n) - 1);
35009
13.1k
    *pidx += n;
35010
13.1k
    return val;
35011
13.1k
}
35012
35013
static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
35014
                                   int byte_code_offset, uint32_t bc_len)
35015
540
{
35016
540
    uint8_t *bc_buf;
35017
540
    int pos, len, op;
35018
540
    JSAtom atom;
35019
540
    uint32_t idx;
35020
35021
540
    if (s->is_rom_data) {
35022
        /* directly use the input buffer */
35023
0
        if (unlikely(s->buf_end - s->ptr < bc_len))
35024
0
            return bc_read_error_end(s);
35025
0
        bc_buf = (uint8_t *)s->ptr;
35026
0
        s->ptr += bc_len;
35027
540
    } else {
35028
540
        bc_buf = (void *)((uint8_t*)b + byte_code_offset);
35029
540
        if (bc_get_buf(s, bc_buf, bc_len))
35030
0
            return -1;
35031
540
    }
35032
540
    b->byte_code_buf = bc_buf;
35033
35034
540
    pos = 0;
35035
15.4k
    while (pos < bc_len) {
35036
14.8k
        op = bc_buf[pos];
35037
14.8k
        len = short_opcode_info(op).size;
35038
14.8k
        switch(short_opcode_info(op).fmt) {
35039
2.69k
        case OP_FMT_atom:
35040
2.80k
        case OP_FMT_atom_u8:
35041
2.93k
        case OP_FMT_atom_u16:
35042
2.93k
        case OP_FMT_atom_label_u8:
35043
2.93k
        case OP_FMT_atom_label_u16:
35044
2.93k
            idx = get_u32(bc_buf + pos + 1);
35045
2.93k
            if (s->is_rom_data) {
35046
                /* just increment the reference count of the atom */
35047
0
                JS_DupAtom(s->ctx, (JSAtom)idx);
35048
2.93k
            } else {
35049
2.93k
                if (bc_idx_to_atom(s, &atom, idx)) {
35050
                    /* Note: the atoms will be freed up to this position */
35051
0
                    b->byte_code_len = pos;
35052
0
                    return -1;
35053
0
                }
35054
2.93k
                put_u32(bc_buf + pos + 1, atom);
35055
#ifdef DUMP_READ_OBJECT
35056
                bc_read_trace(s, "at %d, fixup atom: ", pos + 1); print_atom(s->ctx, atom); printf("\n");
35057
#endif
35058
2.93k
            }
35059
2.93k
            break;
35060
11.9k
        default:
35061
11.9k
            break;
35062
14.8k
        }
35063
14.8k
        pos += len;
35064
14.8k
    }
35065
540
    return 0;
35066
540
}
35067
35068
#ifdef CONFIG_BIGNUM
35069
static JSValue JS_ReadBigNum(BCReaderState *s, int tag)
35070
111
{
35071
111
    JSValue obj = JS_UNDEFINED;
35072
111
    uint8_t v8;
35073
111
    int32_t e;
35074
111
    uint32_t len;
35075
111
    limb_t l, i, n, j;
35076
111
    JSBigFloat *p;
35077
111
    limb_t v;
35078
111
    bf_t *a;
35079
111
    int bpos, d;
35080
    
35081
111
    p = js_new_bf(s->ctx);
35082
111
    if (!p)
35083
0
        goto fail;
35084
111
    switch(tag) {
35085
111
    case BC_TAG_BIG_INT:
35086
111
        obj = JS_MKPTR(JS_TAG_BIG_INT, p);
35087
111
        break;
35088
0
    case BC_TAG_BIG_FLOAT:
35089
0
        obj = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
35090
0
        break;
35091
0
    case BC_TAG_BIG_DECIMAL:
35092
0
        obj = JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
35093
0
        break;
35094
0
    default:
35095
0
        abort();
35096
111
    }
35097
35098
    /* sign + exponent */
35099
111
    if (bc_get_sleb128(s, &e))
35100
0
        goto fail;
35101
35102
111
    a = &p->num;
35103
111
    a->sign = e & 1;
35104
111
    e >>= 1;
35105
111
    if (e == 0)
35106
0
        a->expn = BF_EXP_ZERO;
35107
111
    else if (e == 1)
35108
0
        a->expn = BF_EXP_INF;
35109
111
    else if (e == 2)
35110
0
        a->expn = BF_EXP_NAN;
35111
111
    else if (e >= 3)
35112
111
        a->expn = e - 3;
35113
0
    else
35114
0
        a->expn = e;
35115
35116
    /* mantissa */
35117
111
    if (a->expn != BF_EXP_ZERO &&
35118
111
        a->expn != BF_EXP_INF &&
35119
111
        a->expn != BF_EXP_NAN) {
35120
111
        if (bc_get_leb128(s, &len))
35121
0
            goto fail;
35122
111
        bc_read_trace(s, "len=%" PRId64 "\n", (int64_t)len);
35123
111
        if (len == 0) {
35124
0
            JS_ThrowInternalError(s->ctx, "invalid bignum length");
35125
0
            goto fail;
35126
0
        }
35127
111
        if (tag != BC_TAG_BIG_DECIMAL)
35128
111
            l = (len + sizeof(limb_t) - 1) / sizeof(limb_t);
35129
0
        else
35130
0
            l = (len + LIMB_DIGITS - 1) / LIMB_DIGITS;
35131
111
        if (bf_resize(a, l)) {
35132
0
            JS_ThrowOutOfMemory(s->ctx);
35133
0
            goto fail;
35134
0
        }
35135
111
        if (tag != BC_TAG_BIG_DECIMAL) {
35136
111
            n = len & (sizeof(limb_t) - 1);
35137
111
            if (n != 0) {
35138
101
                v = 0;
35139
485
                for(i = 0; i < n; i++) {
35140
384
                    if (bc_get_u8(s, &v8))
35141
0
                        goto fail;
35142
384
                    v |= (limb_t)v8 << ((sizeof(limb_t) - n + i) * 8);
35143
384
                }
35144
101
                a->tab[0] = v;
35145
101
                i = 1;
35146
101
            } else {
35147
10
                i = 0;
35148
10
            }
35149
403
            for(; i < l; i++) {
35150
#if LIMB_BITS == 32
35151
                if (bc_get_u32(s, &v))
35152
                    goto fail;
35153
#ifdef WORDS_BIGENDIAN
35154
                v = bswap32(v);
35155
#endif
35156
#else
35157
292
                if (bc_get_u64(s, &v))
35158
0
                    goto fail;
35159
#ifdef WORDS_BIGENDIAN
35160
                v = bswap64(v);
35161
#endif
35162
292
#endif
35163
292
                a->tab[i] = v;
35164
292
            }
35165
111
        } else {
35166
0
            bpos = 0;
35167
0
            for(i = 0; i < l; i++) {
35168
0
                if (i == 0 && (n = len % LIMB_DIGITS) != 0) {
35169
0
                    j = LIMB_DIGITS - n;
35170
0
                } else {
35171
0
                    j = 0;
35172
0
                }
35173
0
                v = 0;
35174
0
                for(; j < LIMB_DIGITS; j++) {
35175
0
                    if (bpos == 0) {
35176
0
                        if (bc_get_u8(s, &v8))
35177
0
                            goto fail;
35178
0
                        d = v8 & 0xf;
35179
0
                        bpos = 1;
35180
0
                    } else {
35181
0
                        d = v8 >> 4;
35182
0
                        bpos = 0;
35183
0
                    }
35184
0
                    if (d >= 10) {
35185
0
                        JS_ThrowInternalError(s->ctx, "invalid digit");
35186
0
                        goto fail;
35187
0
                    }
35188
0
                    v += mp_pow_dec[j] * d;
35189
0
                }
35190
0
                a->tab[i] = v;
35191
0
            }
35192
0
        }
35193
111
    }
35194
111
    bc_read_trace(s, "}\n");
35195
111
    return obj;
35196
0
 fail:
35197
0
    JS_FreeValue(s->ctx, obj);
35198
0
    return JS_EXCEPTION;
35199
111
}
35200
#endif /* CONFIG_BIGNUM */
35201
35202
static JSValue JS_ReadObjectRec(BCReaderState *s);
35203
35204
static int BC_add_object_ref1(BCReaderState *s, JSObject *p)
35205
1.18k
{
35206
1.18k
    if (s->allow_reference) {
35207
0
        if (js_resize_array(s->ctx, (void *)&s->objects,
35208
0
                            sizeof(s->objects[0]),
35209
0
                            &s->objects_size, s->objects_count + 1))
35210
0
            return -1;
35211
0
        s->objects[s->objects_count++] = p;
35212
0
    }
35213
1.18k
    return 0;
35214
1.18k
}
35215
35216
static int BC_add_object_ref(BCReaderState *s, JSValueConst obj)
35217
1.18k
{
35218
1.18k
    return BC_add_object_ref1(s, JS_VALUE_GET_OBJ(obj));
35219
1.18k
}
35220
35221
static JSValue JS_ReadFunctionTag(BCReaderState *s)
35222
541
{
35223
541
    JSContext *ctx = s->ctx;
35224
541
    JSFunctionBytecode bc, *b;
35225
541
    JSValue obj = JS_UNDEFINED;
35226
541
    uint16_t v16;
35227
541
    uint8_t v8;
35228
541
    int idx, i, local_count;
35229
541
    int function_size, cpool_offset, byte_code_offset;
35230
541
    int closure_var_offset, vardefs_offset;
35231
35232
541
    memset(&bc, 0, sizeof(bc));
35233
541
    bc.header.ref_count = 1;
35234
    //bc.gc_header.mark = 0;
35235
35236
541
    if (bc_get_u16(s, &v16))
35237
0
        goto fail;
35238
541
    idx = 0;
35239
541
    bc.has_prototype = bc_get_flags(v16, &idx, 1);
35240
541
    bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1);
35241
541
    bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1);
35242
541
    bc.need_home_object = bc_get_flags(v16, &idx, 1);
35243
541
    bc.func_kind = bc_get_flags(v16, &idx, 2);
35244
541
    bc.new_target_allowed = bc_get_flags(v16, &idx, 1);
35245
541
    bc.super_call_allowed = bc_get_flags(v16, &idx, 1);
35246
541
    bc.super_allowed = bc_get_flags(v16, &idx, 1);
35247
541
    bc.arguments_allowed = bc_get_flags(v16, &idx, 1);
35248
541
    bc.has_debug = bc_get_flags(v16, &idx, 1);
35249
541
    bc.backtrace_barrier = bc_get_flags(v16, &idx, 1);
35250
541
    bc.read_only_bytecode = s->is_rom_data;
35251
541
    if (bc_get_u8(s, &v8))
35252
0
        goto fail;
35253
541
    bc.js_mode = v8;
35254
541
    if (bc_get_atom(s, &bc.func_name))  //@ atom leak if failure
35255
0
        goto fail;
35256
541
    if (bc_get_leb128_u16(s, &bc.arg_count))
35257
0
        goto fail;
35258
541
    if (bc_get_leb128_u16(s, &bc.var_count))
35259
0
        goto fail;
35260
541
    if (bc_get_leb128_u16(s, &bc.defined_arg_count))
35261
0
        goto fail;
35262
541
    if (bc_get_leb128_u16(s, &bc.stack_size))
35263
0
        goto fail;
35264
541
    if (bc_get_leb128_int(s, &bc.closure_var_count))
35265
0
        goto fail;
35266
541
    if (bc_get_leb128_int(s, &bc.cpool_count))
35267
0
        goto fail;
35268
541
    if (bc_get_leb128_int(s, &bc.byte_code_len))
35269
0
        goto fail;
35270
541
    if (bc_get_leb128_int(s, &local_count))
35271
0
        goto fail;
35272
35273
541
    if (bc.has_debug) {
35274
517
        function_size = sizeof(*b);
35275
517
    } else {
35276
24
        function_size = offsetof(JSFunctionBytecode, debug);
35277
24
    }
35278
541
    cpool_offset = function_size;
35279
541
    function_size += bc.cpool_count * sizeof(*bc.cpool);
35280
541
    vardefs_offset = function_size;
35281
541
    function_size += local_count * sizeof(*bc.vardefs);
35282
541
    closure_var_offset = function_size;
35283
541
    function_size += bc.closure_var_count * sizeof(*bc.closure_var);
35284
541
    byte_code_offset = function_size;
35285
541
    if (!bc.read_only_bytecode) {
35286
541
        function_size += bc.byte_code_len;
35287
541
    }
35288
35289
541
    b = js_mallocz(ctx, function_size);
35290
541
    if (!b)
35291
1
        return JS_EXCEPTION;
35292
            
35293
540
    memcpy(b, &bc, offsetof(JSFunctionBytecode, debug));
35294
540
    b->header.ref_count = 1;
35295
540
    if (local_count != 0) {
35296
414
        b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
35297
414
    }
35298
540
    if (b->closure_var_count != 0) {
35299
273
        b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
35300
273
    }
35301
540
    if (b->cpool_count != 0) {
35302
174
        b->cpool = (void *)((uint8_t*)b + cpool_offset);
35303
174
    }
35304
    
35305
540
    add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
35306
            
35307
540
    obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
35308
35309
#ifdef DUMP_READ_OBJECT
35310
    bc_read_trace(s, "name: "); print_atom(s->ctx, b->func_name); printf("\n");
35311
#endif
35312
540
    bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n",
35313
540
                  b->arg_count, b->var_count, b->defined_arg_count,
35314
540
                  b->closure_var_count, b->cpool_count);
35315
540
    bc_read_trace(s, "stack=%d bclen=%d locals=%d\n",
35316
540
                  b->stack_size, b->byte_code_len, local_count);
35317
35318
540
    if (local_count != 0) {
35319
414
        bc_read_trace(s, "vars {\n");
35320
1.10k
        for(i = 0; i < local_count; i++) {
35321
686
            JSVarDef *vd = &b->vardefs[i];
35322
686
            if (bc_get_atom(s, &vd->var_name))
35323
0
                goto fail;
35324
686
            if (bc_get_leb128_int(s, &vd->scope_level))
35325
0
                goto fail;
35326
686
            if (bc_get_leb128_int(s, &vd->scope_next))
35327
0
                goto fail;
35328
686
            vd->scope_next--;
35329
686
            if (bc_get_u8(s, &v8))
35330
0
                goto fail;
35331
686
            idx = 0;
35332
686
            vd->var_kind = bc_get_flags(v8, &idx, 4);
35333
686
            vd->is_const = bc_get_flags(v8, &idx, 1);
35334
686
            vd->is_lexical = bc_get_flags(v8, &idx, 1);
35335
686
            vd->is_captured = bc_get_flags(v8, &idx, 1);
35336
#ifdef DUMP_READ_OBJECT
35337
            bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n");
35338
#endif
35339
686
        }
35340
414
        bc_read_trace(s, "}\n");
35341
414
    }
35342
540
    if (b->closure_var_count != 0) {
35343
273
        bc_read_trace(s, "closure vars {\n");
35344
1.15k
        for(i = 0; i < b->closure_var_count; i++) {
35345
884
            JSClosureVar *cv = &b->closure_var[i];
35346
884
            int var_idx;
35347
884
            if (bc_get_atom(s, &cv->var_name))
35348
0
                goto fail;
35349
884
            if (bc_get_leb128_int(s, &var_idx))
35350
0
                goto fail;
35351
884
            cv->var_idx = var_idx;
35352
884
            if (bc_get_u8(s, &v8))
35353
0
                goto fail;
35354
884
            idx = 0;
35355
884
            cv->is_local = bc_get_flags(v8, &idx, 1);
35356
884
            cv->is_arg = bc_get_flags(v8, &idx, 1);
35357
884
            cv->is_const = bc_get_flags(v8, &idx, 1);
35358
884
            cv->is_lexical = bc_get_flags(v8, &idx, 1);
35359
884
            cv->var_kind = bc_get_flags(v8, &idx, 4);
35360
#ifdef DUMP_READ_OBJECT
35361
            bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); printf("\n");
35362
#endif
35363
884
        }
35364
273
        bc_read_trace(s, "}\n");
35365
273
    }
35366
540
    {
35367
540
        bc_read_trace(s, "bytecode {\n");
35368
540
        if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len))
35369
0
            goto fail;
35370
540
        bc_read_trace(s, "}\n");
35371
540
    }
35372
540
    if (b->has_debug) {
35373
        /* read optional debug information */
35374
516
        bc_read_trace(s, "debug {\n");
35375
516
        if (bc_get_atom(s, &b->debug.filename))
35376
0
            goto fail;
35377
516
        if (bc_get_leb128_int(s, &b->debug.line_num))
35378
0
            goto fail;
35379
516
        if (bc_get_leb128_int(s, &b->debug.pc2line_len))
35380
0
            goto fail;
35381
516
        if (b->debug.pc2line_len) {
35382
247
            b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len);
35383
247
            if (!b->debug.pc2line_buf)
35384
0
                goto fail;
35385
247
            if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len))
35386
0
                goto fail;
35387
247
        }
35388
#ifdef DUMP_READ_OBJECT
35389
        bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n");
35390
#endif
35391
516
        bc_read_trace(s, "}\n");
35392
516
    }
35393
540
    if (b->cpool_count != 0) {
35394
174
        bc_read_trace(s, "cpool {\n");
35395
1.54k
        for(i = 0; i < b->cpool_count; i++) {
35396
1.36k
            JSValue val;
35397
1.36k
            val = JS_ReadObjectRec(s);
35398
1.36k
            if (JS_IsException(val))
35399
0
                goto fail;
35400
1.36k
            b->cpool[i] = val;
35401
1.36k
        }
35402
174
        bc_read_trace(s, "}\n");
35403
174
    }
35404
540
    b->realm = JS_DupContext(ctx);
35405
540
    return obj;
35406
0
 fail:
35407
0
    JS_FreeValue(ctx, obj);
35408
0
    return JS_EXCEPTION;
35409
540
}
35410
35411
static JSValue JS_ReadModule(BCReaderState *s)
35412
121
{
35413
121
    JSContext *ctx = s->ctx;
35414
121
    JSValue obj;
35415
121
    JSModuleDef *m = NULL;
35416
121
    JSAtom module_name;
35417
121
    int i;
35418
121
    uint8_t v8;
35419
    
35420
121
    if (bc_get_atom(s, &module_name))
35421
0
        goto fail;
35422
#ifdef DUMP_READ_OBJECT
35423
    bc_read_trace(s, "name: "); print_atom(s->ctx, module_name); printf("\n");
35424
#endif
35425
121
    m = js_new_module_def(ctx, module_name);
35426
121
    if (!m)
35427
0
        goto fail;
35428
121
    obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
35429
121
    if (bc_get_leb128_int(s, &m->req_module_entries_count))
35430
0
        goto fail;
35431
121
    if (m->req_module_entries_count != 0) {
35432
0
        m->req_module_entries_size = m->req_module_entries_count;
35433
0
        m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size);
35434
0
        if (!m->req_module_entries)
35435
0
            goto fail;
35436
0
        for(i = 0; i < m->req_module_entries_count; i++) {
35437
0
            JSReqModuleEntry *rme = &m->req_module_entries[i];
35438
0
            if (bc_get_atom(s, &rme->module_name))
35439
0
                goto fail;
35440
0
        }
35441
0
    }
35442
35443
121
    if (bc_get_leb128_int(s, &m->export_entries_count))
35444
0
        goto fail;
35445
121
    if (m->export_entries_count != 0) {
35446
0
        m->export_entries_size = m->export_entries_count;
35447
0
        m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size);
35448
0
        if (!m->export_entries)
35449
0
            goto fail;
35450
0
        for(i = 0; i < m->export_entries_count; i++) {
35451
0
            JSExportEntry *me = &m->export_entries[i];
35452
0
            if (bc_get_u8(s, &v8))
35453
0
                goto fail;
35454
0
            me->export_type = v8;
35455
0
            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
35456
0
                if (bc_get_leb128_int(s, &me->u.local.var_idx))
35457
0
                    goto fail;
35458
0
            } else {
35459
0
                if (bc_get_leb128_int(s, &me->u.req_module_idx))
35460
0
                    goto fail;
35461
0
                if (bc_get_atom(s, &me->local_name))
35462
0
                    goto fail;
35463
0
            }
35464
0
            if (bc_get_atom(s, &me->export_name))
35465
0
                goto fail;
35466
0
        }
35467
0
    }
35468
35469
121
    if (bc_get_leb128_int(s, &m->star_export_entries_count))
35470
0
        goto fail;
35471
121
    if (m->star_export_entries_count != 0) {
35472
0
        m->star_export_entries_size = m->star_export_entries_count;
35473
0
        m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size);
35474
0
        if (!m->star_export_entries)
35475
0
            goto fail;
35476
0
        for(i = 0; i < m->star_export_entries_count; i++) {
35477
0
            JSStarExportEntry *se = &m->star_export_entries[i];
35478
0
            if (bc_get_leb128_int(s, &se->req_module_idx))
35479
0
                goto fail;
35480
0
        }
35481
0
    }
35482
35483
121
    if (bc_get_leb128_int(s, &m->import_entries_count))
35484
0
        goto fail;
35485
121
    if (m->import_entries_count != 0) {
35486
0
        m->import_entries_size = m->import_entries_count;
35487
0
        m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size);
35488
0
        if (!m->import_entries)
35489
0
            goto fail;
35490
0
        for(i = 0; i < m->import_entries_count; i++) {
35491
0
            JSImportEntry *mi = &m->import_entries[i];
35492
0
            if (bc_get_leb128_int(s, &mi->var_idx))
35493
0
                goto fail;
35494
0
            if (bc_get_atom(s, &mi->import_name))
35495
0
                goto fail;
35496
0
            if (bc_get_leb128_int(s, &mi->req_module_idx))
35497
0
                goto fail;
35498
0
        }
35499
0
    }
35500
35501
121
    m->func_obj = JS_ReadObjectRec(s);
35502
121
    if (JS_IsException(m->func_obj))
35503
1
        goto fail;
35504
120
    return obj;
35505
1
 fail:
35506
1
    if (m) {
35507
1
        js_free_module_def(ctx, m);
35508
1
    }
35509
1
    return JS_EXCEPTION;
35510
121
}
35511
35512
static JSValue JS_ReadObjectTag(BCReaderState *s)
35513
0
{
35514
0
    JSContext *ctx = s->ctx;
35515
0
    JSValue obj;
35516
0
    uint32_t prop_count, i;
35517
0
    JSAtom atom;
35518
0
    JSValue val;
35519
0
    int ret;
35520
    
35521
0
    obj = JS_NewObject(ctx);
35522
0
    if (BC_add_object_ref(s, obj))
35523
0
        goto fail;
35524
0
    if (bc_get_leb128(s, &prop_count))
35525
0
        goto fail;
35526
0
    for(i = 0; i < prop_count; i++) {
35527
0
        if (bc_get_atom(s, &atom))
35528
0
            goto fail;
35529
#ifdef DUMP_READ_OBJECT
35530
        bc_read_trace(s, "propname: "); print_atom(s->ctx, atom); printf("\n");
35531
#endif
35532
0
        val = JS_ReadObjectRec(s);
35533
0
        if (JS_IsException(val)) {
35534
0
            JS_FreeAtom(ctx, atom);
35535
0
            goto fail;
35536
0
        }
35537
0
        ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E);
35538
0
        JS_FreeAtom(ctx, atom);
35539
0
        if (ret < 0)
35540
0
            goto fail;
35541
0
    }
35542
0
    return obj;
35543
0
 fail:
35544
0
    JS_FreeValue(ctx, obj);
35545
0
    return JS_EXCEPTION;
35546
0
}
35547
35548
static JSValue JS_ReadArray(BCReaderState *s, int tag)
35549
1.18k
{
35550
1.18k
    JSContext *ctx = s->ctx;
35551
1.18k
    JSValue obj;
35552
1.18k
    uint32_t len, i;
35553
1.18k
    JSValue val;
35554
1.18k
    int ret, prop_flags;
35555
1.18k
    BOOL is_template;
35556
35557
1.18k
    obj = JS_NewArray(ctx);
35558
1.18k
    if (BC_add_object_ref(s, obj))
35559
0
        goto fail;
35560
1.18k
    is_template = (tag == BC_TAG_TEMPLATE_OBJECT);
35561
1.18k
    if (bc_get_leb128(s, &len))
35562
0
        goto fail;
35563
2.40k
    for(i = 0; i < len; i++) {
35564
1.21k
        val = JS_ReadObjectRec(s);
35565
1.21k
        if (JS_IsException(val))
35566
0
            goto fail;
35567
1.21k
        if (is_template)
35568
1.21k
            prop_flags = JS_PROP_ENUMERABLE;
35569
0
        else
35570
0
            prop_flags = JS_PROP_C_W_E;
35571
1.21k
        ret = JS_DefinePropertyValueUint32(ctx, obj, i, val,
35572
1.21k
                                           prop_flags);
35573
1.21k
        if (ret < 0)
35574
0
            goto fail;
35575
1.21k
    }
35576
1.18k
    if (is_template) {
35577
1.18k
        val = JS_ReadObjectRec(s);
35578
1.18k
        if (JS_IsException(val))
35579
0
            goto fail;
35580
1.18k
        if (!JS_IsUndefined(val)) {
35581
592
            ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0);
35582
592
            if (ret < 0)
35583
0
                goto fail;
35584
592
        }
35585
1.18k
        JS_PreventExtensions(ctx, obj);
35586
1.18k
    }
35587
1.18k
    return obj;
35588
0
 fail:
35589
0
    JS_FreeValue(ctx, obj);
35590
0
    return JS_EXCEPTION;
35591
1.18k
}
35592
35593
static JSValue JS_ReadTypedArray(BCReaderState *s)
35594
0
{
35595
0
    JSContext *ctx = s->ctx;
35596
0
    JSValue obj = JS_UNDEFINED, array_buffer = JS_UNDEFINED;
35597
0
    uint8_t array_tag;
35598
0
    JSValueConst args[3];
35599
0
    uint32_t offset, len, idx;
35600
    
35601
0
    if (bc_get_u8(s, &array_tag))
35602
0
        return JS_EXCEPTION;
35603
0
    if (array_tag >= JS_TYPED_ARRAY_COUNT)
35604
0
        return JS_ThrowTypeError(ctx, "invalid typed array");
35605
0
    if (bc_get_leb128(s, &len))
35606
0
        return JS_EXCEPTION;
35607
0
    if (bc_get_leb128(s, &offset))
35608
0
        return JS_EXCEPTION;
35609
    /* XXX: this hack could be avoided if the typed array could be
35610
       created before the array buffer */
35611
0
    idx = s->objects_count;
35612
0
    if (BC_add_object_ref1(s, NULL))
35613
0
        goto fail;
35614
0
    array_buffer = JS_ReadObjectRec(s);
35615
0
    if (JS_IsException(array_buffer))
35616
0
        return JS_EXCEPTION;
35617
0
    if (!js_get_array_buffer(ctx, array_buffer)) {
35618
0
        JS_FreeValue(ctx, array_buffer);
35619
0
        return JS_EXCEPTION;
35620
0
    }
35621
0
    args[0] = array_buffer;
35622
0
    args[1] = JS_NewInt64(ctx, offset);
35623
0
    args[2] = JS_NewInt64(ctx, len);
35624
0
    obj = js_typed_array_constructor(ctx, JS_UNDEFINED,
35625
0
                                     3, args,
35626
0
                                     JS_CLASS_UINT8C_ARRAY + array_tag);
35627
0
    if (JS_IsException(obj))
35628
0
        goto fail;
35629
0
    if (s->allow_reference) {
35630
0
        s->objects[idx] = JS_VALUE_GET_OBJ(obj);
35631
0
    }
35632
0
    JS_FreeValue(ctx, array_buffer);
35633
0
    return obj;
35634
0
 fail:
35635
0
    JS_FreeValue(ctx, array_buffer);
35636
0
    JS_FreeValue(ctx, obj);
35637
0
    return JS_EXCEPTION;
35638
0
}
35639
35640
static JSValue JS_ReadArrayBuffer(BCReaderState *s)
35641
0
{
35642
0
    JSContext *ctx = s->ctx;
35643
0
    uint32_t byte_length;
35644
0
    JSValue obj;
35645
    
35646
0
    if (bc_get_leb128(s, &byte_length))
35647
0
        return JS_EXCEPTION;
35648
0
    if (unlikely(s->buf_end - s->ptr < byte_length)) {
35649
0
        bc_read_error_end(s);
35650
0
        return JS_EXCEPTION;
35651
0
    }
35652
0
    obj = JS_NewArrayBufferCopy(ctx, s->ptr, byte_length);
35653
0
    if (JS_IsException(obj))
35654
0
        goto fail;
35655
0
    if (BC_add_object_ref(s, obj))
35656
0
        goto fail;
35657
0
    s->ptr += byte_length;
35658
0
    return obj;
35659
0
 fail:
35660
0
    JS_FreeValue(ctx, obj);
35661
0
    return JS_EXCEPTION;
35662
0
}
35663
35664
static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s)
35665
0
{
35666
0
    JSContext *ctx = s->ctx;
35667
0
    uint32_t byte_length;
35668
0
    uint8_t *data_ptr;
35669
0
    JSValue obj;
35670
0
    uint64_t u64;
35671
    
35672
0
    if (bc_get_leb128(s, &byte_length))
35673
0
        return JS_EXCEPTION;
35674
0
    if (bc_get_u64(s, &u64))
35675
0
        return JS_EXCEPTION;
35676
0
    data_ptr = (uint8_t *)(uintptr_t)u64;
35677
    /* the SharedArrayBuffer is cloned */
35678
0
    obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED, byte_length,
35679
0
                                       JS_CLASS_SHARED_ARRAY_BUFFER,
35680
0
                                       data_ptr,
35681
0
                                       NULL, NULL, FALSE);
35682
0
    if (JS_IsException(obj))
35683
0
        goto fail;
35684
0
    if (BC_add_object_ref(s, obj))
35685
0
        goto fail;
35686
0
    return obj;
35687
0
 fail:
35688
0
    JS_FreeValue(ctx, obj);
35689
0
    return JS_EXCEPTION;
35690
0
}
35691
35692
static JSValue JS_ReadDate(BCReaderState *s)
35693
0
{
35694
0
    JSContext *ctx = s->ctx;
35695
0
    JSValue val, obj = JS_UNDEFINED;
35696
35697
0
    val = JS_ReadObjectRec(s);
35698
0
    if (JS_IsException(val))
35699
0
        goto fail;
35700
0
    if (!JS_IsNumber(val)) {
35701
0
        JS_ThrowTypeError(ctx, "Number tag expected for date");
35702
0
        goto fail;
35703
0
    }
35704
0
    obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_DATE],
35705
0
                                 JS_CLASS_DATE);
35706
0
    if (JS_IsException(obj))
35707
0
        goto fail;
35708
0
    if (BC_add_object_ref(s, obj))
35709
0
        goto fail;
35710
0
    JS_SetObjectData(ctx, obj, val);
35711
0
    return obj;
35712
0
 fail:
35713
0
    JS_FreeValue(ctx, val);
35714
0
    JS_FreeValue(ctx, obj);
35715
0
    return JS_EXCEPTION;
35716
0
}
35717
35718
static JSValue JS_ReadObjectValue(BCReaderState *s)
35719
0
{
35720
0
    JSContext *ctx = s->ctx;
35721
0
    JSValue val, obj = JS_UNDEFINED;
35722
35723
0
    val = JS_ReadObjectRec(s);
35724
0
    if (JS_IsException(val))
35725
0
        goto fail;
35726
0
    obj = JS_ToObject(ctx, val);
35727
0
    if (JS_IsException(obj))
35728
0
        goto fail;
35729
0
    if (BC_add_object_ref(s, obj))
35730
0
        goto fail;
35731
0
    JS_FreeValue(ctx, val);
35732
0
    return obj;
35733
0
 fail:
35734
0
    JS_FreeValue(ctx, val);
35735
0
    JS_FreeValue(ctx, obj);
35736
0
    return JS_EXCEPTION;
35737
0
}
35738
35739
static JSValue JS_ReadObjectRec(BCReaderState *s)
35740
4.01k
{
35741
4.01k
    JSContext *ctx = s->ctx;
35742
4.01k
    uint8_t tag;
35743
4.01k
    JSValue obj = JS_UNDEFINED;
35744
35745
4.01k
    if (js_check_stack_overflow(ctx->rt, 0))
35746
0
        return JS_ThrowStackOverflow(ctx);
35747
35748
4.01k
    if (bc_get_u8(s, &tag))
35749
0
        return JS_EXCEPTION;
35750
35751
4.01k
    bc_read_trace(s, "%s {\n", bc_tag_str[tag]);
35752
35753
4.01k
    switch(tag) {
35754
0
    case BC_TAG_NULL:
35755
0
        obj = JS_NULL;
35756
0
        break;
35757
600
    case BC_TAG_UNDEFINED:
35758
600
        obj = JS_UNDEFINED;
35759
600
        break;
35760
0
    case BC_TAG_BOOL_FALSE:
35761
0
    case BC_TAG_BOOL_TRUE:
35762
0
        obj = JS_NewBool(ctx, tag - BC_TAG_BOOL_FALSE);
35763
0
        break;
35764
0
    case BC_TAG_INT32:
35765
0
        {
35766
0
            int32_t val;
35767
0
            if (bc_get_sleb128(s, &val))
35768
0
                return JS_EXCEPTION;
35769
0
            bc_read_trace(s, "%d\n", val);
35770
0
            obj = JS_NewInt32(ctx, val);
35771
0
        }
35772
0
        break;
35773
87
    case BC_TAG_FLOAT64:
35774
87
        {
35775
87
            JSFloat64Union u;
35776
87
            if (bc_get_u64(s, &u.u64))
35777
0
                return JS_EXCEPTION;
35778
87
            bc_read_trace(s, "%g\n", u.d);
35779
87
            obj = __JS_NewFloat64(ctx, u.d);
35780
87
        }
35781
0
        break;
35782
1.36k
    case BC_TAG_STRING:
35783
1.36k
        {
35784
1.36k
            JSString *p;
35785
1.36k
            p = JS_ReadString(s);
35786
1.36k
            if (!p)
35787
0
                return JS_EXCEPTION;
35788
1.36k
            obj = JS_MKPTR(JS_TAG_STRING, p);
35789
1.36k
        }
35790
0
        break;
35791
541
    case BC_TAG_FUNCTION_BYTECODE:
35792
541
        if (!s->allow_bytecode)
35793
0
            goto invalid_tag;
35794
541
        obj = JS_ReadFunctionTag(s);
35795
541
        break;
35796
121
    case BC_TAG_MODULE:
35797
121
        if (!s->allow_bytecode)
35798
0
            goto invalid_tag;
35799
121
        obj = JS_ReadModule(s);
35800
121
        break;
35801
0
    case BC_TAG_OBJECT:
35802
0
        obj = JS_ReadObjectTag(s);
35803
0
        break;
35804
0
    case BC_TAG_ARRAY:
35805
1.18k
    case BC_TAG_TEMPLATE_OBJECT:
35806
1.18k
        obj = JS_ReadArray(s, tag);
35807
1.18k
        break;
35808
0
    case BC_TAG_TYPED_ARRAY:
35809
0
        obj = JS_ReadTypedArray(s);
35810
0
        break;
35811
0
    case BC_TAG_ARRAY_BUFFER:
35812
0
        obj = JS_ReadArrayBuffer(s);
35813
0
        break;
35814
0
    case BC_TAG_SHARED_ARRAY_BUFFER:
35815
0
        if (!s->allow_sab || !ctx->rt->sab_funcs.sab_dup)
35816
0
            goto invalid_tag;
35817
0
        obj = JS_ReadSharedArrayBuffer(s);
35818
0
        break;
35819
0
    case BC_TAG_DATE:
35820
0
        obj = JS_ReadDate(s);
35821
0
        break;
35822
0
    case BC_TAG_OBJECT_VALUE:
35823
0
        obj = JS_ReadObjectValue(s);
35824
0
        break;
35825
0
#ifdef CONFIG_BIGNUM
35826
111
    case BC_TAG_BIG_INT:
35827
111
    case BC_TAG_BIG_FLOAT:
35828
111
    case BC_TAG_BIG_DECIMAL:
35829
111
        obj = JS_ReadBigNum(s, tag);
35830
111
        break;
35831
0
#endif
35832
0
    case BC_TAG_OBJECT_REFERENCE:
35833
0
        {
35834
0
            uint32_t val;
35835
0
            if (!s->allow_reference)
35836
0
                return JS_ThrowSyntaxError(ctx, "object references are not allowed");
35837
0
            if (bc_get_leb128(s, &val))
35838
0
                return JS_EXCEPTION;
35839
0
            bc_read_trace(s, "%u\n", val);
35840
0
            if (val >= s->objects_count) {
35841
0
                return JS_ThrowSyntaxError(ctx, "invalid object reference (%u >= %u)",
35842
0
                                           val, s->objects_count);
35843
0
            }
35844
0
            obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, s->objects[val]));
35845
0
        }
35846
0
        break;
35847
0
    default:
35848
0
    invalid_tag:
35849
0
        return JS_ThrowSyntaxError(ctx, "invalid tag (tag=%d pos=%u)",
35850
0
                                   tag, (unsigned int)(s->ptr - s->buf_start));
35851
4.01k
    }
35852
4.01k
    bc_read_trace(s, "}\n");
35853
4.01k
    return obj;
35854
4.01k
}
35855
35856
static int JS_ReadObjectAtoms(BCReaderState *s)
35857
121
{
35858
121
    uint8_t v8;
35859
121
    JSString *p;
35860
121
    int i;
35861
121
    JSAtom atom;
35862
35863
121
    if (bc_get_u8(s, &v8))
35864
0
        return -1;
35865
    /* XXX: could support byte swapped input */
35866
121
    if (v8 != BC_VERSION) {
35867
0
        JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)",
35868
0
                            v8, BC_VERSION);
35869
0
        return -1;
35870
0
    }
35871
121
    if (bc_get_leb128(s, &s->idx_to_atom_count))
35872
0
        return -1;
35873
35874
121
    bc_read_trace(s, "%d atom indexes {\n", s->idx_to_atom_count);
35875
35876
121
    if (s->idx_to_atom_count != 0) {
35877
121
        s->idx_to_atom = js_mallocz(s->ctx, s->idx_to_atom_count *
35878
121
                                    sizeof(s->idx_to_atom[0]));
35879
121
        if (!s->idx_to_atom)
35880
0
            return s->error_state = -1;
35881
121
    }
35882
735
    for(i = 0; i < s->idx_to_atom_count; i++) {
35883
614
        p = JS_ReadString(s);
35884
614
        if (!p)
35885
0
            return -1;
35886
614
        atom = JS_NewAtomStr(s->ctx, p);
35887
614
        if (atom == JS_ATOM_NULL)
35888
0
            return s->error_state = -1;
35889
614
        s->idx_to_atom[i] = atom;
35890
614
        if (s->is_rom_data && (atom != (i + s->first_atom)))
35891
0
            s->is_rom_data = FALSE; /* atoms must be relocated */
35892
614
    }
35893
121
    bc_read_trace(s, "}\n");
35894
121
    return 0;
35895
121
}
35896
35897
static void bc_reader_free(BCReaderState *s)
35898
121
{
35899
121
    int i;
35900
121
    if (s->idx_to_atom) {
35901
735
        for(i = 0; i < s->idx_to_atom_count; i++) {
35902
614
            JS_FreeAtom(s->ctx, s->idx_to_atom[i]);
35903
614
        }
35904
121
        js_free(s->ctx, s->idx_to_atom);
35905
121
    }
35906
121
    js_free(s->ctx, s->objects);
35907
121
}
35908
35909
JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
35910
                       int flags)
35911
121
{
35912
121
    BCReaderState ss, *s = &ss;
35913
121
    JSValue obj;
35914
35915
121
    ctx->binary_object_count += 1;
35916
121
    ctx->binary_object_size += buf_len;
35917
35918
121
    memset(s, 0, sizeof(*s));
35919
121
    s->ctx = ctx;
35920
121
    s->buf_start = buf;
35921
121
    s->buf_end = buf + buf_len;
35922
121
    s->ptr = buf;
35923
121
    s->allow_bytecode = ((flags & JS_READ_OBJ_BYTECODE) != 0);
35924
121
    s->is_rom_data = ((flags & JS_READ_OBJ_ROM_DATA) != 0);
35925
121
    s->allow_sab = ((flags & JS_READ_OBJ_SAB) != 0);
35926
121
    s->allow_reference = ((flags & JS_READ_OBJ_REFERENCE) != 0);
35927
121
    if (s->allow_bytecode)
35928
121
        s->first_atom = JS_ATOM_END;
35929
0
    else
35930
0
        s->first_atom = 1;
35931
121
    if (JS_ReadObjectAtoms(s)) {
35932
0
        obj = JS_EXCEPTION;
35933
121
    } else {
35934
121
        obj = JS_ReadObjectRec(s);
35935
121
    }
35936
121
    bc_reader_free(s);
35937
121
    return obj;
35938
121
}
35939
35940
/*******************************************************************/
35941
/* runtime functions & objects */
35942
35943
static JSValue js_string_constructor(JSContext *ctx, JSValueConst this_val,
35944
                                     int argc, JSValueConst *argv);
35945
static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst this_val,
35946
                                      int argc, JSValueConst *argv);
35947
static JSValue js_number_constructor(JSContext *ctx, JSValueConst this_val,
35948
                                     int argc, JSValueConst *argv);
35949
35950
static int check_function(JSContext *ctx, JSValueConst obj)
35951
704k
{
35952
704k
    if (likely(JS_IsFunction(ctx, obj)))
35953
704k
        return 0;
35954
0
    JS_ThrowTypeError(ctx, "not a function");
35955
0
    return -1;
35956
704k
}
35957
35958
static int check_exception_free(JSContext *ctx, JSValue obj)
35959
0
{
35960
0
    JS_FreeValue(ctx, obj);
35961
0
    return JS_IsException(obj);
35962
0
}
35963
35964
static JSAtom find_atom(JSContext *ctx, const char *name)
35965
829
{
35966
829
    JSAtom atom;
35967
829
    int len;
35968
35969
829
    if (*name == '[') {
35970
88
        name++;
35971
88
        len = strlen(name) - 1;
35972
        /* We assume 8 bit non null strings, which is the case for these
35973
           symbols */
35974
636
        for(atom = JS_ATOM_Symbol_toPrimitive; atom < JS_ATOM_END; atom++) {
35975
636
            JSAtomStruct *p = ctx->rt->atom_array[atom];
35976
636
            JSString *str = p;
35977
636
            if (str->len == len && !memcmp(str->u.str8, name, len))
35978
88
                return JS_DupAtom(ctx, atom);
35979
636
        }
35980
0
        abort();
35981
741
    } else {
35982
741
        atom = JS_NewAtom(ctx, name);
35983
741
    }
35984
741
    return atom;
35985
829
}
35986
35987
static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
35988
                                               JSAtom atom, void *opaque)
35989
55
{
35990
55
    const JSCFunctionListEntry *e = opaque;
35991
55
    JSValue val;
35992
35993
55
    switch(e->def_type) {
35994
53
    case JS_DEF_CFUNC:
35995
53
        val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
35996
53
                               e->name, e->u.func.length, e->u.func.cproto, e->magic);
35997
53
        break;
35998
2
    case JS_DEF_PROP_STRING:
35999
2
        val = JS_NewAtomString(ctx, e->u.str);
36000
2
        break;
36001
0
    case JS_DEF_OBJECT:
36002
0
        val = JS_NewObject(ctx);
36003
0
        JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
36004
0
        break;
36005
0
    default:
36006
0
        abort();
36007
55
    }
36008
55
    return val;
36009
55
}
36010
36011
static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
36012
                                          JSAtom atom,
36013
                                          const JSCFunctionListEntry *e)
36014
809
{
36015
809
    JSValue val;
36016
809
    int prop_flags = e->prop_flags;
36017
36018
809
    switch(e->def_type) {
36019
20
    case JS_DEF_ALIAS: /* using autoinit for aliases is not safe */
36020
20
        {
36021
20
            JSAtom atom1 = find_atom(ctx, e->u.alias.name);
36022
20
            switch (e->u.alias.base) {
36023
16
            case -1:
36024
16
                val = JS_GetProperty(ctx, obj, atom1);
36025
16
                break;
36026
4
            case 0:
36027
4
                val = JS_GetProperty(ctx, ctx->global_obj, atom1);
36028
4
                break;
36029
0
            case 1:
36030
0
                val = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], atom1);
36031
0
                break;
36032
0
            default:
36033
0
                abort();
36034
20
            }
36035
20
            JS_FreeAtom(ctx, atom1);
36036
20
            if (atom == JS_ATOM_Symbol_toPrimitive) {
36037
                /* Symbol.toPrimitive functions are not writable */
36038
0
                prop_flags = JS_PROP_CONFIGURABLE;
36039
20
            } else if (atom == JS_ATOM_Symbol_hasInstance) {
36040
                /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
36041
0
                prop_flags = 0;
36042
0
            }
36043
20
        }
36044
0
        break;
36045
647
    case JS_DEF_CFUNC:
36046
647
        if (atom == JS_ATOM_Symbol_toPrimitive) {
36047
            /* Symbol.toPrimitive functions are not writable */
36048
4
            prop_flags = JS_PROP_CONFIGURABLE;
36049
643
        } else if (atom == JS_ATOM_Symbol_hasInstance) {
36050
            /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
36051
2
            prop_flags = 0;
36052
2
        }
36053
647
        JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
36054
647
                                  (void *)e, prop_flags);
36055
647
        return 0;
36056
32
    case JS_DEF_CGETSET: /* XXX: use autoinit again ? */
36057
64
    case JS_DEF_CGETSET_MAGIC:
36058
64
        {
36059
64
            JSValue getter, setter;
36060
64
            char buf[64];
36061
36062
64
            getter = JS_UNDEFINED;
36063
64
            if (e->u.getset.get.generic) {
36064
64
                snprintf(buf, sizeof(buf), "get %s", e->name);
36065
64
                getter = JS_NewCFunction2(ctx, e->u.getset.get.generic,
36066
64
                                          buf, 0, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_getter_magic : JS_CFUNC_getter,
36067
64
                                          e->magic);
36068
64
            }
36069
64
            setter = JS_UNDEFINED;
36070
64
            if (e->u.getset.set.generic) {
36071
2
                snprintf(buf, sizeof(buf), "set %s", e->name);
36072
2
                setter = JS_NewCFunction2(ctx, e->u.getset.set.generic,
36073
2
                                          buf, 1, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_setter_magic : JS_CFUNC_setter,
36074
2
                                          e->magic);
36075
2
            }
36076
64
            JS_DefinePropertyGetSet(ctx, obj, atom, getter, setter, prop_flags);
36077
64
            return 0;
36078
32
        }
36079
0
        break;
36080
2
    case JS_DEF_PROP_INT32:
36081
2
        val = JS_NewInt32(ctx, e->u.i32);
36082
2
        break;
36083
0
    case JS_DEF_PROP_INT64:
36084
0
        val = JS_NewInt64(ctx, e->u.i64);
36085
0
        break;
36086
20
    case JS_DEF_PROP_DOUBLE:
36087
20
        val = __JS_NewFloat64(ctx, e->u.f64);
36088
20
        break;
36089
2
    case JS_DEF_PROP_UNDEFINED:
36090
2
        val = JS_UNDEFINED;
36091
2
        break;
36092
46
    case JS_DEF_PROP_STRING:
36093
54
    case JS_DEF_OBJECT:
36094
54
        JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
36095
54
                                  (void *)e, prop_flags);
36096
54
        return 0;
36097
0
    default:
36098
0
        abort();
36099
809
    }
36100
44
    JS_DefinePropertyValue(ctx, obj, atom, val, prop_flags);
36101
44
    return 0;
36102
809
}
36103
36104
void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
36105
                                const JSCFunctionListEntry *tab, int len)
36106
109
{
36107
109
    int i;
36108
36109
918
    for (i = 0; i < len; i++) {
36110
809
        const JSCFunctionListEntry *e = &tab[i];
36111
809
        JSAtom atom = find_atom(ctx, e->name);
36112
809
        JS_InstantiateFunctionListItem(ctx, obj, atom, e);
36113
809
        JS_FreeAtom(ctx, atom);
36114
809
    }
36115
109
}
36116
36117
int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,
36118
                           const JSCFunctionListEntry *tab, int len)
36119
0
{
36120
0
    int i;
36121
0
    for(i = 0; i < len; i++) {
36122
0
        if (JS_AddModuleExport(ctx, m, tab[i].name))
36123
0
            return -1;
36124
0
    }
36125
0
    return 0;
36126
0
}
36127
36128
int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
36129
                           const JSCFunctionListEntry *tab, int len)
36130
0
{
36131
0
    int i;
36132
0
    JSValue val;
36133
36134
0
    for(i = 0; i < len; i++) {
36135
0
        const JSCFunctionListEntry *e = &tab[i];
36136
0
        switch(e->def_type) {
36137
0
        case JS_DEF_CFUNC:
36138
0
            val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
36139
0
                                   e->name, e->u.func.length, e->u.func.cproto, e->magic);
36140
0
            break;
36141
0
        case JS_DEF_PROP_STRING:
36142
0
            val = JS_NewString(ctx, e->u.str);
36143
0
            break;
36144
0
        case JS_DEF_PROP_INT32:
36145
0
            val = JS_NewInt32(ctx, e->u.i32);
36146
0
            break;
36147
0
        case JS_DEF_PROP_INT64:
36148
0
            val = JS_NewInt64(ctx, e->u.i64);
36149
0
            break;
36150
0
        case JS_DEF_PROP_DOUBLE:
36151
0
            val = __JS_NewFloat64(ctx, e->u.f64);
36152
0
            break;
36153
0
        case JS_DEF_OBJECT:
36154
0
            val = JS_NewObject(ctx);
36155
0
            JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
36156
0
            break;
36157
0
        default:
36158
0
            abort();
36159
0
        }
36160
0
        if (JS_SetModuleExport(ctx, m, e->name, val))
36161
0
            return -1;
36162
0
    }
36163
0
    return 0;
36164
0
}
36165
36166
/* Note: 'func_obj' is not necessarily a constructor */
36167
static void JS_SetConstructor2(JSContext *ctx,
36168
                               JSValueConst func_obj,
36169
                               JSValueConst proto,
36170
                               int proto_flags, int ctor_flags)
36171
88
{
36172
88
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype,
36173
88
                           JS_DupValue(ctx, proto), proto_flags);
36174
88
    JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
36175
88
                           JS_DupValue(ctx, func_obj),
36176
88
                           ctor_flags);
36177
88
    set_cycle_flag(ctx, func_obj);
36178
88
    set_cycle_flag(ctx, proto);
36179
88
}
36180
36181
void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, 
36182
                       JSValueConst proto)
36183
78
{
36184
78
    JS_SetConstructor2(ctx, func_obj, proto,
36185
78
                       0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
36186
78
}
36187
36188
static void JS_NewGlobalCConstructor2(JSContext *ctx,
36189
                                      JSValue func_obj,
36190
                                      const char *name,
36191
                                      JSValueConst proto)
36192
76
{
36193
76
    JS_DefinePropertyValueStr(ctx, ctx->global_obj, name,
36194
76
                           JS_DupValue(ctx, func_obj),
36195
76
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
36196
76
    JS_SetConstructor(ctx, func_obj, proto);
36197
76
    JS_FreeValue(ctx, func_obj);
36198
76
}
36199
36200
static JSValueConst JS_NewGlobalCConstructor(JSContext *ctx, const char *name,
36201
                                             JSCFunction *func, int length,
36202
                                             JSValueConst proto)
36203
18
{
36204
18
    JSValue func_obj;
36205
18
    func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor_or_func, 0);
36206
18
    JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
36207
18
    return func_obj;
36208
18
}
36209
36210
static JSValueConst JS_NewGlobalCConstructorOnly(JSContext *ctx, const char *name,
36211
                                                 JSCFunction *func, int length,
36212
                                                 JSValueConst proto)
36213
6
{
36214
6
    JSValue func_obj;
36215
6
    func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor, 0);
36216
6
    JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
36217
6
    return func_obj;
36218
6
}
36219
36220
static JSValue js_global_eval(JSContext *ctx, JSValueConst this_val,
36221
                              int argc, JSValueConst *argv)
36222
0
{
36223
0
    return JS_EvalObject(ctx, ctx->global_obj, argv[0], JS_EVAL_TYPE_INDIRECT, -1);
36224
0
}
36225
36226
static JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val,
36227
                               int argc, JSValueConst *argv)
36228
0
{
36229
0
    double d;
36230
36231
    /* XXX: does this work for bigfloat? */
36232
0
    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
36233
0
        return JS_EXCEPTION;
36234
0
    return JS_NewBool(ctx, isnan(d));
36235
0
}
36236
36237
static JSValue js_global_isFinite(JSContext *ctx, JSValueConst this_val,
36238
                                  int argc, JSValueConst *argv)
36239
0
{
36240
0
    BOOL res;
36241
0
    double d;
36242
0
    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
36243
0
        return JS_EXCEPTION;
36244
0
    res = isfinite(d);
36245
0
    return JS_NewBool(ctx, res);
36246
0
}
36247
36248
/* Object class */
36249
36250
static JSValue JS_ToObject(JSContext *ctx, JSValueConst val)
36251
3.77M
{
36252
3.77M
    int tag = JS_VALUE_GET_NORM_TAG(val);
36253
3.77M
    JSValue obj;
36254
36255
3.77M
    switch(tag) {
36256
0
    default:
36257
0
    case JS_TAG_NULL:
36258
32
    case JS_TAG_UNDEFINED:
36259
32
        return JS_ThrowTypeError(ctx, "cannot convert to object");
36260
2.48M
    case JS_TAG_OBJECT:
36261
2.48M
    case JS_TAG_EXCEPTION:
36262
2.48M
        return JS_DupValue(ctx, val);
36263
0
#ifdef CONFIG_BIGNUM
36264
280
    case JS_TAG_BIG_INT:
36265
280
        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
36266
280
        goto set_value;
36267
0
    case JS_TAG_BIG_FLOAT:
36268
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT);
36269
0
        goto set_value;
36270
0
    case JS_TAG_BIG_DECIMAL:
36271
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_DECIMAL);
36272
0
        goto set_value;
36273
0
#endif
36274
18.6k
    case JS_TAG_INT:
36275
730k
    case JS_TAG_FLOAT64:
36276
730k
        obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
36277
730k
        goto set_value;
36278
560k
    case JS_TAG_STRING:
36279
        /* XXX: should call the string constructor */
36280
560k
        {
36281
560k
            JSString *p1 = JS_VALUE_GET_STRING(val);
36282
560k
            obj = JS_NewObjectClass(ctx, JS_CLASS_STRING);
36283
560k
            JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
36284
560k
        }
36285
560k
        goto set_value;
36286
1.04k
    case JS_TAG_BOOL:
36287
1.04k
        obj = JS_NewObjectClass(ctx, JS_CLASS_BOOLEAN);
36288
1.04k
        goto set_value;
36289
2
    case JS_TAG_SYMBOL:
36290
2
        obj = JS_NewObjectClass(ctx, JS_CLASS_SYMBOL);
36291
1.29M
    set_value:
36292
1.29M
        if (!JS_IsException(obj))
36293
1.29M
            JS_SetObjectData(ctx, obj, JS_DupValue(ctx, val));
36294
1.29M
        return obj;
36295
3.77M
    }
36296
3.77M
}
36297
36298
static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val)
36299
80.4k
{
36300
80.4k
    JSValue obj = JS_ToObject(ctx, val);
36301
80.4k
    JS_FreeValue(ctx, val);
36302
80.4k
    return obj;
36303
80.4k
}
36304
36305
static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
36306
                          JSValueConst desc)
36307
0
{
36308
0
    JSValue val, getter, setter;
36309
0
    int flags;
36310
36311
0
    if (!JS_IsObject(desc)) {
36312
0
        JS_ThrowTypeErrorNotAnObject(ctx);
36313
0
        return -1;
36314
0
    }
36315
0
    flags = 0;
36316
0
    val = JS_UNDEFINED;
36317
0
    getter = JS_UNDEFINED;
36318
0
    setter = JS_UNDEFINED;
36319
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_configurable)) {
36320
0
        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable);
36321
0
        if (JS_IsException(prop))
36322
0
            goto fail;
36323
0
        flags |= JS_PROP_HAS_CONFIGURABLE;
36324
0
        if (JS_ToBoolFree(ctx, prop))
36325
0
            flags |= JS_PROP_CONFIGURABLE;
36326
0
    }
36327
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_writable)) {
36328
0
        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable);
36329
0
        if (JS_IsException(prop))
36330
0
            goto fail;
36331
0
        flags |= JS_PROP_HAS_WRITABLE;
36332
0
        if (JS_ToBoolFree(ctx, prop))
36333
0
            flags |= JS_PROP_WRITABLE;
36334
0
    }
36335
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_enumerable)) {
36336
0
        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable);
36337
0
        if (JS_IsException(prop))
36338
0
            goto fail;
36339
0
        flags |= JS_PROP_HAS_ENUMERABLE;
36340
0
        if (JS_ToBoolFree(ctx, prop))
36341
0
            flags |= JS_PROP_ENUMERABLE;
36342
0
    }
36343
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_value)) {
36344
0
        flags |= JS_PROP_HAS_VALUE;
36345
0
        val = JS_GetProperty(ctx, desc, JS_ATOM_value);
36346
0
        if (JS_IsException(val))
36347
0
            goto fail;
36348
0
    }
36349
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_get)) {
36350
0
        flags |= JS_PROP_HAS_GET;
36351
0
        getter = JS_GetProperty(ctx, desc, JS_ATOM_get);
36352
0
        if (JS_IsException(getter) ||
36353
0
            !(JS_IsUndefined(getter) || JS_IsFunction(ctx, getter))) {
36354
0
            JS_ThrowTypeError(ctx, "invalid getter");
36355
0
            goto fail;
36356
0
        }
36357
0
    }
36358
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_set)) {
36359
0
        flags |= JS_PROP_HAS_SET;
36360
0
        setter = JS_GetProperty(ctx, desc, JS_ATOM_set);
36361
0
        if (JS_IsException(setter) ||
36362
0
            !(JS_IsUndefined(setter) || JS_IsFunction(ctx, setter))) {
36363
0
            JS_ThrowTypeError(ctx, "invalid setter");
36364
0
            goto fail;
36365
0
        }
36366
0
    }
36367
0
    if ((flags & (JS_PROP_HAS_SET | JS_PROP_HAS_GET)) &&
36368
0
        (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE))) {
36369
0
        JS_ThrowTypeError(ctx, "cannot have setter/getter and value or writable");
36370
0
        goto fail;
36371
0
    }
36372
0
    d->flags = flags;
36373
0
    d->value = val;
36374
0
    d->getter = getter;
36375
0
    d->setter = setter;
36376
0
    return 0;
36377
0
 fail:
36378
0
    JS_FreeValue(ctx, val);
36379
0
    JS_FreeValue(ctx, getter);
36380
0
    JS_FreeValue(ctx, setter);
36381
0
    return -1;
36382
0
}
36383
36384
static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
36385
                                             JSAtom prop, JSValueConst desc,
36386
                                             int flags)
36387
0
{
36388
0
    JSPropertyDescriptor d;
36389
0
    int ret;
36390
36391
0
    if (js_obj_to_desc(ctx, &d, desc) < 0)
36392
0
        return -1;
36393
36394
0
    ret = JS_DefineProperty(ctx, obj, prop,
36395
0
                            d.value, d.getter, d.setter, d.flags | flags);
36396
0
    js_free_desc(ctx, &d);
36397
0
    return ret;
36398
0
}
36399
36400
static __exception int JS_ObjectDefineProperties(JSContext *ctx,
36401
                                                 JSValueConst obj,
36402
                                                 JSValueConst properties)
36403
0
{
36404
0
    JSValue props, desc;
36405
0
    JSObject *p;
36406
0
    JSPropertyEnum *atoms;
36407
0
    uint32_t len, i;
36408
0
    int ret = -1;
36409
36410
0
    if (!JS_IsObject(obj)) {
36411
0
        JS_ThrowTypeErrorNotAnObject(ctx);
36412
0
        return -1;
36413
0
    }
36414
0
    desc = JS_UNDEFINED;
36415
0
    props = JS_ToObject(ctx, properties);
36416
0
    if (JS_IsException(props))
36417
0
        return -1;
36418
0
    p = JS_VALUE_GET_OBJ(props);
36419
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) < 0)
36420
0
        goto exception;
36421
0
    for(i = 0; i < len; i++) {
36422
0
        JS_FreeValue(ctx, desc);
36423
0
        desc = JS_GetProperty(ctx, props, atoms[i].atom);
36424
0
        if (JS_IsException(desc))
36425
0
            goto exception;
36426
0
        if (JS_DefinePropertyDesc(ctx, obj, atoms[i].atom, desc, JS_PROP_THROW) < 0)
36427
0
            goto exception;
36428
0
    }
36429
0
    ret = 0;
36430
36431
0
exception:
36432
0
    js_free_prop_enum(ctx, atoms, len);
36433
0
    JS_FreeValue(ctx, props);
36434
0
    JS_FreeValue(ctx, desc);
36435
0
    return ret;
36436
0
}
36437
36438
static JSValue js_object_constructor(JSContext *ctx, JSValueConst new_target,
36439
                                     int argc, JSValueConst *argv)
36440
0
{
36441
0
    JSValue ret;
36442
0
    if (!JS_IsUndefined(new_target) &&
36443
0
        JS_VALUE_GET_OBJ(new_target) !=
36444
0
        JS_VALUE_GET_OBJ(JS_GetActiveFunction(ctx))) {
36445
0
        ret = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
36446
0
    } else {
36447
0
        int tag = JS_VALUE_GET_NORM_TAG(argv[0]);
36448
0
        switch(tag) {
36449
0
        case JS_TAG_NULL:
36450
0
        case JS_TAG_UNDEFINED:
36451
0
            ret = JS_NewObject(ctx);
36452
0
            break;
36453
0
        default:
36454
0
            ret = JS_ToObject(ctx, argv[0]);
36455
0
            break;
36456
0
        }
36457
0
    }
36458
0
    return ret;
36459
0
}
36460
36461
static JSValue js_object_create(JSContext *ctx, JSValueConst this_val,
36462
                                int argc, JSValueConst *argv)
36463
0
{
36464
0
    JSValueConst proto, props;
36465
0
    JSValue obj;
36466
36467
0
    proto = argv[0];
36468
0
    if (!JS_IsObject(proto) && !JS_IsNull(proto))
36469
0
        return JS_ThrowTypeError(ctx, "not a prototype");
36470
0
    obj = JS_NewObjectProto(ctx, proto);
36471
0
    if (JS_IsException(obj))
36472
0
        return JS_EXCEPTION;
36473
0
    props = argv[1];
36474
0
    if (!JS_IsUndefined(props)) {
36475
0
        if (JS_ObjectDefineProperties(ctx, obj, props)) {
36476
0
            JS_FreeValue(ctx, obj);
36477
0
            return JS_EXCEPTION;
36478
0
        }
36479
0
    }
36480
0
    return obj;
36481
0
}
36482
36483
static JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val,
36484
                                        int argc, JSValueConst *argv, int magic)
36485
0
{
36486
0
    JSValueConst val;
36487
36488
0
    val = argv[0];
36489
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) {
36490
        /* ES6 feature non compatible with ES5.1: primitive types are
36491
           accepted */
36492
0
        if (magic || JS_VALUE_GET_TAG(val) == JS_TAG_NULL ||
36493
0
            JS_VALUE_GET_TAG(val) == JS_TAG_UNDEFINED)
36494
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
36495
0
    }
36496
0
    return JS_GetPrototype(ctx, val);
36497
0
}
36498
36499
static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
36500
                                        int argc, JSValueConst *argv)
36501
0
{
36502
0
    JSValueConst obj;
36503
0
    obj = argv[0];
36504
0
    if (JS_SetPrototypeInternal(ctx, obj, argv[1], TRUE) < 0)
36505
0
        return JS_EXCEPTION;
36506
0
    return JS_DupValue(ctx, obj);
36507
0
}
36508
36509
/* magic = 1 if called as Reflect.defineProperty */
36510
static JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val,
36511
                                        int argc, JSValueConst *argv, int magic)
36512
0
{
36513
0
    JSValueConst obj, prop, desc;
36514
0
    int ret, flags;
36515
0
    JSAtom atom;
36516
36517
0
    obj = argv[0];
36518
0
    prop = argv[1];
36519
0
    desc = argv[2];
36520
36521
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
36522
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
36523
0
    atom = JS_ValueToAtom(ctx, prop);
36524
0
    if (unlikely(atom == JS_ATOM_NULL))
36525
0
        return JS_EXCEPTION;
36526
0
    flags = 0;
36527
0
    if (!magic)
36528
0
        flags |= JS_PROP_THROW;
36529
0
    ret = JS_DefinePropertyDesc(ctx, obj, atom, desc, flags);
36530
0
    JS_FreeAtom(ctx, atom);
36531
0
    if (ret < 0) {
36532
0
        return JS_EXCEPTION;
36533
0
    } else if (magic) {
36534
0
        return JS_NewBool(ctx, ret);
36535
0
    } else {
36536
0
        return JS_DupValue(ctx, obj);
36537
0
    }
36538
0
}
36539
36540
static JSValue js_object_defineProperties(JSContext *ctx, JSValueConst this_val,
36541
                                          int argc, JSValueConst *argv)
36542
0
{
36543
    // defineProperties(obj, properties)
36544
0
    JSValueConst obj = argv[0];
36545
36546
0
    if (JS_ObjectDefineProperties(ctx, obj, argv[1]))
36547
0
        return JS_EXCEPTION;
36548
0
    else
36549
0
        return JS_DupValue(ctx, obj);
36550
0
}
36551
36552
/* magic = 1 if called as __defineSetter__ */
36553
static JSValue js_object___defineGetter__(JSContext *ctx, JSValueConst this_val,
36554
                                          int argc, JSValueConst *argv, int magic)
36555
0
{
36556
0
    JSValue obj;
36557
0
    JSValueConst prop, value, get, set;
36558
0
    int ret, flags;
36559
0
    JSAtom atom;
36560
36561
0
    prop = argv[0];
36562
0
    value = argv[1];
36563
36564
0
    obj = JS_ToObject(ctx, this_val);
36565
0
    if (JS_IsException(obj))
36566
0
        return JS_EXCEPTION;
36567
36568
0
    if (check_function(ctx, value)) {
36569
0
        JS_FreeValue(ctx, obj);
36570
0
        return JS_EXCEPTION;
36571
0
    }
36572
0
    atom = JS_ValueToAtom(ctx, prop);
36573
0
    if (unlikely(atom == JS_ATOM_NULL)) {
36574
0
        JS_FreeValue(ctx, obj);
36575
0
        return JS_EXCEPTION;
36576
0
    }
36577
0
    flags = JS_PROP_THROW |
36578
0
        JS_PROP_HAS_ENUMERABLE | JS_PROP_ENUMERABLE |
36579
0
        JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE;
36580
0
    if (magic) {
36581
0
        get = JS_UNDEFINED;
36582
0
        set = value;
36583
0
        flags |= JS_PROP_HAS_SET;
36584
0
    } else {
36585
0
        get = value;
36586
0
        set = JS_UNDEFINED;
36587
0
        flags |= JS_PROP_HAS_GET;
36588
0
    }
36589
0
    ret = JS_DefineProperty(ctx, obj, atom, JS_UNDEFINED, get, set, flags);
36590
0
    JS_FreeValue(ctx, obj);
36591
0
    JS_FreeAtom(ctx, atom);
36592
0
    if (ret < 0) {
36593
0
        return JS_EXCEPTION;
36594
0
    } else {
36595
0
        return JS_UNDEFINED;
36596
0
    }
36597
0
}
36598
36599
static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst this_val,
36600
                                                  int argc, JSValueConst *argv, int magic)
36601
0
{
36602
0
    JSValueConst prop;
36603
0
    JSAtom atom;
36604
0
    JSValue ret, obj;
36605
0
    JSPropertyDescriptor desc;
36606
0
    int res, flags;
36607
36608
0
    if (magic) {
36609
        /* Reflect.getOwnPropertyDescriptor case */
36610
0
        if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
36611
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
36612
0
        obj = JS_DupValue(ctx, argv[0]);
36613
0
    } else {
36614
0
        obj = JS_ToObject(ctx, argv[0]);
36615
0
        if (JS_IsException(obj))
36616
0
            return obj;
36617
0
    }
36618
0
    prop = argv[1];
36619
0
    atom = JS_ValueToAtom(ctx, prop);
36620
0
    if (unlikely(atom == JS_ATOM_NULL))
36621
0
        goto exception;
36622
0
    ret = JS_UNDEFINED;
36623
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
36624
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), atom);
36625
0
        if (res < 0)
36626
0
            goto exception;
36627
0
        if (res) {
36628
0
            ret = JS_NewObject(ctx);
36629
0
            if (JS_IsException(ret))
36630
0
                goto exception1;
36631
0
            flags = JS_PROP_C_W_E | JS_PROP_THROW;
36632
0
            if (desc.flags & JS_PROP_GETSET) {
36633
0
                if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, desc.getter), flags) < 0
36634
0
                ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, desc.setter), flags) < 0)
36635
0
                    goto exception1;
36636
0
            } else {
36637
0
                if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, desc.value), flags) < 0
36638
0
                ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
36639
0
                                           JS_NewBool(ctx, (desc.flags & JS_PROP_WRITABLE) != 0), flags) < 0)
36640
0
                    goto exception1;
36641
0
            }
36642
0
            if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
36643
0
                                       JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0), flags) < 0
36644
0
            ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
36645
0
                                       JS_NewBool(ctx, (desc.flags & JS_PROP_CONFIGURABLE) != 0), flags) < 0)
36646
0
                goto exception1;
36647
0
            js_free_desc(ctx, &desc);
36648
0
        }
36649
0
    }
36650
0
    JS_FreeAtom(ctx, atom);
36651
0
    JS_FreeValue(ctx, obj);
36652
0
    return ret;
36653
36654
0
exception1:
36655
0
    js_free_desc(ctx, &desc);
36656
0
    JS_FreeValue(ctx, ret);
36657
0
exception:
36658
0
    JS_FreeAtom(ctx, atom);
36659
0
    JS_FreeValue(ctx, obj);
36660
0
    return JS_EXCEPTION;
36661
0
}
36662
36663
static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst this_val,
36664
                                                   int argc, JSValueConst *argv)
36665
0
{
36666
    //getOwnPropertyDescriptors(obj)
36667
0
    JSValue obj, r;
36668
0
    JSObject *p;
36669
0
    JSPropertyEnum *props;
36670
0
    uint32_t len, i;
36671
36672
0
    r = JS_UNDEFINED;
36673
0
    obj = JS_ToObject(ctx, argv[0]);
36674
0
    if (JS_IsException(obj))
36675
0
        return JS_EXCEPTION;
36676
36677
0
    p = JS_VALUE_GET_OBJ(obj);
36678
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p,
36679
0
                               JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
36680
0
        goto exception;
36681
0
    r = JS_NewObject(ctx);
36682
0
    if (JS_IsException(r))
36683
0
        goto exception;
36684
0
    for(i = 0; i < len; i++) {
36685
0
        JSValue atomValue, desc;
36686
0
        JSValueConst args[2];
36687
36688
0
        atomValue = JS_AtomToValue(ctx, props[i].atom);
36689
0
        if (JS_IsException(atomValue))
36690
0
            goto exception;
36691
0
        args[0] = obj;
36692
0
        args[1] = atomValue;
36693
0
        desc = js_object_getOwnPropertyDescriptor(ctx, JS_UNDEFINED, 2, args, 0);
36694
0
        JS_FreeValue(ctx, atomValue);
36695
0
        if (JS_IsException(desc))
36696
0
            goto exception;
36697
0
        if (!JS_IsUndefined(desc)) {
36698
0
            if (JS_DefinePropertyValue(ctx, r, props[i].atom, desc,
36699
0
                                       JS_PROP_C_W_E | JS_PROP_THROW) < 0)
36700
0
                goto exception;
36701
0
        }
36702
0
    }
36703
0
    js_free_prop_enum(ctx, props, len);
36704
0
    JS_FreeValue(ctx, obj);
36705
0
    return r;
36706
36707
0
exception:
36708
0
    js_free_prop_enum(ctx, props, len);
36709
0
    JS_FreeValue(ctx, obj);
36710
0
    JS_FreeValue(ctx, r);
36711
0
    return JS_EXCEPTION;
36712
0
}
36713
36714
static JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValueConst obj1,
36715
                                       int flags, int kind)
36716
0
{
36717
0
    JSValue obj, r, val, key, value;
36718
0
    JSObject *p;
36719
0
    JSPropertyEnum *atoms;
36720
0
    uint32_t len, i, j;
36721
36722
0
    r = JS_UNDEFINED;
36723
0
    val = JS_UNDEFINED;
36724
0
    obj = JS_ToObject(ctx, obj1);
36725
0
    if (JS_IsException(obj))
36726
0
        return JS_EXCEPTION;
36727
0
    p = JS_VALUE_GET_OBJ(obj);
36728
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, flags & ~JS_GPN_ENUM_ONLY))
36729
0
        goto exception;
36730
0
    r = JS_NewArray(ctx);
36731
0
    if (JS_IsException(r))
36732
0
        goto exception;
36733
0
    for(j = i = 0; i < len; i++) {
36734
0
        JSAtom atom = atoms[i].atom;
36735
0
        if (flags & JS_GPN_ENUM_ONLY) {
36736
0
            JSPropertyDescriptor desc;
36737
0
            int res;
36738
36739
            /* Check if property is still enumerable */
36740
0
            res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
36741
0
            if (res < 0)
36742
0
                goto exception;
36743
0
            if (!res)
36744
0
                continue;
36745
0
            js_free_desc(ctx, &desc);
36746
0
            if (!(desc.flags & JS_PROP_ENUMERABLE))
36747
0
                continue;
36748
0
        }
36749
0
        switch(kind) {
36750
0
        default:
36751
0
        case JS_ITERATOR_KIND_KEY:
36752
0
            val = JS_AtomToValue(ctx, atom);
36753
0
            if (JS_IsException(val))
36754
0
                goto exception;
36755
0
            break;
36756
0
        case JS_ITERATOR_KIND_VALUE:
36757
0
            val = JS_GetProperty(ctx, obj, atom);
36758
0
            if (JS_IsException(val))
36759
0
                goto exception;
36760
0
            break;
36761
0
        case JS_ITERATOR_KIND_KEY_AND_VALUE:
36762
0
            val = JS_NewArray(ctx);
36763
0
            if (JS_IsException(val))
36764
0
                goto exception;
36765
0
            key = JS_AtomToValue(ctx, atom);
36766
0
            if (JS_IsException(key))
36767
0
                goto exception1;
36768
0
            if (JS_CreateDataPropertyUint32(ctx, val, 0, key, JS_PROP_THROW) < 0)
36769
0
                goto exception1;
36770
0
            value = JS_GetProperty(ctx, obj, atom);
36771
0
            if (JS_IsException(value))
36772
0
                goto exception1;
36773
0
            if (JS_CreateDataPropertyUint32(ctx, val, 1, value, JS_PROP_THROW) < 0)
36774
0
                goto exception1;
36775
0
            break;
36776
0
        }
36777
0
        if (JS_CreateDataPropertyUint32(ctx, r, j++, val, 0) < 0)
36778
0
            goto exception;
36779
0
    }
36780
0
    goto done;
36781
36782
0
exception1:
36783
0
    JS_FreeValue(ctx, val);
36784
0
exception:
36785
0
    JS_FreeValue(ctx, r);
36786
0
    r = JS_EXCEPTION;
36787
0
done:
36788
0
    js_free_prop_enum(ctx, atoms, len);
36789
0
    JS_FreeValue(ctx, obj);
36790
0
    return r;
36791
0
}
36792
36793
static JSValue js_object_getOwnPropertyNames(JSContext *ctx, JSValueConst this_val,
36794
                                             int argc, JSValueConst *argv)
36795
0
{
36796
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
36797
0
                                   JS_GPN_STRING_MASK, JS_ITERATOR_KIND_KEY);
36798
0
}
36799
36800
static JSValue js_object_getOwnPropertySymbols(JSContext *ctx, JSValueConst this_val,
36801
                                             int argc, JSValueConst *argv)
36802
0
{
36803
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
36804
0
                                   JS_GPN_SYMBOL_MASK, JS_ITERATOR_KIND_KEY);
36805
0
}
36806
36807
static JSValue js_object_keys(JSContext *ctx, JSValueConst this_val,
36808
                              int argc, JSValueConst *argv, int kind)
36809
0
{
36810
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
36811
0
                                   JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK, kind);
36812
0
}
36813
36814
static JSValue js_object_isExtensible(JSContext *ctx, JSValueConst this_val,
36815
                                      int argc, JSValueConst *argv, int reflect)
36816
0
{
36817
0
    JSValueConst obj;
36818
0
    int ret;
36819
36820
0
    obj = argv[0];
36821
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
36822
0
        if (reflect)
36823
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
36824
0
        else
36825
0
            return JS_FALSE;
36826
0
    }
36827
0
    ret = JS_IsExtensible(ctx, obj);
36828
0
    if (ret < 0)
36829
0
        return JS_EXCEPTION;
36830
0
    else
36831
0
        return JS_NewBool(ctx, ret);
36832
0
}
36833
36834
static JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val,
36835
                                           int argc, JSValueConst *argv, int reflect)
36836
0
{
36837
0
    JSValueConst obj;
36838
0
    int ret;
36839
36840
0
    obj = argv[0];
36841
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
36842
0
        if (reflect)
36843
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
36844
0
        else
36845
0
            return JS_DupValue(ctx, obj);
36846
0
    }
36847
0
    ret = JS_PreventExtensions(ctx, obj);
36848
0
    if (ret < 0)
36849
0
        return JS_EXCEPTION;
36850
0
    if (reflect) {
36851
0
        return JS_NewBool(ctx, ret);
36852
0
    } else {
36853
0
        if (!ret)
36854
0
            return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
36855
0
        return JS_DupValue(ctx, obj);
36856
0
    }
36857
0
}
36858
36859
static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,
36860
                                        int argc, JSValueConst *argv)
36861
0
{
36862
0
    JSValue obj;
36863
0
    JSAtom atom;
36864
0
    JSObject *p;
36865
0
    BOOL ret;
36866
36867
0
    atom = JS_ValueToAtom(ctx, argv[0]); /* must be done first */
36868
0
    if (unlikely(atom == JS_ATOM_NULL))
36869
0
        return JS_EXCEPTION;
36870
0
    obj = JS_ToObject(ctx, this_val);
36871
0
    if (JS_IsException(obj)) {
36872
0
        JS_FreeAtom(ctx, atom);
36873
0
        return obj;
36874
0
    }
36875
0
    p = JS_VALUE_GET_OBJ(obj);
36876
0
    ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
36877
0
    JS_FreeAtom(ctx, atom);
36878
0
    JS_FreeValue(ctx, obj);
36879
0
    if (ret < 0)
36880
0
        return JS_EXCEPTION;
36881
0
    else
36882
0
        return JS_NewBool(ctx, ret);
36883
0
}
36884
36885
static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val,
36886
                                int argc, JSValueConst *argv)
36887
0
{
36888
0
    JSValue obj;
36889
0
    JSAtom atom;
36890
0
    JSObject *p;
36891
0
    BOOL ret;
36892
36893
0
    obj = JS_ToObject(ctx, argv[0]);
36894
0
    if (JS_IsException(obj))
36895
0
        return obj;
36896
0
    atom = JS_ValueToAtom(ctx, argv[1]);
36897
0
    if (unlikely(atom == JS_ATOM_NULL)) {
36898
0
        JS_FreeValue(ctx, obj);
36899
0
        return JS_EXCEPTION;
36900
0
    }
36901
0
    p = JS_VALUE_GET_OBJ(obj);
36902
0
    ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
36903
0
    JS_FreeAtom(ctx, atom);
36904
0
    JS_FreeValue(ctx, obj);
36905
0
    if (ret < 0)
36906
0
        return JS_EXCEPTION;
36907
0
    else
36908
0
        return JS_NewBool(ctx, ret);
36909
0
}
36910
36911
static JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val,
36912
                                 int argc, JSValueConst *argv)
36913
753k
{
36914
753k
    return JS_ToObject(ctx, this_val);
36915
753k
}
36916
36917
static JSValue js_object_toString(JSContext *ctx, JSValueConst this_val,
36918
                                  int argc, JSValueConst *argv)
36919
288k
{
36920
288k
    JSValue obj, tag;
36921
288k
    int is_array;
36922
288k
    JSAtom atom;
36923
288k
    JSObject *p;
36924
36925
288k
    if (JS_IsNull(this_val)) {
36926
0
        tag = JS_NewString(ctx, "Null");
36927
288k
    } else if (JS_IsUndefined(this_val)) {
36928
0
        tag = JS_NewString(ctx, "Undefined");
36929
288k
    } else {
36930
288k
        obj = JS_ToObject(ctx, this_val);
36931
288k
        if (JS_IsException(obj))
36932
0
            return obj;
36933
288k
        is_array = JS_IsArray(ctx, obj);
36934
288k
        if (is_array < 0) {
36935
0
            JS_FreeValue(ctx, obj);
36936
0
            return JS_EXCEPTION;
36937
0
        }
36938
288k
        if (is_array) {
36939
0
            atom = JS_ATOM_Array;
36940
288k
        } else if (JS_IsFunction(ctx, obj)) {
36941
0
            atom = JS_ATOM_Function;
36942
288k
        } else {
36943
288k
            p = JS_VALUE_GET_OBJ(obj);
36944
288k
            switch(p->class_id) {
36945
0
            case JS_CLASS_STRING:
36946
0
            case JS_CLASS_ARGUMENTS:
36947
0
            case JS_CLASS_MAPPED_ARGUMENTS:
36948
0
            case JS_CLASS_ERROR:
36949
0
            case JS_CLASS_BOOLEAN:
36950
0
            case JS_CLASS_NUMBER:
36951
0
            case JS_CLASS_DATE:
36952
0
            case JS_CLASS_REGEXP:
36953
0
                atom = ctx->rt->class_array[p->class_id].class_name;
36954
0
                break;
36955
288k
            default:
36956
288k
                atom = JS_ATOM_Object;
36957
288k
                break;
36958
288k
            }
36959
288k
        }
36960
288k
        tag = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_toStringTag);
36961
288k
        JS_FreeValue(ctx, obj);
36962
288k
        if (JS_IsException(tag))
36963
0
            return JS_EXCEPTION;
36964
288k
        if (!JS_IsString(tag)) {
36965
188k
            JS_FreeValue(ctx, tag);
36966
188k
            tag = JS_AtomToString(ctx, atom);
36967
188k
        }
36968
288k
    }
36969
288k
    return JS_ConcatString3(ctx, "[object ", tag, "]");
36970
288k
}
36971
36972
static JSValue js_object_toLocaleString(JSContext *ctx, JSValueConst this_val,
36973
                                        int argc, JSValueConst *argv)
36974
0
{
36975
0
    return JS_Invoke(ctx, this_val, JS_ATOM_toString, 0, NULL);
36976
0
}
36977
36978
static JSValue js_object_assign(JSContext *ctx, JSValueConst this_val,
36979
                                int argc, JSValueConst *argv)
36980
0
{
36981
    // Object.assign(obj, source1)
36982
0
    JSValue obj, s;
36983
0
    int i;
36984
36985
0
    s = JS_UNDEFINED;
36986
0
    obj = JS_ToObject(ctx, argv[0]);
36987
0
    if (JS_IsException(obj))
36988
0
        goto exception;
36989
0
    for (i = 1; i < argc; i++) {
36990
0
        if (!JS_IsNull(argv[i]) && !JS_IsUndefined(argv[i])) {
36991
0
            s = JS_ToObject(ctx, argv[i]);
36992
0
            if (JS_IsException(s))
36993
0
                goto exception;
36994
0
            if (JS_CopyDataProperties(ctx, obj, s, JS_UNDEFINED, TRUE))
36995
0
                goto exception;
36996
0
            JS_FreeValue(ctx, s);
36997
0
        }
36998
0
    }
36999
0
    return obj;
37000
0
exception:
37001
0
    JS_FreeValue(ctx, obj);
37002
0
    JS_FreeValue(ctx, s);
37003
0
    return JS_EXCEPTION;
37004
0
}
37005
37006
static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val,
37007
                              int argc, JSValueConst *argv, int freeze_flag)
37008
2
{
37009
2
    JSValueConst obj = argv[0];
37010
2
    JSObject *p;
37011
2
    JSPropertyEnum *props;
37012
2
    uint32_t len, i;
37013
2
    int flags, desc_flags, res;
37014
37015
2
    if (!JS_IsObject(obj))
37016
0
        return JS_DupValue(ctx, obj);
37017
37018
2
    res = JS_PreventExtensions(ctx, obj);
37019
2
    if (res < 0)
37020
0
        return JS_EXCEPTION;
37021
2
    if (!res) {
37022
0
        return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
37023
0
    }
37024
    
37025
2
    p = JS_VALUE_GET_OBJ(obj);
37026
2
    flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
37027
2
    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
37028
0
        return JS_EXCEPTION;
37029
37030
6
    for(i = 0; i < len; i++) {
37031
4
        JSPropertyDescriptor desc;
37032
4
        JSAtom prop = props[i].atom;
37033
37034
4
        desc_flags = JS_PROP_THROW | JS_PROP_HAS_CONFIGURABLE;
37035
4
        if (freeze_flag) {
37036
4
            res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
37037
4
            if (res < 0)
37038
0
                goto exception;
37039
4
            if (res) {
37040
4
                if (desc.flags & JS_PROP_WRITABLE)
37041
0
                    desc_flags |= JS_PROP_HAS_WRITABLE;
37042
4
                js_free_desc(ctx, &desc);
37043
4
            }
37044
4
        }
37045
4
        if (JS_DefineProperty(ctx, obj, prop, JS_UNDEFINED,
37046
4
                              JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0)
37047
0
            goto exception;
37048
4
    }
37049
2
    js_free_prop_enum(ctx, props, len);
37050
2
    return JS_DupValue(ctx, obj);
37051
37052
0
 exception:
37053
0
    js_free_prop_enum(ctx, props, len);
37054
0
    return JS_EXCEPTION;
37055
2
}
37056
37057
static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val,
37058
                                  int argc, JSValueConst *argv, int is_frozen)
37059
0
{
37060
0
    JSValueConst obj = argv[0];
37061
0
    JSObject *p;
37062
0
    JSPropertyEnum *props;
37063
0
    uint32_t len, i;
37064
0
    int flags, res;
37065
    
37066
0
    if (!JS_IsObject(obj))
37067
0
        return JS_TRUE;
37068
37069
0
    p = JS_VALUE_GET_OBJ(obj);
37070
0
    flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
37071
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
37072
0
        return JS_EXCEPTION;
37073
37074
0
    for(i = 0; i < len; i++) {
37075
0
        JSPropertyDescriptor desc;
37076
0
        JSAtom prop = props[i].atom;
37077
37078
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
37079
0
        if (res < 0)
37080
0
            goto exception;
37081
0
        if (res) {
37082
0
            js_free_desc(ctx, &desc);
37083
0
            if ((desc.flags & JS_PROP_CONFIGURABLE)
37084
0
            ||  (is_frozen && (desc.flags & JS_PROP_WRITABLE))) {
37085
0
                res = FALSE;
37086
0
                goto done;
37087
0
            }
37088
0
        }
37089
0
    }
37090
0
    res = JS_IsExtensible(ctx, obj);
37091
0
    if (res < 0)
37092
0
        return JS_EXCEPTION;
37093
0
    res ^= 1;
37094
0
done:        
37095
0
    js_free_prop_enum(ctx, props, len);
37096
0
    return JS_NewBool(ctx, res);
37097
37098
0
exception:
37099
0
    js_free_prop_enum(ctx, props, len);
37100
0
    return JS_EXCEPTION;
37101
0
}
37102
37103
static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val,
37104
                                     int argc, JSValueConst *argv)
37105
0
{
37106
0
    JSValue obj, iter, next_method = JS_UNDEFINED;
37107
0
    JSValueConst iterable;
37108
0
    BOOL done;
37109
37110
    /*  RequireObjectCoercible() not necessary because it is tested in
37111
        JS_GetIterator() by JS_GetProperty() */
37112
0
    iterable = argv[0];
37113
37114
0
    obj = JS_NewObject(ctx);
37115
0
    if (JS_IsException(obj))
37116
0
        return obj;
37117
    
37118
0
    iter = JS_GetIterator(ctx, iterable, FALSE);
37119
0
    if (JS_IsException(iter))
37120
0
        goto fail;
37121
0
    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
37122
0
    if (JS_IsException(next_method))
37123
0
        goto fail;
37124
    
37125
0
    for(;;) {
37126
0
        JSValue key, value, item;
37127
0
        item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
37128
0
        if (JS_IsException(item))
37129
0
            goto fail;
37130
0
        if (done) {
37131
0
            JS_FreeValue(ctx, item);
37132
0
            break;
37133
0
        }
37134
        
37135
0
        key = JS_UNDEFINED;
37136
0
        value = JS_UNDEFINED;
37137
0
        if (!JS_IsObject(item)) {
37138
0
            JS_ThrowTypeErrorNotAnObject(ctx);
37139
0
            goto fail1;
37140
0
        }
37141
0
        key = JS_GetPropertyUint32(ctx, item, 0);
37142
0
        if (JS_IsException(key))
37143
0
            goto fail1;
37144
0
        value = JS_GetPropertyUint32(ctx, item, 1);
37145
0
        if (JS_IsException(value)) {
37146
0
            JS_FreeValue(ctx, key);
37147
0
            goto fail1;
37148
0
        }
37149
0
        if (JS_DefinePropertyValueValue(ctx, obj, key, value,
37150
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0) {
37151
0
        fail1:
37152
0
            JS_FreeValue(ctx, item);
37153
0
            goto fail;
37154
0
        }
37155
0
        JS_FreeValue(ctx, item);
37156
0
    }
37157
0
    JS_FreeValue(ctx, next_method);
37158
0
    JS_FreeValue(ctx, iter);
37159
0
    return obj;
37160
0
 fail:
37161
0
    if (JS_IsObject(iter)) {
37162
        /* close the iterator object, preserving pending exception */
37163
0
        JS_IteratorClose(ctx, iter, TRUE);
37164
0
    }
37165
0
    JS_FreeValue(ctx, next_method);
37166
0
    JS_FreeValue(ctx, iter);
37167
0
    JS_FreeValue(ctx, obj);
37168
0
    return JS_EXCEPTION;
37169
0
}
37170
37171
#if 0
37172
/* Note: corresponds to ECMA spec: CreateDataPropertyOrThrow() */
37173
static JSValue js_object___setOwnProperty(JSContext *ctx, JSValueConst this_val,
37174
                                          int argc, JSValueConst *argv)
37175
{
37176
    int ret;
37177
    ret = JS_DefinePropertyValueValue(ctx, argv[0], JS_DupValue(ctx, argv[1]),
37178
                                      JS_DupValue(ctx, argv[2]),
37179
                                      JS_PROP_C_W_E | JS_PROP_THROW);
37180
    if (ret < 0)
37181
        return JS_EXCEPTION;
37182
    else
37183
        return JS_NewBool(ctx, ret);
37184
}
37185
37186
static JSValue js_object___toObject(JSContext *ctx, JSValueConst this_val,
37187
                                    int argc, JSValueConst *argv)
37188
{
37189
    return JS_ToObject(ctx, argv[0]);
37190
}
37191
37192
static JSValue js_object___toPrimitive(JSContext *ctx, JSValueConst this_val,
37193
                                       int argc, JSValueConst *argv)
37194
{
37195
    int hint = HINT_NONE;
37196
37197
    if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_INT)
37198
        hint = JS_VALUE_GET_INT(argv[1]);
37199
37200
    return JS_ToPrimitive(ctx, argv[0], hint);
37201
}
37202
#endif
37203
37204
/* return an empty string if not an object */
37205
static JSValue js_object___getClass(JSContext *ctx, JSValueConst this_val,
37206
                                    int argc, JSValueConst *argv)
37207
0
{
37208
0
    JSAtom atom;
37209
0
    JSObject *p;
37210
0
    uint32_t tag;
37211
0
    int class_id;
37212
37213
0
    tag = JS_VALUE_GET_NORM_TAG(argv[0]);
37214
0
    if (tag == JS_TAG_OBJECT) {
37215
0
        p = JS_VALUE_GET_OBJ(argv[0]);
37216
0
        class_id = p->class_id;
37217
0
        if (class_id == JS_CLASS_PROXY && JS_IsFunction(ctx, argv[0]))
37218
0
            class_id = JS_CLASS_BYTECODE_FUNCTION;
37219
0
        atom = ctx->rt->class_array[class_id].class_name;
37220
0
    } else {
37221
0
        atom = JS_ATOM_empty_string;
37222
0
    }
37223
0
    return JS_AtomToString(ctx, atom);
37224
0
}
37225
37226
static JSValue js_object_is(JSContext *ctx, JSValueConst this_val,
37227
                            int argc, JSValueConst *argv)
37228
0
{
37229
0
    return JS_NewBool(ctx, js_same_value(ctx, argv[0], argv[1]));
37230
0
}
37231
37232
#if 0
37233
static JSValue js_object___getObjectData(JSContext *ctx, JSValueConst this_val,
37234
                                         int argc, JSValueConst *argv)
37235
{
37236
    return JS_GetObjectData(ctx, argv[0]);
37237
}
37238
37239
static JSValue js_object___setObjectData(JSContext *ctx, JSValueConst this_val,
37240
                                         int argc, JSValueConst *argv)
37241
{
37242
    if (JS_SetObjectData(ctx, argv[0], JS_DupValue(ctx, argv[1])))
37243
        return JS_EXCEPTION;
37244
    return JS_DupValue(ctx, argv[1]);
37245
}
37246
37247
static JSValue js_object___toPropertyKey(JSContext *ctx, JSValueConst this_val,
37248
                                         int argc, JSValueConst *argv)
37249
{
37250
    return JS_ToPropertyKey(ctx, argv[0]);
37251
}
37252
37253
static JSValue js_object___isObject(JSContext *ctx, JSValueConst this_val,
37254
                                    int argc, JSValueConst *argv)
37255
{
37256
    return JS_NewBool(ctx, JS_IsObject(argv[0]));
37257
}
37258
37259
static JSValue js_object___isSameValueZero(JSContext *ctx, JSValueConst this_val,
37260
                                           int argc, JSValueConst *argv)
37261
{
37262
    return JS_NewBool(ctx, js_same_value_zero(ctx, argv[0], argv[1]));
37263
}
37264
37265
static JSValue js_object___isConstructor(JSContext *ctx, JSValueConst this_val,
37266
                                         int argc, JSValueConst *argv)
37267
{
37268
    return JS_NewBool(ctx, JS_IsConstructor(ctx, argv[0]));
37269
}
37270
#endif
37271
37272
static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj,
37273
                                     JSValueConst defaultConstructor)
37274
0
{
37275
0
    JSValue ctor, species;
37276
37277
0
    if (!JS_IsObject(obj))
37278
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
37279
0
    ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
37280
0
    if (JS_IsException(ctor))
37281
0
        return ctor;
37282
0
    if (JS_IsUndefined(ctor))
37283
0
        return JS_DupValue(ctx, defaultConstructor);
37284
0
    if (!JS_IsObject(ctor)) {
37285
0
        JS_FreeValue(ctx, ctor);
37286
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
37287
0
    }
37288
0
    species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
37289
0
    JS_FreeValue(ctx, ctor);
37290
0
    if (JS_IsException(species))
37291
0
        return species;
37292
0
    if (JS_IsUndefined(species) || JS_IsNull(species))
37293
0
        return JS_DupValue(ctx, defaultConstructor);
37294
0
    if (!JS_IsConstructor(ctx, species)) {
37295
0
        JS_FreeValue(ctx, species);
37296
0
        return JS_ThrowTypeError(ctx, "not a constructor");
37297
0
    }
37298
0
    return species;
37299
0
}
37300
37301
#if 0
37302
static JSValue js_object___speciesConstructor(JSContext *ctx, JSValueConst this_val,
37303
                                              int argc, JSValueConst *argv)
37304
{
37305
    return JS_SpeciesConstructor(ctx, argv[0], argv[1]);
37306
}
37307
#endif
37308
37309
static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val)
37310
0
{
37311
0
    JSValue val, ret;
37312
37313
0
    val = JS_ToObject(ctx, this_val);
37314
0
    if (JS_IsException(val))
37315
0
        return val;
37316
0
    ret = JS_GetPrototype(ctx, val);
37317
0
    JS_FreeValue(ctx, val);
37318
0
    return ret;
37319
0
}
37320
37321
static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val,
37322
                                       JSValueConst proto)
37323
0
{
37324
0
    if (JS_IsUndefined(this_val) || JS_IsNull(this_val))
37325
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
37326
0
    if (!JS_IsObject(proto) && !JS_IsNull(proto))
37327
0
        return JS_UNDEFINED;
37328
0
    if (JS_SetPrototypeInternal(ctx, this_val, proto, TRUE) < 0)
37329
0
        return JS_EXCEPTION;
37330
0
    else
37331
0
        return JS_UNDEFINED;
37332
0
}
37333
37334
static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val,
37335
                                       int argc, JSValueConst *argv)
37336
0
{
37337
0
    JSValue obj, v1;
37338
0
    JSValueConst v;
37339
0
    int res;
37340
37341
0
    v = argv[0];
37342
0
    if (!JS_IsObject(v))
37343
0
        return JS_FALSE;
37344
0
    obj = JS_ToObject(ctx, this_val);
37345
0
    if (JS_IsException(obj))
37346
0
        return JS_EXCEPTION;
37347
0
    v1 = JS_DupValue(ctx, v);
37348
0
    for(;;) {
37349
0
        v1 = JS_GetPrototypeFree(ctx, v1);
37350
0
        if (JS_IsException(v1))
37351
0
            goto exception;
37352
0
        if (JS_IsNull(v1)) {
37353
0
            res = FALSE;
37354
0
            break;
37355
0
        }
37356
0
        if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) {
37357
0
            res = TRUE;
37358
0
            break;
37359
0
        }
37360
        /* avoid infinite loop (possible with proxies) */
37361
0
        if (js_poll_interrupts(ctx))
37362
0
            goto exception;
37363
0
    }
37364
0
    JS_FreeValue(ctx, v1);
37365
0
    JS_FreeValue(ctx, obj);
37366
0
    return JS_NewBool(ctx, res);
37367
37368
0
exception:
37369
0
    JS_FreeValue(ctx, v1);
37370
0
    JS_FreeValue(ctx, obj);
37371
0
    return JS_EXCEPTION;
37372
0
}
37373
37374
static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_val,
37375
                                              int argc, JSValueConst *argv)
37376
0
{
37377
0
    JSValue obj, res = JS_EXCEPTION;
37378
0
    JSAtom prop = JS_ATOM_NULL;
37379
0
    JSPropertyDescriptor desc;
37380
0
    int has_prop;
37381
37382
0
    obj = JS_ToObject(ctx, this_val);
37383
0
    if (JS_IsException(obj))
37384
0
        goto exception;
37385
0
    prop = JS_ValueToAtom(ctx, argv[0]);
37386
0
    if (unlikely(prop == JS_ATOM_NULL))
37387
0
        goto exception;
37388
37389
0
    has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
37390
0
    if (has_prop < 0)
37391
0
        goto exception;
37392
0
    if (has_prop) {
37393
0
        res = JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0);
37394
0
        js_free_desc(ctx, &desc);
37395
0
    } else {
37396
0
        res = JS_FALSE;
37397
0
    }
37398
37399
0
exception:
37400
0
    JS_FreeAtom(ctx, prop);
37401
0
    JS_FreeValue(ctx, obj);
37402
0
    return res;
37403
0
}
37404
37405
static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val,
37406
                                          int argc, JSValueConst *argv, int setter)
37407
0
{
37408
0
    JSValue obj, res = JS_EXCEPTION;
37409
0
    JSAtom prop = JS_ATOM_NULL;
37410
0
    JSPropertyDescriptor desc;
37411
0
    int has_prop;
37412
37413
0
    obj = JS_ToObject(ctx, this_val);
37414
0
    if (JS_IsException(obj))
37415
0
        goto exception;
37416
0
    prop = JS_ValueToAtom(ctx, argv[0]);
37417
0
    if (unlikely(prop == JS_ATOM_NULL))
37418
0
        goto exception;
37419
37420
0
    for (;;) {
37421
0
        has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
37422
0
        if (has_prop < 0)
37423
0
            goto exception;
37424
0
        if (has_prop) {
37425
0
            if (desc.flags & JS_PROP_GETSET)
37426
0
                res = JS_DupValue(ctx, setter ? desc.setter : desc.getter);
37427
0
            else
37428
0
                res = JS_UNDEFINED;
37429
0
            js_free_desc(ctx, &desc);
37430
0
            break;
37431
0
        }
37432
0
        obj = JS_GetPrototypeFree(ctx, obj);
37433
0
        if (JS_IsException(obj))
37434
0
            goto exception;
37435
0
        if (JS_IsNull(obj)) {
37436
0
            res = JS_UNDEFINED;
37437
0
            break;
37438
0
        }
37439
        /* avoid infinite loop (possible with proxies) */
37440
0
        if (js_poll_interrupts(ctx))
37441
0
            goto exception;
37442
0
    }
37443
37444
0
exception:
37445
0
    JS_FreeAtom(ctx, prop);
37446
0
    JS_FreeValue(ctx, obj);
37447
0
    return res;
37448
0
}
37449
37450
static const JSCFunctionListEntry js_object_funcs[] = {
37451
    JS_CFUNC_DEF("create", 2, js_object_create ),
37452
    JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 0 ),
37453
    JS_CFUNC_DEF("setPrototypeOf", 2, js_object_setPrototypeOf ),
37454
    JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 0 ),
37455
    JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties ),
37456
    JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames ),
37457
    JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols ),
37458
    JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY ),
37459
    JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ),
37460
    JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ),
37461
    JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 0 ),
37462
    JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 0 ),
37463
    JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 0 ),
37464
    JS_CFUNC_DEF("getOwnPropertyDescriptors", 1, js_object_getOwnPropertyDescriptors ),
37465
    JS_CFUNC_DEF("is", 2, js_object_is ),
37466
    JS_CFUNC_DEF("assign", 2, js_object_assign ),
37467
    JS_CFUNC_MAGIC_DEF("seal", 1, js_object_seal, 0 ),
37468
    JS_CFUNC_MAGIC_DEF("freeze", 1, js_object_seal, 1 ),
37469
    JS_CFUNC_MAGIC_DEF("isSealed", 1, js_object_isSealed, 0 ),
37470
    JS_CFUNC_MAGIC_DEF("isFrozen", 1, js_object_isSealed, 1 ),
37471
    JS_CFUNC_DEF("__getClass", 1, js_object___getClass ),
37472
    //JS_CFUNC_DEF("__isObject", 1, js_object___isObject ),
37473
    //JS_CFUNC_DEF("__isConstructor", 1, js_object___isConstructor ),
37474
    //JS_CFUNC_DEF("__toObject", 1, js_object___toObject ),
37475
    //JS_CFUNC_DEF("__setOwnProperty", 3, js_object___setOwnProperty ),
37476
    //JS_CFUNC_DEF("__toPrimitive", 2, js_object___toPrimitive ),
37477
    //JS_CFUNC_DEF("__toPropertyKey", 1, js_object___toPropertyKey ),
37478
    //JS_CFUNC_DEF("__speciesConstructor", 2, js_object___speciesConstructor ),
37479
    //JS_CFUNC_DEF("__isSameValueZero", 2, js_object___isSameValueZero ),
37480
    //JS_CFUNC_DEF("__getObjectData", 1, js_object___getObjectData ),
37481
    //JS_CFUNC_DEF("__setObjectData", 2, js_object___setObjectData ),
37482
    JS_CFUNC_DEF("fromEntries", 1, js_object_fromEntries ),
37483
    JS_CFUNC_DEF("hasOwn", 2, js_object_hasOwn ),
37484
};
37485
37486
static const JSCFunctionListEntry js_object_proto_funcs[] = {
37487
    JS_CFUNC_DEF("toString", 0, js_object_toString ),
37488
    JS_CFUNC_DEF("toLocaleString", 0, js_object_toLocaleString ),
37489
    JS_CFUNC_DEF("valueOf", 0, js_object_valueOf ),
37490
    JS_CFUNC_DEF("hasOwnProperty", 1, js_object_hasOwnProperty ),
37491
    JS_CFUNC_DEF("isPrototypeOf", 1, js_object_isPrototypeOf ),
37492
    JS_CFUNC_DEF("propertyIsEnumerable", 1, js_object_propertyIsEnumerable ),
37493
    JS_CGETSET_DEF("__proto__", js_object_get___proto__, js_object_set___proto__ ),
37494
    JS_CFUNC_MAGIC_DEF("__defineGetter__", 2, js_object___defineGetter__, 0 ),
37495
    JS_CFUNC_MAGIC_DEF("__defineSetter__", 2, js_object___defineGetter__, 1 ),
37496
    JS_CFUNC_MAGIC_DEF("__lookupGetter__", 1, js_object___lookupGetter__, 0 ),
37497
    JS_CFUNC_MAGIC_DEF("__lookupSetter__", 1, js_object___lookupGetter__, 1 ),
37498
};
37499
37500
/* Function class */
37501
37502
static JSValue js_function_proto(JSContext *ctx, JSValueConst this_val,
37503
                                 int argc, JSValueConst *argv)
37504
0
{
37505
0
    return JS_UNDEFINED;
37506
0
}
37507
37508
/* XXX: add a specific eval mode so that Function("}), ({") is rejected */
37509
static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target,
37510
                                       int argc, JSValueConst *argv, int magic)
37511
15
{
37512
15
    JSFunctionKindEnum func_kind = magic;
37513
15
    int i, n, ret;
37514
15
    JSValue s, proto, obj = JS_UNDEFINED;
37515
15
    StringBuffer b_s, *b = &b_s;
37516
37517
15
    string_buffer_init(ctx, b, 0);
37518
15
    string_buffer_putc8(b, '(');
37519
    
37520
15
    if (func_kind == JS_FUNC_ASYNC || func_kind == JS_FUNC_ASYNC_GENERATOR) {
37521
0
        string_buffer_puts8(b, "async ");
37522
0
    }
37523
15
    string_buffer_puts8(b, "function");
37524
37525
15
    if (func_kind == JS_FUNC_GENERATOR || func_kind == JS_FUNC_ASYNC_GENERATOR) {
37526
0
        string_buffer_putc8(b, '*');
37527
0
    }
37528
15
    string_buffer_puts8(b, " anonymous(");
37529
37530
15
    n = argc - 1;
37531
16
    for(i = 0; i < n; i++) {
37532
1
        if (i != 0) {
37533
0
            string_buffer_putc8(b, ',');
37534
0
        }
37535
1
        if (string_buffer_concat_value(b, argv[i]))
37536
0
            goto fail;
37537
1
    }
37538
15
    string_buffer_puts8(b, "\n) {\n");
37539
15
    if (n >= 0) {
37540
15
        if (string_buffer_concat_value(b, argv[n]))
37541
0
            goto fail;
37542
15
    }
37543
15
    string_buffer_puts8(b, "\n})");
37544
15
    s = string_buffer_end(b);
37545
15
    if (JS_IsException(s))
37546
0
        goto fail1;
37547
37548
15
    obj = JS_EvalObject(ctx, ctx->global_obj, s, JS_EVAL_TYPE_INDIRECT, -1);
37549
15
    JS_FreeValue(ctx, s);
37550
15
    if (JS_IsException(obj))
37551
5
        goto fail1;
37552
10
    if (!JS_IsUndefined(new_target)) {
37553
        /* set the prototype */
37554
0
        proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
37555
0
        if (JS_IsException(proto))
37556
0
            goto fail1;
37557
0
        if (!JS_IsObject(proto)) {
37558
0
            JSContext *realm;
37559
0
            JS_FreeValue(ctx, proto);
37560
0
            realm = JS_GetFunctionRealm(ctx, new_target);
37561
0
            if (!realm)
37562
0
                goto fail1;
37563
0
            proto = JS_DupValue(ctx, realm->class_proto[func_kind_to_class_id[func_kind]]);
37564
0
        }
37565
0
        ret = JS_SetPrototypeInternal(ctx, obj, proto, TRUE);
37566
0
        JS_FreeValue(ctx, proto);
37567
0
        if (ret < 0)
37568
0
            goto fail1;
37569
0
    }
37570
10
    return obj;
37571
37572
0
 fail:
37573
0
    string_buffer_free(b);
37574
5
 fail1:
37575
5
    JS_FreeValue(ctx, obj);
37576
5
    return JS_EXCEPTION;
37577
0
}
37578
37579
static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
37580
                                       JSValueConst obj)
37581
4.13k
{
37582
4.13k
    JSValue len_val;
37583
4.13k
    len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
37584
4.13k
    if (JS_IsException(len_val)) {
37585
0
        *pres = 0;
37586
0
        return -1;
37587
0
    }
37588
4.13k
    return JS_ToUint32Free(ctx, pres, len_val);
37589
4.13k
}
37590
37591
static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
37592
                                       JSValueConst obj)
37593
780k
{
37594
780k
    JSValue len_val;
37595
780k
    len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
37596
780k
    if (JS_IsException(len_val)) {
37597
0
        *pres = 0;
37598
0
        return -1;
37599
0
    }
37600
780k
    return JS_ToLengthFree(ctx, pres, len_val);
37601
780k
}
37602
37603
static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len)
37604
2.61k
{
37605
2.61k
    uint32_t i;
37606
5.22k
    for(i = 0; i < len; i++) {
37607
2.61k
        JS_FreeValue(ctx, tab[i]);
37608
2.61k
    }
37609
2.61k
    js_free(ctx, tab);
37610
2.61k
}
37611
37612
/* XXX: should use ValueArray */
37613
static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
37614
                               JSValueConst array_arg)
37615
2.61k
{
37616
2.61k
    uint32_t len, i;
37617
2.61k
    JSValue *tab, ret;
37618
2.61k
    JSObject *p;
37619
37620
2.61k
    if (JS_VALUE_GET_TAG(array_arg) != JS_TAG_OBJECT) {
37621
0
        JS_ThrowTypeError(ctx, "not a object");
37622
0
        return NULL;
37623
0
    }
37624
2.61k
    if (js_get_length32(ctx, &len, array_arg))
37625
0
        return NULL;
37626
2.61k
    if (len > JS_MAX_LOCAL_VARS) {
37627
0
        JS_ThrowInternalError(ctx, "too many arguments");
37628
0
        return NULL;
37629
0
    }
37630
    /* avoid allocating 0 bytes */
37631
2.61k
    tab = js_mallocz(ctx, sizeof(tab[0]) * max_uint32(1, len));
37632
2.61k
    if (!tab)
37633
0
        return NULL;
37634
2.61k
    p = JS_VALUE_GET_OBJ(array_arg);
37635
2.61k
    if ((p->class_id == JS_CLASS_ARRAY || p->class_id == JS_CLASS_ARGUMENTS) &&
37636
2.61k
        p->fast_array &&
37637
2.61k
        len == p->u.array.count) {
37638
5.22k
        for(i = 0; i < len; i++) {
37639
2.61k
            tab[i] = JS_DupValue(ctx, p->u.array.u.values[i]);
37640
2.61k
        }
37641
2.61k
    } else {
37642
0
        for(i = 0; i < len; i++) {
37643
0
            ret = JS_GetPropertyUint32(ctx, array_arg, i);
37644
0
            if (JS_IsException(ret)) {
37645
0
                free_arg_list(ctx, tab, i);
37646
0
                return NULL;
37647
0
            }
37648
0
            tab[i] = ret;
37649
0
        }
37650
0
    }
37651
2.61k
    *plen = len;
37652
2.61k
    return tab;
37653
2.61k
}
37654
37655
/* magic value: 0 = normal apply, 1 = apply for constructor, 2 =
37656
   Reflect.apply */
37657
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
37658
                                 int argc, JSValueConst *argv, int magic)
37659
2.61k
{
37660
2.61k
    JSValueConst this_arg, array_arg;
37661
2.61k
    uint32_t len;
37662
2.61k
    JSValue *tab, ret;
37663
37664
2.61k
    if (check_function(ctx, this_val))
37665
0
        return JS_EXCEPTION;
37666
2.61k
    this_arg = argv[0];
37667
2.61k
    array_arg = argv[1];
37668
2.61k
    if ((JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED ||
37669
2.61k
         JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) && magic != 2) {
37670
0
        return JS_Call(ctx, this_val, this_arg, 0, NULL);
37671
0
    }
37672
2.61k
    tab = build_arg_list(ctx, &len, array_arg);
37673
2.61k
    if (!tab)
37674
0
        return JS_EXCEPTION;
37675
2.61k
    if (magic & 1) {
37676
0
        ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab);
37677
2.61k
    } else {
37678
2.61k
        ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab);
37679
2.61k
    }
37680
2.61k
    free_arg_list(ctx, tab, len);
37681
2.61k
    return ret;
37682
2.61k
}
37683
37684
static JSValue js_function_call(JSContext *ctx, JSValueConst this_val,
37685
                                int argc, JSValueConst *argv)
37686
0
{
37687
0
    if (argc <= 0) {
37688
0
        return JS_Call(ctx, this_val, JS_UNDEFINED, 0, NULL);
37689
0
    } else {
37690
0
        return JS_Call(ctx, this_val, argv[0], argc - 1, argv + 1);
37691
0
    }
37692
0
}
37693
37694
static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val,
37695
                                int argc, JSValueConst *argv)
37696
0
{
37697
0
    JSBoundFunction *bf;
37698
0
    JSValue func_obj, name1, len_val;
37699
0
    JSObject *p;
37700
0
    int arg_count, i, ret;
37701
37702
0
    if (check_function(ctx, this_val))
37703
0
        return JS_EXCEPTION;
37704
37705
0
    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
37706
0
                                 JS_CLASS_BOUND_FUNCTION);
37707
0
    if (JS_IsException(func_obj))
37708
0
        return JS_EXCEPTION;
37709
0
    p = JS_VALUE_GET_OBJ(func_obj);
37710
0
    p->is_constructor = JS_IsConstructor(ctx, this_val);
37711
0
    arg_count = max_int(0, argc - 1);
37712
0
    bf = js_malloc(ctx, sizeof(*bf) + arg_count * sizeof(JSValue));
37713
0
    if (!bf)
37714
0
        goto exception;
37715
0
    bf->func_obj = JS_DupValue(ctx, this_val);
37716
0
    bf->this_val = JS_DupValue(ctx, argv[0]);
37717
0
    bf->argc = arg_count;
37718
0
    for(i = 0; i < arg_count; i++) {
37719
0
        bf->argv[i] = JS_DupValue(ctx, argv[i + 1]);
37720
0
    }
37721
0
    p->u.bound_function = bf;
37722
37723
    /* XXX: the spec could be simpler by only using GetOwnProperty */
37724
0
    ret = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_length);
37725
0
    if (ret < 0)
37726
0
        goto exception;
37727
0
    if (!ret) {
37728
0
        len_val = JS_NewInt32(ctx, 0);
37729
0
    } else {
37730
0
        len_val = JS_GetProperty(ctx, this_val, JS_ATOM_length);
37731
0
        if (JS_IsException(len_val))
37732
0
            goto exception;
37733
0
        if (JS_VALUE_GET_TAG(len_val) == JS_TAG_INT) {
37734
            /* most common case */
37735
0
            int len1 = JS_VALUE_GET_INT(len_val);
37736
0
            if (len1 <= arg_count)
37737
0
                len1 = 0;
37738
0
            else
37739
0
                len1 -= arg_count;
37740
0
            len_val = JS_NewInt32(ctx, len1);
37741
0
        } else if (JS_VALUE_GET_NORM_TAG(len_val) == JS_TAG_FLOAT64) {
37742
0
            double d = JS_VALUE_GET_FLOAT64(len_val);
37743
0
            if (isnan(d)) {
37744
0
                d = 0.0;
37745
0
            } else {
37746
0
                d = trunc(d);
37747
0
                if (d <= (double)arg_count)
37748
0
                    d = 0.0;
37749
0
                else
37750
0
                    d -= (double)arg_count; /* also converts -0 to +0 */
37751
0
            }
37752
0
            len_val = JS_NewFloat64(ctx, d);
37753
0
        } else {
37754
0
            JS_FreeValue(ctx, len_val);
37755
0
            len_val = JS_NewInt32(ctx, 0);
37756
0
        }
37757
0
    }
37758
0
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length,
37759
0
                           len_val, JS_PROP_CONFIGURABLE);
37760
37761
0
    name1 = JS_GetProperty(ctx, this_val, JS_ATOM_name);
37762
0
    if (JS_IsException(name1))
37763
0
        goto exception;
37764
0
    if (!JS_IsString(name1)) {
37765
0
        JS_FreeValue(ctx, name1);
37766
0
        name1 = JS_AtomToString(ctx, JS_ATOM_empty_string);
37767
0
    }
37768
0
    name1 = JS_ConcatString3(ctx, "bound ", name1, "");
37769
0
    if (JS_IsException(name1))
37770
0
        goto exception;
37771
0
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name1,
37772
0
                           JS_PROP_CONFIGURABLE);
37773
0
    return func_obj;
37774
0
 exception:
37775
0
    JS_FreeValue(ctx, func_obj);
37776
0
    return JS_EXCEPTION;
37777
0
}
37778
37779
static JSValue js_function_toString(JSContext *ctx, JSValueConst this_val,
37780
                                    int argc, JSValueConst *argv)
37781
75.2k
{
37782
75.2k
    JSObject *p;
37783
75.2k
    JSFunctionKindEnum func_kind = JS_FUNC_NORMAL;
37784
37785
75.2k
    if (check_function(ctx, this_val))
37786
0
        return JS_EXCEPTION;
37787
37788
75.2k
    p = JS_VALUE_GET_OBJ(this_val);
37789
75.2k
    if (js_class_has_bytecode(p->class_id)) {
37790
75.0k
        JSFunctionBytecode *b = p->u.func.function_bytecode;
37791
75.0k
        if (b->has_debug && b->debug.source) {
37792
51.8k
            return JS_NewStringLen(ctx, b->debug.source, b->debug.source_len);
37793
51.8k
        }
37794
23.2k
        func_kind = b->func_kind;
37795
23.2k
    }
37796
23.4k
    {
37797
23.4k
        JSValue name;
37798
23.4k
        const char *pref, *suff;
37799
37800
23.4k
        switch(func_kind) {
37801
0
        default:
37802
23.4k
        case JS_FUNC_NORMAL:
37803
23.4k
            pref = "function ";
37804
23.4k
            break;
37805
3
        case JS_FUNC_GENERATOR:
37806
3
            pref = "function *";
37807
3
            break;
37808
0
        case JS_FUNC_ASYNC:
37809
0
            pref = "async function ";
37810
0
            break;
37811
0
        case JS_FUNC_ASYNC_GENERATOR:
37812
0
            pref = "async function *";
37813
0
            break;
37814
23.4k
        }
37815
23.4k
        suff = "() {\n    [native code]\n}";
37816
23.4k
        name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
37817
23.4k
        if (JS_IsUndefined(name))
37818
0
            name = JS_AtomToString(ctx, JS_ATOM_empty_string);
37819
23.4k
        return JS_ConcatString3(ctx, pref, name, suff);
37820
23.4k
    }
37821
23.4k
}
37822
37823
static JSValue js_function_hasInstance(JSContext *ctx, JSValueConst this_val,
37824
                                       int argc, JSValueConst *argv)
37825
0
{
37826
0
    int ret;
37827
0
    ret = JS_OrdinaryIsInstanceOf(ctx, argv[0], this_val);
37828
0
    if (ret < 0)
37829
0
        return JS_EXCEPTION;
37830
0
    else
37831
0
        return JS_NewBool(ctx, ret);
37832
0
}
37833
37834
static const JSCFunctionListEntry js_function_proto_funcs[] = {
37835
    JS_CFUNC_DEF("call", 1, js_function_call ),
37836
    JS_CFUNC_MAGIC_DEF("apply", 2, js_function_apply, 0 ),
37837
    JS_CFUNC_DEF("bind", 1, js_function_bind ),
37838
    JS_CFUNC_DEF("toString", 0, js_function_toString ),
37839
    JS_CFUNC_DEF("[Symbol.hasInstance]", 1, js_function_hasInstance ),
37840
    JS_CGETSET_DEF("fileName", js_function_proto_fileName, NULL ),
37841
    JS_CGETSET_DEF("lineNumber", js_function_proto_lineNumber, NULL ),
37842
};
37843
37844
/* Error class */
37845
37846
static JSValue iterator_to_array(JSContext *ctx, JSValueConst items)
37847
0
{
37848
0
    JSValue iter, next_method = JS_UNDEFINED;
37849
0
    JSValue v, r = JS_UNDEFINED;
37850
0
    int64_t k;
37851
0
    BOOL done;
37852
    
37853
0
    iter = JS_GetIterator(ctx, items, FALSE);
37854
0
    if (JS_IsException(iter))
37855
0
        goto exception;
37856
0
    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
37857
0
    if (JS_IsException(next_method))
37858
0
        goto exception;
37859
0
    r = JS_NewArray(ctx);
37860
0
    if (JS_IsException(r))
37861
0
        goto exception;
37862
0
    for (k = 0;; k++) {
37863
0
        v = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
37864
0
        if (JS_IsException(v))
37865
0
            goto exception_close;
37866
0
        if (done)
37867
0
            break;
37868
0
        if (JS_DefinePropertyValueInt64(ctx, r, k, v,
37869
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
37870
0
            goto exception_close;
37871
0
    }
37872
0
 done:
37873
0
    JS_FreeValue(ctx, next_method);
37874
0
    JS_FreeValue(ctx, iter);
37875
0
    return r;
37876
0
 exception_close:
37877
0
    JS_IteratorClose(ctx, iter, TRUE);
37878
0
 exception:
37879
0
    JS_FreeValue(ctx, r);
37880
0
    r = JS_EXCEPTION;
37881
0
    goto done;
37882
0
}
37883
37884
static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
37885
                                    int argc, JSValueConst *argv, int magic)
37886
0
{
37887
0
    JSValue obj, msg, proto;
37888
0
    JSValueConst message;
37889
37890
0
    if (JS_IsUndefined(new_target))
37891
0
        new_target = JS_GetActiveFunction(ctx);
37892
0
    proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
37893
0
    if (JS_IsException(proto))
37894
0
        return proto;
37895
0
    if (!JS_IsObject(proto)) {
37896
0
        JSContext *realm;
37897
0
        JSValueConst proto1;
37898
        
37899
0
        JS_FreeValue(ctx, proto);
37900
0
        realm = JS_GetFunctionRealm(ctx, new_target);
37901
0
        if (!realm)
37902
0
            return JS_EXCEPTION;
37903
0
        if (magic < 0) {
37904
0
            proto1 = realm->class_proto[JS_CLASS_ERROR];
37905
0
        } else {
37906
0
            proto1 = realm->native_error_proto[magic];
37907
0
        }
37908
0
        proto = JS_DupValue(ctx, proto1);
37909
0
    }
37910
0
    obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_ERROR);
37911
0
    JS_FreeValue(ctx, proto);
37912
0
    if (JS_IsException(obj))
37913
0
        return obj;
37914
0
    if (magic == JS_AGGREGATE_ERROR) {
37915
0
        message = argv[1];
37916
0
    } else {
37917
0
        message = argv[0];
37918
0
    }
37919
37920
0
    if (!JS_IsUndefined(message)) {
37921
0
        msg = JS_ToString(ctx, message);
37922
0
        if (unlikely(JS_IsException(msg)))
37923
0
            goto exception;
37924
0
        JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg,
37925
0
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
37926
0
    }
37927
37928
0
    if (magic == JS_AGGREGATE_ERROR) {
37929
0
        JSValue error_list = iterator_to_array(ctx, argv[0]);
37930
0
        if (JS_IsException(error_list))
37931
0
            goto exception;
37932
0
        JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, error_list,
37933
0
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
37934
0
    }
37935
37936
    /* skip the Error() function in the backtrace */
37937
0
    build_backtrace(ctx, obj, NULL, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
37938
0
    return obj;
37939
0
 exception:
37940
0
    JS_FreeValue(ctx, obj);
37941
0
    return JS_EXCEPTION;
37942
0
}
37943
37944
static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
37945
                                 int argc, JSValueConst *argv)
37946
47
{
37947
47
    JSValue name, msg;
37948
37949
47
    if (!JS_IsObject(this_val))
37950
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
37951
47
    name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
37952
47
    if (JS_IsUndefined(name))
37953
0
        name = JS_AtomToString(ctx, JS_ATOM_Error);
37954
47
    else
37955
47
        name = JS_ToStringFree(ctx, name);
37956
47
    if (JS_IsException(name))
37957
0
        return JS_EXCEPTION;
37958
37959
47
    msg = JS_GetProperty(ctx, this_val, JS_ATOM_message);
37960
47
    if (JS_IsUndefined(msg))
37961
0
        msg = JS_AtomToString(ctx, JS_ATOM_empty_string);
37962
47
    else
37963
47
        msg = JS_ToStringFree(ctx, msg);
37964
47
    if (JS_IsException(msg)) {
37965
0
        JS_FreeValue(ctx, name);
37966
0
        return JS_EXCEPTION;
37967
0
    }
37968
47
    if (!JS_IsEmptyString(name) && !JS_IsEmptyString(msg))
37969
47
        name = JS_ConcatString3(ctx, "", name, ": ");
37970
47
    return JS_ConcatString(ctx, name, msg);
37971
47
}
37972
37973
static const JSCFunctionListEntry js_error_proto_funcs[] = {
37974
    JS_CFUNC_DEF("toString", 0, js_error_toString ),
37975
    JS_PROP_STRING_DEF("name", "Error", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
37976
    JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
37977
};
37978
37979
/* AggregateError */
37980
37981
/* used by C code. */
37982
static JSValue js_aggregate_error_constructor(JSContext *ctx,
37983
                                              JSValueConst errors)
37984
0
{
37985
0
    JSValue obj;
37986
    
37987
0
    obj = JS_NewObjectProtoClass(ctx,
37988
0
                                 ctx->native_error_proto[JS_AGGREGATE_ERROR],
37989
0
                                 JS_CLASS_ERROR);
37990
0
    if (JS_IsException(obj))
37991
0
        return obj;
37992
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, JS_DupValue(ctx, errors),
37993
0
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
37994
0
    return obj;
37995
0
}
37996
37997
/* Array */
37998
37999
static int JS_CopySubArray(JSContext *ctx,
38000
                           JSValueConst obj, int64_t to_pos,
38001
                           int64_t from_pos, int64_t count, int dir)
38002
201k
{
38003
201k
    JSObject *p;
38004
201k
    int64_t i, from, to, len;
38005
201k
    JSValue val;
38006
201k
    int fromPresent;
38007
38008
201k
    p = NULL;
38009
201k
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
38010
201k
        p = JS_VALUE_GET_OBJ(obj);
38011
201k
        if (p->class_id != JS_CLASS_ARRAY || !p->fast_array) {
38012
0
            p = NULL;
38013
0
        }
38014
201k
    }
38015
38016
629k
    for (i = 0; i < count; ) {
38017
427k
        if (dir < 0) {
38018
427k
            from = from_pos + count - i - 1;
38019
427k
            to = to_pos + count - i - 1;
38020
427k
        } else {
38021
0
            from = from_pos + i;
38022
0
            to = to_pos + i;
38023
0
        }
38024
427k
        if (p && p->fast_array &&
38025
427k
            from >= 0 && from < (len = p->u.array.count)  &&
38026
427k
            to >= 0 && to < len) {
38027
201k
            int64_t l, j;
38028
            /* Fast path for fast arrays. Since we don't look at the
38029
               prototype chain, we can optimize only the cases where
38030
               all the elements are present in the array. */
38031
201k
            l = count - i;
38032
201k
            if (dir < 0) {
38033
201k
                l = min_int64(l, from + 1);
38034
201k
                l = min_int64(l, to + 1);
38035
2.42M
                for(j = 0; j < l; j++) {
38036
2.21M
                    set_value(ctx, &p->u.array.u.values[to - j],
38037
2.21M
                              JS_DupValue(ctx, p->u.array.u.values[from - j]));
38038
2.21M
                }
38039
201k
            } else {
38040
0
                l = min_int64(l, len - from);
38041
0
                l = min_int64(l, len - to);
38042
0
                for(j = 0; j < l; j++) {
38043
0
                    set_value(ctx, &p->u.array.u.values[to + j],
38044
0
                              JS_DupValue(ctx, p->u.array.u.values[from + j]));
38045
0
                }
38046
0
            }
38047
201k
            i += l;
38048
225k
        } else {
38049
225k
            fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
38050
225k
            if (fromPresent < 0)
38051
0
                goto exception;
38052
            
38053
225k
            if (fromPresent) {
38054
225k
                if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)
38055
0
                    goto exception;
38056
225k
            } else {
38057
0
                if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0)
38058
0
                    goto exception;
38059
0
            }
38060
225k
            i++;
38061
225k
        }
38062
427k
    }
38063
201k
    return 0;
38064
38065
0
 exception:
38066
0
    return -1;
38067
201k
}
38068
38069
static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target,
38070
                                    int argc, JSValueConst *argv)
38071
201k
{
38072
201k
    JSValue obj;
38073
201k
    int i;
38074
38075
201k
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_ARRAY);
38076
201k
    if (JS_IsException(obj))
38077
0
        return obj;
38078
201k
    if (argc == 1 && JS_IsNumber(argv[0])) {
38079
201k
        uint32_t len;
38080
201k
        if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]), TRUE))
38081
0
            goto fail;
38082
201k
        if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0)
38083
0
            goto fail;
38084
201k
    } else {
38085
20
        for(i = 0; i < argc; i++) {
38086
12
            if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0)
38087
0
                goto fail;
38088
12
        }
38089
8
    }
38090
201k
    return obj;
38091
0
fail:
38092
0
    JS_FreeValue(ctx, obj);
38093
0
    return JS_EXCEPTION;
38094
201k
}
38095
38096
static JSValue js_array_from(JSContext *ctx, JSValueConst this_val,
38097
                             int argc, JSValueConst *argv)
38098
0
{
38099
    // from(items, mapfn = void 0, this_arg = void 0)
38100
0
    JSValueConst items = argv[0], mapfn, this_arg;
38101
0
    JSValueConst args[2];
38102
0
    JSValue stack[2];
38103
0
    JSValue iter, r, v, v2, arrayLike;
38104
0
    int64_t k, len;
38105
0
    int done, mapping;
38106
38107
0
    mapping = FALSE;
38108
0
    mapfn = JS_UNDEFINED;
38109
0
    this_arg = JS_UNDEFINED;
38110
0
    r = JS_UNDEFINED;
38111
0
    arrayLike = JS_UNDEFINED;
38112
0
    stack[0] = JS_UNDEFINED;
38113
0
    stack[1] = JS_UNDEFINED;
38114
38115
0
    if (argc > 1) {
38116
0
        mapfn = argv[1];
38117
0
        if (!JS_IsUndefined(mapfn)) {
38118
0
            if (check_function(ctx, mapfn))
38119
0
                goto exception;
38120
0
            mapping = 1;
38121
0
            if (argc > 2)
38122
0
                this_arg = argv[2];
38123
0
        }
38124
0
    }
38125
0
    iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
38126
0
    if (JS_IsException(iter))
38127
0
        goto exception;
38128
0
    if (!JS_IsUndefined(iter)) {
38129
0
        JS_FreeValue(ctx, iter);
38130
0
        if (JS_IsConstructor(ctx, this_val))
38131
0
            r = JS_CallConstructor(ctx, this_val, 0, NULL);
38132
0
        else
38133
0
            r = JS_NewArray(ctx);
38134
0
        if (JS_IsException(r))
38135
0
            goto exception;
38136
0
        stack[0] = JS_DupValue(ctx, items);
38137
0
        if (js_for_of_start(ctx, &stack[1], FALSE))
38138
0
            goto exception;
38139
0
        for (k = 0;; k++) {
38140
0
            v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done);
38141
0
            if (JS_IsException(v))
38142
0
                goto exception_close;
38143
0
            if (done)
38144
0
                break;
38145
0
            if (mapping) {
38146
0
                args[0] = v;
38147
0
                args[1] = JS_NewInt32(ctx, k);
38148
0
                v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
38149
0
                JS_FreeValue(ctx, v);
38150
0
                v = v2;
38151
0
                if (JS_IsException(v))
38152
0
                    goto exception_close;
38153
0
            }
38154
0
            if (JS_DefinePropertyValueInt64(ctx, r, k, v,
38155
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38156
0
                goto exception_close;
38157
0
        }
38158
0
    } else {
38159
0
        arrayLike = JS_ToObject(ctx, items);
38160
0
        if (JS_IsException(arrayLike))
38161
0
            goto exception;
38162
0
        if (js_get_length64(ctx, &len, arrayLike) < 0)
38163
0
            goto exception;
38164
0
        v = JS_NewInt64(ctx, len);
38165
0
        args[0] = v;
38166
0
        if (JS_IsConstructor(ctx, this_val)) {
38167
0
            r = JS_CallConstructor(ctx, this_val, 1, args);
38168
0
        } else {
38169
0
            r = js_array_constructor(ctx, JS_UNDEFINED, 1, args);
38170
0
        }
38171
0
        JS_FreeValue(ctx, v);
38172
0
        if (JS_IsException(r))
38173
0
            goto exception;
38174
0
        for(k = 0; k < len; k++) {
38175
0
            v = JS_GetPropertyInt64(ctx, arrayLike, k);
38176
0
            if (JS_IsException(v))
38177
0
                goto exception;
38178
0
            if (mapping) {
38179
0
                args[0] = v;
38180
0
                args[1] = JS_NewInt32(ctx, k);
38181
0
                v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
38182
0
                JS_FreeValue(ctx, v);
38183
0
                v = v2;
38184
0
                if (JS_IsException(v))
38185
0
                    goto exception;
38186
0
            }
38187
0
            if (JS_DefinePropertyValueInt64(ctx, r, k, v,
38188
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38189
0
                goto exception;
38190
0
        }
38191
0
    }
38192
0
    if (JS_SetProperty(ctx, r, JS_ATOM_length, JS_NewUint32(ctx, k)) < 0)
38193
0
        goto exception;
38194
0
    goto done;
38195
38196
0
 exception_close:
38197
0
    if (!JS_IsUndefined(stack[0]))
38198
0
        JS_IteratorClose(ctx, stack[0], TRUE);
38199
0
 exception:
38200
0
    JS_FreeValue(ctx, r);
38201
0
    r = JS_EXCEPTION;
38202
0
 done:
38203
0
    JS_FreeValue(ctx, arrayLike);
38204
0
    JS_FreeValue(ctx, stack[0]);
38205
0
    JS_FreeValue(ctx, stack[1]);
38206
0
    return r;
38207
0
}
38208
38209
static JSValue js_array_of(JSContext *ctx, JSValueConst this_val,
38210
                           int argc, JSValueConst *argv)
38211
0
{
38212
0
    JSValue obj, args[1];
38213
0
    int i;
38214
38215
0
    if (JS_IsConstructor(ctx, this_val)) {
38216
0
        args[0] = JS_NewInt32(ctx, argc);
38217
0
        obj = JS_CallConstructor(ctx, this_val, 1, (JSValueConst *)args);
38218
0
    } else {
38219
0
        obj = JS_NewArray(ctx);
38220
0
    }
38221
0
    if (JS_IsException(obj))
38222
0
        return JS_EXCEPTION;
38223
0
    for(i = 0; i < argc; i++) {
38224
0
        if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i]),
38225
0
                                        JS_PROP_THROW) < 0) {
38226
0
            goto fail;
38227
0
        }
38228
0
    }
38229
0
    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, argc)) < 0) {
38230
0
    fail:
38231
0
        JS_FreeValue(ctx, obj);
38232
0
        return JS_EXCEPTION;
38233
0
    }
38234
0
    return obj;
38235
0
}
38236
38237
static JSValue js_array_isArray(JSContext *ctx, JSValueConst this_val,
38238
                                int argc, JSValueConst *argv)
38239
0
{
38240
0
    int ret;
38241
0
    ret = JS_IsArray(ctx, argv[0]);
38242
0
    if (ret < 0)
38243
0
        return JS_EXCEPTION;
38244
0
    else
38245
0
        return JS_NewBool(ctx, ret);
38246
0
}
38247
38248
static JSValue js_get_this(JSContext *ctx,
38249
                           JSValueConst this_val)
38250
201k
{
38251
201k
    return JS_DupValue(ctx, this_val);
38252
201k
}
38253
38254
static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj,
38255
                                     JSValueConst len_val)
38256
201k
{
38257
201k
    JSValue ctor, ret, species;
38258
201k
    int res;
38259
201k
    JSContext *realm;
38260
    
38261
201k
    res = JS_IsArray(ctx, obj);
38262
201k
    if (res < 0)
38263
0
        return JS_EXCEPTION;
38264
201k
    if (!res)
38265
0
        return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
38266
201k
    ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
38267
201k
    if (JS_IsException(ctor))
38268
0
        return ctor;
38269
201k
    if (JS_IsConstructor(ctx, ctor)) {
38270
        /* legacy web compatibility */
38271
201k
        realm = JS_GetFunctionRealm(ctx, ctor);
38272
201k
        if (!realm) {
38273
0
            JS_FreeValue(ctx, ctor);
38274
0
            return JS_EXCEPTION;
38275
0
        }
38276
201k
        if (realm != ctx &&
38277
201k
            js_same_value(ctx, ctor, realm->array_ctor)) {
38278
0
            JS_FreeValue(ctx, ctor);
38279
0
            ctor = JS_UNDEFINED;
38280
0
        }
38281
201k
    }
38282
201k
    if (JS_IsObject(ctor)) {
38283
201k
        species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
38284
201k
        JS_FreeValue(ctx, ctor);
38285
201k
        if (JS_IsException(species))
38286
0
            return species;
38287
201k
        ctor = species;
38288
201k
        if (JS_IsNull(ctor))
38289
0
            ctor = JS_UNDEFINED;
38290
201k
    }
38291
201k
    if (JS_IsUndefined(ctor)) {
38292
0
        return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
38293
201k
    } else {
38294
201k
        ret = JS_CallConstructor(ctx, ctor, 1, &len_val);
38295
201k
        JS_FreeValue(ctx, ctor);
38296
201k
        return ret;
38297
201k
    }
38298
201k
}
38299
38300
static const JSCFunctionListEntry js_array_funcs[] = {
38301
    JS_CFUNC_DEF("isArray", 1, js_array_isArray ),
38302
    JS_CFUNC_DEF("from", 1, js_array_from ),
38303
    JS_CFUNC_DEF("of", 0, js_array_of ),
38304
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
38305
};
38306
38307
static int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj)
38308
0
{
38309
0
    JSValue val;
38310
38311
0
    if (!JS_IsObject(obj))
38312
0
        return FALSE;
38313
0
    val = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_isConcatSpreadable);
38314
0
    if (JS_IsException(val))
38315
0
        return -1;
38316
0
    if (!JS_IsUndefined(val))
38317
0
        return JS_ToBoolFree(ctx, val);
38318
0
    return JS_IsArray(ctx, obj);
38319
0
}
38320
38321
static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val,
38322
                               int argc, JSValueConst *argv)
38323
0
{
38324
0
    JSValue obj, arr, val;
38325
0
    JSValueConst e;
38326
0
    int64_t len, k, n;
38327
0
    int i, res;
38328
38329
0
    arr = JS_UNDEFINED;
38330
0
    obj = JS_ToObject(ctx, this_val);
38331
0
    if (JS_IsException(obj))
38332
0
        goto exception;
38333
38334
0
    arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
38335
0
    if (JS_IsException(arr))
38336
0
        goto exception;
38337
0
    n = 0;
38338
0
    for (i = -1; i < argc; i++) {
38339
0
        if (i < 0)
38340
0
            e = obj;
38341
0
        else
38342
0
            e = argv[i];
38343
38344
0
        res = JS_isConcatSpreadable(ctx, e);
38345
0
        if (res < 0)
38346
0
            goto exception;
38347
0
        if (res) {
38348
0
            if (js_get_length64(ctx, &len, e))
38349
0
                goto exception;
38350
0
            if (n + len > MAX_SAFE_INTEGER) {
38351
0
                JS_ThrowTypeError(ctx, "Array loo long");
38352
0
                goto exception;
38353
0
            }
38354
0
            for (k = 0; k < len; k++, n++) {
38355
0
                res = JS_TryGetPropertyInt64(ctx, e, k, &val);
38356
0
                if (res < 0)
38357
0
                    goto exception;
38358
0
                if (res) {
38359
0
                    if (JS_DefinePropertyValueInt64(ctx, arr, n, val,
38360
0
                                                    JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38361
0
                        goto exception;
38362
0
                }
38363
0
            }
38364
0
        } else {
38365
0
            if (n >= MAX_SAFE_INTEGER) {
38366
0
                JS_ThrowTypeError(ctx, "Array loo long");
38367
0
                goto exception;
38368
0
            }
38369
0
            if (JS_DefinePropertyValueInt64(ctx, arr, n, JS_DupValue(ctx, e),
38370
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38371
0
                goto exception;
38372
0
            n++;
38373
0
        }
38374
0
    }
38375
0
    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
38376
0
        goto exception;
38377
38378
0
    JS_FreeValue(ctx, obj);
38379
0
    return arr;
38380
38381
0
exception:
38382
0
    JS_FreeValue(ctx, arr);
38383
0
    JS_FreeValue(ctx, obj);
38384
0
    return JS_EXCEPTION;
38385
0
}
38386
38387
0
#define special_every    0
38388
0
#define special_some     1
38389
#define special_forEach  2
38390
0
#define special_map      3
38391
0
#define special_filter   4
38392
0
#define special_TA       8
38393
38394
static int js_typed_array_get_length_internal(JSContext *ctx, JSValueConst obj);
38395
38396
static JSValue js_typed_array___speciesCreate(JSContext *ctx,
38397
                                              JSValueConst this_val,
38398
                                              int argc, JSValueConst *argv);
38399
38400
static JSValue js_array_every(JSContext *ctx, JSValueConst this_val,
38401
                              int argc, JSValueConst *argv, int special)
38402
0
{
38403
0
    JSValue obj, val, index_val, res, ret;
38404
0
    JSValueConst args[3];
38405
0
    JSValueConst func, this_arg;
38406
0
    int64_t len, k, n;
38407
0
    int present;
38408
38409
0
    ret = JS_UNDEFINED;
38410
0
    val = JS_UNDEFINED;
38411
0
    if (special & special_TA) {
38412
0
        obj = JS_DupValue(ctx, this_val);
38413
0
        len = js_typed_array_get_length_internal(ctx, obj);
38414
0
        if (len < 0)
38415
0
            goto exception;
38416
0
    } else {
38417
0
        obj = JS_ToObject(ctx, this_val);
38418
0
        if (js_get_length64(ctx, &len, obj))
38419
0
            goto exception;
38420
0
    }
38421
0
    func = argv[0];
38422
0
    this_arg = JS_UNDEFINED;
38423
0
    if (argc > 1)
38424
0
        this_arg = argv[1];
38425
        
38426
0
    if (check_function(ctx, func))
38427
0
        goto exception;
38428
38429
0
    switch (special) {
38430
0
    case special_every:
38431
0
    case special_every | special_TA:
38432
0
        ret = JS_TRUE;
38433
0
        break;
38434
0
    case special_some:
38435
0
    case special_some | special_TA:
38436
0
        ret = JS_FALSE;
38437
0
        break;
38438
0
    case special_map:
38439
        /* XXX: JS_ArraySpeciesCreate should take int64_t */
38440
0
        ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt64(ctx, len));
38441
0
        if (JS_IsException(ret))
38442
0
            goto exception;
38443
0
        break;
38444
0
    case special_filter:
38445
0
        ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
38446
0
        if (JS_IsException(ret))
38447
0
            goto exception;
38448
0
        break;
38449
0
    case special_map | special_TA:
38450
0
        args[0] = obj;
38451
0
        args[1] = JS_NewInt32(ctx, len);
38452
0
        ret = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
38453
0
        if (JS_IsException(ret))
38454
0
            goto exception;
38455
0
        break;
38456
0
    case special_filter | special_TA:
38457
0
        ret = JS_NewArray(ctx);
38458
0
        if (JS_IsException(ret))
38459
0
            goto exception;
38460
0
        break;
38461
0
    }
38462
0
    n = 0;
38463
38464
0
    for(k = 0; k < len; k++) {
38465
0
        if (special & special_TA) {
38466
0
            val = JS_GetPropertyInt64(ctx, obj, k);
38467
0
            if (JS_IsException(val))
38468
0
                goto exception;
38469
0
            present = TRUE;
38470
0
        } else {
38471
0
            present = JS_TryGetPropertyInt64(ctx, obj, k, &val);
38472
0
            if (present < 0)
38473
0
                goto exception;
38474
0
        }
38475
0
        if (present) {
38476
0
            index_val = JS_NewInt64(ctx, k);
38477
0
            if (JS_IsException(index_val))
38478
0
                goto exception;
38479
0
            args[0] = val;
38480
0
            args[1] = index_val;
38481
0
            args[2] = obj;
38482
0
            res = JS_Call(ctx, func, this_arg, 3, args);
38483
0
            JS_FreeValue(ctx, index_val);
38484
0
            if (JS_IsException(res))
38485
0
                goto exception;
38486
0
            switch (special) {
38487
0
            case special_every:
38488
0
            case special_every | special_TA:
38489
0
                if (!JS_ToBoolFree(ctx, res)) {
38490
0
                    ret = JS_FALSE;
38491
0
                    goto done;
38492
0
                }
38493
0
                break;
38494
0
            case special_some:
38495
0
            case special_some | special_TA:
38496
0
                if (JS_ToBoolFree(ctx, res)) {
38497
0
                    ret = JS_TRUE;
38498
0
                    goto done;
38499
0
                }
38500
0
                break;
38501
0
            case special_map:
38502
0
                if (JS_DefinePropertyValueInt64(ctx, ret, k, res,
38503
0
                                                JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38504
0
                    goto exception;
38505
0
                break;
38506
0
            case special_map | special_TA:
38507
0
                if (JS_SetPropertyValue(ctx, ret, JS_NewInt32(ctx, k), res, JS_PROP_THROW) < 0)
38508
0
                    goto exception;
38509
0
                break;
38510
0
            case special_filter:
38511
0
            case special_filter | special_TA:
38512
0
                if (JS_ToBoolFree(ctx, res)) {
38513
0
                    if (JS_DefinePropertyValueInt64(ctx, ret, n++, JS_DupValue(ctx, val),
38514
0
                                                    JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38515
0
                        goto exception;
38516
0
                }
38517
0
                break;
38518
0
            default:
38519
0
                JS_FreeValue(ctx, res);
38520
0
                break;
38521
0
            }
38522
0
            JS_FreeValue(ctx, val);
38523
0
            val = JS_UNDEFINED;
38524
0
        }
38525
0
    }
38526
0
done:
38527
0
    if (special == (special_filter | special_TA)) {
38528
0
        JSValue arr;
38529
0
        args[0] = obj;
38530
0
        args[1] = JS_NewInt32(ctx, n);
38531
0
        arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
38532
0
        if (JS_IsException(arr))
38533
0
            goto exception;
38534
0
        args[0] = ret;
38535
0
        res = JS_Invoke(ctx, arr, JS_ATOM_set, 1, args);
38536
0
        if (check_exception_free(ctx, res))
38537
0
            goto exception;
38538
0
        JS_FreeValue(ctx, ret);
38539
0
        ret = arr;
38540
0
    }
38541
0
    JS_FreeValue(ctx, val);
38542
0
    JS_FreeValue(ctx, obj);
38543
0
    return ret;
38544
38545
0
exception:
38546
0
    JS_FreeValue(ctx, ret);
38547
0
    JS_FreeValue(ctx, val);
38548
0
    JS_FreeValue(ctx, obj);
38549
0
    return JS_EXCEPTION;
38550
0
}
38551
38552
#define special_reduce       0
38553
0
#define special_reduceRight  1
38554
38555
static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val,
38556
                               int argc, JSValueConst *argv, int special)
38557
0
{
38558
0
    JSValue obj, val, index_val, acc, acc1;
38559
0
    JSValueConst args[4];
38560
0
    JSValueConst func;
38561
0
    int64_t len, k, k1;
38562
0
    int present;
38563
38564
0
    acc = JS_UNDEFINED;
38565
0
    val = JS_UNDEFINED;
38566
0
    if (special & special_TA) {
38567
0
        obj = JS_DupValue(ctx, this_val);
38568
0
        len = js_typed_array_get_length_internal(ctx, obj);
38569
0
        if (len < 0)
38570
0
            goto exception;
38571
0
    } else {
38572
0
        obj = JS_ToObject(ctx, this_val);
38573
0
        if (js_get_length64(ctx, &len, obj))
38574
0
            goto exception;
38575
0
    }
38576
0
    func = argv[0];
38577
38578
0
    if (check_function(ctx, func))
38579
0
        goto exception;
38580
38581
0
    k = 0;
38582
0
    if (argc > 1) {
38583
0
        acc = JS_DupValue(ctx, argv[1]);
38584
0
    } else {
38585
0
        for(;;) {
38586
0
            if (k >= len) {
38587
0
                JS_ThrowTypeError(ctx, "empty array");
38588
0
                goto exception;
38589
0
            }
38590
0
            k1 = (special & special_reduceRight) ? len - k - 1 : k;
38591
0
            k++;
38592
0
            if (special & special_TA) {
38593
0
                acc = JS_GetPropertyInt64(ctx, obj, k1);
38594
0
                if (JS_IsException(acc))
38595
0
                    goto exception;
38596
0
                break;
38597
0
            } else {
38598
0
                present = JS_TryGetPropertyInt64(ctx, obj, k1, &acc);
38599
0
                if (present < 0)
38600
0
                    goto exception;
38601
0
                if (present)
38602
0
                    break;
38603
0
            }
38604
0
        }
38605
0
    }
38606
0
    for (; k < len; k++) {
38607
0
        k1 = (special & special_reduceRight) ? len - k - 1 : k;
38608
0
        if (special & special_TA) {
38609
0
            val = JS_GetPropertyInt64(ctx, obj, k1);
38610
0
            if (JS_IsException(val))
38611
0
                goto exception;
38612
0
            present = TRUE;
38613
0
        } else {
38614
0
            present = JS_TryGetPropertyInt64(ctx, obj, k1, &val);
38615
0
            if (present < 0)
38616
0
                goto exception;
38617
0
        }
38618
0
        if (present) {
38619
0
            index_val = JS_NewInt64(ctx, k1);
38620
0
            if (JS_IsException(index_val))
38621
0
                goto exception;
38622
0
            args[0] = acc;
38623
0
            args[1] = val;
38624
0
            args[2] = index_val;
38625
0
            args[3] = obj;
38626
0
            acc1 = JS_Call(ctx, func, JS_UNDEFINED, 4, args);
38627
0
            JS_FreeValue(ctx, index_val);
38628
0
            JS_FreeValue(ctx, val);
38629
0
            val = JS_UNDEFINED;
38630
0
            if (JS_IsException(acc1))
38631
0
                goto exception;
38632
0
            JS_FreeValue(ctx, acc);
38633
0
            acc = acc1;
38634
0
        }
38635
0
    }
38636
0
    JS_FreeValue(ctx, obj);
38637
0
    return acc;
38638
38639
0
exception:
38640
0
    JS_FreeValue(ctx, acc);
38641
0
    JS_FreeValue(ctx, val);
38642
0
    JS_FreeValue(ctx, obj);
38643
0
    return JS_EXCEPTION;
38644
0
}
38645
38646
static JSValue js_array_fill(JSContext *ctx, JSValueConst this_val,
38647
                             int argc, JSValueConst *argv)
38648
0
{
38649
0
    JSValue obj;
38650
0
    int64_t len, start, end;
38651
38652
0
    obj = JS_ToObject(ctx, this_val);
38653
0
    if (js_get_length64(ctx, &len, obj))
38654
0
        goto exception;
38655
38656
0
    start = 0;
38657
0
    if (argc > 1 && !JS_IsUndefined(argv[1])) {
38658
0
        if (JS_ToInt64Clamp(ctx, &start, argv[1], 0, len, len))
38659
0
            goto exception;
38660
0
    }
38661
38662
0
    end = len;
38663
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
38664
0
        if (JS_ToInt64Clamp(ctx, &end, argv[2], 0, len, len))
38665
0
            goto exception;
38666
0
    }
38667
38668
    /* XXX: should special case fast arrays */
38669
0
    while (start < end) {
38670
0
        if (JS_SetPropertyInt64(ctx, obj, start,
38671
0
                                JS_DupValue(ctx, argv[0])) < 0)
38672
0
            goto exception;
38673
0
        start++;
38674
0
    }
38675
0
    return obj;
38676
38677
0
 exception:
38678
0
    JS_FreeValue(ctx, obj);
38679
0
    return JS_EXCEPTION;
38680
0
}
38681
38682
static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val,
38683
                                 int argc, JSValueConst *argv)
38684
0
{
38685
0
    JSValue obj, val;
38686
0
    int64_t len, n, res;
38687
0
    JSValue *arrp;
38688
0
    uint32_t count;
38689
38690
0
    obj = JS_ToObject(ctx, this_val);
38691
0
    if (js_get_length64(ctx, &len, obj))
38692
0
        goto exception;
38693
38694
0
    res = FALSE;
38695
0
    if (len > 0) {
38696
0
        n = 0;
38697
0
        if (argc > 1) {
38698
0
            if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
38699
0
                goto exception;
38700
0
        }
38701
0
        if (js_get_fast_array(ctx, obj, &arrp, &count)) {
38702
0
            for (; n < count; n++) {
38703
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),
38704
0
                                  JS_DupValue(ctx, arrp[n]),
38705
0
                                  JS_EQ_SAME_VALUE_ZERO)) {
38706
0
                    res = TRUE;
38707
0
                    goto done;
38708
0
                }
38709
0
            }
38710
0
        }
38711
0
        for (; n < len; n++) {
38712
0
            val = JS_GetPropertyInt64(ctx, obj, n);
38713
0
            if (JS_IsException(val))
38714
0
                goto exception;
38715
0
            if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val,
38716
0
                              JS_EQ_SAME_VALUE_ZERO)) {
38717
0
                res = TRUE;
38718
0
                break;
38719
0
            }
38720
0
        }
38721
0
    }
38722
0
 done:
38723
0
    JS_FreeValue(ctx, obj);
38724
0
    return JS_NewBool(ctx, res);
38725
38726
0
 exception:
38727
0
    JS_FreeValue(ctx, obj);
38728
0
    return JS_EXCEPTION;
38729
0
}
38730
38731
static JSValue js_array_indexOf(JSContext *ctx, JSValueConst this_val,
38732
                                int argc, JSValueConst *argv)
38733
0
{
38734
0
    JSValue obj, val;
38735
0
    int64_t len, n, res;
38736
0
    JSValue *arrp;
38737
0
    uint32_t count;
38738
38739
0
    obj = JS_ToObject(ctx, this_val);
38740
0
    if (js_get_length64(ctx, &len, obj))
38741
0
        goto exception;
38742
38743
0
    res = -1;
38744
0
    if (len > 0) {
38745
0
        n = 0;
38746
0
        if (argc > 1) {
38747
0
            if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
38748
0
                goto exception;
38749
0
        }
38750
0
        if (js_get_fast_array(ctx, obj, &arrp, &count)) {
38751
0
            for (; n < count; n++) {
38752
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),
38753
0
                                  JS_DupValue(ctx, arrp[n]), JS_EQ_STRICT)) {
38754
0
                    res = n;
38755
0
                    goto done;
38756
0
                }
38757
0
            }
38758
0
        }
38759
0
        for (; n < len; n++) {
38760
0
            int present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
38761
0
            if (present < 0)
38762
0
                goto exception;
38763
0
            if (present) {
38764
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
38765
0
                    res = n;
38766
0
                    break;
38767
0
                }
38768
0
            }
38769
0
        }
38770
0
    }
38771
0
 done:
38772
0
    JS_FreeValue(ctx, obj);
38773
0
    return JS_NewInt64(ctx, res);
38774
38775
0
 exception:
38776
0
    JS_FreeValue(ctx, obj);
38777
0
    return JS_EXCEPTION;
38778
0
}
38779
38780
static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val,
38781
                                    int argc, JSValueConst *argv)
38782
0
{
38783
0
    JSValue obj, val;
38784
0
    int64_t len, n, res;
38785
0
    int present;
38786
38787
0
    obj = JS_ToObject(ctx, this_val);
38788
0
    if (js_get_length64(ctx, &len, obj))
38789
0
        goto exception;
38790
38791
0
    res = -1;
38792
0
    if (len > 0) {
38793
0
        n = len - 1;
38794
0
        if (argc > 1) {
38795
0
            if (JS_ToInt64Clamp(ctx, &n, argv[1], -1, len - 1, len))
38796
0
                goto exception;
38797
0
        }
38798
        /* XXX: should special case fast arrays */
38799
0
        for (; n >= 0; n--) {
38800
0
            present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
38801
0
            if (present < 0)
38802
0
                goto exception;
38803
0
            if (present) {
38804
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
38805
0
                    res = n;
38806
0
                    break;
38807
0
                }
38808
0
            }
38809
0
        }
38810
0
    }
38811
0
    JS_FreeValue(ctx, obj);
38812
0
    return JS_NewInt64(ctx, res);
38813
38814
0
 exception:
38815
0
    JS_FreeValue(ctx, obj);
38816
0
    return JS_EXCEPTION;
38817
0
}
38818
38819
static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
38820
                             int argc, JSValueConst *argv, int findIndex)
38821
0
{
38822
0
    JSValueConst func, this_arg;
38823
0
    JSValueConst args[3];
38824
0
    JSValue obj, val, index_val, res;
38825
0
    int64_t len, k;
38826
38827
0
    index_val = JS_UNDEFINED;
38828
0
    val = JS_UNDEFINED;
38829
0
    obj = JS_ToObject(ctx, this_val);
38830
0
    if (js_get_length64(ctx, &len, obj))
38831
0
        goto exception;
38832
38833
0
    func = argv[0];
38834
0
    if (check_function(ctx, func))
38835
0
        goto exception;
38836
38837
0
    this_arg = JS_UNDEFINED;
38838
0
    if (argc > 1)
38839
0
        this_arg = argv[1];
38840
38841
0
    for(k = 0; k < len; k++) {
38842
0
        index_val = JS_NewInt64(ctx, k);
38843
0
        if (JS_IsException(index_val))
38844
0
            goto exception;
38845
0
        val = JS_GetPropertyValue(ctx, obj, index_val);
38846
0
        if (JS_IsException(val))
38847
0
            goto exception;
38848
0
        args[0] = val;
38849
0
        args[1] = index_val;
38850
0
        args[2] = this_val;
38851
0
        res = JS_Call(ctx, func, this_arg, 3, args);
38852
0
        if (JS_IsException(res))
38853
0
            goto exception;
38854
0
        if (JS_ToBoolFree(ctx, res)) {
38855
0
            if (findIndex) {
38856
0
                JS_FreeValue(ctx, val);
38857
0
                JS_FreeValue(ctx, obj);
38858
0
                return index_val;
38859
0
            } else {
38860
0
                JS_FreeValue(ctx, index_val);
38861
0
                JS_FreeValue(ctx, obj);
38862
0
                return val;
38863
0
            }
38864
0
        }
38865
0
        JS_FreeValue(ctx, val);
38866
0
        JS_FreeValue(ctx, index_val);
38867
0
    }
38868
0
    JS_FreeValue(ctx, obj);
38869
0
    if (findIndex)
38870
0
        return JS_NewInt32(ctx, -1);
38871
0
    else
38872
0
        return JS_UNDEFINED;
38873
38874
0
exception:
38875
0
    JS_FreeValue(ctx, index_val);
38876
0
    JS_FreeValue(ctx, val);
38877
0
    JS_FreeValue(ctx, obj);
38878
0
    return JS_EXCEPTION;
38879
0
}
38880
38881
static JSValue js_array_toString(JSContext *ctx, JSValueConst this_val,
38882
                                 int argc, JSValueConst *argv)
38883
578k
{
38884
578k
    JSValue obj, method, ret;
38885
38886
578k
    obj = JS_ToObject(ctx, this_val);
38887
578k
    if (JS_IsException(obj))
38888
0
        return JS_EXCEPTION;
38889
578k
    method = JS_GetProperty(ctx, obj, JS_ATOM_join);
38890
578k
    if (JS_IsException(method)) {
38891
0
        ret = JS_EXCEPTION;
38892
0
    } else
38893
578k
    if (!JS_IsFunction(ctx, method)) {
38894
        /* Use intrinsic Object.prototype.toString */
38895
0
        JS_FreeValue(ctx, method);
38896
0
        ret = js_object_toString(ctx, obj, 0, NULL);
38897
578k
    } else {
38898
578k
        ret = JS_CallFree(ctx, method, obj, 0, NULL);
38899
578k
    }
38900
578k
    JS_FreeValue(ctx, obj);
38901
578k
    return ret;
38902
578k
}
38903
38904
static JSValue js_array_join(JSContext *ctx, JSValueConst this_val,
38905
                             int argc, JSValueConst *argv, int toLocaleString)
38906
578k
{
38907
578k
    JSValue obj, sep = JS_UNDEFINED, el;
38908
578k
    StringBuffer b_s, *b = &b_s;
38909
578k
    JSString *p = NULL;
38910
578k
    int64_t i, n;
38911
578k
    int c;
38912
38913
578k
    obj = JS_ToObject(ctx, this_val);
38914
578k
    if (js_get_length64(ctx, &n, obj))
38915
0
        goto exception;
38916
38917
578k
    c = ',';    /* default separator */
38918
578k
    if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
38919
0
        sep = JS_ToString(ctx, argv[0]);
38920
0
        if (JS_IsException(sep))
38921
0
            goto exception;
38922
0
        p = JS_VALUE_GET_STRING(sep);
38923
0
        if (p->len == 1 && !p->is_wide_char)
38924
0
            c = p->u.str8[0];
38925
0
        else
38926
0
            c = -1;
38927
0
    }
38928
578k
    string_buffer_init(ctx, b, 0);
38929
38930
1.64M
    for(i = 0; i < n; i++) {
38931
1.06M
        if (i > 0) {
38932
648k
            if (c >= 0) {
38933
648k
                string_buffer_putc8(b, c);
38934
648k
            } else {
38935
0
                string_buffer_concat(b, p, 0, p->len);
38936
0
            }
38937
648k
        }
38938
1.06M
        el = JS_GetPropertyUint32(ctx, obj, i);
38939
1.06M
        if (JS_IsException(el))
38940
0
            goto fail;
38941
1.06M
        if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
38942
1.06M
            if (toLocaleString) {
38943
0
                el = JS_ToLocaleStringFree(ctx, el);
38944
0
            }
38945
1.06M
            if (string_buffer_concat_value_free(b, el))
38946
0
                goto fail;
38947
1.06M
        }
38948
1.06M
    }
38949
578k
    JS_FreeValue(ctx, sep);
38950
578k
    JS_FreeValue(ctx, obj);
38951
578k
    return string_buffer_end(b);
38952
38953
0
fail:
38954
0
    string_buffer_free(b);
38955
0
    JS_FreeValue(ctx, sep);
38956
0
exception:
38957
0
    JS_FreeValue(ctx, obj);
38958
0
    return JS_EXCEPTION;
38959
0
}
38960
38961
static JSValue js_array_pop(JSContext *ctx, JSValueConst this_val,
38962
                            int argc, JSValueConst *argv, int shift)
38963
0
{
38964
0
    JSValue obj, res = JS_UNDEFINED;
38965
0
    int64_t len, newLen;
38966
0
    JSValue *arrp;
38967
0
    uint32_t count32;
38968
38969
0
    obj = JS_ToObject(ctx, this_val);
38970
0
    if (js_get_length64(ctx, &len, obj))
38971
0
        goto exception;
38972
0
    newLen = 0;
38973
0
    if (len > 0) {
38974
0
        newLen = len - 1;
38975
        /* Special case fast arrays */
38976
0
        if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
38977
0
            JSObject *p = JS_VALUE_GET_OBJ(obj);
38978
0
            if (shift) {
38979
0
                res = arrp[0];
38980
0
                memmove(arrp, arrp + 1, (count32 - 1) * sizeof(*arrp));
38981
0
                p->u.array.count--;
38982
0
            } else {
38983
0
                res = arrp[count32 - 1];
38984
0
                p->u.array.count--;
38985
0
            }
38986
0
        } else {
38987
0
            if (shift) {
38988
0
                res = JS_GetPropertyInt64(ctx, obj, 0);
38989
0
                if (JS_IsException(res))
38990
0
                    goto exception;
38991
0
                if (JS_CopySubArray(ctx, obj, 0, 1, len - 1, +1))
38992
0
                    goto exception;
38993
0
            } else {
38994
0
                res = JS_GetPropertyInt64(ctx, obj, newLen);
38995
0
                if (JS_IsException(res))
38996
0
                    goto exception;
38997
0
            }
38998
0
            if (JS_DeletePropertyInt64(ctx, obj, newLen, JS_PROP_THROW) < 0)
38999
0
                goto exception;
39000
0
        }
39001
0
    }
39002
0
    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
39003
0
        goto exception;
39004
39005
0
    JS_FreeValue(ctx, obj);
39006
0
    return res;
39007
39008
0
 exception:
39009
0
    JS_FreeValue(ctx, res);
39010
0
    JS_FreeValue(ctx, obj);
39011
0
    return JS_EXCEPTION;
39012
0
}
39013
39014
static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
39015
                             int argc, JSValueConst *argv, int unshift)
39016
0
{
39017
0
    JSValue obj;
39018
0
    int i;
39019
0
    int64_t len, from, newLen;
39020
39021
0
    obj = JS_ToObject(ctx, this_val);
39022
0
    if (js_get_length64(ctx, &len, obj))
39023
0
        goto exception;
39024
0
    newLen = len + argc;
39025
0
    if (newLen > MAX_SAFE_INTEGER) {
39026
0
        JS_ThrowTypeError(ctx, "Array loo long");
39027
0
        goto exception;
39028
0
    }
39029
0
    from = len;
39030
0
    if (unshift && argc > 0) {
39031
0
        if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
39032
0
            goto exception;
39033
0
        from = 0;
39034
0
    }
39035
0
    for(i = 0; i < argc; i++) {
39036
0
        if (JS_SetPropertyInt64(ctx, obj, from + i,
39037
0
                                JS_DupValue(ctx, argv[i])) < 0)
39038
0
            goto exception;
39039
0
    }
39040
0
    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
39041
0
        goto exception;
39042
39043
0
    JS_FreeValue(ctx, obj);
39044
0
    return JS_NewInt64(ctx, newLen);
39045
39046
0
 exception:
39047
0
    JS_FreeValue(ctx, obj);
39048
0
    return JS_EXCEPTION;
39049
0
}
39050
39051
static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val,
39052
                                int argc, JSValueConst *argv)
39053
0
{
39054
0
    JSValue obj, lval, hval;
39055
0
    JSValue *arrp;
39056
0
    int64_t len, l, h;
39057
0
    int l_present, h_present;
39058
0
    uint32_t count32;
39059
39060
0
    lval = JS_UNDEFINED;
39061
0
    obj = JS_ToObject(ctx, this_val);
39062
0
    if (js_get_length64(ctx, &len, obj))
39063
0
        goto exception;
39064
39065
    /* Special case fast arrays */
39066
0
    if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
39067
0
        uint32_t ll, hh;
39068
39069
0
        if (count32 > 1) {
39070
0
            for (ll = 0, hh = count32 - 1; ll < hh; ll++, hh--) {
39071
0
                lval = arrp[ll];
39072
0
                arrp[ll] = arrp[hh];
39073
0
                arrp[hh] = lval;
39074
0
            }
39075
0
        }
39076
0
        return obj;
39077
0
    }
39078
39079
0
    for (l = 0, h = len - 1; l < h; l++, h--) {
39080
0
        l_present = JS_TryGetPropertyInt64(ctx, obj, l, &lval);
39081
0
        if (l_present < 0)
39082
0
            goto exception;
39083
0
        h_present = JS_TryGetPropertyInt64(ctx, obj, h, &hval);
39084
0
        if (h_present < 0)
39085
0
            goto exception;
39086
0
        if (h_present) {
39087
0
            if (JS_SetPropertyInt64(ctx, obj, l, hval) < 0)
39088
0
                goto exception;
39089
39090
0
            if (l_present) {
39091
0
                if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
39092
0
                    lval = JS_UNDEFINED;
39093
0
                    goto exception;
39094
0
                }
39095
0
                lval = JS_UNDEFINED;
39096
0
            } else {
39097
0
                if (JS_DeletePropertyInt64(ctx, obj, h, JS_PROP_THROW) < 0)
39098
0
                    goto exception;
39099
0
            }
39100
0
        } else {
39101
0
            if (l_present) {
39102
0
                if (JS_DeletePropertyInt64(ctx, obj, l, JS_PROP_THROW) < 0)
39103
0
                    goto exception;
39104
0
                if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
39105
0
                    lval = JS_UNDEFINED;
39106
0
                    goto exception;
39107
0
                }
39108
0
                lval = JS_UNDEFINED;
39109
0
            }
39110
0
        }
39111
0
    }
39112
0
    return obj;
39113
39114
0
 exception:
39115
0
    JS_FreeValue(ctx, lval);
39116
0
    JS_FreeValue(ctx, obj);
39117
0
    return JS_EXCEPTION;
39118
0
}
39119
39120
static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
39121
                              int argc, JSValueConst *argv, int splice)
39122
201k
{
39123
201k
    JSValue obj, arr, val, len_val;
39124
201k
    int64_t len, start, k, final, n, count, del_count, new_len;
39125
201k
    int kPresent;
39126
201k
    JSValue *arrp;
39127
201k
    uint32_t count32, i, item_count;
39128
39129
201k
    arr = JS_UNDEFINED;
39130
201k
    obj = JS_ToObject(ctx, this_val);
39131
201k
    if (js_get_length64(ctx, &len, obj))
39132
0
        goto exception;
39133
39134
201k
    if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
39135
2
        goto exception;
39136
39137
201k
    if (splice) {
39138
201k
        if (argc == 0) {
39139
0
            item_count = 0;
39140
0
            del_count = 0;
39141
0
        } else
39142
201k
        if (argc == 1) {
39143
9
            item_count = 0;
39144
9
            del_count = len - start;
39145
201k
        } else {
39146
201k
            item_count = argc - 2;
39147
201k
            if (JS_ToInt64Clamp(ctx, &del_count, argv[1], 0, len - start, 0))
39148
0
                goto exception;
39149
201k
        }
39150
201k
        if (len + item_count - del_count > MAX_SAFE_INTEGER) {
39151
0
            JS_ThrowTypeError(ctx, "Array loo long");
39152
0
            goto exception;
39153
0
        }
39154
201k
        count = del_count;
39155
201k
    } else {
39156
0
        item_count = 0; /* avoid warning */
39157
0
        final = len;
39158
0
        if (!JS_IsUndefined(argv[1])) {
39159
0
            if (JS_ToInt64Clamp(ctx, &final, argv[1], 0, len, len))
39160
0
                goto exception;
39161
0
        }
39162
0
        count = max_int64(final - start, 0);
39163
0
    }
39164
201k
    len_val = JS_NewInt64(ctx, count);
39165
201k
    arr = JS_ArraySpeciesCreate(ctx, obj, len_val);
39166
201k
    JS_FreeValue(ctx, len_val);
39167
201k
    if (JS_IsException(arr))
39168
0
        goto exception;
39169
39170
201k
    k = start;
39171
201k
    final = start + count;
39172
201k
    n = 0;
39173
    /* The fast array test on arr ensures that
39174
       JS_CreateDataPropertyUint32() won't modify obj in case arr is
39175
       an exotic object */
39176
    /* Special case fast arrays */
39177
201k
    if (js_get_fast_array(ctx, obj, &arrp, &count32) &&
39178
201k
        js_is_fast_array(ctx, arr)) {
39179
        /* XXX: should share code with fast array constructor */
39180
283k
        for (; k < final && k < count32; k++, n++) {
39181
81.5k
            if (JS_CreateDataPropertyUint32(ctx, arr, n, JS_DupValue(ctx, arrp[k]), JS_PROP_THROW) < 0)
39182
0
                goto exception;
39183
81.5k
        }
39184
201k
    }
39185
    /* Copy the remaining elements if any (handle case of inherited properties) */
39186
201k
    for (; k < final; k++, n++) {
39187
0
        kPresent = JS_TryGetPropertyInt64(ctx, obj, k, &val);
39188
0
        if (kPresent < 0)
39189
0
            goto exception;
39190
0
        if (kPresent) {
39191
0
            if (JS_CreateDataPropertyUint32(ctx, arr, n, val, JS_PROP_THROW) < 0)
39192
0
                goto exception;
39193
0
        }
39194
0
    }
39195
201k
    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
39196
0
        goto exception;
39197
39198
201k
    if (splice) {
39199
201k
        new_len = len + item_count - del_count;
39200
201k
        if (item_count != del_count) {
39201
201k
            if (JS_CopySubArray(ctx, obj, start + item_count,
39202
201k
                                start + del_count, len - (start + del_count),
39203
201k
                                item_count <= del_count ? +1 : -1) < 0)
39204
0
                goto exception;
39205
39206
283k
            for (k = len; k-- > new_len; ) {
39207
81.5k
                if (JS_DeletePropertyInt64(ctx, obj, k, JS_PROP_THROW) < 0)
39208
0
                    goto exception;
39209
81.5k
            }
39210
201k
        }
39211
403k
        for (i = 0; i < item_count; i++) {
39212
201k
            if (JS_SetPropertyInt64(ctx, obj, start + i, JS_DupValue(ctx, argv[i + 2])) < 0)
39213
0
                goto exception;
39214
201k
        }
39215
201k
        if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, new_len)) < 0)
39216
0
            goto exception;
39217
201k
    }
39218
201k
    JS_FreeValue(ctx, obj);
39219
201k
    return arr;
39220
39221
2
 exception:
39222
2
    JS_FreeValue(ctx, obj);
39223
2
    JS_FreeValue(ctx, arr);
39224
2
    return JS_EXCEPTION;
39225
201k
}
39226
39227
static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val,
39228
                                   int argc, JSValueConst *argv)
39229
0
{
39230
0
    JSValue obj;
39231
0
    int64_t len, from, to, final, count;
39232
39233
0
    obj = JS_ToObject(ctx, this_val);
39234
0
    if (js_get_length64(ctx, &len, obj))
39235
0
        goto exception;
39236
39237
0
    if (JS_ToInt64Clamp(ctx, &to, argv[0], 0, len, len))
39238
0
        goto exception;
39239
39240
0
    if (JS_ToInt64Clamp(ctx, &from, argv[1], 0, len, len))
39241
0
        goto exception;
39242
39243
0
    final = len;
39244
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
39245
0
        if (JS_ToInt64Clamp(ctx, &final, argv[2], 0, len, len))
39246
0
            goto exception;
39247
0
    }
39248
39249
0
    count = min_int64(final - from, len - to);
39250
39251
0
    if (JS_CopySubArray(ctx, obj, to, from, count,
39252
0
                        (from < to && to < from + count) ? -1 : +1))
39253
0
        goto exception;
39254
39255
0
    return obj;
39256
39257
0
 exception:
39258
0
    JS_FreeValue(ctx, obj);
39259
0
    return JS_EXCEPTION;
39260
0
}
39261
39262
static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
39263
                                   JSValueConst source, int64_t sourceLen,
39264
                                   int64_t targetIndex, int depth,
39265
                                   JSValueConst mapperFunction,
39266
                                   JSValueConst thisArg)
39267
0
{
39268
0
    JSValue element;
39269
0
    int64_t sourceIndex, elementLen;
39270
0
    int present, is_array;
39271
39272
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
39273
0
        JS_ThrowStackOverflow(ctx);
39274
0
        return -1;
39275
0
    }
39276
39277
0
    for (sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
39278
0
        present = JS_TryGetPropertyInt64(ctx, source, sourceIndex, &element);
39279
0
        if (present < 0)
39280
0
            return -1;
39281
0
        if (!present)
39282
0
            continue;
39283
0
        if (!JS_IsUndefined(mapperFunction)) {
39284
0
            JSValueConst args[3] = { element, JS_NewInt64(ctx, sourceIndex), source };
39285
0
            element = JS_Call(ctx, mapperFunction, thisArg, 3, args);
39286
0
            JS_FreeValue(ctx, (JSValue)args[0]);
39287
0
            JS_FreeValue(ctx, (JSValue)args[1]);
39288
0
            if (JS_IsException(element))
39289
0
                return -1;
39290
0
        }
39291
0
        if (depth > 0) {
39292
0
            is_array = JS_IsArray(ctx, element);
39293
0
            if (is_array < 0)
39294
0
                goto fail;
39295
0
            if (is_array) {
39296
0
                if (js_get_length64(ctx, &elementLen, element) < 0)
39297
0
                    goto fail;
39298
0
                targetIndex = JS_FlattenIntoArray(ctx, target, element,
39299
0
                                                  elementLen, targetIndex,
39300
0
                                                  depth - 1,
39301
0
                                                  JS_UNDEFINED, JS_UNDEFINED);
39302
0
                if (targetIndex < 0)
39303
0
                    goto fail;
39304
0
                JS_FreeValue(ctx, element);
39305
0
                continue;
39306
0
            }
39307
0
        }
39308
0
        if (targetIndex >= MAX_SAFE_INTEGER) {
39309
0
            JS_ThrowTypeError(ctx, "Array too long");
39310
0
            goto fail;
39311
0
        }
39312
0
        if (JS_DefinePropertyValueInt64(ctx, target, targetIndex, element,
39313
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
39314
0
            return -1;
39315
0
        targetIndex++;
39316
0
    }
39317
0
    return targetIndex;
39318
39319
0
fail:
39320
0
    JS_FreeValue(ctx, element);
39321
0
    return -1;
39322
0
}
39323
39324
static JSValue js_array_flatten(JSContext *ctx, JSValueConst this_val,
39325
                                int argc, JSValueConst *argv, int map)
39326
0
{
39327
0
    JSValue obj, arr;
39328
0
    JSValueConst mapperFunction, thisArg;
39329
0
    int64_t sourceLen;
39330
0
    int depthNum;
39331
39332
0
    arr = JS_UNDEFINED;
39333
0
    obj = JS_ToObject(ctx, this_val);
39334
0
    if (js_get_length64(ctx, &sourceLen, obj))
39335
0
        goto exception;
39336
39337
0
    depthNum = 1;
39338
0
    mapperFunction = JS_UNDEFINED;
39339
0
    thisArg = JS_UNDEFINED;
39340
0
    if (map) {
39341
0
        mapperFunction = argv[0];
39342
0
        if (argc > 1) {
39343
0
            thisArg = argv[1];
39344
0
        }
39345
0
        if (check_function(ctx, mapperFunction))
39346
0
            goto exception;
39347
0
    } else {
39348
0
        if (argc > 0 && !JS_IsUndefined(argv[0])) {
39349
0
            if (JS_ToInt32Sat(ctx, &depthNum, argv[0]) < 0)
39350
0
                goto exception;
39351
0
        }
39352
0
    }
39353
0
    arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
39354
0
    if (JS_IsException(arr))
39355
0
        goto exception;
39356
0
    if (JS_FlattenIntoArray(ctx, arr, obj, sourceLen, 0, depthNum,
39357
0
                            mapperFunction, thisArg) < 0)
39358
0
        goto exception;
39359
0
    JS_FreeValue(ctx, obj);
39360
0
    return arr;
39361
39362
0
exception:
39363
0
    JS_FreeValue(ctx, obj);
39364
0
    JS_FreeValue(ctx, arr);
39365
0
    return JS_EXCEPTION;
39366
0
}
39367
39368
/* Array sort */
39369
39370
typedef struct ValueSlot {
39371
    JSValue val;
39372
    JSString *str;
39373
    int64_t pos;
39374
} ValueSlot;
39375
39376
struct array_sort_context {
39377
    JSContext *ctx;
39378
    int exception;
39379
    int has_method;
39380
    JSValueConst method;
39381
};
39382
39383
0
static int js_array_cmp_generic(const void *a, const void *b, void *opaque) {
39384
0
    struct array_sort_context *psc = opaque;
39385
0
    JSContext *ctx = psc->ctx;
39386
0
    JSValueConst argv[2];
39387
0
    JSValue res;
39388
0
    ValueSlot *ap = (ValueSlot *)(void *)a;
39389
0
    ValueSlot *bp = (ValueSlot *)(void *)b;
39390
0
    int cmp;
39391
39392
0
    if (psc->exception)
39393
0
        return 0;
39394
39395
0
    if (psc->has_method) {
39396
        /* custom sort function is specified as returning 0 for identical
39397
         * objects: avoid method call overhead.
39398
         */
39399
0
        if (!memcmp(&ap->val, &bp->val, sizeof(ap->val)))
39400
0
            goto cmp_same;
39401
0
        argv[0] = ap->val;
39402
0
        argv[1] = bp->val;
39403
0
        res = JS_Call(ctx, psc->method, JS_UNDEFINED, 2, argv);
39404
0
        if (JS_IsException(res))
39405
0
            goto exception;
39406
0
        if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
39407
0
            int val = JS_VALUE_GET_INT(res);
39408
0
            cmp = (val > 0) - (val < 0);
39409
0
        } else {
39410
0
            double val;
39411
0
            if (JS_ToFloat64Free(ctx, &val, res) < 0)
39412
0
                goto exception;
39413
0
            cmp = (val > 0) - (val < 0);
39414
0
        }
39415
0
    } else {
39416
        /* Not supposed to bypass ToString even for identical objects as
39417
         * tested in test262/test/built-ins/Array/prototype/sort/bug_596_1.js
39418
         */
39419
0
        if (!ap->str) {
39420
0
            JSValue str = JS_ToString(ctx, ap->val);
39421
0
            if (JS_IsException(str))
39422
0
                goto exception;
39423
0
            ap->str = JS_VALUE_GET_STRING(str);
39424
0
        }
39425
0
        if (!bp->str) {
39426
0
            JSValue str = JS_ToString(ctx, bp->val);
39427
0
            if (JS_IsException(str))
39428
0
                goto exception;
39429
0
            bp->str = JS_VALUE_GET_STRING(str);
39430
0
        }
39431
0
        cmp = js_string_compare(ctx, ap->str, bp->str);
39432
0
    }
39433
0
    if (cmp != 0)
39434
0
        return cmp;
39435
0
cmp_same:
39436
    /* make sort stable: compare array offsets */
39437
0
    return (ap->pos > bp->pos) - (ap->pos < bp->pos);
39438
39439
0
exception:
39440
0
    psc->exception = 1;
39441
0
    return 0;
39442
0
}
39443
39444
static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val,
39445
                             int argc, JSValueConst *argv)
39446
0
{
39447
0
    struct array_sort_context asc = { ctx, 0, 0, argv[0] };
39448
0
    JSValue obj = JS_UNDEFINED;
39449
0
    ValueSlot *array = NULL;
39450
0
    size_t array_size = 0, pos = 0, n = 0;
39451
0
    int64_t i, len, undefined_count = 0;
39452
0
    int present;
39453
39454
0
    if (!JS_IsUndefined(asc.method)) {
39455
0
        if (check_function(ctx, asc.method))
39456
0
            goto exception;
39457
0
        asc.has_method = 1;
39458
0
    }
39459
0
    obj = JS_ToObject(ctx, this_val);
39460
0
    if (js_get_length64(ctx, &len, obj))
39461
0
        goto exception;
39462
39463
    /* XXX: should special case fast arrays */
39464
0
    for (i = 0; i < len; i++) {
39465
0
        if (pos >= array_size) {
39466
0
            size_t new_size, slack;
39467
0
            ValueSlot *new_array;
39468
0
            new_size = (array_size + (array_size >> 1) + 31) & ~15;
39469
0
            new_array = js_realloc2(ctx, array, new_size * sizeof(*array), &slack);
39470
0
            if (new_array == NULL)
39471
0
                goto exception;
39472
0
            new_size += slack / sizeof(*new_array);
39473
0
            array = new_array;
39474
0
            array_size = new_size;
39475
0
        }
39476
0
        present = JS_TryGetPropertyInt64(ctx, obj, i, &array[pos].val);
39477
0
        if (present < 0)
39478
0
            goto exception;
39479
0
        if (present == 0)
39480
0
            continue;
39481
0
        if (JS_IsUndefined(array[pos].val)) {
39482
0
            undefined_count++;
39483
0
            continue;
39484
0
        }
39485
0
        array[pos].str = NULL;
39486
0
        array[pos].pos = i;
39487
0
        pos++;
39488
0
    }
39489
0
    rqsort(array, pos, sizeof(*array), js_array_cmp_generic, &asc);
39490
0
    if (asc.exception)
39491
0
        goto exception;
39492
39493
    /* XXX: should special case fast arrays */
39494
0
    while (n < pos) {
39495
0
        if (array[n].str)
39496
0
            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
39497
0
        if (array[n].pos == n) {
39498
0
            JS_FreeValue(ctx, array[n].val);
39499
0
        } else {
39500
0
            if (JS_SetPropertyInt64(ctx, obj, n, array[n].val) < 0) {
39501
0
                n++;
39502
0
                goto exception;
39503
0
            }
39504
0
        }
39505
0
        n++;
39506
0
    }
39507
0
    js_free(ctx, array);
39508
0
    for (i = n; undefined_count-- > 0; i++) {
39509
0
        if (JS_SetPropertyInt64(ctx, obj, i, JS_UNDEFINED) < 0)
39510
0
            goto fail;
39511
0
    }
39512
0
    for (; i < len; i++) {
39513
0
        if (JS_DeletePropertyInt64(ctx, obj, i, JS_PROP_THROW) < 0)
39514
0
            goto fail;
39515
0
    }
39516
0
    return obj;
39517
39518
0
exception:
39519
0
    for (; n < pos; n++) {
39520
0
        JS_FreeValue(ctx, array[n].val);
39521
0
        if (array[n].str)
39522
0
            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
39523
0
    }
39524
0
    js_free(ctx, array);
39525
0
fail:
39526
0
    JS_FreeValue(ctx, obj);
39527
0
    return JS_EXCEPTION;
39528
0
}
39529
39530
typedef struct JSArrayIteratorData {
39531
    JSValue obj;
39532
    JSIteratorKindEnum kind;
39533
    uint32_t idx;
39534
} JSArrayIteratorData;
39535
39536
static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val)
39537
167k
{
39538
167k
    JSObject *p = JS_VALUE_GET_OBJ(val);
39539
167k
    JSArrayIteratorData *it = p->u.array_iterator_data;
39540
167k
    if (it) {
39541
167k
        JS_FreeValueRT(rt, it->obj);
39542
167k
        js_free_rt(rt, it);
39543
167k
    }
39544
167k
}
39545
39546
static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
39547
                                   JS_MarkFunc *mark_func)
39548
6
{
39549
6
    JSObject *p = JS_VALUE_GET_OBJ(val);
39550
6
    JSArrayIteratorData *it = p->u.array_iterator_data;
39551
6
    if (it) {
39552
6
        JS_MarkValue(rt, it->obj, mark_func);
39553
6
    }
39554
6
}
39555
39556
static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab)
39557
0
{
39558
0
    JSValue obj;
39559
0
    int i;
39560
39561
0
    obj = JS_NewArray(ctx);
39562
0
    if (JS_IsException(obj))
39563
0
        return JS_EXCEPTION;
39564
0
    for(i = 0; i < len; i++) {
39565
0
        if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, tab[i]), 0) < 0) {
39566
0
            JS_FreeValue(ctx, obj);
39567
0
            return JS_EXCEPTION;
39568
0
        }
39569
0
    }
39570
0
    return obj;
39571
0
}
39572
39573
static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
39574
                                        int argc, JSValueConst *argv, int magic)
39575
167k
{
39576
167k
    JSValue enum_obj, arr;
39577
167k
    JSArrayIteratorData *it;
39578
167k
    JSIteratorKindEnum kind;
39579
167k
    int class_id;
39580
39581
167k
    kind = magic & 3;
39582
167k
    if (magic & 4) {
39583
        /* string iterator case */
39584
167k
        arr = JS_ToStringCheckObject(ctx, this_val);
39585
167k
        class_id = JS_CLASS_STRING_ITERATOR;
39586
167k
    } else {
39587
692
        arr = JS_ToObject(ctx, this_val);
39588
692
        class_id = JS_CLASS_ARRAY_ITERATOR;
39589
692
    }
39590
167k
    if (JS_IsException(arr))
39591
0
        goto fail;
39592
167k
    enum_obj = JS_NewObjectClass(ctx, class_id);
39593
167k
    if (JS_IsException(enum_obj))
39594
0
        goto fail;
39595
167k
    it = js_malloc(ctx, sizeof(*it));
39596
167k
    if (!it)
39597
0
        goto fail1;
39598
167k
    it->obj = arr;
39599
167k
    it->kind = kind;
39600
167k
    it->idx = 0;
39601
167k
    JS_SetOpaque(enum_obj, it);
39602
167k
    return enum_obj;
39603
0
 fail1:
39604
0
    JS_FreeValue(ctx, enum_obj);
39605
0
 fail:
39606
0
    JS_FreeValue(ctx, arr);
39607
0
    return JS_EXCEPTION;
39608
0
}
39609
39610
static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
39611
                                      int argc, JSValueConst *argv,
39612
                                      BOOL *pdone, int magic)
39613
322
{
39614
322
    JSArrayIteratorData *it;
39615
322
    uint32_t len, idx;
39616
322
    JSValue val, obj;
39617
322
    JSObject *p;
39618
39619
322
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_ITERATOR);
39620
322
    if (!it)
39621
0
        goto fail1;
39622
322
    if (JS_IsUndefined(it->obj))
39623
0
        goto done;
39624
322
    p = JS_VALUE_GET_OBJ(it->obj);
39625
322
    if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
39626
322
        p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
39627
0
        if (typed_array_is_detached(ctx, p)) {
39628
0
            JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
39629
0
            goto fail1;
39630
0
        }
39631
0
        len = p->u.array.count;
39632
322
    } else {
39633
322
        if (js_get_length32(ctx, &len, it->obj)) {
39634
0
        fail1:
39635
0
            *pdone = FALSE;
39636
0
            return JS_EXCEPTION;
39637
0
        }
39638
322
    }
39639
322
    idx = it->idx;
39640
322
    if (idx >= len) {
39641
107
        JS_FreeValue(ctx, it->obj);
39642
107
        it->obj = JS_UNDEFINED;
39643
107
    done:
39644
107
        *pdone = TRUE;
39645
107
        return JS_UNDEFINED;
39646
107
    }
39647
215
    it->idx = idx + 1;
39648
215
    *pdone = FALSE;
39649
215
    if (it->kind == JS_ITERATOR_KIND_KEY) {
39650
0
        return JS_NewUint32(ctx, idx);
39651
215
    } else {
39652
215
        val = JS_GetPropertyUint32(ctx, it->obj, idx);
39653
215
        if (JS_IsException(val))
39654
0
            return JS_EXCEPTION;
39655
215
        if (it->kind == JS_ITERATOR_KIND_VALUE) {
39656
215
            return val;
39657
215
        } else {
39658
0
            JSValueConst args[2];
39659
0
            JSValue num;
39660
0
            num = JS_NewUint32(ctx, idx);
39661
0
            args[0] = num;
39662
0
            args[1] = val;
39663
0
            obj = js_create_array(ctx, 2, args);
39664
0
            JS_FreeValue(ctx, val);
39665
0
            JS_FreeValue(ctx, num);
39666
0
            return obj;
39667
0
        }
39668
215
    }
39669
215
}
39670
39671
static JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val,
39672
                                          int argc, JSValueConst *argv)
39673
58
{
39674
58
    return JS_DupValue(ctx, this_val);
39675
58
}
39676
39677
static const JSCFunctionListEntry js_iterator_proto_funcs[] = {
39678
    JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator ),
39679
};
39680
39681
static const JSCFunctionListEntry js_array_proto_funcs[] = {
39682
    JS_CFUNC_DEF("concat", 1, js_array_concat ),
39683
    JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every ),
39684
    JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some ),
39685
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach ),
39686
    JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map ),
39687
    JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter ),
39688
    JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ),
39689
    JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ),
39690
    JS_CFUNC_DEF("fill", 1, js_array_fill ),
39691
    JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, 0 ),
39692
    JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, 1 ),
39693
    JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ),
39694
    JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ),
39695
    JS_CFUNC_DEF("includes", 1, js_array_includes ),
39696
    JS_CFUNC_MAGIC_DEF("join", 1, js_array_join, 0 ),
39697
    JS_CFUNC_DEF("toString", 0, js_array_toString ),
39698
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_array_join, 1 ),
39699
    JS_CFUNC_MAGIC_DEF("pop", 0, js_array_pop, 0 ),
39700
    JS_CFUNC_MAGIC_DEF("push", 1, js_array_push, 0 ),
39701
    JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1 ),
39702
    JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ),
39703
    JS_CFUNC_DEF("reverse", 0, js_array_reverse ),
39704
    JS_CFUNC_DEF("sort", 1, js_array_sort ),
39705
    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ),
39706
    JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ),
39707
    JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ),
39708
    JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ),
39709
    JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ),
39710
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ),
39711
    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
39712
    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ),
39713
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
39714
};
39715
39716
static const JSCFunctionListEntry js_array_iterator_proto_funcs[] = {
39717
    JS_ITERATOR_NEXT_DEF("next", 0, js_array_iterator_next, 0 ),
39718
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Array Iterator", JS_PROP_CONFIGURABLE ),
39719
};
39720
39721
/* Number */
39722
39723
static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
39724
                                     int argc, JSValueConst *argv)
39725
0
{
39726
0
    JSValue val, obj;
39727
0
    if (argc == 0) {
39728
0
        val = JS_NewInt32(ctx, 0);
39729
0
    } else {
39730
0
        val = JS_ToNumeric(ctx, argv[0]);
39731
0
        if (JS_IsException(val))
39732
0
            return val;
39733
0
        switch(JS_VALUE_GET_TAG(val)) {
39734
0
#ifdef CONFIG_BIGNUM
39735
0
        case JS_TAG_BIG_INT:
39736
0
        case JS_TAG_BIG_FLOAT:
39737
0
            {
39738
0
                JSBigFloat *p = JS_VALUE_GET_PTR(val);
39739
0
                double d;
39740
0
                bf_get_float64(&p->num, &d, BF_RNDN);
39741
0
                JS_FreeValue(ctx, val);
39742
0
                val = __JS_NewFloat64(ctx, d);
39743
0
            }
39744
0
            break;
39745
0
        case JS_TAG_BIG_DECIMAL:
39746
0
            val = JS_ToStringFree(ctx, val);
39747
0
            if (JS_IsException(val))
39748
0
                return val;
39749
0
            val = JS_ToNumberFree(ctx, val);
39750
0
            if (JS_IsException(val))
39751
0
                return val;
39752
0
            break;
39753
0
#endif
39754
0
        default:
39755
0
            break;
39756
0
        }
39757
0
    }
39758
0
    if (!JS_IsUndefined(new_target)) {
39759
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);
39760
0
        if (!JS_IsException(obj))
39761
0
            JS_SetObjectData(ctx, obj, val);
39762
0
        return obj;
39763
0
    } else {
39764
0
        return val;
39765
0
    }
39766
0
}
39767
39768
#if 0
39769
static JSValue js_number___toInteger(JSContext *ctx, JSValueConst this_val,
39770
                                     int argc, JSValueConst *argv)
39771
{
39772
    return JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[0]));
39773
}
39774
39775
static JSValue js_number___toLength(JSContext *ctx, JSValueConst this_val,
39776
                                    int argc, JSValueConst *argv)
39777
{
39778
    int64_t v;
39779
    if (JS_ToLengthFree(ctx, &v, JS_DupValue(ctx, argv[0])))
39780
        return JS_EXCEPTION;
39781
    return JS_NewInt64(ctx, v);
39782
}
39783
#endif
39784
39785
static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,
39786
                               int argc, JSValueConst *argv)
39787
0
{
39788
0
    if (!JS_IsNumber(argv[0]))
39789
0
        return JS_FALSE;
39790
0
    return js_global_isNaN(ctx, this_val, argc, argv);
39791
0
}
39792
39793
static JSValue js_number_isFinite(JSContext *ctx, JSValueConst this_val,
39794
                                  int argc, JSValueConst *argv)
39795
0
{
39796
0
    if (!JS_IsNumber(argv[0]))
39797
0
        return JS_FALSE;
39798
0
    return js_global_isFinite(ctx, this_val, argc, argv);
39799
0
}
39800
39801
static JSValue js_number_isInteger(JSContext *ctx, JSValueConst this_val,
39802
                                   int argc, JSValueConst *argv)
39803
0
{
39804
0
    int ret;
39805
0
    ret = JS_NumberIsInteger(ctx, argv[0]);
39806
0
    if (ret < 0)
39807
0
        return JS_EXCEPTION;
39808
0
    else
39809
0
        return JS_NewBool(ctx, ret);
39810
0
}
39811
39812
static JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val,
39813
                                       int argc, JSValueConst *argv)
39814
0
{
39815
0
    double d;
39816
0
    if (!JS_IsNumber(argv[0]))
39817
0
        return JS_FALSE;
39818
0
    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
39819
0
        return JS_EXCEPTION;
39820
0
    return JS_NewBool(ctx, is_safe_integer(d));
39821
0
}
39822
39823
static const JSCFunctionListEntry js_number_funcs[] = {
39824
    /* global ParseInt and parseFloat should be defined already or delayed */
39825
    JS_ALIAS_BASE_DEF("parseInt", "parseInt", 0 ),
39826
    JS_ALIAS_BASE_DEF("parseFloat", "parseFloat", 0 ),
39827
    JS_CFUNC_DEF("isNaN", 1, js_number_isNaN ),
39828
    JS_CFUNC_DEF("isFinite", 1, js_number_isFinite ),
39829
    JS_CFUNC_DEF("isInteger", 1, js_number_isInteger ),
39830
    JS_CFUNC_DEF("isSafeInteger", 1, js_number_isSafeInteger ),
39831
    JS_PROP_DOUBLE_DEF("MAX_VALUE", 1.7976931348623157e+308, 0 ),
39832
    JS_PROP_DOUBLE_DEF("MIN_VALUE", 5e-324, 0 ),
39833
    JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
39834
    JS_PROP_DOUBLE_DEF("NEGATIVE_INFINITY", -INFINITY, 0 ),
39835
    JS_PROP_DOUBLE_DEF("POSITIVE_INFINITY", INFINITY, 0 ),
39836
    JS_PROP_DOUBLE_DEF("EPSILON", 2.220446049250313e-16, 0 ), /* ES6 */
39837
    JS_PROP_DOUBLE_DEF("MAX_SAFE_INTEGER", 9007199254740991.0, 0 ), /* ES6 */
39838
    JS_PROP_DOUBLE_DEF("MIN_SAFE_INTEGER", -9007199254740991.0, 0 ), /* ES6 */
39839
    //JS_CFUNC_DEF("__toInteger", 1, js_number___toInteger ),
39840
    //JS_CFUNC_DEF("__toLength", 1, js_number___toLength ),
39841
};
39842
39843
static JSValue js_thisNumberValue(JSContext *ctx, JSValueConst this_val)
39844
0
{
39845
0
    if (JS_IsNumber(this_val))
39846
0
        return JS_DupValue(ctx, this_val);
39847
39848
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
39849
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
39850
0
        if (p->class_id == JS_CLASS_NUMBER) {
39851
0
            if (JS_IsNumber(p->u.object_data))
39852
0
                return JS_DupValue(ctx, p->u.object_data);
39853
0
        }
39854
0
    }
39855
0
    return JS_ThrowTypeError(ctx, "not a number");
39856
0
}
39857
39858
static JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val,
39859
                                 int argc, JSValueConst *argv)
39860
0
{
39861
0
    return js_thisNumberValue(ctx, this_val);
39862
0
}
39863
39864
static int js_get_radix(JSContext *ctx, JSValueConst val)
39865
0
{
39866
0
    int radix;
39867
0
    if (JS_ToInt32Sat(ctx, &radix, val))
39868
0
        return -1;
39869
0
    if (radix < 2 || radix > 36) {
39870
0
        JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
39871
0
        return -1;
39872
0
    }
39873
0
    return radix;
39874
0
}
39875
39876
static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
39877
                                  int argc, JSValueConst *argv, int magic)
39878
0
{
39879
0
    JSValue val;
39880
0
    int base;
39881
0
    double d;
39882
39883
0
    val = js_thisNumberValue(ctx, this_val);
39884
0
    if (JS_IsException(val))
39885
0
        return val;
39886
0
    if (magic || JS_IsUndefined(argv[0])) {
39887
0
        base = 10;
39888
0
    } else {
39889
0
        base = js_get_radix(ctx, argv[0]);
39890
0
        if (base < 0)
39891
0
            goto fail;
39892
0
    }
39893
0
    if (JS_ToFloat64Free(ctx, &d, val))
39894
0
        return JS_EXCEPTION;
39895
0
    return js_dtoa(ctx, d, base, 0, JS_DTOA_VAR_FORMAT);
39896
0
 fail:
39897
0
    JS_FreeValue(ctx, val);
39898
0
    return JS_EXCEPTION;
39899
0
}
39900
39901
static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
39902
                                 int argc, JSValueConst *argv)
39903
0
{
39904
0
    JSValue val;
39905
0
    int f;
39906
0
    double d;
39907
39908
0
    val = js_thisNumberValue(ctx, this_val);
39909
0
    if (JS_IsException(val))
39910
0
        return val;
39911
0
    if (JS_ToFloat64Free(ctx, &d, val))
39912
0
        return JS_EXCEPTION;
39913
0
    if (JS_ToInt32Sat(ctx, &f, argv[0]))
39914
0
        return JS_EXCEPTION;
39915
0
    if (f < 0 || f > 100)
39916
0
        return JS_ThrowRangeError(ctx, "invalid number of digits");
39917
0
    if (fabs(d) >= 1e21) {
39918
0
        return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d));
39919
0
    } else {
39920
0
        return js_dtoa(ctx, d, 10, f, JS_DTOA_FRAC_FORMAT);
39921
0
    }
39922
0
}
39923
39924
static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
39925
                                       int argc, JSValueConst *argv)
39926
0
{
39927
0
    JSValue val;
39928
0
    int f, flags;
39929
0
    double d;
39930
39931
0
    val = js_thisNumberValue(ctx, this_val);
39932
0
    if (JS_IsException(val))
39933
0
        return val;
39934
0
    if (JS_ToFloat64Free(ctx, &d, val))
39935
0
        return JS_EXCEPTION;
39936
0
    if (JS_ToInt32Sat(ctx, &f, argv[0]))
39937
0
        return JS_EXCEPTION;
39938
0
    if (!isfinite(d)) {
39939
0
        return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
39940
0
    }
39941
0
    if (JS_IsUndefined(argv[0])) {
39942
0
        flags = 0;
39943
0
        f = 0;
39944
0
    } else {
39945
0
        if (f < 0 || f > 100)
39946
0
            return JS_ThrowRangeError(ctx, "invalid number of digits");
39947
0
        f++;
39948
0
        flags = JS_DTOA_FIXED_FORMAT;
39949
0
    }
39950
0
    return js_dtoa(ctx, d, 10, f, flags | JS_DTOA_FORCE_EXP);
39951
0
}
39952
39953
static JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,
39954
                                     int argc, JSValueConst *argv)
39955
0
{
39956
0
    JSValue val;
39957
0
    int p;
39958
0
    double d;
39959
39960
0
    val = js_thisNumberValue(ctx, this_val);
39961
0
    if (JS_IsException(val))
39962
0
        return val;
39963
0
    if (JS_ToFloat64Free(ctx, &d, val))
39964
0
        return JS_EXCEPTION;
39965
0
    if (JS_IsUndefined(argv[0]))
39966
0
        goto to_string;
39967
0
    if (JS_ToInt32Sat(ctx, &p, argv[0]))
39968
0
        return JS_EXCEPTION;
39969
0
    if (!isfinite(d)) {
39970
0
    to_string:
39971
0
        return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
39972
0
    }
39973
0
    if (p < 1 || p > 100)
39974
0
        return JS_ThrowRangeError(ctx, "invalid number of digits");
39975
0
    return js_dtoa(ctx, d, 10, p, JS_DTOA_FIXED_FORMAT);
39976
0
}
39977
39978
static const JSCFunctionListEntry js_number_proto_funcs[] = {
39979
    JS_CFUNC_DEF("toExponential", 1, js_number_toExponential ),
39980
    JS_CFUNC_DEF("toFixed", 1, js_number_toFixed ),
39981
    JS_CFUNC_DEF("toPrecision", 1, js_number_toPrecision ),
39982
    JS_CFUNC_MAGIC_DEF("toString", 1, js_number_toString, 0 ),
39983
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_number_toString, 1 ),
39984
    JS_CFUNC_DEF("valueOf", 0, js_number_valueOf ),
39985
};
39986
39987
static JSValue js_parseInt(JSContext *ctx, JSValueConst this_val,
39988
                           int argc, JSValueConst *argv)
39989
0
{
39990
0
    const char *str, *p;
39991
0
    int radix, flags;
39992
0
    JSValue ret;
39993
39994
0
    str = JS_ToCString(ctx, argv[0]);
39995
0
    if (!str)
39996
0
        return JS_EXCEPTION;
39997
0
    if (JS_ToInt32(ctx, &radix, argv[1])) {
39998
0
        JS_FreeCString(ctx, str);
39999
0
        return JS_EXCEPTION;
40000
0
    }
40001
0
    if (radix != 0 && (radix < 2 || radix > 36)) {
40002
0
        ret = JS_NAN;
40003
0
    } else {
40004
0
        p = str;
40005
0
        p += skip_spaces(p);
40006
0
        flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN;
40007
0
        ret = js_atof(ctx, p, NULL, radix, flags);
40008
0
    }
40009
0
    JS_FreeCString(ctx, str);
40010
0
    return ret;
40011
0
}
40012
40013
static JSValue js_parseFloat(JSContext *ctx, JSValueConst this_val,
40014
                             int argc, JSValueConst *argv)
40015
0
{
40016
0
    const char *str, *p;
40017
0
    JSValue ret;
40018
40019
0
    str = JS_ToCString(ctx, argv[0]);
40020
0
    if (!str)
40021
0
        return JS_EXCEPTION;
40022
0
    p = str;
40023
0
    p += skip_spaces(p);
40024
0
    ret = js_atof(ctx, p, NULL, 10, 0);
40025
0
    JS_FreeCString(ctx, str);
40026
0
    return ret;
40027
0
}
40028
40029
/* Boolean */
40030
static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst new_target,
40031
                                     int argc, JSValueConst *argv)
40032
0
{
40033
0
    JSValue val, obj;
40034
0
    val = JS_NewBool(ctx, JS_ToBool(ctx, argv[0]));
40035
0
    if (!JS_IsUndefined(new_target)) {
40036
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_BOOLEAN);
40037
0
        if (!JS_IsException(obj))
40038
0
            JS_SetObjectData(ctx, obj, val);
40039
0
        return obj;
40040
0
    } else {
40041
0
        return val;
40042
0
    }
40043
0
}
40044
40045
static JSValue js_thisBooleanValue(JSContext *ctx, JSValueConst this_val)
40046
0
{
40047
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_BOOL)
40048
0
        return JS_DupValue(ctx, this_val);
40049
40050
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
40051
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
40052
0
        if (p->class_id == JS_CLASS_BOOLEAN) {
40053
0
            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_BOOL)
40054
0
                return p->u.object_data;
40055
0
        }
40056
0
    }
40057
0
    return JS_ThrowTypeError(ctx, "not a boolean");
40058
0
}
40059
40060
static JSValue js_boolean_toString(JSContext *ctx, JSValueConst this_val,
40061
                                   int argc, JSValueConst *argv)
40062
0
{
40063
0
    JSValue val = js_thisBooleanValue(ctx, this_val);
40064
0
    if (JS_IsException(val))
40065
0
        return val;
40066
0
    return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
40067
0
                       JS_ATOM_true : JS_ATOM_false);
40068
0
}
40069
40070
static JSValue js_boolean_valueOf(JSContext *ctx, JSValueConst this_val,
40071
                                  int argc, JSValueConst *argv)
40072
0
{
40073
0
    return js_thisBooleanValue(ctx, this_val);
40074
0
}
40075
40076
static const JSCFunctionListEntry js_boolean_proto_funcs[] = {
40077
    JS_CFUNC_DEF("toString", 0, js_boolean_toString ),
40078
    JS_CFUNC_DEF("valueOf", 0, js_boolean_valueOf ),
40079
};
40080
40081
/* String */
40082
40083
static int js_string_get_own_property(JSContext *ctx,
40084
                                      JSPropertyDescriptor *desc,
40085
                                      JSValueConst obj, JSAtom prop)
40086
5.31M
{
40087
5.31M
    JSObject *p;
40088
5.31M
    JSString *p1;
40089
5.31M
    uint32_t idx, ch;
40090
40091
    /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
40092
5.31M
    if (__JS_AtomIsTaggedInt(prop)) {
40093
3.37M
        p = JS_VALUE_GET_OBJ(obj);
40094
3.37M
        if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
40095
3.37M
            p1 = JS_VALUE_GET_STRING(p->u.object_data);
40096
3.37M
            idx = __JS_AtomToUInt32(prop);
40097
3.37M
            if (idx < p1->len) {
40098
3.37M
                if (desc) {
40099
1.58M
                    if (p1->is_wide_char)
40100
1.04M
                        ch = p1->u.str16[idx];
40101
543k
                    else
40102
543k
                        ch = p1->u.str8[idx];
40103
1.58M
                    desc->flags = JS_PROP_ENUMERABLE;
40104
1.58M
                    desc->value = js_new_string_char(ctx, ch);
40105
1.58M
                    desc->getter = JS_UNDEFINED;
40106
1.58M
                    desc->setter = JS_UNDEFINED;
40107
1.58M
                }
40108
3.37M
                return TRUE;
40109
3.37M
            }
40110
3.37M
        }
40111
3.37M
    }
40112
1.93M
    return FALSE;
40113
5.31M
}
40114
40115
static int js_string_define_own_property(JSContext *ctx,
40116
                                         JSValueConst this_obj,
40117
                                         JSAtom prop, JSValueConst val,
40118
                                         JSValueConst getter,
40119
                                         JSValueConst setter, int flags)
40120
560k
{
40121
560k
    uint32_t idx;
40122
560k
    JSObject *p;
40123
560k
    JSString *p1, *p2;
40124
    
40125
560k
    if (__JS_AtomIsTaggedInt(prop)) {
40126
0
        idx = __JS_AtomToUInt32(prop);
40127
0
        p = JS_VALUE_GET_OBJ(this_obj);
40128
0
        if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING)
40129
0
            goto def;
40130
0
        p1 = JS_VALUE_GET_STRING(p->u.object_data);
40131
0
        if (idx >= p1->len)
40132
0
            goto def;
40133
0
        if (!check_define_prop_flags(JS_PROP_ENUMERABLE, flags))
40134
0
            goto fail;
40135
        /* check that the same value is configured */
40136
0
        if (flags & JS_PROP_HAS_VALUE) {
40137
0
            if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
40138
0
                goto fail;
40139
0
            p2 = JS_VALUE_GET_STRING(val);
40140
0
            if (p2->len != 1)
40141
0
                goto fail;
40142
0
            if (string_get(p1, idx) != string_get(p2, 0)) {
40143
0
            fail:
40144
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
40145
0
            }
40146
0
        }
40147
0
        return TRUE;
40148
560k
    } else {
40149
560k
    def:
40150
560k
        return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
40151
560k
                                 flags | JS_PROP_NO_EXOTIC);
40152
560k
    }
40153
560k
}
40154
40155
static int js_string_delete_property(JSContext *ctx,
40156
                                     JSValueConst obj, JSAtom prop)
40157
0
{
40158
0
    uint32_t idx;
40159
40160
0
    if (__JS_AtomIsTaggedInt(prop)) {
40161
0
        idx = __JS_AtomToUInt32(prop);
40162
0
        if (idx < js_string_obj_get_length(ctx, obj)) {
40163
0
            return FALSE;
40164
0
        }
40165
0
    }
40166
0
    return TRUE;
40167
0
}
40168
40169
static const JSClassExoticMethods js_string_exotic_methods = {
40170
    .get_own_property = js_string_get_own_property,
40171
    .define_own_property = js_string_define_own_property,
40172
    .delete_property = js_string_delete_property,
40173
};
40174
40175
static JSValue js_string_constructor(JSContext *ctx, JSValueConst new_target,
40176
                                     int argc, JSValueConst *argv)
40177
0
{
40178
0
    JSValue val, obj;
40179
0
    if (argc == 0) {
40180
0
        val = JS_AtomToString(ctx, JS_ATOM_empty_string);
40181
0
    } else {
40182
0
        if (JS_IsUndefined(new_target) && JS_IsSymbol(argv[0])) {
40183
0
            JSAtomStruct *p = JS_VALUE_GET_PTR(argv[0]);
40184
0
            val = JS_ConcatString3(ctx, "Symbol(", JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p)), ")");
40185
0
        } else {
40186
0
            val = JS_ToString(ctx, argv[0]);
40187
0
        }
40188
0
        if (JS_IsException(val))
40189
0
            return val;
40190
0
    }
40191
0
    if (!JS_IsUndefined(new_target)) {
40192
0
        JSString *p1 = JS_VALUE_GET_STRING(val);
40193
40194
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING);
40195
0
        if (!JS_IsException(obj)) {
40196
0
            JS_SetObjectData(ctx, obj, val);
40197
0
            JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
40198
0
        }
40199
0
        return obj;
40200
0
    } else {
40201
0
        return val;
40202
0
    }
40203
0
}
40204
40205
static JSValue js_thisStringValue(JSContext *ctx, JSValueConst this_val)
40206
0
{
40207
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING)
40208
0
        return JS_DupValue(ctx, this_val);
40209
40210
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
40211
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
40212
0
        if (p->class_id == JS_CLASS_STRING) {
40213
0
            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING)
40214
0
                return JS_DupValue(ctx, p->u.object_data);
40215
0
        }
40216
0
    }
40217
0
    return JS_ThrowTypeError(ctx, "not a string");
40218
0
}
40219
40220
static JSValue js_string_fromCharCode(JSContext *ctx, JSValueConst this_val,
40221
                                      int argc, JSValueConst *argv)
40222
0
{
40223
0
    int i;
40224
0
    StringBuffer b_s, *b = &b_s;
40225
40226
0
    string_buffer_init(ctx, b, argc);
40227
40228
0
    for(i = 0; i < argc; i++) {
40229
0
        int32_t c;
40230
0
        if (JS_ToInt32(ctx, &c, argv[i]) || string_buffer_putc16(b, c & 0xffff)) {
40231
0
            string_buffer_free(b);
40232
0
            return JS_EXCEPTION;
40233
0
        }
40234
0
    }
40235
0
    return string_buffer_end(b);
40236
0
}
40237
40238
static JSValue js_string_fromCodePoint(JSContext *ctx, JSValueConst this_val,
40239
                                       int argc, JSValueConst *argv)
40240
0
{
40241
0
    double d;
40242
0
    int i, c;
40243
0
    StringBuffer b_s, *b = &b_s;
40244
40245
    /* XXX: could pre-compute string length if all arguments are JS_TAG_INT */
40246
40247
0
    if (string_buffer_init(ctx, b, argc))
40248
0
        goto fail;
40249
0
    for(i = 0; i < argc; i++) {
40250
0
        if (JS_VALUE_GET_TAG(argv[i]) == JS_TAG_INT) {
40251
0
            c = JS_VALUE_GET_INT(argv[i]);
40252
0
            if (c < 0 || c > 0x10ffff)
40253
0
                goto range_error;
40254
0
        } else {
40255
0
            if (JS_ToFloat64(ctx, &d, argv[i]))
40256
0
                goto fail;
40257
0
            if (d < 0 || d > 0x10ffff || (c = (int)d) != d)
40258
0
                goto range_error;
40259
0
        }
40260
0
        if (string_buffer_putc(b, c))
40261
0
            goto fail;
40262
0
    }
40263
0
    return string_buffer_end(b);
40264
40265
0
 range_error:
40266
0
    JS_ThrowRangeError(ctx, "invalid code point");
40267
0
 fail:
40268
0
    string_buffer_free(b);
40269
0
    return JS_EXCEPTION;
40270
0
}
40271
40272
static JSValue js_string_raw(JSContext *ctx, JSValueConst this_val,
40273
                             int argc, JSValueConst *argv)
40274
0
{
40275
    // raw(temp,...a)
40276
0
    JSValue cooked, val, raw;
40277
0
    StringBuffer b_s, *b = &b_s;
40278
0
    int64_t i, n;
40279
40280
0
    string_buffer_init(ctx, b, 0);
40281
0
    raw = JS_UNDEFINED;
40282
0
    cooked = JS_ToObject(ctx, argv[0]);
40283
0
    if (JS_IsException(cooked))
40284
0
        goto exception;
40285
0
    raw = JS_ToObjectFree(ctx, JS_GetProperty(ctx, cooked, JS_ATOM_raw));
40286
0
    if (JS_IsException(raw))
40287
0
        goto exception;
40288
0
    if (js_get_length64(ctx, &n, raw) < 0)
40289
0
        goto exception;
40290
        
40291
0
    for (i = 0; i < n; i++) {
40292
0
        val = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, raw, i));
40293
0
        if (JS_IsException(val))
40294
0
            goto exception;
40295
0
        string_buffer_concat_value_free(b, val);
40296
0
        if (i < n - 1 && i + 1 < argc) {
40297
0
            if (string_buffer_concat_value(b, argv[i + 1]))
40298
0
                goto exception;
40299
0
        }
40300
0
    }
40301
0
    JS_FreeValue(ctx, cooked);
40302
0
    JS_FreeValue(ctx, raw);
40303
0
    return string_buffer_end(b);
40304
40305
0
exception:
40306
0
    JS_FreeValue(ctx, cooked);
40307
0
    JS_FreeValue(ctx, raw);
40308
0
    string_buffer_free(b);
40309
0
    return JS_EXCEPTION;
40310
0
}
40311
40312
/* only used in test262 */
40313
JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
40314
                                 int argc, JSValueConst *argv)
40315
0
{
40316
0
    uint32_t start, end, i, n;
40317
0
    StringBuffer b_s, *b = &b_s;
40318
40319
0
    if (JS_ToUint32(ctx, &start, argv[0]) ||
40320
0
        JS_ToUint32(ctx, &end, argv[1]))
40321
0
        return JS_EXCEPTION;
40322
0
    end = min_uint32(end, 0x10ffff + 1);
40323
40324
0
    if (start > end) {
40325
0
        start = end;
40326
0
    }
40327
0
    n = end - start;
40328
0
    if (end > 0x10000) {
40329
0
        n += end - max_uint32(start, 0x10000);
40330
0
    }
40331
0
    if (string_buffer_init2(ctx, b, n, end >= 0x100))
40332
0
        return JS_EXCEPTION;
40333
0
    for(i = start; i < end; i++) {
40334
0
        string_buffer_putc(b, i);
40335
0
    }
40336
0
    return string_buffer_end(b);
40337
0
}
40338
40339
#if 0
40340
static JSValue js_string___isSpace(JSContext *ctx, JSValueConst this_val,
40341
                                   int argc, JSValueConst *argv)
40342
{
40343
    int c;
40344
    if (JS_ToInt32(ctx, &c, argv[0]))
40345
        return JS_EXCEPTION;
40346
    return JS_NewBool(ctx, lre_is_space(c));
40347
}
40348
#endif
40349
40350
static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val,
40351
                                     int argc, JSValueConst *argv)
40352
0
{
40353
0
    JSValue val, ret;
40354
0
    JSString *p;
40355
0
    int idx, c;
40356
40357
0
    val = JS_ToStringCheckObject(ctx, this_val);
40358
0
    if (JS_IsException(val))
40359
0
        return val;
40360
0
    p = JS_VALUE_GET_STRING(val);
40361
0
    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
40362
0
        JS_FreeValue(ctx, val);
40363
0
        return JS_EXCEPTION;
40364
0
    }
40365
0
    if (idx < 0 || idx >= p->len) {
40366
0
        ret = JS_NAN;
40367
0
    } else {
40368
0
        if (p->is_wide_char)
40369
0
            c = p->u.str16[idx];
40370
0
        else
40371
0
            c = p->u.str8[idx];
40372
0
        ret = JS_NewInt32(ctx, c);
40373
0
    }
40374
0
    JS_FreeValue(ctx, val);
40375
0
    return ret;
40376
0
}
40377
40378
static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val,
40379
                                int argc, JSValueConst *argv)
40380
0
{
40381
0
    JSValue val, ret;
40382
0
    JSString *p;
40383
0
    int idx, c;
40384
40385
0
    val = JS_ToStringCheckObject(ctx, this_val);
40386
0
    if (JS_IsException(val))
40387
0
        return val;
40388
0
    p = JS_VALUE_GET_STRING(val);
40389
0
    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
40390
0
        JS_FreeValue(ctx, val);
40391
0
        return JS_EXCEPTION;
40392
0
    }
40393
0
    if (idx < 0 || idx >= p->len) {
40394
0
        ret = js_new_string8(ctx, NULL, 0);
40395
0
    } else {
40396
0
        if (p->is_wide_char)
40397
0
            c = p->u.str16[idx];
40398
0
        else
40399
0
            c = p->u.str8[idx];
40400
0
        ret = js_new_string_char(ctx, c);
40401
0
    }
40402
0
    JS_FreeValue(ctx, val);
40403
0
    return ret;
40404
0
}
40405
40406
static JSValue js_string_codePointAt(JSContext *ctx, JSValueConst this_val,
40407
                                     int argc, JSValueConst *argv)
40408
0
{
40409
0
    JSValue val, ret;
40410
0
    JSString *p;
40411
0
    int idx, c;
40412
40413
0
    val = JS_ToStringCheckObject(ctx, this_val);
40414
0
    if (JS_IsException(val))
40415
0
        return val;
40416
0
    p = JS_VALUE_GET_STRING(val);
40417
0
    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
40418
0
        JS_FreeValue(ctx, val);
40419
0
        return JS_EXCEPTION;
40420
0
    }
40421
0
    if (idx < 0 || idx >= p->len) {
40422
0
        ret = JS_UNDEFINED;
40423
0
    } else {
40424
0
        c = string_getc(p, &idx);
40425
0
        ret = JS_NewInt32(ctx, c);
40426
0
    }
40427
0
    JS_FreeValue(ctx, val);
40428
0
    return ret;
40429
0
}
40430
40431
static JSValue js_string_concat(JSContext *ctx, JSValueConst this_val,
40432
                                int argc, JSValueConst *argv)
40433
33
{
40434
33
    JSValue r;
40435
33
    int i;
40436
40437
    /* XXX: Use more efficient method */
40438
    /* XXX: This method is OK if r has a single refcount */
40439
    /* XXX: should use string_buffer? */
40440
33
    r = JS_ToStringCheckObject(ctx, this_val);
40441
6.69k
    for (i = 0; i < argc; i++) {
40442
6.65k
        if (JS_IsException(r))
40443
0
            break;
40444
6.65k
        r = JS_ConcatString(ctx, r, JS_DupValue(ctx, argv[i]));
40445
6.65k
    }
40446
33
    return r;
40447
33
}
40448
40449
static int string_cmp(JSString *p1, JSString *p2, int x1, int x2, int len)
40450
8.50k
{
40451
8.50k
    int i, c1, c2;
40452
8.62k
    for (i = 0; i < len; i++) {
40453
8.35k
        if ((c1 = string_get(p1, x1 + i)) != (c2 = string_get(p2, x2 + i)))
40454
8.23k
            return c1 - c2;
40455
8.35k
    }
40456
270
    return 0;
40457
8.50k
}
40458
40459
static int string_indexof_char(JSString *p, int c, int from)
40460
8.96k
{
40461
    /* assuming 0 <= from <= p->len */
40462
8.96k
    int i, len = p->len;
40463
8.96k
    if (p->is_wide_char) {
40464
20.9k
        for (i = from; i < len; i++) {
40465
20.9k
            if (p->u.str16[i] == c)
40466
8.26k
                return i;
40467
20.9k
        }
40468
8.27k
    } else {
40469
697
        if ((c & ~0xff) == 0) {
40470
66.4k
            for (i = from; i < len; i++) {
40471
66.4k
                if (p->u.str8[i] == (uint8_t)c)
40472
690
                    return i;
40473
66.4k
            }
40474
697
        }
40475
697
    }
40476
11
    return -1;
40477
8.96k
}
40478
40479
static int string_indexof(JSString *p1, JSString *p2, int from)
40480
2.29M
{
40481
    /* assuming 0 <= from <= p1->len */
40482
2.29M
    int c, i, j, len1 = p1->len, len2 = p2->len;
40483
2.29M
    if (len2 == 0)
40484
2.29M
        return from;
40485
8.96k
    for (i = from, c = string_get(p2, 0); i + len2 <= len1; i = j + 1) {
40486
8.96k
        j = string_indexof_char(p1, c, i);
40487
8.96k
        if (j < 0 || j + len2 > len1)
40488
460
            break;
40489
8.50k
        if (!string_cmp(p1, p2, j + 1, 1, len2 - 1))
40490
270
            return j;
40491
8.50k
    }
40492
460
    return -1;
40493
730
}
40494
40495
static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode)
40496
0
{
40497
0
    if (!unicode || index >= p->len || !p->is_wide_char) {
40498
0
        index++;
40499
0
    } else {
40500
0
        int index32 = (int)index;
40501
0
        string_getc(p, &index32);
40502
0
        index = index32;
40503
0
    }
40504
0
    return index;
40505
0
}
40506
40507
static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val,
40508
                                 int argc, JSValueConst *argv, int lastIndexOf)
40509
0
{
40510
0
    JSValue str, v;
40511
0
    int i, len, v_len, pos, start, stop, ret, inc;
40512
0
    JSString *p;
40513
0
    JSString *p1;
40514
40515
0
    str = JS_ToStringCheckObject(ctx, this_val);
40516
0
    if (JS_IsException(str))
40517
0
        return str;
40518
0
    v = JS_ToString(ctx, argv[0]);
40519
0
    if (JS_IsException(v))
40520
0
        goto fail;
40521
0
    p = JS_VALUE_GET_STRING(str);
40522
0
    p1 = JS_VALUE_GET_STRING(v);
40523
0
    len = p->len;
40524
0
    v_len = p1->len;
40525
0
    if (lastIndexOf) {
40526
0
        pos = len - v_len;
40527
0
        if (argc > 1) {
40528
0
            double d;
40529
0
            if (JS_ToFloat64(ctx, &d, argv[1]))
40530
0
                goto fail;
40531
0
            if (!isnan(d)) {
40532
0
                if (d <= 0)
40533
0
                    pos = 0;
40534
0
                else if (d < pos)
40535
0
                    pos = d;
40536
0
            }
40537
0
        }
40538
0
        start = pos;
40539
0
        stop = 0;
40540
0
        inc = -1;
40541
0
    } else {
40542
0
        pos = 0;
40543
0
        if (argc > 1) {
40544
0
            if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
40545
0
                goto fail;
40546
0
        }
40547
0
        start = pos;
40548
0
        stop = len - v_len;
40549
0
        inc = 1;
40550
0
    }
40551
0
    ret = -1;
40552
0
    if (len >= v_len && inc * (stop - start) >= 0) {
40553
0
        for (i = start;; i += inc) {
40554
0
            if (!string_cmp(p, p1, i, 0, v_len)) {
40555
0
                ret = i;
40556
0
                break;
40557
0
            }
40558
0
            if (i == stop)
40559
0
                break;
40560
0
        }
40561
0
    }
40562
0
    JS_FreeValue(ctx, str);
40563
0
    JS_FreeValue(ctx, v);
40564
0
    return JS_NewInt32(ctx, ret);
40565
40566
0
fail:
40567
0
    JS_FreeValue(ctx, str);
40568
0
    JS_FreeValue(ctx, v);
40569
0
    return JS_EXCEPTION;
40570
0
}
40571
40572
/* return < 0 if exception or TRUE/FALSE */
40573
static int js_is_regexp(JSContext *ctx, JSValueConst obj);
40574
40575
static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val,
40576
                                  int argc, JSValueConst *argv, int magic)
40577
0
{
40578
0
    JSValue str, v = JS_UNDEFINED;
40579
0
    int i, len, v_len, pos, start, stop, ret;
40580
0
    JSString *p;
40581
0
    JSString *p1;
40582
40583
0
    str = JS_ToStringCheckObject(ctx, this_val);
40584
0
    if (JS_IsException(str))
40585
0
        return str;
40586
0
    ret = js_is_regexp(ctx, argv[0]);
40587
0
    if (ret) {
40588
0
        if (ret > 0)
40589
0
            JS_ThrowTypeError(ctx, "regex not supported");
40590
0
        goto fail;
40591
0
    }
40592
0
    v = JS_ToString(ctx, argv[0]);
40593
0
    if (JS_IsException(v))
40594
0
        goto fail;
40595
0
    p = JS_VALUE_GET_STRING(str);
40596
0
    p1 = JS_VALUE_GET_STRING(v);
40597
0
    len = p->len;
40598
0
    v_len = p1->len;
40599
0
    pos = (magic == 2) ? len : 0;
40600
0
    if (argc > 1 && !JS_IsUndefined(argv[1])) {
40601
0
        if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
40602
0
            goto fail;
40603
0
    }
40604
0
    len -= v_len;
40605
0
    ret = 0;
40606
0
    if (magic == 0) {
40607
0
        start = pos;
40608
0
        stop = len;
40609
0
    } else {
40610
0
        if (magic == 1) {
40611
0
            if (pos > len)
40612
0
                goto done;
40613
0
        } else {
40614
0
            pos -= v_len;
40615
0
        }
40616
0
        start = stop = pos;
40617
0
    }
40618
0
    if (start >= 0 && start <= stop) {
40619
0
        for (i = start;; i++) {
40620
0
            if (!string_cmp(p, p1, i, 0, v_len)) {
40621
0
                ret = 1;
40622
0
                break;
40623
0
            }
40624
0
            if (i == stop)
40625
0
                break;
40626
0
        }
40627
0
    }
40628
0
 done:
40629
0
    JS_FreeValue(ctx, str);
40630
0
    JS_FreeValue(ctx, v);
40631
0
    return JS_NewBool(ctx, ret);
40632
40633
0
fail:
40634
0
    JS_FreeValue(ctx, str);
40635
0
    JS_FreeValue(ctx, v);
40636
0
    return JS_EXCEPTION;
40637
0
}
40638
40639
static int check_regexp_g_flag(JSContext *ctx, JSValueConst regexp)
40640
0
{
40641
0
    int ret;
40642
0
    JSValue flags;
40643
    
40644
0
    ret = js_is_regexp(ctx, regexp);
40645
0
    if (ret < 0)
40646
0
        return -1;
40647
0
    if (ret) {
40648
0
        flags = JS_GetProperty(ctx, regexp, JS_ATOM_flags);
40649
0
        if (JS_IsException(flags))
40650
0
            return -1;
40651
0
        if (JS_IsUndefined(flags) || JS_IsNull(flags)) {
40652
0
            JS_ThrowTypeError(ctx, "cannot convert to object");
40653
0
            return -1;
40654
0
        }
40655
0
        flags = JS_ToStringFree(ctx, flags);
40656
0
        if (JS_IsException(flags))
40657
0
            return -1;
40658
0
        ret = string_indexof_char(JS_VALUE_GET_STRING(flags), 'g', 0);
40659
0
        JS_FreeValue(ctx, flags);
40660
0
        if (ret < 0) {
40661
0
            JS_ThrowTypeError(ctx, "regexp must have the 'g' flag");
40662
0
            return -1;
40663
0
        }
40664
0
    }
40665
0
    return 0;
40666
0
}
40667
40668
static JSValue js_string_match(JSContext *ctx, JSValueConst this_val,
40669
                               int argc, JSValueConst *argv, int atom)
40670
151
{
40671
    // match(rx), search(rx), matchAll(rx)
40672
    // atom is JS_ATOM_Symbol_match, JS_ATOM_Symbol_search, or JS_ATOM_Symbol_matchAll
40673
151
    JSValueConst O = this_val, regexp = argv[0], args[2];
40674
151
    JSValue matcher, S, rx, result, str;
40675
151
    int args_len;
40676
40677
151
    if (JS_IsUndefined(O) || JS_IsNull(O))
40678
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
40679
40680
151
    if (!JS_IsUndefined(regexp) && !JS_IsNull(regexp)) {
40681
151
        matcher = JS_GetProperty(ctx, regexp, atom);
40682
151
        if (JS_IsException(matcher))
40683
0
            return JS_EXCEPTION;
40684
151
        if (atom == JS_ATOM_Symbol_matchAll) {
40685
0
            if (check_regexp_g_flag(ctx, regexp) < 0) {
40686
0
                JS_FreeValue(ctx, matcher);
40687
0
                return JS_EXCEPTION;
40688
0
            }
40689
0
        }
40690
151
        if (!JS_IsUndefined(matcher) && !JS_IsNull(matcher)) {
40691
0
            return JS_CallFree(ctx, matcher, regexp, 1, &O);
40692
0
        }
40693
151
    }
40694
151
    S = JS_ToString(ctx, O);
40695
151
    if (JS_IsException(S))
40696
0
        return JS_EXCEPTION;
40697
151
    args_len = 1;
40698
151
    args[0] = regexp;
40699
151
    str = JS_UNDEFINED;
40700
151
    if (atom == JS_ATOM_Symbol_matchAll) {
40701
0
        str = JS_NewString(ctx, "g");
40702
0
        if (JS_IsException(str))
40703
0
            goto fail;
40704
0
        args[args_len++] = (JSValueConst)str;
40705
0
    }
40706
151
    rx = JS_CallConstructor(ctx, ctx->regexp_ctor, args_len, args);
40707
151
    JS_FreeValue(ctx, str);
40708
151
    if (JS_IsException(rx)) {
40709
7
    fail:
40710
7
        JS_FreeValue(ctx, S);
40711
7
        return JS_EXCEPTION;
40712
7
    }
40713
144
    result = JS_InvokeFree(ctx, rx, atom, 1, (JSValueConst *)&S);
40714
144
    JS_FreeValue(ctx, S);
40715
144
    return result;
40716
151
}
40717
40718
static JSValue js_string___GetSubstitution(JSContext *ctx, JSValueConst this_val,
40719
                                           int argc, JSValueConst *argv)
40720
6
{
40721
    // GetSubstitution(matched, str, position, captures, namedCaptures, rep)
40722
6
    JSValueConst matched, str, captures, namedCaptures, rep;
40723
6
    JSValue capture, name, s;
40724
6
    uint32_t position, len, matched_len, captures_len;
40725
6
    int i, j, j0, k, k1;
40726
6
    int c, c1;
40727
6
    StringBuffer b_s, *b = &b_s;
40728
6
    JSString *sp, *rp;
40729
40730
6
    matched = argv[0];
40731
6
    str = argv[1];
40732
6
    captures = argv[3];
40733
6
    namedCaptures = argv[4];
40734
6
    rep = argv[5];
40735
40736
6
    if (!JS_IsString(rep) || !JS_IsString(str))
40737
0
        return JS_ThrowTypeError(ctx, "not a string");
40738
40739
6
    sp = JS_VALUE_GET_STRING(str);
40740
6
    rp = JS_VALUE_GET_STRING(rep);
40741
40742
6
    string_buffer_init(ctx, b, 0);
40743
40744
6
    captures_len = 0;
40745
6
    if (!JS_IsUndefined(captures)) {
40746
0
        if (js_get_length32(ctx, &captures_len, captures))
40747
0
            goto exception;
40748
0
    }
40749
6
    if (js_get_length32(ctx, &matched_len, matched))
40750
0
        goto exception;
40751
6
    if (JS_ToUint32(ctx, &position, argv[2]) < 0)
40752
0
        goto exception;
40753
40754
6
    len = rp->len;
40755
6
    i = 0;
40756
6
    for(;;) {
40757
6
        j = string_indexof_char(rp, '$', i);
40758
6
        if (j < 0 || j + 1 >= len)
40759
6
            break;
40760
0
        string_buffer_concat(b, rp, i, j);
40761
0
        j0 = j++;
40762
0
        c = string_get(rp, j++);
40763
0
        if (c == '$') {
40764
0
            string_buffer_putc8(b, '$');
40765
0
        } else if (c == '&') {
40766
0
            if (string_buffer_concat_value(b, matched))
40767
0
                goto exception;
40768
0
        } else if (c == '`') {
40769
0
            string_buffer_concat(b, sp, 0, position);
40770
0
        } else if (c == '\'') {
40771
0
            string_buffer_concat(b, sp, position + matched_len, sp->len);
40772
0
        } else if (c >= '0' && c <= '9') {
40773
0
            k = c - '0';
40774
0
            if (j < len) {
40775
0
                c1 = string_get(rp, j);
40776
0
                if (c1 >= '0' && c1 <= '9') {
40777
                    /* This behavior is specified in ES6 and refined in ECMA 2019 */
40778
                    /* ECMA 2019 does not have the extra test, but
40779
                       Test262 S15.5.4.11_A3_T1..3 require this behavior */
40780
0
                    k1 = k * 10 + c1 - '0';
40781
0
                    if (k1 >= 1 && k1 < captures_len) {
40782
0
                        k = k1;
40783
0
                        j++;
40784
0
                    }
40785
0
                }
40786
0
            }
40787
0
            if (k >= 1 && k < captures_len) {
40788
0
                s = JS_GetPropertyInt64(ctx, captures, k);
40789
0
                if (JS_IsException(s))
40790
0
                    goto exception;
40791
0
                if (!JS_IsUndefined(s)) {
40792
0
                    if (string_buffer_concat_value_free(b, s))
40793
0
                        goto exception;
40794
0
                }
40795
0
            } else {
40796
0
                goto norep;
40797
0
            }
40798
0
        } else if (c == '<' && !JS_IsUndefined(namedCaptures)) {
40799
0
            k = string_indexof_char(rp, '>', j);
40800
0
            if (k < 0)
40801
0
                goto norep;
40802
0
            name = js_sub_string(ctx, rp, j, k);
40803
0
            if (JS_IsException(name))
40804
0
                goto exception;
40805
0
            capture = JS_GetPropertyValue(ctx, namedCaptures, name);
40806
0
            if (JS_IsException(capture))
40807
0
                goto exception;
40808
0
            if (!JS_IsUndefined(capture)) {
40809
0
                if (string_buffer_concat_value_free(b, capture))
40810
0
                    goto exception;
40811
0
            }
40812
0
            j = k + 1;
40813
0
        } else {
40814
0
        norep:
40815
0
            string_buffer_concat(b, rp, j0, j);
40816
0
        }
40817
0
        i = j;
40818
0
    }
40819
6
    string_buffer_concat(b, rp, i, rp->len);
40820
6
    return string_buffer_end(b);
40821
0
exception:
40822
0
    string_buffer_free(b);
40823
0
    return JS_EXCEPTION;
40824
6
}
40825
40826
static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val,
40827
                                 int argc, JSValueConst *argv,
40828
                                 int is_replaceAll)
40829
6
{
40830
    // replace(rx, rep)
40831
6
    JSValueConst O = this_val, searchValue = argv[0], replaceValue = argv[1];
40832
6
    JSValueConst args[6];
40833
6
    JSValue str, search_str, replaceValue_str, repl_str;
40834
6
    JSString *sp, *searchp;
40835
6
    StringBuffer b_s, *b = &b_s;
40836
6
    int pos, functionalReplace, endOfLastMatch;
40837
6
    BOOL is_first;
40838
40839
6
    if (JS_IsUndefined(O) || JS_IsNull(O))
40840
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
40841
40842
6
    search_str = JS_UNDEFINED;
40843
6
    replaceValue_str = JS_UNDEFINED;
40844
6
    repl_str = JS_UNDEFINED;
40845
40846
6
    if (!JS_IsUndefined(searchValue) && !JS_IsNull(searchValue)) {
40847
6
        JSValue replacer;
40848
6
        if (is_replaceAll) {
40849
0
            if (check_regexp_g_flag(ctx, searchValue) < 0)
40850
0
                return JS_EXCEPTION;
40851
0
        }
40852
6
        replacer = JS_GetProperty(ctx, searchValue, JS_ATOM_Symbol_replace);
40853
6
        if (JS_IsException(replacer))
40854
0
            return JS_EXCEPTION;
40855
6
        if (!JS_IsUndefined(replacer) && !JS_IsNull(replacer)) {
40856
0
            args[0] = O;
40857
0
            args[1] = replaceValue;
40858
0
            return JS_CallFree(ctx, replacer, searchValue, 2, args);
40859
0
        }
40860
6
    }
40861
6
    string_buffer_init(ctx, b, 0);
40862
40863
6
    str = JS_ToString(ctx, O);
40864
6
    if (JS_IsException(str))
40865
0
        goto exception;
40866
6
    search_str = JS_ToString(ctx, searchValue);
40867
6
    if (JS_IsException(search_str))
40868
0
        goto exception;
40869
6
    functionalReplace = JS_IsFunction(ctx, replaceValue);
40870
6
    if (!functionalReplace) {
40871
6
        replaceValue_str = JS_ToString(ctx, replaceValue);
40872
6
        if (JS_IsException(replaceValue_str))
40873
0
            goto exception;
40874
6
    }
40875
40876
6
    sp = JS_VALUE_GET_STRING(str);
40877
6
    searchp = JS_VALUE_GET_STRING(search_str);
40878
6
    endOfLastMatch = 0;
40879
6
    is_first = TRUE;
40880
6
    for(;;) {
40881
6
        if (unlikely(searchp->len == 0)) {
40882
0
            if (is_first)
40883
0
                pos = 0;
40884
0
            else if (endOfLastMatch >= sp->len)
40885
0
                pos = -1;
40886
0
            else
40887
0
                pos = endOfLastMatch + 1;
40888
6
        } else {
40889
6
            pos = string_indexof(sp, searchp, endOfLastMatch);
40890
6
        }
40891
6
        if (pos < 0) {
40892
0
            if (is_first) {
40893
0
                string_buffer_free(b);
40894
0
                JS_FreeValue(ctx, search_str);
40895
0
                JS_FreeValue(ctx, replaceValue_str);
40896
0
                return str;
40897
0
            } else {
40898
0
                break;
40899
0
            }
40900
0
        }
40901
6
        if (functionalReplace) {
40902
0
            args[0] = search_str;
40903
0
            args[1] = JS_NewInt32(ctx, pos);
40904
0
            args[2] = str;
40905
0
            repl_str = JS_ToStringFree(ctx, JS_Call(ctx, replaceValue, JS_UNDEFINED, 3, args));
40906
6
        } else {
40907
6
            args[0] = search_str;
40908
6
            args[1] = str;
40909
6
            args[2] = JS_NewInt32(ctx, pos);
40910
6
            args[3] = JS_UNDEFINED;
40911
6
            args[4] = JS_UNDEFINED;
40912
6
            args[5] = replaceValue_str;
40913
6
            repl_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
40914
6
        }
40915
6
        if (JS_IsException(repl_str))
40916
0
            goto exception;
40917
        
40918
6
        string_buffer_concat(b, sp, endOfLastMatch, pos);
40919
6
        string_buffer_concat_value_free(b, repl_str);
40920
6
        endOfLastMatch = pos + searchp->len;
40921
6
        is_first = FALSE;
40922
6
        if (!is_replaceAll)
40923
6
            break;
40924
6
    }
40925
6
    string_buffer_concat(b, sp, endOfLastMatch, sp->len);
40926
6
    JS_FreeValue(ctx, search_str);
40927
6
    JS_FreeValue(ctx, replaceValue_str);
40928
6
    JS_FreeValue(ctx, str);
40929
6
    return string_buffer_end(b);
40930
40931
0
exception:
40932
0
    string_buffer_free(b);
40933
0
    JS_FreeValue(ctx, search_str);
40934
0
    JS_FreeValue(ctx, replaceValue_str);
40935
0
    JS_FreeValue(ctx, str);
40936
0
    return JS_EXCEPTION;
40937
6
}
40938
40939
static JSValue js_string_split(JSContext *ctx, JSValueConst this_val,
40940
                               int argc, JSValueConst *argv)
40941
202k
{
40942
    // split(sep, limit)
40943
202k
    JSValueConst O = this_val, separator = argv[0], limit = argv[1];
40944
202k
    JSValueConst args[2];
40945
202k
    JSValue S, A, R, T;
40946
202k
    uint32_t lim, lengthA;
40947
202k
    int64_t p, q, s, r, e;
40948
202k
    JSString *sp, *rp;
40949
40950
202k
    if (JS_IsUndefined(O) || JS_IsNull(O))
40951
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
40952
40953
202k
    S = JS_UNDEFINED;
40954
202k
    A = JS_UNDEFINED;
40955
202k
    R = JS_UNDEFINED;
40956
40957
202k
    if (!JS_IsUndefined(separator) && !JS_IsNull(separator)) {
40958
202k
        JSValue splitter;
40959
202k
        splitter = JS_GetProperty(ctx, separator, JS_ATOM_Symbol_split);
40960
202k
        if (JS_IsException(splitter))
40961
0
            return JS_EXCEPTION;
40962
202k
        if (!JS_IsUndefined(splitter) && !JS_IsNull(splitter)) {
40963
0
            args[0] = O;
40964
0
            args[1] = limit;
40965
0
            return JS_CallFree(ctx, splitter, separator, 2, args);
40966
0
        }
40967
202k
    }
40968
202k
    S = JS_ToString(ctx, O);
40969
202k
    if (JS_IsException(S))
40970
0
        goto exception;
40971
202k
    A = JS_NewArray(ctx);
40972
202k
    if (JS_IsException(A))
40973
0
        goto exception;
40974
202k
    lengthA = 0;
40975
202k
    if (JS_IsUndefined(limit)) {
40976
202k
        lim = 0xffffffff;
40977
202k
    } else {
40978
0
        if (JS_ToUint32(ctx, &lim, limit) < 0)
40979
0
            goto exception;
40980
0
    }
40981
202k
    sp = JS_VALUE_GET_STRING(S);
40982
202k
    s = sp->len;
40983
202k
    R = JS_ToString(ctx, separator);
40984
202k
    if (JS_IsException(R))
40985
0
        goto exception;
40986
202k
    rp = JS_VALUE_GET_STRING(R);
40987
202k
    r = rp->len;
40988
202k
    p = 0;
40989
202k
    if (lim == 0)
40990
0
        goto done;
40991
202k
    if (JS_IsUndefined(separator))
40992
0
        goto add_tail;
40993
202k
    if (s == 0) {
40994
0
        if (r != 0)
40995
0
            goto add_tail;
40996
0
        goto done;
40997
0
    }
40998
202k
    q = p;
40999
2.50M
    for (q = p; (q += !r) <= s - r - !r; q = p = e + r) {
41000
2.29M
        e = string_indexof(sp, rp, q);
41001
2.29M
        if (e < 0)
41002
460
            break;
41003
2.29M
        T = js_sub_string(ctx, sp, p, e);
41004
2.29M
        if (JS_IsException(T))
41005
0
            goto exception;
41006
2.29M
        if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T, 0) < 0)
41007
0
            goto exception;
41008
2.29M
        if (lengthA == lim)
41009
0
            goto done;
41010
2.29M
    }
41011
202k
add_tail:
41012
202k
    T = js_sub_string(ctx, sp, p, s);
41013
202k
    if (JS_IsException(T))
41014
0
        goto exception;
41015
202k
    if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T,0 ) < 0)
41016
0
        goto exception;
41017
202k
done:
41018
202k
    JS_FreeValue(ctx, S);
41019
202k
    JS_FreeValue(ctx, R);
41020
202k
    return A;
41021
41022
0
exception:
41023
0
    JS_FreeValue(ctx, A);
41024
0
    JS_FreeValue(ctx, S);
41025
0
    JS_FreeValue(ctx, R);
41026
0
    return JS_EXCEPTION;
41027
202k
}
41028
41029
static JSValue js_string_substring(JSContext *ctx, JSValueConst this_val,
41030
                                   int argc, JSValueConst *argv)
41031
0
{
41032
0
    JSValue str, ret;
41033
0
    int a, b, start, end;
41034
0
    JSString *p;
41035
41036
0
    str = JS_ToStringCheckObject(ctx, this_val);
41037
0
    if (JS_IsException(str))
41038
0
        return str;
41039
0
    p = JS_VALUE_GET_STRING(str);
41040
0
    if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, p->len, 0)) {
41041
0
        JS_FreeValue(ctx, str);
41042
0
        return JS_EXCEPTION;
41043
0
    }
41044
0
    b = p->len;
41045
0
    if (!JS_IsUndefined(argv[1])) {
41046
0
        if (JS_ToInt32Clamp(ctx, &b, argv[1], 0, p->len, 0)) {
41047
0
            JS_FreeValue(ctx, str);
41048
0
            return JS_EXCEPTION;
41049
0
        }
41050
0
    }
41051
0
    if (a < b) {
41052
0
        start = a;
41053
0
        end = b;
41054
0
    } else {
41055
0
        start = b;
41056
0
        end = a;
41057
0
    }
41058
0
    ret = js_sub_string(ctx, p, start, end);
41059
0
    JS_FreeValue(ctx, str);
41060
0
    return ret;
41061
0
}
41062
41063
static JSValue js_string_substr(JSContext *ctx, JSValueConst this_val,
41064
                                int argc, JSValueConst *argv)
41065
0
{
41066
0
    JSValue str, ret;
41067
0
    int a, len, n;
41068
0
    JSString *p;
41069
41070
0
    str = JS_ToStringCheckObject(ctx, this_val);
41071
0
    if (JS_IsException(str))
41072
0
        return str;
41073
0
    p = JS_VALUE_GET_STRING(str);
41074
0
    len = p->len;
41075
0
    if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, len, len)) {
41076
0
        JS_FreeValue(ctx, str);
41077
0
        return JS_EXCEPTION;
41078
0
    }
41079
0
    n = len - a;
41080
0
    if (!JS_IsUndefined(argv[1])) {
41081
0
        if (JS_ToInt32Clamp(ctx, &n, argv[1], 0, len - a, 0)) {
41082
0
            JS_FreeValue(ctx, str);
41083
0
            return JS_EXCEPTION;
41084
0
        }
41085
0
    }
41086
0
    ret = js_sub_string(ctx, p, a, a + n);
41087
0
    JS_FreeValue(ctx, str);
41088
0
    return ret;
41089
0
}
41090
41091
static JSValue js_string_slice(JSContext *ctx, JSValueConst this_val,
41092
                               int argc, JSValueConst *argv)
41093
3
{
41094
3
    JSValue str, ret;
41095
3
    int len, start, end;
41096
3
    JSString *p;
41097
41098
3
    str = JS_ToStringCheckObject(ctx, this_val);
41099
3
    if (JS_IsException(str))
41100
0
        return str;
41101
3
    p = JS_VALUE_GET_STRING(str);
41102
3
    len = p->len;
41103
3
    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) {
41104
0
        JS_FreeValue(ctx, str);
41105
0
        return JS_EXCEPTION;
41106
0
    }
41107
3
    end = len;
41108
3
    if (!JS_IsUndefined(argv[1])) {
41109
0
        if (JS_ToInt32Clamp(ctx, &end, argv[1], 0, len, len)) {
41110
0
            JS_FreeValue(ctx, str);
41111
0
            return JS_EXCEPTION;
41112
0
        }
41113
0
    }
41114
3
    ret = js_sub_string(ctx, p, start, max_int(end, start));
41115
3
    JS_FreeValue(ctx, str);
41116
3
    return ret;
41117
3
}
41118
41119
static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val,
41120
                             int argc, JSValueConst *argv, int padEnd)
41121
0
{
41122
0
    JSValue str, v = JS_UNDEFINED;
41123
0
    StringBuffer b_s, *b = &b_s;
41124
0
    JSString *p, *p1 = NULL;
41125
0
    int n, len, c = ' ';
41126
41127
0
    str = JS_ToStringCheckObject(ctx, this_val);
41128
0
    if (JS_IsException(str))
41129
0
        goto fail1;
41130
0
    if (JS_ToInt32Sat(ctx, &n, argv[0]))
41131
0
        goto fail2;
41132
0
    p = JS_VALUE_GET_STRING(str);
41133
0
    len = p->len;
41134
0
    if (len >= n)
41135
0
        return str;
41136
0
    if (argc > 1 && !JS_IsUndefined(argv[1])) {
41137
0
        v = JS_ToString(ctx, argv[1]);
41138
0
        if (JS_IsException(v))
41139
0
            goto fail2;
41140
0
        p1 = JS_VALUE_GET_STRING(v);
41141
0
        if (p1->len == 0) {
41142
0
            JS_FreeValue(ctx, v);
41143
0
            return str;
41144
0
        }
41145
0
        if (p1->len == 1) {
41146
0
            c = string_get(p1, 0);
41147
0
            p1 = NULL;
41148
0
        }
41149
0
    }
41150
0
    if (n > JS_STRING_LEN_MAX) {
41151
0
        JS_ThrowInternalError(ctx, "string too long");
41152
0
        goto fail2;
41153
0
    }
41154
0
    if (string_buffer_init(ctx, b, n))
41155
0
        goto fail3;
41156
0
    n -= len;
41157
0
    if (padEnd) {
41158
0
        if (string_buffer_concat(b, p, 0, len))
41159
0
            goto fail;
41160
0
    }
41161
0
    if (p1) {
41162
0
        while (n > 0) {
41163
0
            int chunk = min_int(n, p1->len);
41164
0
            if (string_buffer_concat(b, p1, 0, chunk))
41165
0
                goto fail;
41166
0
            n -= chunk;
41167
0
        }
41168
0
    } else {
41169
0
        if (string_buffer_fill(b, c, n))
41170
0
            goto fail;
41171
0
    }
41172
0
    if (!padEnd) {
41173
0
        if (string_buffer_concat(b, p, 0, len))
41174
0
            goto fail;
41175
0
    }
41176
0
    JS_FreeValue(ctx, v);
41177
0
    JS_FreeValue(ctx, str);
41178
0
    return string_buffer_end(b);
41179
41180
0
fail:
41181
0
    string_buffer_free(b);
41182
0
fail3:
41183
0
    JS_FreeValue(ctx, v);
41184
0
fail2:
41185
0
    JS_FreeValue(ctx, str);
41186
0
fail1:
41187
0
    return JS_EXCEPTION;
41188
0
}
41189
41190
static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val,
41191
                                int argc, JSValueConst *argv)
41192
0
{
41193
0
    JSValue str;
41194
0
    StringBuffer b_s, *b = &b_s;
41195
0
    JSString *p;
41196
0
    int64_t val;
41197
0
    int n, len;
41198
41199
0
    str = JS_ToStringCheckObject(ctx, this_val);
41200
0
    if (JS_IsException(str))
41201
0
        goto fail;
41202
0
    if (JS_ToInt64Sat(ctx, &val, argv[0]))
41203
0
        goto fail;
41204
0
    if (val < 0 || val > 2147483647) {
41205
0
        JS_ThrowRangeError(ctx, "invalid repeat count");
41206
0
        goto fail;
41207
0
    }
41208
0
    n = val;
41209
0
    p = JS_VALUE_GET_STRING(str);
41210
0
    len = p->len;
41211
0
    if (len == 0 || n == 1)
41212
0
        return str;
41213
0
    if (val * len > JS_STRING_LEN_MAX) {
41214
0
        JS_ThrowInternalError(ctx, "string too long");
41215
0
        goto fail;
41216
0
    }
41217
0
    if (string_buffer_init2(ctx, b, n * len, p->is_wide_char))
41218
0
        goto fail;
41219
0
    if (len == 1) {
41220
0
        string_buffer_fill(b, string_get(p, 0), n);
41221
0
    } else {
41222
0
        while (n-- > 0) {
41223
0
            string_buffer_concat(b, p, 0, len);
41224
0
        }
41225
0
    }
41226
0
    JS_FreeValue(ctx, str);
41227
0
    return string_buffer_end(b);
41228
41229
0
fail:
41230
0
    JS_FreeValue(ctx, str);
41231
0
    return JS_EXCEPTION;
41232
0
}
41233
41234
static JSValue js_string_trim(JSContext *ctx, JSValueConst this_val,
41235
                              int argc, JSValueConst *argv, int magic)
41236
0
{
41237
0
    JSValue str, ret;
41238
0
    int a, b, len;
41239
0
    JSString *p;
41240
41241
0
    str = JS_ToStringCheckObject(ctx, this_val);
41242
0
    if (JS_IsException(str))
41243
0
        return str;
41244
0
    p = JS_VALUE_GET_STRING(str);
41245
0
    a = 0;
41246
0
    b = len = p->len;
41247
0
    if (magic & 1) {
41248
0
        while (a < len && lre_is_space(string_get(p, a)))
41249
0
            a++;
41250
0
    }
41251
0
    if (magic & 2) {
41252
0
        while (b > a && lre_is_space(string_get(p, b - 1)))
41253
0
            b--;
41254
0
    }
41255
0
    ret = js_sub_string(ctx, p, a, b);
41256
0
    JS_FreeValue(ctx, str);
41257
0
    return ret;
41258
0
}
41259
41260
static JSValue js_string___quote(JSContext *ctx, JSValueConst this_val,
41261
                                 int argc, JSValueConst *argv)
41262
0
{
41263
0
    return JS_ToQuotedString(ctx, this_val);
41264
0
}
41265
41266
/* return 0 if before the first char */
41267
static int string_prevc(JSString *p, int *pidx)
41268
0
{
41269
0
    int idx, c, c1;
41270
41271
0
    idx = *pidx;
41272
0
    if (idx <= 0)
41273
0
        return 0;
41274
0
    idx--;
41275
0
    if (p->is_wide_char) {
41276
0
        c = p->u.str16[idx];
41277
0
        if (c >= 0xdc00 && c < 0xe000 && idx > 0) {
41278
0
            c1 = p->u.str16[idx - 1];
41279
0
            if (c1 >= 0xd800 && c1 <= 0xdc00) {
41280
0
                c = (((c1 & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000;
41281
0
                idx--;
41282
0
            }
41283
0
        }
41284
0
    } else {
41285
0
        c = p->u.str8[idx];
41286
0
    }
41287
0
    *pidx = idx;
41288
0
    return c;
41289
0
}
41290
41291
static BOOL test_final_sigma(JSString *p, int sigma_pos)
41292
0
{
41293
0
    int k, c1;
41294
41295
    /* before C: skip case ignorable chars and check there is
41296
       a cased letter */
41297
0
    k = sigma_pos;
41298
0
    for(;;) {
41299
0
        c1 = string_prevc(p, &k);
41300
0
        if (!lre_is_case_ignorable(c1))
41301
0
            break;
41302
0
    }
41303
0
    if (!lre_is_cased(c1))
41304
0
        return FALSE;
41305
41306
    /* after C: skip case ignorable chars and check there is
41307
       no cased letter */
41308
0
    k = sigma_pos + 1;
41309
0
    for(;;) {
41310
0
        if (k >= p->len)
41311
0
            return TRUE;
41312
0
        c1 = string_getc(p, &k);
41313
0
        if (!lre_is_case_ignorable(c1))
41314
0
            break;
41315
0
    }
41316
0
    return !lre_is_cased(c1);
41317
0
}
41318
41319
static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
41320
                                       int argc, JSValueConst *argv)
41321
0
{
41322
0
    JSValue a, b;
41323
0
    int cmp;
41324
41325
0
    a = JS_ToStringCheckObject(ctx, this_val);
41326
0
    if (JS_IsException(a))
41327
0
        return JS_EXCEPTION;
41328
0
    b = JS_ToString(ctx, argv[0]);
41329
0
    if (JS_IsException(b)) {
41330
0
        JS_FreeValue(ctx, a);
41331
0
        return JS_EXCEPTION;
41332
0
    }
41333
0
    cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b));
41334
0
    JS_FreeValue(ctx, a);
41335
0
    JS_FreeValue(ctx, b);
41336
0
    return JS_NewInt32(ctx, cmp);
41337
0
}
41338
41339
static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val,
41340
                                     int argc, JSValueConst *argv, int to_lower)
41341
0
{
41342
0
    JSValue val;
41343
0
    StringBuffer b_s, *b = &b_s;
41344
0
    JSString *p;
41345
0
    int i, c, j, l;
41346
0
    uint32_t res[LRE_CC_RES_LEN_MAX];
41347
41348
0
    val = JS_ToStringCheckObject(ctx, this_val);
41349
0
    if (JS_IsException(val))
41350
0
        return val;
41351
0
    p = JS_VALUE_GET_STRING(val);
41352
0
    if (p->len == 0)
41353
0
        return val;
41354
0
    if (string_buffer_init(ctx, b, p->len))
41355
0
        goto fail;
41356
0
    for(i = 0; i < p->len;) {
41357
0
        c = string_getc(p, &i);
41358
0
        if (c == 0x3a3 && to_lower && test_final_sigma(p, i - 1)) {
41359
0
            res[0] = 0x3c2; /* final sigma */
41360
0
            l = 1;
41361
0
        } else {
41362
0
            l = lre_case_conv(res, c, to_lower);
41363
0
        }
41364
0
        for(j = 0; j < l; j++) {
41365
0
            if (string_buffer_putc(b, res[j]))
41366
0
                goto fail;
41367
0
        }
41368
0
    }
41369
0
    JS_FreeValue(ctx, val);
41370
0
    return string_buffer_end(b);
41371
0
 fail:
41372
0
    JS_FreeValue(ctx, val);
41373
0
    string_buffer_free(b);
41374
0
    return JS_EXCEPTION;
41375
0
}
41376
41377
#ifdef CONFIG_ALL_UNICODE
41378
41379
/* return (-1, NULL) if exception, otherwise (len, buf) */
41380
static int JS_ToUTF32String(JSContext *ctx, uint32_t **pbuf, JSValueConst val1)
41381
0
{
41382
0
    JSValue val;
41383
0
    JSString *p;
41384
0
    uint32_t *buf;
41385
0
    int i, j, len;
41386
41387
0
    val = JS_ToString(ctx, val1);
41388
0
    if (JS_IsException(val))
41389
0
        return -1;
41390
0
    p = JS_VALUE_GET_STRING(val);
41391
0
    len = p->len;
41392
    /* UTF32 buffer length is len minus the number of correct surrogates pairs */
41393
0
    buf = js_malloc(ctx, sizeof(buf[0]) * max_int(len, 1));
41394
0
    if (!buf) {
41395
0
        JS_FreeValue(ctx, val);
41396
0
        goto fail;
41397
0
    }
41398
0
    for(i = j = 0; i < len;)
41399
0
        buf[j++] = string_getc(p, &i);
41400
0
    JS_FreeValue(ctx, val);
41401
0
    *pbuf = buf;
41402
0
    return j;
41403
0
 fail:
41404
0
    *pbuf = NULL;
41405
0
    return -1;
41406
0
}
41407
41408
static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len)
41409
0
{
41410
0
    int i;
41411
0
    StringBuffer b_s, *b = &b_s;
41412
0
    if (string_buffer_init(ctx, b, len))
41413
0
        return JS_EXCEPTION;
41414
0
    for(i = 0; i < len; i++) {
41415
0
        if (string_buffer_putc(b, buf[i]))
41416
0
            goto fail;
41417
0
    }
41418
0
    return string_buffer_end(b);
41419
0
 fail:
41420
0
    string_buffer_free(b);
41421
0
    return JS_EXCEPTION;
41422
0
}
41423
41424
static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val,
41425
                                   int argc, JSValueConst *argv)
41426
0
{
41427
0
    const char *form, *p;
41428
0
    size_t form_len;
41429
0
    int is_compat, buf_len, out_len;
41430
0
    UnicodeNormalizationEnum n_type;
41431
0
    JSValue val;
41432
0
    uint32_t *buf, *out_buf;
41433
41434
0
    val = JS_ToStringCheckObject(ctx, this_val);
41435
0
    if (JS_IsException(val))
41436
0
        return val;
41437
0
    buf_len = JS_ToUTF32String(ctx, &buf, val);
41438
0
    JS_FreeValue(ctx, val);
41439
0
    if (buf_len < 0)
41440
0
        return JS_EXCEPTION;
41441
41442
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
41443
0
        n_type = UNICODE_NFC;
41444
0
    } else {
41445
0
        form = JS_ToCStringLen(ctx, &form_len, argv[0]);
41446
0
        if (!form)
41447
0
            goto fail1;
41448
0
        p = form;
41449
0
        if (p[0] != 'N' || p[1] != 'F')
41450
0
            goto bad_form;
41451
0
        p += 2;
41452
0
        is_compat = FALSE;
41453
0
        if (*p == 'K') {
41454
0
            is_compat = TRUE;
41455
0
            p++;
41456
0
        }
41457
0
        if (*p == 'C' || *p == 'D') {
41458
0
            n_type = UNICODE_NFC + is_compat * 2 + (*p - 'C');
41459
0
            if ((p + 1 - form) != form_len)
41460
0
                goto bad_form;
41461
0
        } else {
41462
0
        bad_form:
41463
0
            JS_FreeCString(ctx, form);
41464
0
            JS_ThrowRangeError(ctx, "bad normalization form");
41465
0
        fail1:
41466
0
            js_free(ctx, buf);
41467
0
            return JS_EXCEPTION;
41468
0
        }
41469
0
        JS_FreeCString(ctx, form);
41470
0
    }
41471
41472
0
    out_len = unicode_normalize(&out_buf, buf, buf_len, n_type,
41473
0
                                ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
41474
0
    js_free(ctx, buf);
41475
0
    if (out_len < 0)
41476
0
        return JS_EXCEPTION;
41477
0
    val = JS_NewUTF32String(ctx, out_buf, out_len);
41478
0
    js_free(ctx, out_buf);
41479
0
    return val;
41480
0
}
41481
#endif /* CONFIG_ALL_UNICODE */
41482
41483
/* also used for String.prototype.valueOf */
41484
static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val,
41485
                                  int argc, JSValueConst *argv)
41486
0
{
41487
0
    return js_thisStringValue(ctx, this_val);
41488
0
}
41489
41490
#if 0
41491
static JSValue js_string___toStringCheckObject(JSContext *ctx, JSValueConst this_val,
41492
                                               int argc, JSValueConst *argv)
41493
{
41494
    return JS_ToStringCheckObject(ctx, argv[0]);
41495
}
41496
41497
static JSValue js_string___toString(JSContext *ctx, JSValueConst this_val,
41498
                                    int argc, JSValueConst *argv)
41499
{
41500
    return JS_ToString(ctx, argv[0]);
41501
}
41502
41503
static JSValue js_string___advanceStringIndex(JSContext *ctx, JSValueConst
41504
                                              this_val,
41505
                                              int argc, JSValueConst *argv)
41506
{
41507
    JSValue str;
41508
    int idx;
41509
    BOOL is_unicode;
41510
    JSString *p;
41511
41512
    str = JS_ToString(ctx, argv[0]);
41513
    if (JS_IsException(str))
41514
        return str;
41515
    if (JS_ToInt32Sat(ctx, &idx, argv[1])) {
41516
        JS_FreeValue(ctx, str);
41517
        return JS_EXCEPTION;
41518
    }
41519
    is_unicode = JS_ToBool(ctx, argv[2]);
41520
    p = JS_VALUE_GET_STRING(str);
41521
    if (!is_unicode || (unsigned)idx >= p->len || !p->is_wide_char) {
41522
        idx++;
41523
    } else {
41524
        string_getc(p, &idx);
41525
    }
41526
    JS_FreeValue(ctx, str);
41527
    return JS_NewInt32(ctx, idx);
41528
}
41529
#endif
41530
41531
/* String Iterator */
41532
41533
static JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val,
41534
                                       int argc, JSValueConst *argv,
41535
                                       BOOL *pdone, int magic)
41536
605k
{
41537
605k
    JSArrayIteratorData *it;
41538
605k
    uint32_t idx, c, start;
41539
605k
    JSString *p;
41540
41541
605k
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_STRING_ITERATOR);
41542
605k
    if (!it) {
41543
0
        *pdone = FALSE;
41544
0
        return JS_EXCEPTION;
41545
0
    }
41546
605k
    if (JS_IsUndefined(it->obj))
41547
0
        goto done;
41548
605k
    p = JS_VALUE_GET_STRING(it->obj);
41549
605k
    idx = it->idx;
41550
605k
    if (idx >= p->len) {
41551
2.75k
        JS_FreeValue(ctx, it->obj);
41552
2.75k
        it->obj = JS_UNDEFINED;
41553
2.75k
    done:
41554
2.75k
        *pdone = TRUE;
41555
2.75k
        return JS_UNDEFINED;
41556
2.75k
    }
41557
41558
603k
    start = idx;
41559
603k
    c = string_getc(p, (int *)&idx);
41560
603k
    it->idx = idx;
41561
603k
    *pdone = FALSE;
41562
603k
    if (c <= 0xffff) {
41563
602k
        return js_new_string_char(ctx, c);
41564
602k
    } else {
41565
108
        return js_new_string16(ctx, p->u.str16 + start, 2);
41566
108
    }
41567
603k
}
41568
41569
/* ES6 Annex B 2.3.2 etc. */
41570
enum {
41571
    magic_string_anchor,
41572
    magic_string_big,
41573
    magic_string_blink,
41574
    magic_string_bold,
41575
    magic_string_fixed,
41576
    magic_string_fontcolor,
41577
    magic_string_fontsize,
41578
    magic_string_italics,
41579
    magic_string_link,
41580
    magic_string_small,
41581
    magic_string_strike,
41582
    magic_string_sub,
41583
    magic_string_sup,
41584
};
41585
41586
static JSValue js_string_CreateHTML(JSContext *ctx, JSValueConst this_val,
41587
                                    int argc, JSValueConst *argv, int magic)
41588
0
{
41589
0
    JSValue str;
41590
0
    const JSString *p;
41591
0
    StringBuffer b_s, *b = &b_s;
41592
0
    static struct { const char *tag, *attr; } const defs[] = {
41593
0
        { "a", "name" }, { "big", NULL }, { "blink", NULL }, { "b", NULL },
41594
0
        { "tt", NULL }, { "font", "color" }, { "font", "size" }, { "i", NULL },
41595
0
        { "a", "href" }, { "small", NULL }, { "strike", NULL }, 
41596
0
        { "sub", NULL }, { "sup", NULL },
41597
0
    };
41598
41599
0
    str = JS_ToStringCheckObject(ctx, this_val);
41600
0
    if (JS_IsException(str))
41601
0
        return JS_EXCEPTION;
41602
0
    string_buffer_init(ctx, b, 7);
41603
0
    string_buffer_putc8(b, '<');
41604
0
    string_buffer_puts8(b, defs[magic].tag);
41605
0
    if (defs[magic].attr) {
41606
        // r += " " + attr + "=\"" + value + "\"";
41607
0
        JSValue value;
41608
0
        int i;
41609
41610
0
        string_buffer_putc8(b, ' ');
41611
0
        string_buffer_puts8(b, defs[magic].attr);
41612
0
        string_buffer_puts8(b, "=\"");
41613
0
        value = JS_ToStringCheckObject(ctx, argv[0]);
41614
0
        if (JS_IsException(value)) {
41615
0
            JS_FreeValue(ctx, str);
41616
0
            string_buffer_free(b);
41617
0
            return JS_EXCEPTION;
41618
0
        }
41619
0
        p = JS_VALUE_GET_STRING(value);
41620
0
        for (i = 0; i < p->len; i++) {
41621
0
            int c = string_get(p, i);
41622
0
            if (c == '"') {
41623
0
                string_buffer_puts8(b, "&quot;");
41624
0
            } else {
41625
0
                string_buffer_putc16(b, c);
41626
0
            }
41627
0
        }
41628
0
        JS_FreeValue(ctx, value);
41629
0
        string_buffer_putc8(b, '\"');
41630
0
    }
41631
    // return r + ">" + str + "</" + tag + ">";
41632
0
    string_buffer_putc8(b, '>');
41633
0
    string_buffer_concat_value_free(b, str);
41634
0
    string_buffer_puts8(b, "</");
41635
0
    string_buffer_puts8(b, defs[magic].tag);
41636
0
    string_buffer_putc8(b, '>');
41637
0
    return string_buffer_end(b);
41638
0
}
41639
41640
static const JSCFunctionListEntry js_string_funcs[] = {
41641
    JS_CFUNC_DEF("fromCharCode", 1, js_string_fromCharCode ),
41642
    JS_CFUNC_DEF("fromCodePoint", 1, js_string_fromCodePoint ),
41643
    JS_CFUNC_DEF("raw", 1, js_string_raw ),
41644
    //JS_CFUNC_DEF("__toString", 1, js_string___toString ),
41645
    //JS_CFUNC_DEF("__isSpace", 1, js_string___isSpace ),
41646
    //JS_CFUNC_DEF("__toStringCheckObject", 1, js_string___toStringCheckObject ),
41647
    //JS_CFUNC_DEF("__advanceStringIndex", 3, js_string___advanceStringIndex ),
41648
    //JS_CFUNC_DEF("__GetSubstitution", 6, js_string___GetSubstitution ),
41649
};
41650
41651
static const JSCFunctionListEntry js_string_proto_funcs[] = {
41652
    JS_PROP_INT32_DEF("length", 0, JS_PROP_CONFIGURABLE ),
41653
    JS_CFUNC_DEF("charCodeAt", 1, js_string_charCodeAt ),
41654
    JS_CFUNC_DEF("charAt", 1, js_string_charAt ),
41655
    JS_CFUNC_DEF("concat", 1, js_string_concat ),
41656
    JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ),
41657
    JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0 ),
41658
    JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1 ),
41659
    JS_CFUNC_MAGIC_DEF("includes", 1, js_string_includes, 0 ),
41660
    JS_CFUNC_MAGIC_DEF("endsWith", 1, js_string_includes, 2 ),
41661
    JS_CFUNC_MAGIC_DEF("startsWith", 1, js_string_includes, 1 ),
41662
    JS_CFUNC_MAGIC_DEF("match", 1, js_string_match, JS_ATOM_Symbol_match ),
41663
    JS_CFUNC_MAGIC_DEF("matchAll", 1, js_string_match, JS_ATOM_Symbol_matchAll ),
41664
    JS_CFUNC_MAGIC_DEF("search", 1, js_string_match, JS_ATOM_Symbol_search ),
41665
    JS_CFUNC_DEF("split", 2, js_string_split ),
41666
    JS_CFUNC_DEF("substring", 2, js_string_substring ),
41667
    JS_CFUNC_DEF("substr", 2, js_string_substr ),
41668
    JS_CFUNC_DEF("slice", 2, js_string_slice ),
41669
    JS_CFUNC_DEF("repeat", 1, js_string_repeat ),
41670
    JS_CFUNC_MAGIC_DEF("replace", 2, js_string_replace, 0 ),
41671
    JS_CFUNC_MAGIC_DEF("replaceAll", 2, js_string_replace, 1 ),
41672
    JS_CFUNC_MAGIC_DEF("padEnd", 1, js_string_pad, 1 ),
41673
    JS_CFUNC_MAGIC_DEF("padStart", 1, js_string_pad, 0 ),
41674
    JS_CFUNC_MAGIC_DEF("trim", 0, js_string_trim, 3 ),
41675
    JS_CFUNC_MAGIC_DEF("trimEnd", 0, js_string_trim, 2 ),
41676
    JS_ALIAS_DEF("trimRight", "trimEnd" ),
41677
    JS_CFUNC_MAGIC_DEF("trimStart", 0, js_string_trim, 1 ),
41678
    JS_ALIAS_DEF("trimLeft", "trimStart" ),
41679
    JS_CFUNC_DEF("toString", 0, js_string_toString ),
41680
    JS_CFUNC_DEF("valueOf", 0, js_string_toString ),
41681
    JS_CFUNC_DEF("__quote", 1, js_string___quote ),
41682
    JS_CFUNC_DEF("localeCompare", 1, js_string_localeCompare ),
41683
    JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ),
41684
    JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ),
41685
    JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ),
41686
    JS_CFUNC_MAGIC_DEF("toLocaleUpperCase", 0, js_string_toLowerCase, 0 ),
41687
    JS_CFUNC_MAGIC_DEF("[Symbol.iterator]", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE | 4 ),
41688
    /* ES6 Annex B 2.3.2 etc. */
41689
    JS_CFUNC_MAGIC_DEF("anchor", 1, js_string_CreateHTML, magic_string_anchor ),
41690
    JS_CFUNC_MAGIC_DEF("big", 0, js_string_CreateHTML, magic_string_big ),
41691
    JS_CFUNC_MAGIC_DEF("blink", 0, js_string_CreateHTML, magic_string_blink ),
41692
    JS_CFUNC_MAGIC_DEF("bold", 0, js_string_CreateHTML, magic_string_bold ),
41693
    JS_CFUNC_MAGIC_DEF("fixed", 0, js_string_CreateHTML, magic_string_fixed ),
41694
    JS_CFUNC_MAGIC_DEF("fontcolor", 1, js_string_CreateHTML, magic_string_fontcolor ),
41695
    JS_CFUNC_MAGIC_DEF("fontsize", 1, js_string_CreateHTML, magic_string_fontsize ),
41696
    JS_CFUNC_MAGIC_DEF("italics", 0, js_string_CreateHTML, magic_string_italics ),
41697
    JS_CFUNC_MAGIC_DEF("link", 1, js_string_CreateHTML, magic_string_link ),
41698
    JS_CFUNC_MAGIC_DEF("small", 0, js_string_CreateHTML, magic_string_small ),
41699
    JS_CFUNC_MAGIC_DEF("strike", 0, js_string_CreateHTML, magic_string_strike ),
41700
    JS_CFUNC_MAGIC_DEF("sub", 0, js_string_CreateHTML, magic_string_sub ),
41701
    JS_CFUNC_MAGIC_DEF("sup", 0, js_string_CreateHTML, magic_string_sup ),
41702
};
41703
41704
static const JSCFunctionListEntry js_string_iterator_proto_funcs[] = {
41705
    JS_ITERATOR_NEXT_DEF("next", 0, js_string_iterator_next, 0 ),
41706
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "String Iterator", JS_PROP_CONFIGURABLE ),
41707
};
41708
41709
#ifdef CONFIG_ALL_UNICODE
41710
static const JSCFunctionListEntry js_string_proto_normalize[] = {
41711
    JS_CFUNC_DEF("normalize", 0, js_string_normalize ),
41712
};
41713
#endif
41714
41715
void JS_AddIntrinsicStringNormalize(JSContext *ctx)
41716
2
{
41717
2
#ifdef CONFIG_ALL_UNICODE
41718
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_normalize,
41719
2
                               countof(js_string_proto_normalize));
41720
2
#endif
41721
2
}
41722
41723
/* Math */
41724
41725
/* precondition: a and b are not NaN */
41726
static double js_fmin(double a, double b)
41727
0
{
41728
0
    if (a == 0 && b == 0) {
41729
0
        JSFloat64Union a1, b1;
41730
0
        a1.d = a;
41731
0
        b1.d = b;
41732
0
        a1.u64 |= b1.u64;
41733
0
        return a1.d;
41734
0
    } else {
41735
0
        return fmin(a, b);
41736
0
    }
41737
0
}
41738
41739
/* precondition: a and b are not NaN */
41740
static double js_fmax(double a, double b)
41741
0
{
41742
0
    if (a == 0 && b == 0) {
41743
0
        JSFloat64Union a1, b1;
41744
0
        a1.d = a;
41745
0
        b1.d = b;
41746
0
        a1.u64 &= b1.u64;
41747
0
        return a1.d;
41748
0
    } else {
41749
0
        return fmax(a, b);
41750
0
    }
41751
0
}
41752
41753
static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
41754
                               int argc, JSValueConst *argv, int magic)
41755
0
{
41756
0
    BOOL is_max = magic;
41757
0
    double r, a;
41758
0
    int i;
41759
0
    uint32_t tag;
41760
41761
0
    if (unlikely(argc == 0)) {
41762
0
        return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
41763
0
    }
41764
41765
0
    tag = JS_VALUE_GET_TAG(argv[0]);
41766
0
    if (tag == JS_TAG_INT) {
41767
0
        int a1, r1 = JS_VALUE_GET_INT(argv[0]);
41768
0
        for(i = 1; i < argc; i++) {
41769
0
            tag = JS_VALUE_GET_TAG(argv[i]);
41770
0
            if (tag != JS_TAG_INT) {
41771
0
                r = r1;
41772
0
                goto generic_case;
41773
0
            }
41774
0
            a1 = JS_VALUE_GET_INT(argv[i]);
41775
0
            if (is_max)
41776
0
                r1 = max_int(r1, a1);
41777
0
            else
41778
0
                r1 = min_int(r1, a1);
41779
41780
0
        }
41781
0
        return JS_NewInt32(ctx, r1);
41782
0
    } else {
41783
0
        if (JS_ToFloat64(ctx, &r, argv[0]))
41784
0
            return JS_EXCEPTION;
41785
0
        i = 1;
41786
0
    generic_case:
41787
0
        while (i < argc) {
41788
0
            if (JS_ToFloat64(ctx, &a, argv[i]))
41789
0
                return JS_EXCEPTION;
41790
0
            if (!isnan(r)) {
41791
0
                if (isnan(a)) {
41792
0
                    r = a;
41793
0
                } else {
41794
0
                    if (is_max)
41795
0
                        r = js_fmax(r, a);
41796
0
                    else
41797
0
                        r = js_fmin(r, a);
41798
0
                }
41799
0
            }
41800
0
            i++;
41801
0
        }
41802
0
        return JS_NewFloat64(ctx, r);
41803
0
    }
41804
0
}
41805
41806
static double js_math_sign(double a)
41807
0
{
41808
0
    if (isnan(a) || a == 0.0)
41809
0
        return a;
41810
0
    if (a < 0)
41811
0
        return -1;
41812
0
    else
41813
0
        return 1;
41814
0
}
41815
41816
static double js_math_round(double a)
41817
0
{
41818
0
    JSFloat64Union u;
41819
0
    uint64_t frac_mask, one;
41820
0
    unsigned int e, s;
41821
41822
0
    u.d = a;
41823
0
    e = (u.u64 >> 52) & 0x7ff;
41824
0
    if (e < 1023) {
41825
        /* abs(a) < 1 */
41826
0
        if (e == (1023 - 1) && u.u64 != 0xbfe0000000000000) {
41827
            /* abs(a) > 0.5 or a = 0.5: return +/-1.0 */
41828
0
            u.u64 = (u.u64 & ((uint64_t)1 << 63)) | ((uint64_t)1023 << 52);
41829
0
        } else {
41830
            /* return +/-0.0 */
41831
0
            u.u64 &= (uint64_t)1 << 63;
41832
0
        }
41833
0
    } else if (e < (1023 + 52)) {
41834
0
        s = u.u64 >> 63;
41835
0
        one = (uint64_t)1 << (52 - (e - 1023));
41836
0
        frac_mask = one - 1;
41837
0
        u.u64 += (one >> 1) - s;
41838
0
        u.u64 &= ~frac_mask; /* truncate to an integer */
41839
0
    }
41840
    /* otherwise: abs(a) >= 2^52, or NaN, +/-Infinity: no change */
41841
0
    return u.d;
41842
0
}
41843
41844
static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
41845
                             int argc, JSValueConst *argv)
41846
0
{
41847
0
    double r, a;
41848
0
    int i;
41849
41850
0
    r = 0;
41851
0
    if (argc > 0) {
41852
0
        if (JS_ToFloat64(ctx, &r, argv[0]))
41853
0
            return JS_EXCEPTION;
41854
0
        if (argc == 1) {
41855
0
            r = fabs(r);
41856
0
        } else {
41857
            /* use the built-in function to minimize precision loss */
41858
0
            for (i = 1; i < argc; i++) {
41859
0
                if (JS_ToFloat64(ctx, &a, argv[i]))
41860
0
                    return JS_EXCEPTION;
41861
0
                r = hypot(r, a);
41862
0
            }
41863
0
        }
41864
0
    }
41865
0
    return JS_NewFloat64(ctx, r);
41866
0
}
41867
41868
static double js_math_fround(double a)
41869
0
{
41870
0
    return (float)a;
41871
0
}
41872
41873
static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,
41874
                            int argc, JSValueConst *argv)
41875
0
{
41876
0
    int a, b;
41877
41878
0
    if (JS_ToInt32(ctx, &a, argv[0]))
41879
0
        return JS_EXCEPTION;
41880
0
    if (JS_ToInt32(ctx, &b, argv[1]))
41881
0
        return JS_EXCEPTION;
41882
    /* purposely ignoring overflow */
41883
0
    return JS_NewInt32(ctx, a * b);
41884
0
}
41885
41886
static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
41887
                             int argc, JSValueConst *argv)
41888
0
{
41889
0
    uint32_t a, r;
41890
41891
0
    if (JS_ToUint32(ctx, &a, argv[0]))
41892
0
        return JS_EXCEPTION;
41893
0
    if (a == 0)
41894
0
        r = 32;
41895
0
    else
41896
0
        r = clz32(a);
41897
0
    return JS_NewInt32(ctx, r);
41898
0
}
41899
41900
/* xorshift* random number generator by Marsaglia */
41901
static uint64_t xorshift64star(uint64_t *pstate)
41902
0
{
41903
0
    uint64_t x;
41904
0
    x = *pstate;
41905
0
    x ^= x >> 12;
41906
0
    x ^= x << 25;
41907
0
    x ^= x >> 27;
41908
0
    *pstate = x;
41909
0
    return x * 0x2545F4914F6CDD1D;
41910
0
}
41911
41912
static void js_random_init(JSContext *ctx)
41913
2
{
41914
2
    struct timeval tv;
41915
2
    gettimeofday(&tv, NULL);
41916
2
    ctx->random_state = ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
41917
    /* the state must be non zero */
41918
2
    if (ctx->random_state == 0)
41919
0
        ctx->random_state = 1;
41920
2
}
41921
41922
static JSValue js_math_random(JSContext *ctx, JSValueConst this_val,
41923
                              int argc, JSValueConst *argv)
41924
0
{
41925
0
    JSFloat64Union u;
41926
0
    uint64_t v;
41927
41928
0
    v = xorshift64star(&ctx->random_state);
41929
    /* 1.0 <= u.d < 2 */
41930
0
    u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12);
41931
0
    return __JS_NewFloat64(ctx, u.d - 1.0);
41932
0
}
41933
41934
static const JSCFunctionListEntry js_math_funcs[] = {
41935
    JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
41936
    JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
41937
    JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ),
41938
    JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ),
41939
    JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ),
41940
    JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),
41941
    JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt ),
41942
41943
    JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, acos ),
41944
    JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, asin ),
41945
    JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, atan ),
41946
    JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, atan2 ),
41947
    JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, cos ),
41948
    JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, exp ),
41949
    JS_CFUNC_SPECIAL_DEF("log", 1, f_f, log ),
41950
    JS_CFUNC_SPECIAL_DEF("pow", 2, f_f_f, js_pow ),
41951
    JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, sin ),
41952
    JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, tan ),
41953
    /* ES6 */
41954
    JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, trunc ),
41955
    JS_CFUNC_SPECIAL_DEF("sign", 1, f_f, js_math_sign ),
41956
    JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, cosh ),
41957
    JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, sinh ),
41958
    JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, tanh ),
41959
    JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, acosh ),
41960
    JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, asinh ),
41961
    JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, atanh ),
41962
    JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, expm1 ),
41963
    JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, log1p ),
41964
    JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2 ),
41965
    JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, log10 ),
41966
    JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, cbrt ),
41967
    JS_CFUNC_DEF("hypot", 2, js_math_hypot ),
41968
    JS_CFUNC_DEF("random", 0, js_math_random ),
41969
    JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround ),
41970
    JS_CFUNC_DEF("imul", 2, js_math_imul ),
41971
    JS_CFUNC_DEF("clz32", 1, js_math_clz32 ),
41972
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Math", JS_PROP_CONFIGURABLE ),
41973
    JS_PROP_DOUBLE_DEF("E", 2.718281828459045, 0 ),
41974
    JS_PROP_DOUBLE_DEF("LN10", 2.302585092994046, 0 ),
41975
    JS_PROP_DOUBLE_DEF("LN2", 0.6931471805599453, 0 ),
41976
    JS_PROP_DOUBLE_DEF("LOG2E", 1.4426950408889634, 0 ),
41977
    JS_PROP_DOUBLE_DEF("LOG10E", 0.4342944819032518, 0 ),
41978
    JS_PROP_DOUBLE_DEF("PI", 3.141592653589793, 0 ),
41979
    JS_PROP_DOUBLE_DEF("SQRT1_2", 0.7071067811865476, 0 ),
41980
    JS_PROP_DOUBLE_DEF("SQRT2", 1.4142135623730951, 0 ),
41981
};
41982
41983
static const JSCFunctionListEntry js_math_obj[] = {
41984
    JS_OBJECT_DEF("Math", js_math_funcs, countof(js_math_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
41985
};
41986
41987
/* Date */
41988
41989
#if 0
41990
/* OS dependent: return the UTC time in ms since 1970. */
41991
static JSValue js___date_now(JSContext *ctx, JSValueConst this_val,
41992
                             int argc, JSValueConst *argv)
41993
{
41994
    int64_t d;
41995
    struct timeval tv;
41996
    gettimeofday(&tv, NULL);
41997
    d = (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
41998
    return JS_NewInt64(ctx, d);
41999
}
42000
#endif
42001
42002
/* OS dependent: return the UTC time in microseconds since 1970. */
42003
static JSValue js___date_clock(JSContext *ctx, JSValueConst this_val,
42004
                               int argc, JSValueConst *argv)
42005
0
{
42006
0
    int64_t d;
42007
0
    struct timeval tv;
42008
0
    gettimeofday(&tv, NULL);
42009
0
    d = (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
42010
0
    return JS_NewInt64(ctx, d);
42011
0
}
42012
42013
/* OS dependent. d = argv[0] is in ms from 1970. Return the difference
42014
   between UTC time and local time 'd' in minutes */
42015
0
static int getTimezoneOffset(int64_t time) {
42016
#if defined(_WIN32)
42017
    /* XXX: TODO */
42018
    return 0;
42019
#else
42020
0
    time_t ti;
42021
0
    struct tm tm;
42022
42023
0
    time /= 1000; /* convert to seconds */
42024
0
    if (sizeof(time_t) == 4) {
42025
        /* on 32-bit systems, we need to clamp the time value to the
42026
           range of `time_t`. This is better than truncating values to
42027
           32 bits and hopefully provides the same result as 64-bit
42028
           implementation of localtime_r.
42029
         */
42030
0
        if ((time_t)-1 < 0) {
42031
0
            if (time < INT32_MIN) {
42032
0
                time = INT32_MIN;
42033
0
            } else if (time > INT32_MAX) {
42034
0
                time = INT32_MAX;
42035
0
            }
42036
0
        } else {
42037
0
            if (time < 0) {
42038
0
                time = 0;
42039
0
            } else if (time > UINT32_MAX) {
42040
0
                time = UINT32_MAX;
42041
0
            }
42042
0
        }
42043
0
    }
42044
0
    ti = time;
42045
0
    localtime_r(&ti, &tm);
42046
0
    return -tm.tm_gmtoff / 60;
42047
0
#endif
42048
0
}
42049
42050
#if 0
42051
static JSValue js___date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
42052
                                           int argc, JSValueConst *argv)
42053
{
42054
    double dd;
42055
42056
    if (JS_ToFloat64(ctx, &dd, argv[0]))
42057
        return JS_EXCEPTION;
42058
    if (isnan(dd))
42059
        return __JS_NewFloat64(ctx, dd);
42060
    else
42061
        return JS_NewInt32(ctx, getTimezoneOffset((int64_t)dd));
42062
}
42063
42064
static JSValue js_get_prototype_from_ctor(JSContext *ctx, JSValueConst ctor,
42065
                                          JSValueConst def_proto)
42066
{
42067
    JSValue proto;
42068
    proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
42069
    if (JS_IsException(proto))
42070
        return proto;
42071
    if (!JS_IsObject(proto)) {
42072
        JS_FreeValue(ctx, proto);
42073
        proto = JS_DupValue(ctx, def_proto);
42074
    }
42075
    return proto;
42076
}
42077
42078
/* create a new date object */
42079
static JSValue js___date_create(JSContext *ctx, JSValueConst this_val,
42080
                                int argc, JSValueConst *argv)
42081
{
42082
    JSValue obj, proto;
42083
    proto = js_get_prototype_from_ctor(ctx, argv[0], argv[1]);
42084
    if (JS_IsException(proto))
42085
        return proto;
42086
    obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_DATE);
42087
    JS_FreeValue(ctx, proto);
42088
    if (!JS_IsException(obj))
42089
        JS_SetObjectData(ctx, obj, JS_DupValue(ctx, argv[2]));
42090
    return obj;
42091
}
42092
#endif
42093
42094
/* RegExp */
42095
42096
static void js_regexp_finalizer(JSRuntime *rt, JSValue val)
42097
19.5k
{
42098
19.5k
    JSObject *p = JS_VALUE_GET_OBJ(val);
42099
19.5k
    JSRegExp *re = &p->u.regexp;
42100
19.5k
    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->bytecode));
42101
19.5k
    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->pattern));
42102
19.5k
}
42103
42104
/* create a string containing the RegExp bytecode */
42105
static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
42106
                                 JSValueConst flags)
42107
7.69k
{
42108
7.69k
    const char *str;
42109
7.69k
    int re_flags, mask;
42110
7.69k
    uint8_t *re_bytecode_buf;
42111
7.69k
    size_t i, len;
42112
7.69k
    int re_bytecode_len;
42113
7.69k
    JSValue ret;
42114
7.69k
    char error_msg[64];
42115
42116
7.69k
    re_flags = 0;
42117
7.69k
    if (!JS_IsUndefined(flags)) {
42118
7.51k
        str = JS_ToCStringLen(ctx, &len, flags);
42119
7.51k
        if (!str)
42120
0
            return JS_EXCEPTION;
42121
        /* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */
42122
7.61k
        for (i = 0; i < len; i++) {
42123
100
            switch(str[i]) {
42124
9
            case 'g':
42125
9
                mask = LRE_FLAG_GLOBAL;
42126
9
                break;
42127
21
            case 'i':
42128
21
                mask = LRE_FLAG_IGNORECASE;
42129
21
                break;
42130
4
            case 'm':
42131
4
                mask = LRE_FLAG_MULTILINE;
42132
4
                break;
42133
1
            case 's':
42134
1
                mask = LRE_FLAG_DOTALL;
42135
1
                break;
42136
64
            case 'u':
42137
64
                mask = LRE_FLAG_UTF16;
42138
64
                break;
42139
0
            case 'y':
42140
0
                mask = LRE_FLAG_STICKY;
42141
0
                break;
42142
1
            default:
42143
1
                goto bad_flags;
42144
100
            }
42145
99
            if ((re_flags & mask) != 0) {
42146
1
            bad_flags:
42147
1
                JS_FreeCString(ctx, str);
42148
1
                return JS_ThrowSyntaxError(ctx, "invalid regular expression flags");
42149
0
            }
42150
99
            re_flags |= mask;
42151
99
        }
42152
7.51k
        JS_FreeCString(ctx, str);
42153
7.51k
    }
42154
42155
7.69k
    str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & LRE_FLAG_UTF16));
42156
7.69k
    if (!str)
42157
0
        return JS_EXCEPTION;
42158
7.69k
    re_bytecode_buf = lre_compile(&re_bytecode_len, error_msg,
42159
7.69k
                                  sizeof(error_msg), str, len, re_flags, ctx);
42160
7.69k
    JS_FreeCString(ctx, str);
42161
7.69k
    if (!re_bytecode_buf) {
42162
85
        JS_ThrowSyntaxError(ctx, "%s", error_msg);
42163
85
        return JS_EXCEPTION;
42164
85
    }
42165
42166
7.60k
    ret = js_new_string8(ctx, re_bytecode_buf, re_bytecode_len);
42167
7.60k
    js_free(ctx, re_bytecode_buf);
42168
7.60k
    return ret;
42169
7.69k
}
42170
42171
/* create a RegExp object from a string containing the RegExp bytecode
42172
   and the source pattern */
42173
static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
42174
                                              JSValue pattern, JSValue bc)
42175
19.5k
{
42176
19.5k
    JSValue obj;
42177
19.5k
    JSObject *p;
42178
19.5k
    JSRegExp *re;
42179
42180
    /* sanity check */
42181
19.5k
    if (JS_VALUE_GET_TAG(bc) != JS_TAG_STRING ||
42182
19.5k
        JS_VALUE_GET_TAG(pattern) != JS_TAG_STRING) {
42183
0
        JS_ThrowTypeError(ctx, "string expected");
42184
0
    fail:
42185
0
        JS_FreeValue(ctx, bc);
42186
0
        JS_FreeValue(ctx, pattern);
42187
0
        return JS_EXCEPTION;
42188
0
    }
42189
42190
19.5k
    obj = js_create_from_ctor(ctx, ctor, JS_CLASS_REGEXP);
42191
19.5k
    if (JS_IsException(obj))
42192
0
        goto fail;
42193
19.5k
    p = JS_VALUE_GET_OBJ(obj);
42194
19.5k
    re = &p->u.regexp;
42195
19.5k
    re->pattern = JS_VALUE_GET_STRING(pattern);
42196
19.5k
    re->bytecode = JS_VALUE_GET_STRING(bc);
42197
19.5k
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0),
42198
19.5k
                           JS_PROP_WRITABLE);
42199
19.5k
    return obj;
42200
19.5k
}
42201
42202
static JSRegExp *js_get_regexp(JSContext *ctx, JSValueConst obj, BOOL throw_error)
42203
119k
{
42204
119k
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
42205
119k
        JSObject *p = JS_VALUE_GET_OBJ(obj);
42206
119k
        if (p->class_id == JS_CLASS_REGEXP)
42207
119k
            return &p->u.regexp;
42208
119k
    }
42209
348
    if (throw_error) {
42210
0
        JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
42211
0
    }
42212
348
    return NULL;
42213
119k
}
42214
42215
/* return < 0 if exception or TRUE/FALSE */
42216
static int js_is_regexp(JSContext *ctx, JSValueConst obj)
42217
174
{
42218
174
    JSValue m;
42219
42220
174
    if (!JS_IsObject(obj))
42221
0
        return FALSE;
42222
174
    m = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_match);
42223
174
    if (JS_IsException(m))
42224
0
        return -1;
42225
174
    if (!JS_IsUndefined(m))
42226
0
        return JS_ToBoolFree(ctx, m);
42227
174
    return js_get_regexp(ctx, obj, FALSE) != NULL;
42228
174
}
42229
42230
static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target,
42231
                                     int argc, JSValueConst *argv)
42232
174
{
42233
174
    JSValue pattern, flags, bc, val;
42234
174
    JSValueConst pat, flags1;
42235
174
    JSRegExp *re;
42236
174
    int pat_is_regexp;
42237
42238
174
    pat = argv[0];
42239
174
    flags1 = argv[1];
42240
174
    pat_is_regexp = js_is_regexp(ctx, pat);
42241
174
    if (pat_is_regexp < 0)
42242
0
        return JS_EXCEPTION;
42243
174
    if (JS_IsUndefined(new_target)) {
42244
        /* called as a function */
42245
23
        new_target = JS_GetActiveFunction(ctx);
42246
23
        if (pat_is_regexp && JS_IsUndefined(flags1)) {
42247
0
            JSValue ctor;
42248
0
            BOOL res;
42249
0
            ctor = JS_GetProperty(ctx, pat, JS_ATOM_constructor);
42250
0
            if (JS_IsException(ctor))
42251
0
                return ctor;
42252
0
            res = js_same_value(ctx, ctor, new_target);
42253
0
            JS_FreeValue(ctx, ctor);
42254
0
            if (res)
42255
0
                return JS_DupValue(ctx, pat);
42256
0
        }
42257
23
    }
42258
174
    re = js_get_regexp(ctx, pat, FALSE);
42259
174
    if (re) {
42260
0
        pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
42261
0
        if (JS_IsUndefined(flags1)) {
42262
0
            bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
42263
0
            goto no_compilation;
42264
0
        } else {
42265
0
            flags = JS_ToString(ctx, flags1);
42266
0
            if (JS_IsException(flags))
42267
0
                goto fail;
42268
0
        }
42269
174
    } else {
42270
174
        flags = JS_UNDEFINED;
42271
174
        if (pat_is_regexp) {
42272
0
            pattern = JS_GetProperty(ctx, pat, JS_ATOM_source);
42273
0
            if (JS_IsException(pattern))
42274
0
                goto fail;
42275
0
            if (JS_IsUndefined(flags1)) {
42276
0
                flags = JS_GetProperty(ctx, pat, JS_ATOM_flags);
42277
0
                if (JS_IsException(flags))
42278
0
                    goto fail;
42279
0
            } else {
42280
0
                flags = JS_DupValue(ctx, flags1);
42281
0
            }
42282
174
        } else {
42283
174
            pattern = JS_DupValue(ctx, pat);
42284
174
            flags = JS_DupValue(ctx, flags1);
42285
174
        }
42286
174
        if (JS_IsUndefined(pattern)) {
42287
0
            pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
42288
174
        } else {
42289
174
            val = pattern;
42290
174
            pattern = JS_ToString(ctx, val);
42291
174
            JS_FreeValue(ctx, val);
42292
174
            if (JS_IsException(pattern))
42293
0
                goto fail;
42294
174
        }
42295
174
    }
42296
174
    bc = js_compile_regexp(ctx, pattern, flags);
42297
174
    if (JS_IsException(bc))
42298
8
        goto fail;
42299
166
    JS_FreeValue(ctx, flags);
42300
166
 no_compilation:
42301
166
    return js_regexp_constructor_internal(ctx, new_target, pattern, bc);
42302
8
 fail:
42303
8
    JS_FreeValue(ctx, pattern);
42304
8
    JS_FreeValue(ctx, flags);
42305
8
    return JS_EXCEPTION;
42306
166
}
42307
42308
static JSValue js_regexp_compile(JSContext *ctx, JSValueConst this_val,
42309
                                 int argc, JSValueConst *argv)
42310
0
{
42311
0
    JSRegExp *re1, *re;
42312
0
    JSValueConst pattern1, flags1;
42313
0
    JSValue bc, pattern;
42314
42315
0
    re = js_get_regexp(ctx, this_val, TRUE);
42316
0
    if (!re)
42317
0
        return JS_EXCEPTION;
42318
0
    pattern1 = argv[0];
42319
0
    flags1 = argv[1];
42320
0
    re1 = js_get_regexp(ctx, pattern1, FALSE);
42321
0
    if (re1) {
42322
0
        if (!JS_IsUndefined(flags1))
42323
0
            return JS_ThrowTypeError(ctx, "flags must be undefined");
42324
0
        pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->pattern));
42325
0
        bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->bytecode));
42326
0
    } else {
42327
0
        bc = JS_UNDEFINED;
42328
0
        if (JS_IsUndefined(pattern1))
42329
0
            pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
42330
0
        else
42331
0
            pattern = JS_ToString(ctx, pattern1);
42332
0
        if (JS_IsException(pattern))
42333
0
            goto fail;
42334
0
        bc = js_compile_regexp(ctx, pattern, flags1);
42335
0
        if (JS_IsException(bc))
42336
0
            goto fail;
42337
0
    }
42338
0
    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
42339
0
    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
42340
0
    re->pattern = JS_VALUE_GET_STRING(pattern);
42341
0
    re->bytecode = JS_VALUE_GET_STRING(bc);
42342
0
    if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
42343
0
                       JS_NewInt32(ctx, 0)) < 0)
42344
0
        return JS_EXCEPTION;
42345
0
    return JS_DupValue(ctx, this_val);
42346
0
 fail:
42347
0
    JS_FreeValue(ctx, pattern);
42348
0
    JS_FreeValue(ctx, bc);
42349
0
    return JS_EXCEPTION;
42350
0
}
42351
42352
#if 0
42353
static JSValue js_regexp_get___source(JSContext *ctx, JSValueConst this_val)
42354
{
42355
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
42356
    if (!re)
42357
        return JS_EXCEPTION;
42358
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
42359
}
42360
42361
static JSValue js_regexp_get___flags(JSContext *ctx, JSValueConst this_val)
42362
{
42363
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
42364
    int flags;
42365
42366
    if (!re)
42367
        return JS_EXCEPTION;
42368
    flags = lre_get_flags(re->bytecode->u.str8);
42369
    return JS_NewInt32(ctx, flags);
42370
}
42371
#endif
42372
42373
static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val)
42374
16.9k
{
42375
16.9k
    JSRegExp *re;
42376
16.9k
    JSString *p;
42377
16.9k
    StringBuffer b_s, *b = &b_s;
42378
16.9k
    int i, n, c, c2, bra;
42379
42380
16.9k
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
42381
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
42382
42383
16.9k
    if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
42384
0
        goto empty_regex;
42385
42386
16.9k
    re = js_get_regexp(ctx, this_val, TRUE);
42387
16.9k
    if (!re)
42388
0
        return JS_EXCEPTION;
42389
42390
16.9k
    p = re->pattern;
42391
42392
16.9k
    if (p->len == 0) {
42393
8
    empty_regex:
42394
8
        return JS_NewString(ctx, "(?:)");
42395
8
    }    
42396
16.9k
    string_buffer_init2(ctx, b, p->len, p->is_wide_char);
42397
42398
    /* Escape '/' and newline sequences as needed */
42399
16.9k
    bra = 0;
42400
6.60M
    for (i = 0, n = p->len; i < n;) {
42401
6.59M
        c2 = -1;
42402
6.59M
        switch (c = string_get(p, i++)) {
42403
185k
        case '\\':
42404
185k
            if (i < n)
42405
185k
                c2 = string_get(p, i++);
42406
185k
            break;
42407
2.04k
        case ']':
42408
2.04k
            bra = 0;
42409
2.04k
            break;
42410
4.44k
        case '[':
42411
4.44k
            if (!bra) {
42412
785
                if (i < n && string_get(p, i) == ']')
42413
69
                    c2 = string_get(p, i++);
42414
785
                bra = 1;
42415
785
            }
42416
4.44k
            break;
42417
0
        case '\n':
42418
0
            c = '\\';
42419
0
            c2 = 'n';
42420
0
            break;
42421
8
        case '\r':
42422
8
            c = '\\';
42423
8
            c2 = 'r';
42424
8
            break;
42425
952
        case '/':
42426
952
            if (!bra) {
42427
16
                c = '\\';
42428
16
                c2 = '/';
42429
16
            }
42430
952
            break;
42431
6.59M
        }
42432
6.59M
        string_buffer_putc16(b, c);
42433
6.59M
        if (c2 >= 0)
42434
185k
            string_buffer_putc16(b, c2);
42435
6.59M
    }
42436
16.9k
    return string_buffer_end(b);
42437
16.9k
}
42438
42439
static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mask)
42440
102k
{
42441
102k
    JSRegExp *re;
42442
102k
    int flags;
42443
42444
102k
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
42445
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
42446
42447
102k
    re = js_get_regexp(ctx, this_val, FALSE);
42448
102k
    if (!re) {
42449
0
        if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
42450
0
            return JS_UNDEFINED;
42451
0
        else
42452
0
            return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
42453
0
    }
42454
    
42455
102k
    flags = lre_get_flags(re->bytecode->u.str8);
42456
102k
    return JS_NewBool(ctx, (flags & mask) != 0);
42457
102k
}
42458
42459
static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val)
42460
16.9k
{
42461
16.9k
    char str[8], *p = str;
42462
16.9k
    int res;
42463
42464
16.9k
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
42465
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
42466
42467
16.9k
    res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_global));
42468
16.9k
    if (res < 0)
42469
0
        goto exception;
42470
16.9k
    if (res)
42471
1.64k
        *p++ = 'g';
42472
16.9k
    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "ignoreCase"));
42473
16.9k
    if (res < 0)
42474
0
        goto exception;
42475
16.9k
    if (res)
42476
557
        *p++ = 'i';
42477
16.9k
    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "multiline"));
42478
16.9k
    if (res < 0)
42479
0
        goto exception;
42480
16.9k
    if (res)
42481
556
        *p++ = 'm';
42482
16.9k
    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "dotAll"));
42483
16.9k
    if (res < 0)
42484
0
        goto exception;
42485
16.9k
    if (res)
42486
0
        *p++ = 's';
42487
16.9k
    res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_unicode));
42488
16.9k
    if (res < 0)
42489
0
        goto exception;
42490
16.9k
    if (res)
42491
0
        *p++ = 'u';
42492
16.9k
    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "sticky"));
42493
16.9k
    if (res < 0)
42494
0
        goto exception;
42495
16.9k
    if (res)
42496
0
        *p++ = 'y';
42497
16.9k
    return JS_NewStringLen(ctx, str, p - str);
42498
42499
0
exception:
42500
0
    return JS_EXCEPTION;
42501
16.9k
}
42502
42503
static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,
42504
                                  int argc, JSValueConst *argv)
42505
16.9k
{
42506
16.9k
    JSValue pattern, flags;
42507
16.9k
    StringBuffer b_s, *b = &b_s;
42508
42509
16.9k
    if (!JS_IsObject(this_val))
42510
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
42511
42512
16.9k
    string_buffer_init(ctx, b, 0);
42513
16.9k
    string_buffer_putc8(b, '/');
42514
16.9k
    pattern = JS_GetProperty(ctx, this_val, JS_ATOM_source);
42515
16.9k
    if (string_buffer_concat_value_free(b, pattern))
42516
0
        goto fail;
42517
16.9k
    string_buffer_putc8(b, '/');
42518
16.9k
    flags = JS_GetProperty(ctx, this_val, JS_ATOM_flags);
42519
16.9k
    if (string_buffer_concat_value_free(b, flags))
42520
0
        goto fail;
42521
16.9k
    return string_buffer_end(b);
42522
42523
0
fail:
42524
0
    string_buffer_free(b);
42525
0
    return JS_EXCEPTION;
42526
16.9k
}
42527
42528
BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size)
42529
53.4k
{
42530
53.4k
    JSContext *ctx = opaque;
42531
53.4k
    return js_check_stack_overflow(ctx->rt, alloca_size);
42532
53.4k
}
42533
42534
void *lre_realloc(void *opaque, void *ptr, size_t size)
42535
2.57M
{
42536
2.57M
    JSContext *ctx = opaque;
42537
    /* No JS exception is raised here */
42538
2.57M
    return js_realloc_rt(ctx->rt, ptr, size);
42539
2.57M
}
42540
42541
static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
42542
                              int argc, JSValueConst *argv)
42543
144
{
42544
144
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
42545
144
    JSString *str;
42546
144
    JSValue str_val, obj, val, groups = JS_UNDEFINED;
42547
144
    uint8_t *re_bytecode;
42548
144
    int ret;
42549
144
    uint8_t **capture, *str_buf;
42550
144
    int capture_count, shift, i, re_flags;
42551
144
    int64_t last_index;
42552
144
    const char *group_name_ptr;
42553
42554
144
    if (!re)
42555
0
        return JS_EXCEPTION;
42556
144
    str_val = JS_ToString(ctx, argv[0]);
42557
144
    if (JS_IsException(str_val))
42558
0
        return str_val;
42559
144
    val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
42560
144
    if (JS_IsException(val) ||
42561
144
        JS_ToLengthFree(ctx, &last_index, val)) {
42562
0
        JS_FreeValue(ctx, str_val);
42563
0
        return JS_EXCEPTION;
42564
0
    }
42565
144
    re_bytecode = re->bytecode->u.str8;
42566
144
    re_flags = lre_get_flags(re_bytecode);
42567
144
    if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
42568
144
        last_index = 0;
42569
144
    }
42570
144
    str = JS_VALUE_GET_STRING(str_val);
42571
144
    capture_count = lre_get_capture_count(re_bytecode);
42572
144
    capture = NULL;
42573
144
    if (capture_count > 0) {
42574
144
        capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
42575
144
        if (!capture) {
42576
0
            JS_FreeValue(ctx, str_val);
42577
0
            return JS_EXCEPTION;
42578
0
        }
42579
144
    }
42580
144
    shift = str->is_wide_char;
42581
144
    str_buf = str->u.str8;
42582
144
    if (last_index > str->len) {
42583
0
        ret = 2;
42584
144
    } else {
42585
144
        ret = lre_exec(capture, re_bytecode,
42586
144
                       str_buf, last_index, str->len,
42587
144
                       shift, ctx);
42588
144
    }
42589
144
    obj = JS_NULL;
42590
144
    if (ret != 1) {
42591
143
        if (ret >= 0) {
42592
143
            if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
42593
0
                if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
42594
0
                                   JS_NewInt32(ctx, 0)) < 0)
42595
0
                    goto fail;
42596
0
            }
42597
143
        } else {
42598
0
            JS_ThrowInternalError(ctx, "out of memory in regexp execution");
42599
0
            goto fail;
42600
0
        }
42601
143
        JS_FreeValue(ctx, str_val);
42602
143
    } else {
42603
1
        int prop_flags;
42604
1
        if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
42605
0
            if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
42606
0
                               JS_NewInt32(ctx, (capture[1] - str_buf) >> shift)) < 0)
42607
0
                goto fail;
42608
0
        }
42609
1
        obj = JS_NewArray(ctx);
42610
1
        if (JS_IsException(obj))
42611
0
            goto fail;
42612
1
        prop_flags = JS_PROP_C_W_E | JS_PROP_THROW;
42613
1
        group_name_ptr = lre_get_groupnames(re_bytecode);
42614
1
        if (group_name_ptr) {
42615
0
            groups = JS_NewObjectProto(ctx, JS_NULL);
42616
0
            if (JS_IsException(groups))
42617
0
                goto fail;
42618
0
        }
42619
42620
37
        for(i = 0; i < capture_count; i++) {
42621
36
            int start, end;
42622
36
            JSValue val;
42623
36
            if (capture[2 * i] == NULL ||
42624
36
                capture[2 * i + 1] == NULL) {
42625
33
                val = JS_UNDEFINED;
42626
33
            } else {
42627
3
                start = (capture[2 * i] - str_buf) >> shift;
42628
3
                end = (capture[2 * i + 1] - str_buf) >> shift;
42629
3
                val = js_sub_string(ctx, str, start, end);
42630
3
                if (JS_IsException(val))
42631
0
                    goto fail;
42632
3
            }
42633
36
            if (group_name_ptr && i > 0) {
42634
0
                if (*group_name_ptr) {
42635
0
                    if (JS_DefinePropertyValueStr(ctx, groups, group_name_ptr,
42636
0
                                                  JS_DupValue(ctx, val),
42637
0
                                                  prop_flags) < 0) {
42638
0
                        JS_FreeValue(ctx, val);
42639
0
                        goto fail;
42640
0
                    }
42641
0
                }
42642
0
                group_name_ptr += strlen(group_name_ptr) + 1;
42643
0
            }
42644
36
            if (JS_DefinePropertyValueUint32(ctx, obj, i, val, prop_flags) < 0)
42645
0
                goto fail;
42646
36
        }
42647
1
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_groups,
42648
1
                                   groups, prop_flags) < 0)
42649
0
            goto fail;
42650
1
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index,
42651
1
                                   JS_NewInt32(ctx, (capture[0] - str_buf) >> shift), prop_flags) < 0)
42652
0
            goto fail;
42653
1
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, str_val, prop_flags) < 0)
42654
0
            goto fail1;
42655
1
    }
42656
144
    js_free(ctx, capture);
42657
144
    return obj;
42658
0
fail:
42659
0
    JS_FreeValue(ctx, groups);
42660
0
    JS_FreeValue(ctx, str_val);
42661
0
fail1:
42662
0
    JS_FreeValue(ctx, obj);
42663
0
    js_free(ctx, capture);
42664
0
    return JS_EXCEPTION;
42665
0
}
42666
42667
/* delete portions of a string that match a given regex */
42668
static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueConst arg)
42669
0
{
42670
0
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
42671
0
    JSString *str;
42672
0
    JSValue str_val, val;
42673
0
    uint8_t *re_bytecode;
42674
0
    int ret;
42675
0
    uint8_t **capture, *str_buf;
42676
0
    int capture_count, shift, re_flags;
42677
0
    int next_src_pos, start, end;
42678
0
    int64_t last_index;
42679
0
    StringBuffer b_s, *b = &b_s;
42680
42681
0
    if (!re)
42682
0
        return JS_EXCEPTION;
42683
42684
0
    string_buffer_init(ctx, b, 0);
42685
42686
0
    capture = NULL;
42687
0
    str_val = JS_ToString(ctx, arg);
42688
0
    if (JS_IsException(str_val))
42689
0
        goto fail;
42690
0
    str = JS_VALUE_GET_STRING(str_val);
42691
0
    re_bytecode = re->bytecode->u.str8;
42692
0
    re_flags = lre_get_flags(re_bytecode);
42693
0
    if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
42694
0
        last_index = 0;
42695
0
    } else {
42696
0
        val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
42697
0
        if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val))
42698
0
            goto fail;
42699
0
    }
42700
0
    capture_count = lre_get_capture_count(re_bytecode);
42701
0
    if (capture_count > 0) {
42702
0
        capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
42703
0
        if (!capture)
42704
0
            goto fail;
42705
0
    }
42706
0
    shift = str->is_wide_char;
42707
0
    str_buf = str->u.str8;
42708
0
    next_src_pos = 0;
42709
0
    for (;;) {
42710
0
        if (last_index > str->len)
42711
0
            break;
42712
42713
0
        ret = lre_exec(capture, re_bytecode,
42714
0
                       str_buf, last_index, str->len, shift, ctx);
42715
0
        if (ret != 1) {
42716
0
            if (ret >= 0) {
42717
0
                if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
42718
0
                    if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
42719
0
                                       JS_NewInt32(ctx, 0)) < 0)
42720
0
                        goto fail;
42721
0
                }
42722
0
            } else {
42723
0
                JS_ThrowInternalError(ctx, "out of memory in regexp execution");
42724
0
                goto fail;
42725
0
            }
42726
0
            break;
42727
0
        }
42728
0
        start = (capture[0] - str_buf) >> shift;
42729
0
        end = (capture[1] - str_buf) >> shift;
42730
0
        last_index = end;
42731
0
        if (next_src_pos < start) {
42732
0
            if (string_buffer_concat(b, str, next_src_pos, start))
42733
0
                goto fail;
42734
0
        }
42735
0
        next_src_pos = end;
42736
0
        if (!(re_flags & LRE_FLAG_GLOBAL)) {
42737
0
            if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
42738
0
                               JS_NewInt32(ctx, end)) < 0)
42739
0
                goto fail;
42740
0
            break;
42741
0
        }
42742
0
        if (end == start) {
42743
0
            if (!(re_flags & LRE_FLAG_UTF16) || (unsigned)end >= str->len || !str->is_wide_char) {
42744
0
                end++;
42745
0
            } else {
42746
0
                string_getc(str, &end);
42747
0
            }
42748
0
        }
42749
0
        last_index = end;
42750
0
    }
42751
0
    if (string_buffer_concat(b, str, next_src_pos, str->len))
42752
0
        goto fail;
42753
0
    JS_FreeValue(ctx, str_val);
42754
0
    js_free(ctx, capture);
42755
0
    return string_buffer_end(b);
42756
0
fail:
42757
0
    JS_FreeValue(ctx, str_val);
42758
0
    js_free(ctx, capture);
42759
0
    string_buffer_free(b);
42760
0
    return JS_EXCEPTION;
42761
0
}
42762
42763
static JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s)
42764
144
{
42765
144
    JSValue method, ret;
42766
42767
144
    method = JS_GetProperty(ctx, r, JS_ATOM_exec);
42768
144
    if (JS_IsException(method))
42769
0
        return method;
42770
144
    if (JS_IsFunction(ctx, method)) {
42771
144
        ret = JS_CallFree(ctx, method, r, 1, &s);
42772
144
        if (JS_IsException(ret))
42773
0
            return ret;
42774
144
        if (!JS_IsObject(ret) && !JS_IsNull(ret)) {
42775
0
            JS_FreeValue(ctx, ret);
42776
0
            return JS_ThrowTypeError(ctx, "RegExp exec method must return an object or null");
42777
0
        }
42778
144
        return ret;
42779
144
    }
42780
0
    JS_FreeValue(ctx, method);
42781
0
    return js_regexp_exec(ctx, r, 1, &s);
42782
144
}
42783
42784
#if 0
42785
static JSValue js_regexp___RegExpExec(JSContext *ctx, JSValueConst this_val,
42786
                                      int argc, JSValueConst *argv)
42787
{
42788
    return JS_RegExpExec(ctx, argv[0], argv[1]);
42789
}
42790
static JSValue js_regexp___RegExpDelete(JSContext *ctx, JSValueConst this_val,
42791
                                        int argc, JSValueConst *argv)
42792
{
42793
    return JS_RegExpDelete(ctx, argv[0], argv[1]);
42794
}
42795
#endif
42796
42797
static JSValue js_regexp_test(JSContext *ctx, JSValueConst this_val,
42798
                              int argc, JSValueConst *argv)
42799
0
{
42800
0
    JSValue val;
42801
0
    BOOL ret;
42802
42803
0
    val = JS_RegExpExec(ctx, this_val, argv[0]);
42804
0
    if (JS_IsException(val))
42805
0
        return JS_EXCEPTION;
42806
0
    ret = !JS_IsNull(val);
42807
0
    JS_FreeValue(ctx, val);
42808
0
    return JS_NewBool(ctx, ret);
42809
0
}
42810
42811
static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
42812
                                      int argc, JSValueConst *argv)
42813
144
{
42814
    // [Symbol.match](str)
42815
144
    JSValueConst rx = this_val;
42816
144
    JSValue A, S, result, matchStr;
42817
144
    int global, n, fullUnicode, isEmpty;
42818
144
    JSString *p;
42819
42820
144
    if (!JS_IsObject(rx))
42821
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
42822
42823
144
    A = JS_UNDEFINED;
42824
144
    result = JS_UNDEFINED;
42825
144
    matchStr = JS_UNDEFINED;
42826
144
    S = JS_ToString(ctx, argv[0]);
42827
144
    if (JS_IsException(S))
42828
0
        goto exception;
42829
42830
144
    global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global));
42831
144
    if (global < 0)
42832
0
        goto exception;
42833
42834
144
    if (!global) {
42835
144
        A = JS_RegExpExec(ctx, rx, S);
42836
144
    } else {
42837
0
        fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
42838
0
        if (fullUnicode < 0)
42839
0
            goto exception;
42840
42841
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
42842
0
            goto exception;
42843
0
        A = JS_NewArray(ctx);
42844
0
        if (JS_IsException(A))
42845
0
            goto exception;
42846
0
        n = 0;
42847
0
        for(;;) {
42848
0
            JS_FreeValue(ctx, result);
42849
0
            result = JS_RegExpExec(ctx, rx, S);
42850
0
            if (JS_IsException(result))
42851
0
                goto exception;
42852
0
            if (JS_IsNull(result))
42853
0
                break;
42854
0
            matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
42855
0
            if (JS_IsException(matchStr))
42856
0
                goto exception;
42857
0
            isEmpty = JS_IsEmptyString(matchStr);
42858
0
            if (JS_SetPropertyInt64(ctx, A, n++, matchStr) < 0)
42859
0
                goto exception;
42860
0
            if (isEmpty) {
42861
0
                int64_t thisIndex, nextIndex;
42862
0
                if (JS_ToLengthFree(ctx, &thisIndex,
42863
0
                                    JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
42864
0
                    goto exception;
42865
0
                p = JS_VALUE_GET_STRING(S);
42866
0
                nextIndex = string_advance_index(p, thisIndex, fullUnicode);
42867
0
                if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
42868
0
                    goto exception;
42869
0
            }
42870
0
        }
42871
0
        if (n == 0) {
42872
0
            JS_FreeValue(ctx, A);
42873
0
            A = JS_NULL;
42874
0
        }
42875
0
    }
42876
144
    JS_FreeValue(ctx, result);
42877
144
    JS_FreeValue(ctx, S);
42878
144
    return A;
42879
42880
0
exception:
42881
0
    JS_FreeValue(ctx, A);
42882
0
    JS_FreeValue(ctx, result);
42883
0
    JS_FreeValue(ctx, S);
42884
0
    return JS_EXCEPTION;
42885
144
}
42886
42887
typedef struct JSRegExpStringIteratorData {
42888
    JSValue iterating_regexp;
42889
    JSValue iterated_string;
42890
    BOOL global;
42891
    BOOL unicode;
42892
    BOOL done;
42893
} JSRegExpStringIteratorData;
42894
42895
static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val)
42896
0
{
42897
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
42898
0
    JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
42899
0
    if (it) {
42900
0
        JS_FreeValueRT(rt, it->iterating_regexp);
42901
0
        JS_FreeValueRT(rt, it->iterated_string);
42902
0
        js_free_rt(rt, it);
42903
0
    }
42904
0
}
42905
42906
static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
42907
                                           JS_MarkFunc *mark_func)
42908
0
{
42909
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
42910
0
    JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
42911
0
    if (it) {
42912
0
        JS_MarkValue(rt, it->iterating_regexp, mark_func);
42913
0
        JS_MarkValue(rt, it->iterated_string, mark_func);
42914
0
    }
42915
0
}
42916
42917
static JSValue js_regexp_string_iterator_next(JSContext *ctx,
42918
                                              JSValueConst this_val,
42919
                                              int argc, JSValueConst *argv,
42920
                                              BOOL *pdone, int magic)
42921
0
{
42922
0
    JSRegExpStringIteratorData *it;
42923
0
    JSValueConst R, S;
42924
0
    JSValue matchStr = JS_UNDEFINED, match = JS_UNDEFINED;
42925
0
    JSString *sp;
42926
42927
0
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_REGEXP_STRING_ITERATOR);
42928
0
    if (!it)
42929
0
        goto exception;
42930
0
    if (it->done) {
42931
0
        *pdone = TRUE;
42932
0
        return JS_UNDEFINED;
42933
0
    }
42934
0
    R = it->iterating_regexp;
42935
0
    S = it->iterated_string;
42936
0
    match = JS_RegExpExec(ctx, R, S);
42937
0
    if (JS_IsException(match))
42938
0
        goto exception;
42939
0
    if (JS_IsNull(match)) {
42940
0
        it->done = TRUE;
42941
0
        *pdone = TRUE;
42942
0
        return JS_UNDEFINED;
42943
0
    } else if (it->global) {
42944
0
        matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, match, 0));
42945
0
        if (JS_IsException(matchStr))
42946
0
            goto exception;
42947
0
        if (JS_IsEmptyString(matchStr)) {
42948
0
            int64_t thisIndex, nextIndex;
42949
0
            if (JS_ToLengthFree(ctx, &thisIndex,
42950
0
                                JS_GetProperty(ctx, R, JS_ATOM_lastIndex)) < 0)
42951
0
                goto exception;
42952
0
            sp = JS_VALUE_GET_STRING(S);
42953
0
            nextIndex = string_advance_index(sp, thisIndex, it->unicode);
42954
0
            if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex,
42955
0
                               JS_NewInt64(ctx, nextIndex)) < 0)
42956
0
                goto exception;
42957
0
        }
42958
0
        JS_FreeValue(ctx, matchStr);
42959
0
    } else {
42960
0
        it->done = TRUE;
42961
0
    }
42962
0
    *pdone = FALSE;
42963
0
    return match;
42964
0
 exception:
42965
0
    JS_FreeValue(ctx, match);
42966
0
    JS_FreeValue(ctx, matchStr);
42967
0
    *pdone = FALSE;
42968
0
    return JS_EXCEPTION;
42969
0
}
42970
42971
static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,
42972
                                         int argc, JSValueConst *argv)
42973
0
{
42974
    // [Symbol.matchAll](str)
42975
0
    JSValueConst R = this_val;
42976
0
    JSValue S, C, flags, matcher, iter;
42977
0
    JSValueConst args[2];
42978
0
    JSString *strp;
42979
0
    int64_t lastIndex;
42980
0
    JSRegExpStringIteratorData *it;
42981
    
42982
0
    if (!JS_IsObject(R))
42983
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
42984
42985
0
    C = JS_UNDEFINED;
42986
0
    flags = JS_UNDEFINED;
42987
0
    matcher = JS_UNDEFINED;
42988
0
    iter = JS_UNDEFINED;
42989
    
42990
0
    S = JS_ToString(ctx, argv[0]);
42991
0
    if (JS_IsException(S))
42992
0
        goto exception;
42993
0
    C = JS_SpeciesConstructor(ctx, R, ctx->regexp_ctor);
42994
0
    if (JS_IsException(C))
42995
0
        goto exception;
42996
0
    flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, R, JS_ATOM_flags));
42997
0
    if (JS_IsException(flags))
42998
0
        goto exception;
42999
0
    args[0] = R;
43000
0
    args[1] = flags;
43001
0
    matcher = JS_CallConstructor(ctx, C, 2, args);
43002
0
    if (JS_IsException(matcher))
43003
0
        goto exception;
43004
0
    if (JS_ToLengthFree(ctx, &lastIndex,
43005
0
                        JS_GetProperty(ctx, R, JS_ATOM_lastIndex)))
43006
0
        goto exception;
43007
0
    if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex,
43008
0
                       JS_NewInt64(ctx, lastIndex)) < 0)
43009
0
        goto exception;
43010
    
43011
0
    iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR);
43012
0
    if (JS_IsException(iter))
43013
0
        goto exception;
43014
0
    it = js_malloc(ctx, sizeof(*it));
43015
0
    if (!it)
43016
0
        goto exception;
43017
0
    it->iterating_regexp = matcher;
43018
0
    it->iterated_string = S;
43019
0
    strp = JS_VALUE_GET_STRING(flags);
43020
0
    it->global = string_indexof_char(strp, 'g', 0) >= 0;
43021
0
    it->unicode = string_indexof_char(strp, 'u', 0) >= 0;
43022
0
    it->done = FALSE;
43023
0
    JS_SetOpaque(iter, it);
43024
43025
0
    JS_FreeValue(ctx, C);
43026
0
    JS_FreeValue(ctx, flags);
43027
0
    return iter;
43028
0
 exception:
43029
0
    JS_FreeValue(ctx, S);
43030
0
    JS_FreeValue(ctx, C);
43031
0
    JS_FreeValue(ctx, flags);
43032
0
    JS_FreeValue(ctx, matcher);
43033
0
    JS_FreeValue(ctx, iter);
43034
0
    return JS_EXCEPTION;
43035
0
}
43036
43037
typedef struct ValueBuffer {
43038
    JSContext *ctx;
43039
    JSValue *arr;
43040
    JSValue def[4];
43041
    int len;
43042
    int size;
43043
    int error_status;
43044
} ValueBuffer;
43045
43046
static int value_buffer_init(JSContext *ctx, ValueBuffer *b)
43047
0
{
43048
0
    b->ctx = ctx;
43049
0
    b->len = 0;
43050
0
    b->size = 4;
43051
0
    b->error_status = 0;
43052
0
    b->arr = b->def;
43053
0
    return 0;
43054
0
}
43055
43056
static void value_buffer_free(ValueBuffer *b)
43057
0
{
43058
0
    while (b->len > 0)
43059
0
        JS_FreeValue(b->ctx, b->arr[--b->len]);
43060
0
    if (b->arr != b->def)
43061
0
        js_free(b->ctx, b->arr);
43062
0
    b->arr = b->def;
43063
0
    b->size = 4;
43064
0
}
43065
43066
static int value_buffer_append(ValueBuffer *b, JSValue val)
43067
0
{
43068
0
    if (b->error_status)
43069
0
        return -1;
43070
43071
0
    if (b->len >= b->size) {
43072
0
        int new_size = (b->len + (b->len >> 1) + 31) & ~16;
43073
0
        size_t slack;
43074
0
        JSValue *new_arr;
43075
43076
0
        if (b->arr == b->def) {
43077
0
            new_arr = js_realloc2(b->ctx, NULL, sizeof(*b->arr) * new_size, &slack);
43078
0
            if (new_arr)
43079
0
                memcpy(new_arr, b->def, sizeof b->def);
43080
0
        } else {
43081
0
            new_arr = js_realloc2(b->ctx, b->arr, sizeof(*b->arr) * new_size, &slack);
43082
0
        }
43083
0
        if (!new_arr) {
43084
0
            value_buffer_free(b);
43085
0
            JS_FreeValue(b->ctx, val);
43086
0
            b->error_status = -1;
43087
0
            return -1;
43088
0
        }
43089
0
        new_size += slack / sizeof(*new_arr);
43090
0
        b->arr = new_arr;
43091
0
        b->size = new_size;
43092
0
    }
43093
0
    b->arr[b->len++] = val;
43094
0
    return 0;
43095
0
}
43096
43097
static int js_is_standard_regexp(JSContext *ctx, JSValueConst rx)
43098
0
{
43099
0
    JSValue val;
43100
0
    int res;
43101
43102
0
    val = JS_GetProperty(ctx, rx, JS_ATOM_constructor);
43103
0
    if (JS_IsException(val))
43104
0
        return -1;
43105
    // rx.constructor === RegExp
43106
0
    res = js_same_value(ctx, val, ctx->regexp_ctor);
43107
0
    JS_FreeValue(ctx, val);
43108
0
    if (res) {
43109
0
        val = JS_GetProperty(ctx, rx, JS_ATOM_exec);
43110
0
        if (JS_IsException(val))
43111
0
            return -1;
43112
        // rx.exec === RE_exec
43113
0
        res = JS_IsCFunction(ctx, val, js_regexp_exec, 0);
43114
0
        JS_FreeValue(ctx, val);
43115
0
    }
43116
0
    return res;
43117
0
}
43118
43119
static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
43120
                                        int argc, JSValueConst *argv)
43121
0
{
43122
    // [Symbol.replace](str, rep)
43123
0
    JSValueConst rx = this_val, rep = argv[1];
43124
0
    JSValueConst args[6];
43125
0
    JSValue str, rep_val, matched, tab, rep_str, namedCaptures, res;
43126
0
    JSString *sp, *rp;
43127
0
    StringBuffer b_s, *b = &b_s;
43128
0
    ValueBuffer v_b, *results = &v_b;
43129
0
    int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode;
43130
0
    uint32_t nCaptures;
43131
0
    int64_t position;
43132
43133
0
    if (!JS_IsObject(rx))
43134
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
43135
43136
0
    string_buffer_init(ctx, b, 0);
43137
0
    value_buffer_init(ctx, results);
43138
43139
0
    rep_val = JS_UNDEFINED;
43140
0
    matched = JS_UNDEFINED;
43141
0
    tab = JS_UNDEFINED;
43142
0
    rep_str = JS_UNDEFINED;
43143
0
    namedCaptures = JS_UNDEFINED;
43144
43145
0
    str = JS_ToString(ctx, argv[0]);
43146
0
    if (JS_IsException(str))
43147
0
        goto exception;
43148
        
43149
0
    sp = JS_VALUE_GET_STRING(str);
43150
0
    rp = NULL;
43151
0
    functionalReplace = JS_IsFunction(ctx, rep);
43152
0
    if (!functionalReplace) {
43153
0
        rep_val = JS_ToString(ctx, rep);
43154
0
        if (JS_IsException(rep_val))
43155
0
            goto exception;
43156
0
        rp = JS_VALUE_GET_STRING(rep_val);
43157
0
    }
43158
0
    fullUnicode = 0;
43159
0
    is_global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global));
43160
0
    if (is_global < 0)
43161
0
        goto exception;
43162
0
    if (is_global) {
43163
0
        fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
43164
0
        if (fullUnicode < 0)
43165
0
            goto exception;
43166
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
43167
0
            goto exception;
43168
0
    }
43169
43170
0
    if (rp && rp->len == 0 && is_global && js_is_standard_regexp(ctx, rx)) {
43171
        /* use faster version for simple cases */
43172
0
        res = JS_RegExpDelete(ctx, rx, str);
43173
0
        goto done;
43174
0
    }
43175
0
    for(;;) {
43176
0
        JSValue result;
43177
0
        result = JS_RegExpExec(ctx, rx, str);
43178
0
        if (JS_IsException(result))
43179
0
            goto exception;
43180
0
        if (JS_IsNull(result))
43181
0
            break;
43182
0
        if (value_buffer_append(results, result) < 0)
43183
0
            goto exception;
43184
0
        if (!is_global)
43185
0
            break;
43186
0
        JS_FreeValue(ctx, matched);
43187
0
        matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
43188
0
        if (JS_IsException(matched))
43189
0
            goto exception;
43190
0
        if (JS_IsEmptyString(matched)) {
43191
            /* always advance of at least one char */
43192
0
            int64_t thisIndex, nextIndex;
43193
0
            if (JS_ToLengthFree(ctx, &thisIndex, JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
43194
0
                goto exception;
43195
0
            nextIndex = string_advance_index(sp, thisIndex, fullUnicode);
43196
0
            if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
43197
0
                goto exception;
43198
0
        }
43199
0
    }
43200
0
    nextSourcePosition = 0;
43201
0
    for(j = 0; j < results->len; j++) {
43202
0
        JSValueConst result;
43203
0
        result = results->arr[j];
43204
0
        if (js_get_length32(ctx, &nCaptures, result) < 0)
43205
0
            goto exception;
43206
0
        JS_FreeValue(ctx, matched);
43207
0
        matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
43208
0
        if (JS_IsException(matched))
43209
0
            goto exception;
43210
0
        if (JS_ToLengthFree(ctx, &position, JS_GetProperty(ctx, result, JS_ATOM_index)))
43211
0
            goto exception;
43212
0
        if (position > sp->len)
43213
0
            position = sp->len;
43214
0
        else if (position < 0)
43215
0
            position = 0;
43216
        /* ignore substition if going backward (can happen
43217
           with custom regexp object) */
43218
0
        JS_FreeValue(ctx, tab);
43219
0
        tab = JS_NewArray(ctx);
43220
0
        if (JS_IsException(tab))
43221
0
            goto exception;
43222
0
        if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched),
43223
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43224
0
            goto exception;
43225
0
        for(n = 1; n < nCaptures; n++) {
43226
0
            JSValue capN;
43227
0
            capN = JS_GetPropertyInt64(ctx, result, n);
43228
0
            if (JS_IsException(capN))
43229
0
                goto exception;
43230
0
            if (!JS_IsUndefined(capN)) {
43231
0
                capN = JS_ToStringFree(ctx, capN);
43232
0
                if (JS_IsException(capN))
43233
0
                    goto exception;
43234
0
            }
43235
0
            if (JS_DefinePropertyValueInt64(ctx, tab, n, capN,
43236
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43237
0
                goto exception;
43238
0
        }
43239
0
        JS_FreeValue(ctx, namedCaptures);
43240
0
        namedCaptures = JS_GetProperty(ctx, result, JS_ATOM_groups);
43241
0
        if (JS_IsException(namedCaptures))
43242
0
            goto exception;
43243
0
        if (functionalReplace) {
43244
0
            if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43245
0
                goto exception;
43246
0
            if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43247
0
                goto exception;
43248
0
            if (!JS_IsUndefined(namedCaptures)) {
43249
0
                if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43250
0
                    goto exception;
43251
0
            }
43252
0
            args[0] = JS_UNDEFINED;
43253
0
            args[1] = tab;
43254
0
            JS_FreeValue(ctx, rep_str);
43255
0
            rep_str = JS_ToStringFree(ctx, js_function_apply(ctx, rep, 2, args, 0));
43256
0
        } else {
43257
0
            JSValue namedCaptures1;
43258
0
            if (!JS_IsUndefined(namedCaptures)) {
43259
0
                namedCaptures1 = JS_ToObject(ctx, namedCaptures);
43260
0
                if (JS_IsException(namedCaptures1))
43261
0
                    goto exception;
43262
0
            } else {
43263
0
                namedCaptures1 = JS_UNDEFINED;
43264
0
            }
43265
0
            args[0] = matched;
43266
0
            args[1] = str;
43267
0
            args[2] = JS_NewInt32(ctx, position);
43268
0
            args[3] = tab;
43269
0
            args[4] = namedCaptures1;
43270
0
            args[5] = rep_val;
43271
0
            JS_FreeValue(ctx, rep_str);
43272
0
            rep_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
43273
0
            JS_FreeValue(ctx, namedCaptures1);
43274
0
        }
43275
0
        if (JS_IsException(rep_str))
43276
0
            goto exception;
43277
0
        if (position >= nextSourcePosition) {
43278
0
            string_buffer_concat(b, sp, nextSourcePosition, position);
43279
0
            string_buffer_concat_value(b, rep_str);
43280
0
            nextSourcePosition = position + JS_VALUE_GET_STRING(matched)->len;
43281
0
        }
43282
0
    }
43283
0
    string_buffer_concat(b, sp, nextSourcePosition, sp->len);
43284
0
    res = string_buffer_end(b);
43285
0
    goto done1;
43286
43287
0
exception:
43288
0
    res = JS_EXCEPTION;
43289
0
done:
43290
0
    string_buffer_free(b);
43291
0
done1:
43292
0
    value_buffer_free(results);
43293
0
    JS_FreeValue(ctx, rep_val);
43294
0
    JS_FreeValue(ctx, matched);
43295
0
    JS_FreeValue(ctx, tab);
43296
0
    JS_FreeValue(ctx, rep_str);
43297
0
    JS_FreeValue(ctx, namedCaptures);
43298
0
    JS_FreeValue(ctx, str);
43299
0
    return res;
43300
0
}
43301
43302
static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val,
43303
                                       int argc, JSValueConst *argv)
43304
0
{
43305
0
    JSValueConst rx = this_val;
43306
0
    JSValue str, previousLastIndex, currentLastIndex, result, index;
43307
43308
0
    if (!JS_IsObject(rx))
43309
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
43310
43311
0
    result = JS_UNDEFINED;
43312
0
    currentLastIndex = JS_UNDEFINED;
43313
0
    previousLastIndex = JS_UNDEFINED;
43314
0
    str = JS_ToString(ctx, argv[0]);
43315
0
    if (JS_IsException(str))
43316
0
        goto exception;
43317
43318
0
    previousLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
43319
0
    if (JS_IsException(previousLastIndex))
43320
0
        goto exception;
43321
43322
0
    if (!js_same_value(ctx, previousLastIndex, JS_NewInt32(ctx, 0))) {
43323
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) {
43324
0
            goto exception;
43325
0
        }
43326
0
    }
43327
0
    result = JS_RegExpExec(ctx, rx, str);
43328
0
    if (JS_IsException(result))
43329
0
        goto exception;
43330
0
    currentLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
43331
0
    if (JS_IsException(currentLastIndex))
43332
0
        goto exception;
43333
0
    if (js_same_value(ctx, currentLastIndex, previousLastIndex)) {
43334
0
        JS_FreeValue(ctx, previousLastIndex);
43335
0
    } else {
43336
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) {
43337
0
            previousLastIndex = JS_UNDEFINED;
43338
0
            goto exception;
43339
0
        }
43340
0
    }
43341
0
    JS_FreeValue(ctx, str);
43342
0
    JS_FreeValue(ctx, currentLastIndex);
43343
43344
0
    if (JS_IsNull(result)) {
43345
0
        return JS_NewInt32(ctx, -1);
43346
0
    } else {
43347
0
        index = JS_GetProperty(ctx, result, JS_ATOM_index);
43348
0
        JS_FreeValue(ctx, result);
43349
0
        return index;
43350
0
    }
43351
43352
0
exception:
43353
0
    JS_FreeValue(ctx, result);
43354
0
    JS_FreeValue(ctx, str);
43355
0
    JS_FreeValue(ctx, currentLastIndex);
43356
0
    JS_FreeValue(ctx, previousLastIndex);
43357
0
    return JS_EXCEPTION;
43358
0
}
43359
43360
static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
43361
                                       int argc, JSValueConst *argv)
43362
0
{
43363
    // [Symbol.split](str, limit)
43364
0
    JSValueConst rx = this_val;
43365
0
    JSValueConst args[2];
43366
0
    JSValue str, ctor, splitter, A, flags, z, sub;
43367
0
    JSString *strp;
43368
0
    uint32_t lim, size, p, q;
43369
0
    int unicodeMatching;
43370
0
    int64_t lengthA, e, numberOfCaptures, i;
43371
43372
0
    if (!JS_IsObject(rx))
43373
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
43374
43375
0
    ctor = JS_UNDEFINED;
43376
0
    splitter = JS_UNDEFINED;
43377
0
    A = JS_UNDEFINED;
43378
0
    flags = JS_UNDEFINED;
43379
0
    z = JS_UNDEFINED;
43380
0
    str = JS_ToString(ctx, argv[0]);
43381
0
    if (JS_IsException(str))
43382
0
        goto exception;
43383
0
    ctor = JS_SpeciesConstructor(ctx, rx, ctx->regexp_ctor);
43384
0
    if (JS_IsException(ctor))
43385
0
        goto exception;
43386
0
    flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_flags));
43387
0
    if (JS_IsException(flags))
43388
0
        goto exception;
43389
0
    strp = JS_VALUE_GET_STRING(flags);
43390
0
    unicodeMatching = string_indexof_char(strp, 'u', 0) >= 0;
43391
0
    if (string_indexof_char(strp, 'y', 0) < 0) {
43392
0
        flags = JS_ConcatString3(ctx, "", flags, "y");
43393
0
        if (JS_IsException(flags))
43394
0
            goto exception;
43395
0
    }
43396
0
    args[0] = rx;
43397
0
    args[1] = flags;
43398
0
    splitter = JS_CallConstructor(ctx, ctor, 2, args);
43399
0
    if (JS_IsException(splitter))
43400
0
        goto exception;
43401
0
    A = JS_NewArray(ctx);
43402
0
    if (JS_IsException(A))
43403
0
        goto exception;
43404
0
    lengthA = 0;
43405
0
    if (JS_IsUndefined(argv[1])) {
43406
0
        lim = 0xffffffff;
43407
0
    } else {
43408
0
        if (JS_ToUint32(ctx, &lim, argv[1]) < 0)
43409
0
            goto exception;
43410
0
        if (lim == 0)
43411
0
            goto done;
43412
0
    }
43413
0
    strp = JS_VALUE_GET_STRING(str);
43414
0
    p = q = 0;
43415
0
    size = strp->len;
43416
0
    if (size == 0) {
43417
0
        z = JS_RegExpExec(ctx, splitter, str);
43418
0
        if (JS_IsException(z))
43419
0
            goto exception;
43420
0
        if (JS_IsNull(z))
43421
0
            goto add_tail;
43422
0
        goto done;
43423
0
    }
43424
0
    while (q < size) {
43425
0
        if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0)
43426
0
            goto exception;
43427
0
        JS_FreeValue(ctx, z);    
43428
0
        z = JS_RegExpExec(ctx, splitter, str);
43429
0
        if (JS_IsException(z))
43430
0
            goto exception;
43431
0
        if (JS_IsNull(z)) {
43432
0
            q = string_advance_index(strp, q, unicodeMatching);
43433
0
        } else {
43434
0
            if (JS_ToLengthFree(ctx, &e, JS_GetProperty(ctx, splitter, JS_ATOM_lastIndex)))
43435
0
                goto exception;
43436
0
            if (e > size)
43437
0
                e = size;
43438
0
            if (e == p) {
43439
0
                q = string_advance_index(strp, q, unicodeMatching);
43440
0
            } else {
43441
0
                sub = js_sub_string(ctx, strp, p, q);
43442
0
                if (JS_IsException(sub))
43443
0
                    goto exception;
43444
0
                if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub,
43445
0
                                                JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43446
0
                    goto exception;
43447
0
                if (lengthA == lim)
43448
0
                    goto done;
43449
0
                p = e;
43450
0
                if (js_get_length64(ctx, &numberOfCaptures, z))
43451
0
                    goto exception;
43452
0
                for(i = 1; i < numberOfCaptures; i++) {
43453
0
                    sub = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, z, i));
43454
0
                    if (JS_IsException(sub))
43455
0
                        goto exception;
43456
0
                    if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43457
0
                        goto exception;
43458
0
                    if (lengthA == lim)
43459
0
                        goto done;
43460
0
                }
43461
0
                q = p;
43462
0
            }
43463
0
        }
43464
0
    }
43465
0
add_tail:
43466
0
    if (p > size)
43467
0
        p = size;
43468
0
    sub = js_sub_string(ctx, strp, p, size);
43469
0
    if (JS_IsException(sub))
43470
0
        goto exception;
43471
0
    if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43472
0
        goto exception;
43473
0
    goto done;
43474
0
exception:
43475
0
    JS_FreeValue(ctx, A);
43476
0
    A = JS_EXCEPTION;
43477
0
done:
43478
0
    JS_FreeValue(ctx, str);
43479
0
    JS_FreeValue(ctx, ctor);
43480
0
    JS_FreeValue(ctx, splitter);
43481
0
    JS_FreeValue(ctx, flags);
43482
0
    JS_FreeValue(ctx, z);    
43483
0
    return A;
43484
0
}
43485
43486
static const JSCFunctionListEntry js_regexp_funcs[] = {
43487
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
43488
    //JS_CFUNC_DEF("__RegExpExec", 2, js_regexp___RegExpExec ),
43489
    //JS_CFUNC_DEF("__RegExpDelete", 2, js_regexp___RegExpDelete ),
43490
};
43491
43492
static const JSCFunctionListEntry js_regexp_proto_funcs[] = {
43493
    JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ),
43494
    JS_CGETSET_DEF("source", js_regexp_get_source, NULL ),
43495
    JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, 1 ),
43496
    JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, 2 ),
43497
    JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, 4 ),
43498
    JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, 8 ),
43499
    JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, 16 ),
43500
    JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, 32 ),
43501
    JS_CFUNC_DEF("exec", 1, js_regexp_exec ),
43502
    JS_CFUNC_DEF("compile", 2, js_regexp_compile ),
43503
    JS_CFUNC_DEF("test", 1, js_regexp_test ),
43504
    JS_CFUNC_DEF("toString", 0, js_regexp_toString ),
43505
    JS_CFUNC_DEF("[Symbol.replace]", 2, js_regexp_Symbol_replace ),
43506
    JS_CFUNC_DEF("[Symbol.match]", 1, js_regexp_Symbol_match ),
43507
    JS_CFUNC_DEF("[Symbol.matchAll]", 1, js_regexp_Symbol_matchAll ),
43508
    JS_CFUNC_DEF("[Symbol.search]", 1, js_regexp_Symbol_search ),
43509
    JS_CFUNC_DEF("[Symbol.split]", 2, js_regexp_Symbol_split ),
43510
    //JS_CGETSET_DEF("__source", js_regexp_get___source, NULL ),
43511
    //JS_CGETSET_DEF("__flags", js_regexp_get___flags, NULL ),
43512
};
43513
43514
static const JSCFunctionListEntry js_regexp_string_iterator_proto_funcs[] = {
43515
    JS_ITERATOR_NEXT_DEF("next", 0, js_regexp_string_iterator_next, 0 ),
43516
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "RegExp String Iterator", JS_PROP_CONFIGURABLE ),
43517
};
43518
43519
void JS_AddIntrinsicRegExpCompiler(JSContext *ctx)
43520
2
{
43521
2
    ctx->compile_regexp = js_compile_regexp;
43522
2
}
43523
43524
void JS_AddIntrinsicRegExp(JSContext *ctx)
43525
2
{
43526
2
    JSValueConst obj;
43527
43528
2
    JS_AddIntrinsicRegExpCompiler(ctx);
43529
43530
2
    ctx->class_proto[JS_CLASS_REGEXP] = JS_NewObject(ctx);
43531
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP], js_regexp_proto_funcs,
43532
2
                               countof(js_regexp_proto_funcs));
43533
2
    obj = JS_NewGlobalCConstructor(ctx, "RegExp", js_regexp_constructor, 2,
43534
2
                                   ctx->class_proto[JS_CLASS_REGEXP]);
43535
2
    ctx->regexp_ctor = JS_DupValue(ctx, obj);
43536
2
    JS_SetPropertyFunctionList(ctx, obj, js_regexp_funcs, countof(js_regexp_funcs));
43537
43538
2
    ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR] =
43539
2
        JS_NewObjectProto(ctx, ctx->iterator_proto);
43540
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR],
43541
2
                               js_regexp_string_iterator_proto_funcs,
43542
2
                               countof(js_regexp_string_iterator_proto_funcs));
43543
2
}
43544
43545
/* JSON */
43546
43547
static int json_parse_expect(JSParseState *s, int tok)
43548
0
{
43549
0
    if (s->token.val != tok) {
43550
        /* XXX: dump token correctly in all cases */
43551
0
        return js_parse_error(s, "expecting '%c'", tok);
43552
0
    }
43553
0
    return json_next_token(s);
43554
0
}
43555
43556
static JSValue json_parse_value(JSParseState *s)
43557
0
{
43558
0
    JSContext *ctx = s->ctx;
43559
0
    JSValue val = JS_NULL;
43560
0
    int ret;
43561
43562
0
    switch(s->token.val) {
43563
0
    case '{':
43564
0
        {
43565
0
            JSValue prop_val;
43566
0
            JSAtom prop_name;
43567
            
43568
0
            if (json_next_token(s))
43569
0
                goto fail;
43570
0
            val = JS_NewObject(ctx);
43571
0
            if (JS_IsException(val))
43572
0
                goto fail;
43573
0
            if (s->token.val != '}') {
43574
0
                for(;;) {
43575
0
                    if (s->token.val == TOK_STRING) {
43576
0
                        prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);
43577
0
                        if (prop_name == JS_ATOM_NULL)
43578
0
                            goto fail;
43579
0
                    } else if (s->ext_json && s->token.val == TOK_IDENT) {
43580
0
                        prop_name = JS_DupAtom(ctx, s->token.u.ident.atom);
43581
0
                    } else {
43582
0
                        js_parse_error(s, "expecting property name");
43583
0
                        goto fail;
43584
0
                    }
43585
0
                    if (json_next_token(s))
43586
0
                        goto fail1;
43587
0
                    if (json_parse_expect(s, ':'))
43588
0
                        goto fail1;
43589
0
                    prop_val = json_parse_value(s);
43590
0
                    if (JS_IsException(prop_val)) {
43591
0
                    fail1:
43592
0
                        JS_FreeAtom(ctx, prop_name);
43593
0
                        goto fail;
43594
0
                    }
43595
0
                    ret = JS_DefinePropertyValue(ctx, val, prop_name,
43596
0
                                                 prop_val, JS_PROP_C_W_E);
43597
0
                    JS_FreeAtom(ctx, prop_name);
43598
0
                    if (ret < 0)
43599
0
                        goto fail;
43600
43601
0
                    if (s->token.val != ',')
43602
0
                        break;
43603
0
                    if (json_next_token(s))
43604
0
                        goto fail;
43605
0
                    if (s->ext_json && s->token.val == '}')
43606
0
                        break;
43607
0
                }
43608
0
            }
43609
0
            if (json_parse_expect(s, '}'))
43610
0
                goto fail;
43611
0
        }
43612
0
        break;
43613
0
    case '[':
43614
0
        {
43615
0
            JSValue el;
43616
0
            uint32_t idx;
43617
43618
0
            if (json_next_token(s))
43619
0
                goto fail;
43620
0
            val = JS_NewArray(ctx);
43621
0
            if (JS_IsException(val))
43622
0
                goto fail;
43623
0
            if (s->token.val != ']') {
43624
0
                idx = 0;
43625
0
                for(;;) {
43626
0
                    el = json_parse_value(s);
43627
0
                    if (JS_IsException(el))
43628
0
                        goto fail;
43629
0
                    ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E);
43630
0
                    if (ret < 0)
43631
0
                        goto fail;
43632
0
                    if (s->token.val != ',')
43633
0
                        break;
43634
0
                    if (json_next_token(s))
43635
0
                        goto fail;
43636
0
                    idx++;
43637
0
                    if (s->ext_json && s->token.val == ']')
43638
0
                        break;
43639
0
                }
43640
0
            }
43641
0
            if (json_parse_expect(s, ']'))
43642
0
                goto fail;
43643
0
        }
43644
0
        break;
43645
0
    case TOK_STRING:
43646
0
        val = JS_DupValue(ctx, s->token.u.str.str);
43647
0
        if (json_next_token(s))
43648
0
            goto fail;
43649
0
        break;
43650
0
    case TOK_NUMBER:
43651
0
        val = s->token.u.num.val;
43652
0
        if (json_next_token(s))
43653
0
            goto fail;
43654
0
        break;
43655
0
    case TOK_IDENT:
43656
0
        if (s->token.u.ident.atom == JS_ATOM_false ||
43657
0
            s->token.u.ident.atom == JS_ATOM_true) {
43658
0
            val = JS_NewBool(ctx, (s->token.u.ident.atom == JS_ATOM_true));
43659
0
        } else if (s->token.u.ident.atom == JS_ATOM_null) {
43660
0
            val = JS_NULL;
43661
0
        } else {
43662
0
            goto def_token;
43663
0
        }
43664
0
        if (json_next_token(s))
43665
0
            goto fail;
43666
0
        break;
43667
0
    default:
43668
0
    def_token:
43669
0
        if (s->token.val == TOK_EOF) {
43670
0
            js_parse_error(s, "unexpected end of input");
43671
0
        } else {
43672
0
            js_parse_error(s, "unexpected token: '%.*s'",
43673
0
                           (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
43674
0
        }
43675
0
        goto fail;
43676
0
    }
43677
0
    return val;
43678
0
 fail:
43679
0
    JS_FreeValue(ctx, val);
43680
0
    return JS_EXCEPTION;
43681
0
}
43682
43683
JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
43684
                      const char *filename, int flags)
43685
0
{
43686
0
    JSParseState s1, *s = &s1;
43687
0
    JSValue val = JS_UNDEFINED;
43688
43689
0
    js_parse_init(ctx, s, buf, buf_len, filename);
43690
0
    s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);
43691
0
    if (json_next_token(s))
43692
0
        goto fail;
43693
0
    val = json_parse_value(s);
43694
0
    if (JS_IsException(val))
43695
0
        goto fail;
43696
0
    if (s->token.val != TOK_EOF) {
43697
0
        if (js_parse_error(s, "unexpected data at the end"))
43698
0
            goto fail;
43699
0
    }
43700
0
    return val;
43701
0
 fail:
43702
0
    JS_FreeValue(ctx, val);
43703
0
    free_token(s, &s->token);
43704
0
    return JS_EXCEPTION;
43705
0
}
43706
43707
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
43708
                     const char *filename)
43709
0
{
43710
0
    return JS_ParseJSON2(ctx, buf, buf_len, filename, 0); 
43711
0
}
43712
43713
static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
43714
                                         JSAtom name, JSValueConst reviver)
43715
0
{
43716
0
    JSValue val, new_el, name_val, res;
43717
0
    JSValueConst args[2];
43718
0
    int ret, is_array;
43719
0
    uint32_t i, len = 0;
43720
0
    JSAtom prop;
43721
0
    JSPropertyEnum *atoms = NULL;
43722
43723
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
43724
0
        return JS_ThrowStackOverflow(ctx);
43725
0
    }
43726
43727
0
    val = JS_GetProperty(ctx, holder, name);
43728
0
    if (JS_IsException(val))
43729
0
        return val;
43730
0
    if (JS_IsObject(val)) {
43731
0
        is_array = JS_IsArray(ctx, val);
43732
0
        if (is_array < 0)
43733
0
            goto fail;
43734
0
        if (is_array) {
43735
0
            if (js_get_length32(ctx, &len, val))
43736
0
                goto fail;
43737
0
        } else {
43738
0
            ret = JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, JS_VALUE_GET_OBJ(val), JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
43739
0
            if (ret < 0)
43740
0
                goto fail;
43741
0
        }
43742
0
        for(i = 0; i < len; i++) {
43743
0
            if (is_array) {
43744
0
                prop = JS_NewAtomUInt32(ctx, i);
43745
0
                if (prop == JS_ATOM_NULL)
43746
0
                    goto fail;
43747
0
            } else {
43748
0
                prop = JS_DupAtom(ctx, atoms[i].atom);
43749
0
            }
43750
0
            new_el = internalize_json_property(ctx, val, prop, reviver);
43751
0
            if (JS_IsException(new_el)) {
43752
0
                JS_FreeAtom(ctx, prop);
43753
0
                goto fail;
43754
0
            }
43755
0
            if (JS_IsUndefined(new_el)) {
43756
0
                ret = JS_DeleteProperty(ctx, val, prop, 0);
43757
0
            } else {
43758
0
                ret = JS_DefinePropertyValue(ctx, val, prop, new_el, JS_PROP_C_W_E);
43759
0
            }
43760
0
            JS_FreeAtom(ctx, prop);
43761
0
            if (ret < 0)
43762
0
                goto fail;
43763
0
        }
43764
0
    }
43765
0
    js_free_prop_enum(ctx, atoms, len);
43766
0
    atoms = NULL;
43767
0
    name_val = JS_AtomToValue(ctx, name);
43768
0
    if (JS_IsException(name_val))
43769
0
        goto fail;
43770
0
    args[0] = name_val;
43771
0
    args[1] = val;
43772
0
    res = JS_Call(ctx, reviver, holder, 2, args);
43773
0
    JS_FreeValue(ctx, name_val);
43774
0
    JS_FreeValue(ctx, val);
43775
0
    return res;
43776
0
 fail:
43777
0
    js_free_prop_enum(ctx, atoms, len);
43778
0
    JS_FreeValue(ctx, val);
43779
0
    return JS_EXCEPTION;
43780
0
}
43781
43782
static JSValue js_json_parse(JSContext *ctx, JSValueConst this_val,
43783
                             int argc, JSValueConst *argv)
43784
0
{
43785
0
    JSValue obj, root;
43786
0
    JSValueConst reviver;
43787
0
    const char *str;
43788
0
    size_t len;
43789
43790
0
    str = JS_ToCStringLen(ctx, &len, argv[0]);
43791
0
    if (!str)
43792
0
        return JS_EXCEPTION;
43793
0
    obj = JS_ParseJSON(ctx, str, len, "<input>");
43794
0
    JS_FreeCString(ctx, str);
43795
0
    if (JS_IsException(obj))
43796
0
        return obj;
43797
0
    if (argc > 1 && JS_IsFunction(ctx, argv[1])) {
43798
0
        reviver = argv[1];
43799
0
        root = JS_NewObject(ctx);
43800
0
        if (JS_IsException(root)) {
43801
0
            JS_FreeValue(ctx, obj);
43802
0
            return JS_EXCEPTION;
43803
0
        }
43804
0
        if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj,
43805
0
                                   JS_PROP_C_W_E) < 0) {
43806
0
            JS_FreeValue(ctx, root);
43807
0
            return JS_EXCEPTION;
43808
0
        }
43809
0
        obj = internalize_json_property(ctx, root, JS_ATOM_empty_string,
43810
0
                                        reviver);
43811
0
        JS_FreeValue(ctx, root);
43812
0
    }
43813
0
    return obj;
43814
0
}
43815
43816
typedef struct JSONStringifyContext {
43817
    JSValueConst replacer_func;
43818
    JSValue stack;
43819
    JSValue property_list;
43820
    JSValue gap;
43821
    JSValue empty;
43822
    StringBuffer *b;
43823
} JSONStringifyContext;
43824
43825
0
static JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) {
43826
0
    JSValue r = JS_ToQuotedString(ctx, val);
43827
0
    JS_FreeValue(ctx, val);
43828
0
    return r;
43829
0
}
43830
43831
static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
43832
                             JSValueConst holder, JSValue val, JSValueConst key)
43833
0
{
43834
0
    JSValue v;
43835
0
    JSValueConst args[2];
43836
43837
0
    if (JS_IsObject(val)
43838
0
#ifdef CONFIG_BIGNUM
43839
0
    ||  JS_IsBigInt(ctx, val)   /* XXX: probably useless */
43840
0
#endif
43841
0
        ) {
43842
0
            JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);
43843
0
            if (JS_IsException(f))
43844
0
                goto exception;
43845
0
            if (JS_IsFunction(ctx, f)) {
43846
0
                v = JS_CallFree(ctx, f, val, 1, &key);
43847
0
                JS_FreeValue(ctx, val);
43848
0
                val = v;
43849
0
                if (JS_IsException(val))
43850
0
                    goto exception;
43851
0
            } else {
43852
0
                JS_FreeValue(ctx, f);
43853
0
            }
43854
0
        }
43855
43856
0
    if (!JS_IsUndefined(jsc->replacer_func)) {
43857
0
        args[0] = key;
43858
0
        args[1] = val;
43859
0
        v = JS_Call(ctx, jsc->replacer_func, holder, 2, args);
43860
0
        JS_FreeValue(ctx, val);
43861
0
        val = v;
43862
0
        if (JS_IsException(val))
43863
0
            goto exception;
43864
0
    }
43865
43866
0
    switch (JS_VALUE_GET_NORM_TAG(val)) {
43867
0
    case JS_TAG_OBJECT:
43868
0
        if (JS_IsFunction(ctx, val))
43869
0
            break;
43870
0
    case JS_TAG_STRING:
43871
0
    case JS_TAG_INT:
43872
0
    case JS_TAG_FLOAT64:
43873
0
#ifdef CONFIG_BIGNUM
43874
0
    case JS_TAG_BIG_FLOAT:
43875
0
#endif
43876
0
    case JS_TAG_BOOL:
43877
0
    case JS_TAG_NULL:
43878
0
#ifdef CONFIG_BIGNUM
43879
0
    case JS_TAG_BIG_INT:
43880
0
#endif
43881
0
    case JS_TAG_EXCEPTION:
43882
0
        return val;
43883
0
    default:
43884
0
        break;
43885
0
    }
43886
0
    JS_FreeValue(ctx, val);
43887
0
    return JS_UNDEFINED;
43888
43889
0
exception:
43890
0
    JS_FreeValue(ctx, val);
43891
0
    return JS_EXCEPTION;
43892
0
}
43893
43894
static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
43895
                          JSValueConst holder, JSValue val,
43896
                          JSValueConst indent)
43897
0
{
43898
0
    JSValue indent1, sep, sep1, tab, v, prop;
43899
0
    JSObject *p;
43900
0
    int64_t i, len;
43901
0
    int cl, ret;
43902
0
    BOOL has_content;
43903
    
43904
0
    indent1 = JS_UNDEFINED;
43905
0
    sep = JS_UNDEFINED;
43906
0
    sep1 = JS_UNDEFINED;
43907
0
    tab = JS_UNDEFINED;
43908
0
    prop = JS_UNDEFINED;
43909
43910
0
    switch (JS_VALUE_GET_NORM_TAG(val)) {
43911
0
    case JS_TAG_OBJECT:
43912
0
        p = JS_VALUE_GET_OBJ(val);
43913
0
        cl = p->class_id;
43914
0
        if (cl == JS_CLASS_STRING) {
43915
0
            val = JS_ToStringFree(ctx, val);
43916
0
            if (JS_IsException(val))
43917
0
                goto exception;
43918
0
            val = JS_ToQuotedStringFree(ctx, val);
43919
0
            if (JS_IsException(val))
43920
0
                goto exception;
43921
0
            return string_buffer_concat_value_free(jsc->b, val);
43922
0
        } else if (cl == JS_CLASS_NUMBER) {
43923
0
            val = JS_ToNumberFree(ctx, val);
43924
0
            if (JS_IsException(val))
43925
0
                goto exception;
43926
0
            return string_buffer_concat_value_free(jsc->b, val);
43927
0
        } else if (cl == JS_CLASS_BOOLEAN) {
43928
0
            ret = string_buffer_concat_value(jsc->b, p->u.object_data);
43929
0
            JS_FreeValue(ctx, val);
43930
0
            return ret;
43931
0
        }
43932
0
#ifdef CONFIG_BIGNUM
43933
0
        else if (cl == JS_CLASS_BIG_FLOAT) {
43934
0
            return string_buffer_concat_value_free(jsc->b, val);
43935
0
        } else if (cl == JS_CLASS_BIG_INT) {
43936
0
            JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
43937
0
            goto exception;
43938
0
        }
43939
0
#endif
43940
0
        v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val);
43941
0
        if (JS_IsException(v))
43942
0
            goto exception;
43943
0
        if (JS_ToBoolFree(ctx, v)) {
43944
0
            JS_ThrowTypeError(ctx, "circular reference");
43945
0
            goto exception;
43946
0
        }
43947
0
        indent1 = JS_ConcatString(ctx, JS_DupValue(ctx, indent), JS_DupValue(ctx, jsc->gap));
43948
0
        if (JS_IsException(indent1))
43949
0
            goto exception;
43950
0
        if (!JS_IsEmptyString(jsc->gap)) {
43951
0
            sep = JS_ConcatString3(ctx, "\n", JS_DupValue(ctx, indent1), "");
43952
0
            if (JS_IsException(sep))
43953
0
                goto exception;
43954
0
            sep1 = JS_NewString(ctx, " ");
43955
0
            if (JS_IsException(sep1))
43956
0
                goto exception;
43957
0
        } else {
43958
0
            sep = JS_DupValue(ctx, jsc->empty);
43959
0
            sep1 = JS_DupValue(ctx, jsc->empty);
43960
0
        }
43961
0
        v = js_array_push(ctx, jsc->stack, 1, (JSValueConst *)&val, 0);
43962
0
        if (check_exception_free(ctx, v))
43963
0
            goto exception;
43964
0
        ret = JS_IsArray(ctx, val);
43965
0
        if (ret < 0)
43966
0
            goto exception;
43967
0
        if (ret) {
43968
0
            if (js_get_length64(ctx, &len, val))
43969
0
                goto exception;
43970
0
            string_buffer_putc8(jsc->b, '[');
43971
0
            for(i = 0; i < len; i++) {
43972
0
                if (i > 0)
43973
0
                    string_buffer_putc8(jsc->b, ',');
43974
0
                string_buffer_concat_value(jsc->b, sep);
43975
0
                v = JS_GetPropertyInt64(ctx, val, i);
43976
0
                if (JS_IsException(v))
43977
0
                    goto exception;
43978
                /* XXX: could do this string conversion only when needed */
43979
0
                prop = JS_ToStringFree(ctx, JS_NewInt64(ctx, i));
43980
0
                if (JS_IsException(prop))
43981
0
                    goto exception;
43982
0
                v = js_json_check(ctx, jsc, val, v, prop);
43983
0
                JS_FreeValue(ctx, prop);
43984
0
                prop = JS_UNDEFINED;
43985
0
                if (JS_IsException(v))
43986
0
                    goto exception;
43987
0
                if (JS_IsUndefined(v))
43988
0
                    v = JS_NULL;
43989
0
                if (js_json_to_str(ctx, jsc, val, v, indent1))
43990
0
                    goto exception;
43991
0
            }
43992
0
            if (len > 0 && !JS_IsEmptyString(jsc->gap)) {
43993
0
                string_buffer_putc8(jsc->b, '\n');
43994
0
                string_buffer_concat_value(jsc->b, indent);
43995
0
            }
43996
0
            string_buffer_putc8(jsc->b, ']');
43997
0
        } else {
43998
0
            if (!JS_IsUndefined(jsc->property_list))
43999
0
                tab = JS_DupValue(ctx, jsc->property_list);
44000
0
            else
44001
0
                tab = js_object_keys(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val, JS_ITERATOR_KIND_KEY);
44002
0
            if (JS_IsException(tab))
44003
0
                goto exception;
44004
0
            if (js_get_length64(ctx, &len, tab))
44005
0
                goto exception;
44006
0
            string_buffer_putc8(jsc->b, '{');
44007
0
            has_content = FALSE;
44008
0
            for(i = 0; i < len; i++) {
44009
0
                JS_FreeValue(ctx, prop);
44010
0
                prop = JS_GetPropertyInt64(ctx, tab, i);
44011
0
                if (JS_IsException(prop))
44012
0
                    goto exception;
44013
0
                v = JS_GetPropertyValue(ctx, val, JS_DupValue(ctx, prop));
44014
0
                if (JS_IsException(v))
44015
0
                    goto exception;
44016
0
                v = js_json_check(ctx, jsc, val, v, prop);
44017
0
                if (JS_IsException(v))
44018
0
                    goto exception;
44019
0
                if (!JS_IsUndefined(v)) {
44020
0
                    if (has_content)
44021
0
                        string_buffer_putc8(jsc->b, ',');
44022
0
                    prop = JS_ToQuotedStringFree(ctx, prop);
44023
0
                    if (JS_IsException(prop)) {
44024
0
                        JS_FreeValue(ctx, v);
44025
0
                        goto exception;
44026
0
                    }
44027
0
                    string_buffer_concat_value(jsc->b, sep);
44028
0
                    string_buffer_concat_value(jsc->b, prop);
44029
0
                    string_buffer_putc8(jsc->b, ':');
44030
0
                    string_buffer_concat_value(jsc->b, sep1);
44031
0
                    if (js_json_to_str(ctx, jsc, val, v, indent1))
44032
0
                        goto exception;
44033
0
                    has_content = TRUE;
44034
0
                }
44035
0
            }
44036
0
            if (has_content && JS_VALUE_GET_STRING(jsc->gap)->len != 0) {
44037
0
                string_buffer_putc8(jsc->b, '\n');
44038
0
                string_buffer_concat_value(jsc->b, indent);
44039
0
            }
44040
0
            string_buffer_putc8(jsc->b, '}');
44041
0
        }
44042
0
        if (check_exception_free(ctx, js_array_pop(ctx, jsc->stack, 0, NULL, 0)))
44043
0
            goto exception;
44044
0
        JS_FreeValue(ctx, val);
44045
0
        JS_FreeValue(ctx, tab);
44046
0
        JS_FreeValue(ctx, sep);
44047
0
        JS_FreeValue(ctx, sep1);
44048
0
        JS_FreeValue(ctx, indent1);
44049
0
        JS_FreeValue(ctx, prop);
44050
0
        return 0;
44051
0
    case JS_TAG_STRING:
44052
0
        val = JS_ToQuotedStringFree(ctx, val);
44053
0
        if (JS_IsException(val))
44054
0
            goto exception;
44055
0
        goto concat_value;
44056
0
    case JS_TAG_FLOAT64:
44057
0
        if (!isfinite(JS_VALUE_GET_FLOAT64(val))) {
44058
0
            val = JS_NULL;
44059
0
        }
44060
0
        goto concat_value;
44061
0
    case JS_TAG_INT:
44062
0
#ifdef CONFIG_BIGNUM
44063
0
    case JS_TAG_BIG_FLOAT:
44064
0
#endif
44065
0
    case JS_TAG_BOOL:
44066
0
    case JS_TAG_NULL:
44067
0
    concat_value:
44068
0
        return string_buffer_concat_value_free(jsc->b, val);
44069
0
#ifdef CONFIG_BIGNUM
44070
0
    case JS_TAG_BIG_INT:
44071
0
        JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
44072
0
        goto exception;
44073
0
#endif
44074
0
    default:
44075
0
        JS_FreeValue(ctx, val);
44076
0
        return 0;
44077
0
    }
44078
    
44079
0
exception:
44080
0
    JS_FreeValue(ctx, val);
44081
0
    JS_FreeValue(ctx, tab);
44082
0
    JS_FreeValue(ctx, sep);
44083
0
    JS_FreeValue(ctx, sep1);
44084
0
    JS_FreeValue(ctx, indent1);
44085
0
    JS_FreeValue(ctx, prop);
44086
0
    return -1;
44087
0
}
44088
44089
JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
44090
                         JSValueConst replacer, JSValueConst space0)
44091
0
{
44092
0
    StringBuffer b_s;
44093
0
    JSONStringifyContext jsc_s, *jsc = &jsc_s;
44094
0
    JSValue val, v, space, ret, wrapper;
44095
0
    int res;
44096
0
    int64_t i, j, n;
44097
44098
0
    jsc->replacer_func = JS_UNDEFINED;
44099
0
    jsc->stack = JS_UNDEFINED;
44100
0
    jsc->property_list = JS_UNDEFINED;
44101
0
    jsc->gap = JS_UNDEFINED;
44102
0
    jsc->b = &b_s;
44103
0
    jsc->empty = JS_AtomToString(ctx, JS_ATOM_empty_string);
44104
0
    ret = JS_UNDEFINED;
44105
0
    wrapper = JS_UNDEFINED;
44106
44107
0
    string_buffer_init(ctx, jsc->b, 0);
44108
0
    jsc->stack = JS_NewArray(ctx);
44109
0
    if (JS_IsException(jsc->stack))
44110
0
        goto exception;
44111
0
    if (JS_IsFunction(ctx, replacer)) {
44112
0
        jsc->replacer_func = replacer;
44113
0
    } else {
44114
0
        res = JS_IsArray(ctx, replacer);
44115
0
        if (res < 0)
44116
0
            goto exception;
44117
0
        if (res) {
44118
            /* XXX: enumeration is not fully correct */
44119
0
            jsc->property_list = JS_NewArray(ctx);
44120
0
            if (JS_IsException(jsc->property_list))
44121
0
                goto exception;
44122
0
            if (js_get_length64(ctx, &n, replacer))
44123
0
                goto exception;
44124
0
            for (i = j = 0; i < n; i++) {
44125
0
                JSValue present;
44126
0
                v = JS_GetPropertyInt64(ctx, replacer, i);
44127
0
                if (JS_IsException(v))
44128
0
                    goto exception;
44129
0
                if (JS_IsObject(v)) {
44130
0
                    JSObject *p = JS_VALUE_GET_OBJ(v);
44131
0
                    if (p->class_id == JS_CLASS_STRING ||
44132
0
                        p->class_id == JS_CLASS_NUMBER) {
44133
0
                        v = JS_ToStringFree(ctx, v);
44134
0
                        if (JS_IsException(v))
44135
0
                            goto exception;
44136
0
                    } else {
44137
0
                        JS_FreeValue(ctx, v);
44138
0
                        continue;
44139
0
                    }
44140
0
                } else if (JS_IsNumber(v)) {
44141
0
                    v = JS_ToStringFree(ctx, v);
44142
0
                    if (JS_IsException(v))
44143
0
                        goto exception;
44144
0
                } else if (!JS_IsString(v)) {
44145
0
                    JS_FreeValue(ctx, v);
44146
0
                    continue;
44147
0
                }
44148
0
                present = js_array_includes(ctx, jsc->property_list,
44149
0
                                            1, (JSValueConst *)&v);
44150
0
                if (JS_IsException(present)) {
44151
0
                    JS_FreeValue(ctx, v);
44152
0
                    goto exception;
44153
0
                }
44154
0
                if (!JS_ToBoolFree(ctx, present)) {
44155
0
                    JS_SetPropertyInt64(ctx, jsc->property_list, j++, v);
44156
0
                } else {
44157
0
                    JS_FreeValue(ctx, v);
44158
0
                }
44159
0
            }
44160
0
        }
44161
0
    }
44162
0
    space = JS_DupValue(ctx, space0);
44163
0
    if (JS_IsObject(space)) {
44164
0
        JSObject *p = JS_VALUE_GET_OBJ(space);
44165
0
        if (p->class_id == JS_CLASS_NUMBER) {
44166
0
            space = JS_ToNumberFree(ctx, space);
44167
0
        } else if (p->class_id == JS_CLASS_STRING) {
44168
0
            space = JS_ToStringFree(ctx, space);
44169
0
        }
44170
0
        if (JS_IsException(space)) {
44171
0
            JS_FreeValue(ctx, space);
44172
0
            goto exception;
44173
0
        }
44174
0
    }
44175
0
    if (JS_IsNumber(space)) {
44176
0
        int n;
44177
0
        if (JS_ToInt32Clamp(ctx, &n, space, 0, 10, 0))
44178
0
            goto exception;
44179
0
        jsc->gap = JS_NewStringLen(ctx, "          ", n);
44180
0
    } else if (JS_IsString(space)) {
44181
0
        JSString *p = JS_VALUE_GET_STRING(space);
44182
0
        jsc->gap = js_sub_string(ctx, p, 0, min_int(p->len, 10));
44183
0
    } else {
44184
0
        jsc->gap = JS_DupValue(ctx, jsc->empty);
44185
0
    }
44186
0
    JS_FreeValue(ctx, space);
44187
0
    if (JS_IsException(jsc->gap))
44188
0
        goto exception;
44189
0
    wrapper = JS_NewObject(ctx);
44190
0
    if (JS_IsException(wrapper))
44191
0
        goto exception;
44192
0
    if (JS_DefinePropertyValue(ctx, wrapper, JS_ATOM_empty_string,
44193
0
                               JS_DupValue(ctx, obj), JS_PROP_C_W_E) < 0)
44194
0
        goto exception;
44195
0
    val = JS_DupValue(ctx, obj);
44196
                           
44197
0
    val = js_json_check(ctx, jsc, wrapper, val, jsc->empty);
44198
0
    if (JS_IsException(val))
44199
0
        goto exception;
44200
0
    if (JS_IsUndefined(val)) {
44201
0
        ret = JS_UNDEFINED;
44202
0
        goto done1;
44203
0
    }
44204
0
    if (js_json_to_str(ctx, jsc, wrapper, val, jsc->empty))
44205
0
        goto exception;
44206
44207
0
    ret = string_buffer_end(jsc->b);
44208
0
    goto done;
44209
44210
0
exception:
44211
0
    ret = JS_EXCEPTION;
44212
0
done1:
44213
0
    string_buffer_free(jsc->b);
44214
0
done:
44215
0
    JS_FreeValue(ctx, wrapper);
44216
0
    JS_FreeValue(ctx, jsc->empty);
44217
0
    JS_FreeValue(ctx, jsc->gap);
44218
0
    JS_FreeValue(ctx, jsc->property_list);
44219
0
    JS_FreeValue(ctx, jsc->stack);
44220
0
    return ret;
44221
0
}
44222
44223
static JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val,
44224
                                 int argc, JSValueConst *argv)
44225
0
{
44226
    // stringify(val, replacer, space)
44227
0
    return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]);
44228
0
}
44229
44230
static const JSCFunctionListEntry js_json_funcs[] = {
44231
    JS_CFUNC_DEF("parse", 2, js_json_parse ),
44232
    JS_CFUNC_DEF("stringify", 3, js_json_stringify ),
44233
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "JSON", JS_PROP_CONFIGURABLE ),
44234
};
44235
44236
static const JSCFunctionListEntry js_json_obj[] = {
44237
    JS_OBJECT_DEF("JSON", js_json_funcs, countof(js_json_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
44238
};
44239
44240
void JS_AddIntrinsicJSON(JSContext *ctx)
44241
2
{
44242
    /* add JSON as autoinit object */
44243
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_json_obj, countof(js_json_obj));
44244
2
}
44245
44246
/* Reflect */
44247
44248
static JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val,
44249
                                int argc, JSValueConst *argv)
44250
0
{
44251
0
    return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2);
44252
0
}
44253
44254
static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
44255
                                    int argc, JSValueConst *argv)
44256
0
{
44257
0
    JSValueConst func, array_arg, new_target;
44258
0
    JSValue *tab, ret;
44259
0
    uint32_t len;
44260
44261
0
    func = argv[0];
44262
0
    array_arg = argv[1];
44263
0
    if (argc > 2) {
44264
0
        new_target = argv[2];
44265
0
        if (!JS_IsConstructor(ctx, new_target))
44266
0
            return JS_ThrowTypeError(ctx, "not a constructor");
44267
0
    } else {
44268
0
        new_target = func;
44269
0
    }
44270
0
    tab = build_arg_list(ctx, &len, array_arg);
44271
0
    if (!tab)
44272
0
        return JS_EXCEPTION;
44273
0
    ret = JS_CallConstructor2(ctx, func, new_target, len, (JSValueConst *)tab);
44274
0
    free_arg_list(ctx, tab, len);
44275
0
    return ret;
44276
0
}
44277
44278
static JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val,
44279
                                         int argc, JSValueConst *argv)
44280
0
{
44281
0
    JSValueConst obj;
44282
0
    JSAtom atom;
44283
0
    int ret;
44284
44285
0
    obj = argv[0];
44286
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
44287
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44288
0
    atom = JS_ValueToAtom(ctx, argv[1]);
44289
0
    if (unlikely(atom == JS_ATOM_NULL))
44290
0
        return JS_EXCEPTION;
44291
0
    ret = JS_DeleteProperty(ctx, obj, atom, 0);
44292
0
    JS_FreeAtom(ctx, atom);
44293
0
    if (ret < 0)
44294
0
        return JS_EXCEPTION;
44295
0
    else
44296
0
        return JS_NewBool(ctx, ret);
44297
0
}
44298
44299
static JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val,
44300
                              int argc, JSValueConst *argv)
44301
0
{
44302
0
    JSValueConst obj, prop, receiver;
44303
0
    JSAtom atom;
44304
0
    JSValue ret;
44305
44306
0
    obj = argv[0];
44307
0
    prop = argv[1];
44308
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
44309
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44310
0
    if (argc > 2)
44311
0
        receiver = argv[2];
44312
0
    else
44313
0
        receiver = obj;
44314
0
    atom = JS_ValueToAtom(ctx, prop);
44315
0
    if (unlikely(atom == JS_ATOM_NULL))
44316
0
        return JS_EXCEPTION;
44317
0
    ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, FALSE);
44318
0
    JS_FreeAtom(ctx, atom);
44319
0
    return ret;
44320
0
}
44321
44322
static JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val,
44323
                              int argc, JSValueConst *argv)
44324
0
{
44325
0
    JSValueConst obj, prop;
44326
0
    JSAtom atom;
44327
0
    int ret;
44328
44329
0
    obj = argv[0];
44330
0
    prop = argv[1];
44331
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
44332
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44333
0
    atom = JS_ValueToAtom(ctx, prop);
44334
0
    if (unlikely(atom == JS_ATOM_NULL))
44335
0
        return JS_EXCEPTION;
44336
0
    ret = JS_HasProperty(ctx, obj, atom);
44337
0
    JS_FreeAtom(ctx, atom);
44338
0
    if (ret < 0)
44339
0
        return JS_EXCEPTION;
44340
0
    else
44341
0
        return JS_NewBool(ctx, ret);
44342
0
}
44343
44344
static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
44345
                              int argc, JSValueConst *argv)
44346
0
{
44347
0
    JSValueConst obj, prop, val, receiver;
44348
0
    int ret;
44349
0
    JSAtom atom;
44350
44351
0
    obj = argv[0];
44352
0
    prop = argv[1];
44353
0
    val = argv[2];
44354
0
    if (argc > 3)
44355
0
        receiver = argv[3];
44356
0
    else
44357
0
        receiver = obj;
44358
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
44359
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44360
0
    atom = JS_ValueToAtom(ctx, prop);
44361
0
    if (unlikely(atom == JS_ATOM_NULL))
44362
0
        return JS_EXCEPTION;
44363
0
    ret = JS_SetPropertyGeneric(ctx, obj, atom,
44364
0
                                JS_DupValue(ctx, val), receiver, 0);
44365
0
    JS_FreeAtom(ctx, atom);
44366
0
    if (ret < 0)
44367
0
        return JS_EXCEPTION;
44368
0
    else
44369
0
        return JS_NewBool(ctx, ret);
44370
0
}
44371
44372
static JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
44373
                                         int argc, JSValueConst *argv)
44374
0
{
44375
0
    int ret;
44376
0
    ret = JS_SetPrototypeInternal(ctx, argv[0], argv[1], FALSE);
44377
0
    if (ret < 0)
44378
0
        return JS_EXCEPTION;
44379
0
    else
44380
0
        return JS_NewBool(ctx, ret);
44381
0
}
44382
44383
static JSValue js_reflect_ownKeys(JSContext *ctx, JSValueConst this_val,
44384
                                  int argc, JSValueConst *argv)
44385
0
{
44386
0
    if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
44387
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44388
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
44389
0
                                   JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK,
44390
0
                                   JS_ITERATOR_KIND_KEY);
44391
0
}
44392
44393
static const JSCFunctionListEntry js_reflect_funcs[] = {
44394
    JS_CFUNC_DEF("apply", 3, js_reflect_apply ),
44395
    JS_CFUNC_DEF("construct", 2, js_reflect_construct ),
44396
    JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 1 ),
44397
    JS_CFUNC_DEF("deleteProperty", 2, js_reflect_deleteProperty ),
44398
    JS_CFUNC_DEF("get", 2, js_reflect_get ),
44399
    JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 1 ),
44400
    JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 1 ),
44401
    JS_CFUNC_DEF("has", 2, js_reflect_has ),
44402
    JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 1 ),
44403
    JS_CFUNC_DEF("ownKeys", 1, js_reflect_ownKeys ),
44404
    JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 1 ),
44405
    JS_CFUNC_DEF("set", 3, js_reflect_set ),
44406
    JS_CFUNC_DEF("setPrototypeOf", 2, js_reflect_setPrototypeOf ),
44407
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Reflect", JS_PROP_CONFIGURABLE ),
44408
};
44409
44410
static const JSCFunctionListEntry js_reflect_obj[] = {
44411
    JS_OBJECT_DEF("Reflect", js_reflect_funcs, countof(js_reflect_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
44412
};
44413
44414
/* Proxy */
44415
44416
static void js_proxy_finalizer(JSRuntime *rt, JSValue val)
44417
0
{
44418
0
    JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
44419
0
    if (s) {
44420
0
        JS_FreeValueRT(rt, s->target);
44421
0
        JS_FreeValueRT(rt, s->handler);
44422
0
        js_free_rt(rt, s);
44423
0
    }
44424
0
}
44425
44426
static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
44427
                          JS_MarkFunc *mark_func)
44428
0
{
44429
0
    JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
44430
0
    if (s) {
44431
0
        JS_MarkValue(rt, s->target, mark_func);
44432
0
        JS_MarkValue(rt, s->handler, mark_func);
44433
0
    }
44434
0
}
44435
44436
static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx)
44437
0
{
44438
0
    return JS_ThrowTypeError(ctx, "revoked proxy");
44439
0
}
44440
44441
static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod,
44442
                                     JSValueConst obj, JSAtom name)
44443
0
{
44444
0
    JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
44445
0
    JSValue method;
44446
44447
    /* safer to test recursion in all proxy methods */
44448
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
44449
0
        JS_ThrowStackOverflow(ctx);
44450
0
        return NULL;
44451
0
    }
44452
    
44453
    /* 's' should never be NULL */
44454
0
    if (s->is_revoked) {
44455
0
        JS_ThrowTypeErrorRevokedProxy(ctx);
44456
0
        return NULL;
44457
0
    }
44458
0
    method = JS_GetProperty(ctx, s->handler, name);
44459
0
    if (JS_IsException(method))
44460
0
        return NULL;
44461
0
    if (JS_IsNull(method))
44462
0
        method = JS_UNDEFINED;
44463
0
    *pmethod = method;
44464
0
    return s;
44465
0
}
44466
44467
static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
44468
0
{
44469
0
    JSProxyData *s;
44470
0
    JSValue method, ret, proto1;
44471
0
    int res;
44472
44473
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_getPrototypeOf);
44474
0
    if (!s)
44475
0
        return JS_EXCEPTION;
44476
0
    if (JS_IsUndefined(method))
44477
0
        return JS_GetPrototype(ctx, s->target);
44478
0
    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
44479
0
    if (JS_IsException(ret))
44480
0
        return ret;
44481
0
    if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL &&
44482
0
        JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
44483
0
        goto fail;
44484
0
    }
44485
0
    res = JS_IsExtensible(ctx, s->target);
44486
0
    if (res < 0) {
44487
0
        JS_FreeValue(ctx, ret);
44488
0
        return JS_EXCEPTION;
44489
0
    }
44490
0
    if (!res) {
44491
        /* check invariant */
44492
0
        proto1 = JS_GetPrototype(ctx, s->target);
44493
0
        if (JS_IsException(proto1)) {
44494
0
            JS_FreeValue(ctx, ret);
44495
0
            return JS_EXCEPTION;
44496
0
        }
44497
0
        if (JS_VALUE_GET_OBJ(proto1) != JS_VALUE_GET_OBJ(ret)) {
44498
0
            JS_FreeValue(ctx, proto1);
44499
0
        fail:
44500
0
            JS_FreeValue(ctx, ret);
44501
0
            return JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
44502
0
        }
44503
0
        JS_FreeValue(ctx, proto1);
44504
0
    }
44505
0
    return ret;
44506
0
}
44507
44508
static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
44509
                                   JSValueConst proto_val, BOOL throw_flag)
44510
0
{
44511
0
    JSProxyData *s;
44512
0
    JSValue method, ret, proto1;
44513
0
    JSValueConst args[2];
44514
0
    BOOL res;
44515
0
    int res2;
44516
44517
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_setPrototypeOf);
44518
0
    if (!s)
44519
0
        return -1;
44520
0
    if (JS_IsUndefined(method))
44521
0
        return JS_SetPrototypeInternal(ctx, s->target, proto_val, throw_flag);
44522
0
    args[0] = s->target;
44523
0
    args[1] = proto_val;
44524
0
    ret = JS_CallFree(ctx, method, s->handler, 2, args);
44525
0
    if (JS_IsException(ret))
44526
0
        return -1;
44527
0
    res = JS_ToBoolFree(ctx, ret);
44528
0
    if (!res) {
44529
0
        if (throw_flag) {
44530
0
            JS_ThrowTypeError(ctx, "proxy: bad prototype");
44531
0
            return -1;
44532
0
        } else {
44533
0
            return FALSE;
44534
0
        }
44535
0
    }
44536
0
    res2 = JS_IsExtensible(ctx, s->target);
44537
0
    if (res2 < 0)
44538
0
        return -1;
44539
0
    if (!res2) {
44540
0
        proto1 = JS_GetPrototype(ctx, s->target);
44541
0
        if (JS_IsException(proto1))
44542
0
            return -1;
44543
0
        if (JS_VALUE_GET_OBJ(proto_val) != JS_VALUE_GET_OBJ(proto1)) {
44544
0
            JS_FreeValue(ctx, proto1);
44545
0
            JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
44546
0
            return -1;
44547
0
        }
44548
0
        JS_FreeValue(ctx, proto1);
44549
0
    }
44550
0
    return TRUE;
44551
0
}
44552
44553
static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj)
44554
0
{
44555
0
    JSProxyData *s;
44556
0
    JSValue method, ret;
44557
0
    BOOL res;
44558
0
    int res2;
44559
44560
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_isExtensible);
44561
0
    if (!s)
44562
0
        return -1;
44563
0
    if (JS_IsUndefined(method))
44564
0
        return JS_IsExtensible(ctx, s->target);
44565
0
    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
44566
0
    if (JS_IsException(ret))
44567
0
        return -1;
44568
0
    res = JS_ToBoolFree(ctx, ret);
44569
0
    res2 = JS_IsExtensible(ctx, s->target);
44570
0
    if (res2 < 0)
44571
0
        return res2;
44572
0
    if (res != res2) {
44573
0
        JS_ThrowTypeError(ctx, "proxy: inconsistent isExtensible");
44574
0
        return -1;
44575
0
    }
44576
0
    return res;
44577
0
}
44578
44579
static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj)
44580
0
{
44581
0
    JSProxyData *s;
44582
0
    JSValue method, ret;
44583
0
    BOOL res;
44584
0
    int res2;
44585
44586
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_preventExtensions);
44587
0
    if (!s)
44588
0
        return -1;
44589
0
    if (JS_IsUndefined(method))
44590
0
        return JS_PreventExtensions(ctx, s->target);
44591
0
    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
44592
0
    if (JS_IsException(ret))
44593
0
        return -1;
44594
0
    res = JS_ToBoolFree(ctx, ret);
44595
0
    if (res) {
44596
0
        res2 = JS_IsExtensible(ctx, s->target);
44597
0
        if (res2 < 0)
44598
0
            return res2;
44599
0
        if (res2) {
44600
0
            JS_ThrowTypeError(ctx, "proxy: inconsistent preventExtensions");
44601
0
            return -1;
44602
0
        }
44603
0
    }
44604
0
    return res;
44605
0
}
44606
44607
static int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
44608
0
{
44609
0
    JSProxyData *s;
44610
0
    JSValue method, ret1, atom_val;
44611
0
    int ret, res;
44612
0
    JSObject *p;
44613
0
    JSValueConst args[2];
44614
0
    BOOL res2;
44615
44616
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_has);
44617
0
    if (!s)
44618
0
        return -1;
44619
0
    if (JS_IsUndefined(method))
44620
0
        return JS_HasProperty(ctx, s->target, atom);
44621
0
    atom_val = JS_AtomToValue(ctx, atom);
44622
0
    if (JS_IsException(atom_val)) {
44623
0
        JS_FreeValue(ctx, method);
44624
0
        return -1;
44625
0
    }
44626
0
    args[0] = s->target;
44627
0
    args[1] = atom_val;
44628
0
    ret1 = JS_CallFree(ctx, method, s->handler, 2, args);
44629
0
    JS_FreeValue(ctx, atom_val);
44630
0
    if (JS_IsException(ret1))
44631
0
        return -1;
44632
0
    ret = JS_ToBoolFree(ctx, ret1);
44633
0
    if (!ret) {
44634
0
        JSPropertyDescriptor desc;
44635
0
        p = JS_VALUE_GET_OBJ(s->target);
44636
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
44637
0
        if (res < 0)
44638
0
            return -1;
44639
0
        if (res) {
44640
0
            res2 = !(desc.flags & JS_PROP_CONFIGURABLE);
44641
0
            js_free_desc(ctx, &desc);
44642
0
            if (res2 || !p->extensible) {
44643
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent has");
44644
0
                return -1;
44645
0
            }
44646
0
        }
44647
0
    }
44648
0
    return ret;
44649
0
}
44650
44651
static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,
44652
                            JSValueConst receiver)
44653
0
{
44654
0
    JSProxyData *s;
44655
0
    JSValue method, ret, atom_val;
44656
0
    int res;
44657
0
    JSValueConst args[3];
44658
0
    JSPropertyDescriptor desc;
44659
44660
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_get);
44661
0
    if (!s)
44662
0
        return JS_EXCEPTION;
44663
    /* Note: recursion is possible thru the prototype of s->target */
44664
0
    if (JS_IsUndefined(method))
44665
0
        return JS_GetPropertyInternal(ctx, s->target, atom, receiver, FALSE);
44666
0
    atom_val = JS_AtomToValue(ctx, atom);
44667
0
    if (JS_IsException(atom_val)) {
44668
0
        JS_FreeValue(ctx, method);
44669
0
        return JS_EXCEPTION;
44670
0
    }
44671
0
    args[0] = s->target;
44672
0
    args[1] = atom_val;
44673
0
    args[2] = receiver;
44674
0
    ret = JS_CallFree(ctx, method, s->handler, 3, args);
44675
0
    JS_FreeValue(ctx, atom_val);
44676
0
    if (JS_IsException(ret))
44677
0
        return JS_EXCEPTION;
44678
0
    res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
44679
0
    if (res < 0)
44680
0
        return JS_EXCEPTION;
44681
0
    if (res) {
44682
0
        if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
44683
0
            if (!js_same_value(ctx, desc.value, ret)) {
44684
0
                goto fail;
44685
0
            }
44686
0
        } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET) {
44687
0
            if (JS_IsUndefined(desc.getter) && !JS_IsUndefined(ret)) {
44688
0
            fail:
44689
0
                js_free_desc(ctx, &desc);
44690
0
                JS_FreeValue(ctx, ret);
44691
0
                return JS_ThrowTypeError(ctx, "proxy: inconsistent get");
44692
0
            }
44693
0
        }
44694
0
        js_free_desc(ctx, &desc);
44695
0
    }
44696
0
    return ret;
44697
0
}
44698
44699
static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
44700
                        JSValueConst value, JSValueConst receiver, int flags)
44701
0
{
44702
0
    JSProxyData *s;
44703
0
    JSValue method, ret1, atom_val;
44704
0
    int ret, res;
44705
0
    JSValueConst args[4];
44706
44707
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_set);
44708
0
    if (!s)
44709
0
        return -1;
44710
0
    if (JS_IsUndefined(method)) {
44711
0
        return JS_SetPropertyGeneric(ctx, s->target, atom,
44712
0
                                     JS_DupValue(ctx, value), receiver,
44713
0
                                     flags);
44714
0
    }
44715
0
    atom_val = JS_AtomToValue(ctx, atom);
44716
0
    if (JS_IsException(atom_val)) {
44717
0
        JS_FreeValue(ctx, method);
44718
0
        return -1;
44719
0
    }
44720
0
    args[0] = s->target;
44721
0
    args[1] = atom_val;
44722
0
    args[2] = value;
44723
0
    args[3] = receiver;
44724
0
    ret1 = JS_CallFree(ctx, method, s->handler, 4, args);
44725
0
    JS_FreeValue(ctx, atom_val);
44726
0
    if (JS_IsException(ret1))
44727
0
        return -1;
44728
0
    ret = JS_ToBoolFree(ctx, ret1);
44729
0
    if (ret) {
44730
0
        JSPropertyDescriptor desc;
44731
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
44732
0
        if (res < 0)
44733
0
            return -1;
44734
0
        if (res) {
44735
0
            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
44736
0
                if (!js_same_value(ctx, desc.value, value)) {
44737
0
                    goto fail;
44738
0
                }
44739
0
            } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET && JS_IsUndefined(desc.setter)) {
44740
0
                fail:
44741
0
                    js_free_desc(ctx, &desc);
44742
0
                    JS_ThrowTypeError(ctx, "proxy: inconsistent set");
44743
0
                    return -1;
44744
0
            }
44745
0
            js_free_desc(ctx, &desc);
44746
0
        }
44747
0
    } else {
44748
0
        if ((flags & JS_PROP_THROW) ||
44749
0
            ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
44750
0
            JS_ThrowTypeError(ctx, "proxy: cannot set property");
44751
0
            return -1;
44752
0
        }
44753
0
    }
44754
0
    return ret;
44755
0
}
44756
44757
static JSValue js_create_desc(JSContext *ctx, JSValueConst val,
44758
                              JSValueConst getter, JSValueConst setter,
44759
                              int flags)
44760
0
{
44761
0
    JSValue ret;
44762
0
    ret = JS_NewObject(ctx);
44763
0
    if (JS_IsException(ret))
44764
0
        return ret;
44765
0
    if (flags & JS_PROP_HAS_GET) {
44766
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, getter),
44767
0
                               JS_PROP_C_W_E);
44768
0
    }
44769
0
    if (flags & JS_PROP_HAS_SET) {
44770
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, setter),
44771
0
                               JS_PROP_C_W_E);
44772
0
    }
44773
0
    if (flags & JS_PROP_HAS_VALUE) {
44774
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, val),
44775
0
                               JS_PROP_C_W_E);
44776
0
    }
44777
0
    if (flags & JS_PROP_HAS_WRITABLE) {
44778
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
44779
0
                               JS_NewBool(ctx, (flags & JS_PROP_WRITABLE) != 0),
44780
0
                               JS_PROP_C_W_E);
44781
0
    }
44782
0
    if (flags & JS_PROP_HAS_ENUMERABLE) {
44783
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
44784
0
                               JS_NewBool(ctx, (flags & JS_PROP_ENUMERABLE) != 0),
44785
0
                               JS_PROP_C_W_E);
44786
0
    }
44787
0
    if (flags & JS_PROP_HAS_CONFIGURABLE) {
44788
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
44789
0
                               JS_NewBool(ctx, (flags & JS_PROP_CONFIGURABLE) != 0),
44790
0
                               JS_PROP_C_W_E);
44791
0
    }
44792
0
    return ret;
44793
0
}
44794
44795
static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc,
44796
                                     JSValueConst obj, JSAtom prop)
44797
0
{
44798
0
    JSProxyData *s;
44799
0
    JSValue method, trap_result_obj, prop_val;
44800
0
    int res, target_desc_ret, ret;
44801
0
    JSObject *p;
44802
0
    JSValueConst args[2];
44803
0
    JSPropertyDescriptor result_desc, target_desc;
44804
44805
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_getOwnPropertyDescriptor);
44806
0
    if (!s)
44807
0
        return -1;
44808
0
    p = JS_VALUE_GET_OBJ(s->target);
44809
0
    if (JS_IsUndefined(method)) {
44810
0
        return JS_GetOwnPropertyInternal(ctx, pdesc, p, prop);
44811
0
    }
44812
0
    prop_val = JS_AtomToValue(ctx, prop);
44813
0
    if (JS_IsException(prop_val)) {
44814
0
        JS_FreeValue(ctx, method);
44815
0
        return -1;
44816
0
    }
44817
0
    args[0] = s->target;
44818
0
    args[1] = prop_val;
44819
0
    trap_result_obj = JS_CallFree(ctx, method, s->handler, 2, args);
44820
0
    JS_FreeValue(ctx, prop_val);
44821
0
    if (JS_IsException(trap_result_obj))
44822
0
        return -1;
44823
0
    if (!JS_IsObject(trap_result_obj) && !JS_IsUndefined(trap_result_obj)) {
44824
0
        JS_FreeValue(ctx, trap_result_obj);
44825
0
        goto fail;
44826
0
    }
44827
0
    target_desc_ret = JS_GetOwnPropertyInternal(ctx, &target_desc, p, prop);
44828
0
    if (target_desc_ret < 0) {
44829
0
        JS_FreeValue(ctx, trap_result_obj);
44830
0
        return -1;
44831
0
    }
44832
0
    if (target_desc_ret)
44833
0
        js_free_desc(ctx, &target_desc);
44834
0
    if (JS_IsUndefined(trap_result_obj)) {
44835
0
        if (target_desc_ret) {
44836
0
            if (!(target_desc.flags & JS_PROP_CONFIGURABLE) || !p->extensible)
44837
0
                goto fail;
44838
0
        }
44839
0
        ret = FALSE;
44840
0
    } else {
44841
0
        int flags1, extensible_target;
44842
0
        extensible_target = JS_IsExtensible(ctx, s->target);
44843
0
        if (extensible_target < 0) {
44844
0
            JS_FreeValue(ctx, trap_result_obj);
44845
0
            return -1;
44846
0
        }
44847
0
        res = js_obj_to_desc(ctx, &result_desc, trap_result_obj);
44848
0
        JS_FreeValue(ctx, trap_result_obj);
44849
0
        if (res < 0)
44850
0
            return -1;
44851
        
44852
0
        if (target_desc_ret) {
44853
            /* convert result_desc.flags to defineProperty flags */
44854
0
            flags1 = result_desc.flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE;
44855
0
            if (result_desc.flags & JS_PROP_GETSET)
44856
0
                flags1 |= JS_PROP_HAS_GET | JS_PROP_HAS_SET;
44857
0
            else
44858
0
                flags1 |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE;
44859
            /* XXX: not complete check: need to compare value &
44860
               getter/setter as in defineproperty */
44861
0
            if (!check_define_prop_flags(target_desc.flags, flags1))
44862
0
                goto fail1;
44863
0
        } else {
44864
0
            if (!extensible_target)
44865
0
                goto fail1;
44866
0
        }
44867
0
        if (!(result_desc.flags & JS_PROP_CONFIGURABLE)) {
44868
0
            if (!target_desc_ret || (target_desc.flags & JS_PROP_CONFIGURABLE))
44869
0
                goto fail1;
44870
0
            if ((result_desc.flags &
44871
0
                 (JS_PROP_GETSET | JS_PROP_WRITABLE)) == 0 &&
44872
0
                target_desc_ret &&
44873
0
                (target_desc.flags & JS_PROP_WRITABLE) != 0) {
44874
                /* proxy-missing-checks */
44875
0
            fail1:
44876
0
                js_free_desc(ctx, &result_desc);
44877
0
            fail:
44878
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent getOwnPropertyDescriptor");
44879
0
                return -1;
44880
0
            }
44881
0
        }
44882
0
        ret = TRUE;
44883
0
        if (pdesc) {
44884
0
            *pdesc = result_desc;
44885
0
        } else {
44886
0
            js_free_desc(ctx, &result_desc);
44887
0
        }
44888
0
    }
44889
0
    return ret;
44890
0
}
44891
44892
static int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj,
44893
                                        JSAtom prop, JSValueConst val,
44894
                                        JSValueConst getter, JSValueConst setter,
44895
                                        int flags)
44896
0
{
44897
0
    JSProxyData *s;
44898
0
    JSValue method, ret1, prop_val, desc_val;
44899
0
    int res, ret;
44900
0
    JSObject *p;
44901
0
    JSValueConst args[3];
44902
0
    JSPropertyDescriptor desc;
44903
0
    BOOL setting_not_configurable;
44904
44905
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_defineProperty);
44906
0
    if (!s)
44907
0
        return -1;
44908
0
    if (JS_IsUndefined(method)) {
44909
0
        return JS_DefineProperty(ctx, s->target, prop, val, getter, setter, flags);
44910
0
    }
44911
0
    prop_val = JS_AtomToValue(ctx, prop);
44912
0
    if (JS_IsException(prop_val)) {
44913
0
        JS_FreeValue(ctx, method);
44914
0
        return -1;
44915
0
    }
44916
0
    desc_val = js_create_desc(ctx, val, getter, setter, flags);
44917
0
    if (JS_IsException(desc_val)) {
44918
0
        JS_FreeValue(ctx, prop_val);
44919
0
        JS_FreeValue(ctx, method);
44920
0
        return -1;
44921
0
    }
44922
0
    args[0] = s->target;
44923
0
    args[1] = prop_val;
44924
0
    args[2] = desc_val;
44925
0
    ret1 = JS_CallFree(ctx, method, s->handler, 3, args);
44926
0
    JS_FreeValue(ctx, prop_val);
44927
0
    JS_FreeValue(ctx, desc_val);
44928
0
    if (JS_IsException(ret1))
44929
0
        return -1;
44930
0
    ret = JS_ToBoolFree(ctx, ret1);
44931
0
    if (!ret) {
44932
0
        if (flags & JS_PROP_THROW) {
44933
0
            JS_ThrowTypeError(ctx, "proxy: defineProperty exception");
44934
0
            return -1;
44935
0
        } else {
44936
0
            return 0;
44937
0
        }
44938
0
    }
44939
0
    p = JS_VALUE_GET_OBJ(s->target);
44940
0
    res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
44941
0
    if (res < 0)
44942
0
        return -1;
44943
0
    setting_not_configurable = ((flags & (JS_PROP_HAS_CONFIGURABLE |
44944
0
                                          JS_PROP_CONFIGURABLE)) ==
44945
0
                                JS_PROP_HAS_CONFIGURABLE);
44946
0
    if (!res) {
44947
0
        if (!p->extensible || setting_not_configurable)
44948
0
            goto fail;
44949
0
    } else {
44950
0
        if (!check_define_prop_flags(desc.flags, flags) ||
44951
0
            ((desc.flags & JS_PROP_CONFIGURABLE) && setting_not_configurable)) {
44952
0
            goto fail1;
44953
0
        }
44954
0
        if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
44955
0
            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) ==
44956
0
                JS_PROP_GETSET) {
44957
0
                if ((flags & JS_PROP_HAS_GET) &&
44958
0
                    !js_same_value(ctx, getter, desc.getter)) {
44959
0
                    goto fail1;
44960
0
                }
44961
0
                if ((flags & JS_PROP_HAS_SET) &&
44962
0
                    !js_same_value(ctx, setter, desc.setter)) {
44963
0
                    goto fail1;
44964
0
                }
44965
0
            }
44966
0
        } else if (flags & JS_PROP_HAS_VALUE) {
44967
0
            if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) ==
44968
0
                JS_PROP_WRITABLE && !(flags & JS_PROP_WRITABLE)) {
44969
                /* missing-proxy-check feature */
44970
0
                goto fail1;
44971
0
            } else if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
44972
0
                !js_same_value(ctx, val, desc.value)) {
44973
0
                goto fail1;
44974
0
            }
44975
0
        }
44976
0
        if (flags & JS_PROP_HAS_WRITABLE) {
44977
0
            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE |
44978
0
                               JS_PROP_WRITABLE)) == JS_PROP_WRITABLE) {
44979
                /* proxy-missing-checks */
44980
0
            fail1:
44981
0
                js_free_desc(ctx, &desc);
44982
0
            fail:
44983
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent defineProperty");
44984
0
                return -1;
44985
0
            }
44986
0
        }
44987
0
        js_free_desc(ctx, &desc);
44988
0
    }
44989
0
    return 1;
44990
0
}
44991
44992
static int js_proxy_delete_property(JSContext *ctx, JSValueConst obj,
44993
                                    JSAtom atom)
44994
0
{
44995
0
    JSProxyData *s;
44996
0
    JSValue method, ret, atom_val;
44997
0
    int res, res2, is_extensible;
44998
0
    JSValueConst args[2];
44999
45000
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_deleteProperty);
45001
0
    if (!s)
45002
0
        return -1;
45003
0
    if (JS_IsUndefined(method)) {
45004
0
        return JS_DeleteProperty(ctx, s->target, atom, 0);
45005
0
    }
45006
0
    atom_val = JS_AtomToValue(ctx, atom);;
45007
0
    if (JS_IsException(atom_val)) {
45008
0
        JS_FreeValue(ctx, method);
45009
0
        return -1;
45010
0
    }
45011
0
    args[0] = s->target;
45012
0
    args[1] = atom_val;
45013
0
    ret = JS_CallFree(ctx, method, s->handler, 2, args);
45014
0
    JS_FreeValue(ctx, atom_val);
45015
0
    if (JS_IsException(ret))
45016
0
        return -1;
45017
0
    res = JS_ToBoolFree(ctx, ret);
45018
0
    if (res) {
45019
0
        JSPropertyDescriptor desc;
45020
0
        res2 = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
45021
0
        if (res2 < 0)
45022
0
            return -1;
45023
0
        if (res2) {
45024
0
            if (!(desc.flags & JS_PROP_CONFIGURABLE))
45025
0
                goto fail;
45026
0
            is_extensible = JS_IsExtensible(ctx, s->target);
45027
0
            if (is_extensible < 0)
45028
0
                goto fail1;
45029
0
            if (!is_extensible) {
45030
                /* proxy-missing-checks */
45031
0
            fail:
45032
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent deleteProperty");
45033
0
            fail1:
45034
0
                js_free_desc(ctx, &desc);
45035
0
                return -1;
45036
0
            }
45037
0
            js_free_desc(ctx, &desc);
45038
0
        }
45039
0
    }
45040
0
    return res;
45041
0
}
45042
45043
/* return the index of the property or -1 if not found */
45044
static int find_prop_key(const JSPropertyEnum *tab, int n, JSAtom atom)
45045
0
{
45046
0
    int i;
45047
0
    for(i = 0; i < n; i++) {
45048
0
        if (tab[i].atom == atom)
45049
0
            return i;
45050
0
    }
45051
0
    return -1;
45052
0
}
45053
45054
static int js_proxy_get_own_property_names(JSContext *ctx,
45055
                                           JSPropertyEnum **ptab,
45056
                                           uint32_t *plen,
45057
                                           JSValueConst obj)
45058
0
{
45059
0
    JSProxyData *s;
45060
0
    JSValue method, prop_array, val;
45061
0
    uint32_t len, i, len2;
45062
0
    JSPropertyEnum *tab, *tab2;
45063
0
    JSAtom atom;
45064
0
    JSPropertyDescriptor desc;
45065
0
    int res, is_extensible, idx;
45066
45067
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_ownKeys);
45068
0
    if (!s)
45069
0
        return -1;
45070
0
    if (JS_IsUndefined(method)) {
45071
0
        return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
45072
0
                                      JS_VALUE_GET_OBJ(s->target),
45073
0
                                      JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK);
45074
0
    }
45075
0
    prop_array = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
45076
0
    if (JS_IsException(prop_array))
45077
0
        return -1;
45078
0
    tab = NULL;
45079
0
    len = 0;
45080
0
    tab2 = NULL;
45081
0
    len2 = 0;
45082
0
    if (js_get_length32(ctx, &len, prop_array))
45083
0
        goto fail;
45084
0
    if (len > 0) {
45085
0
        tab = js_mallocz(ctx, sizeof(tab[0]) * len);
45086
0
        if (!tab)
45087
0
            goto fail;
45088
0
    }
45089
0
    for(i = 0; i < len; i++) {
45090
0
        val = JS_GetPropertyUint32(ctx, prop_array, i);
45091
0
        if (JS_IsException(val))
45092
0
            goto fail;
45093
0
        if (!JS_IsString(val) && !JS_IsSymbol(val)) {
45094
0
            JS_FreeValue(ctx, val);
45095
0
            JS_ThrowTypeError(ctx, "proxy: properties must be strings or symbols");
45096
0
            goto fail;
45097
0
        }
45098
0
        atom = JS_ValueToAtom(ctx, val);
45099
0
        JS_FreeValue(ctx, val);
45100
0
        if (atom == JS_ATOM_NULL)
45101
0
            goto fail;
45102
0
        tab[i].atom = atom;
45103
0
        tab[i].is_enumerable = FALSE; /* XXX: redundant? */
45104
0
    }
45105
45106
    /* check duplicate properties (XXX: inefficient, could store the
45107
     * properties an a temporary object to use the hash) */
45108
0
    for(i = 1; i < len; i++) {
45109
0
        if (find_prop_key(tab, i, tab[i].atom) >= 0) {
45110
0
            JS_ThrowTypeError(ctx, "proxy: duplicate property");
45111
0
            goto fail;
45112
0
        }
45113
0
    }
45114
45115
0
    is_extensible = JS_IsExtensible(ctx, s->target);
45116
0
    if (is_extensible < 0)
45117
0
        goto fail;
45118
45119
    /* check if there are non configurable properties */
45120
0
    if (s->is_revoked) {
45121
0
        JS_ThrowTypeErrorRevokedProxy(ctx);
45122
0
        goto fail;
45123
0
    }
45124
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &tab2, &len2, JS_VALUE_GET_OBJ(s->target),
45125
0
                               JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
45126
0
        goto fail;
45127
0
    for(i = 0; i < len2; i++) {
45128
0
        if (s->is_revoked) {
45129
0
            JS_ThrowTypeErrorRevokedProxy(ctx);
45130
0
            goto fail;
45131
0
        }
45132
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target),
45133
0
                                tab2[i].atom);
45134
0
        if (res < 0)
45135
0
            goto fail;
45136
0
        if (res) {  /* safety, property should be found */
45137
0
            js_free_desc(ctx, &desc);
45138
0
            if (!(desc.flags & JS_PROP_CONFIGURABLE) || !is_extensible) {
45139
0
                idx = find_prop_key(tab, len, tab2[i].atom);
45140
0
                if (idx < 0) {
45141
0
                    JS_ThrowTypeError(ctx, "proxy: target property must be present in proxy ownKeys");
45142
0
                    goto fail;
45143
0
                }
45144
                /* mark the property as found */
45145
0
                if (!is_extensible)
45146
0
                    tab[idx].is_enumerable = TRUE;
45147
0
            }
45148
0
        }
45149
0
    }
45150
0
    if (!is_extensible) {
45151
        /* check that all property in 'tab' were checked */
45152
0
        for(i = 0; i < len; i++) {
45153
0
            if (!tab[i].is_enumerable) {
45154
0
                JS_ThrowTypeError(ctx, "proxy: property not present in target were returned by non extensible proxy");
45155
0
                goto fail;
45156
0
            }
45157
0
        }
45158
0
    }
45159
45160
0
    js_free_prop_enum(ctx, tab2, len2);
45161
0
    JS_FreeValue(ctx, prop_array);
45162
0
    *ptab = tab;
45163
0
    *plen = len;
45164
0
    return 0;
45165
0
 fail:
45166
0
    js_free_prop_enum(ctx, tab2, len2);
45167
0
    js_free_prop_enum(ctx, tab, len);
45168
0
    JS_FreeValue(ctx, prop_array);
45169
0
    return -1;
45170
0
}
45171
45172
static JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj,
45173
                                         JSValueConst new_target,
45174
                                         int argc, JSValueConst *argv)
45175
0
{
45176
0
    JSProxyData *s;
45177
0
    JSValue method, arg_array, ret;
45178
0
    JSValueConst args[3];
45179
45180
0
    s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_construct);
45181
0
    if (!s)
45182
0
        return JS_EXCEPTION;
45183
0
    if (!JS_IsConstructor(ctx, s->target))
45184
0
        return JS_ThrowTypeError(ctx, "not a constructor");
45185
0
    if (JS_IsUndefined(method))
45186
0
        return JS_CallConstructor2(ctx, s->target, new_target, argc, argv);
45187
0
    arg_array = js_create_array(ctx, argc, argv);
45188
0
    if (JS_IsException(arg_array)) {
45189
0
        ret = JS_EXCEPTION;
45190
0
        goto fail;
45191
0
    }
45192
0
    args[0] = s->target;
45193
0
    args[1] = arg_array;
45194
0
    args[2] = new_target;
45195
0
    ret = JS_Call(ctx, method, s->handler, 3, args);
45196
0
    if (!JS_IsException(ret) && JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
45197
0
        JS_FreeValue(ctx, ret);
45198
0
        ret = JS_ThrowTypeErrorNotAnObject(ctx);
45199
0
    }
45200
0
 fail:
45201
0
    JS_FreeValue(ctx, method);
45202
0
    JS_FreeValue(ctx, arg_array);
45203
0
    return ret;
45204
0
}
45205
45206
static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,
45207
                             JSValueConst this_obj,
45208
                             int argc, JSValueConst *argv, int flags)
45209
0
{
45210
0
    JSProxyData *s;
45211
0
    JSValue method, arg_array, ret;
45212
0
    JSValueConst args[3];
45213
45214
0
    if (flags & JS_CALL_FLAG_CONSTRUCTOR)
45215
0
        return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv);
45216
    
45217
0
    s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_apply);
45218
0
    if (!s)
45219
0
        return JS_EXCEPTION;
45220
0
    if (!s->is_func) {
45221
0
        JS_FreeValue(ctx, method);
45222
0
        return JS_ThrowTypeError(ctx, "not a function");
45223
0
    }
45224
0
    if (JS_IsUndefined(method))
45225
0
        return JS_Call(ctx, s->target, this_obj, argc, argv);
45226
0
    arg_array = js_create_array(ctx, argc, argv);
45227
0
    if (JS_IsException(arg_array)) {
45228
0
        ret = JS_EXCEPTION;
45229
0
        goto fail;
45230
0
    }
45231
0
    args[0] = s->target;
45232
0
    args[1] = this_obj;
45233
0
    args[2] = arg_array;
45234
0
    ret = JS_Call(ctx, method, s->handler, 3, args);
45235
0
 fail:
45236
0
    JS_FreeValue(ctx, method);
45237
0
    JS_FreeValue(ctx, arg_array);
45238
0
    return ret;
45239
0
}
45240
45241
static int js_proxy_isArray(JSContext *ctx, JSValueConst obj)
45242
0
{
45243
0
    JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
45244
0
    if (!s)
45245
0
        return FALSE;
45246
0
    if (s->is_revoked) {
45247
0
        JS_ThrowTypeErrorRevokedProxy(ctx);
45248
0
        return -1;
45249
0
    }
45250
0
    return JS_IsArray(ctx, s->target);
45251
0
}
45252
45253
static const JSClassExoticMethods js_proxy_exotic_methods = {
45254
    .get_own_property = js_proxy_get_own_property,
45255
    .define_own_property = js_proxy_define_own_property,
45256
    .delete_property = js_proxy_delete_property,
45257
    .get_own_property_names = js_proxy_get_own_property_names,
45258
    .has_property = js_proxy_has,
45259
    .get_property = js_proxy_get,
45260
    .set_property = js_proxy_set,
45261
};
45262
45263
static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val,
45264
                                    int argc, JSValueConst *argv)
45265
0
{
45266
0
    JSValueConst target, handler;
45267
0
    JSValue obj;
45268
0
    JSProxyData *s;
45269
45270
0
    target = argv[0];
45271
0
    handler = argv[1];
45272
0
    if (JS_VALUE_GET_TAG(target) != JS_TAG_OBJECT ||
45273
0
        JS_VALUE_GET_TAG(handler) != JS_TAG_OBJECT)
45274
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45275
45276
0
    obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_PROXY);
45277
0
    if (JS_IsException(obj))
45278
0
        return obj;
45279
0
    s = js_malloc(ctx, sizeof(JSProxyData));
45280
0
    if (!s) {
45281
0
        JS_FreeValue(ctx, obj);
45282
0
        return JS_EXCEPTION;
45283
0
    }
45284
0
    s->target = JS_DupValue(ctx, target);
45285
0
    s->handler = JS_DupValue(ctx, handler);
45286
0
    s->is_func = JS_IsFunction(ctx, target);
45287
0
    s->is_revoked = FALSE;
45288
0
    JS_SetOpaque(obj, s);
45289
0
    JS_SetConstructorBit(ctx, obj, JS_IsConstructor(ctx, target));
45290
0
    return obj;
45291
0
}
45292
45293
static JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val,
45294
                               int argc, JSValueConst *argv, int magic,
45295
                               JSValue *func_data)
45296
0
{
45297
0
    JSProxyData *s = JS_GetOpaque(func_data[0], JS_CLASS_PROXY);
45298
0
    if (s) {
45299
        /* We do not free the handler and target in case they are
45300
           referenced as constants in the C call stack */
45301
0
        s->is_revoked = TRUE;
45302
0
        JS_FreeValue(ctx, func_data[0]);
45303
0
        func_data[0] = JS_NULL;
45304
0
    }
45305
0
    return JS_UNDEFINED;
45306
0
}
45307
45308
static JSValue js_proxy_revoke_constructor(JSContext *ctx,
45309
                                           JSValueConst proxy_obj)
45310
0
{
45311
0
    return JS_NewCFunctionData(ctx, js_proxy_revoke, 0, 0, 1, &proxy_obj);
45312
0
}
45313
45314
static JSValue js_proxy_revocable(JSContext *ctx, JSValueConst this_val,
45315
                                 int argc, JSValueConst *argv)
45316
0
{
45317
0
    JSValue proxy_obj, revoke_obj = JS_UNDEFINED, obj;
45318
45319
0
    proxy_obj = js_proxy_constructor(ctx, JS_UNDEFINED, argc, argv);
45320
0
    if (JS_IsException(proxy_obj))
45321
0
        goto fail;
45322
0
    revoke_obj = js_proxy_revoke_constructor(ctx, proxy_obj);
45323
0
    if (JS_IsException(revoke_obj))
45324
0
        goto fail;
45325
0
    obj = JS_NewObject(ctx);
45326
0
    if (JS_IsException(obj))
45327
0
        goto fail;
45328
    // XXX: exceptions?
45329
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_proxy, proxy_obj, JS_PROP_C_W_E);
45330
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_revoke, revoke_obj, JS_PROP_C_W_E);
45331
0
    return obj;
45332
0
 fail:
45333
0
    JS_FreeValue(ctx, proxy_obj);
45334
0
    JS_FreeValue(ctx, revoke_obj);
45335
0
    return JS_EXCEPTION;
45336
0
}
45337
45338
static const JSCFunctionListEntry js_proxy_funcs[] = {
45339
    JS_CFUNC_DEF("revocable", 2, js_proxy_revocable ),
45340
};
45341
45342
static const JSClassShortDef js_proxy_class_def[] = {
45343
    { JS_ATOM_Object, js_proxy_finalizer, js_proxy_mark }, /* JS_CLASS_PROXY */
45344
};
45345
45346
void JS_AddIntrinsicProxy(JSContext *ctx)
45347
2
{
45348
2
    JSRuntime *rt = ctx->rt;
45349
2
    JSValue obj1;
45350
45351
2
    if (!JS_IsRegisteredClass(rt, JS_CLASS_PROXY)) {
45352
2
        init_class_range(rt, js_proxy_class_def, JS_CLASS_PROXY,
45353
2
                         countof(js_proxy_class_def));
45354
2
        rt->class_array[JS_CLASS_PROXY].exotic = &js_proxy_exotic_methods;
45355
2
        rt->class_array[JS_CLASS_PROXY].call = js_proxy_call;
45356
2
    }
45357
45358
2
    obj1 = JS_NewCFunction2(ctx, js_proxy_constructor, "Proxy", 2,
45359
2
                            JS_CFUNC_constructor, 0);
45360
2
    JS_SetConstructorBit(ctx, obj1, TRUE);
45361
2
    JS_SetPropertyFunctionList(ctx, obj1, js_proxy_funcs,
45362
2
                               countof(js_proxy_funcs));
45363
2
    JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Proxy",
45364
2
                              obj1, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
45365
2
}
45366
45367
/* Symbol */
45368
45369
static JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target,
45370
                                     int argc, JSValueConst *argv)
45371
0
{
45372
0
    JSValue str;
45373
0
    JSString *p;
45374
45375
0
    if (!JS_IsUndefined(new_target))
45376
0
        return JS_ThrowTypeError(ctx, "not a constructor");
45377
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
45378
0
        p = NULL;
45379
0
    } else {
45380
0
        str = JS_ToString(ctx, argv[0]);
45381
0
        if (JS_IsException(str))
45382
0
            return JS_EXCEPTION;
45383
0
        p = JS_VALUE_GET_STRING(str);
45384
0
    }
45385
0
    return JS_NewSymbol(ctx, p, JS_ATOM_TYPE_SYMBOL);
45386
0
}
45387
45388
static JSValue js_thisSymbolValue(JSContext *ctx, JSValueConst this_val)
45389
0
{
45390
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_SYMBOL)
45391
0
        return JS_DupValue(ctx, this_val);
45392
45393
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
45394
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
45395
0
        if (p->class_id == JS_CLASS_SYMBOL) {
45396
0
            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_SYMBOL)
45397
0
                return JS_DupValue(ctx, p->u.object_data);
45398
0
        }
45399
0
    }
45400
0
    return JS_ThrowTypeError(ctx, "not a symbol");
45401
0
}
45402
45403
static JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val,
45404
                                  int argc, JSValueConst *argv)
45405
0
{
45406
0
    JSValue val, ret;
45407
0
    val = js_thisSymbolValue(ctx, this_val);
45408
0
    if (JS_IsException(val))
45409
0
        return val;
45410
    /* XXX: use JS_ToStringInternal() with a flags */
45411
0
    ret = js_string_constructor(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val);
45412
0
    JS_FreeValue(ctx, val);
45413
0
    return ret;
45414
0
}
45415
45416
static JSValue js_symbol_valueOf(JSContext *ctx, JSValueConst this_val,
45417
                                 int argc, JSValueConst *argv)
45418
0
{
45419
0
    return js_thisSymbolValue(ctx, this_val);
45420
0
}
45421
45422
static JSValue js_symbol_get_description(JSContext *ctx, JSValueConst this_val)
45423
0
{
45424
0
    JSValue val, ret;
45425
0
    JSAtomStruct *p;
45426
45427
0
    val = js_thisSymbolValue(ctx, this_val);
45428
0
    if (JS_IsException(val))
45429
0
        return val;
45430
0
    p = JS_VALUE_GET_PTR(val);
45431
0
    if (p->len == 0 && p->is_wide_char != 0) {
45432
0
        ret = JS_UNDEFINED;
45433
0
    } else {
45434
0
        ret = JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p));
45435
0
    }
45436
0
    JS_FreeValue(ctx, val);
45437
0
    return ret;
45438
0
}
45439
45440
static const JSCFunctionListEntry js_symbol_proto_funcs[] = {
45441
    JS_CFUNC_DEF("toString", 0, js_symbol_toString ),
45442
    JS_CFUNC_DEF("valueOf", 0, js_symbol_valueOf ),
45443
    // XXX: should have writable: false
45444
    JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_symbol_valueOf ),
45445
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Symbol", JS_PROP_CONFIGURABLE ),
45446
    JS_CGETSET_DEF("description", js_symbol_get_description, NULL ),
45447
};
45448
45449
static JSValue js_symbol_for(JSContext *ctx, JSValueConst this_val,
45450
                             int argc, JSValueConst *argv)
45451
0
{
45452
0
    JSValue str;
45453
45454
0
    str = JS_ToString(ctx, argv[0]);
45455
0
    if (JS_IsException(str))
45456
0
        return JS_EXCEPTION;
45457
0
    return JS_NewSymbol(ctx, JS_VALUE_GET_STRING(str), JS_ATOM_TYPE_GLOBAL_SYMBOL);
45458
0
}
45459
45460
static JSValue js_symbol_keyFor(JSContext *ctx, JSValueConst this_val,
45461
                                int argc, JSValueConst *argv)
45462
0
{
45463
0
    JSAtomStruct *p;
45464
45465
0
    if (!JS_IsSymbol(argv[0]))
45466
0
        return JS_ThrowTypeError(ctx, "not a symbol");
45467
0
    p = JS_VALUE_GET_PTR(argv[0]);
45468
0
    if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL)
45469
0
        return JS_UNDEFINED;
45470
0
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
45471
0
}
45472
45473
static const JSCFunctionListEntry js_symbol_funcs[] = {
45474
    JS_CFUNC_DEF("for", 1, js_symbol_for ),
45475
    JS_CFUNC_DEF("keyFor", 1, js_symbol_keyFor ),
45476
};
45477
45478
/* Set/Map/WeakSet/WeakMap */
45479
45480
typedef struct JSMapRecord {
45481
    int ref_count; /* used during enumeration to avoid freeing the record */
45482
    BOOL empty; /* TRUE if the record is deleted */
45483
    struct JSMapState *map;
45484
    struct JSMapRecord *next_weak_ref;
45485
    struct list_head link;
45486
    struct list_head hash_link;
45487
    JSValue key;
45488
    JSValue value;
45489
} JSMapRecord;
45490
45491
typedef struct JSMapState {
45492
    BOOL is_weak; /* TRUE if WeakSet/WeakMap */
45493
    struct list_head records; /* list of JSMapRecord.link */
45494
    uint32_t record_count;
45495
    struct list_head *hash_table;
45496
    uint32_t hash_size; /* must be a power of two */
45497
    uint32_t record_count_threshold; /* count at which a hash table
45498
                                        resize is needed */
45499
} JSMapState;
45500
45501
0
#define MAGIC_SET (1 << 0)
45502
0
#define MAGIC_WEAK (1 << 1)
45503
45504
static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
45505
                                  int argc, JSValueConst *argv, int magic)
45506
0
{
45507
0
    JSMapState *s;
45508
0
    JSValue obj, adder = JS_UNDEFINED, iter = JS_UNDEFINED, next_method = JS_UNDEFINED;
45509
0
    JSValueConst arr;
45510
0
    BOOL is_set, is_weak;
45511
45512
0
    is_set = magic & MAGIC_SET;
45513
0
    is_weak = ((magic & MAGIC_WEAK) != 0);
45514
0
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_MAP + magic);
45515
0
    if (JS_IsException(obj))
45516
0
        return JS_EXCEPTION;
45517
0
    s = js_mallocz(ctx, sizeof(*s));
45518
0
    if (!s)
45519
0
        goto fail;
45520
0
    init_list_head(&s->records);
45521
0
    s->is_weak = is_weak;
45522
0
    JS_SetOpaque(obj, s);
45523
0
    s->hash_size = 1;
45524
0
    s->hash_table = js_malloc(ctx, sizeof(s->hash_table[0]) * s->hash_size);
45525
0
    if (!s->hash_table)
45526
0
        goto fail;
45527
0
    init_list_head(&s->hash_table[0]);
45528
0
    s->record_count_threshold = 4;
45529
45530
0
    arr = JS_UNDEFINED;
45531
0
    if (argc > 0)
45532
0
        arr = argv[0];
45533
0
    if (!JS_IsUndefined(arr) && !JS_IsNull(arr)) {
45534
0
        JSValue item, ret;
45535
0
        BOOL done;
45536
45537
0
        adder = JS_GetProperty(ctx, obj, is_set ? JS_ATOM_add : JS_ATOM_set);
45538
0
        if (JS_IsException(adder))
45539
0
            goto fail;
45540
0
        if (!JS_IsFunction(ctx, adder)) {
45541
0
            JS_ThrowTypeError(ctx, "set/add is not a function");
45542
0
            goto fail;
45543
0
        }
45544
45545
0
        iter = JS_GetIterator(ctx, arr, FALSE);
45546
0
        if (JS_IsException(iter))
45547
0
            goto fail;
45548
0
        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
45549
0
        if (JS_IsException(next_method))
45550
0
            goto fail;
45551
45552
0
        for(;;) {
45553
0
            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
45554
0
            if (JS_IsException(item))
45555
0
                goto fail;
45556
0
            if (done) {
45557
0
                JS_FreeValue(ctx, item);
45558
0
                break;
45559
0
            }
45560
0
            if (is_set) {
45561
0
                ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item);
45562
0
                if (JS_IsException(ret)) {
45563
0
                    JS_FreeValue(ctx, item);
45564
0
                    goto fail;
45565
0
                }
45566
0
            } else {
45567
0
                JSValue key, value;
45568
0
                JSValueConst args[2];
45569
0
                key = JS_UNDEFINED;
45570
0
                value = JS_UNDEFINED;
45571
0
                if (!JS_IsObject(item)) {
45572
0
                    JS_ThrowTypeErrorNotAnObject(ctx);
45573
0
                    goto fail1;
45574
0
                }
45575
0
                key = JS_GetPropertyUint32(ctx, item, 0);
45576
0
                if (JS_IsException(key))
45577
0
                    goto fail1;
45578
0
                value = JS_GetPropertyUint32(ctx, item, 1);
45579
0
                if (JS_IsException(value))
45580
0
                    goto fail1;
45581
0
                args[0] = key;
45582
0
                args[1] = value;
45583
0
                ret = JS_Call(ctx, adder, obj, 2, args);
45584
0
                if (JS_IsException(ret)) {
45585
0
                fail1:
45586
0
                    JS_FreeValue(ctx, item);
45587
0
                    JS_FreeValue(ctx, key);
45588
0
                    JS_FreeValue(ctx, value);
45589
0
                    goto fail;
45590
0
                }
45591
0
                JS_FreeValue(ctx, key);
45592
0
                JS_FreeValue(ctx, value);
45593
0
            }
45594
0
            JS_FreeValue(ctx, ret);
45595
0
            JS_FreeValue(ctx, item);
45596
0
        }
45597
0
        JS_FreeValue(ctx, next_method);
45598
0
        JS_FreeValue(ctx, iter);
45599
0
        JS_FreeValue(ctx, adder);
45600
0
    }
45601
0
    return obj;
45602
0
 fail:
45603
0
    if (JS_IsObject(iter)) {
45604
        /* close the iterator object, preserving pending exception */
45605
0
        JS_IteratorClose(ctx, iter, TRUE);
45606
0
    }
45607
0
    JS_FreeValue(ctx, next_method);
45608
0
    JS_FreeValue(ctx, iter);
45609
0
    JS_FreeValue(ctx, adder);
45610
0
    JS_FreeValue(ctx, obj);
45611
0
    return JS_EXCEPTION;
45612
0
}
45613
45614
/* XXX: could normalize strings to speed up comparison */
45615
static JSValueConst map_normalize_key(JSContext *ctx, JSValueConst key)
45616
0
{
45617
0
    uint32_t tag = JS_VALUE_GET_TAG(key);
45618
    /* convert -0.0 to +0.0 */
45619
0
    if (JS_TAG_IS_FLOAT64(tag) && JS_VALUE_GET_FLOAT64(key) == 0.0) {
45620
0
        key = JS_NewInt32(ctx, 0);
45621
0
    }
45622
0
    return key;
45623
0
}
45624
45625
/* XXX: better hash ? */
45626
static uint32_t map_hash_key(JSContext *ctx, JSValueConst key)
45627
0
{
45628
0
    uint32_t tag = JS_VALUE_GET_NORM_TAG(key);
45629
0
    uint32_t h;
45630
0
    double d;
45631
0
    JSFloat64Union u;
45632
45633
0
    switch(tag) {
45634
0
    case JS_TAG_BOOL:
45635
0
        h = JS_VALUE_GET_INT(key);
45636
0
        break;
45637
0
    case JS_TAG_STRING:
45638
0
        h = hash_string(JS_VALUE_GET_STRING(key), 0);
45639
0
        break;
45640
0
    case JS_TAG_OBJECT:
45641
0
    case JS_TAG_SYMBOL:
45642
0
        h = (uintptr_t)JS_VALUE_GET_PTR(key) * 3163;
45643
0
        break;
45644
0
    case JS_TAG_INT:
45645
0
        d = JS_VALUE_GET_INT(key) * 3163;
45646
0
        goto hash_float64;
45647
0
    case JS_TAG_FLOAT64:
45648
0
        d = JS_VALUE_GET_FLOAT64(key);
45649
        /* normalize the NaN */
45650
0
        if (isnan(d))
45651
0
            d = JS_FLOAT64_NAN;
45652
0
    hash_float64:
45653
0
        u.d = d;
45654
0
        h = (u.u32[0] ^ u.u32[1]) * 3163;
45655
0
        break;
45656
0
    default:
45657
0
        h = 0; /* XXX: bignum support */
45658
0
        break;
45659
0
    }
45660
0
    h ^= tag;
45661
0
    return h;
45662
0
}
45663
45664
static JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s,
45665
                                    JSValueConst key)
45666
0
{
45667
0
    struct list_head *el;
45668
0
    JSMapRecord *mr;
45669
0
    uint32_t h;
45670
0
    h = map_hash_key(ctx, key) & (s->hash_size - 1);
45671
0
    list_for_each(el, &s->hash_table[h]) {
45672
0
        mr = list_entry(el, JSMapRecord, hash_link);
45673
0
        if (js_same_value_zero(ctx, mr->key, key))
45674
0
            return mr;
45675
0
    }
45676
0
    return NULL;
45677
0
}
45678
45679
static void map_hash_resize(JSContext *ctx, JSMapState *s)
45680
0
{
45681
0
    uint32_t new_hash_size, i, h;
45682
0
    size_t slack;
45683
0
    struct list_head *new_hash_table, *el;
45684
0
    JSMapRecord *mr;
45685
45686
    /* XXX: no reporting of memory allocation failure */
45687
0
    if (s->hash_size == 1)
45688
0
        new_hash_size = 4;
45689
0
    else
45690
0
        new_hash_size = s->hash_size * 2;
45691
0
    new_hash_table = js_realloc2(ctx, s->hash_table,
45692
0
                                 sizeof(new_hash_table[0]) * new_hash_size, &slack);
45693
0
    if (!new_hash_table)
45694
0
        return;
45695
0
    new_hash_size += slack / sizeof(*new_hash_table);
45696
45697
0
    for(i = 0; i < new_hash_size; i++)
45698
0
        init_list_head(&new_hash_table[i]);
45699
45700
0
    list_for_each(el, &s->records) {
45701
0
        mr = list_entry(el, JSMapRecord, link);
45702
0
        if (!mr->empty) {
45703
0
            h = map_hash_key(ctx, mr->key) & (new_hash_size - 1);
45704
0
            list_add_tail(&mr->hash_link, &new_hash_table[h]);
45705
0
        }
45706
0
    }
45707
0
    s->hash_table = new_hash_table;
45708
0
    s->hash_size = new_hash_size;
45709
0
    s->record_count_threshold = new_hash_size * 2;
45710
0
}
45711
45712
static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
45713
                                   JSValueConst key)
45714
0
{
45715
0
    uint32_t h;
45716
0
    JSMapRecord *mr;
45717
45718
0
    mr = js_malloc(ctx, sizeof(*mr));
45719
0
    if (!mr)
45720
0
        return NULL;
45721
0
    mr->ref_count = 1;
45722
0
    mr->map = s;
45723
0
    mr->empty = FALSE;
45724
0
    if (s->is_weak) {
45725
0
        JSObject *p = JS_VALUE_GET_OBJ(key);
45726
        /* Add the weak reference */
45727
0
        mr->next_weak_ref = p->first_weak_ref;
45728
0
        p->first_weak_ref = mr;
45729
0
    } else {
45730
0
        JS_DupValue(ctx, key);
45731
0
    }
45732
0
    mr->key = (JSValue)key;
45733
0
    h = map_hash_key(ctx, key) & (s->hash_size - 1);
45734
0
    list_add_tail(&mr->hash_link, &s->hash_table[h]);
45735
0
    list_add_tail(&mr->link, &s->records);
45736
0
    s->record_count++;
45737
0
    if (s->record_count >= s->record_count_threshold) {
45738
0
        map_hash_resize(ctx, s);
45739
0
    }
45740
0
    return mr;
45741
0
}
45742
45743
/* Remove the weak reference from the object weak
45744
   reference list. we don't use a doubly linked list to
45745
   save space, assuming a given object has few weak
45746
       references to it */
45747
static void delete_weak_ref(JSRuntime *rt, JSMapRecord *mr)
45748
0
{
45749
0
    JSMapRecord **pmr, *mr1;
45750
0
    JSObject *p;
45751
45752
0
    p = JS_VALUE_GET_OBJ(mr->key);
45753
0
    pmr = &p->first_weak_ref;
45754
0
    for(;;) {
45755
0
        mr1 = *pmr;
45756
0
        assert(mr1 != NULL);
45757
0
        if (mr1 == mr)
45758
0
            break;
45759
0
        pmr = &mr1->next_weak_ref;
45760
0
    }
45761
0
    *pmr = mr1->next_weak_ref;
45762
0
}
45763
45764
static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr)
45765
0
{
45766
0
    if (mr->empty)
45767
0
        return;
45768
0
    list_del(&mr->hash_link);
45769
0
    if (s->is_weak) {
45770
0
        delete_weak_ref(rt, mr);
45771
0
    } else {
45772
0
        JS_FreeValueRT(rt, mr->key);
45773
0
    }
45774
0
    JS_FreeValueRT(rt, mr->value);
45775
0
    if (--mr->ref_count == 0) {
45776
0
        list_del(&mr->link);
45777
0
        js_free_rt(rt, mr);
45778
0
    } else {
45779
        /* keep a zombie record for iterators */
45780
0
        mr->empty = TRUE;
45781
0
        mr->key = JS_UNDEFINED;
45782
0
        mr->value = JS_UNDEFINED;
45783
0
    }
45784
0
    s->record_count--;
45785
0
}
45786
45787
static void map_decref_record(JSRuntime *rt, JSMapRecord *mr)
45788
0
{
45789
0
    if (--mr->ref_count == 0) {
45790
        /* the record can be safely removed */
45791
0
        assert(mr->empty);
45792
0
        list_del(&mr->link);
45793
0
        js_free_rt(rt, mr);
45794
0
    }
45795
0
}
45796
45797
static void reset_weak_ref(JSRuntime *rt, JSObject *p)
45798
0
{
45799
0
    JSMapRecord *mr, *mr_next;
45800
0
    JSMapState *s;
45801
    
45802
    /* first pass to remove the records from the WeakMap/WeakSet
45803
       lists */
45804
0
    for(mr = p->first_weak_ref; mr != NULL; mr = mr->next_weak_ref) {
45805
0
        s = mr->map;
45806
0
        assert(s->is_weak);
45807
0
        assert(!mr->empty); /* no iterator on WeakMap/WeakSet */
45808
0
        list_del(&mr->hash_link);
45809
0
        list_del(&mr->link);
45810
0
    }
45811
    
45812
    /* second pass to free the values to avoid modifying the weak
45813
       reference list while traversing it. */
45814
0
    for(mr = p->first_weak_ref; mr != NULL; mr = mr_next) {
45815
0
        mr_next = mr->next_weak_ref;
45816
0
        JS_FreeValueRT(rt, mr->value);
45817
0
        js_free_rt(rt, mr);
45818
0
    }
45819
45820
0
    p->first_weak_ref = NULL; /* fail safe */
45821
0
}
45822
45823
static JSValue js_map_set(JSContext *ctx, JSValueConst this_val,
45824
                          int argc, JSValueConst *argv, int magic)
45825
0
{
45826
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45827
0
    JSMapRecord *mr;
45828
0
    JSValueConst key, value;
45829
45830
0
    if (!s)
45831
0
        return JS_EXCEPTION;
45832
0
    key = map_normalize_key(ctx, argv[0]);
45833
0
    if (s->is_weak && !JS_IsObject(key))
45834
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45835
0
    if (magic & MAGIC_SET)
45836
0
        value = JS_UNDEFINED;
45837
0
    else
45838
0
        value = argv[1];
45839
0
    mr = map_find_record(ctx, s, key);
45840
0
    if (mr) {
45841
0
        JS_FreeValue(ctx, mr->value);
45842
0
    } else {
45843
0
        mr = map_add_record(ctx, s, key);
45844
0
        if (!mr)
45845
0
            return JS_EXCEPTION;
45846
0
    }
45847
0
    mr->value = JS_DupValue(ctx, value);
45848
0
    return JS_DupValue(ctx, this_val);
45849
0
}
45850
45851
static JSValue js_map_get(JSContext *ctx, JSValueConst this_val,
45852
                          int argc, JSValueConst *argv, int magic)
45853
0
{
45854
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45855
0
    JSMapRecord *mr;
45856
0
    JSValueConst key;
45857
45858
0
    if (!s)
45859
0
        return JS_EXCEPTION;
45860
0
    key = map_normalize_key(ctx, argv[0]);
45861
0
    mr = map_find_record(ctx, s, key);
45862
0
    if (!mr)
45863
0
        return JS_UNDEFINED;
45864
0
    else
45865
0
        return JS_DupValue(ctx, mr->value);
45866
0
}
45867
45868
static JSValue js_map_has(JSContext *ctx, JSValueConst this_val,
45869
                          int argc, JSValueConst *argv, int magic)
45870
0
{
45871
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45872
0
    JSMapRecord *mr;
45873
0
    JSValueConst key;
45874
45875
0
    if (!s)
45876
0
        return JS_EXCEPTION;
45877
0
    key = map_normalize_key(ctx, argv[0]);
45878
0
    mr = map_find_record(ctx, s, key);
45879
0
    return JS_NewBool(ctx, (mr != NULL));
45880
0
}
45881
45882
static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val,
45883
                             int argc, JSValueConst *argv, int magic)
45884
0
{
45885
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45886
0
    JSMapRecord *mr;
45887
0
    JSValueConst key;
45888
45889
0
    if (!s)
45890
0
        return JS_EXCEPTION;
45891
0
    key = map_normalize_key(ctx, argv[0]);
45892
0
    mr = map_find_record(ctx, s, key);
45893
0
    if (!mr)
45894
0
        return JS_FALSE;
45895
0
    map_delete_record(ctx->rt, s, mr);
45896
0
    return JS_TRUE;
45897
0
}
45898
45899
static JSValue js_map_clear(JSContext *ctx, JSValueConst this_val,
45900
                            int argc, JSValueConst *argv, int magic)
45901
0
{
45902
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45903
0
    struct list_head *el, *el1;
45904
0
    JSMapRecord *mr;
45905
45906
0
    if (!s)
45907
0
        return JS_EXCEPTION;
45908
0
    list_for_each_safe(el, el1, &s->records) {
45909
0
        mr = list_entry(el, JSMapRecord, link);
45910
0
        map_delete_record(ctx->rt, s, mr);
45911
0
    }
45912
0
    return JS_UNDEFINED;
45913
0
}
45914
45915
static JSValue js_map_get_size(JSContext *ctx, JSValueConst this_val, int magic)
45916
0
{
45917
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45918
0
    if (!s)
45919
0
        return JS_EXCEPTION;
45920
0
    return JS_NewUint32(ctx, s->record_count);
45921
0
}
45922
45923
static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,
45924
                              int argc, JSValueConst *argv, int magic)
45925
0
{
45926
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45927
0
    JSValueConst func, this_arg;
45928
0
    JSValue ret, args[3];
45929
0
    struct list_head *el;
45930
0
    JSMapRecord *mr;
45931
45932
0
    if (!s)
45933
0
        return JS_EXCEPTION;
45934
0
    func = argv[0];
45935
0
    if (argc > 1)
45936
0
        this_arg = argv[1];
45937
0
    else
45938
0
        this_arg = JS_UNDEFINED;
45939
0
    if (check_function(ctx, func))
45940
0
        return JS_EXCEPTION;
45941
    /* Note: the list can be modified while traversing it, but the
45942
       current element is locked */
45943
0
    el = s->records.next;
45944
0
    while (el != &s->records) {
45945
0
        mr = list_entry(el, JSMapRecord, link);
45946
0
        if (!mr->empty) {
45947
0
            mr->ref_count++;
45948
            /* must duplicate in case the record is deleted */
45949
0
            args[1] = JS_DupValue(ctx, mr->key);
45950
0
            if (magic)
45951
0
                args[0] = args[1];
45952
0
            else
45953
0
                args[0] = JS_DupValue(ctx, mr->value);
45954
0
            args[2] = (JSValue)this_val;
45955
0
            ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args);
45956
0
            JS_FreeValue(ctx, args[0]);
45957
0
            if (!magic)
45958
0
                JS_FreeValue(ctx, args[1]);
45959
0
            el = el->next;
45960
0
            map_decref_record(ctx->rt, mr);
45961
0
            if (JS_IsException(ret))
45962
0
                return ret;
45963
0
            JS_FreeValue(ctx, ret);
45964
0
        } else {
45965
0
            el = el->next;
45966
0
        }
45967
0
    }
45968
0
    return JS_UNDEFINED;
45969
0
}
45970
45971
static void js_map_finalizer(JSRuntime *rt, JSValue val)
45972
0
{
45973
0
    JSObject *p;
45974
0
    JSMapState *s;
45975
0
    struct list_head *el, *el1;
45976
0
    JSMapRecord *mr;
45977
45978
0
    p = JS_VALUE_GET_OBJ(val);
45979
0
    s = p->u.map_state;
45980
0
    if (s) {
45981
        /* if the object is deleted we are sure that no iterator is
45982
           using it */
45983
0
        list_for_each_safe(el, el1, &s->records) {
45984
0
            mr = list_entry(el, JSMapRecord, link);
45985
0
            if (!mr->empty) {
45986
0
                if (s->is_weak)
45987
0
                    delete_weak_ref(rt, mr);
45988
0
                else
45989
0
                    JS_FreeValueRT(rt, mr->key);
45990
0
                JS_FreeValueRT(rt, mr->value);
45991
0
            }
45992
0
            js_free_rt(rt, mr);
45993
0
        }
45994
0
        js_free_rt(rt, s->hash_table);
45995
0
        js_free_rt(rt, s);
45996
0
    }
45997
0
}
45998
45999
static void js_map_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
46000
0
{
46001
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
46002
0
    JSMapState *s;
46003
0
    struct list_head *el;
46004
0
    JSMapRecord *mr;
46005
46006
0
    s = p->u.map_state;
46007
0
    if (s) {
46008
0
        list_for_each(el, &s->records) {
46009
0
            mr = list_entry(el, JSMapRecord, link);
46010
0
            if (!s->is_weak)
46011
0
                JS_MarkValue(rt, mr->key, mark_func);
46012
0
            JS_MarkValue(rt, mr->value, mark_func);
46013
0
        }
46014
0
    }
46015
0
}
46016
46017
/* Map Iterator */
46018
46019
typedef struct JSMapIteratorData {
46020
    JSValue obj;
46021
    JSIteratorKindEnum kind;
46022
    JSMapRecord *cur_record;
46023
} JSMapIteratorData;
46024
46025
static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val)
46026
0
{
46027
0
    JSObject *p;
46028
0
    JSMapIteratorData *it;
46029
46030
0
    p = JS_VALUE_GET_OBJ(val);
46031
0
    it = p->u.map_iterator_data;
46032
0
    if (it) {
46033
        /* During the GC sweep phase the Map finalizer may be
46034
           called before the Map iterator finalizer */
46035
0
        if (JS_IsLiveObject(rt, it->obj) && it->cur_record) {
46036
0
            map_decref_record(rt, it->cur_record);
46037
0
        }
46038
0
        JS_FreeValueRT(rt, it->obj);
46039
0
        js_free_rt(rt, it);
46040
0
    }
46041
0
}
46042
46043
static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
46044
                                 JS_MarkFunc *mark_func)
46045
0
{
46046
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
46047
0
    JSMapIteratorData *it;
46048
0
    it = p->u.map_iterator_data;
46049
0
    if (it) {
46050
        /* the record is already marked by the object */
46051
0
        JS_MarkValue(rt, it->obj, mark_func);
46052
0
    }
46053
0
}
46054
46055
static JSValue js_create_map_iterator(JSContext *ctx, JSValueConst this_val,
46056
                                      int argc, JSValueConst *argv, int magic)
46057
0
{
46058
0
    JSIteratorKindEnum kind;
46059
0
    JSMapState *s;
46060
0
    JSMapIteratorData *it;
46061
0
    JSValue enum_obj;
46062
46063
0
    kind = magic >> 2;
46064
0
    magic &= 3;
46065
0
    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
46066
0
    if (!s)
46067
0
        return JS_EXCEPTION;
46068
0
    enum_obj = JS_NewObjectClass(ctx, JS_CLASS_MAP_ITERATOR + magic);
46069
0
    if (JS_IsException(enum_obj))
46070
0
        goto fail;
46071
0
    it = js_malloc(ctx, sizeof(*it));
46072
0
    if (!it) {
46073
0
        JS_FreeValue(ctx, enum_obj);
46074
0
        goto fail;
46075
0
    }
46076
0
    it->obj = JS_DupValue(ctx, this_val);
46077
0
    it->kind = kind;
46078
0
    it->cur_record = NULL;
46079
0
    JS_SetOpaque(enum_obj, it);
46080
0
    return enum_obj;
46081
0
 fail:
46082
0
    return JS_EXCEPTION;
46083
0
}
46084
46085
static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val,
46086
                                    int argc, JSValueConst *argv,
46087
                                    BOOL *pdone, int magic)
46088
0
{
46089
0
    JSMapIteratorData *it;
46090
0
    JSMapState *s;
46091
0
    JSMapRecord *mr;
46092
0
    struct list_head *el;
46093
46094
0
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP_ITERATOR + magic);
46095
0
    if (!it) {
46096
0
        *pdone = FALSE;
46097
0
        return JS_EXCEPTION;
46098
0
    }
46099
0
    if (JS_IsUndefined(it->obj))
46100
0
        goto done;
46101
0
    s = JS_GetOpaque(it->obj, JS_CLASS_MAP + magic);
46102
0
    assert(s != NULL);
46103
0
    if (!it->cur_record) {
46104
0
        el = s->records.next;
46105
0
    } else {
46106
0
        mr = it->cur_record;
46107
0
        el = mr->link.next;
46108
0
        map_decref_record(ctx->rt, mr); /* the record can be freed here */
46109
0
    }
46110
0
    for(;;) {
46111
0
        if (el == &s->records) {
46112
            /* no more record  */
46113
0
            it->cur_record = NULL;
46114
0
            JS_FreeValue(ctx, it->obj);
46115
0
            it->obj = JS_UNDEFINED;
46116
0
        done:
46117
            /* end of enumeration */
46118
0
            *pdone = TRUE;
46119
0
            return JS_UNDEFINED;
46120
0
        }
46121
0
        mr = list_entry(el, JSMapRecord, link);
46122
0
        if (!mr->empty)
46123
0
            break;
46124
        /* get the next record */
46125
0
        el = mr->link.next;
46126
0
    }
46127
46128
    /* lock the record so that it won't be freed */
46129
0
    mr->ref_count++;
46130
0
    it->cur_record = mr;
46131
0
    *pdone = FALSE;
46132
46133
0
    if (it->kind == JS_ITERATOR_KIND_KEY) {
46134
0
        return JS_DupValue(ctx, mr->key);
46135
0
    } else {
46136
0
        JSValueConst args[2];
46137
0
        args[0] = mr->key;
46138
0
        if (magic)
46139
0
            args[1] = mr->key;
46140
0
        else
46141
0
            args[1] = mr->value;
46142
0
        if (it->kind == JS_ITERATOR_KIND_VALUE) {
46143
0
            return JS_DupValue(ctx, args[1]);
46144
0
        } else {
46145
0
            return js_create_array(ctx, 2, args);
46146
0
        }
46147
0
    }
46148
0
}
46149
46150
static const JSCFunctionListEntry js_map_funcs[] = {
46151
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
46152
};
46153
46154
static const JSCFunctionListEntry js_map_proto_funcs[] = {
46155
    JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, 0 ),
46156
    JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, 0 ),
46157
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, 0 ),
46158
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, 0 ),
46159
    JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, 0 ),
46160
    JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, 0),
46161
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, 0 ),
46162
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_VALUE << 2) | 0 ),
46163
    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | 0 ),
46164
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | 0 ),
46165
    JS_ALIAS_DEF("[Symbol.iterator]", "entries" ),
46166
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map", JS_PROP_CONFIGURABLE ),
46167
};
46168
46169
static const JSCFunctionListEntry js_map_iterator_proto_funcs[] = {
46170
    JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, 0 ),
46171
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map Iterator", JS_PROP_CONFIGURABLE ),
46172
};
46173
46174
static const JSCFunctionListEntry js_set_proto_funcs[] = {
46175
    JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET ),
46176
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET ),
46177
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET ),
46178
    JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, MAGIC_SET ),
46179
    JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, MAGIC_SET ),
46180
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, MAGIC_SET ),
46181
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | MAGIC_SET ),
46182
    JS_ALIAS_DEF("keys", "values" ),
46183
    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
46184
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | MAGIC_SET ),
46185
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set", JS_PROP_CONFIGURABLE ),
46186
};
46187
46188
static const JSCFunctionListEntry js_set_iterator_proto_funcs[] = {
46189
    JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, MAGIC_SET ),
46190
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set Iterator", JS_PROP_CONFIGURABLE ),
46191
};
46192
46193
static const JSCFunctionListEntry js_weak_map_proto_funcs[] = {
46194
    JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, MAGIC_WEAK ),
46195
    JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, MAGIC_WEAK ),
46196
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_WEAK ),
46197
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_WEAK ),
46198
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakMap", JS_PROP_CONFIGURABLE ),
46199
};
46200
46201
static const JSCFunctionListEntry js_weak_set_proto_funcs[] = {
46202
    JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET | MAGIC_WEAK ),
46203
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET | MAGIC_WEAK ),
46204
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET | MAGIC_WEAK ),
46205
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakSet", JS_PROP_CONFIGURABLE ),
46206
};
46207
46208
static const JSCFunctionListEntry * const js_map_proto_funcs_ptr[6] = {
46209
    js_map_proto_funcs,
46210
    js_set_proto_funcs,
46211
    js_weak_map_proto_funcs,
46212
    js_weak_set_proto_funcs,
46213
    js_map_iterator_proto_funcs,
46214
    js_set_iterator_proto_funcs,
46215
};
46216
46217
static const uint8_t js_map_proto_funcs_count[6] = {
46218
    countof(js_map_proto_funcs),
46219
    countof(js_set_proto_funcs),
46220
    countof(js_weak_map_proto_funcs),
46221
    countof(js_weak_set_proto_funcs),
46222
    countof(js_map_iterator_proto_funcs),
46223
    countof(js_set_iterator_proto_funcs),
46224
};
46225
46226
void JS_AddIntrinsicMapSet(JSContext *ctx)
46227
2
{
46228
2
    int i;
46229
2
    JSValue obj1;
46230
2
    char buf[ATOM_GET_STR_BUF_SIZE];
46231
46232
10
    for(i = 0; i < 4; i++) {
46233
8
        const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf),
46234
8
                                         JS_ATOM_Map + i);
46235
8
        ctx->class_proto[JS_CLASS_MAP + i] = JS_NewObject(ctx);
46236
8
        JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP + i],
46237
8
                                   js_map_proto_funcs_ptr[i],
46238
8
                                   js_map_proto_funcs_count[i]);
46239
8
        obj1 = JS_NewCFunctionMagic(ctx, js_map_constructor, name, 0,
46240
8
                                    JS_CFUNC_constructor_magic, i);
46241
8
        if (i < 2) {
46242
4
            JS_SetPropertyFunctionList(ctx, obj1, js_map_funcs,
46243
4
                                       countof(js_map_funcs));
46244
4
        }
46245
8
        JS_NewGlobalCConstructor2(ctx, obj1, name, ctx->class_proto[JS_CLASS_MAP + i]);
46246
8
    }
46247
46248
6
    for(i = 0; i < 2; i++) {
46249
4
        ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] =
46250
4
            JS_NewObjectProto(ctx, ctx->iterator_proto);
46251
4
        JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP_ITERATOR + i],
46252
4
                                   js_map_proto_funcs_ptr[i + 4],
46253
4
                                   js_map_proto_funcs_count[i + 4]);
46254
4
    }
46255
2
}
46256
46257
/* Generator */
46258
static const JSCFunctionListEntry js_generator_function_proto_funcs[] = {
46259
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "GeneratorFunction", JS_PROP_CONFIGURABLE),
46260
};
46261
46262
static const JSCFunctionListEntry js_generator_proto_funcs[] = {
46263
    JS_ITERATOR_NEXT_DEF("next", 1, js_generator_next, GEN_MAGIC_NEXT ),
46264
    JS_ITERATOR_NEXT_DEF("return", 1, js_generator_next, GEN_MAGIC_RETURN ),
46265
    JS_ITERATOR_NEXT_DEF("throw", 1, js_generator_next, GEN_MAGIC_THROW ),
46266
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Generator", JS_PROP_CONFIGURABLE),
46267
};
46268
46269
/* Promise */
46270
46271
typedef enum JSPromiseStateEnum {
46272
    JS_PROMISE_PENDING,
46273
    JS_PROMISE_FULFILLED,
46274
    JS_PROMISE_REJECTED,
46275
} JSPromiseStateEnum;
46276
46277
typedef struct JSPromiseData {
46278
    JSPromiseStateEnum promise_state;
46279
    /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */
46280
    struct list_head promise_reactions[2];
46281
    BOOL is_handled; /* Note: only useful to debug */
46282
    JSValue promise_result;
46283
} JSPromiseData;
46284
46285
typedef struct JSPromiseFunctionDataResolved {
46286
    int ref_count;
46287
    BOOL already_resolved;
46288
} JSPromiseFunctionDataResolved;
46289
46290
typedef struct JSPromiseFunctionData {
46291
    JSValue promise;
46292
    JSPromiseFunctionDataResolved *presolved;
46293
} JSPromiseFunctionData;
46294
46295
typedef struct JSPromiseReactionData {
46296
    struct list_head link; /* not used in promise_reaction_job */
46297
    JSValue resolving_funcs[2];
46298
    JSValue handler;
46299
} JSPromiseReactionData;
46300
46301
static int js_create_resolving_functions(JSContext *ctx, JSValue *args,
46302
                                         JSValueConst promise);
46303
46304
static void promise_reaction_data_free(JSRuntime *rt,
46305
                                       JSPromiseReactionData *rd)
46306
0
{
46307
0
    JS_FreeValueRT(rt, rd->resolving_funcs[0]);
46308
0
    JS_FreeValueRT(rt, rd->resolving_funcs[1]);
46309
0
    JS_FreeValueRT(rt, rd->handler);
46310
0
    js_free_rt(rt, rd);
46311
0
}
46312
46313
static JSValue promise_reaction_job(JSContext *ctx, int argc,
46314
                                    JSValueConst *argv)
46315
0
{
46316
0
    JSValueConst handler, arg, func;
46317
0
    JSValue res, res2;
46318
0
    BOOL is_reject;
46319
46320
0
    assert(argc == 5);
46321
0
    handler = argv[2];
46322
0
    is_reject = JS_ToBool(ctx, argv[3]);
46323
0
    arg = argv[4];
46324
#ifdef DUMP_PROMISE
46325
    printf("promise_reaction_job: is_reject=%d\n", is_reject);
46326
#endif
46327
46328
0
    if (JS_IsUndefined(handler)) {
46329
0
        if (is_reject) {
46330
0
            res = JS_Throw(ctx, JS_DupValue(ctx, arg));
46331
0
        } else {
46332
0
            res = JS_DupValue(ctx, arg);
46333
0
        }
46334
0
    } else {
46335
0
        res = JS_Call(ctx, handler, JS_UNDEFINED, 1, &arg);
46336
0
    }
46337
0
    is_reject = JS_IsException(res);
46338
0
    if (is_reject)
46339
0
        res = JS_GetException(ctx);
46340
0
    func = argv[is_reject];
46341
    /* as an extension, we support undefined as value to avoid
46342
       creating a dummy promise in the 'await' implementation of async
46343
       functions */
46344
0
    if (!JS_IsUndefined(func)) {
46345
0
        res2 = JS_Call(ctx, func, JS_UNDEFINED,
46346
0
                       1, (JSValueConst *)&res);
46347
0
    } else {
46348
0
        res2 = JS_UNDEFINED;
46349
0
    }
46350
0
    JS_FreeValue(ctx, res);
46351
46352
0
    return res2;
46353
0
}
46354
46355
void JS_SetHostPromiseRejectionTracker(JSRuntime *rt,
46356
                                       JSHostPromiseRejectionTracker *cb,
46357
                                       void *opaque)
46358
0
{
46359
0
    rt->host_promise_rejection_tracker = cb;
46360
0
    rt->host_promise_rejection_tracker_opaque = opaque;
46361
0
}
46362
46363
static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise,
46364
                                      JSValueConst value, BOOL is_reject)
46365
109k
{
46366
109k
    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
46367
109k
    struct list_head *el, *el1;
46368
109k
    JSPromiseReactionData *rd;
46369
109k
    JSValueConst args[5];
46370
46371
109k
    if (!s || s->promise_state != JS_PROMISE_PENDING)
46372
0
        return; /* should never happen */
46373
109k
    set_value(ctx, &s->promise_result, JS_DupValue(ctx, value));
46374
109k
    s->promise_state = JS_PROMISE_FULFILLED + is_reject;
46375
#ifdef DUMP_PROMISE
46376
    printf("fulfill_or_reject_promise: is_reject=%d\n", is_reject);
46377
#endif
46378
109k
    if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
46379
109k
        JSRuntime *rt = ctx->rt;
46380
109k
        if (rt->host_promise_rejection_tracker) {
46381
0
            rt->host_promise_rejection_tracker(ctx, promise, value, FALSE,
46382
0
                                               rt->host_promise_rejection_tracker_opaque);
46383
0
        }
46384
109k
    }
46385
46386
109k
    list_for_each_safe(el, el1, &s->promise_reactions[is_reject]) {
46387
0
        rd = list_entry(el, JSPromiseReactionData, link);
46388
0
        args[0] = rd->resolving_funcs[0];
46389
0
        args[1] = rd->resolving_funcs[1];
46390
0
        args[2] = rd->handler;
46391
0
        args[3] = JS_NewBool(ctx, is_reject);
46392
0
        args[4] = value;
46393
0
        JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
46394
0
        list_del(&rd->link);
46395
0
        promise_reaction_data_free(ctx->rt, rd);
46396
0
    }
46397
46398
109k
    list_for_each_safe(el, el1, &s->promise_reactions[1 - is_reject]) {
46399
0
        rd = list_entry(el, JSPromiseReactionData, link);
46400
0
        list_del(&rd->link);
46401
0
        promise_reaction_data_free(ctx->rt, rd);
46402
0
    }
46403
109k
}
46404
46405
static void reject_promise(JSContext *ctx, JSValueConst promise,
46406
                           JSValueConst value)
46407
0
{
46408
0
    fulfill_or_reject_promise(ctx, promise, value, TRUE);
46409
0
}
46410
46411
static JSValue js_promise_resolve_thenable_job(JSContext *ctx,
46412
                                               int argc, JSValueConst *argv)
46413
0
{
46414
0
    JSValueConst promise, thenable, then;
46415
0
    JSValue args[2], res;
46416
46417
#ifdef DUMP_PROMISE
46418
    printf("js_promise_resolve_thenable_job\n");
46419
#endif
46420
0
    assert(argc == 3);
46421
0
    promise = argv[0];
46422
0
    thenable = argv[1];
46423
0
    then = argv[2];
46424
0
    if (js_create_resolving_functions(ctx, args, promise) < 0)
46425
0
        return JS_EXCEPTION;
46426
0
    res = JS_Call(ctx, then, thenable, 2, (JSValueConst *)args);
46427
0
    if (JS_IsException(res)) {
46428
0
        JSValue error = JS_GetException(ctx);
46429
0
        res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
46430
0
        JS_FreeValue(ctx, error);
46431
0
    }
46432
0
    JS_FreeValue(ctx, args[0]);
46433
0
    JS_FreeValue(ctx, args[1]);
46434
0
    return res;
46435
0
}
46436
46437
static void js_promise_resolve_function_free_resolved(JSRuntime *rt,
46438
                                                      JSPromiseFunctionDataResolved *sr)
46439
427k
{
46440
427k
    if (--sr->ref_count == 0) {
46441
109k
        js_free_rt(rt, sr);
46442
109k
    }
46443
427k
}
46444
46445
static int js_create_resolving_functions(JSContext *ctx,
46446
                                         JSValue *resolving_funcs,
46447
                                         JSValueConst promise)
46448
46449
208k
{
46450
208k
    JSValue obj;
46451
208k
    JSPromiseFunctionData *s;
46452
208k
    JSPromiseFunctionDataResolved *sr;
46453
208k
    int i, ret;
46454
46455
208k
    sr = js_malloc(ctx, sizeof(*sr));
46456
208k
    if (!sr)
46457
1
        return -1;
46458
208k
    sr->ref_count = 1;
46459
208k
    sr->already_resolved = FALSE; /* must be shared between the two functions */
46460
208k
    ret = 0;
46461
626k
    for(i = 0; i < 2; i++) {
46462
417k
        obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
46463
417k
                                     JS_CLASS_PROMISE_RESOLVE_FUNCTION + i);
46464
417k
        if (JS_IsException(obj))
46465
2
            goto fail;
46466
417k
        s = js_malloc(ctx, sizeof(*s));
46467
417k
        if (!s) {
46468
0
            JS_FreeValue(ctx, obj);
46469
2
        fail:
46470
46471
2
            if (i != 0)
46472
1
                JS_FreeValue(ctx, resolving_funcs[0]);
46473
2
            ret = -1;
46474
2
            break;
46475
0
        }
46476
417k
        sr->ref_count++;
46477
417k
        s->presolved = sr;
46478
417k
        s->promise = JS_DupValue(ctx, promise);
46479
417k
        JS_SetOpaque(obj, s);
46480
417k
        js_function_set_properties(ctx, obj, JS_ATOM_empty_string, 1);
46481
417k
        resolving_funcs[i] = obj;
46482
417k
    }
46483
208k
    js_promise_resolve_function_free_resolved(ctx->rt, sr);
46484
208k
    return ret;
46485
208k
}
46486
46487
static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val)
46488
218k
{
46489
218k
    JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
46490
218k
    if (s) {
46491
218k
        js_promise_resolve_function_free_resolved(rt, s->presolved);
46492
218k
        JS_FreeValueRT(rt, s->promise);
46493
218k
        js_free_rt(rt, s);
46494
218k
    }
46495
218k
}
46496
46497
static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
46498
                                             JS_MarkFunc *mark_func)
46499
893k
{
46500
893k
    JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
46501
893k
    if (s) {
46502
893k
        JS_MarkValue(rt, s->promise, mark_func);
46503
893k
    }
46504
893k
}
46505
46506
static JSValue js_promise_resolve_function_call(JSContext *ctx,
46507
                                                JSValueConst func_obj,
46508
                                                JSValueConst this_val,
46509
                                                int argc, JSValueConst *argv,
46510
                                                int flags)
46511
109k
{
46512
109k
    JSObject *p = JS_VALUE_GET_OBJ(func_obj);
46513
109k
    JSPromiseFunctionData *s;
46514
109k
    JSValueConst resolution, args[3];
46515
109k
    JSValue then;
46516
109k
    BOOL is_reject;
46517
46518
109k
    s = p->u.promise_function_data;
46519
109k
    if (!s || s->presolved->already_resolved)
46520
0
        return JS_UNDEFINED;
46521
109k
    s->presolved->already_resolved = TRUE;
46522
109k
    is_reject = p->class_id - JS_CLASS_PROMISE_RESOLVE_FUNCTION;
46523
109k
    if (argc > 0)
46524
109k
        resolution = argv[0];
46525
0
    else
46526
0
        resolution = JS_UNDEFINED;
46527
#ifdef DUMP_PROMISE
46528
    printf("js_promise_resolving_function_call: is_reject=%d resolution=", is_reject);
46529
    JS_DumpValue(ctx, resolution);
46530
    printf("\n");
46531
#endif
46532
109k
    if (is_reject || !JS_IsObject(resolution)) {
46533
109k
        goto done;
46534
109k
    } else if (js_same_value(ctx, resolution, s->promise)) {
46535
0
        JS_ThrowTypeError(ctx, "promise self resolution");
46536
0
        goto fail_reject;
46537
0
    }
46538
0
    then = JS_GetProperty(ctx, resolution, JS_ATOM_then);
46539
0
    if (JS_IsException(then)) {
46540
0
        JSValue error;
46541
0
    fail_reject:
46542
0
        error = JS_GetException(ctx);
46543
0
        reject_promise(ctx, s->promise, error);
46544
0
        JS_FreeValue(ctx, error);
46545
0
    } else if (!JS_IsFunction(ctx, then)) {
46546
0
        JS_FreeValue(ctx, then);
46547
109k
    done:
46548
109k
        fulfill_or_reject_promise(ctx, s->promise, resolution, is_reject);
46549
109k
    } else {
46550
0
        args[0] = s->promise;
46551
0
        args[1] = resolution;
46552
0
        args[2] = then;
46553
0
        JS_EnqueueJob(ctx, js_promise_resolve_thenable_job, 3, args);
46554
0
        JS_FreeValue(ctx, then);
46555
0
    }
46556
109k
    return JS_UNDEFINED;
46557
0
}
46558
46559
static void js_promise_finalizer(JSRuntime *rt, JSValue val)
46560
109k
{
46561
109k
    JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
46562
109k
    struct list_head *el, *el1;
46563
109k
    int i;
46564
46565
109k
    if (!s)
46566
0
        return;
46567
327k
    for(i = 0; i < 2; i++) {
46568
218k
        list_for_each_safe(el, el1, &s->promise_reactions[i]) {
46569
0
            JSPromiseReactionData *rd =
46570
0
                list_entry(el, JSPromiseReactionData, link);
46571
0
            promise_reaction_data_free(rt, rd);
46572
0
        }
46573
218k
    }
46574
109k
    JS_FreeValueRT(rt, s->promise_result);
46575
109k
    js_free_rt(rt, s);
46576
109k
}
46577
46578
static void js_promise_mark(JSRuntime *rt, JSValueConst val,
46579
                            JS_MarkFunc *mark_func)
46580
446k
{
46581
446k
    JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
46582
446k
    struct list_head *el;
46583
446k
    int i;
46584
46585
446k
    if (!s)
46586
0
        return;
46587
1.33M
    for(i = 0; i < 2; i++) {
46588
893k
        list_for_each(el, &s->promise_reactions[i]) {
46589
0
            JSPromiseReactionData *rd =
46590
0
                list_entry(el, JSPromiseReactionData, link);
46591
0
            JS_MarkValue(rt, rd->resolving_funcs[0], mark_func);
46592
0
            JS_MarkValue(rt, rd->resolving_funcs[1], mark_func);
46593
0
            JS_MarkValue(rt, rd->handler, mark_func);
46594
0
        }
46595
893k
    }
46596
446k
    JS_MarkValue(rt, s->promise_result, mark_func);
46597
446k
}
46598
46599
static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target,
46600
                                      int argc, JSValueConst *argv)
46601
208k
{
46602
208k
    JSValueConst executor;
46603
208k
    JSValue obj;
46604
208k
    JSPromiseData *s;
46605
208k
    JSValue args[2], ret;
46606
208k
    int i;
46607
46608
208k
    executor = argv[0];
46609
208k
    if (check_function(ctx, executor))
46610
0
        return JS_EXCEPTION;
46611
208k
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_PROMISE);
46612
208k
    if (JS_IsException(obj))
46613
1
        return JS_EXCEPTION;
46614
208k
    s = js_mallocz(ctx, sizeof(*s));
46615
208k
    if (!s)
46616
0
        goto fail;
46617
208k
    s->promise_state = JS_PROMISE_PENDING;
46618
208k
    s->is_handled = FALSE;
46619
626k
    for(i = 0; i < 2; i++)
46620
417k
        init_list_head(&s->promise_reactions[i]);
46621
208k
    s->promise_result = JS_UNDEFINED;
46622
208k
    JS_SetOpaque(obj, s);
46623
208k
    if (js_create_resolving_functions(ctx, args, obj))
46624
3
        goto fail;
46625
208k
    ret = JS_Call(ctx, executor, JS_UNDEFINED, 2, (JSValueConst *)args);
46626
208k
    if (JS_IsException(ret)) {
46627
0
        JSValue ret2, error;
46628
0
        error = JS_GetException(ctx);
46629
0
        ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
46630
0
        JS_FreeValue(ctx, error);
46631
0
        if (JS_IsException(ret2))
46632
0
            goto fail1;
46633
0
        JS_FreeValue(ctx, ret2);
46634
0
    }
46635
208k
    JS_FreeValue(ctx, ret);
46636
208k
    JS_FreeValue(ctx, args[0]);
46637
208k
    JS_FreeValue(ctx, args[1]);
46638
208k
    return obj;
46639
0
 fail1:
46640
0
    JS_FreeValue(ctx, args[0]);
46641
0
    JS_FreeValue(ctx, args[1]);
46642
3
 fail:
46643
3
    JS_FreeValue(ctx, obj);
46644
3
    return JS_EXCEPTION;
46645
0
}
46646
46647
static JSValue js_promise_executor(JSContext *ctx,
46648
                                   JSValueConst this_val,
46649
                                   int argc, JSValueConst *argv,
46650
                                   int magic, JSValue *func_data)
46651
208k
{
46652
208k
    int i;
46653
46654
626k
    for(i = 0; i < 2; i++) {
46655
417k
        if (!JS_IsUndefined(func_data[i]))
46656
0
            return JS_ThrowTypeError(ctx, "resolving function already set");
46657
417k
        func_data[i] = JS_DupValue(ctx, argv[i]);
46658
417k
    }
46659
208k
    return JS_UNDEFINED;
46660
208k
}
46661
46662
static JSValue js_promise_executor_new(JSContext *ctx)
46663
208k
{
46664
208k
    JSValueConst func_data[2];
46665
46666
208k
    func_data[0] = JS_UNDEFINED;
46667
208k
    func_data[1] = JS_UNDEFINED;
46668
208k
    return JS_NewCFunctionData(ctx, js_promise_executor, 2,
46669
208k
                               0, 2, func_data);
46670
208k
}
46671
46672
static JSValue js_new_promise_capability(JSContext *ctx,
46673
                                         JSValue *resolving_funcs,
46674
                                         JSValueConst ctor)
46675
208k
{
46676
208k
    JSValue executor, result_promise;
46677
208k
    JSCFunctionDataRecord *s;
46678
208k
    int i;
46679
46680
208k
    executor = js_promise_executor_new(ctx);
46681
208k
    if (JS_IsException(executor))
46682
0
        return executor;
46683
46684
208k
    if (JS_IsUndefined(ctor)) {
46685
208k
        result_promise = js_promise_constructor(ctx, ctor, 1,
46686
208k
                                                (JSValueConst *)&executor);
46687
208k
    } else {
46688
0
        result_promise = JS_CallConstructor(ctx, ctor, 1,
46689
0
                                            (JSValueConst *)&executor);
46690
0
    }
46691
208k
    if (JS_IsException(result_promise))
46692
4
        goto fail;
46693
208k
    s = JS_GetOpaque(executor, JS_CLASS_C_FUNCTION_DATA);
46694
626k
    for(i = 0; i < 2; i++) {
46695
417k
        if (check_function(ctx, s->data[i]))
46696
0
            goto fail;
46697
417k
    }
46698
626k
    for(i = 0; i < 2; i++)
46699
417k
        resolving_funcs[i] = JS_DupValue(ctx, s->data[i]);
46700
208k
    JS_FreeValue(ctx, executor);
46701
208k
    return result_promise;
46702
4
 fail:
46703
4
    JS_FreeValue(ctx, executor);
46704
4
    JS_FreeValue(ctx, result_promise);
46705
4
    return JS_EXCEPTION;
46706
208k
}
46707
46708
JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs)
46709
208k
{
46710
208k
    return js_new_promise_capability(ctx, resolving_funcs, JS_UNDEFINED);
46711
208k
}
46712
46713
static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
46714
                                  int argc, JSValueConst *argv, int magic)
46715
0
{
46716
0
    JSValue result_promise, resolving_funcs[2], ret;
46717
0
    BOOL is_reject = magic;
46718
46719
0
    if (!JS_IsObject(this_val))
46720
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
46721
0
    if (!is_reject && JS_GetOpaque(argv[0], JS_CLASS_PROMISE)) {
46722
0
        JSValue ctor;
46723
0
        BOOL is_same;
46724
0
        ctor = JS_GetProperty(ctx, argv[0], JS_ATOM_constructor);
46725
0
        if (JS_IsException(ctor))
46726
0
            return ctor;
46727
0
        is_same = js_same_value(ctx, ctor, this_val);
46728
0
        JS_FreeValue(ctx, ctor);
46729
0
        if (is_same)
46730
0
            return JS_DupValue(ctx, argv[0]);
46731
0
    }
46732
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
46733
0
    if (JS_IsException(result_promise))
46734
0
        return result_promise;
46735
0
    ret = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, argv);
46736
0
    JS_FreeValue(ctx, resolving_funcs[0]);
46737
0
    JS_FreeValue(ctx, resolving_funcs[1]);
46738
0
    if (JS_IsException(ret)) {
46739
0
        JS_FreeValue(ctx, result_promise);
46740
0
        return ret;
46741
0
    }
46742
0
    JS_FreeValue(ctx, ret);
46743
0
    return result_promise;
46744
0
}
46745
46746
#if 0
46747
static JSValue js_promise___newPromiseCapability(JSContext *ctx,
46748
                                                 JSValueConst this_val,
46749
                                                 int argc, JSValueConst *argv)
46750
{
46751
    JSValue result_promise, resolving_funcs[2], obj;
46752
    JSValueConst ctor;
46753
    ctor = argv[0];
46754
    if (!JS_IsObject(ctor))
46755
        return JS_ThrowTypeErrorNotAnObject(ctx);
46756
    result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
46757
    if (JS_IsException(result_promise))
46758
        return result_promise;
46759
    obj = JS_NewObject(ctx);
46760
    if (JS_IsException(obj)) {
46761
        JS_FreeValue(ctx, resolving_funcs[0]);
46762
        JS_FreeValue(ctx, resolving_funcs[1]);
46763
        JS_FreeValue(ctx, result_promise);
46764
        return JS_EXCEPTION;
46765
    }
46766
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_promise, result_promise, JS_PROP_C_W_E);
46767
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_resolve, resolving_funcs[0], JS_PROP_C_W_E);
46768
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1], JS_PROP_C_W_E);
46769
    return obj;
46770
}
46771
#endif
46772
46773
static __exception int remainingElementsCount_add(JSContext *ctx,
46774
                                                  JSValueConst resolve_element_env,
46775
                                                  int addend)
46776
0
{
46777
0
    JSValue val;
46778
0
    int remainingElementsCount;
46779
46780
0
    val = JS_GetPropertyUint32(ctx, resolve_element_env, 0);
46781
0
    if (JS_IsException(val))
46782
0
        return -1;
46783
0
    if (JS_ToInt32Free(ctx, &remainingElementsCount, val))
46784
0
        return -1;
46785
0
    remainingElementsCount += addend;
46786
0
    if (JS_SetPropertyUint32(ctx, resolve_element_env, 0,
46787
0
                             JS_NewInt32(ctx, remainingElementsCount)) < 0)
46788
0
        return -1;
46789
0
    return (remainingElementsCount == 0);
46790
0
}
46791
46792
#define PROMISE_MAGIC_all        0
46793
0
#define PROMISE_MAGIC_allSettled 1
46794
0
#define PROMISE_MAGIC_any        2
46795
46796
static JSValue js_promise_all_resolve_element(JSContext *ctx,
46797
                                              JSValueConst this_val,
46798
                                              int argc, JSValueConst *argv,
46799
                                              int magic,
46800
                                              JSValue *func_data)
46801
0
{
46802
0
    int resolve_type = magic & 3;
46803
0
    int is_reject = magic & 4;
46804
0
    BOOL alreadyCalled = JS_ToBool(ctx, func_data[0]);
46805
0
    JSValueConst values = func_data[2];
46806
0
    JSValueConst resolve = func_data[3];
46807
0
    JSValueConst resolve_element_env = func_data[4];
46808
0
    JSValue ret, obj;
46809
0
    int is_zero, index;
46810
    
46811
0
    if (JS_ToInt32(ctx, &index, func_data[1]))
46812
0
        return JS_EXCEPTION;
46813
0
    if (alreadyCalled)
46814
0
        return JS_UNDEFINED;
46815
0
    func_data[0] = JS_NewBool(ctx, TRUE);
46816
46817
0
    if (resolve_type == PROMISE_MAGIC_allSettled) {
46818
0
        JSValue str;
46819
        
46820
0
        obj = JS_NewObject(ctx);
46821
0
        if (JS_IsException(obj))
46822
0
            return JS_EXCEPTION;
46823
0
        str = JS_NewString(ctx, is_reject ? "rejected" : "fulfilled");
46824
0
        if (JS_IsException(str))
46825
0
            goto fail1;
46826
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_status,
46827
0
                                   str,
46828
0
                                   JS_PROP_C_W_E) < 0)
46829
0
            goto fail1;
46830
0
        if (JS_DefinePropertyValue(ctx, obj,
46831
0
                                   is_reject ? JS_ATOM_reason : JS_ATOM_value,
46832
0
                                   JS_DupValue(ctx, argv[0]),
46833
0
                                   JS_PROP_C_W_E) < 0) {
46834
0
        fail1:
46835
0
            JS_FreeValue(ctx, obj);
46836
0
            return JS_EXCEPTION;
46837
0
        }
46838
0
    } else {
46839
0
        obj = JS_DupValue(ctx, argv[0]);
46840
0
    }
46841
0
    if (JS_DefinePropertyValueUint32(ctx, values, index,
46842
0
                                     obj, JS_PROP_C_W_E) < 0)
46843
0
        return JS_EXCEPTION;
46844
    
46845
0
    is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
46846
0
    if (is_zero < 0)
46847
0
        return JS_EXCEPTION;
46848
0
    if (is_zero) {
46849
0
        if (resolve_type == PROMISE_MAGIC_any) {
46850
0
            JSValue error;
46851
0
            error = js_aggregate_error_constructor(ctx, values);
46852
0
            if (JS_IsException(error))
46853
0
                return JS_EXCEPTION;
46854
0
            ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&error);
46855
0
            JS_FreeValue(ctx, error);
46856
0
        } else {
46857
0
            ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values);
46858
0
        }
46859
0
        if (JS_IsException(ret))
46860
0
            return ret;
46861
0
        JS_FreeValue(ctx, ret);
46862
0
    }
46863
0
    return JS_UNDEFINED;
46864
0
}
46865
46866
/* magic = 0: Promise.all 1: Promise.allSettled */
46867
static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
46868
                              int argc, JSValueConst *argv, int magic)
46869
0
{
46870
0
    JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
46871
0
    JSValue next_method = JS_UNDEFINED, values = JS_UNDEFINED;
46872
0
    JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element;
46873
0
    JSValue promise_resolve = JS_UNDEFINED, iter = JS_UNDEFINED;
46874
0
    JSValueConst then_args[2], resolve_element_data[5];
46875
0
    BOOL done;
46876
0
    int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any);
46877
    
46878
0
    if (!JS_IsObject(this_val))
46879
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
46880
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
46881
0
    if (JS_IsException(result_promise))
46882
0
        return result_promise;
46883
0
    promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
46884
0
    if (JS_IsException(promise_resolve) ||
46885
0
        check_function(ctx, promise_resolve))
46886
0
        goto fail_reject;
46887
0
    iter = JS_GetIterator(ctx, argv[0], FALSE);
46888
0
    if (JS_IsException(iter)) {
46889
0
        JSValue error;
46890
0
    fail_reject:
46891
0
        error = JS_GetException(ctx);
46892
0
        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
46893
0
                       (JSValueConst *)&error);
46894
0
        JS_FreeValue(ctx, error);
46895
0
        if (JS_IsException(ret))
46896
0
            goto fail;
46897
0
        JS_FreeValue(ctx, ret);
46898
0
    } else {
46899
0
        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
46900
0
        if (JS_IsException(next_method))
46901
0
            goto fail_reject;
46902
0
        values = JS_NewArray(ctx);
46903
0
        if (JS_IsException(values))
46904
0
            goto fail_reject;
46905
0
        resolve_element_env = JS_NewArray(ctx);
46906
0
        if (JS_IsException(resolve_element_env))
46907
0
            goto fail_reject;
46908
        /* remainingElementsCount field */
46909
0
        if (JS_DefinePropertyValueUint32(ctx, resolve_element_env, 0,
46910
0
                                         JS_NewInt32(ctx, 1),
46911
0
                                         JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
46912
0
            goto fail_reject;
46913
        
46914
0
        index = 0;
46915
0
        for(;;) {
46916
            /* XXX: conformance: should close the iterator if error on 'done'
46917
               access, but not on 'value' access */
46918
0
            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
46919
0
            if (JS_IsException(item))
46920
0
                goto fail_reject;
46921
0
            if (done)
46922
0
                break;
46923
0
            next_promise = JS_Call(ctx, promise_resolve, 
46924
0
                                   this_val, 1, (JSValueConst *)&item);
46925
0
            JS_FreeValue(ctx, item);
46926
0
            if (JS_IsException(next_promise)) {
46927
0
            fail_reject1:
46928
0
                JS_IteratorClose(ctx, iter, TRUE);
46929
0
                goto fail_reject;
46930
0
            }
46931
0
            resolve_element_data[0] = JS_NewBool(ctx, FALSE);
46932
0
            resolve_element_data[1] = (JSValueConst)JS_NewInt32(ctx, index);
46933
0
            resolve_element_data[2] = values;
46934
0
            resolve_element_data[3] = resolving_funcs[is_promise_any];
46935
0
            resolve_element_data[4] = resolve_element_env;
46936
0
            resolve_element =
46937
0
                JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
46938
0
                                    magic, 5, resolve_element_data);
46939
0
            if (JS_IsException(resolve_element)) {
46940
0
                JS_FreeValue(ctx, next_promise);
46941
0
                goto fail_reject1;
46942
0
            }
46943
            
46944
0
            if (magic == PROMISE_MAGIC_allSettled) {
46945
0
                reject_element =
46946
0
                    JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
46947
0
                                        magic | 4, 5, resolve_element_data);
46948
0
                if (JS_IsException(reject_element)) {
46949
0
                    JS_FreeValue(ctx, next_promise);
46950
0
                    goto fail_reject1;
46951
0
                }
46952
0
            } else if (magic == PROMISE_MAGIC_any) {
46953
0
                if (JS_DefinePropertyValueUint32(ctx, values, index,
46954
0
                                                 JS_UNDEFINED, JS_PROP_C_W_E) < 0)
46955
0
                    goto fail_reject1;
46956
0
                reject_element = resolve_element;
46957
0
                resolve_element = JS_DupValue(ctx, resolving_funcs[0]);
46958
0
            } else {
46959
0
                reject_element = JS_DupValue(ctx, resolving_funcs[1]);
46960
0
            }
46961
46962
0
            if (remainingElementsCount_add(ctx, resolve_element_env, 1) < 0) {
46963
0
                JS_FreeValue(ctx, next_promise);
46964
0
                JS_FreeValue(ctx, resolve_element);
46965
0
                JS_FreeValue(ctx, reject_element);
46966
0
                goto fail_reject1;
46967
0
            }
46968
46969
0
            then_args[0] = resolve_element;
46970
0
            then_args[1] = reject_element;
46971
0
            ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2, then_args);
46972
0
            JS_FreeValue(ctx, resolve_element);
46973
0
            JS_FreeValue(ctx, reject_element);
46974
0
            if (check_exception_free(ctx, ret))
46975
0
                goto fail_reject1;
46976
0
            index++;
46977
0
        }
46978
46979
0
        is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
46980
0
        if (is_zero < 0)
46981
0
            goto fail_reject;
46982
0
        if (is_zero) {
46983
0
            if (magic == PROMISE_MAGIC_any) {
46984
0
                JSValue error;
46985
0
                error = js_aggregate_error_constructor(ctx, values);
46986
0
                if (JS_IsException(error))
46987
0
                    goto fail_reject;
46988
0
                JS_FreeValue(ctx, values);
46989
0
                values = error;
46990
0
            }
46991
0
            ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED,
46992
0
                          1, (JSValueConst *)&values);
46993
0
            if (check_exception_free(ctx, ret))
46994
0
                goto fail_reject;
46995
0
        }
46996
0
    }
46997
0
 done:
46998
0
    JS_FreeValue(ctx, promise_resolve);
46999
0
    JS_FreeValue(ctx, resolve_element_env);
47000
0
    JS_FreeValue(ctx, values);
47001
0
    JS_FreeValue(ctx, next_method);
47002
0
    JS_FreeValue(ctx, iter);
47003
0
    JS_FreeValue(ctx, resolving_funcs[0]);
47004
0
    JS_FreeValue(ctx, resolving_funcs[1]);
47005
0
    return result_promise;
47006
0
 fail:
47007
0
    JS_FreeValue(ctx, result_promise);
47008
0
    result_promise = JS_EXCEPTION;
47009
0
    goto done;
47010
0
}
47011
47012
static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
47013
                               int argc, JSValueConst *argv)
47014
0
{
47015
0
    JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
47016
0
    JSValue next_method = JS_UNDEFINED, iter = JS_UNDEFINED;
47017
0
    JSValue promise_resolve = JS_UNDEFINED;
47018
0
    BOOL done;
47019
47020
0
    if (!JS_IsObject(this_val))
47021
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
47022
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
47023
0
    if (JS_IsException(result_promise))
47024
0
        return result_promise;
47025
0
    promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
47026
0
    if (JS_IsException(promise_resolve) ||
47027
0
        check_function(ctx, promise_resolve))
47028
0
        goto fail_reject;
47029
0
    iter = JS_GetIterator(ctx, argv[0], FALSE);
47030
0
    if (JS_IsException(iter)) {
47031
0
        JSValue error;
47032
0
    fail_reject:
47033
0
        error = JS_GetException(ctx);
47034
0
        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
47035
0
                       (JSValueConst *)&error);
47036
0
        JS_FreeValue(ctx, error);
47037
0
        if (JS_IsException(ret))
47038
0
            goto fail;
47039
0
        JS_FreeValue(ctx, ret);
47040
0
    } else {
47041
0
        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
47042
0
        if (JS_IsException(next_method))
47043
0
            goto fail_reject;
47044
47045
0
        for(;;) {
47046
            /* XXX: conformance: should close the iterator if error on 'done'
47047
               access, but not on 'value' access */
47048
0
            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
47049
0
            if (JS_IsException(item))
47050
0
                goto fail_reject;
47051
0
            if (done)
47052
0
                break;
47053
0
            next_promise = JS_Call(ctx, promise_resolve,
47054
0
                                   this_val, 1, (JSValueConst *)&item);
47055
0
            JS_FreeValue(ctx, item);
47056
0
            if (JS_IsException(next_promise)) {
47057
0
            fail_reject1:
47058
0
                JS_IteratorClose(ctx, iter, TRUE);
47059
0
                goto fail_reject;
47060
0
            }
47061
0
            ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2,
47062
0
                                (JSValueConst *)resolving_funcs);
47063
0
            if (check_exception_free(ctx, ret))
47064
0
                goto fail_reject1;
47065
0
        }
47066
0
    }
47067
0
 done:
47068
0
    JS_FreeValue(ctx, promise_resolve);
47069
0
    JS_FreeValue(ctx, next_method);
47070
0
    JS_FreeValue(ctx, iter);
47071
0
    JS_FreeValue(ctx, resolving_funcs[0]);
47072
0
    JS_FreeValue(ctx, resolving_funcs[1]);
47073
0
    return result_promise;
47074
0
 fail:
47075
    //JS_FreeValue(ctx, next_method); // why not???
47076
0
    JS_FreeValue(ctx, result_promise);
47077
0
    result_promise = JS_EXCEPTION;
47078
0
    goto done;
47079
0
}
47080
47081
static __exception int perform_promise_then(JSContext *ctx,
47082
                                            JSValueConst promise,
47083
                                            JSValueConst *resolve_reject,
47084
                                            JSValueConst *cap_resolving_funcs)
47085
0
{
47086
0
    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
47087
0
    JSPromiseReactionData *rd_array[2], *rd;
47088
0
    int i, j;
47089
47090
0
    rd_array[0] = NULL;
47091
0
    rd_array[1] = NULL;
47092
0
    for(i = 0; i < 2; i++) {
47093
0
        JSValueConst handler;
47094
0
        rd = js_mallocz(ctx, sizeof(*rd));
47095
0
        if (!rd) {
47096
0
            if (i == 1)
47097
0
                promise_reaction_data_free(ctx->rt, rd_array[0]);
47098
0
            return -1;
47099
0
        }
47100
0
        for(j = 0; j < 2; j++)
47101
0
            rd->resolving_funcs[j] = JS_DupValue(ctx, cap_resolving_funcs[j]);
47102
0
        handler = resolve_reject[i];
47103
0
        if (!JS_IsFunction(ctx, handler))
47104
0
            handler = JS_UNDEFINED;
47105
0
        rd->handler = JS_DupValue(ctx, handler);
47106
0
        rd_array[i] = rd;
47107
0
    }
47108
47109
0
    if (s->promise_state == JS_PROMISE_PENDING) {
47110
0
        for(i = 0; i < 2; i++)
47111
0
            list_add_tail(&rd_array[i]->link, &s->promise_reactions[i]);
47112
0
    } else {
47113
0
        JSValueConst args[5];
47114
0
        if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
47115
0
            JSRuntime *rt = ctx->rt;
47116
0
            if (rt->host_promise_rejection_tracker) {
47117
0
                rt->host_promise_rejection_tracker(ctx, promise, s->promise_result,
47118
0
                                                   TRUE, rt->host_promise_rejection_tracker_opaque);
47119
0
            }
47120
0
        }
47121
0
        i = s->promise_state - JS_PROMISE_FULFILLED;
47122
0
        rd = rd_array[i];
47123
0
        args[0] = rd->resolving_funcs[0];
47124
0
        args[1] = rd->resolving_funcs[1];
47125
0
        args[2] = rd->handler;
47126
0
        args[3] = JS_NewBool(ctx, i);
47127
0
        args[4] = s->promise_result;
47128
0
        JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
47129
0
        for(i = 0; i < 2; i++)
47130
0
            promise_reaction_data_free(ctx->rt, rd_array[i]);
47131
0
    }
47132
0
    s->is_handled = TRUE;
47133
0
    return 0;
47134
0
}
47135
47136
static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
47137
                               int argc, JSValueConst *argv)
47138
0
{
47139
0
    JSValue ctor, result_promise, resolving_funcs[2];
47140
0
    JSPromiseData *s;
47141
0
    int i, ret;
47142
47143
0
    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_PROMISE);
47144
0
    if (!s)
47145
0
        return JS_EXCEPTION;
47146
47147
0
    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
47148
0
    if (JS_IsException(ctor))
47149
0
        return ctor;
47150
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
47151
0
    JS_FreeValue(ctx, ctor);
47152
0
    if (JS_IsException(result_promise))
47153
0
        return result_promise;
47154
0
    ret = perform_promise_then(ctx, this_val, argv,
47155
0
                               (JSValueConst *)resolving_funcs);
47156
0
    for(i = 0; i < 2; i++)
47157
0
        JS_FreeValue(ctx, resolving_funcs[i]);
47158
0
    if (ret) {
47159
0
        JS_FreeValue(ctx, result_promise);
47160
0
        return JS_EXCEPTION;
47161
0
    }
47162
0
    return result_promise;
47163
0
}
47164
47165
static JSValue js_promise_catch(JSContext *ctx, JSValueConst this_val,
47166
                                int argc, JSValueConst *argv)
47167
0
{
47168
0
    JSValueConst args[2];
47169
0
    args[0] = JS_UNDEFINED;
47170
0
    args[1] = argv[0];
47171
0
    return JS_Invoke(ctx, this_val, JS_ATOM_then, 2, args);
47172
0
}
47173
47174
static JSValue js_promise_finally_value_thunk(JSContext *ctx, JSValueConst this_val,
47175
                                              int argc, JSValueConst *argv,
47176
                                              int magic, JSValue *func_data)
47177
0
{
47178
0
    return JS_DupValue(ctx, func_data[0]);
47179
0
}
47180
47181
static JSValue js_promise_finally_thrower(JSContext *ctx, JSValueConst this_val,
47182
                                          int argc, JSValueConst *argv,
47183
                                          int magic, JSValue *func_data)
47184
0
{
47185
0
    return JS_Throw(ctx, JS_DupValue(ctx, func_data[0]));
47186
0
}
47187
47188
static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_val,
47189
                                            int argc, JSValueConst *argv,
47190
                                            int magic, JSValue *func_data)
47191
0
{
47192
0
    JSValueConst ctor = func_data[0];
47193
0
    JSValueConst onFinally = func_data[1];
47194
0
    JSValue res, promise, ret, then_func;
47195
47196
0
    res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL);
47197
0
    if (JS_IsException(res))
47198
0
        return res;
47199
0
    promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0);
47200
0
    JS_FreeValue(ctx, res);
47201
0
    if (JS_IsException(promise))
47202
0
        return promise;
47203
0
    if (magic == 0) {
47204
0
        then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0,
47205
0
                                        0, 1, argv);
47206
0
    } else {
47207
0
        then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 0,
47208
0
                                        0, 1, argv);
47209
0
    }
47210
0
    if (JS_IsException(then_func)) {
47211
0
        JS_FreeValue(ctx, promise);
47212
0
        return then_func;
47213
0
    }
47214
0
    ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, (JSValueConst *)&then_func);
47215
0
    JS_FreeValue(ctx, then_func);
47216
0
    return ret;
47217
0
}
47218
47219
static JSValue js_promise_finally(JSContext *ctx, JSValueConst this_val,
47220
                                  int argc, JSValueConst *argv)
47221
0
{
47222
0
    JSValueConst onFinally = argv[0];
47223
0
    JSValue ctor, ret;
47224
0
    JSValue then_funcs[2];
47225
0
    JSValueConst func_data[2];
47226
0
    int i;
47227
47228
0
    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
47229
0
    if (JS_IsException(ctor))
47230
0
        return ctor;
47231
0
    if (!JS_IsFunction(ctx, onFinally)) {
47232
0
        then_funcs[0] = JS_DupValue(ctx, onFinally);
47233
0
        then_funcs[1] = JS_DupValue(ctx, onFinally);
47234
0
    } else {
47235
0
        func_data[0] = ctor;
47236
0
        func_data[1] = onFinally;
47237
0
        for(i = 0; i < 2; i++) {
47238
0
            then_funcs[i] = JS_NewCFunctionData(ctx, js_promise_then_finally_func, 1, i, 2, func_data);
47239
0
            if (JS_IsException(then_funcs[i])) {
47240
0
                if (i == 1)
47241
0
                    JS_FreeValue(ctx, then_funcs[0]);
47242
0
                JS_FreeValue(ctx, ctor);
47243
0
                return JS_EXCEPTION;
47244
0
            }
47245
0
        }
47246
0
    }
47247
0
    JS_FreeValue(ctx, ctor);
47248
0
    ret = JS_Invoke(ctx, this_val, JS_ATOM_then, 2, (JSValueConst *)then_funcs);
47249
0
    JS_FreeValue(ctx, then_funcs[0]);
47250
0
    JS_FreeValue(ctx, then_funcs[1]);
47251
0
    return ret;
47252
0
}
47253
47254
static const JSCFunctionListEntry js_promise_funcs[] = {
47255
    JS_CFUNC_MAGIC_DEF("resolve", 1, js_promise_resolve, 0 ),
47256
    JS_CFUNC_MAGIC_DEF("reject", 1, js_promise_resolve, 1 ),
47257
    JS_CFUNC_MAGIC_DEF("all", 1, js_promise_all, PROMISE_MAGIC_all ),
47258
    JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ),
47259
    JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ),
47260
    JS_CFUNC_DEF("race", 1, js_promise_race ),
47261
    //JS_CFUNC_DEF("__newPromiseCapability", 1, js_promise___newPromiseCapability ),
47262
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
47263
};
47264
47265
static const JSCFunctionListEntry js_promise_proto_funcs[] = {
47266
    JS_CFUNC_DEF("then", 2, js_promise_then ),
47267
    JS_CFUNC_DEF("catch", 1, js_promise_catch ),
47268
    JS_CFUNC_DEF("finally", 1, js_promise_finally ),
47269
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Promise", JS_PROP_CONFIGURABLE ),
47270
};
47271
47272
/* AsyncFunction */
47273
static const JSCFunctionListEntry js_async_function_proto_funcs[] = {
47274
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncFunction", JS_PROP_CONFIGURABLE ),
47275
};
47276
47277
static JSValue js_async_from_sync_iterator_unwrap(JSContext *ctx,
47278
                                                  JSValueConst this_val,
47279
                                                  int argc, JSValueConst *argv,
47280
                                                  int magic, JSValue *func_data)
47281
0
{
47282
0
    return js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]),
47283
0
                                     JS_ToBool(ctx, func_data[0]));
47284
0
}
47285
47286
static JSValue js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx,
47287
                                                              BOOL done)
47288
0
{
47289
0
    JSValueConst func_data[1];
47290
47291
0
    func_data[0] = (JSValueConst)JS_NewBool(ctx, done);
47292
0
    return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_unwrap,
47293
0
                               1, 0, 1, func_data);
47294
0
}
47295
47296
/* AsyncIteratorPrototype */
47297
47298
static const JSCFunctionListEntry js_async_iterator_proto_funcs[] = {
47299
    JS_CFUNC_DEF("[Symbol.asyncIterator]", 0, js_iterator_proto_iterator ),
47300
};
47301
47302
/* AsyncFromSyncIteratorPrototype */
47303
47304
typedef struct JSAsyncFromSyncIteratorData {
47305
    JSValue sync_iter;
47306
    JSValue next_method;
47307
} JSAsyncFromSyncIteratorData;
47308
47309
static void js_async_from_sync_iterator_finalizer(JSRuntime *rt, JSValue val)
47310
0
{
47311
0
    JSAsyncFromSyncIteratorData *s =
47312
0
        JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
47313
0
    if (s) {
47314
0
        JS_FreeValueRT(rt, s->sync_iter);
47315
0
        JS_FreeValueRT(rt, s->next_method);
47316
0
        js_free_rt(rt, s);
47317
0
    }
47318
0
}
47319
47320
static void js_async_from_sync_iterator_mark(JSRuntime *rt, JSValueConst val,
47321
                                             JS_MarkFunc *mark_func)
47322
0
{
47323
0
    JSAsyncFromSyncIteratorData *s =
47324
0
        JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
47325
0
    if (s) {
47326
0
        JS_MarkValue(rt, s->sync_iter, mark_func);
47327
0
        JS_MarkValue(rt, s->next_method, mark_func);
47328
0
    }
47329
0
}
47330
47331
static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
47332
                                              JSValueConst sync_iter)
47333
0
{
47334
0
    JSValue async_iter, next_method;
47335
0
    JSAsyncFromSyncIteratorData *s;
47336
47337
0
    next_method = JS_GetProperty(ctx, sync_iter, JS_ATOM_next);
47338
0
    if (JS_IsException(next_method))
47339
0
        return JS_EXCEPTION;
47340
0
    async_iter = JS_NewObjectClass(ctx, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
47341
0
    if (JS_IsException(async_iter)) {
47342
0
        JS_FreeValue(ctx, next_method);
47343
0
        return async_iter;
47344
0
    }
47345
0
    s = js_mallocz(ctx, sizeof(*s));
47346
0
    if (!s) {
47347
0
        JS_FreeValue(ctx, async_iter);
47348
0
        JS_FreeValue(ctx, next_method);
47349
0
        return JS_EXCEPTION;
47350
0
    }
47351
0
    s->sync_iter = JS_DupValue(ctx, sync_iter);
47352
0
    s->next_method = next_method;
47353
0
    JS_SetOpaque(async_iter, s);
47354
0
    return async_iter;
47355
0
}
47356
47357
static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst this_val,
47358
                                                int argc, JSValueConst *argv,
47359
                                                int magic)
47360
0
{
47361
0
    JSValue promise, resolving_funcs[2], value, err, method;
47362
0
    JSAsyncFromSyncIteratorData *s;
47363
0
    int done;
47364
0
    int is_reject;
47365
47366
0
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
47367
0
    if (JS_IsException(promise))
47368
0
        return JS_EXCEPTION;
47369
0
    s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
47370
0
    if (!s) {
47371
0
        JS_ThrowTypeError(ctx, "not an Async-from-Sync Iterator");
47372
0
        goto reject;
47373
0
    }
47374
47375
0
    if (magic == GEN_MAGIC_NEXT) {
47376
0
        method = JS_DupValue(ctx, s->next_method);
47377
0
    } else {
47378
0
        method = JS_GetProperty(ctx, s->sync_iter,
47379
0
                                magic == GEN_MAGIC_RETURN ? JS_ATOM_return :
47380
0
                                JS_ATOM_throw);
47381
0
        if (JS_IsException(method))
47382
0
            goto reject;
47383
0
        if (JS_IsUndefined(method) || JS_IsNull(method)) {
47384
0
            if (magic == GEN_MAGIC_RETURN) {
47385
0
                err = js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]), TRUE);
47386
0
                is_reject = 0;
47387
0
            } else {
47388
0
                err = JS_DupValue(ctx, argv[0]);
47389
0
                is_reject = 1;
47390
0
            }
47391
0
            goto done_resolve;
47392
0
        }
47393
0
    }
47394
0
    value = JS_IteratorNext2(ctx, s->sync_iter, method,
47395
0
                             argc >= 1 ? 1 : 0, argv, &done);
47396
0
    JS_FreeValue(ctx, method);
47397
0
    if (JS_IsException(value))
47398
0
        goto reject;
47399
0
    if (done == 2) {
47400
0
        JSValue obj = value;
47401
0
        value = JS_IteratorGetCompleteValue(ctx, obj, &done);
47402
0
        JS_FreeValue(ctx, obj);
47403
0
        if (JS_IsException(value))
47404
0
            goto reject;
47405
0
    }
47406
47407
0
    if (JS_IsException(value)) {
47408
0
        JSValue res2;
47409
0
    reject:
47410
0
        err = JS_GetException(ctx);
47411
0
        is_reject = 1;
47412
0
    done_resolve:
47413
0
        res2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED,
47414
0
                       1, (JSValueConst *)&err);
47415
0
        JS_FreeValue(ctx, err);
47416
0
        JS_FreeValue(ctx, res2);
47417
0
        JS_FreeValue(ctx, resolving_funcs[0]);
47418
0
        JS_FreeValue(ctx, resolving_funcs[1]);
47419
0
        return promise;
47420
0
    }
47421
0
    {
47422
0
        JSValue value_wrapper_promise, resolve_reject[2];
47423
0
        int res;
47424
47425
0
        value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor,
47426
0
                                                   1, (JSValueConst *)&value, 0);
47427
0
        if (JS_IsException(value_wrapper_promise)) {
47428
0
            JS_FreeValue(ctx, value);
47429
0
            goto reject;
47430
0
        }
47431
47432
0
        resolve_reject[0] =
47433
0
            js_async_from_sync_iterator_unwrap_func_create(ctx, done);
47434
0
        if (JS_IsException(resolve_reject[0])) {
47435
0
            JS_FreeValue(ctx, value_wrapper_promise);
47436
0
            goto fail;
47437
0
        }
47438
0
        JS_FreeValue(ctx, value);
47439
0
        resolve_reject[1] = JS_UNDEFINED;
47440
47441
0
        res = perform_promise_then(ctx, value_wrapper_promise,
47442
0
                                   (JSValueConst *)resolve_reject,
47443
0
                                   (JSValueConst *)resolving_funcs);
47444
0
        JS_FreeValue(ctx, resolve_reject[0]);
47445
0
        JS_FreeValue(ctx, value_wrapper_promise);
47446
0
        JS_FreeValue(ctx, resolving_funcs[0]);
47447
0
        JS_FreeValue(ctx, resolving_funcs[1]);
47448
0
        if (res) {
47449
0
            JS_FreeValue(ctx, promise);
47450
0
            return JS_EXCEPTION;
47451
0
        }
47452
0
    }
47453
0
    return promise;
47454
0
 fail:
47455
0
    JS_FreeValue(ctx, value);
47456
0
    JS_FreeValue(ctx, resolving_funcs[0]);
47457
0
    JS_FreeValue(ctx, resolving_funcs[1]);
47458
0
    JS_FreeValue(ctx, promise);
47459
0
    return JS_EXCEPTION;
47460
0
}
47461
47462
static const JSCFunctionListEntry js_async_from_sync_iterator_proto_funcs[] = {
47463
    JS_CFUNC_MAGIC_DEF("next", 1, js_async_from_sync_iterator_next, GEN_MAGIC_NEXT ),
47464
    JS_CFUNC_MAGIC_DEF("return", 1, js_async_from_sync_iterator_next, GEN_MAGIC_RETURN ),
47465
    JS_CFUNC_MAGIC_DEF("throw", 1, js_async_from_sync_iterator_next, GEN_MAGIC_THROW ),
47466
};
47467
47468
/* AsyncGeneratorFunction */
47469
47470
static const JSCFunctionListEntry js_async_generator_function_proto_funcs[] = {
47471
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGeneratorFunction", JS_PROP_CONFIGURABLE ),
47472
};
47473
47474
/* AsyncGenerator prototype */
47475
47476
static const JSCFunctionListEntry js_async_generator_proto_funcs[] = {
47477
    JS_CFUNC_MAGIC_DEF("next", 1, js_async_generator_next, GEN_MAGIC_NEXT ),
47478
    JS_CFUNC_MAGIC_DEF("return", 1, js_async_generator_next, GEN_MAGIC_RETURN ),
47479
    JS_CFUNC_MAGIC_DEF("throw", 1, js_async_generator_next, GEN_MAGIC_THROW ),
47480
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGenerator", JS_PROP_CONFIGURABLE ),
47481
};
47482
47483
static JSClassShortDef const js_async_class_def[] = {
47484
    { JS_ATOM_Promise, js_promise_finalizer, js_promise_mark },                      /* JS_CLASS_PROMISE */
47485
    { JS_ATOM_PromiseResolveFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_RESOLVE_FUNCTION */
47486
    { JS_ATOM_PromiseRejectFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_REJECT_FUNCTION */
47487
    { JS_ATOM_AsyncFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_FUNCTION */
47488
    { JS_ATOM_AsyncFunctionResolve, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_RESOLVE */
47489
    { JS_ATOM_AsyncFunctionReject, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_REJECT */
47490
    { JS_ATOM_empty_string, js_async_from_sync_iterator_finalizer, js_async_from_sync_iterator_mark }, /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
47491
    { JS_ATOM_AsyncGeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_GENERATOR_FUNCTION */
47492
    { JS_ATOM_AsyncGenerator, js_async_generator_finalizer, js_async_generator_mark },  /* JS_CLASS_ASYNC_GENERATOR */
47493
};
47494
47495
void JS_AddIntrinsicPromise(JSContext *ctx)
47496
2
{
47497
2
    JSRuntime *rt = ctx->rt;
47498
2
    JSValue obj1;
47499
47500
2
    if (!JS_IsRegisteredClass(rt, JS_CLASS_PROMISE)) {
47501
2
        init_class_range(rt, js_async_class_def, JS_CLASS_PROMISE,
47502
2
                         countof(js_async_class_def));
47503
2
        rt->class_array[JS_CLASS_PROMISE_RESOLVE_FUNCTION].call = js_promise_resolve_function_call;
47504
2
        rt->class_array[JS_CLASS_PROMISE_REJECT_FUNCTION].call = js_promise_resolve_function_call;
47505
2
        rt->class_array[JS_CLASS_ASYNC_FUNCTION].call = js_async_function_call;
47506
2
        rt->class_array[JS_CLASS_ASYNC_FUNCTION_RESOLVE].call = js_async_function_resolve_call;
47507
2
        rt->class_array[JS_CLASS_ASYNC_FUNCTION_REJECT].call = js_async_function_resolve_call;
47508
2
        rt->class_array[JS_CLASS_ASYNC_GENERATOR_FUNCTION].call = js_async_generator_function_call;
47509
2
    }
47510
47511
    /* Promise */
47512
2
    ctx->class_proto[JS_CLASS_PROMISE] = JS_NewObject(ctx);
47513
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_PROMISE],
47514
2
                               js_promise_proto_funcs,
47515
2
                               countof(js_promise_proto_funcs));
47516
2
    obj1 = JS_NewCFunction2(ctx, js_promise_constructor, "Promise", 1,
47517
2
                            JS_CFUNC_constructor, 0);
47518
2
    ctx->promise_ctor = JS_DupValue(ctx, obj1);
47519
2
    JS_SetPropertyFunctionList(ctx, obj1,
47520
2
                               js_promise_funcs,
47521
2
                               countof(js_promise_funcs));
47522
2
    JS_NewGlobalCConstructor2(ctx, obj1, "Promise",
47523
2
                              ctx->class_proto[JS_CLASS_PROMISE]);
47524
47525
    /* AsyncFunction */
47526
2
    ctx->class_proto[JS_CLASS_ASYNC_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
47527
2
    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
47528
2
                            "AsyncFunction", 1,
47529
2
                            JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC,
47530
2
                            ctx->function_ctor);
47531
2
    JS_SetPropertyFunctionList(ctx,
47532
2
                               ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
47533
2
                               js_async_function_proto_funcs,
47534
2
                               countof(js_async_function_proto_funcs));
47535
2
    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
47536
2
                       0, JS_PROP_CONFIGURABLE);
47537
2
    JS_FreeValue(ctx, obj1);
47538
47539
    /* AsyncIteratorPrototype */
47540
2
    ctx->async_iterator_proto = JS_NewObject(ctx);
47541
2
    JS_SetPropertyFunctionList(ctx, ctx->async_iterator_proto,
47542
2
                               js_async_iterator_proto_funcs,
47543
2
                               countof(js_async_iterator_proto_funcs));
47544
47545
    /* AsyncFromSyncIteratorPrototype */
47546
2
    ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR] =
47547
2
        JS_NewObjectProto(ctx, ctx->async_iterator_proto);
47548
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR],
47549
2
                               js_async_from_sync_iterator_proto_funcs,
47550
2
                               countof(js_async_from_sync_iterator_proto_funcs));
47551
47552
    /* AsyncGeneratorPrototype */
47553
2
    ctx->class_proto[JS_CLASS_ASYNC_GENERATOR] =
47554
2
        JS_NewObjectProto(ctx, ctx->async_iterator_proto);
47555
2
    JS_SetPropertyFunctionList(ctx,
47556
2
                               ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
47557
2
                               js_async_generator_proto_funcs,
47558
2
                               countof(js_async_generator_proto_funcs));
47559
47560
    /* AsyncGeneratorFunction */
47561
2
    ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION] =
47562
2
        JS_NewObjectProto(ctx, ctx->function_proto);
47563
2
    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
47564
2
                            "AsyncGeneratorFunction", 1,
47565
2
                            JS_CFUNC_constructor_or_func_magic,
47566
2
                            JS_FUNC_ASYNC_GENERATOR,
47567
2
                            ctx->function_ctor);
47568
2
    JS_SetPropertyFunctionList(ctx,
47569
2
                               ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
47570
2
                               js_async_generator_function_proto_funcs,
47571
2
                               countof(js_async_generator_function_proto_funcs));
47572
2
    JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
47573
2
                       ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
47574
2
                       JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
47575
2
    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
47576
2
                       0, JS_PROP_CONFIGURABLE);
47577
2
    JS_FreeValue(ctx, obj1);
47578
2
}
47579
47580
/* URI handling */
47581
47582
0
static int string_get_hex(JSString *p, int k, int n) {
47583
0
    int c = 0, h;
47584
0
    while (n-- > 0) {
47585
0
        if ((h = from_hex(string_get(p, k++))) < 0)
47586
0
            return -1;
47587
0
        c = (c << 4) | h;
47588
0
    }
47589
0
    return c;
47590
0
}
47591
47592
0
static int isURIReserved(int c) {
47593
0
    return c < 0x100 && memchr(";/?:@&=+$,#", c, sizeof(";/?:@&=+$,#") - 1) != NULL;
47594
0
}
47595
47596
static int __attribute__((format(printf, 2, 3))) js_throw_URIError(JSContext *ctx, const char *fmt, ...)
47597
0
{
47598
0
    va_list ap;
47599
47600
0
    va_start(ap, fmt);
47601
0
    JS_ThrowError(ctx, JS_URI_ERROR, fmt, ap);
47602
0
    va_end(ap);
47603
0
    return -1;
47604
0
}
47605
47606
0
static int hex_decode(JSContext *ctx, JSString *p, int k) {
47607
0
    int c;
47608
47609
0
    if (k >= p->len || string_get(p, k) != '%')
47610
0
        return js_throw_URIError(ctx, "expecting %%");
47611
0
    if (k + 2 >= p->len || (c = string_get_hex(p, k + 1, 2)) < 0)
47612
0
        return js_throw_URIError(ctx, "expecting hex digit");
47613
47614
0
    return c;
47615
0
}
47616
47617
static JSValue js_global_decodeURI(JSContext *ctx, JSValueConst this_val,
47618
                                   int argc, JSValueConst *argv, int isComponent)
47619
0
{
47620
0
    JSValue str;
47621
0
    StringBuffer b_s, *b = &b_s;
47622
0
    JSString *p;
47623
0
    int k, c, c1, n, c_min;
47624
47625
0
    str = JS_ToString(ctx, argv[0]);
47626
0
    if (JS_IsException(str))
47627
0
        return str;
47628
47629
0
    string_buffer_init(ctx, b, 0);
47630
47631
0
    p = JS_VALUE_GET_STRING(str);
47632
0
    for (k = 0; k < p->len;) {
47633
0
        c = string_get(p, k);
47634
0
        if (c == '%') {
47635
0
            c = hex_decode(ctx, p, k);
47636
0
            if (c < 0)
47637
0
                goto fail;
47638
0
            k += 3;
47639
0
            if (c < 0x80) {
47640
0
                if (!isComponent && isURIReserved(c)) {
47641
0
                    c = '%';
47642
0
                    k -= 2;
47643
0
                }
47644
0
            } else {
47645
                /* Decode URI-encoded UTF-8 sequence */
47646
0
                if (c >= 0xc0 && c <= 0xdf) {
47647
0
                    n = 1;
47648
0
                    c_min = 0x80;
47649
0
                    c &= 0x1f;
47650
0
                } else if (c >= 0xe0 && c <= 0xef) {
47651
0
                    n = 2;
47652
0
                    c_min = 0x800;
47653
0
                    c &= 0xf;
47654
0
                } else if (c >= 0xf0 && c <= 0xf7) {
47655
0
                    n = 3;
47656
0
                    c_min = 0x10000;
47657
0
                    c &= 0x7;
47658
0
                } else {
47659
0
                    n = 0;
47660
0
                    c_min = 1;
47661
0
                    c = 0;
47662
0
                }
47663
0
                while (n-- > 0) {
47664
0
                    c1 = hex_decode(ctx, p, k);
47665
0
                    if (c1 < 0)
47666
0
                        goto fail;
47667
0
                    k += 3;
47668
0
                    if ((c1 & 0xc0) != 0x80) {
47669
0
                        c = 0;
47670
0
                        break;
47671
0
                    }
47672
0
                    c = (c << 6) | (c1 & 0x3f);
47673
0
                }
47674
0
                if (c < c_min || c > 0x10FFFF ||
47675
0
                    (c >= 0xd800 && c < 0xe000)) {
47676
0
                    js_throw_URIError(ctx, "malformed UTF-8");
47677
0
                    goto fail;
47678
0
                }
47679
0
            }
47680
0
        } else {
47681
0
            k++;
47682
0
        }
47683
0
        string_buffer_putc(b, c);
47684
0
    }
47685
0
    JS_FreeValue(ctx, str);
47686
0
    return string_buffer_end(b);
47687
47688
0
fail:
47689
0
    JS_FreeValue(ctx, str);
47690
0
    string_buffer_free(b);
47691
0
    return JS_EXCEPTION;
47692
0
}
47693
47694
0
static int isUnescaped(int c) {
47695
0
    static char const unescaped_chars[] =
47696
0
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
47697
0
        "abcdefghijklmnopqrstuvwxyz"
47698
0
        "0123456789"
47699
0
        "@*_+-./";
47700
0
    return c < 0x100 &&
47701
0
        memchr(unescaped_chars, c, sizeof(unescaped_chars) - 1);
47702
0
}
47703
47704
0
static int isURIUnescaped(int c, int isComponent) {
47705
0
    return c < 0x100 &&
47706
0
        ((c >= 0x61 && c <= 0x7a) ||
47707
0
         (c >= 0x41 && c <= 0x5a) ||
47708
0
         (c >= 0x30 && c <= 0x39) ||
47709
0
         memchr("-_.!~*'()", c, sizeof("-_.!~*'()") - 1) != NULL ||
47710
0
         (!isComponent && isURIReserved(c)));
47711
0
}
47712
47713
0
static int encodeURI_hex(StringBuffer *b, int c) {
47714
0
    uint8_t buf[6];
47715
0
    int n = 0;
47716
0
    const char *hex = "0123456789ABCDEF";
47717
47718
0
    buf[n++] = '%';
47719
0
    if (c >= 256) {
47720
0
        buf[n++] = 'u';
47721
0
        buf[n++] = hex[(c >> 12) & 15];
47722
0
        buf[n++] = hex[(c >>  8) & 15];
47723
0
    }
47724
0
    buf[n++] = hex[(c >> 4) & 15];
47725
0
    buf[n++] = hex[(c >> 0) & 15];
47726
0
    return string_buffer_write8(b, buf, n);
47727
0
}
47728
47729
static JSValue js_global_encodeURI(JSContext *ctx, JSValueConst this_val,
47730
                                   int argc, JSValueConst *argv,
47731
                                   int isComponent)
47732
0
{
47733
0
    JSValue str;
47734
0
    StringBuffer b_s, *b = &b_s;
47735
0
    JSString *p;
47736
0
    int k, c, c1;
47737
47738
0
    str = JS_ToString(ctx, argv[0]);
47739
0
    if (JS_IsException(str))
47740
0
        return str;
47741
47742
0
    p = JS_VALUE_GET_STRING(str);
47743
0
    string_buffer_init(ctx, b, p->len);
47744
0
    for (k = 0; k < p->len;) {
47745
0
        c = string_get(p, k);
47746
0
        k++;
47747
0
        if (isURIUnescaped(c, isComponent)) {
47748
0
            string_buffer_putc16(b, c);
47749
0
        } else {
47750
0
            if (c >= 0xdc00 && c <= 0xdfff) {
47751
0
                js_throw_URIError(ctx, "invalid character");
47752
0
                goto fail;
47753
0
            } else if (c >= 0xd800 && c <= 0xdbff) {
47754
0
                if (k >= p->len) {
47755
0
                    js_throw_URIError(ctx, "expecting surrogate pair");
47756
0
                    goto fail;
47757
0
                }
47758
0
                c1 = string_get(p, k);
47759
0
                k++;
47760
0
                if (c1 < 0xdc00 || c1 > 0xdfff) {
47761
0
                    js_throw_URIError(ctx, "expecting surrogate pair");
47762
0
                    goto fail;
47763
0
                }
47764
0
                c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
47765
0
            }
47766
0
            if (c < 0x80) {
47767
0
                encodeURI_hex(b, c);
47768
0
            } else {
47769
                /* XXX: use C UTF-8 conversion ? */
47770
0
                if (c < 0x800) {
47771
0
                    encodeURI_hex(b, (c >> 6) | 0xc0);
47772
0
                } else {
47773
0
                    if (c < 0x10000) {
47774
0
                        encodeURI_hex(b, (c >> 12) | 0xe0);
47775
0
                    } else {
47776
0
                        encodeURI_hex(b, (c >> 18) | 0xf0);
47777
0
                        encodeURI_hex(b, ((c >> 12) & 0x3f) | 0x80);
47778
0
                    }
47779
0
                    encodeURI_hex(b, ((c >> 6) & 0x3f) | 0x80);
47780
0
                }
47781
0
                encodeURI_hex(b, (c & 0x3f) | 0x80);
47782
0
            }
47783
0
        }
47784
0
    }
47785
0
    JS_FreeValue(ctx, str);
47786
0
    return string_buffer_end(b);
47787
47788
0
fail:
47789
0
    JS_FreeValue(ctx, str);
47790
0
    string_buffer_free(b);
47791
0
    return JS_EXCEPTION;
47792
0
}
47793
47794
static JSValue js_global_escape(JSContext *ctx, JSValueConst this_val,
47795
                                int argc, JSValueConst *argv)
47796
0
{
47797
0
    JSValue str;
47798
0
    StringBuffer b_s, *b = &b_s;
47799
0
    JSString *p;
47800
0
    int i, len, c;
47801
47802
0
    str = JS_ToString(ctx, argv[0]);
47803
0
    if (JS_IsException(str))
47804
0
        return str;
47805
47806
0
    p = JS_VALUE_GET_STRING(str);
47807
0
    string_buffer_init(ctx, b, p->len);
47808
0
    for (i = 0, len = p->len; i < len; i++) {
47809
0
        c = string_get(p, i);
47810
0
        if (isUnescaped(c)) {
47811
0
            string_buffer_putc16(b, c);
47812
0
        } else {
47813
0
            encodeURI_hex(b, c);
47814
0
        }
47815
0
    }
47816
0
    JS_FreeValue(ctx, str);
47817
0
    return string_buffer_end(b);
47818
0
}
47819
47820
static JSValue js_global_unescape(JSContext *ctx, JSValueConst this_val,
47821
                                  int argc, JSValueConst *argv)
47822
0
{
47823
0
    JSValue str;
47824
0
    StringBuffer b_s, *b = &b_s;
47825
0
    JSString *p;
47826
0
    int i, len, c, n;
47827
47828
0
    str = JS_ToString(ctx, argv[0]);
47829
0
    if (JS_IsException(str))
47830
0
        return str;
47831
47832
0
    string_buffer_init(ctx, b, 0);
47833
0
    p = JS_VALUE_GET_STRING(str);
47834
0
    for (i = 0, len = p->len; i < len; i++) {
47835
0
        c = string_get(p, i);
47836
0
        if (c == '%') {
47837
0
            if (i + 6 <= len
47838
0
            &&  string_get(p, i + 1) == 'u'
47839
0
            &&  (n = string_get_hex(p, i + 2, 4)) >= 0) {
47840
0
                c = n;
47841
0
                i += 6 - 1;
47842
0
            } else
47843
0
            if (i + 3 <= len
47844
0
            &&  (n = string_get_hex(p, i + 1, 2)) >= 0) {
47845
0
                c = n;
47846
0
                i += 3 - 1;
47847
0
            }
47848
0
        }
47849
0
        string_buffer_putc16(b, c);
47850
0
    }
47851
0
    JS_FreeValue(ctx, str);
47852
0
    return string_buffer_end(b);
47853
0
}
47854
47855
/* global object */
47856
47857
static const JSCFunctionListEntry js_global_funcs[] = {
47858
    JS_CFUNC_DEF("parseInt", 2, js_parseInt ),
47859
    JS_CFUNC_DEF("parseFloat", 1, js_parseFloat ),
47860
    JS_CFUNC_DEF("isNaN", 1, js_global_isNaN ),
47861
    JS_CFUNC_DEF("isFinite", 1, js_global_isFinite ),
47862
47863
    JS_CFUNC_MAGIC_DEF("decodeURI", 1, js_global_decodeURI, 0 ),
47864
    JS_CFUNC_MAGIC_DEF("decodeURIComponent", 1, js_global_decodeURI, 1 ),
47865
    JS_CFUNC_MAGIC_DEF("encodeURI", 1, js_global_encodeURI, 0 ),
47866
    JS_CFUNC_MAGIC_DEF("encodeURIComponent", 1, js_global_encodeURI, 1 ),
47867
    JS_CFUNC_DEF("escape", 1, js_global_escape ),
47868
    JS_CFUNC_DEF("unescape", 1, js_global_unescape ),
47869
    JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ),
47870
    JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
47871
    JS_PROP_UNDEFINED_DEF("undefined", 0 ),
47872
47873
    /* for the 'Date' implementation */
47874
    JS_CFUNC_DEF("__date_clock", 0, js___date_clock ),
47875
    //JS_CFUNC_DEF("__date_now", 0, js___date_now ),
47876
    //JS_CFUNC_DEF("__date_getTimezoneOffset", 1, js___date_getTimezoneOffset ),
47877
    //JS_CFUNC_DEF("__date_create", 3, js___date_create ),
47878
};
47879
47880
/* Date */
47881
47882
0
static int64_t math_mod(int64_t a, int64_t b) {
47883
    /* return positive modulo */
47884
0
    int64_t m = a % b;
47885
0
    return m + (m < 0) * b;
47886
0
}
47887
47888
0
static int64_t floor_div(int64_t a, int64_t b) {
47889
    /* integer division rounding toward -Infinity */
47890
0
    int64_t m = a % b;
47891
0
    return (a - (m + (m < 0) * b)) / b;
47892
0
}
47893
47894
static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
47895
                             int argc, JSValueConst *argv);
47896
47897
static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val)
47898
0
{
47899
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
47900
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
47901
0
        if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data))
47902
0
            return JS_ToFloat64(ctx, valp, p->u.object_data);
47903
0
    }
47904
0
    JS_ThrowTypeError(ctx, "not a Date object");
47905
0
    return -1;
47906
0
}
47907
47908
static JSValue JS_SetThisTimeValue(JSContext *ctx, JSValueConst this_val, double v)
47909
0
{
47910
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
47911
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
47912
0
        if (p->class_id == JS_CLASS_DATE) {
47913
0
            JS_FreeValue(ctx, p->u.object_data);
47914
0
            p->u.object_data = JS_NewFloat64(ctx, v);
47915
0
            return JS_DupValue(ctx, p->u.object_data);
47916
0
        }
47917
0
    }
47918
0
    return JS_ThrowTypeError(ctx, "not a Date object");
47919
0
}
47920
47921
0
static int64_t days_from_year(int64_t y) {
47922
0
    return 365 * (y - 1970) + floor_div(y - 1969, 4) -
47923
0
        floor_div(y - 1901, 100) + floor_div(y - 1601, 400);
47924
0
}
47925
47926
0
static int64_t days_in_year(int64_t y) {
47927
0
    return 365 + !(y % 4) - !(y % 100) + !(y % 400);
47928
0
}
47929
47930
/* return the year, update days */
47931
0
static int64_t year_from_days(int64_t *days) {
47932
0
    int64_t y, d1, nd, d = *days;
47933
0
    y = floor_div(d * 10000, 3652425) + 1970;
47934
    /* the initial approximation is very good, so only a few
47935
       iterations are necessary */
47936
0
    for(;;) {
47937
0
        d1 = d - days_from_year(y);
47938
0
        if (d1 < 0) {
47939
0
            y--;
47940
0
            d1 += days_in_year(y);
47941
0
        } else {
47942
0
            nd = days_in_year(y);
47943
0
            if (d1 < nd)
47944
0
                break;
47945
0
            d1 -= nd;
47946
0
            y++;
47947
0
        }
47948
0
    }
47949
0
    *days = d1;
47950
0
    return y;
47951
0
}
47952
47953
static int const month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
47954
static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
47955
static char const day_names[] = "SunMonTueWedThuFriSat";
47956
47957
static __exception int get_date_fields(JSContext *ctx, JSValueConst obj,
47958
                                       double fields[9], int is_local, int force)
47959
0
{
47960
0
    double dval;
47961
0
    int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0;
47962
47963
0
    if (JS_ThisTimeValue(ctx, &dval, obj))
47964
0
        return -1;
47965
47966
0
    if (isnan(dval)) {
47967
0
        if (!force)
47968
0
            return FALSE; /* NaN */
47969
0
        d = 0;        /* initialize all fields to 0 */
47970
0
    } else {
47971
0
        d = dval;
47972
0
        if (is_local) {
47973
0
            tz = -getTimezoneOffset(d);
47974
0
            d += tz * 60000;
47975
0
        }
47976
0
    }
47977
47978
    /* result is >= 0, we can use % */
47979
0
    h = math_mod(d, 86400000);
47980
0
    days = (d - h) / 86400000;
47981
0
    ms = h % 1000;
47982
0
    h = (h - ms) / 1000;
47983
0
    s = h % 60;
47984
0
    h = (h - s) / 60;
47985
0
    m = h % 60;
47986
0
    h = (h - m) / 60;
47987
0
    wd = math_mod(days + 4, 7); /* week day */
47988
0
    y = year_from_days(&days);
47989
47990
0
    for(i = 0; i < 11; i++) {
47991
0
        md = month_days[i];
47992
0
        if (i == 1)
47993
0
            md += days_in_year(y) - 365;
47994
0
        if (days < md)
47995
0
            break;
47996
0
        days -= md;
47997
0
    }
47998
0
    fields[0] = y;
47999
0
    fields[1] = i;
48000
0
    fields[2] = days + 1;
48001
0
    fields[3] = h;
48002
0
    fields[4] = m;
48003
0
    fields[5] = s;
48004
0
    fields[6] = ms;
48005
0
    fields[7] = wd;
48006
0
    fields[8] = tz;
48007
0
    return TRUE;
48008
0
}
48009
48010
0
static double time_clip(double t) {
48011
0
    if (t >= -8.64e15 && t <= 8.64e15)
48012
0
        return trunc(t) + 0.0;  /* convert -0 to +0 */
48013
0
    else
48014
0
        return NAN;
48015
0
}
48016
48017
/* The spec mandates the use of 'double' and it fixes the order
48018
   of the operations */
48019
0
static double set_date_fields(double fields[], int is_local) {
48020
0
    int64_t y;
48021
0
    double days, d, h, m1;
48022
0
    int i, m, md;
48023
    
48024
0
    m1 = fields[1];
48025
0
    m = fmod(m1, 12);
48026
0
    if (m < 0)
48027
0
        m += 12;
48028
0
    y = (int64_t)(fields[0] + floor(m1 / 12));
48029
0
    days = days_from_year(y);
48030
48031
0
    for(i = 0; i < m; i++) {
48032
0
        md = month_days[i];
48033
0
        if (i == 1)
48034
0
            md += days_in_year(y) - 365;
48035
0
        days += md;
48036
0
    }
48037
0
    days += fields[2] - 1;
48038
0
    h = fields[3] * 3600000 + fields[4] * 60000 + 
48039
0
        fields[5] * 1000 + fields[6];
48040
0
    d = days * 86400000 + h;
48041
0
    if (is_local)
48042
0
        d += getTimezoneOffset(d) * 60000;
48043
0
    return time_clip(d);
48044
0
}
48045
48046
static JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
48047
                              int argc, JSValueConst *argv, int magic)
48048
0
{
48049
    // get_date_field(obj, n, is_local)
48050
0
    double fields[9];
48051
0
    int res, n, is_local;
48052
48053
0
    is_local = magic & 0x0F;
48054
0
    n = (magic >> 4) & 0x0F;
48055
0
    res = get_date_fields(ctx, this_val, fields, is_local, 0);
48056
0
    if (res < 0)
48057
0
        return JS_EXCEPTION;
48058
0
    if (!res)
48059
0
        return JS_NAN;
48060
48061
0
    if (magic & 0x100) {    // getYear
48062
0
        fields[0] -= 1900;
48063
0
    }
48064
0
    return JS_NewFloat64(ctx, fields[n]);
48065
0
}
48066
48067
static JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
48068
                              int argc, JSValueConst *argv, int magic)
48069
0
{
48070
    // _field(obj, first_field, end_field, args, is_local)
48071
0
    double fields[9];
48072
0
    int res, first_field, end_field, is_local, i, n;
48073
0
    double d, a;
48074
48075
0
    d = NAN;
48076
0
    first_field = (magic >> 8) & 0x0F;
48077
0
    end_field = (magic >> 4) & 0x0F;
48078
0
    is_local = magic & 0x0F;
48079
48080
0
    res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0);
48081
0
    if (res < 0)
48082
0
        return JS_EXCEPTION;
48083
0
    if (res && argc > 0) {
48084
0
        n = end_field - first_field;
48085
0
        if (argc < n)
48086
0
            n = argc;
48087
0
        for(i = 0; i < n; i++) {
48088
0
            if (JS_ToFloat64(ctx, &a, argv[i]))
48089
0
                return JS_EXCEPTION;
48090
0
            if (!isfinite(a))
48091
0
                goto done;
48092
0
            fields[first_field + i] = trunc(a);
48093
0
        }
48094
0
        d = set_date_fields(fields, is_local);
48095
0
    }
48096
0
done:
48097
0
    return JS_SetThisTimeValue(ctx, this_val, d);
48098
0
}
48099
48100
/* fmt:
48101
   0: toUTCString: "Tue, 02 Jan 2018 23:04:46 GMT"
48102
   1: toString: "Wed Jan 03 2018 00:05:22 GMT+0100 (CET)"
48103
   2: toISOString: "2018-01-02T23:02:56.927Z"
48104
   3: toLocaleString: "1/2/2018, 11:40:40 PM"
48105
   part: 1=date, 2=time 3=all
48106
   XXX: should use a variant of strftime().
48107
 */
48108
static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
48109
                               int argc, JSValueConst *argv, int magic)
48110
0
{
48111
    // _string(obj, fmt, part)
48112
0
    char buf[64];
48113
0
    double fields[9];
48114
0
    int res, fmt, part, pos;
48115
0
    int y, mon, d, h, m, s, ms, wd, tz;
48116
48117
0
    fmt = (magic >> 4) & 0x0F;
48118
0
    part = magic & 0x0F;
48119
48120
0
    res = get_date_fields(ctx, this_val, fields, fmt & 1, 0);
48121
0
    if (res < 0)
48122
0
        return JS_EXCEPTION;
48123
0
    if (!res) {
48124
0
        if (fmt == 2)
48125
0
            return JS_ThrowRangeError(ctx, "Date value is NaN");
48126
0
        else
48127
0
            return JS_NewString(ctx, "Invalid Date");
48128
0
    }
48129
48130
0
    y = fields[0];
48131
0
    mon = fields[1];
48132
0
    d = fields[2];
48133
0
    h = fields[3];
48134
0
    m = fields[4];
48135
0
    s = fields[5];
48136
0
    ms = fields[6];
48137
0
    wd = fields[7];
48138
0
    tz = fields[8];
48139
48140
0
    pos = 0;
48141
48142
0
    if (part & 1) { /* date part */
48143
0
        switch(fmt) {
48144
0
        case 0:
48145
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48146
0
                            "%.3s, %02d %.3s %0*d ",
48147
0
                            day_names + wd * 3, d,
48148
0
                            month_names + mon * 3, 4 + (y < 0), y);
48149
0
            break;
48150
0
        case 1:
48151
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48152
0
                            "%.3s %.3s %02d %0*d",
48153
0
                            day_names + wd * 3,
48154
0
                            month_names + mon * 3, d, 4 + (y < 0), y);
48155
0
            if (part == 3) {
48156
0
                buf[pos++] = ' ';
48157
0
            }
48158
0
            break;
48159
0
        case 2:
48160
0
            if (y >= 0 && y <= 9999) {
48161
0
                pos += snprintf(buf + pos, sizeof(buf) - pos,
48162
0
                                "%04d", y);
48163
0
            } else {
48164
0
                pos += snprintf(buf + pos, sizeof(buf) - pos,
48165
0
                                "%+07d", y);
48166
0
            }
48167
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48168
0
                            "-%02d-%02dT", mon + 1, d);
48169
0
            break;
48170
0
        case 3:
48171
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48172
0
                            "%02d/%02d/%0*d", mon + 1, d, 4 + (y < 0), y);
48173
0
            if (part == 3) {
48174
0
                buf[pos++] = ',';
48175
0
                buf[pos++] = ' ';
48176
0
            }
48177
0
            break;
48178
0
        }
48179
0
    }
48180
0
    if (part & 2) { /* time part */
48181
0
        switch(fmt) {
48182
0
        case 0:
48183
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48184
0
                            "%02d:%02d:%02d GMT", h, m, s);
48185
0
            break;
48186
0
        case 1:
48187
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48188
0
                            "%02d:%02d:%02d GMT", h, m, s);
48189
0
            if (tz < 0) {
48190
0
                buf[pos++] = '-';
48191
0
                tz = -tz;
48192
0
            } else {
48193
0
                buf[pos++] = '+';
48194
0
            }
48195
            /* tz is >= 0, can use % */
48196
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48197
0
                            "%02d%02d", tz / 60, tz % 60);
48198
            /* XXX: tack the time zone code? */
48199
0
            break;
48200
0
        case 2:
48201
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48202
0
                            "%02d:%02d:%02d.%03dZ", h, m, s, ms);
48203
0
            break;
48204
0
        case 3:
48205
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48206
0
                            "%02d:%02d:%02d %cM", (h + 1) % 12 - 1, m, s,
48207
0
                            (h < 12) ? 'A' : 'P');
48208
0
            break;
48209
0
        }
48210
0
    }
48211
0
    return JS_NewStringLen(ctx, buf, pos);
48212
0
}
48213
48214
/* OS dependent: return the UTC time in ms since 1970. */
48215
0
static int64_t date_now(void) {
48216
0
    struct timeval tv;
48217
0
    gettimeofday(&tv, NULL);
48218
0
    return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
48219
0
}
48220
48221
static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,
48222
                                   int argc, JSValueConst *argv)
48223
0
{
48224
    // Date(y, mon, d, h, m, s, ms)
48225
0
    JSValue rv;
48226
0
    int i, n;
48227
0
    double a, val;
48228
48229
0
    if (JS_IsUndefined(new_target)) {
48230
        /* invoked as function */
48231
0
        argc = 0;
48232
0
    }
48233
0
    n = argc;
48234
0
    if (n == 0) {
48235
0
        val = date_now();
48236
0
    } else if (n == 1) {
48237
0
        JSValue v, dv;
48238
0
        if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
48239
0
            JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
48240
0
            if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data)) {
48241
0
                if (JS_ToFloat64(ctx, &val, p->u.object_data))
48242
0
                    return JS_EXCEPTION;
48243
0
                val = time_clip(val);
48244
0
                goto has_val;
48245
0
            }
48246
0
        }
48247
0
        v = JS_ToPrimitive(ctx, argv[0], HINT_NONE);
48248
0
        if (JS_IsString(v)) {
48249
0
            dv = js_Date_parse(ctx, JS_UNDEFINED, 1, (JSValueConst *)&v);
48250
0
            JS_FreeValue(ctx, v);
48251
0
            if (JS_IsException(dv))
48252
0
                return JS_EXCEPTION;
48253
0
            if (JS_ToFloat64Free(ctx, &val, dv))
48254
0
                return JS_EXCEPTION;
48255
0
        } else {
48256
0
            if (JS_ToFloat64Free(ctx, &val, v))
48257
0
                return JS_EXCEPTION;
48258
0
        }
48259
0
        val = time_clip(val);
48260
0
    } else {
48261
0
        double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
48262
0
        if (n > 7)
48263
0
            n = 7;
48264
0
        for(i = 0; i < n; i++) {
48265
0
            if (JS_ToFloat64(ctx, &a, argv[i]))
48266
0
                return JS_EXCEPTION;
48267
0
            if (!isfinite(a))
48268
0
                break;
48269
0
            fields[i] = trunc(a);
48270
0
            if (i == 0 && fields[0] >= 0 && fields[0] < 100)
48271
0
                fields[0] += 1900;
48272
0
        }
48273
0
        val = (i == n) ? set_date_fields(fields, 1) : NAN;
48274
0
    }
48275
0
has_val:
48276
#if 0
48277
    JSValueConst args[3];
48278
    args[0] = new_target;
48279
    args[1] = ctx->class_proto[JS_CLASS_DATE];
48280
    args[2] = JS_NewFloat64(ctx, val);
48281
    rv = js___date_create(ctx, JS_UNDEFINED, 3, args);
48282
#else
48283
0
    rv = js_create_from_ctor(ctx, new_target, JS_CLASS_DATE);
48284
0
    if (!JS_IsException(rv))
48285
0
        JS_SetObjectData(ctx, rv, JS_NewFloat64(ctx, val));
48286
0
#endif
48287
0
    if (!JS_IsException(rv) && JS_IsUndefined(new_target)) {
48288
        /* invoked as a function, return (new Date()).toString(); */
48289
0
        JSValue s;
48290
0
        s = get_date_string(ctx, rv, 0, NULL, 0x13);
48291
0
        JS_FreeValue(ctx, rv);
48292
0
        rv = s;
48293
0
    }
48294
0
    return rv;
48295
0
}
48296
48297
static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,
48298
                           int argc, JSValueConst *argv)
48299
0
{
48300
    // UTC(y, mon, d, h, m, s, ms)
48301
0
    double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
48302
0
    int i, n;
48303
0
    double a;
48304
48305
0
    n = argc;
48306
0
    if (n == 0)
48307
0
        return JS_NAN;
48308
0
    if (n > 7)
48309
0
        n = 7;
48310
0
    for(i = 0; i < n; i++) {
48311
0
        if (JS_ToFloat64(ctx, &a, argv[i]))
48312
0
            return JS_EXCEPTION;
48313
0
        if (!isfinite(a))
48314
0
            return JS_NAN;
48315
0
        fields[i] = trunc(a);
48316
0
        if (i == 0 && fields[0] >= 0 && fields[0] < 100)
48317
0
            fields[0] += 1900;
48318
0
    }
48319
0
    return JS_NewFloat64(ctx, set_date_fields(fields, 0));
48320
0
}
48321
48322
0
static void string_skip_spaces(JSString *sp, int *pp) {
48323
0
    while (*pp < sp->len && string_get(sp, *pp) == ' ')
48324
0
        *pp += 1;
48325
0
}
48326
48327
0
static void string_skip_non_spaces(JSString *sp, int *pp) {
48328
0
    while (*pp < sp->len && string_get(sp, *pp) != ' ')
48329
0
        *pp += 1;
48330
0
}
48331
48332
/* parse a numeric field with an optional sign if accept_sign is TRUE */
48333
0
static int string_get_digits(JSString *sp, int *pp, int64_t *pval) {
48334
0
    int64_t v = 0;
48335
0
    int c, p = *pp, p_start;
48336
    
48337
0
    if (p >= sp->len)
48338
0
        return -1;
48339
0
    p_start = p;
48340
0
    while (p < sp->len) {
48341
0
        c = string_get(sp, p);
48342
0
        if (!(c >= '0' && c <= '9')) {
48343
0
            if (p == p_start)
48344
0
                return -1;
48345
0
            else
48346
0
                break;
48347
0
        }
48348
0
        v = v * 10 + c - '0';
48349
0
        p++;
48350
0
    }
48351
0
    *pval = v;
48352
0
    *pp = p;
48353
0
    return 0;
48354
0
}
48355
48356
0
static int string_get_signed_digits(JSString *sp, int *pp, int64_t *pval) {
48357
0
    int res, sgn, p = *pp;
48358
    
48359
0
    if (p >= sp->len)
48360
0
        return -1;
48361
48362
0
    sgn = string_get(sp, p);
48363
0
    if (sgn == '-' || sgn == '+')
48364
0
        p++;
48365
 
48366
0
    res = string_get_digits(sp, &p, pval);
48367
0
    if (res == 0 && sgn == '-')
48368
0
        *pval = -*pval;
48369
0
    *pp = p;
48370
0
    return res;
48371
0
}
48372
48373
/* parse a fixed width numeric field */
48374
0
static int string_get_fixed_width_digits(JSString *sp, int *pp, int n, int64_t *pval) {
48375
0
    int64_t v = 0;
48376
0
    int i, c, p = *pp;
48377
48378
0
    for(i = 0; i < n; i++) {
48379
0
        if (p >= sp->len)
48380
0
            return -1;
48381
0
        c = string_get(sp, p);
48382
0
        if (!(c >= '0' && c <= '9'))
48383
0
            return -1;
48384
0
        v = v * 10 + c - '0';
48385
0
        p++;
48386
0
    }
48387
0
    *pval = v;
48388
0
    *pp = p;
48389
0
    return 0;
48390
0
}
48391
48392
0
static int string_get_milliseconds(JSString *sp, int *pp, int64_t *pval) {
48393
    /* parse milliseconds as a fractional part, round to nearest */
48394
    /* XXX: the spec does not indicate which rounding should be used */
48395
0
    int mul = 1000, ms = 0, p = *pp, c, p_start;
48396
0
    if (p >= sp->len)
48397
0
        return -1;
48398
0
    p_start = p;
48399
0
    while (p < sp->len) {
48400
0
        c = string_get(sp, p);
48401
0
        if (!(c >= '0' && c <= '9')) {
48402
0
            if (p == p_start)
48403
0
                return -1;
48404
0
            else
48405
0
                break;
48406
0
        }
48407
0
        if (mul == 1 && c >= '5')
48408
0
            ms += 1;
48409
0
        ms += (c - '0') * (mul /= 10);
48410
0
        p++;
48411
0
    }
48412
0
    *pval = ms;
48413
0
    *pp = p;
48414
0
    return 0;
48415
0
}
48416
48417
48418
0
static int find_abbrev(JSString *sp, int p, const char *list, int count) {
48419
0
    int n, i;
48420
48421
0
    if (p + 3 <= sp->len) {
48422
0
        for (n = 0; n < count; n++) {
48423
0
            for (i = 0; i < 3; i++) {
48424
0
                if (string_get(sp, p + i) != month_names[n * 3 + i])
48425
0
                    goto next;
48426
0
            }
48427
0
            return n;
48428
0
        next:;
48429
0
        }
48430
0
    }
48431
0
    return -1;
48432
0
}
48433
48434
0
static int string_get_month(JSString *sp, int *pp, int64_t *pval) {
48435
0
    int n;
48436
48437
0
    string_skip_spaces(sp, pp);
48438
0
    n = find_abbrev(sp, *pp, month_names, 12);
48439
0
    if (n < 0)
48440
0
        return -1;
48441
48442
0
    *pval = n;
48443
0
    *pp += 3;
48444
0
    return 0;
48445
0
}
48446
48447
static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
48448
                             int argc, JSValueConst *argv)
48449
0
{
48450
    // parse(s)
48451
0
    JSValue s, rv;
48452
0
    int64_t fields[] = { 0, 1, 1, 0, 0, 0, 0 };
48453
0
    double fields1[7];
48454
0
    int64_t tz, hh, mm;
48455
0
    double d;
48456
0
    int p, i, c, sgn, l;
48457
0
    JSString *sp;
48458
0
    BOOL is_local;
48459
    
48460
0
    rv = JS_NAN;
48461
48462
0
    s = JS_ToString(ctx, argv[0]);
48463
0
    if (JS_IsException(s))
48464
0
        return JS_EXCEPTION;
48465
    
48466
0
    sp = JS_VALUE_GET_STRING(s);
48467
0
    p = 0;
48468
0
    if (p < sp->len && (((c = string_get(sp, p)) >= '0' && c <= '9') || c == '+' || c == '-')) {
48469
        /* ISO format */
48470
        /* year field can be negative */
48471
0
        if (string_get_signed_digits(sp, &p, &fields[0]))
48472
0
            goto done;
48473
48474
0
        for (i = 1; i < 7; i++) {
48475
0
            if (p >= sp->len)
48476
0
                break;
48477
0
            switch(i) {
48478
0
            case 1:
48479
0
            case 2:
48480
0
                c = '-';
48481
0
                break;
48482
0
            case 3:
48483
0
                c = 'T';
48484
0
                break;
48485
0
            case 4:
48486
0
            case 5:
48487
0
                c = ':';
48488
0
                break;
48489
0
            case 6:
48490
0
                c = '.';
48491
0
                break;
48492
0
            }
48493
0
            if (string_get(sp, p) != c)
48494
0
                break;
48495
0
            p++;
48496
0
            if (i == 6) {
48497
0
                if (string_get_milliseconds(sp, &p, &fields[i]))
48498
0
                    goto done;
48499
0
            } else {
48500
0
                if (string_get_digits(sp, &p, &fields[i]))
48501
0
                    goto done;
48502
0
            }
48503
0
        }
48504
        /* no time: UTC by default */
48505
0
        is_local = (i > 3);
48506
0
        fields[1] -= 1;
48507
48508
        /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
48509
0
        tz = 0;
48510
0
        if (p < sp->len) {
48511
0
            sgn = string_get(sp, p);
48512
0
            if (sgn == '+' || sgn == '-') {
48513
0
                p++;
48514
0
                l = sp->len - p;
48515
0
                if (l != 4 && l != 5)
48516
0
                    goto done;
48517
0
                if (string_get_fixed_width_digits(sp, &p, 2, &hh))
48518
0
                    goto done;
48519
0
                if (l == 5) {
48520
0
                    if (string_get(sp, p) != ':')
48521
0
                        goto done;
48522
0
                    p++;
48523
0
                }
48524
0
                if (string_get_fixed_width_digits(sp, &p, 2, &mm))
48525
0
                    goto done;
48526
0
                tz = hh * 60 + mm;
48527
0
                if (sgn == '-')
48528
0
                    tz = -tz;
48529
0
                is_local = FALSE;
48530
0
            } else if (sgn == 'Z') {
48531
0
                p++;
48532
0
                is_local = FALSE;
48533
0
            } else {
48534
0
                goto done;
48535
0
            }
48536
            /* error if extraneous characters */
48537
0
            if (p != sp->len)
48538
0
                goto done;
48539
0
        }
48540
0
    } else {
48541
        /* toString or toUTCString format */
48542
        /* skip the day of the week */
48543
0
        string_skip_non_spaces(sp, &p);
48544
0
        string_skip_spaces(sp, &p);
48545
0
        if (p >= sp->len)
48546
0
            goto done;
48547
0
        c = string_get(sp, p);
48548
0
        if (c >= '0' && c <= '9') {
48549
            /* day of month first */
48550
0
            if (string_get_digits(sp, &p, &fields[2]))
48551
0
                goto done;
48552
0
            if (string_get_month(sp, &p, &fields[1]))
48553
0
                goto done;
48554
0
        } else {
48555
            /* month first */
48556
0
            if (string_get_month(sp, &p, &fields[1]))
48557
0
                goto done;
48558
0
            string_skip_spaces(sp, &p);
48559
0
            if (string_get_digits(sp, &p, &fields[2]))
48560
0
                goto done;
48561
0
        }
48562
        /* year */
48563
0
        string_skip_spaces(sp, &p);
48564
0
        if (string_get_signed_digits(sp, &p, &fields[0]))
48565
0
            goto done;
48566
48567
        /* hour, min, seconds */
48568
0
        string_skip_spaces(sp, &p);
48569
0
        for(i = 0; i < 3; i++) {
48570
0
            if (i == 1 || i == 2) {
48571
0
                if (p >= sp->len)
48572
0
                    goto done;
48573
0
                if (string_get(sp, p) != ':')
48574
0
                    goto done;
48575
0
                p++;
48576
0
            }
48577
0
            if (string_get_digits(sp, &p, &fields[3 + i]))
48578
0
                goto done;
48579
0
        }
48580
        // XXX: parse optional milliseconds?
48581
48582
        /* parse the time zone offset if present: [+-]HHmm */
48583
0
        is_local = FALSE;
48584
0
        tz = 0;
48585
0
        for (tz = 0; p < sp->len; p++) {
48586
0
            sgn = string_get(sp, p);
48587
0
            if (sgn == '+' || sgn == '-') {
48588
0
                p++;
48589
0
                if (string_get_fixed_width_digits(sp, &p, 2, &hh))
48590
0
                    goto done;
48591
0
                if (string_get_fixed_width_digits(sp, &p, 2, &mm))
48592
0
                    goto done;
48593
0
                tz = hh * 60 + mm;
48594
0
                if (sgn == '-')
48595
0
                    tz = -tz;
48596
0
                break;
48597
0
            }
48598
0
        }
48599
0
    }
48600
0
    for(i = 0; i < 7; i++)
48601
0
        fields1[i] = fields[i];
48602
0
    d = set_date_fields(fields1, is_local) - tz * 60000;
48603
0
    rv = JS_NewFloat64(ctx, d);
48604
48605
0
done:
48606
0
    JS_FreeValue(ctx, s);
48607
0
    return rv;
48608
0
}
48609
48610
static JSValue js_Date_now(JSContext *ctx, JSValueConst this_val,
48611
                           int argc, JSValueConst *argv)
48612
0
{
48613
    // now()
48614
0
    return JS_NewInt64(ctx, date_now());
48615
0
}
48616
48617
static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val,
48618
                                          int argc, JSValueConst *argv)
48619
0
{
48620
    // Symbol_toPrimitive(hint)
48621
0
    JSValueConst obj = this_val;
48622
0
    JSAtom hint = JS_ATOM_NULL;
48623
0
    int hint_num;
48624
48625
0
    if (!JS_IsObject(obj))
48626
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
48627
48628
0
    if (JS_IsString(argv[0])) {
48629
0
        hint = JS_ValueToAtom(ctx, argv[0]);
48630
0
        if (hint == JS_ATOM_NULL)
48631
0
            return JS_EXCEPTION;
48632
0
        JS_FreeAtom(ctx, hint);
48633
0
    }
48634
0
    switch (hint) {
48635
0
    case JS_ATOM_number:
48636
0
#ifdef CONFIG_BIGNUM
48637
0
    case JS_ATOM_integer:
48638
0
#endif
48639
0
        hint_num = HINT_NUMBER;
48640
0
        break;
48641
0
    case JS_ATOM_string:
48642
0
    case JS_ATOM_default:
48643
0
        hint_num = HINT_STRING;
48644
0
        break;
48645
0
    default:
48646
0
        return JS_ThrowTypeError(ctx, "invalid hint");
48647
0
    }
48648
0
    return JS_ToPrimitive(ctx, obj, hint_num | HINT_FORCE_ORDINARY);
48649
0
}
48650
48651
static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
48652
                                         int argc, JSValueConst *argv)
48653
0
{
48654
    // getTimezoneOffset()
48655
0
    double v;
48656
48657
0
    if (JS_ThisTimeValue(ctx, &v, this_val))
48658
0
        return JS_EXCEPTION;
48659
0
    if (isnan(v))
48660
0
        return JS_NAN;
48661
0
    else
48662
0
        return JS_NewInt64(ctx, getTimezoneOffset((int64_t)trunc(v)));
48663
0
}
48664
48665
static JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val,
48666
                               int argc, JSValueConst *argv)
48667
0
{
48668
    // getTime()
48669
0
    double v;
48670
48671
0
    if (JS_ThisTimeValue(ctx, &v, this_val))
48672
0
        return JS_EXCEPTION;
48673
0
    return JS_NewFloat64(ctx, v);
48674
0
}
48675
48676
static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val,
48677
                               int argc, JSValueConst *argv)
48678
0
{
48679
    // setTime(v)
48680
0
    double v;
48681
48682
0
    if (JS_ThisTimeValue(ctx, &v, this_val) || JS_ToFloat64(ctx, &v, argv[0]))
48683
0
        return JS_EXCEPTION;
48684
0
    return JS_SetThisTimeValue(ctx, this_val, time_clip(v));
48685
0
}
48686
48687
static JSValue js_date_setYear(JSContext *ctx, JSValueConst this_val,
48688
                               int argc, JSValueConst *argv)
48689
0
{
48690
    // setYear(y)
48691
0
    double y;
48692
0
    JSValueConst args[1];
48693
48694
0
    if (JS_ThisTimeValue(ctx, &y, this_val) || JS_ToFloat64(ctx, &y, argv[0]))
48695
0
        return JS_EXCEPTION;
48696
0
    y = +y;
48697
0
    if (isfinite(y)) {
48698
0
        y = trunc(y);
48699
0
        if (y >= 0 && y < 100)
48700
0
            y += 1900;
48701
0
    }
48702
0
    args[0] = JS_NewFloat64(ctx, y);
48703
0
    return set_date_field(ctx, this_val, 1, args, 0x011);
48704
0
}
48705
48706
static JSValue js_date_toJSON(JSContext *ctx, JSValueConst this_val,
48707
                              int argc, JSValueConst *argv)
48708
0
{
48709
    // toJSON(key)
48710
0
    JSValue obj, tv, method, rv;
48711
0
    double d;
48712
48713
0
    rv = JS_EXCEPTION;
48714
0
    tv = JS_UNDEFINED;
48715
48716
0
    obj = JS_ToObject(ctx, this_val);
48717
0
    tv = JS_ToPrimitive(ctx, obj, HINT_NUMBER);
48718
0
    if (JS_IsException(tv))
48719
0
        goto exception;
48720
0
    if (JS_IsNumber(tv)) {
48721
0
        if (JS_ToFloat64(ctx, &d, tv) < 0)
48722
0
            goto exception;
48723
0
        if (!isfinite(d)) {
48724
0
            rv = JS_NULL;
48725
0
            goto done;
48726
0
        }
48727
0
    }
48728
0
    method = JS_GetPropertyStr(ctx, obj, "toISOString");
48729
0
    if (JS_IsException(method))
48730
0
        goto exception;
48731
0
    if (!JS_IsFunction(ctx, method)) {
48732
0
        JS_ThrowTypeError(ctx, "object needs toISOString method");
48733
0
        JS_FreeValue(ctx, method);
48734
0
        goto exception;
48735
0
    }
48736
0
    rv = JS_CallFree(ctx, method, obj, 0, NULL);
48737
0
exception:
48738
0
done:
48739
0
    JS_FreeValue(ctx, obj);
48740
0
    JS_FreeValue(ctx, tv);
48741
0
    return rv;
48742
0
}
48743
48744
static const JSCFunctionListEntry js_date_funcs[] = {
48745
    JS_CFUNC_DEF("now", 0, js_Date_now ),
48746
    JS_CFUNC_DEF("parse", 1, js_Date_parse ),
48747
    JS_CFUNC_DEF("UTC", 7, js_Date_UTC ),
48748
};
48749
48750
static const JSCFunctionListEntry js_date_proto_funcs[] = {
48751
    JS_CFUNC_DEF("valueOf", 0, js_date_getTime ),
48752
    JS_CFUNC_MAGIC_DEF("toString", 0, get_date_string, 0x13 ),
48753
    JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_date_Symbol_toPrimitive ),
48754
    JS_CFUNC_MAGIC_DEF("toUTCString", 0, get_date_string, 0x03 ),
48755
    JS_ALIAS_DEF("toGMTString", "toUTCString" ),
48756
    JS_CFUNC_MAGIC_DEF("toISOString", 0, get_date_string, 0x23 ),
48757
    JS_CFUNC_MAGIC_DEF("toDateString", 0, get_date_string, 0x11 ),
48758
    JS_CFUNC_MAGIC_DEF("toTimeString", 0, get_date_string, 0x12 ),
48759
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, get_date_string, 0x33 ),
48760
    JS_CFUNC_MAGIC_DEF("toLocaleDateString", 0, get_date_string, 0x31 ),
48761
    JS_CFUNC_MAGIC_DEF("toLocaleTimeString", 0, get_date_string, 0x32 ),
48762
    JS_CFUNC_DEF("getTimezoneOffset", 0, js_date_getTimezoneOffset ),
48763
    JS_CFUNC_DEF("getTime", 0, js_date_getTime ),
48764
    JS_CFUNC_MAGIC_DEF("getYear", 0, get_date_field, 0x101 ),
48765
    JS_CFUNC_MAGIC_DEF("getFullYear", 0, get_date_field, 0x01 ),
48766
    JS_CFUNC_MAGIC_DEF("getUTCFullYear", 0, get_date_field, 0x00 ),
48767
    JS_CFUNC_MAGIC_DEF("getMonth", 0, get_date_field, 0x11 ),
48768
    JS_CFUNC_MAGIC_DEF("getUTCMonth", 0, get_date_field, 0x10 ),
48769
    JS_CFUNC_MAGIC_DEF("getDate", 0, get_date_field, 0x21 ),
48770
    JS_CFUNC_MAGIC_DEF("getUTCDate", 0, get_date_field, 0x20 ),
48771
    JS_CFUNC_MAGIC_DEF("getHours", 0, get_date_field, 0x31 ),
48772
    JS_CFUNC_MAGIC_DEF("getUTCHours", 0, get_date_field, 0x30 ),
48773
    JS_CFUNC_MAGIC_DEF("getMinutes", 0, get_date_field, 0x41 ),
48774
    JS_CFUNC_MAGIC_DEF("getUTCMinutes", 0, get_date_field, 0x40 ),
48775
    JS_CFUNC_MAGIC_DEF("getSeconds", 0, get_date_field, 0x51 ),
48776
    JS_CFUNC_MAGIC_DEF("getUTCSeconds", 0, get_date_field, 0x50 ),
48777
    JS_CFUNC_MAGIC_DEF("getMilliseconds", 0, get_date_field, 0x61 ),
48778
    JS_CFUNC_MAGIC_DEF("getUTCMilliseconds", 0, get_date_field, 0x60 ),
48779
    JS_CFUNC_MAGIC_DEF("getDay", 0, get_date_field, 0x71 ),
48780
    JS_CFUNC_MAGIC_DEF("getUTCDay", 0, get_date_field, 0x70 ),
48781
    JS_CFUNC_DEF("setTime", 1, js_date_setTime ),
48782
    JS_CFUNC_MAGIC_DEF("setMilliseconds", 1, set_date_field, 0x671 ),
48783
    JS_CFUNC_MAGIC_DEF("setUTCMilliseconds", 1, set_date_field, 0x670 ),
48784
    JS_CFUNC_MAGIC_DEF("setSeconds", 2, set_date_field, 0x571 ),
48785
    JS_CFUNC_MAGIC_DEF("setUTCSeconds", 2, set_date_field, 0x570 ),
48786
    JS_CFUNC_MAGIC_DEF("setMinutes", 3, set_date_field, 0x471 ),
48787
    JS_CFUNC_MAGIC_DEF("setUTCMinutes", 3, set_date_field, 0x470 ),
48788
    JS_CFUNC_MAGIC_DEF("setHours", 4, set_date_field, 0x371 ),
48789
    JS_CFUNC_MAGIC_DEF("setUTCHours", 4, set_date_field, 0x370 ),
48790
    JS_CFUNC_MAGIC_DEF("setDate", 1, set_date_field, 0x231 ),
48791
    JS_CFUNC_MAGIC_DEF("setUTCDate", 1, set_date_field, 0x230 ),
48792
    JS_CFUNC_MAGIC_DEF("setMonth", 2, set_date_field, 0x131 ),
48793
    JS_CFUNC_MAGIC_DEF("setUTCMonth", 2, set_date_field, 0x130 ),
48794
    JS_CFUNC_DEF("setYear", 1, js_date_setYear ),
48795
    JS_CFUNC_MAGIC_DEF("setFullYear", 3, set_date_field, 0x031 ),
48796
    JS_CFUNC_MAGIC_DEF("setUTCFullYear", 3, set_date_field, 0x030 ),
48797
    JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ),
48798
};
48799
48800
void JS_AddIntrinsicDate(JSContext *ctx)
48801
2
{
48802
2
    JSValueConst obj;
48803
48804
    /* Date */
48805
2
    ctx->class_proto[JS_CLASS_DATE] = JS_NewObject(ctx);
48806
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATE], js_date_proto_funcs,
48807
2
                               countof(js_date_proto_funcs));
48808
2
    obj = JS_NewGlobalCConstructor(ctx, "Date", js_date_constructor, 7,
48809
2
                                   ctx->class_proto[JS_CLASS_DATE]);
48810
2
    JS_SetPropertyFunctionList(ctx, obj, js_date_funcs, countof(js_date_funcs));
48811
2
}
48812
48813
/* eval */
48814
48815
void JS_AddIntrinsicEval(JSContext *ctx)
48816
2
{
48817
2
    ctx->eval_internal = __JS_EvalInternal;
48818
2
}
48819
48820
#ifdef CONFIG_BIGNUM
48821
48822
/* Operators */
48823
48824
static void js_operator_set_finalizer(JSRuntime *rt, JSValue val)
48825
0
{
48826
0
    JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
48827
0
    int i, j;
48828
0
    JSBinaryOperatorDefEntry *ent;
48829
    
48830
0
    if (opset) {
48831
0
        for(i = 0; i < JS_OVOP_COUNT; i++) {
48832
0
            if (opset->self_ops[i])
48833
0
                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]));
48834
0
        }
48835
0
        for(j = 0; j < opset->left.count; j++) {
48836
0
            ent = &opset->left.tab[j];
48837
0
            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
48838
0
                if (ent->ops[i])
48839
0
                    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
48840
0
            }
48841
0
        }
48842
0
        js_free_rt(rt, opset->left.tab);
48843
0
        for(j = 0; j < opset->right.count; j++) {
48844
0
            ent = &opset->right.tab[j];
48845
0
            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
48846
0
                if (ent->ops[i])
48847
0
                    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
48848
0
            }
48849
0
        }
48850
0
        js_free_rt(rt, opset->right.tab);
48851
0
        js_free_rt(rt, opset);
48852
0
    }
48853
0
}
48854
48855
static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
48856
                                 JS_MarkFunc *mark_func)
48857
0
{
48858
0
    JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
48859
0
    int i, j;
48860
0
    JSBinaryOperatorDefEntry *ent;
48861
    
48862
0
    if (opset) {
48863
0
        for(i = 0; i < JS_OVOP_COUNT; i++) {
48864
0
            if (opset->self_ops[i])
48865
0
                JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]),
48866
0
                             mark_func);
48867
0
        }
48868
0
        for(j = 0; j < opset->left.count; j++) {
48869
0
            ent = &opset->left.tab[j];
48870
0
            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
48871
0
                if (ent->ops[i])
48872
0
                    JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
48873
0
                                 mark_func);
48874
0
            }
48875
0
        }
48876
0
        for(j = 0; j < opset->right.count; j++) {
48877
0
            ent = &opset->right.tab[j];
48878
0
            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
48879
0
                if (ent->ops[i])
48880
0
                    JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
48881
0
                                 mark_func);
48882
0
            }
48883
0
        }
48884
0
    }
48885
0
}
48886
48887
48888
/* create an OperatorSet object */
48889
static JSValue js_operators_create_internal(JSContext *ctx,
48890
                                            int argc, JSValueConst *argv,
48891
                                            BOOL is_primitive)
48892
0
{
48893
0
    JSValue opset_obj, prop, obj;
48894
0
    JSOperatorSetData *opset, *opset1;
48895
0
    JSBinaryOperatorDef *def;
48896
0
    JSValueConst arg;
48897
0
    int i, j;
48898
0
    JSBinaryOperatorDefEntry *new_tab;
48899
0
    JSBinaryOperatorDefEntry *ent;
48900
0
    uint32_t op_count;
48901
48902
0
    if (ctx->rt->operator_count == UINT32_MAX) {
48903
0
        return JS_ThrowTypeError(ctx, "too many operators");
48904
0
    }
48905
0
    opset_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_OPERATOR_SET);
48906
0
    if (JS_IsException(opset_obj))
48907
0
        goto fail;
48908
0
    opset = js_mallocz(ctx, sizeof(*opset));
48909
0
    if (!opset)
48910
0
        goto fail;
48911
0
    JS_SetOpaque(opset_obj, opset);
48912
0
    if (argc >= 1) {
48913
0
        arg = argv[0];
48914
        /* self operators */
48915
0
        for(i = 0; i < JS_OVOP_COUNT; i++) {
48916
0
            prop = JS_GetPropertyStr(ctx, arg, js_overloadable_operator_names[i]);
48917
0
            if (JS_IsException(prop))
48918
0
                goto fail;
48919
0
            if (!JS_IsUndefined(prop)) {
48920
0
                if (check_function(ctx, prop)) {
48921
0
                    JS_FreeValue(ctx, prop);
48922
0
                    goto fail;
48923
0
                }
48924
0
                opset->self_ops[i] = JS_VALUE_GET_OBJ(prop);
48925
0
            }
48926
0
        }
48927
0
    }
48928
    /* left & right operators */
48929
0
    for(j = 1; j < argc; j++) {
48930
0
        arg = argv[j];
48931
0
        prop = JS_GetPropertyStr(ctx, arg, "left");
48932
0
        if (JS_IsException(prop))
48933
0
            goto fail;
48934
0
        def = &opset->right;
48935
0
        if (JS_IsUndefined(prop)) {
48936
0
            prop = JS_GetPropertyStr(ctx, arg, "right");
48937
0
            if (JS_IsException(prop))
48938
0
                goto fail;
48939
0
            if (JS_IsUndefined(prop)) {
48940
0
                JS_ThrowTypeError(ctx, "left or right property must be present");
48941
0
                goto fail;
48942
0
            }
48943
0
            def = &opset->left;
48944
0
        }
48945
        /* get the operator set */
48946
0
        obj = JS_GetProperty(ctx, prop, JS_ATOM_prototype);
48947
0
        JS_FreeValue(ctx, prop);
48948
0
        if (JS_IsException(obj))
48949
0
            goto fail;
48950
0
        prop = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
48951
0
        JS_FreeValue(ctx, obj);
48952
0
        if (JS_IsException(prop))
48953
0
            goto fail;
48954
0
        opset1 = JS_GetOpaque2(ctx, prop, JS_CLASS_OPERATOR_SET);
48955
0
        if (!opset1) {
48956
0
            JS_FreeValue(ctx, prop);
48957
0
            goto fail;
48958
0
        }
48959
0
        op_count = opset1->operator_counter;
48960
0
        JS_FreeValue(ctx, prop);
48961
        
48962
        /* we assume there are few entries */
48963
0
        new_tab = js_realloc(ctx, def->tab,
48964
0
                             (def->count + 1) * sizeof(def->tab[0]));
48965
0
        if (!new_tab)
48966
0
            goto fail;
48967
0
        def->tab = new_tab;
48968
0
        def->count++;
48969
0
        ent = def->tab + def->count - 1;
48970
0
        memset(ent, 0, sizeof(def->tab[0]));
48971
0
        ent->operator_index = op_count;
48972
        
48973
0
        for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
48974
0
            prop = JS_GetPropertyStr(ctx, arg,
48975
0
                                     js_overloadable_operator_names[i]);
48976
0
            if (JS_IsException(prop))
48977
0
                goto fail;
48978
0
            if (!JS_IsUndefined(prop)) {
48979
0
                if (check_function(ctx, prop)) {
48980
0
                    JS_FreeValue(ctx, prop);
48981
0
                    goto fail;
48982
0
                }
48983
0
                ent->ops[i] = JS_VALUE_GET_OBJ(prop);
48984
0
            }
48985
0
        }
48986
0
    }
48987
0
    opset->is_primitive = is_primitive;
48988
0
    opset->operator_counter = ctx->rt->operator_count++;
48989
0
    return opset_obj;
48990
0
 fail:
48991
0
    JS_FreeValue(ctx, opset_obj);
48992
0
    return JS_EXCEPTION;
48993
0
}
48994
48995
static JSValue js_operators_create(JSContext *ctx, JSValueConst this_val,
48996
                                int argc, JSValueConst *argv)
48997
0
{
48998
0
    return js_operators_create_internal(ctx, argc, argv, FALSE);
48999
0
}
49000
49001
static JSValue js_operators_updateBigIntOperators(JSContext *ctx, JSValueConst this_val,
49002
                                                  int argc, JSValueConst *argv)
49003
0
{
49004
0
    JSValue opset_obj, prop;
49005
0
    JSOperatorSetData *opset;
49006
0
    const JSOverloadableOperatorEnum ops[2] = { JS_OVOP_DIV, JS_OVOP_POW };
49007
0
    JSOverloadableOperatorEnum op;
49008
0
    int i;
49009
    
49010
0
    opset_obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
49011
0
                               JS_ATOM_Symbol_operatorSet);
49012
0
    if (JS_IsException(opset_obj))
49013
0
        goto fail;
49014
0
    opset = JS_GetOpaque2(ctx, opset_obj, JS_CLASS_OPERATOR_SET);
49015
0
    if (!opset)
49016
0
        goto fail;
49017
0
    for(i = 0; i < countof(ops); i++) {
49018
0
        op = ops[i];
49019
0
        prop = JS_GetPropertyStr(ctx, argv[0],
49020
0
                                 js_overloadable_operator_names[op]);
49021
0
        if (JS_IsException(prop))
49022
0
            goto fail;
49023
0
        if (!JS_IsUndefined(prop)) {
49024
0
            if (!JS_IsNull(prop) && check_function(ctx, prop)) {
49025
0
                JS_FreeValue(ctx, prop);
49026
0
                goto fail;
49027
0
            }
49028
0
            if (opset->self_ops[op])
49029
0
                JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[op]));
49030
0
            if (JS_IsNull(prop)) {
49031
0
                opset->self_ops[op] = NULL;
49032
0
            } else {
49033
0
                opset->self_ops[op] = JS_VALUE_GET_PTR(prop);
49034
0
            }
49035
0
        }
49036
0
    }
49037
0
    JS_FreeValue(ctx, opset_obj);
49038
0
    return JS_UNDEFINED;
49039
0
 fail:
49040
0
    JS_FreeValue(ctx, opset_obj);
49041
0
    return JS_EXCEPTION;
49042
0
}
49043
49044
static int js_operators_set_default(JSContext *ctx, JSValueConst obj)
49045
0
{
49046
0
    JSValue opset_obj;
49047
49048
0
    if (!JS_IsObject(obj)) /* in case the prototype is not defined */
49049
0
        return 0;
49050
0
    opset_obj = js_operators_create_internal(ctx, 0, NULL, TRUE);
49051
0
    if (JS_IsException(opset_obj))
49052
0
        return -1;
49053
    /* cannot be modified by the user */
49054
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_operatorSet,
49055
0
                           opset_obj, 0);
49056
0
    return 0;
49057
0
}
49058
49059
static JSValue js_dummy_operators_ctor(JSContext *ctx, JSValueConst new_target,
49060
                                       int argc, JSValueConst *argv)
49061
0
{
49062
0
    return js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
49063
0
}
49064
49065
static JSValue js_global_operators(JSContext *ctx, JSValueConst this_val,
49066
                                   int argc, JSValueConst *argv)
49067
0
{
49068
0
    JSValue func_obj, proto, opset_obj;
49069
49070
0
    func_obj = JS_UNDEFINED;
49071
0
    proto = JS_NewObject(ctx);
49072
0
    if (JS_IsException(proto))
49073
0
        return JS_EXCEPTION;
49074
0
    opset_obj = js_operators_create_internal(ctx, argc, argv, FALSE);
49075
0
    if (JS_IsException(opset_obj))
49076
0
        goto fail;
49077
0
    JS_DefinePropertyValue(ctx, proto, JS_ATOM_Symbol_operatorSet,
49078
0
                           opset_obj, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
49079
0
    func_obj = JS_NewCFunction2(ctx, js_dummy_operators_ctor, "Operators",
49080
0
                                0, JS_CFUNC_constructor, 0);
49081
0
    if (JS_IsException(func_obj))
49082
0
        goto fail;
49083
0
    JS_SetConstructor2(ctx, func_obj, proto,
49084
0
                       0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
49085
0
    JS_FreeValue(ctx, proto);
49086
0
    return func_obj;
49087
0
 fail:
49088
0
    JS_FreeValue(ctx, proto);
49089
0
    JS_FreeValue(ctx, func_obj);
49090
0
    return JS_EXCEPTION;
49091
0
}
49092
49093
static const JSCFunctionListEntry js_operators_funcs[] = {
49094
    JS_CFUNC_DEF("create", 1, js_operators_create ),
49095
    JS_CFUNC_DEF("updateBigIntOperators", 2, js_operators_updateBigIntOperators ),
49096
};
49097
49098
/* must be called after all overloadable base types are initialized */
49099
void JS_AddIntrinsicOperators(JSContext *ctx)
49100
0
{
49101
0
    JSValue obj;
49102
49103
0
    ctx->allow_operator_overloading = TRUE;
49104
0
    obj = JS_NewCFunction(ctx, js_global_operators, "Operators", 1);
49105
0
    JS_SetPropertyFunctionList(ctx, obj,
49106
0
                               js_operators_funcs,
49107
0
                               countof(js_operators_funcs));
49108
0
    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Operators,
49109
0
                           obj,
49110
0
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
49111
    /* add default operatorSets */
49112
0
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BOOLEAN]);
49113
0
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_NUMBER]);
49114
0
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_STRING]);
49115
0
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_INT]);
49116
0
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT]);
49117
0
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
49118
0
}
49119
49120
/* BigInt */
49121
49122
static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
49123
0
{
49124
0
    uint32_t tag;
49125
49126
0
 redo:
49127
0
    tag = JS_VALUE_GET_NORM_TAG(val);
49128
0
    switch(tag) {
49129
0
    case JS_TAG_INT:
49130
0
    case JS_TAG_BOOL:
49131
0
        val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));
49132
0
        break;
49133
0
    case JS_TAG_BIG_INT:
49134
0
        break;
49135
0
    case JS_TAG_FLOAT64:
49136
0
    case JS_TAG_BIG_FLOAT:
49137
0
        {
49138
0
            bf_t *a, a_s;
49139
            
49140
0
            a = JS_ToBigFloat(ctx, &a_s, val);
49141
0
            if (!bf_is_finite(a)) {
49142
0
                JS_FreeValue(ctx, val);
49143
0
                val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint");
49144
0
            } else {
49145
0
                JSValue val1 = JS_NewBigInt(ctx);
49146
0
                bf_t *r;
49147
0
                int ret;
49148
0
                if (JS_IsException(val1)) {
49149
0
                    JS_FreeValue(ctx, val);
49150
0
                    return JS_EXCEPTION;
49151
0
                }
49152
0
                r = JS_GetBigInt(val1);
49153
0
                ret = bf_set(r, a);
49154
0
                ret |= bf_rint(r, BF_RNDZ);
49155
0
                JS_FreeValue(ctx, val);
49156
0
                if (ret & BF_ST_MEM_ERROR) {
49157
0
                    JS_FreeValue(ctx, val1);
49158
0
                    val = JS_ThrowOutOfMemory(ctx);
49159
0
                } else if (ret & BF_ST_INEXACT) {
49160
0
                    JS_FreeValue(ctx, val1);
49161
0
                    val = JS_ThrowRangeError(ctx, "cannot convert to bigint: not an integer");
49162
0
                } else {
49163
0
                    val = JS_CompactBigInt(ctx, val1);
49164
0
                }
49165
0
            }
49166
0
            if (a == &a_s)
49167
0
                bf_delete(a);
49168
0
        }
49169
0
        break;
49170
0
    case JS_TAG_BIG_DECIMAL:
49171
0
        val = JS_ToStringFree(ctx, val);
49172
0
         if (JS_IsException(val))
49173
0
            break;
49174
0
        goto redo;
49175
0
    case JS_TAG_STRING:
49176
0
        val = JS_StringToBigIntErr(ctx, val);
49177
0
        break;
49178
0
    case JS_TAG_OBJECT:
49179
0
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
49180
0
        if (JS_IsException(val))
49181
0
            break;
49182
0
        goto redo;
49183
0
    case JS_TAG_NULL:
49184
0
    case JS_TAG_UNDEFINED:
49185
0
    default:
49186
0
        JS_FreeValue(ctx, val);
49187
0
        return JS_ThrowTypeError(ctx, "cannot convert to bigint");
49188
0
    }
49189
0
    return val;
49190
0
}
49191
49192
static JSValue js_bigint_constructor(JSContext *ctx,
49193
                                     JSValueConst new_target,
49194
                                     int argc, JSValueConst *argv)
49195
0
{
49196
0
    if (!JS_IsUndefined(new_target))
49197
0
        return JS_ThrowTypeError(ctx, "not a constructor");
49198
0
    return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
49199
0
}
49200
49201
static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
49202
0
{
49203
0
    if (JS_IsBigInt(ctx, this_val))
49204
0
        return JS_DupValue(ctx, this_val);
49205
49206
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
49207
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
49208
0
        if (p->class_id == JS_CLASS_BIG_INT) {
49209
0
            if (JS_IsBigInt(ctx, p->u.object_data))
49210
0
                return JS_DupValue(ctx, p->u.object_data);
49211
0
        }
49212
0
    }
49213
0
    return JS_ThrowTypeError(ctx, "not a bigint");
49214
0
}
49215
49216
static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val,
49217
                                  int argc, JSValueConst *argv)
49218
0
{
49219
0
    JSValue val;
49220
0
    int base;
49221
0
    JSValue ret;
49222
49223
0
    val = js_thisBigIntValue(ctx, this_val);
49224
0
    if (JS_IsException(val))
49225
0
        return val;
49226
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
49227
0
        base = 10;
49228
0
    } else {
49229
0
        base = js_get_radix(ctx, argv[0]);
49230
0
        if (base < 0)
49231
0
            goto fail;
49232
0
    }
49233
0
    ret = js_bigint_to_string1(ctx, val, base);
49234
0
    JS_FreeValue(ctx, val);
49235
0
    return ret;
49236
0
 fail:
49237
0
    JS_FreeValue(ctx, val);
49238
0
    return JS_EXCEPTION;
49239
0
}
49240
49241
static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val,
49242
                                 int argc, JSValueConst *argv)
49243
0
{
49244
0
    return js_thisBigIntValue(ctx, this_val);
49245
0
}
49246
49247
static JSValue js_bigint_div(JSContext *ctx,
49248
                              JSValueConst this_val,
49249
                              int argc, JSValueConst *argv, int magic)
49250
0
{
49251
0
    bf_t a_s, b_s, *a, *b, *r, *q;
49252
0
    int status;
49253
0
    JSValue q_val, r_val;
49254
    
49255
0
    q_val = JS_NewBigInt(ctx);
49256
0
    if (JS_IsException(q_val))
49257
0
        return JS_EXCEPTION;
49258
0
    r_val = JS_NewBigInt(ctx);
49259
0
    if (JS_IsException(r_val))
49260
0
        goto fail;
49261
0
    b = NULL;
49262
0
    a = JS_ToBigInt(ctx, &a_s, argv[0]);
49263
0
    if (!a)
49264
0
        goto fail;
49265
0
    b = JS_ToBigInt(ctx, &b_s, argv[1]);
49266
0
    if (!b) {
49267
0
        JS_FreeBigInt(ctx, a, &a_s);
49268
0
        goto fail;
49269
0
    }
49270
0
    q = JS_GetBigInt(q_val);
49271
0
    r = JS_GetBigInt(r_val);
49272
0
    status = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, magic & 0xf);
49273
0
    JS_FreeBigInt(ctx, a, &a_s);
49274
0
    JS_FreeBigInt(ctx, b, &b_s);
49275
0
    if (unlikely(status)) {
49276
0
        throw_bf_exception(ctx, status);
49277
0
        goto fail;
49278
0
    }
49279
0
    q_val = JS_CompactBigInt(ctx, q_val);
49280
0
    if (magic & 0x10) {
49281
0
        JSValue ret;
49282
0
        ret = JS_NewArray(ctx);
49283
0
        if (JS_IsException(ret))
49284
0
            goto fail;
49285
0
        JS_SetPropertyUint32(ctx, ret, 0, q_val);
49286
0
        JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, r_val));
49287
0
        return ret;
49288
0
    } else {
49289
0
        JS_FreeValue(ctx, r_val);
49290
0
        return q_val;
49291
0
    }
49292
0
 fail:
49293
0
    JS_FreeValue(ctx, q_val);
49294
0
    JS_FreeValue(ctx, r_val);
49295
0
    return JS_EXCEPTION;
49296
0
}
49297
49298
static JSValue js_bigint_sqrt(JSContext *ctx,
49299
                               JSValueConst this_val,
49300
                               int argc, JSValueConst *argv, int magic)
49301
0
{
49302
0
    bf_t a_s, *a, *r, *rem;
49303
0
    int status;
49304
0
    JSValue r_val, rem_val;
49305
    
49306
0
    r_val = JS_NewBigInt(ctx);
49307
0
    if (JS_IsException(r_val))
49308
0
        return JS_EXCEPTION;
49309
0
    rem_val = JS_NewBigInt(ctx);
49310
0
    if (JS_IsException(rem_val))
49311
0
        return JS_EXCEPTION;
49312
0
    r = JS_GetBigInt(r_val);
49313
0
    rem = JS_GetBigInt(rem_val);
49314
49315
0
    a = JS_ToBigInt(ctx, &a_s, argv[0]);
49316
0
    if (!a)
49317
0
        goto fail;
49318
0
    status = bf_sqrtrem(r, rem, a);
49319
0
    JS_FreeBigInt(ctx, a, &a_s);
49320
0
    if (unlikely(status & ~BF_ST_INEXACT)) {
49321
0
        throw_bf_exception(ctx, status);
49322
0
        goto fail;
49323
0
    }
49324
0
    r_val = JS_CompactBigInt(ctx, r_val);
49325
0
    if (magic) {
49326
0
        JSValue ret;
49327
0
        ret = JS_NewArray(ctx);
49328
0
        if (JS_IsException(ret))
49329
0
            goto fail;
49330
0
        JS_SetPropertyUint32(ctx, ret, 0, r_val);
49331
0
        JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, rem_val));
49332
0
        return ret;
49333
0
    } else {
49334
0
        JS_FreeValue(ctx, rem_val);
49335
0
        return r_val;
49336
0
    }
49337
0
 fail:
49338
0
    JS_FreeValue(ctx, r_val);
49339
0
    JS_FreeValue(ctx, rem_val);
49340
0
    return JS_EXCEPTION;
49341
0
}
49342
49343
static JSValue js_bigint_op1(JSContext *ctx,
49344
                              JSValueConst this_val,
49345
                              int argc, JSValueConst *argv,
49346
                              int magic)
49347
0
{
49348
0
    bf_t a_s, *a;
49349
0
    int64_t res;
49350
49351
0
    a = JS_ToBigInt(ctx, &a_s, argv[0]);
49352
0
    if (!a)
49353
0
        return JS_EXCEPTION;
49354
0
    switch(magic) {
49355
0
    case 0: /* floorLog2 */
49356
0
        if (a->sign || a->expn <= 0) {
49357
0
            res = -1;
49358
0
        } else {
49359
0
            res = a->expn - 1;
49360
0
        }
49361
0
        break;
49362
0
    case 1: /* ctz */
49363
0
        if (bf_is_zero(a)) {
49364
0
            res = -1;
49365
0
        } else {
49366
0
            res = bf_get_exp_min(a);
49367
0
        }
49368
0
        break;
49369
0
    default:
49370
0
        abort();
49371
0
    }
49372
0
    JS_FreeBigInt(ctx, a, &a_s);
49373
0
    return JS_NewBigInt64(ctx, res);
49374
0
}
49375
49376
static JSValue js_bigint_asUintN(JSContext *ctx,
49377
                                  JSValueConst this_val,
49378
                                  int argc, JSValueConst *argv, int asIntN)
49379
0
{
49380
0
    uint64_t bits;
49381
0
    bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s;
49382
0
    JSValue res;
49383
    
49384
0
    if (JS_ToIndex(ctx, &bits, argv[0]))
49385
0
        return JS_EXCEPTION;
49386
0
    res = JS_NewBigInt(ctx);
49387
0
    if (JS_IsException(res))
49388
0
        return JS_EXCEPTION;
49389
0
    r = JS_GetBigInt(res);
49390
0
    a = JS_ToBigInt(ctx, &a_s, argv[1]);
49391
0
    if (!a) {
49392
0
        JS_FreeValue(ctx, res);
49393
0
        return JS_EXCEPTION;
49394
0
    }
49395
    /* XXX: optimize */
49396
0
    r = JS_GetBigInt(res);
49397
0
    bf_init(ctx->bf_ctx, mask);
49398
0
    bf_set_ui(mask, 1);
49399
0
    bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
49400
0
    bf_add_si(mask, mask, -1, BF_PREC_INF, BF_RNDZ);
49401
0
    bf_logic_and(r, a, mask);
49402
0
    if (asIntN && bits != 0) {
49403
0
        bf_set_ui(mask, 1);
49404
0
        bf_mul_2exp(mask, bits - 1, BF_PREC_INF, BF_RNDZ);
49405
0
        if (bf_cmpu(r, mask) >= 0) {
49406
0
            bf_set_ui(mask, 1);
49407
0
            bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
49408
0
            bf_sub(r, r, mask, BF_PREC_INF, BF_RNDZ);
49409
0
        }
49410
0
    }
49411
0
    bf_delete(mask);
49412
0
    JS_FreeBigInt(ctx, a, &a_s);
49413
0
    return JS_CompactBigInt(ctx, res);
49414
0
}
49415
49416
static const JSCFunctionListEntry js_bigint_funcs[] = {
49417
    JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ),
49418
    JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ),
49419
    /* QuickJS extensions */
49420
    JS_CFUNC_MAGIC_DEF("tdiv", 2, js_bigint_div, BF_RNDZ ),
49421
    JS_CFUNC_MAGIC_DEF("fdiv", 2, js_bigint_div, BF_RNDD ),
49422
    JS_CFUNC_MAGIC_DEF("cdiv", 2, js_bigint_div, BF_RNDU ),
49423
    JS_CFUNC_MAGIC_DEF("ediv", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN ),
49424
    JS_CFUNC_MAGIC_DEF("tdivrem", 2, js_bigint_div, BF_RNDZ | 0x10 ),
49425
    JS_CFUNC_MAGIC_DEF("fdivrem", 2, js_bigint_div, BF_RNDD | 0x10 ),
49426
    JS_CFUNC_MAGIC_DEF("cdivrem", 2, js_bigint_div, BF_RNDU | 0x10 ),
49427
    JS_CFUNC_MAGIC_DEF("edivrem", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN | 0x10 ),
49428
    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigint_sqrt, 0 ),
49429
    JS_CFUNC_MAGIC_DEF("sqrtrem", 1, js_bigint_sqrt, 1 ),
49430
    JS_CFUNC_MAGIC_DEF("floorLog2", 1, js_bigint_op1, 0 ),
49431
    JS_CFUNC_MAGIC_DEF("ctz", 1, js_bigint_op1, 1 ),
49432
};
49433
49434
static const JSCFunctionListEntry js_bigint_proto_funcs[] = {
49435
    JS_CFUNC_DEF("toString", 0, js_bigint_toString ),
49436
    JS_CFUNC_DEF("valueOf", 0, js_bigint_valueOf ),
49437
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "BigInt", JS_PROP_CONFIGURABLE ),
49438
};
49439
49440
void JS_AddIntrinsicBigInt(JSContext *ctx)
49441
2
{
49442
2
    JSRuntime *rt = ctx->rt;
49443
2
    JSValueConst obj1;
49444
49445
2
    rt->bigint_ops.to_string = js_bigint_to_string;
49446
2
    rt->bigint_ops.from_string = js_string_to_bigint;
49447
2
    rt->bigint_ops.unary_arith = js_unary_arith_bigint;
49448
2
    rt->bigint_ops.binary_arith = js_binary_arith_bigint;
49449
2
    rt->bigint_ops.compare = js_compare_bigfloat;
49450
    
49451
2
    ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx);
49452
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
49453
2
                               js_bigint_proto_funcs,
49454
2
                               countof(js_bigint_proto_funcs));
49455
2
    obj1 = JS_NewGlobalCConstructor(ctx, "BigInt", js_bigint_constructor, 1,
49456
2
                                    ctx->class_proto[JS_CLASS_BIG_INT]);
49457
2
    JS_SetPropertyFunctionList(ctx, obj1, js_bigint_funcs,
49458
2
                               countof(js_bigint_funcs));
49459
2
}
49460
49461
/* BigFloat */
49462
49463
static JSValue js_thisBigFloatValue(JSContext *ctx, JSValueConst this_val)
49464
0
{
49465
0
    if (JS_IsBigFloat(this_val))
49466
0
        return JS_DupValue(ctx, this_val);
49467
49468
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
49469
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
49470
0
        if (p->class_id == JS_CLASS_BIG_FLOAT) {
49471
0
            if (JS_IsBigFloat(p->u.object_data))
49472
0
                return JS_DupValue(ctx, p->u.object_data);
49473
0
        }
49474
0
    }
49475
0
    return JS_ThrowTypeError(ctx, "not a bigfloat");
49476
0
}
49477
49478
static JSValue js_bigfloat_toString(JSContext *ctx, JSValueConst this_val,
49479
                                    int argc, JSValueConst *argv)
49480
0
{
49481
0
    JSValue val;
49482
0
    int base;
49483
0
    JSValue ret;
49484
49485
0
    val = js_thisBigFloatValue(ctx, this_val);
49486
0
    if (JS_IsException(val))
49487
0
        return val;
49488
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
49489
0
        base = 10;
49490
0
    } else {
49491
0
        base = js_get_radix(ctx, argv[0]);
49492
0
        if (base < 0)
49493
0
            goto fail;
49494
0
    }
49495
0
    ret = js_ftoa(ctx, val, base, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
49496
0
    JS_FreeValue(ctx, val);
49497
0
    return ret;
49498
0
 fail:
49499
0
    JS_FreeValue(ctx, val);
49500
0
    return JS_EXCEPTION;
49501
0
}
49502
49503
static JSValue js_bigfloat_valueOf(JSContext *ctx, JSValueConst this_val,
49504
                                   int argc, JSValueConst *argv)
49505
0
{
49506
0
    return js_thisBigFloatValue(ctx, this_val);
49507
0
}
49508
49509
static int bigfloat_get_rnd_mode(JSContext *ctx, JSValueConst val)
49510
0
{
49511
0
    int rnd_mode;
49512
0
    if (JS_ToInt32Sat(ctx, &rnd_mode, val))
49513
0
        return -1;
49514
0
    if (rnd_mode < BF_RNDN || rnd_mode > BF_RNDF) {
49515
0
        JS_ThrowRangeError(ctx, "invalid rounding mode");
49516
0
        return -1;
49517
0
    }
49518
0
    return rnd_mode;
49519
0
}
49520
49521
static JSValue js_bigfloat_toFixed(JSContext *ctx, JSValueConst this_val,
49522
                                 int argc, JSValueConst *argv)
49523
0
{
49524
0
    JSValue val, ret;
49525
0
    int64_t f;
49526
0
    int rnd_mode, radix;
49527
49528
0
    val = js_thisBigFloatValue(ctx, this_val);
49529
0
    if (JS_IsException(val))
49530
0
        return val;
49531
0
    if (JS_ToInt64Sat(ctx, &f, argv[0]))
49532
0
        goto fail;
49533
0
    if (f < 0 || f > BF_PREC_MAX) {
49534
0
        JS_ThrowRangeError(ctx, "invalid number of digits");
49535
0
        goto fail;
49536
0
    }
49537
0
    rnd_mode = BF_RNDNA;
49538
0
    radix = 10;
49539
    /* XXX: swap parameter order for rounding mode and radix */
49540
0
    if (argc > 1) {
49541
0
        rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
49542
0
        if (rnd_mode < 0)
49543
0
            goto fail;
49544
0
    }
49545
0
    if (argc > 2) {
49546
0
        radix = js_get_radix(ctx, argv[2]);
49547
0
        if (radix < 0)
49548
0
            goto fail;
49549
0
    }
49550
0
    ret = js_ftoa(ctx, val, radix, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
49551
0
    JS_FreeValue(ctx, val);
49552
0
    return ret;
49553
0
 fail:
49554
0
    JS_FreeValue(ctx, val);
49555
0
    return JS_EXCEPTION;
49556
0
}
49557
49558
static BOOL js_bigfloat_is_finite(JSContext *ctx, JSValueConst val)
49559
0
{
49560
0
    BOOL res;
49561
0
    uint32_t tag;
49562
49563
0
    tag = JS_VALUE_GET_NORM_TAG(val);
49564
0
    switch(tag) {
49565
0
    case JS_TAG_BIG_FLOAT:
49566
0
        {
49567
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
49568
0
            res = bf_is_finite(&p->num);
49569
0
        }
49570
0
        break;
49571
0
    default:
49572
0
        res = FALSE;
49573
0
        break;
49574
0
    }
49575
0
    return res;
49576
0
}
49577
49578
static JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val,
49579
                                       int argc, JSValueConst *argv)
49580
0
{
49581
0
    JSValue val, ret;
49582
0
    int64_t f;
49583
0
    int rnd_mode, radix;
49584
49585
0
    val = js_thisBigFloatValue(ctx, this_val);
49586
0
    if (JS_IsException(val))
49587
0
        return val;
49588
0
    if (JS_ToInt64Sat(ctx, &f, argv[0]))
49589
0
        goto fail;
49590
0
    if (!js_bigfloat_is_finite(ctx, val)) {
49591
0
        ret = JS_ToString(ctx, val);
49592
0
    } else if (JS_IsUndefined(argv[0])) {
49593
0
        ret = js_ftoa(ctx, val, 10, 0,
49594
0
                      BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
49595
0
    } else {
49596
0
        if (f < 0 || f > BF_PREC_MAX) {
49597
0
            JS_ThrowRangeError(ctx, "invalid number of digits");
49598
0
            goto fail;
49599
0
        }
49600
0
        rnd_mode = BF_RNDNA;
49601
0
        radix = 10;
49602
0
        if (argc > 1) {
49603
0
            rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
49604
0
            if (rnd_mode < 0)
49605
0
                goto fail;
49606
0
        }
49607
0
        if (argc > 2) {
49608
0
            radix = js_get_radix(ctx, argv[2]);
49609
0
            if (radix < 0)
49610
0
                goto fail;
49611
0
        }
49612
0
        ret = js_ftoa(ctx, val, radix, f + 1,
49613
0
                      rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
49614
0
    }
49615
0
    JS_FreeValue(ctx, val);
49616
0
    return ret;
49617
0
 fail:
49618
0
    JS_FreeValue(ctx, val);
49619
0
    return JS_EXCEPTION;
49620
0
}
49621
49622
static JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val,
49623
                                     int argc, JSValueConst *argv)
49624
0
{
49625
0
    JSValue val, ret;
49626
0
    int64_t p;
49627
0
    int rnd_mode, radix;
49628
49629
0
    val = js_thisBigFloatValue(ctx, this_val);
49630
0
    if (JS_IsException(val))
49631
0
        return val;
49632
0
    if (JS_IsUndefined(argv[0]))
49633
0
        goto to_string;
49634
0
    if (JS_ToInt64Sat(ctx, &p, argv[0]))
49635
0
        goto fail;
49636
0
    if (!js_bigfloat_is_finite(ctx, val)) {
49637
0
    to_string:
49638
0
        ret = JS_ToString(ctx, this_val);
49639
0
    } else {
49640
0
        if (p < 1 || p > BF_PREC_MAX) {
49641
0
            JS_ThrowRangeError(ctx, "invalid number of digits");
49642
0
            goto fail;
49643
0
        }
49644
0
        rnd_mode = BF_RNDNA;
49645
0
        radix = 10;
49646
0
        if (argc > 1) {
49647
0
            rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
49648
0
            if (rnd_mode < 0)
49649
0
                goto fail;
49650
0
        }
49651
0
        if (argc > 2) {
49652
0
            radix = js_get_radix(ctx, argv[2]);
49653
0
            if (radix < 0)
49654
0
                goto fail;
49655
0
        }
49656
0
        ret = js_ftoa(ctx, val, radix, p, rnd_mode | BF_FTOA_FORMAT_FIXED);
49657
0
    }
49658
0
    JS_FreeValue(ctx, val);
49659
0
    return ret;
49660
0
 fail:
49661
0
    JS_FreeValue(ctx, val);
49662
0
    return JS_EXCEPTION;
49663
0
}
49664
49665
static const JSCFunctionListEntry js_bigfloat_proto_funcs[] = {
49666
    JS_CFUNC_DEF("toString", 0, js_bigfloat_toString ),
49667
    JS_CFUNC_DEF("valueOf", 0, js_bigfloat_valueOf ),
49668
    JS_CFUNC_DEF("toPrecision", 1, js_bigfloat_toPrecision ),
49669
    JS_CFUNC_DEF("toFixed", 1, js_bigfloat_toFixed ),
49670
    JS_CFUNC_DEF("toExponential", 1, js_bigfloat_toExponential ),
49671
};
49672
49673
static JSValue js_bigfloat_constructor(JSContext *ctx,
49674
                                       JSValueConst new_target,
49675
                                       int argc, JSValueConst *argv)
49676
0
{
49677
0
    JSValue val;
49678
0
    if (!JS_IsUndefined(new_target))
49679
0
        return JS_ThrowTypeError(ctx, "not a constructor");
49680
0
    if (argc == 0) {
49681
0
        bf_t *r;
49682
0
        val = JS_NewBigFloat(ctx);
49683
0
        if (JS_IsException(val))
49684
0
            return val;
49685
0
        r = JS_GetBigFloat(val);
49686
0
        bf_set_zero(r, 0);
49687
0
    } else {
49688
0
        val = JS_DupValue(ctx, argv[0]);
49689
0
    redo:
49690
0
        switch(JS_VALUE_GET_NORM_TAG(val)) {
49691
0
        case JS_TAG_BIG_FLOAT:
49692
0
            break;
49693
0
        case JS_TAG_FLOAT64:
49694
0
            {
49695
0
                bf_t *r;
49696
0
                double d = JS_VALUE_GET_FLOAT64(val);
49697
0
                val = JS_NewBigFloat(ctx);
49698
0
                if (JS_IsException(val))
49699
0
                    break;
49700
0
                r = JS_GetBigFloat(val);
49701
0
                if (bf_set_float64(r, d))
49702
0
                    goto fail;
49703
0
            }
49704
0
            break;
49705
0
        case JS_TAG_INT:
49706
0
            {
49707
0
                bf_t *r;
49708
0
                int32_t v = JS_VALUE_GET_INT(val);
49709
0
                val = JS_NewBigFloat(ctx);
49710
0
                if (JS_IsException(val))
49711
0
                    break;
49712
0
                r = JS_GetBigFloat(val);
49713
0
                if (bf_set_si(r, v))
49714
0
                    goto fail;
49715
0
            }
49716
0
            break;
49717
0
        case JS_TAG_BIG_INT:
49718
            /* We keep the full precision of the integer */
49719
0
            {
49720
0
                JSBigFloat *p = JS_VALUE_GET_PTR(val);
49721
0
                val = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
49722
0
            }
49723
0
            break;
49724
0
        case JS_TAG_BIG_DECIMAL:
49725
0
            val = JS_ToStringFree(ctx, val);
49726
0
            if (JS_IsException(val))
49727
0
                break;
49728
0
            goto redo;
49729
0
        case JS_TAG_STRING:
49730
0
            {
49731
0
                const char *str, *p;
49732
0
                size_t len;
49733
0
                int err;
49734
49735
0
                str = JS_ToCStringLen(ctx, &len, val);
49736
0
                JS_FreeValue(ctx, val);
49737
0
                if (!str)
49738
0
                    return JS_EXCEPTION;
49739
0
                p = str;
49740
0
                p += skip_spaces(p);
49741
0
                if ((p - str) == len) {
49742
0
                    bf_t *r;
49743
0
                    val = JS_NewBigFloat(ctx);
49744
0
                    if (JS_IsException(val))
49745
0
                        break;
49746
0
                    r = JS_GetBigFloat(val);
49747
0
                    bf_set_zero(r, 0);
49748
0
                    err = 0;
49749
0
                } else {
49750
0
                    val = js_atof(ctx, p, &p, 0, ATOD_ACCEPT_BIN_OCT |
49751
0
                                  ATOD_TYPE_BIG_FLOAT |
49752
0
                                  ATOD_ACCEPT_PREFIX_AFTER_SIGN);
49753
0
                    if (JS_IsException(val)) {
49754
0
                        JS_FreeCString(ctx, str);
49755
0
                        return JS_EXCEPTION;
49756
0
                    }
49757
0
                    p += skip_spaces(p);
49758
0
                    err = ((p - str) != len);
49759
0
                }
49760
0
                JS_FreeCString(ctx, str);
49761
0
                if (err) {
49762
0
                    JS_FreeValue(ctx, val);
49763
0
                    return JS_ThrowSyntaxError(ctx, "invalid bigfloat literal");
49764
0
                }
49765
0
            }
49766
0
            break;
49767
0
        case JS_TAG_OBJECT:
49768
0
            val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
49769
0
            if (JS_IsException(val))
49770
0
                break;
49771
0
            goto redo;
49772
0
        case JS_TAG_NULL:
49773
0
        case JS_TAG_UNDEFINED:
49774
0
        default:
49775
0
            JS_FreeValue(ctx, val);
49776
0
            return JS_ThrowTypeError(ctx, "cannot convert to bigfloat");
49777
0
        }
49778
0
    }
49779
0
    return val;
49780
0
 fail:
49781
0
    JS_FreeValue(ctx, val);
49782
0
    return JS_EXCEPTION;
49783
0
}
49784
49785
static JSValue js_bigfloat_get_const(JSContext *ctx,
49786
                                     JSValueConst this_val, int magic)
49787
0
{
49788
0
    bf_t *r;
49789
0
    JSValue val;
49790
0
    val = JS_NewBigFloat(ctx);
49791
0
    if (JS_IsException(val))
49792
0
        return val;
49793
0
    r = JS_GetBigFloat(val);
49794
0
    switch(magic) {
49795
0
    case 0: /* PI */
49796
0
        bf_const_pi(r, ctx->fp_env.prec, ctx->fp_env.flags);
49797
0
        break;
49798
0
    case 1: /* LN2 */
49799
0
        bf_const_log2(r, ctx->fp_env.prec, ctx->fp_env.flags);
49800
0
        break;
49801
0
    case 2: /* MIN_VALUE */
49802
0
    case 3: /* MAX_VALUE */
49803
0
        {
49804
0
            slimb_t e_range, e;
49805
0
            e_range = (limb_t)1 << (bf_get_exp_bits(ctx->fp_env.flags) - 1);
49806
0
            bf_set_ui(r, 1);
49807
0
            if (magic == 2) {
49808
0
                e = -e_range + 2;
49809
0
                if (ctx->fp_env.flags & BF_FLAG_SUBNORMAL)
49810
0
                    e -= ctx->fp_env.prec - 1;
49811
0
                bf_mul_2exp(r, e, ctx->fp_env.prec, ctx->fp_env.flags);
49812
0
            } else {
49813
0
                bf_mul_2exp(r, ctx->fp_env.prec, ctx->fp_env.prec,
49814
0
                            ctx->fp_env.flags);
49815
0
                bf_add_si(r, r, -1, ctx->fp_env.prec, ctx->fp_env.flags);
49816
0
                bf_mul_2exp(r, e_range - ctx->fp_env.prec, ctx->fp_env.prec,
49817
0
                            ctx->fp_env.flags);
49818
0
            }
49819
0
        }
49820
0
        break;
49821
0
    case 4: /* EPSILON */
49822
0
        bf_set_ui(r, 1);
49823
0
        bf_mul_2exp(r, 1 - ctx->fp_env.prec,
49824
0
                    ctx->fp_env.prec, ctx->fp_env.flags);
49825
0
        break;
49826
0
    default:
49827
0
        abort();
49828
0
    }
49829
0
    return val;
49830
0
}
49831
49832
static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val,
49833
                                      int argc, JSValueConst *argv)
49834
0
{
49835
0
    bf_t *a;
49836
0
    const char *str;
49837
0
    JSValue ret;
49838
0
    int radix;
49839
0
    JSFloatEnv *fe;
49840
49841
0
    str = JS_ToCString(ctx, argv[0]);
49842
0
    if (!str)
49843
0
        return JS_EXCEPTION;
49844
0
    if (JS_ToInt32(ctx, &radix, argv[1])) {
49845
0
    fail:
49846
0
        JS_FreeCString(ctx, str);
49847
0
        return JS_EXCEPTION;
49848
0
    }
49849
0
    if (radix != 0 && (radix < 2 || radix > 36)) {
49850
0
        JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
49851
0
        goto fail;
49852
0
    }
49853
0
    fe = &ctx->fp_env;
49854
0
    if (argc > 2) {
49855
0
        fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
49856
0
        if (!fe)
49857
0
            goto fail;
49858
0
    }
49859
0
    ret = JS_NewBigFloat(ctx);
49860
0
    if (JS_IsException(ret))
49861
0
        goto done;
49862
0
    a = JS_GetBigFloat(ret);
49863
    /* XXX: use js_atof() */
49864
0
    bf_atof(a, str, NULL, radix, fe->prec, fe->flags);
49865
0
 done:
49866
0
    JS_FreeCString(ctx, str);
49867
0
    return ret;
49868
0
}
49869
49870
static JSValue js_bigfloat_isFinite(JSContext *ctx, JSValueConst this_val,
49871
                                    int argc, JSValueConst *argv)
49872
0
{
49873
0
    JSValueConst val = argv[0];
49874
0
    JSBigFloat *p;
49875
    
49876
0
    if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)
49877
0
        return JS_FALSE;
49878
0
    p = JS_VALUE_GET_PTR(val);
49879
0
    return JS_NewBool(ctx, bf_is_finite(&p->num));
49880
0
}
49881
49882
static JSValue js_bigfloat_isNaN(JSContext *ctx, JSValueConst this_val,
49883
                                 int argc, JSValueConst *argv)
49884
0
{
49885
0
    JSValueConst val = argv[0];
49886
0
    JSBigFloat *p;
49887
    
49888
0
    if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)
49889
0
        return JS_FALSE;
49890
0
    p = JS_VALUE_GET_PTR(val);
49891
0
    return JS_NewBool(ctx, bf_is_nan(&p->num));
49892
0
}
49893
49894
enum {
49895
    MATH_OP_ABS,
49896
    MATH_OP_FLOOR,
49897
    MATH_OP_CEIL,
49898
    MATH_OP_ROUND,
49899
    MATH_OP_TRUNC,
49900
    MATH_OP_SQRT,
49901
    MATH_OP_FPROUND,
49902
    MATH_OP_ACOS,
49903
    MATH_OP_ASIN,
49904
    MATH_OP_ATAN,
49905
    MATH_OP_ATAN2,
49906
    MATH_OP_COS,
49907
    MATH_OP_EXP,
49908
    MATH_OP_LOG,
49909
    MATH_OP_POW,
49910
    MATH_OP_SIN,
49911
    MATH_OP_TAN,
49912
    MATH_OP_FMOD,
49913
    MATH_OP_REM,
49914
    MATH_OP_SIGN,
49915
49916
    MATH_OP_ADD,
49917
    MATH_OP_SUB,
49918
    MATH_OP_MUL,
49919
    MATH_OP_DIV,
49920
};
49921
49922
static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val,
49923
                           int argc, JSValueConst *argv, int magic)
49924
0
{
49925
0
    bf_t a_s, *a, *r;
49926
0
    JSFloatEnv *fe;
49927
0
    int rnd_mode;
49928
0
    JSValue op1, res;
49929
49930
0
    op1 = JS_ToNumeric(ctx, argv[0]);
49931
0
    if (JS_IsException(op1))
49932
0
        return op1;
49933
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
49934
0
    fe = &ctx->fp_env;
49935
0
    if (argc > 1) {
49936
0
        fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV);
49937
0
        if (!fe)
49938
0
            goto fail;
49939
0
    }
49940
0
    res = JS_NewBigFloat(ctx);
49941
0
    if (JS_IsException(res)) {
49942
0
    fail:
49943
0
        if (a == &a_s)
49944
0
            bf_delete(a);
49945
0
        JS_FreeValue(ctx, op1);
49946
0
        return JS_EXCEPTION;
49947
0
    }
49948
0
    r = JS_GetBigFloat(res);
49949
0
    switch (magic) {
49950
0
    case MATH_OP_ABS:
49951
0
        bf_set(r, a);
49952
0
        r->sign = 0;
49953
0
        break;
49954
0
    case MATH_OP_FLOOR:
49955
0
        rnd_mode = BF_RNDD;
49956
0
        goto rint;
49957
0
    case MATH_OP_CEIL:
49958
0
        rnd_mode = BF_RNDU;
49959
0
        goto rint;
49960
0
    case MATH_OP_ROUND:
49961
0
        rnd_mode = BF_RNDNA;
49962
0
        goto rint;
49963
0
    case MATH_OP_TRUNC:
49964
0
        rnd_mode = BF_RNDZ;
49965
0
    rint:
49966
0
        bf_set(r, a);
49967
0
        fe->status |= bf_rint(r, rnd_mode);
49968
0
        break;
49969
0
    case MATH_OP_SQRT:
49970
0
        fe->status |= bf_sqrt(r, a, fe->prec, fe->flags);
49971
0
        break;
49972
0
    case MATH_OP_FPROUND:
49973
0
        bf_set(r, a);
49974
0
        fe->status |= bf_round(r, fe->prec, fe->flags);
49975
0
        break;
49976
0
    case MATH_OP_ACOS:
49977
0
        fe->status |= bf_acos(r, a, fe->prec, fe->flags);
49978
0
        break;
49979
0
    case MATH_OP_ASIN:
49980
0
        fe->status |= bf_asin(r, a, fe->prec, fe->flags);
49981
0
        break;
49982
0
    case MATH_OP_ATAN:
49983
0
        fe->status |= bf_atan(r, a, fe->prec, fe->flags);
49984
0
        break;
49985
0
    case MATH_OP_COS:
49986
0
        fe->status |= bf_cos(r, a, fe->prec, fe->flags);
49987
0
        break;
49988
0
    case MATH_OP_EXP:
49989
0
        fe->status |= bf_exp(r, a, fe->prec, fe->flags);
49990
0
        break;
49991
0
    case MATH_OP_LOG:
49992
0
        fe->status |= bf_log(r, a, fe->prec, fe->flags);
49993
0
        break;
49994
0
    case MATH_OP_SIN:
49995
0
        fe->status |= bf_sin(r, a, fe->prec, fe->flags);
49996
0
        break;
49997
0
    case MATH_OP_TAN:
49998
0
        fe->status |= bf_tan(r, a, fe->prec, fe->flags);
49999
0
        break;
50000
0
    case MATH_OP_SIGN:
50001
0
        if (bf_is_nan(a) || bf_is_zero(a)) {
50002
0
            bf_set(r, a);
50003
0
        } else {
50004
0
            bf_set_si(r, 1 - 2 * a->sign);
50005
0
        }
50006
0
        break;
50007
0
    default:
50008
0
        abort();
50009
0
    }
50010
0
    if (a == &a_s)
50011
0
        bf_delete(a);
50012
0
    JS_FreeValue(ctx, op1);
50013
0
    return res;
50014
0
}
50015
50016
static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val,
50017
                            int argc, JSValueConst *argv, int magic)
50018
0
{
50019
0
    bf_t a_s, *a, b_s, *b, r_s, *r = &r_s;
50020
0
    JSFloatEnv *fe;
50021
0
    JSValue op1, op2, res;
50022
50023
0
    op1 = JS_ToNumeric(ctx, argv[0]);
50024
0
    if (JS_IsException(op1))
50025
0
        return op1;
50026
0
    op2 = JS_ToNumeric(ctx, argv[1]);
50027
0
    if (JS_IsException(op2)) {
50028
0
        JS_FreeValue(ctx, op1);
50029
0
        return op2;
50030
0
    }
50031
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
50032
0
    b = JS_ToBigFloat(ctx, &b_s, op2);
50033
0
    fe = &ctx->fp_env;
50034
0
    if (argc > 2) {
50035
0
        fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
50036
0
        if (!fe)
50037
0
            goto fail;
50038
0
    }
50039
0
    res = JS_NewBigFloat(ctx);
50040
0
    if (JS_IsException(res)) {
50041
0
    fail:
50042
0
        if (a == &a_s)
50043
0
            bf_delete(a);
50044
0
        if (b == &b_s)
50045
0
            bf_delete(b);
50046
0
        JS_FreeValue(ctx, op1);
50047
0
        JS_FreeValue(ctx, op2);
50048
0
        return JS_EXCEPTION;
50049
0
    }
50050
0
    r = JS_GetBigFloat(res);
50051
0
    switch (magic) {
50052
0
    case MATH_OP_ATAN2:
50053
0
        fe->status |= bf_atan2(r, a, b, fe->prec, fe->flags);
50054
0
        break;
50055
0
    case MATH_OP_POW:
50056
0
        fe->status |= bf_pow(r, a, b, fe->prec, fe->flags | BF_POW_JS_QUIRKS);
50057
0
        break;
50058
0
    case MATH_OP_FMOD:
50059
0
        fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
50060
0
        break;
50061
0
    case MATH_OP_REM:
50062
0
        fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDN);
50063
0
        break;
50064
0
    case MATH_OP_ADD:
50065
0
        fe->status |= bf_add(r, a, b, fe->prec, fe->flags);
50066
0
        break;
50067
0
    case MATH_OP_SUB:
50068
0
        fe->status |= bf_sub(r, a, b, fe->prec, fe->flags);
50069
0
        break;
50070
0
    case MATH_OP_MUL:
50071
0
        fe->status |= bf_mul(r, a, b, fe->prec, fe->flags);
50072
0
        break;
50073
0
    case MATH_OP_DIV:
50074
0
        fe->status |= bf_div(r, a, b, fe->prec, fe->flags);
50075
0
        break;
50076
0
    default:
50077
0
        abort();
50078
0
    }
50079
0
    if (a == &a_s)
50080
0
        bf_delete(a);
50081
0
    if (b == &b_s)
50082
0
        bf_delete(b);
50083
0
    JS_FreeValue(ctx, op1);
50084
0
    JS_FreeValue(ctx, op2);
50085
0
    return res;
50086
0
}
50087
50088
static const JSCFunctionListEntry js_bigfloat_funcs[] = {
50089
    JS_CGETSET_MAGIC_DEF("PI", js_bigfloat_get_const, NULL, 0 ),
50090
    JS_CGETSET_MAGIC_DEF("LN2", js_bigfloat_get_const, NULL, 1 ),
50091
    JS_CGETSET_MAGIC_DEF("MIN_VALUE", js_bigfloat_get_const, NULL, 2 ),
50092
    JS_CGETSET_MAGIC_DEF("MAX_VALUE", js_bigfloat_get_const, NULL, 3 ),
50093
    JS_CGETSET_MAGIC_DEF("EPSILON", js_bigfloat_get_const, NULL, 4 ),
50094
    JS_CFUNC_DEF("parseFloat", 1, js_bigfloat_parseFloat ),
50095
    JS_CFUNC_DEF("isFinite", 1, js_bigfloat_isFinite ),
50096
    JS_CFUNC_DEF("isNaN", 1, js_bigfloat_isNaN ),
50097
    JS_CFUNC_MAGIC_DEF("abs", 1, js_bigfloat_fop, MATH_OP_ABS ),
50098
    JS_CFUNC_MAGIC_DEF("fpRound", 1, js_bigfloat_fop, MATH_OP_FPROUND ),
50099
    JS_CFUNC_MAGIC_DEF("floor", 1, js_bigfloat_fop, MATH_OP_FLOOR ),
50100
    JS_CFUNC_MAGIC_DEF("ceil", 1, js_bigfloat_fop, MATH_OP_CEIL ),
50101
    JS_CFUNC_MAGIC_DEF("round", 1, js_bigfloat_fop, MATH_OP_ROUND ),
50102
    JS_CFUNC_MAGIC_DEF("trunc", 1, js_bigfloat_fop, MATH_OP_TRUNC ),
50103
    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigfloat_fop, MATH_OP_SQRT ),
50104
    JS_CFUNC_MAGIC_DEF("acos", 1, js_bigfloat_fop, MATH_OP_ACOS ),
50105
    JS_CFUNC_MAGIC_DEF("asin", 1, js_bigfloat_fop, MATH_OP_ASIN ),
50106
    JS_CFUNC_MAGIC_DEF("atan", 1, js_bigfloat_fop, MATH_OP_ATAN ),
50107
    JS_CFUNC_MAGIC_DEF("atan2", 2, js_bigfloat_fop2, MATH_OP_ATAN2 ),
50108
    JS_CFUNC_MAGIC_DEF("cos", 1, js_bigfloat_fop, MATH_OP_COS ),
50109
    JS_CFUNC_MAGIC_DEF("exp", 1, js_bigfloat_fop, MATH_OP_EXP ),
50110
    JS_CFUNC_MAGIC_DEF("log", 1, js_bigfloat_fop, MATH_OP_LOG ),
50111
    JS_CFUNC_MAGIC_DEF("pow", 2, js_bigfloat_fop2, MATH_OP_POW ),
50112
    JS_CFUNC_MAGIC_DEF("sin", 1, js_bigfloat_fop, MATH_OP_SIN ),
50113
    JS_CFUNC_MAGIC_DEF("tan", 1, js_bigfloat_fop, MATH_OP_TAN ),
50114
    JS_CFUNC_MAGIC_DEF("sign", 1, js_bigfloat_fop, MATH_OP_SIGN ),
50115
    JS_CFUNC_MAGIC_DEF("add", 2, js_bigfloat_fop2, MATH_OP_ADD ),
50116
    JS_CFUNC_MAGIC_DEF("sub", 2, js_bigfloat_fop2, MATH_OP_SUB ),
50117
    JS_CFUNC_MAGIC_DEF("mul", 2, js_bigfloat_fop2, MATH_OP_MUL ),
50118
    JS_CFUNC_MAGIC_DEF("div", 2, js_bigfloat_fop2, MATH_OP_DIV ),
50119
    JS_CFUNC_MAGIC_DEF("fmod", 2, js_bigfloat_fop2, MATH_OP_FMOD ),
50120
    JS_CFUNC_MAGIC_DEF("remainder", 2, js_bigfloat_fop2, MATH_OP_REM ),
50121
};
50122
50123
/* FloatEnv */
50124
50125
static JSValue js_float_env_constructor(JSContext *ctx,
50126
                                        JSValueConst new_target,
50127
                                        int argc, JSValueConst *argv)
50128
0
{
50129
0
    JSValue obj;
50130
0
    JSFloatEnv *fe;
50131
0
    int64_t prec;
50132
0
    int flags, rndmode;
50133
50134
0
    prec = ctx->fp_env.prec;
50135
0
    flags = ctx->fp_env.flags;
50136
0
    if (!JS_IsUndefined(argv[0])) {
50137
0
        if (JS_ToInt64Sat(ctx, &prec, argv[0]))
50138
0
            return JS_EXCEPTION;
50139
0
        if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
50140
0
            return JS_ThrowRangeError(ctx, "invalid precision");
50141
0
        flags = BF_RNDN; /* RNDN, max exponent size, no subnormal */
50142
0
        if (argc > 1 && !JS_IsUndefined(argv[1])) {
50143
0
            if (JS_ToInt32Sat(ctx, &rndmode, argv[1]))
50144
0
                return JS_EXCEPTION;
50145
0
            if (rndmode < BF_RNDN || rndmode > BF_RNDF)
50146
0
                return JS_ThrowRangeError(ctx, "invalid rounding mode");
50147
0
            flags = rndmode;
50148
0
        }
50149
0
    }
50150
50151
0
    obj = JS_NewObjectClass(ctx, JS_CLASS_FLOAT_ENV);
50152
0
    if (JS_IsException(obj))
50153
0
        return JS_EXCEPTION;
50154
0
    fe = js_malloc(ctx, sizeof(*fe));
50155
0
    if (!fe)
50156
0
        return JS_EXCEPTION;
50157
0
    fe->prec = prec;
50158
0
    fe->flags = flags;
50159
0
    fe->status = 0;
50160
0
    JS_SetOpaque(obj, fe);
50161
0
    return obj;
50162
0
}
50163
50164
static void js_float_env_finalizer(JSRuntime *rt, JSValue val)
50165
0
{
50166
0
    JSFloatEnv *fe = JS_GetOpaque(val, JS_CLASS_FLOAT_ENV);
50167
0
    js_free_rt(rt, fe);
50168
0
}
50169
50170
static JSValue js_float_env_get_prec(JSContext *ctx, JSValueConst this_val)
50171
0
{
50172
0
    return JS_NewInt64(ctx, ctx->fp_env.prec);
50173
0
}
50174
50175
static JSValue js_float_env_get_expBits(JSContext *ctx, JSValueConst this_val)
50176
0
{
50177
0
    return JS_NewInt32(ctx, bf_get_exp_bits(ctx->fp_env.flags));
50178
0
}
50179
50180
static JSValue js_float_env_setPrec(JSContext *ctx,
50181
                                    JSValueConst this_val,
50182
                                    int argc, JSValueConst *argv)
50183
0
{
50184
0
    JSValueConst func;
50185
0
    int exp_bits, flags, saved_flags;
50186
0
    JSValue ret;
50187
0
    limb_t saved_prec;
50188
0
    int64_t prec;
50189
50190
0
    func = argv[0];
50191
0
    if (JS_ToInt64Sat(ctx, &prec, argv[1]))
50192
0
        return JS_EXCEPTION;
50193
0
    if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
50194
0
        return JS_ThrowRangeError(ctx, "invalid precision");
50195
0
    exp_bits = BF_EXP_BITS_MAX;
50196
50197
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
50198
0
        if (JS_ToInt32Sat(ctx, &exp_bits, argv[2]))
50199
0
            return JS_EXCEPTION;
50200
0
        if (exp_bits < BF_EXP_BITS_MIN || exp_bits > BF_EXP_BITS_MAX)
50201
0
            return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
50202
0
    }
50203
50204
0
    flags = BF_RNDN | BF_FLAG_SUBNORMAL | bf_set_exp_bits(exp_bits);
50205
50206
0
    saved_prec = ctx->fp_env.prec;
50207
0
    saved_flags = ctx->fp_env.flags;
50208
50209
0
    ctx->fp_env.prec = prec;
50210
0
    ctx->fp_env.flags = flags;
50211
50212
0
    ret = JS_Call(ctx, func, JS_UNDEFINED, 0, NULL);
50213
    /* always restore the floating point precision */
50214
0
    ctx->fp_env.prec = saved_prec;
50215
0
    ctx->fp_env.flags = saved_flags;
50216
0
    return ret;
50217
0
}
50218
50219
0
#define FE_PREC      (-1)
50220
0
#define FE_EXP       (-2)
50221
0
#define FE_RNDMODE   (-3)
50222
0
#define FE_SUBNORMAL (-4)
50223
50224
static JSValue js_float_env_proto_get_status(JSContext *ctx, JSValueConst this_val, int magic)
50225
0
{
50226
0
    JSFloatEnv *fe;
50227
0
    fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
50228
0
    if (!fe)
50229
0
        return JS_EXCEPTION;
50230
0
    switch(magic) {
50231
0
    case FE_PREC:
50232
0
        return JS_NewInt64(ctx, fe->prec);
50233
0
    case FE_EXP:
50234
0
        return JS_NewInt32(ctx, bf_get_exp_bits(fe->flags));
50235
0
    case FE_RNDMODE:
50236
0
        return JS_NewInt32(ctx, fe->flags & BF_RND_MASK);
50237
0
    case FE_SUBNORMAL:
50238
0
        return JS_NewBool(ctx, (fe->flags & BF_FLAG_SUBNORMAL) != 0);
50239
0
    default:
50240
0
        return JS_NewBool(ctx, (fe->status & magic) != 0);
50241
0
    }
50242
0
}
50243
50244
static JSValue js_float_env_proto_set_status(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic)
50245
0
{
50246
0
    JSFloatEnv *fe;
50247
0
    int b;
50248
0
    int64_t prec;
50249
50250
0
    fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
50251
0
    if (!fe)
50252
0
        return JS_EXCEPTION;
50253
0
    switch(magic) {
50254
0
    case FE_PREC:
50255
0
        if (JS_ToInt64Sat(ctx, &prec, val))
50256
0
            return JS_EXCEPTION;
50257
0
        if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
50258
0
            return JS_ThrowRangeError(ctx, "invalid precision");
50259
0
        fe->prec = prec;
50260
0
        break;
50261
0
    case FE_EXP:
50262
0
        if (JS_ToInt32Sat(ctx, &b, val))
50263
0
            return JS_EXCEPTION;
50264
0
        if (b < BF_EXP_BITS_MIN || b > BF_EXP_BITS_MAX)
50265
0
            return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
50266
0
        fe->flags = (fe->flags & ~(BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)) |
50267
0
            bf_set_exp_bits(b);
50268
0
        break;
50269
0
    case FE_RNDMODE:
50270
0
        b = bigfloat_get_rnd_mode(ctx, val);
50271
0
        if (b < 0)
50272
0
            return JS_EXCEPTION;
50273
0
        fe->flags = (fe->flags & ~BF_RND_MASK) | b;
50274
0
        break;
50275
0
    case FE_SUBNORMAL:
50276
0
        b = JS_ToBool(ctx, val);
50277
0
        fe->flags = (fe->flags & ~BF_FLAG_SUBNORMAL) | (b ? BF_FLAG_SUBNORMAL: 0);
50278
0
        break;
50279
0
    default:
50280
0
        b = JS_ToBool(ctx, val);
50281
0
        fe->status = (fe->status & ~magic) & ((-b) & magic);
50282
0
        break;
50283
0
    }
50284
0
    return JS_UNDEFINED;
50285
0
}
50286
50287
static JSValue js_float_env_clearStatus(JSContext *ctx,
50288
                                        JSValueConst this_val,
50289
                                        int argc, JSValueConst *argv)
50290
0
{
50291
0
    JSFloatEnv *fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
50292
0
    if (!fe)
50293
0
        return JS_EXCEPTION;
50294
0
    fe->status = 0;
50295
0
    return JS_UNDEFINED;
50296
0
}
50297
50298
static const JSCFunctionListEntry js_float_env_funcs[] = {
50299
    JS_CGETSET_DEF("prec", js_float_env_get_prec, NULL ),
50300
    JS_CGETSET_DEF("expBits", js_float_env_get_expBits, NULL ),
50301
    JS_CFUNC_DEF("setPrec", 2, js_float_env_setPrec ),
50302
    JS_PROP_INT32_DEF("RNDN", BF_RNDN, 0 ),
50303
    JS_PROP_INT32_DEF("RNDZ", BF_RNDZ, 0 ),
50304
    JS_PROP_INT32_DEF("RNDU", BF_RNDU, 0 ),
50305
    JS_PROP_INT32_DEF("RNDD", BF_RNDD, 0 ),
50306
    JS_PROP_INT32_DEF("RNDNA", BF_RNDNA, 0 ),
50307
    JS_PROP_INT32_DEF("RNDA", BF_RNDA, 0 ),
50308
    JS_PROP_INT32_DEF("RNDF", BF_RNDF, 0 ),
50309
    JS_PROP_INT32_DEF("precMin", BF_PREC_MIN, 0 ),
50310
    JS_PROP_INT64_DEF("precMax", BF_PREC_MAX, 0 ),
50311
    JS_PROP_INT32_DEF("expBitsMin", BF_EXP_BITS_MIN, 0 ),
50312
    JS_PROP_INT32_DEF("expBitsMax", BF_EXP_BITS_MAX, 0 ),
50313
};
50314
50315
static const JSCFunctionListEntry js_float_env_proto_funcs[] = {
50316
    JS_CGETSET_MAGIC_DEF("prec", js_float_env_proto_get_status,
50317
                         js_float_env_proto_set_status, FE_PREC ),
50318
    JS_CGETSET_MAGIC_DEF("expBits", js_float_env_proto_get_status,
50319
                         js_float_env_proto_set_status, FE_EXP ),
50320
    JS_CGETSET_MAGIC_DEF("rndMode", js_float_env_proto_get_status,
50321
                         js_float_env_proto_set_status, FE_RNDMODE ),
50322
    JS_CGETSET_MAGIC_DEF("subnormal", js_float_env_proto_get_status,
50323
                         js_float_env_proto_set_status, FE_SUBNORMAL ),
50324
    JS_CGETSET_MAGIC_DEF("invalidOperation", js_float_env_proto_get_status,
50325
                         js_float_env_proto_set_status, BF_ST_INVALID_OP ),
50326
    JS_CGETSET_MAGIC_DEF("divideByZero", js_float_env_proto_get_status,
50327
                         js_float_env_proto_set_status, BF_ST_DIVIDE_ZERO ),
50328
    JS_CGETSET_MAGIC_DEF("overflow", js_float_env_proto_get_status,
50329
                         js_float_env_proto_set_status, BF_ST_OVERFLOW ),
50330
    JS_CGETSET_MAGIC_DEF("underflow", js_float_env_proto_get_status,
50331
                         js_float_env_proto_set_status, BF_ST_UNDERFLOW ),
50332
    JS_CGETSET_MAGIC_DEF("inexact", js_float_env_proto_get_status,
50333
                         js_float_env_proto_set_status, BF_ST_INEXACT ),
50334
    JS_CFUNC_DEF("clearStatus", 0, js_float_env_clearStatus ),
50335
};
50336
50337
void JS_AddIntrinsicBigFloat(JSContext *ctx)
50338
0
{
50339
0
    JSRuntime *rt = ctx->rt;
50340
0
    JSValueConst obj1;
50341
    
50342
0
    rt->bigfloat_ops.to_string = js_bigfloat_to_string;
50343
0
    rt->bigfloat_ops.from_string = js_string_to_bigfloat;
50344
0
    rt->bigfloat_ops.unary_arith = js_unary_arith_bigfloat;
50345
0
    rt->bigfloat_ops.binary_arith = js_binary_arith_bigfloat;
50346
0
    rt->bigfloat_ops.compare = js_compare_bigfloat;
50347
0
    rt->bigfloat_ops.mul_pow10_to_float64 = js_mul_pow10_to_float64;
50348
0
    rt->bigfloat_ops.mul_pow10 = js_mul_pow10;
50349
    
50350
0
    ctx->class_proto[JS_CLASS_BIG_FLOAT] = JS_NewObject(ctx);
50351
0
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT],
50352
0
                               js_bigfloat_proto_funcs,
50353
0
                               countof(js_bigfloat_proto_funcs));
50354
0
    obj1 = JS_NewGlobalCConstructor(ctx, "BigFloat", js_bigfloat_constructor, 1,
50355
0
                                    ctx->class_proto[JS_CLASS_BIG_FLOAT]);
50356
0
    JS_SetPropertyFunctionList(ctx, obj1, js_bigfloat_funcs,
50357
0
                               countof(js_bigfloat_funcs));
50358
50359
0
    ctx->class_proto[JS_CLASS_FLOAT_ENV] = JS_NewObject(ctx);
50360
0
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FLOAT_ENV],
50361
0
                               js_float_env_proto_funcs,
50362
0
                               countof(js_float_env_proto_funcs));
50363
0
    obj1 = JS_NewGlobalCConstructorOnly(ctx, "BigFloatEnv",
50364
0
                                        js_float_env_constructor, 1,
50365
0
                                        ctx->class_proto[JS_CLASS_FLOAT_ENV]);
50366
0
    JS_SetPropertyFunctionList(ctx, obj1, js_float_env_funcs,
50367
0
                               countof(js_float_env_funcs));
50368
0
}
50369
50370
/* BigDecimal */
50371
50372
static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
50373
                                   BOOL allow_null_or_undefined)
50374
0
{
50375
0
 redo:
50376
0
    switch(JS_VALUE_GET_NORM_TAG(val)) {
50377
0
    case JS_TAG_BIG_DECIMAL:
50378
0
        break;
50379
0
    case JS_TAG_NULL:
50380
0
        if (!allow_null_or_undefined)
50381
0
            goto fail;
50382
        /* fall thru */
50383
0
    case JS_TAG_BOOL:
50384
0
    case JS_TAG_INT:
50385
0
        {
50386
0
            bfdec_t *r;
50387
0
            int32_t v = JS_VALUE_GET_INT(val);
50388
50389
0
            val = JS_NewBigDecimal(ctx);
50390
0
            if (JS_IsException(val))
50391
0
                break;
50392
0
            r = JS_GetBigDecimal(val);
50393
0
            if (bfdec_set_si(r, v)) {
50394
0
                JS_FreeValue(ctx, val);
50395
0
                val = JS_EXCEPTION;
50396
0
                break;
50397
0
            }
50398
0
        }
50399
0
        break;
50400
0
    case JS_TAG_FLOAT64:
50401
0
    case JS_TAG_BIG_INT:
50402
0
    case JS_TAG_BIG_FLOAT:
50403
0
        val = JS_ToStringFree(ctx, val);
50404
0
        if (JS_IsException(val))
50405
0
            break;
50406
0
        goto redo;
50407
0
    case JS_TAG_STRING:
50408
0
        {
50409
0
            const char *str, *p;
50410
0
            size_t len;
50411
0
            int err;
50412
50413
0
            str = JS_ToCStringLen(ctx, &len, val);
50414
0
            JS_FreeValue(ctx, val);
50415
0
            if (!str)
50416
0
                return JS_EXCEPTION;
50417
0
            p = str;
50418
0
            p += skip_spaces(p);
50419
0
            if ((p - str) == len) {
50420
0
                bfdec_t *r;
50421
0
                val = JS_NewBigDecimal(ctx);
50422
0
                if (JS_IsException(val))
50423
0
                    break;
50424
0
                r = JS_GetBigDecimal(val);
50425
0
                bfdec_set_zero(r, 0);
50426
0
                err = 0;
50427
0
            } else {
50428
0
                val = js_atof(ctx, p, &p, 0, ATOD_TYPE_BIG_DECIMAL);
50429
0
                if (JS_IsException(val)) {
50430
0
                    JS_FreeCString(ctx, str);
50431
0
                    return JS_EXCEPTION;
50432
0
                }
50433
0
                p += skip_spaces(p);
50434
0
                err = ((p - str) != len);
50435
0
            }
50436
0
            JS_FreeCString(ctx, str);
50437
0
            if (err) {
50438
0
                JS_FreeValue(ctx, val);
50439
0
                return JS_ThrowSyntaxError(ctx, "invalid bigdecimal literal");
50440
0
            }
50441
0
        }
50442
0
        break;
50443
0
    case JS_TAG_OBJECT:
50444
0
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
50445
0
        if (JS_IsException(val))
50446
0
            break;
50447
0
        goto redo;
50448
0
    case JS_TAG_UNDEFINED:
50449
0
        {
50450
0
            bfdec_t *r;
50451
0
            if (!allow_null_or_undefined)
50452
0
                goto fail;
50453
0
            val = JS_NewBigDecimal(ctx);
50454
0
            if (JS_IsException(val))
50455
0
                break;
50456
0
            r = JS_GetBigDecimal(val);
50457
0
            bfdec_set_nan(r);
50458
0
        }
50459
0
        break;
50460
0
    default:
50461
0
    fail:
50462
0
        JS_FreeValue(ctx, val);
50463
0
        return JS_ThrowTypeError(ctx, "cannot convert to bigdecimal");
50464
0
    }
50465
0
    return val;
50466
0
}
50467
50468
static JSValue js_bigdecimal_constructor(JSContext *ctx,
50469
                                         JSValueConst new_target,
50470
                                         int argc, JSValueConst *argv)
50471
0
{
50472
0
    JSValue val;
50473
0
    if (!JS_IsUndefined(new_target))
50474
0
        return JS_ThrowTypeError(ctx, "not a constructor");
50475
0
    if (argc == 0) {
50476
0
        bfdec_t *r;
50477
0
        val = JS_NewBigDecimal(ctx);
50478
0
        if (JS_IsException(val))
50479
0
            return val;
50480
0
        r = JS_GetBigDecimal(val);
50481
0
        bfdec_set_zero(r, 0);
50482
0
    } else {
50483
0
        val = JS_ToBigDecimalFree(ctx, JS_DupValue(ctx, argv[0]), FALSE);
50484
0
    }
50485
0
    return val;
50486
0
}
50487
50488
static JSValue js_thisBigDecimalValue(JSContext *ctx, JSValueConst this_val)
50489
0
{
50490
0
    if (JS_IsBigDecimal(this_val))
50491
0
        return JS_DupValue(ctx, this_val);
50492
50493
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
50494
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
50495
0
        if (p->class_id == JS_CLASS_BIG_DECIMAL) {
50496
0
            if (JS_IsBigDecimal(p->u.object_data))
50497
0
                return JS_DupValue(ctx, p->u.object_data);
50498
0
        }
50499
0
    }
50500
0
    return JS_ThrowTypeError(ctx, "not a bigdecimal");
50501
0
}
50502
50503
static JSValue js_bigdecimal_toString(JSContext *ctx, JSValueConst this_val,
50504
                                      int argc, JSValueConst *argv)
50505
0
{
50506
0
    JSValue val;
50507
50508
0
    val = js_thisBigDecimalValue(ctx, this_val);
50509
0
    if (JS_IsException(val))
50510
0
        return val;
50511
0
    return JS_ToStringFree(ctx, val);
50512
0
}
50513
50514
static JSValue js_bigdecimal_valueOf(JSContext *ctx, JSValueConst this_val,
50515
                                   int argc, JSValueConst *argv)
50516
0
{
50517
0
    return js_thisBigDecimalValue(ctx, this_val);
50518
0
}
50519
50520
static int js_bigdecimal_get_rnd_mode(JSContext *ctx, JSValueConst obj)
50521
0
{
50522
0
    const char *str;
50523
0
    size_t size;
50524
0
    int rnd_mode;
50525
    
50526
0
    str = JS_ToCStringLen(ctx, &size, obj);
50527
0
    if (!str)
50528
0
        return -1;
50529
0
    if (strlen(str) != size)
50530
0
        goto invalid_rounding_mode;
50531
0
    if (!strcmp(str, "floor")) {
50532
0
        rnd_mode = BF_RNDD;
50533
0
    } else if (!strcmp(str, "ceiling")) {
50534
0
        rnd_mode = BF_RNDU;
50535
0
    } else if (!strcmp(str, "down")) {
50536
0
        rnd_mode = BF_RNDZ;
50537
0
    } else if (!strcmp(str, "up")) {
50538
0
        rnd_mode = BF_RNDA;
50539
0
    } else if (!strcmp(str, "half-even")) {
50540
0
        rnd_mode = BF_RNDN;
50541
0
    } else if (!strcmp(str, "half-up")) {
50542
0
        rnd_mode = BF_RNDNA;
50543
0
    } else {
50544
0
    invalid_rounding_mode:
50545
0
        JS_FreeCString(ctx, str);
50546
0
        JS_ThrowTypeError(ctx, "invalid rounding mode");
50547
0
        return -1;
50548
0
    }
50549
0
    JS_FreeCString(ctx, str);
50550
0
    return rnd_mode;
50551
0
}
50552
50553
typedef struct {
50554
    int64_t prec;
50555
    bf_flags_t flags;
50556
} BigDecimalEnv;
50557
50558
static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe,
50559
                                 JSValueConst obj)
50560
0
{
50561
0
    JSValue prop;
50562
0
    int64_t val;
50563
0
    BOOL has_prec;
50564
0
    int rnd_mode;
50565
    
50566
0
    if (!JS_IsObject(obj)) {
50567
0
        JS_ThrowTypeErrorNotAnObject(ctx);
50568
0
        return -1;
50569
0
    }
50570
0
    prop = JS_GetProperty(ctx, obj, JS_ATOM_roundingMode);
50571
0
    if (JS_IsException(prop))
50572
0
        return -1;
50573
0
    rnd_mode = js_bigdecimal_get_rnd_mode(ctx, prop);
50574
0
    JS_FreeValue(ctx, prop);
50575
0
    if (rnd_mode < 0)
50576
0
        return -1;
50577
0
    fe->flags = rnd_mode;
50578
    
50579
0
    prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits);
50580
0
    if (JS_IsException(prop))
50581
0
        return -1;
50582
0
    has_prec = FALSE;
50583
0
    if (!JS_IsUndefined(prop)) {
50584
0
        if (JS_ToInt64SatFree(ctx, &val, prop))
50585
0
            return -1;
50586
0
        if (val < 1 || val > BF_PREC_MAX)
50587
0
            goto invalid_precision;
50588
0
        fe->prec = val;
50589
0
        has_prec = TRUE;
50590
0
    }
50591
50592
0
    prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumFractionDigits);
50593
0
    if (JS_IsException(prop))
50594
0
        return -1;
50595
0
    if (!JS_IsUndefined(prop)) {
50596
0
        if (has_prec) {
50597
0
            JS_FreeValue(ctx, prop);
50598
0
            JS_ThrowTypeError(ctx, "cannot provide both maximumSignificantDigits and maximumFractionDigits");
50599
0
            return -1;
50600
0
        }
50601
0
        if (JS_ToInt64SatFree(ctx, &val, prop))
50602
0
            return -1;
50603
0
        if (val < 0 || val > BF_PREC_MAX) {
50604
0
        invalid_precision:
50605
0
            JS_ThrowTypeError(ctx, "invalid precision");
50606
0
            return -1;
50607
0
        }
50608
0
        fe->prec = val;
50609
0
        fe->flags |= BF_FLAG_RADPNT_PREC;
50610
0
        has_prec = TRUE;
50611
0
    }
50612
0
    if (!has_prec) {
50613
0
        JS_ThrowTypeError(ctx, "precision must be present");
50614
0
        return -1;
50615
0
    }
50616
0
    return 0;
50617
0
}
50618
50619
50620
static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val,
50621
                                 int argc, JSValueConst *argv, int magic)
50622
0
{
50623
0
    bfdec_t *a, *b, r_s, *r = &r_s;
50624
0
    JSValue op1, op2, res;
50625
0
    BigDecimalEnv fe_s, *fe = &fe_s;
50626
0
    int op_count, ret;
50627
50628
0
    if (magic == MATH_OP_SQRT ||
50629
0
        magic == MATH_OP_ROUND)
50630
0
        op_count = 1;
50631
0
    else
50632
0
        op_count = 2;
50633
    
50634
0
    op1 = JS_ToNumeric(ctx, argv[0]);
50635
0
    if (JS_IsException(op1))
50636
0
        return op1;
50637
0
    a = JS_ToBigDecimal(ctx, op1);
50638
0
    if (!a) {
50639
0
        JS_FreeValue(ctx, op1);
50640
0
        return JS_EXCEPTION;
50641
0
    }
50642
0
    if (op_count >= 2) {
50643
0
        op2 = JS_ToNumeric(ctx, argv[1]);
50644
0
        if (JS_IsException(op2)) {
50645
0
            JS_FreeValue(ctx, op1);
50646
0
            return op2;
50647
0
        }
50648
0
        b = JS_ToBigDecimal(ctx, op2);
50649
0
        if (!b)
50650
0
            goto fail;
50651
0
    } else {
50652
0
        op2 = JS_UNDEFINED;
50653
0
        b = NULL;
50654
0
    }
50655
0
    fe->flags = BF_RNDZ;
50656
0
    fe->prec = BF_PREC_INF;
50657
0
    if (op_count < argc) {
50658
0
        if (js_bigdecimal_get_env(ctx, fe, argv[op_count]))
50659
0
            goto fail;
50660
0
    }
50661
50662
0
    res = JS_NewBigDecimal(ctx);
50663
0
    if (JS_IsException(res)) {
50664
0
    fail:
50665
0
        JS_FreeValue(ctx, op1);
50666
0
        JS_FreeValue(ctx, op2);
50667
0
        return JS_EXCEPTION;
50668
0
    }
50669
0
    r = JS_GetBigDecimal(res);
50670
0
    switch (magic) {
50671
0
    case MATH_OP_ADD:
50672
0
        ret = bfdec_add(r, a, b, fe->prec, fe->flags);
50673
0
        break;
50674
0
    case MATH_OP_SUB:
50675
0
        ret = bfdec_sub(r, a, b, fe->prec, fe->flags);
50676
0
        break;
50677
0
    case MATH_OP_MUL:
50678
0
        ret = bfdec_mul(r, a, b, fe->prec, fe->flags);
50679
0
        break;
50680
0
    case MATH_OP_DIV:
50681
0
        ret = bfdec_div(r, a, b, fe->prec, fe->flags);
50682
0
        break;
50683
0
    case MATH_OP_FMOD:
50684
0
        ret = bfdec_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
50685
0
        break;
50686
0
    case MATH_OP_SQRT:
50687
0
        ret = bfdec_sqrt(r, a, fe->prec, fe->flags);
50688
0
        break;
50689
0
    case MATH_OP_ROUND:
50690
0
        ret = bfdec_set(r, a);
50691
0
        if (!(ret & BF_ST_MEM_ERROR))
50692
0
            ret = bfdec_round(r, fe->prec, fe->flags);
50693
0
        break;
50694
0
    default:
50695
0
        abort();
50696
0
    }
50697
0
    JS_FreeValue(ctx, op1);
50698
0
    JS_FreeValue(ctx, op2);
50699
0
    ret &= BF_ST_MEM_ERROR | BF_ST_DIVIDE_ZERO | BF_ST_INVALID_OP |
50700
0
        BF_ST_OVERFLOW;
50701
0
    if (ret != 0) {
50702
0
        JS_FreeValue(ctx, res);
50703
0
        return throw_bf_exception(ctx, ret);
50704
0
    } else {
50705
0
        return res;
50706
0
    }
50707
0
}
50708
50709
static JSValue js_bigdecimal_toFixed(JSContext *ctx, JSValueConst this_val,
50710
                                 int argc, JSValueConst *argv)
50711
0
{
50712
0
    JSValue val, ret;
50713
0
    int64_t f;
50714
0
    int rnd_mode;
50715
50716
0
    val = js_thisBigDecimalValue(ctx, this_val);
50717
0
    if (JS_IsException(val))
50718
0
        return val;
50719
0
    if (JS_ToInt64Sat(ctx, &f, argv[0]))
50720
0
        goto fail;
50721
0
    if (f < 0 || f > BF_PREC_MAX) {
50722
0
        JS_ThrowRangeError(ctx, "invalid number of digits");
50723
0
        goto fail;
50724
0
    }
50725
0
    rnd_mode = BF_RNDNA;
50726
0
    if (argc > 1) {
50727
0
        rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
50728
0
        if (rnd_mode < 0)
50729
0
            goto fail;
50730
0
    }
50731
0
    ret = js_bigdecimal_to_string1(ctx, val, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
50732
0
    JS_FreeValue(ctx, val);
50733
0
    return ret;
50734
0
 fail:
50735
0
    JS_FreeValue(ctx, val);
50736
0
    return JS_EXCEPTION;
50737
0
}
50738
50739
static JSValue js_bigdecimal_toExponential(JSContext *ctx, JSValueConst this_val,
50740
                                       int argc, JSValueConst *argv)
50741
0
{
50742
0
    JSValue val, ret;
50743
0
    int64_t f;
50744
0
    int rnd_mode;
50745
50746
0
    val = js_thisBigDecimalValue(ctx, this_val);
50747
0
    if (JS_IsException(val))
50748
0
        return val;
50749
0
    if (JS_ToInt64Sat(ctx, &f, argv[0]))
50750
0
        goto fail;
50751
0
    if (JS_IsUndefined(argv[0])) {
50752
0
        ret = js_bigdecimal_to_string1(ctx, val, 0,
50753
0
                  BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
50754
0
    } else {
50755
0
        if (f < 0 || f > BF_PREC_MAX) {
50756
0
            JS_ThrowRangeError(ctx, "invalid number of digits");
50757
0
            goto fail;
50758
0
        }
50759
0
        rnd_mode = BF_RNDNA;
50760
0
        if (argc > 1) {
50761
0
            rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
50762
0
            if (rnd_mode < 0)
50763
0
                goto fail;
50764
0
        }
50765
0
        ret = js_bigdecimal_to_string1(ctx, val, f + 1,
50766
0
                      rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
50767
0
    }
50768
0
    JS_FreeValue(ctx, val);
50769
0
    return ret;
50770
0
 fail:
50771
0
    JS_FreeValue(ctx, val);
50772
0
    return JS_EXCEPTION;
50773
0
}
50774
50775
static JSValue js_bigdecimal_toPrecision(JSContext *ctx, JSValueConst this_val,
50776
                                     int argc, JSValueConst *argv)
50777
0
{
50778
0
    JSValue val, ret;
50779
0
    int64_t p;
50780
0
    int rnd_mode;
50781
50782
0
    val = js_thisBigDecimalValue(ctx, this_val);
50783
0
    if (JS_IsException(val))
50784
0
        return val;
50785
0
    if (JS_IsUndefined(argv[0])) {
50786
0
        return JS_ToStringFree(ctx, val);
50787
0
    }
50788
0
    if (JS_ToInt64Sat(ctx, &p, argv[0]))
50789
0
        goto fail;
50790
0
    if (p < 1 || p > BF_PREC_MAX) {
50791
0
        JS_ThrowRangeError(ctx, "invalid number of digits");
50792
0
        goto fail;
50793
0
    }
50794
0
    rnd_mode = BF_RNDNA;
50795
0
    if (argc > 1) {
50796
0
        rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
50797
0
        if (rnd_mode < 0)
50798
0
            goto fail;
50799
0
    }
50800
0
    ret = js_bigdecimal_to_string1(ctx, val, p,
50801
0
                                   rnd_mode | BF_FTOA_FORMAT_FIXED);
50802
0
    JS_FreeValue(ctx, val);
50803
0
    return ret;
50804
0
 fail:
50805
0
    JS_FreeValue(ctx, val);
50806
0
    return JS_EXCEPTION;
50807
0
}
50808
50809
static const JSCFunctionListEntry js_bigdecimal_proto_funcs[] = {
50810
    JS_CFUNC_DEF("toString", 0, js_bigdecimal_toString ),
50811
    JS_CFUNC_DEF("valueOf", 0, js_bigdecimal_valueOf ),
50812
    JS_CFUNC_DEF("toPrecision", 1, js_bigdecimal_toPrecision ),
50813
    JS_CFUNC_DEF("toFixed", 1, js_bigdecimal_toFixed ),
50814
    JS_CFUNC_DEF("toExponential", 1, js_bigdecimal_toExponential ),
50815
};
50816
50817
static const JSCFunctionListEntry js_bigdecimal_funcs[] = {
50818
    JS_CFUNC_MAGIC_DEF("add", 2, js_bigdecimal_fop, MATH_OP_ADD ),
50819
    JS_CFUNC_MAGIC_DEF("sub", 2, js_bigdecimal_fop, MATH_OP_SUB ),
50820
    JS_CFUNC_MAGIC_DEF("mul", 2, js_bigdecimal_fop, MATH_OP_MUL ),
50821
    JS_CFUNC_MAGIC_DEF("div", 2, js_bigdecimal_fop, MATH_OP_DIV ),
50822
    JS_CFUNC_MAGIC_DEF("mod", 2, js_bigdecimal_fop, MATH_OP_FMOD ),
50823
    JS_CFUNC_MAGIC_DEF("round", 1, js_bigdecimal_fop, MATH_OP_ROUND ),
50824
    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigdecimal_fop, MATH_OP_SQRT ),
50825
};
50826
50827
void JS_AddIntrinsicBigDecimal(JSContext *ctx)
50828
0
{
50829
0
    JSRuntime *rt = ctx->rt;
50830
0
    JSValueConst obj1;
50831
50832
0
    rt->bigdecimal_ops.to_string = js_bigdecimal_to_string;
50833
0
    rt->bigdecimal_ops.from_string = js_string_to_bigdecimal;
50834
0
    rt->bigdecimal_ops.unary_arith = js_unary_arith_bigdecimal;
50835
0
    rt->bigdecimal_ops.binary_arith = js_binary_arith_bigdecimal;
50836
0
    rt->bigdecimal_ops.compare = js_compare_bigdecimal;
50837
50838
0
    ctx->class_proto[JS_CLASS_BIG_DECIMAL] = JS_NewObject(ctx);
50839
0
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL],
50840
0
                               js_bigdecimal_proto_funcs,
50841
0
                               countof(js_bigdecimal_proto_funcs));
50842
0
    obj1 = JS_NewGlobalCConstructor(ctx, "BigDecimal",
50843
0
                                    js_bigdecimal_constructor, 1,
50844
0
                                    ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
50845
0
    JS_SetPropertyFunctionList(ctx, obj1, js_bigdecimal_funcs,
50846
0
                               countof(js_bigdecimal_funcs));
50847
0
}
50848
50849
void JS_EnableBignumExt(JSContext *ctx, BOOL enable)
50850
0
{
50851
0
    ctx->bignum_ext = enable;
50852
0
}
50853
50854
#endif /* CONFIG_BIGNUM */
50855
50856
static const char * const native_error_name[JS_NATIVE_ERROR_COUNT] = {
50857
    "EvalError", "RangeError", "ReferenceError",
50858
    "SyntaxError", "TypeError", "URIError",
50859
    "InternalError", "AggregateError",
50860
};
50861
50862
/* Minimum amount of objects to be able to compile code and display
50863
   error messages. No JSAtom should be allocated by this function. */
50864
static void JS_AddIntrinsicBasicObjects(JSContext *ctx)
50865
3
{
50866
3
    JSValue proto;
50867
3
    int i;
50868
50869
3
    ctx->class_proto[JS_CLASS_OBJECT] = JS_NewObjectProto(ctx, JS_NULL);
50870
3
    ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, "", 0,
50871
3
                                           JS_CFUNC_generic, 0,
50872
3
                                           ctx->class_proto[JS_CLASS_OBJECT]);
50873
3
    ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = JS_DupValue(ctx, ctx->function_proto);
50874
3
    ctx->class_proto[JS_CLASS_ERROR] = JS_NewObject(ctx);
50875
#if 0
50876
    /* these are auto-initialized from js_error_proto_funcs,
50877
       but delaying might be a problem */
50878
    JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_name,
50879
                           JS_AtomToString(ctx, JS_ATOM_Error),
50880
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
50881
    JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_message,
50882
                           JS_AtomToString(ctx, JS_ATOM_empty_string),
50883
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
50884
#endif
50885
3
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ERROR],
50886
3
                               js_error_proto_funcs,
50887
3
                               countof(js_error_proto_funcs));
50888
50889
27
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
50890
24
        proto = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ERROR]);
50891
24
        JS_DefinePropertyValue(ctx, proto, JS_ATOM_name,
50892
24
                               JS_NewAtomString(ctx, native_error_name[i]),
50893
24
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
50894
24
        JS_DefinePropertyValue(ctx, proto, JS_ATOM_message,
50895
24
                               JS_AtomToString(ctx, JS_ATOM_empty_string),
50896
24
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
50897
24
        ctx->native_error_proto[i] = proto;
50898
24
    }
50899
50900
    /* the array prototype is an array */
50901
3
    ctx->class_proto[JS_CLASS_ARRAY] =
50902
3
        JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
50903
3
                               JS_CLASS_ARRAY);
50904
50905
3
    ctx->array_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]),
50906
3
                                     JS_PROP_INITIAL_HASH_SIZE, 1);
50907
3
    add_shape_property(ctx, &ctx->array_shape, NULL,
50908
3
                       JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH);
50909
50910
    /* XXX: could test it on first context creation to ensure that no
50911
       new atoms are created in JS_AddIntrinsicBasicObjects(). It is
50912
       necessary to avoid useless renumbering of atoms after
50913
       JS_EvalBinary() if it is done just after
50914
       JS_AddIntrinsicBasicObjects(). */
50915
    //    assert(ctx->rt->atom_count == JS_ATOM_END);
50916
3
}
50917
50918
void JS_AddIntrinsicBaseObjects(JSContext *ctx)
50919
2
{
50920
2
    int i;
50921
2
    JSValueConst obj, number_obj;
50922
2
    JSValue obj1;
50923
50924
2
    ctx->throw_type_error = JS_NewCFunction(ctx, js_throw_type_error, NULL, 0);
50925
50926
    /* add caller and arguments properties to throw a TypeError */
50927
2
    obj1 = JS_NewCFunction(ctx, js_function_proto_caller, NULL, 0);
50928
2
    JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_caller, JS_UNDEFINED,
50929
2
                      obj1, ctx->throw_type_error,
50930
2
                      JS_PROP_HAS_GET | JS_PROP_HAS_SET |
50931
2
                      JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
50932
2
    JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_arguments, JS_UNDEFINED,
50933
2
                      obj1, ctx->throw_type_error,
50934
2
                      JS_PROP_HAS_GET | JS_PROP_HAS_SET |
50935
2
                      JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
50936
2
    JS_FreeValue(ctx, obj1);
50937
2
    JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, (JSValueConst *)&ctx->throw_type_error, 1));
50938
50939
2
    ctx->global_obj = JS_NewObject(ctx);
50940
2
    ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL);
50941
50942
    /* Object */
50943
2
    obj = JS_NewGlobalCConstructor(ctx, "Object", js_object_constructor, 1,
50944
2
                                   ctx->class_proto[JS_CLASS_OBJECT]);
50945
2
    JS_SetPropertyFunctionList(ctx, obj, js_object_funcs, countof(js_object_funcs));
50946
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_OBJECT],
50947
2
                               js_object_proto_funcs, countof(js_object_proto_funcs));
50948
50949
    /* Function */
50950
2
    JS_SetPropertyFunctionList(ctx, ctx->function_proto, js_function_proto_funcs, countof(js_function_proto_funcs));
50951
2
    ctx->function_ctor = JS_NewCFunctionMagic(ctx, js_function_constructor,
50952
2
                                              "Function", 1, JS_CFUNC_constructor_or_func_magic,
50953
2
                                              JS_FUNC_NORMAL);
50954
2
    JS_NewGlobalCConstructor2(ctx, JS_DupValue(ctx, ctx->function_ctor), "Function",
50955
2
                              ctx->function_proto);
50956
50957
    /* Error */
50958
2
    obj1 = JS_NewCFunctionMagic(ctx, js_error_constructor,
50959
2
                                "Error", 1, JS_CFUNC_constructor_or_func_magic, -1);
50960
2
    JS_NewGlobalCConstructor2(ctx, obj1,
50961
2
                              "Error", ctx->class_proto[JS_CLASS_ERROR]);
50962
50963
18
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
50964
16
        JSValue func_obj;
50965
16
        int n_args;
50966
16
        n_args = 1 + (i == JS_AGGREGATE_ERROR);
50967
16
        func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_error_constructor,
50968
16
                                    native_error_name[i], n_args,
50969
16
                                    JS_CFUNC_constructor_or_func_magic, i, obj1);
50970
16
        JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i],
50971
16
                                  ctx->native_error_proto[i]);
50972
16
    }
50973
50974
    /* Iterator prototype */
50975
2
    ctx->iterator_proto = JS_NewObject(ctx);
50976
2
    JS_SetPropertyFunctionList(ctx, ctx->iterator_proto,
50977
2
                               js_iterator_proto_funcs,
50978
2
                               countof(js_iterator_proto_funcs));
50979
50980
    /* Array */
50981
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY],
50982
2
                               js_array_proto_funcs,
50983
2
                               countof(js_array_proto_funcs));
50984
50985
2
    obj = JS_NewGlobalCConstructor(ctx, "Array", js_array_constructor, 1,
50986
2
                                   ctx->class_proto[JS_CLASS_ARRAY]);
50987
2
    ctx->array_ctor = JS_DupValue(ctx, obj);
50988
2
    JS_SetPropertyFunctionList(ctx, obj, js_array_funcs,
50989
2
                               countof(js_array_funcs));
50990
50991
    /* XXX: create auto_initializer */
50992
2
    {
50993
        /* initialize Array.prototype[Symbol.unscopables] */
50994
2
        char const unscopables[] = "copyWithin" "\0" "entries" "\0" "fill" "\0" "find" "\0"
50995
2
            "findIndex" "\0" "flat" "\0" "flatMap" "\0" "includes" "\0" "keys" "\0" "values" "\0";
50996
2
        const char *p = unscopables;
50997
2
        obj1 = JS_NewObjectProto(ctx, JS_NULL);
50998
22
        for(p = unscopables; *p; p += strlen(p) + 1) {
50999
20
            JS_DefinePropertyValueStr(ctx, obj1, p, JS_TRUE, JS_PROP_C_W_E);
51000
20
        }
51001
2
        JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ARRAY],
51002
2
                               JS_ATOM_Symbol_unscopables, obj1,
51003
2
                               JS_PROP_CONFIGURABLE);
51004
2
    }
51005
51006
    /* needed to initialize arguments[Symbol.iterator] */
51007
2
    ctx->array_proto_values =
51008
2
        JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_values);
51009
51010
2
    ctx->class_proto[JS_CLASS_ARRAY_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
51011
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_ITERATOR],
51012
2
                               js_array_iterator_proto_funcs,
51013
2
                               countof(js_array_iterator_proto_funcs));
51014
51015
    /* parseFloat and parseInteger must be defined before Number
51016
       because of the Number.parseFloat and Number.parseInteger
51017
       aliases */
51018
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_global_funcs,
51019
2
                               countof(js_global_funcs));
51020
51021
    /* Number */
51022
2
    ctx->class_proto[JS_CLASS_NUMBER] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
51023
2
                                                               JS_CLASS_NUMBER);
51024
2
    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_NUMBER], JS_NewInt32(ctx, 0));
51025
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_NUMBER],
51026
2
                               js_number_proto_funcs,
51027
2
                               countof(js_number_proto_funcs));
51028
2
    number_obj = JS_NewGlobalCConstructor(ctx, "Number", js_number_constructor, 1,
51029
2
                                          ctx->class_proto[JS_CLASS_NUMBER]);
51030
2
    JS_SetPropertyFunctionList(ctx, number_obj, js_number_funcs, countof(js_number_funcs));
51031
51032
    /* Boolean */
51033
2
    ctx->class_proto[JS_CLASS_BOOLEAN] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
51034
2
                                                                JS_CLASS_BOOLEAN);
51035
2
    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], JS_NewBool(ctx, FALSE));
51036
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], js_boolean_proto_funcs,
51037
2
                               countof(js_boolean_proto_funcs));
51038
2
    JS_NewGlobalCConstructor(ctx, "Boolean", js_boolean_constructor, 1,
51039
2
                             ctx->class_proto[JS_CLASS_BOOLEAN]);
51040
51041
    /* String */
51042
2
    ctx->class_proto[JS_CLASS_STRING] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
51043
2
                                                               JS_CLASS_STRING);
51044
2
    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_STRING], JS_AtomToString(ctx, JS_ATOM_empty_string));
51045
2
    obj = JS_NewGlobalCConstructor(ctx, "String", js_string_constructor, 1,
51046
2
                                   ctx->class_proto[JS_CLASS_STRING]);
51047
2
    JS_SetPropertyFunctionList(ctx, obj, js_string_funcs,
51048
2
                               countof(js_string_funcs));
51049
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_funcs,
51050
2
                               countof(js_string_proto_funcs));
51051
51052
2
    ctx->class_proto[JS_CLASS_STRING_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
51053
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING_ITERATOR],
51054
2
                               js_string_iterator_proto_funcs,
51055
2
                               countof(js_string_iterator_proto_funcs));
51056
51057
    /* Math: create as autoinit object */
51058
2
    js_random_init(ctx);
51059
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_math_obj, countof(js_math_obj));
51060
51061
    /* ES6 Reflect: create as autoinit object */
51062
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_reflect_obj, countof(js_reflect_obj));
51063
51064
    /* ES6 Symbol */
51065
2
    ctx->class_proto[JS_CLASS_SYMBOL] = JS_NewObject(ctx);
51066
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SYMBOL], js_symbol_proto_funcs,
51067
2
                               countof(js_symbol_proto_funcs));
51068
2
    obj = JS_NewGlobalCConstructor(ctx, "Symbol", js_symbol_constructor, 0,
51069
2
                                   ctx->class_proto[JS_CLASS_SYMBOL]);
51070
2
    JS_SetPropertyFunctionList(ctx, obj, js_symbol_funcs,
51071
2
                               countof(js_symbol_funcs));
51072
30
    for(i = JS_ATOM_Symbol_toPrimitive; i < JS_ATOM_END; i++) {
51073
28
        char buf[ATOM_GET_STR_BUF_SIZE];
51074
28
        const char *str, *p;
51075
28
        str = JS_AtomGetStr(ctx, buf, sizeof(buf), i);
51076
        /* skip "Symbol." */
51077
28
        p = strchr(str, '.');
51078
28
        if (p)
51079
28
            str = p + 1;
51080
28
        JS_DefinePropertyValueStr(ctx, obj, str, JS_AtomToValue(ctx, i), 0);
51081
28
    }
51082
51083
    /* ES6 Generator */
51084
2
    ctx->class_proto[JS_CLASS_GENERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
51085
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_GENERATOR],
51086
2
                               js_generator_proto_funcs,
51087
2
                               countof(js_generator_proto_funcs));
51088
51089
2
    ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
51090
2
    obj1 = JS_NewCFunctionMagic(ctx, js_function_constructor,
51091
2
                                "GeneratorFunction", 1,
51092
2
                                JS_CFUNC_constructor_or_func_magic, JS_FUNC_GENERATOR);
51093
2
    JS_SetPropertyFunctionList(ctx,
51094
2
                               ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
51095
2
                               js_generator_function_proto_funcs,
51096
2
                               countof(js_generator_function_proto_funcs));
51097
2
    JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
51098
2
                       ctx->class_proto[JS_CLASS_GENERATOR],
51099
2
                       JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
51100
2
    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
51101
2
                       0, JS_PROP_CONFIGURABLE);
51102
2
    JS_FreeValue(ctx, obj1);
51103
51104
    /* global properties */
51105
2
    ctx->eval_obj = JS_NewCFunction(ctx, js_global_eval, "eval", 1);
51106
2
    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_eval,
51107
2
                           JS_DupValue(ctx, ctx->eval_obj),
51108
2
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
51109
51110
2
    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_globalThis,
51111
2
                           JS_DupValue(ctx, ctx->global_obj),
51112
2
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
51113
2
}
51114
51115
/* Typed Arrays */
51116
51117
static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = {
51118
    0, 0, 0, 1, 1, 2, 2,
51119
#ifdef CONFIG_BIGNUM
51120
    3, 3, /* BigInt64Array, BigUint64Array */
51121
#endif
51122
    2, 3
51123
};
51124
51125
static JSValue js_array_buffer_constructor3(JSContext *ctx,
51126
                                            JSValueConst new_target,
51127
                                            uint64_t len, JSClassID class_id,
51128
                                            uint8_t *buf,
51129
                                            JSFreeArrayBufferDataFunc *free_func,
51130
                                            void *opaque, BOOL alloc_flag)
51131
0
{
51132
0
    JSRuntime *rt = ctx->rt;
51133
0
    JSValue obj;
51134
0
    JSArrayBuffer *abuf = NULL;
51135
51136
0
    obj = js_create_from_ctor(ctx, new_target, class_id);
51137
0
    if (JS_IsException(obj))
51138
0
        return obj;
51139
    /* XXX: we are currently limited to 2 GB */
51140
0
    if (len > INT32_MAX) {
51141
0
        JS_ThrowRangeError(ctx, "invalid array buffer length");
51142
0
        goto fail;
51143
0
    }
51144
0
    abuf = js_malloc(ctx, sizeof(*abuf));
51145
0
    if (!abuf)
51146
0
        goto fail;
51147
0
    abuf->byte_length = len;
51148
0
    if (alloc_flag) {
51149
0
        if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
51150
0
            rt->sab_funcs.sab_alloc) {
51151
0
            abuf->data = rt->sab_funcs.sab_alloc(rt->sab_funcs.sab_opaque,
51152
0
                                                 max_int(len, 1));
51153
0
            if (!abuf->data)
51154
0
                goto fail;
51155
0
            memset(abuf->data, 0, len);
51156
0
        } else {
51157
            /* the allocation must be done after the object creation */
51158
0
            abuf->data = js_mallocz(ctx, max_int(len, 1));
51159
0
            if (!abuf->data)
51160
0
                goto fail;
51161
0
        }
51162
0
    } else {
51163
0
        if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
51164
0
            rt->sab_funcs.sab_dup) {
51165
0
            rt->sab_funcs.sab_dup(rt->sab_funcs.sab_opaque, buf);
51166
0
        }
51167
0
        abuf->data = buf;
51168
0
    }
51169
0
    init_list_head(&abuf->array_list);
51170
0
    abuf->detached = FALSE;
51171
0
    abuf->shared = (class_id == JS_CLASS_SHARED_ARRAY_BUFFER);
51172
0
    abuf->opaque = opaque;
51173
0
    abuf->free_func = free_func;
51174
0
    if (alloc_flag && buf)
51175
0
        memcpy(abuf->data, buf, len);
51176
0
    JS_SetOpaque(obj, abuf);
51177
0
    return obj;
51178
0
 fail:
51179
0
    JS_FreeValue(ctx, obj);
51180
0
    js_free(ctx, abuf);
51181
0
    return JS_EXCEPTION;
51182
0
}
51183
51184
static void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr)
51185
0
{
51186
0
    js_free_rt(rt, ptr);
51187
0
}
51188
51189
static JSValue js_array_buffer_constructor2(JSContext *ctx,
51190
                                            JSValueConst new_target,
51191
                                            uint64_t len, JSClassID class_id)
51192
0
{
51193
0
    return js_array_buffer_constructor3(ctx, new_target, len, class_id,
51194
0
                                        NULL, js_array_buffer_free, NULL,
51195
0
                                        TRUE);
51196
0
}
51197
51198
static JSValue js_array_buffer_constructor1(JSContext *ctx,
51199
                                            JSValueConst new_target,
51200
                                            uint64_t len)
51201
0
{
51202
0
    return js_array_buffer_constructor2(ctx, new_target, len,
51203
0
                                        JS_CLASS_ARRAY_BUFFER);
51204
0
}
51205
51206
JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
51207
                          JSFreeArrayBufferDataFunc *free_func, void *opaque,
51208
                          BOOL is_shared)
51209
0
{
51210
0
    return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len,
51211
0
                                        is_shared ? JS_CLASS_SHARED_ARRAY_BUFFER : JS_CLASS_ARRAY_BUFFER,
51212
0
                                        buf, free_func, opaque, FALSE);
51213
0
}
51214
51215
/* create a new ArrayBuffer of length 'len' and copy 'buf' to it */
51216
JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len)
51217
0
{
51218
0
    return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len,
51219
0
                                        JS_CLASS_ARRAY_BUFFER,
51220
0
                                        (uint8_t *)buf,
51221
0
                                        js_array_buffer_free, NULL,
51222
0
                                        TRUE);
51223
0
}
51224
51225
static JSValue js_array_buffer_constructor(JSContext *ctx,
51226
                                           JSValueConst new_target,
51227
                                           int argc, JSValueConst *argv)
51228
0
{
51229
0
    uint64_t len;
51230
0
    if (JS_ToIndex(ctx, &len, argv[0]))
51231
0
        return JS_EXCEPTION;
51232
0
    return js_array_buffer_constructor1(ctx, new_target, len);
51233
0
}
51234
51235
static JSValue js_shared_array_buffer_constructor(JSContext *ctx,
51236
                                                  JSValueConst new_target,
51237
                                                  int argc, JSValueConst *argv)
51238
0
{
51239
0
    uint64_t len;
51240
0
    if (JS_ToIndex(ctx, &len, argv[0]))
51241
0
        return JS_EXCEPTION;
51242
0
    return js_array_buffer_constructor2(ctx, new_target, len,
51243
0
                                        JS_CLASS_SHARED_ARRAY_BUFFER);
51244
0
}
51245
51246
/* also used for SharedArrayBuffer */
51247
static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val)
51248
0
{
51249
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
51250
0
    JSArrayBuffer *abuf = p->u.array_buffer;
51251
0
    if (abuf) {
51252
        /* The ArrayBuffer finalizer may be called before the typed
51253
           array finalizers using it, so abuf->array_list is not
51254
           necessarily empty. */
51255
        // assert(list_empty(&abuf->array_list));
51256
0
        if (abuf->shared && rt->sab_funcs.sab_free) {
51257
0
            rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data);
51258
0
        } else {
51259
0
            if (abuf->free_func)
51260
0
                abuf->free_func(rt, abuf->opaque, abuf->data);
51261
0
        }
51262
0
        js_free_rt(rt, abuf);
51263
0
    }
51264
0
}
51265
51266
static JSValue js_array_buffer_isView(JSContext *ctx,
51267
                                      JSValueConst this_val,
51268
                                      int argc, JSValueConst *argv)
51269
0
{
51270
0
    JSObject *p;
51271
0
    BOOL res;
51272
0
    res = FALSE;
51273
0
    if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
51274
0
        p = JS_VALUE_GET_OBJ(argv[0]);
51275
0
        if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
51276
0
            p->class_id <= JS_CLASS_DATAVIEW) {
51277
0
            res = TRUE;
51278
0
        }
51279
0
    }
51280
0
    return JS_NewBool(ctx, res);
51281
0
}
51282
51283
static const JSCFunctionListEntry js_array_buffer_funcs[] = {
51284
    JS_CFUNC_DEF("isView", 1, js_array_buffer_isView ),
51285
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
51286
};
51287
51288
static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx)
51289
0
{
51290
0
    return JS_ThrowTypeError(ctx, "ArrayBuffer is detached");
51291
0
}
51292
51293
static JSValue js_array_buffer_get_byteLength(JSContext *ctx,
51294
                                              JSValueConst this_val,
51295
                                              int class_id)
51296
0
{
51297
0
    JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);
51298
0
    if (!abuf)
51299
0
        return JS_EXCEPTION;
51300
    /* return 0 if detached */
51301
0
    return JS_NewUint32(ctx, abuf->byte_length);
51302
0
}
51303
51304
void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
51305
0
{
51306
0
    JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);
51307
0
    struct list_head *el;
51308
51309
0
    if (!abuf || abuf->detached)
51310
0
        return;
51311
0
    if (abuf->free_func)
51312
0
        abuf->free_func(ctx->rt, abuf->opaque, abuf->data);
51313
0
    abuf->data = NULL;
51314
0
    abuf->byte_length = 0;
51315
0
    abuf->detached = TRUE;
51316
51317
0
    list_for_each(el, &abuf->array_list) {
51318
0
        JSTypedArray *ta;
51319
0
        JSObject *p;
51320
51321
0
        ta = list_entry(el, JSTypedArray, link);
51322
0
        p = ta->obj;
51323
        /* Note: the typed array length and offset fields are not modified */
51324
0
        if (p->class_id != JS_CLASS_DATAVIEW) {
51325
0
            p->u.array.count = 0;
51326
0
            p->u.array.u.ptr = NULL;
51327
0
        }
51328
0
    }
51329
0
}
51330
51331
/* get an ArrayBuffer or SharedArrayBuffer */
51332
static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj)
51333
0
{
51334
0
    JSObject *p;
51335
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
51336
0
        goto fail;
51337
0
    p = JS_VALUE_GET_OBJ(obj);
51338
0
    if (p->class_id != JS_CLASS_ARRAY_BUFFER &&
51339
0
        p->class_id != JS_CLASS_SHARED_ARRAY_BUFFER) {
51340
0
    fail:
51341
0
        JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_ARRAY_BUFFER);
51342
0
        return NULL;
51343
0
    }
51344
0
    return p->u.array_buffer;
51345
0
}
51346
51347
/* return NULL if exception. WARNING: any JS call can detach the
51348
   buffer and render the returned pointer invalid */
51349
uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj)
51350
0
{
51351
0
    JSArrayBuffer *abuf = js_get_array_buffer(ctx, obj);
51352
0
    if (!abuf)
51353
0
        goto fail;
51354
0
    if (abuf->detached) {
51355
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51356
0
        goto fail;
51357
0
    }
51358
0
    *psize = abuf->byte_length;
51359
0
    return abuf->data;
51360
0
 fail:
51361
0
    *psize = 0;
51362
0
    return NULL;
51363
0
}
51364
51365
static JSValue js_array_buffer_slice(JSContext *ctx,
51366
                                     JSValueConst this_val,
51367
                                     int argc, JSValueConst *argv, int class_id)
51368
0
{
51369
0
    JSArrayBuffer *abuf, *new_abuf;
51370
0
    int64_t len, start, end, new_len;
51371
0
    JSValue ctor, new_obj;
51372
51373
0
    abuf = JS_GetOpaque2(ctx, this_val, class_id);
51374
0
    if (!abuf)
51375
0
        return JS_EXCEPTION;
51376
0
    if (abuf->detached)
51377
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51378
0
    len = abuf->byte_length;
51379
51380
0
    if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
51381
0
        return JS_EXCEPTION;
51382
51383
0
    end = len;
51384
0
    if (!JS_IsUndefined(argv[1])) {
51385
0
        if (JS_ToInt64Clamp(ctx, &end, argv[1], 0, len, len))
51386
0
            return JS_EXCEPTION;
51387
0
    }
51388
0
    new_len = max_int64(end - start, 0);
51389
0
    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
51390
0
    if (JS_IsException(ctor))
51391
0
        return ctor;
51392
0
    if (JS_IsUndefined(ctor)) {
51393
0
        new_obj = js_array_buffer_constructor2(ctx, JS_UNDEFINED, new_len,
51394
0
                                               class_id);
51395
0
    } else {
51396
0
        JSValue args[1];
51397
0
        args[0] = JS_NewInt64(ctx, new_len);
51398
0
        new_obj = JS_CallConstructor(ctx, ctor, 1, (JSValueConst *)args);
51399
0
        JS_FreeValue(ctx, ctor);
51400
0
        JS_FreeValue(ctx, args[0]);
51401
0
    }
51402
0
    if (JS_IsException(new_obj))
51403
0
        return new_obj;
51404
0
    new_abuf = JS_GetOpaque2(ctx, new_obj, class_id);
51405
0
    if (!new_abuf)
51406
0
        goto fail;
51407
0
    if (js_same_value(ctx, new_obj, this_val)) {
51408
0
        JS_ThrowTypeError(ctx, "cannot use identical ArrayBuffer");
51409
0
        goto fail;
51410
0
    }
51411
0
    if (new_abuf->detached) {
51412
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51413
0
        goto fail;
51414
0
    }
51415
0
    if (new_abuf->byte_length < new_len) {
51416
0
        JS_ThrowTypeError(ctx, "new ArrayBuffer is too small");
51417
0
        goto fail;
51418
0
    }
51419
    /* must test again because of side effects */
51420
0
    if (abuf->detached) {
51421
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51422
0
        goto fail;
51423
0
    }
51424
0
    memcpy(new_abuf->data, abuf->data + start, new_len);
51425
0
    return new_obj;
51426
0
 fail:
51427
0
    JS_FreeValue(ctx, new_obj);
51428
0
    return JS_EXCEPTION;
51429
0
}
51430
51431
static const JSCFunctionListEntry js_array_buffer_proto_funcs[] = {
51432
    JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_ARRAY_BUFFER ),
51433
    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_ARRAY_BUFFER ),
51434
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "ArrayBuffer", JS_PROP_CONFIGURABLE ),
51435
};
51436
51437
/* SharedArrayBuffer */
51438
51439
static const JSCFunctionListEntry js_shared_array_buffer_funcs[] = {
51440
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
51441
};
51442
51443
static const JSCFunctionListEntry js_shared_array_buffer_proto_funcs[] = {
51444
    JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),
51445
    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_SHARED_ARRAY_BUFFER ),
51446
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "SharedArrayBuffer", JS_PROP_CONFIGURABLE ),
51447
};
51448
51449
static JSObject *get_typed_array(JSContext *ctx,
51450
                                 JSValueConst this_val,
51451
                                 int is_dataview)
51452
0
{
51453
0
    JSObject *p;
51454
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
51455
0
        goto fail;
51456
0
    p = JS_VALUE_GET_OBJ(this_val);
51457
0
    if (is_dataview) {
51458
0
        if (p->class_id != JS_CLASS_DATAVIEW)
51459
0
            goto fail;
51460
0
    } else {
51461
0
        if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&
51462
0
              p->class_id <= JS_CLASS_FLOAT64_ARRAY)) {
51463
0
        fail:
51464
0
            JS_ThrowTypeError(ctx, "not a %s", is_dataview ? "DataView" : "TypedArray");
51465
0
            return NULL;
51466
0
        }
51467
0
    }
51468
0
    return p;
51469
0
}
51470
51471
/* WARNING: 'p' must be a typed array */
51472
static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p)
51473
0
{
51474
0
    JSTypedArray *ta = p->u.typed_array;
51475
0
    JSArrayBuffer *abuf = ta->buffer->u.array_buffer;
51476
    /* XXX: could simplify test by ensuring that
51477
       p->u.array.u.ptr is NULL iff it is detached */
51478
0
    return abuf->detached;
51479
0
}
51480
51481
/* WARNING: 'p' must be a typed array. Works even if the array buffer
51482
   is detached */
51483
static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p)
51484
0
{
51485
0
    JSTypedArray *ta = p->u.typed_array;
51486
0
    int size_log2 = typed_array_size_log2(p->class_id);
51487
0
    return ta->length >> size_log2;
51488
0
}
51489
51490
static int validate_typed_array(JSContext *ctx, JSValueConst this_val)
51491
0
{
51492
0
    JSObject *p;
51493
0
    p = get_typed_array(ctx, this_val, 0);
51494
0
    if (!p)
51495
0
        return -1;
51496
0
    if (typed_array_is_detached(ctx, p)) {
51497
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51498
0
        return -1;
51499
0
    }
51500
0
    return 0;
51501
0
}
51502
51503
static JSValue js_typed_array_get_length(JSContext *ctx,
51504
                                         JSValueConst this_val)
51505
0
{
51506
0
    JSObject *p;
51507
0
    p = get_typed_array(ctx, this_val, 0);
51508
0
    if (!p)
51509
0
        return JS_EXCEPTION;
51510
0
    return JS_NewInt32(ctx, p->u.array.count);
51511
0
}
51512
51513
static JSValue js_typed_array_get_buffer(JSContext *ctx,
51514
                                         JSValueConst this_val, int is_dataview)
51515
0
{
51516
0
    JSObject *p;
51517
0
    JSTypedArray *ta;
51518
0
    p = get_typed_array(ctx, this_val, is_dataview);
51519
0
    if (!p)
51520
0
        return JS_EXCEPTION;
51521
0
    ta = p->u.typed_array;
51522
0
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
51523
0
}
51524
51525
static JSValue js_typed_array_get_byteLength(JSContext *ctx,
51526
                                             JSValueConst this_val,
51527
                                             int is_dataview)
51528
0
{
51529
0
    JSObject *p;
51530
0
    JSTypedArray *ta;
51531
0
    p = get_typed_array(ctx, this_val, is_dataview);
51532
0
    if (!p)
51533
0
        return JS_EXCEPTION;
51534
0
    if (typed_array_is_detached(ctx, p)) {
51535
0
        if (is_dataview) {
51536
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51537
0
        } else {
51538
0
            return JS_NewInt32(ctx, 0);
51539
0
        }
51540
0
    }
51541
0
    ta = p->u.typed_array;
51542
0
    return JS_NewInt32(ctx, ta->length);
51543
0
}
51544
51545
static JSValue js_typed_array_get_byteOffset(JSContext *ctx,
51546
                                             JSValueConst this_val,
51547
                                             int is_dataview)
51548
0
{
51549
0
    JSObject *p;
51550
0
    JSTypedArray *ta;
51551
0
    p = get_typed_array(ctx, this_val, is_dataview);
51552
0
    if (!p)
51553
0
        return JS_EXCEPTION;
51554
0
    if (typed_array_is_detached(ctx, p)) {
51555
0
        if (is_dataview) {
51556
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51557
0
        } else {
51558
0
            return JS_NewInt32(ctx, 0);
51559
0
        }
51560
0
    }
51561
0
    ta = p->u.typed_array;
51562
0
    return JS_NewInt32(ctx, ta->offset);
51563
0
}
51564
51565
/* Return the buffer associated to the typed array or an exception if
51566
   it is not a typed array or if the buffer is detached. pbyte_offset,
51567
   pbyte_length or pbytes_per_element can be NULL. */
51568
JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
51569
                               size_t *pbyte_offset,
51570
                               size_t *pbyte_length,
51571
                               size_t *pbytes_per_element)
51572
0
{
51573
0
    JSObject *p;
51574
0
    JSTypedArray *ta;
51575
0
    p = get_typed_array(ctx, obj, FALSE);
51576
0
    if (!p)
51577
0
        return JS_EXCEPTION;
51578
0
    if (typed_array_is_detached(ctx, p))
51579
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51580
0
    ta = p->u.typed_array;
51581
0
    if (pbyte_offset)
51582
0
        *pbyte_offset = ta->offset;
51583
0
    if (pbyte_length)
51584
0
        *pbyte_length = ta->length;
51585
0
    if (pbytes_per_element) {
51586
0
        *pbytes_per_element = 1 << typed_array_size_log2(p->class_id);
51587
0
    }
51588
0
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
51589
0
}
51590
                               
51591
static JSValue js_typed_array_get_toStringTag(JSContext *ctx,
51592
                                              JSValueConst this_val)
51593
0
{
51594
0
    JSObject *p;
51595
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
51596
0
        return JS_UNDEFINED;
51597
0
    p = JS_VALUE_GET_OBJ(this_val);
51598
0
    if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&
51599
0
          p->class_id <= JS_CLASS_FLOAT64_ARRAY))
51600
0
        return JS_UNDEFINED;
51601
0
    return JS_AtomToString(ctx, ctx->rt->class_array[p->class_id].class_name);
51602
0
}
51603
51604
static JSValue js_typed_array_set_internal(JSContext *ctx,
51605
                                           JSValueConst dst,
51606
                                           JSValueConst src,
51607
                                           JSValueConst off)
51608
0
{
51609
0
    JSObject *p;
51610
0
    JSObject *src_p;
51611
0
    uint32_t i;
51612
0
    int64_t src_len, offset;
51613
0
    JSValue val, src_obj = JS_UNDEFINED;
51614
51615
0
    p = get_typed_array(ctx, dst, 0);
51616
0
    if (!p)
51617
0
        goto fail;
51618
0
    if (JS_ToInt64Sat(ctx, &offset, off))
51619
0
        goto fail;
51620
0
    if (offset < 0)
51621
0
        goto range_error;
51622
0
    if (typed_array_is_detached(ctx, p)) {
51623
0
    detached:
51624
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51625
0
        goto fail;
51626
0
    }
51627
0
    src_obj = JS_ToObject(ctx, src);
51628
0
    if (JS_IsException(src_obj))
51629
0
        goto fail;
51630
0
    src_p = JS_VALUE_GET_OBJ(src_obj);
51631
0
    if (src_p->class_id >= JS_CLASS_UINT8C_ARRAY &&
51632
0
        src_p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
51633
0
        JSTypedArray *dest_ta = p->u.typed_array;
51634
0
        JSArrayBuffer *dest_abuf = dest_ta->buffer->u.array_buffer;
51635
0
        JSTypedArray *src_ta = src_p->u.typed_array;
51636
0
        JSArrayBuffer *src_abuf = src_ta->buffer->u.array_buffer;
51637
0
        int shift = typed_array_size_log2(p->class_id);
51638
51639
0
        if (src_abuf->detached)
51640
0
            goto detached;
51641
51642
0
        src_len = src_p->u.array.count;
51643
0
        if (offset > (int64_t)(p->u.array.count - src_len))
51644
0
            goto range_error;
51645
51646
        /* copying between typed objects */
51647
0
        if (src_p->class_id == p->class_id) {
51648
            /* same type, use memmove */
51649
0
            memmove(dest_abuf->data + dest_ta->offset + (offset << shift),
51650
0
                    src_abuf->data + src_ta->offset, src_len << shift);
51651
0
            goto done;
51652
0
        }
51653
0
        if (dest_abuf->data == src_abuf->data) {
51654
            /* copying between the same buffer using different types of mappings
51655
               would require a temporary buffer */
51656
0
        }
51657
        /* otherwise, default behavior is slow but correct */
51658
0
    } else {
51659
0
        if (js_get_length64(ctx, &src_len, src_obj))
51660
0
            goto fail;
51661
0
        if (offset > (int64_t)(p->u.array.count - src_len)) {
51662
0
        range_error:
51663
0
            JS_ThrowRangeError(ctx, "invalid array length");
51664
0
            goto fail;
51665
0
        }
51666
0
    }
51667
0
    for(i = 0; i < src_len; i++) {
51668
0
        val = JS_GetPropertyUint32(ctx, src_obj, i);
51669
0
        if (JS_IsException(val))
51670
0
            goto fail;
51671
0
        if (JS_SetPropertyUint32(ctx, dst, offset + i, val) < 0)
51672
0
            goto fail;
51673
0
    }
51674
0
done:
51675
0
    JS_FreeValue(ctx, src_obj);
51676
0
    return JS_UNDEFINED;
51677
0
fail:
51678
0
    JS_FreeValue(ctx, src_obj);
51679
0
    return JS_EXCEPTION;
51680
0
}
51681
51682
static JSValue js_typed_array_set(JSContext *ctx,
51683
                                  JSValueConst this_val,
51684
                                  int argc, JSValueConst *argv)
51685
0
{
51686
0
    JSValueConst offset = JS_UNDEFINED;
51687
0
    if (argc > 1) {
51688
0
        offset = argv[1];
51689
0
    }
51690
0
    return js_typed_array_set_internal(ctx, this_val, argv[0], offset);
51691
0
}
51692
51693
static JSValue js_create_typed_array_iterator(JSContext *ctx, JSValueConst this_val,
51694
                                              int argc, JSValueConst *argv, int magic)
51695
0
{
51696
0
    if (validate_typed_array(ctx, this_val))
51697
0
        return JS_EXCEPTION;
51698
0
    return js_create_array_iterator(ctx, this_val, argc, argv, magic);
51699
0
}
51700
51701
/* return < 0 if exception */
51702
static int js_typed_array_get_length_internal(JSContext *ctx,
51703
                                              JSValueConst obj)
51704
0
{
51705
0
    JSObject *p;
51706
0
    p = get_typed_array(ctx, obj, 0);
51707
0
    if (!p)
51708
0
        return -1;
51709
0
    if (typed_array_is_detached(ctx, p)) {
51710
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51711
0
        return -1;
51712
0
    }
51713
0
    return p->u.array.count;
51714
0
}
51715
51716
#if 0
51717
/* validate a typed array and return its length */
51718
static JSValue js_typed_array___getLength(JSContext *ctx,
51719
                                          JSValueConst this_val,
51720
                                          int argc, JSValueConst *argv)
51721
{
51722
    BOOL ignore_detached = JS_ToBool(ctx, argv[1]);
51723
51724
    if (ignore_detached) {
51725
        return js_typed_array_get_length(ctx, argv[0]);
51726
    } else {
51727
        int len;
51728
        len = js_typed_array_get_length_internal(ctx, argv[0]);
51729
        if (len < 0)
51730
            return JS_EXCEPTION;
51731
        return JS_NewInt32(ctx, len);
51732
    }
51733
}
51734
#endif
51735
51736
static JSValue js_typed_array_create(JSContext *ctx, JSValueConst ctor,
51737
                                     int argc, JSValueConst *argv)
51738
0
{
51739
0
    JSValue ret;
51740
0
    int new_len;
51741
0
    int64_t len;
51742
51743
0
    ret = JS_CallConstructor(ctx, ctor, argc, argv);
51744
0
    if (JS_IsException(ret))
51745
0
        return ret;
51746
    /* validate the typed array */
51747
0
    new_len = js_typed_array_get_length_internal(ctx, ret);
51748
0
    if (new_len < 0)
51749
0
        goto fail;
51750
0
    if (argc == 1) {
51751
        /* ensure that it is large enough */
51752
0
        if (JS_ToLengthFree(ctx, &len, JS_DupValue(ctx, argv[0])))
51753
0
            goto fail;
51754
0
        if (new_len < len) {
51755
0
            JS_ThrowTypeError(ctx, "TypedArray length is too small");
51756
0
        fail:
51757
0
            JS_FreeValue(ctx, ret);
51758
0
            return JS_EXCEPTION;
51759
0
        }
51760
0
    }
51761
0
    return ret;
51762
0
}
51763
51764
#if 0
51765
static JSValue js_typed_array___create(JSContext *ctx,
51766
                                       JSValueConst this_val,
51767
                                       int argc, JSValueConst *argv)
51768
{
51769
    return js_typed_array_create(ctx, argv[0], max_int(argc - 1, 0), argv + 1);
51770
}
51771
#endif
51772
51773
static JSValue js_typed_array___speciesCreate(JSContext *ctx,
51774
                                              JSValueConst this_val,
51775
                                              int argc, JSValueConst *argv)
51776
0
{
51777
0
    JSValueConst obj;
51778
0
    JSObject *p;
51779
0
    JSValue ctor, ret;
51780
0
    int argc1;
51781
51782
0
    obj = argv[0];
51783
0
    p = get_typed_array(ctx, obj, 0);
51784
0
    if (!p)
51785
0
        return JS_EXCEPTION;
51786
0
    ctor = JS_SpeciesConstructor(ctx, obj, JS_UNDEFINED);
51787
0
    if (JS_IsException(ctor))
51788
0
        return ctor;
51789
0
    argc1 = max_int(argc - 1, 0);
51790
0
    if (JS_IsUndefined(ctor)) {
51791
0
        ret = js_typed_array_constructor(ctx, JS_UNDEFINED, argc1, argv + 1,
51792
0
                                         p->class_id);
51793
0
    } else {
51794
0
        ret = js_typed_array_create(ctx, ctor, argc1, argv + 1);
51795
0
        JS_FreeValue(ctx, ctor);
51796
0
    }
51797
0
    return ret;
51798
0
}
51799
51800
static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val,
51801
                                   int argc, JSValueConst *argv)
51802
0
{
51803
    // from(items, mapfn = void 0, this_arg = void 0)
51804
0
    JSValueConst items = argv[0], mapfn, this_arg;
51805
0
    JSValueConst args[2];
51806
0
    JSValue stack[2];
51807
0
    JSValue iter, arr, r, v, v2;
51808
0
    int64_t k, len;
51809
0
    int done, mapping;
51810
51811
0
    mapping = FALSE;
51812
0
    mapfn = JS_UNDEFINED;
51813
0
    this_arg = JS_UNDEFINED;
51814
0
    r = JS_UNDEFINED;
51815
0
    arr = JS_UNDEFINED;
51816
0
    stack[0] = JS_UNDEFINED;
51817
0
    stack[1] = JS_UNDEFINED;
51818
51819
0
    if (argc > 1) {
51820
0
        mapfn = argv[1];
51821
0
        if (!JS_IsUndefined(mapfn)) {
51822
0
            if (check_function(ctx, mapfn))
51823
0
                goto exception;
51824
0
            mapping = 1;
51825
0
            if (argc > 2)
51826
0
                this_arg = argv[2];
51827
0
        }
51828
0
    }
51829
0
    iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
51830
0
    if (JS_IsException(iter))
51831
0
        goto exception;
51832
0
    if (!JS_IsUndefined(iter)) {
51833
0
        JS_FreeValue(ctx, iter);
51834
0
        arr = JS_NewArray(ctx);
51835
0
        if (JS_IsException(arr))
51836
0
            goto exception;
51837
0
        stack[0] = JS_DupValue(ctx, items);
51838
0
        if (js_for_of_start(ctx, &stack[1], FALSE))
51839
0
            goto exception;
51840
0
        for (k = 0;; k++) {
51841
0
            v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done);
51842
0
            if (JS_IsException(v))
51843
0
                goto exception_close;
51844
0
            if (done)
51845
0
                break;
51846
0
            if (JS_DefinePropertyValueInt64(ctx, arr, k, v, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
51847
0
                goto exception_close;
51848
0
        }
51849
0
    } else {
51850
0
        arr = JS_ToObject(ctx, items);
51851
0
        if (JS_IsException(arr))
51852
0
            goto exception;
51853
0
    }
51854
0
    if (js_get_length64(ctx, &len, arr) < 0)
51855
0
        goto exception;
51856
0
    v = JS_NewInt64(ctx, len);
51857
0
    args[0] = v;
51858
0
    r = js_typed_array_create(ctx, this_val, 1, args);
51859
0
    JS_FreeValue(ctx, v);
51860
0
    if (JS_IsException(r))
51861
0
        goto exception;
51862
0
    for(k = 0; k < len; k++) {
51863
0
        v = JS_GetPropertyInt64(ctx, arr, k);
51864
0
        if (JS_IsException(v))
51865
0
            goto exception;
51866
0
        if (mapping) {
51867
0
            args[0] = v;
51868
0
            args[1] = JS_NewInt32(ctx, k);
51869
0
            v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
51870
0
            JS_FreeValue(ctx, v);
51871
0
            v = v2;
51872
0
            if (JS_IsException(v))
51873
0
                goto exception;
51874
0
        }
51875
0
        if (JS_SetPropertyInt64(ctx, r, k, v) < 0)
51876
0
            goto exception;
51877
0
    }
51878
0
    goto done;
51879
51880
0
 exception_close:
51881
0
    if (!JS_IsUndefined(stack[0]))
51882
0
        JS_IteratorClose(ctx, stack[0], TRUE);
51883
0
 exception:
51884
0
    JS_FreeValue(ctx, r);
51885
0
    r = JS_EXCEPTION;
51886
0
 done:
51887
0
    JS_FreeValue(ctx, arr);
51888
0
    JS_FreeValue(ctx, stack[0]);
51889
0
    JS_FreeValue(ctx, stack[1]);
51890
0
    return r;
51891
0
}
51892
51893
static JSValue js_typed_array_of(JSContext *ctx, JSValueConst this_val,
51894
                                 int argc, JSValueConst *argv)
51895
0
{
51896
0
    JSValue obj;
51897
0
    JSValueConst args[1];
51898
0
    int i;
51899
51900
0
    args[0] = JS_NewInt32(ctx, argc);
51901
0
    obj = js_typed_array_create(ctx, this_val, 1, args);
51902
0
    if (JS_IsException(obj))
51903
0
        return obj;
51904
51905
0
    for(i = 0; i < argc; i++) {
51906
0
        if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0) {
51907
0
            JS_FreeValue(ctx, obj);
51908
0
            return JS_EXCEPTION;
51909
0
        }
51910
0
    }
51911
0
    return obj;
51912
0
}
51913
51914
static JSValue js_typed_array_copyWithin(JSContext *ctx, JSValueConst this_val,
51915
                                         int argc, JSValueConst *argv)
51916
0
{
51917
0
    JSObject *p;
51918
0
    int len, to, from, final, count, shift;
51919
51920
0
    len = js_typed_array_get_length_internal(ctx, this_val);
51921
0
    if (len < 0)
51922
0
        return JS_EXCEPTION;
51923
51924
0
    if (JS_ToInt32Clamp(ctx, &to, argv[0], 0, len, len))
51925
0
        return JS_EXCEPTION;
51926
51927
0
    if (JS_ToInt32Clamp(ctx, &from, argv[1], 0, len, len))
51928
0
        return JS_EXCEPTION;
51929
51930
0
    final = len;
51931
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
51932
0
        if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
51933
0
            return JS_EXCEPTION;
51934
0
    }
51935
51936
0
    count = min_int(final - from, len - to);
51937
0
    if (count > 0) {
51938
0
        p = JS_VALUE_GET_OBJ(this_val);
51939
0
        if (typed_array_is_detached(ctx, p))
51940
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51941
0
        shift = typed_array_size_log2(p->class_id);
51942
0
        memmove(p->u.array.u.uint8_ptr + (to << shift),
51943
0
                p->u.array.u.uint8_ptr + (from << shift),
51944
0
                count << shift);
51945
0
    }
51946
0
    return JS_DupValue(ctx, this_val);
51947
0
}
51948
51949
static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val,
51950
                                   int argc, JSValueConst *argv)
51951
0
{
51952
0
    JSObject *p;
51953
0
    int len, k, final, shift;
51954
0
    uint64_t v64;
51955
51956
0
    len = js_typed_array_get_length_internal(ctx, this_val);
51957
0
    if (len < 0)
51958
0
        return JS_EXCEPTION;
51959
0
    p = JS_VALUE_GET_OBJ(this_val);
51960
51961
0
    if (p->class_id == JS_CLASS_UINT8C_ARRAY) {
51962
0
        int32_t v;
51963
0
        if (JS_ToUint8ClampFree(ctx, &v, JS_DupValue(ctx, argv[0])))
51964
0
            return JS_EXCEPTION;
51965
0
        v64 = v;
51966
0
    } else if (p->class_id <= JS_CLASS_UINT32_ARRAY) {
51967
0
        uint32_t v;
51968
0
        if (JS_ToUint32(ctx, &v, argv[0]))
51969
0
            return JS_EXCEPTION;
51970
0
        v64 = v;
51971
0
    } else
51972
0
#ifdef CONFIG_BIGNUM
51973
0
    if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
51974
0
        if (JS_ToBigInt64(ctx, (int64_t *)&v64, argv[0]))
51975
0
            return JS_EXCEPTION;
51976
0
    } else
51977
0
#endif
51978
0
    {
51979
0
        double d;
51980
0
        if (JS_ToFloat64(ctx, &d, argv[0]))
51981
0
            return JS_EXCEPTION;
51982
0
        if (p->class_id == JS_CLASS_FLOAT32_ARRAY) {
51983
0
            union {
51984
0
                float f;
51985
0
                uint32_t u32;
51986
0
            } u;
51987
0
            u.f = d;
51988
0
            v64 = u.u32;
51989
0
        } else {
51990
0
            JSFloat64Union u;
51991
0
            u.d = d;
51992
0
            v64 = u.u64;
51993
0
        }
51994
0
    }
51995
51996
0
    k = 0;
51997
0
    if (argc > 1) {
51998
0
        if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
51999
0
            return JS_EXCEPTION;
52000
0
    }
52001
52002
0
    final = len;
52003
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
52004
0
        if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
52005
0
            return JS_EXCEPTION;
52006
0
    }
52007
52008
0
    if (typed_array_is_detached(ctx, p))
52009
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
52010
    
52011
0
    shift = typed_array_size_log2(p->class_id);
52012
0
    switch(shift) {
52013
0
    case 0:
52014
0
        if (k < final) {
52015
0
            memset(p->u.array.u.uint8_ptr + k, v64, final - k);
52016
0
        }
52017
0
        break;
52018
0
    case 1:
52019
0
        for(; k < final; k++) {
52020
0
            p->u.array.u.uint16_ptr[k] = v64;
52021
0
        }
52022
0
        break;
52023
0
    case 2:
52024
0
        for(; k < final; k++) {
52025
0
            p->u.array.u.uint32_ptr[k] = v64;
52026
0
        }
52027
0
        break;
52028
0
    case 3:
52029
0
        for(; k < final; k++) {
52030
0
            p->u.array.u.uint64_ptr[k] = v64;
52031
0
        }
52032
0
        break;
52033
0
    default:
52034
0
        abort();
52035
0
    }
52036
0
    return JS_DupValue(ctx, this_val);
52037
0
}
52038
52039
static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
52040
                                   int argc, JSValueConst *argv, int findIndex)
52041
0
{
52042
0
    JSValueConst func, this_arg;
52043
0
    JSValueConst args[3];
52044
0
    JSValue val, index_val, res;
52045
0
    int len, k;
52046
52047
0
    val = JS_UNDEFINED;
52048
0
    len = js_typed_array_get_length_internal(ctx, this_val);
52049
0
    if (len < 0)
52050
0
        goto exception;
52051
52052
0
    func = argv[0];
52053
0
    if (check_function(ctx, func))
52054
0
        goto exception;
52055
52056
0
    this_arg = JS_UNDEFINED;
52057
0
    if (argc > 1)
52058
0
        this_arg = argv[1];
52059
52060
0
    for(k = 0; k < len; k++) {
52061
0
        index_val = JS_NewInt32(ctx, k);
52062
0
        val = JS_GetPropertyValue(ctx, this_val, index_val);
52063
0
        if (JS_IsException(val))
52064
0
            goto exception;
52065
0
        args[0] = val;
52066
0
        args[1] = index_val;
52067
0
        args[2] = this_val;
52068
0
        res = JS_Call(ctx, func, this_arg, 3, args);
52069
0
        if (JS_IsException(res))
52070
0
            goto exception;
52071
0
        if (JS_ToBoolFree(ctx, res)) {
52072
0
            if (findIndex) {
52073
0
                JS_FreeValue(ctx, val);
52074
0
                return index_val;
52075
0
            } else {
52076
0
                return val;
52077
0
            }
52078
0
        }
52079
0
        JS_FreeValue(ctx, val);
52080
0
    }
52081
0
    if (findIndex)
52082
0
        return JS_NewInt32(ctx, -1);
52083
0
    else
52084
0
        return JS_UNDEFINED;
52085
52086
0
exception:
52087
0
    JS_FreeValue(ctx, val);
52088
0
    return JS_EXCEPTION;
52089
0
}
52090
52091
#define special_indexOf 0
52092
0
#define special_lastIndexOf 1
52093
0
#define special_includes -1
52094
52095
static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
52096
                                      int argc, JSValueConst *argv, int special)
52097
0
{
52098
0
    JSObject *p;
52099
0
    int len, tag, is_int, is_bigint, k, stop, inc, res = -1;
52100
0
    int64_t v64;
52101
0
    double d;
52102
0
    float f;
52103
52104
0
    len = js_typed_array_get_length_internal(ctx, this_val);
52105
0
    if (len < 0)
52106
0
        goto exception;
52107
0
    if (len == 0)
52108
0
        goto done;
52109
52110
0
    if (special == special_lastIndexOf) {
52111
0
        k = len - 1;
52112
0
        if (argc > 1) {
52113
0
            if (JS_ToFloat64(ctx, &d, argv[1]))
52114
0
                goto exception;
52115
0
            if (isnan(d)) {
52116
0
                k = 0;
52117
0
            } else {
52118
0
                if (d >= 0) {
52119
0
                    if (d < k) {
52120
0
                        k = d;
52121
0
                    }
52122
0
                } else {
52123
0
                    d += len;
52124
0
                    if (d < 0)
52125
0
                        goto done;
52126
0
                    k = d;
52127
0
                }
52128
0
            }
52129
0
        }
52130
0
        stop = -1;
52131
0
        inc = -1;
52132
0
    } else {
52133
0
        k = 0;
52134
0
        if (argc > 1) {
52135
0
            if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
52136
0
                goto exception;
52137
0
        }
52138
0
        stop = len;
52139
0
        inc = 1;
52140
0
    }
52141
52142
0
    p = JS_VALUE_GET_OBJ(this_val);
52143
    /* if the array was detached, no need to go further (but no
52144
       exception is raised) */
52145
0
    if (typed_array_is_detached(ctx, p)) {
52146
        /* "includes" scans all the properties, so "undefined" can match */
52147
0
        if (special == special_includes && JS_IsUndefined(argv[0]) && len > 0)
52148
0
            res = 0;
52149
0
        goto done;
52150
0
    }
52151
    
52152
0
    is_bigint = 0;
52153
0
    is_int = 0; /* avoid warning */
52154
0
    v64 = 0; /* avoid warning */
52155
0
    tag = JS_VALUE_GET_NORM_TAG(argv[0]);
52156
0
    if (tag == JS_TAG_INT) {
52157
0
        is_int = 1;
52158
0
        v64 = JS_VALUE_GET_INT(argv[0]);
52159
0
        d = v64;
52160
0
    } else
52161
0
    if (tag == JS_TAG_FLOAT64) {
52162
0
        d = JS_VALUE_GET_FLOAT64(argv[0]);
52163
0
        v64 = d;
52164
0
        is_int = (v64 == d);
52165
0
    } else
52166
0
#ifdef CONFIG_BIGNUM
52167
0
    if (tag == JS_TAG_BIG_INT) {
52168
0
        JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]);
52169
        
52170
0
        if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {
52171
0
            if (bf_get_int64(&v64, &p1->num, 0) != 0)
52172
0
                goto done;
52173
0
        } else if (p->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
52174
0
            if (bf_get_uint64((uint64_t *)&v64, &p1->num) != 0)
52175
0
                goto done;
52176
0
        } else {
52177
0
            goto done;
52178
0
        }
52179
0
        d = 0;
52180
0
        is_bigint = 1;
52181
0
    } else
52182
0
#endif
52183
0
    {
52184
0
        goto done;
52185
0
    }
52186
52187
0
    switch (p->class_id) {
52188
0
    case JS_CLASS_INT8_ARRAY:
52189
0
        if (is_int && (int8_t)v64 == v64)
52190
0
            goto scan8;
52191
0
        break;
52192
0
    case JS_CLASS_UINT8C_ARRAY:
52193
0
    case JS_CLASS_UINT8_ARRAY:
52194
0
        if (is_int && (uint8_t)v64 == v64) {
52195
0
            const uint8_t *pv, *pp;
52196
0
            uint16_t v;
52197
0
        scan8:
52198
0
            pv = p->u.array.u.uint8_ptr;
52199
0
            v = v64;
52200
0
            if (inc > 0) {
52201
0
                pp = memchr(pv + k, v, len - k);
52202
0
                if (pp)
52203
0
                    res = pp - pv;
52204
0
            } else {
52205
0
                for (; k != stop; k += inc) {
52206
0
                    if (pv[k] == v) {
52207
0
                        res = k;
52208
0
                        break;
52209
0
                    }
52210
0
                }
52211
0
            }
52212
0
        }
52213
0
        break;
52214
0
    case JS_CLASS_INT16_ARRAY:
52215
0
        if (is_int && (int16_t)v64 == v64)
52216
0
            goto scan16;
52217
0
        break;
52218
0
    case JS_CLASS_UINT16_ARRAY:
52219
0
        if (is_int && (uint16_t)v64 == v64) {
52220
0
            const uint16_t *pv;
52221
0
            uint16_t v;
52222
0
        scan16:
52223
0
            pv = p->u.array.u.uint16_ptr;
52224
0
            v = v64;
52225
0
            for (; k != stop; k += inc) {
52226
0
                if (pv[k] == v) {
52227
0
                    res = k;
52228
0
                    break;
52229
0
                }
52230
0
            }
52231
0
        }
52232
0
        break;
52233
0
    case JS_CLASS_INT32_ARRAY:
52234
0
        if (is_int && (int32_t)v64 == v64)
52235
0
            goto scan32;
52236
0
        break;
52237
0
    case JS_CLASS_UINT32_ARRAY:
52238
0
        if (is_int && (uint32_t)v64 == v64) {
52239
0
            const uint32_t *pv;
52240
0
            uint32_t v;
52241
0
        scan32:
52242
0
            pv = p->u.array.u.uint32_ptr;
52243
0
            v = v64;
52244
0
            for (; k != stop; k += inc) {
52245
0
                if (pv[k] == v) {
52246
0
                    res = k;
52247
0
                    break;
52248
0
                }
52249
0
            }
52250
0
        }
52251
0
        break;
52252
0
    case JS_CLASS_FLOAT32_ARRAY:
52253
0
        if (is_bigint)
52254
0
            break;
52255
0
        if (isnan(d)) {
52256
0
            const float *pv = p->u.array.u.float_ptr;
52257
            /* special case: indexOf returns -1, includes finds NaN */
52258
0
            if (special != special_includes)
52259
0
                goto done;
52260
0
            for (; k != stop; k += inc) {
52261
0
                if (isnan(pv[k])) {
52262
0
                    res = k;
52263
0
                    break;
52264
0
                }
52265
0
            }
52266
0
        } else if ((f = (float)d) == d) {
52267
0
            const float *pv = p->u.array.u.float_ptr;
52268
0
            for (; k != stop; k += inc) {
52269
0
                if (pv[k] == f) {
52270
0
                    res = k;
52271
0
                    break;
52272
0
                }
52273
0
            }
52274
0
        }
52275
0
        break;
52276
0
    case JS_CLASS_FLOAT64_ARRAY:
52277
0
        if (is_bigint)
52278
0
            break;
52279
0
        if (isnan(d)) {
52280
0
            const double *pv = p->u.array.u.double_ptr;
52281
            /* special case: indexOf returns -1, includes finds NaN */
52282
0
            if (special != special_includes)
52283
0
                goto done;
52284
0
            for (; k != stop; k += inc) {
52285
0
                if (isnan(pv[k])) {
52286
0
                    res = k;
52287
0
                    break;
52288
0
                }
52289
0
            }
52290
0
        } else {
52291
0
            const double *pv = p->u.array.u.double_ptr;
52292
0
            for (; k != stop; k += inc) {
52293
0
                if (pv[k] == d) {
52294
0
                    res = k;
52295
0
                    break;
52296
0
                }
52297
0
            }
52298
0
        }
52299
0
        break;
52300
0
#ifdef CONFIG_BIGNUM
52301
0
    case JS_CLASS_BIG_INT64_ARRAY:
52302
0
        if (is_bigint || (is_math_mode(ctx) && is_int &&
52303
0
                          v64 >= -MAX_SAFE_INTEGER &&
52304
0
                          v64 <= MAX_SAFE_INTEGER)) {
52305
0
            goto scan64;
52306
0
        }
52307
0
        break;
52308
0
    case JS_CLASS_BIG_UINT64_ARRAY:
52309
0
        if (is_bigint || (is_math_mode(ctx) && is_int &&
52310
0
                          v64 >= 0 && v64 <= MAX_SAFE_INTEGER)) {
52311
0
            const uint64_t *pv;
52312
0
            uint64_t v;
52313
0
        scan64:
52314
0
            pv = p->u.array.u.uint64_ptr;
52315
0
            v = v64;
52316
0
            for (; k != stop; k += inc) {
52317
0
                if (pv[k] == v) {
52318
0
                    res = k;
52319
0
                    break;
52320
0
                }
52321
0
            }
52322
0
        }
52323
0
        break;
52324
0
#endif
52325
0
    }
52326
52327
0
done:
52328
0
    if (special == special_includes)
52329
0
        return JS_NewBool(ctx, res >= 0);
52330
0
    else
52331
0
        return JS_NewInt32(ctx, res);
52332
52333
0
exception:
52334
0
    return JS_EXCEPTION;
52335
0
}
52336
52337
static JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val,
52338
                                   int argc, JSValueConst *argv, int toLocaleString)
52339
0
{
52340
0
    JSValue sep = JS_UNDEFINED, el;
52341
0
    StringBuffer b_s, *b = &b_s;
52342
0
    JSString *p = NULL;
52343
0
    int i, n;
52344
0
    int c;
52345
52346
0
    n = js_typed_array_get_length_internal(ctx, this_val);
52347
0
    if (n < 0)
52348
0
        goto exception;
52349
52350
0
    c = ',';    /* default separator */
52351
0
    if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
52352
0
        sep = JS_ToString(ctx, argv[0]);
52353
0
        if (JS_IsException(sep))
52354
0
            goto exception;
52355
0
        p = JS_VALUE_GET_STRING(sep);
52356
0
        if (p->len == 1 && !p->is_wide_char)
52357
0
            c = p->u.str8[0];
52358
0
        else
52359
0
            c = -1;
52360
0
    }
52361
0
    string_buffer_init(ctx, b, 0);
52362
52363
    /* XXX: optimize with direct access */
52364
0
    for(i = 0; i < n; i++) {
52365
0
        if (i > 0) {
52366
0
            if (c >= 0) {
52367
0
                if (string_buffer_putc8(b, c))
52368
0
                    goto fail;
52369
0
            } else {
52370
0
                if (string_buffer_concat(b, p, 0, p->len))
52371
0
                    goto fail;
52372
0
            }
52373
0
        }
52374
0
        el = JS_GetPropertyUint32(ctx, this_val, i);
52375
        /* Can return undefined for example if the typed array is detached */
52376
0
        if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
52377
0
            if (JS_IsException(el))
52378
0
                goto fail;
52379
0
            if (toLocaleString) {
52380
0
                el = JS_ToLocaleStringFree(ctx, el);
52381
0
            }
52382
0
            if (string_buffer_concat_value_free(b, el))
52383
0
                goto fail;
52384
0
        }
52385
0
    }
52386
0
    JS_FreeValue(ctx, sep);
52387
0
    return string_buffer_end(b);
52388
52389
0
fail:
52390
0
    string_buffer_free(b);
52391
0
    JS_FreeValue(ctx, sep);
52392
0
exception:
52393
0
    return JS_EXCEPTION;
52394
0
}
52395
52396
static JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val,
52397
                                      int argc, JSValueConst *argv)
52398
0
{
52399
0
    JSObject *p;
52400
0
    int len;
52401
52402
0
    len = js_typed_array_get_length_internal(ctx, this_val);
52403
0
    if (len < 0)
52404
0
        return JS_EXCEPTION;
52405
0
    if (len > 0) {
52406
0
        p = JS_VALUE_GET_OBJ(this_val);
52407
0
        switch (typed_array_size_log2(p->class_id)) {
52408
0
        case 0:
52409
0
            {
52410
0
                uint8_t *p1 = p->u.array.u.uint8_ptr;
52411
0
                uint8_t *p2 = p1 + len - 1;
52412
0
                while (p1 < p2) {
52413
0
                    uint8_t v = *p1;
52414
0
                    *p1++ = *p2;
52415
0
                    *p2-- = v;
52416
0
                }
52417
0
            }
52418
0
            break;
52419
0
        case 1:
52420
0
            {
52421
0
                uint16_t *p1 = p->u.array.u.uint16_ptr;
52422
0
                uint16_t *p2 = p1 + len - 1;
52423
0
                while (p1 < p2) {
52424
0
                    uint16_t v = *p1;
52425
0
                    *p1++ = *p2;
52426
0
                    *p2-- = v;
52427
0
                }
52428
0
            }
52429
0
            break;
52430
0
        case 2:
52431
0
            {
52432
0
                uint32_t *p1 = p->u.array.u.uint32_ptr;
52433
0
                uint32_t *p2 = p1 + len - 1;
52434
0
                while (p1 < p2) {
52435
0
                    uint32_t v = *p1;
52436
0
                    *p1++ = *p2;
52437
0
                    *p2-- = v;
52438
0
                }
52439
0
            }
52440
0
            break;
52441
0
        case 3:
52442
0
            {
52443
0
                uint64_t *p1 = p->u.array.u.uint64_ptr;
52444
0
                uint64_t *p2 = p1 + len - 1;
52445
0
                while (p1 < p2) {
52446
0
                    uint64_t v = *p1;
52447
0
                    *p1++ = *p2;
52448
0
                    *p2-- = v;
52449
0
                }
52450
0
            }
52451
0
            break;
52452
0
        default:
52453
0
            abort();
52454
0
        }
52455
0
    }
52456
0
    return JS_DupValue(ctx, this_val);
52457
0
}
52458
52459
static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val,
52460
                                    int argc, JSValueConst *argv)
52461
0
{
52462
0
    JSValueConst args[2];
52463
0
    JSValue arr, val;
52464
0
    JSObject *p, *p1;
52465
0
    int n, len, start, final, count, shift;
52466
52467
0
    arr = JS_UNDEFINED;
52468
0
    len = js_typed_array_get_length_internal(ctx, this_val);
52469
0
    if (len < 0)
52470
0
        goto exception;
52471
52472
0
    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
52473
0
        goto exception;
52474
0
    final = len;
52475
0
    if (!JS_IsUndefined(argv[1])) {
52476
0
        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
52477
0
            goto exception;
52478
0
    }
52479
0
    count = max_int(final - start, 0);
52480
52481
0
    p = get_typed_array(ctx, this_val, 0);
52482
0
    if (p == NULL)
52483
0
        goto exception;
52484
0
    shift = typed_array_size_log2(p->class_id);
52485
52486
0
    args[0] = this_val;
52487
0
    args[1] = JS_NewInt32(ctx, count);
52488
0
    arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
52489
0
    if (JS_IsException(arr))
52490
0
        goto exception;
52491
52492
0
    if (count > 0) {
52493
0
        if (validate_typed_array(ctx, this_val)
52494
0
        ||  validate_typed_array(ctx, arr))
52495
0
            goto exception;
52496
52497
0
        p1 = get_typed_array(ctx, arr, 0);
52498
0
        if (p1 != NULL && p->class_id == p1->class_id &&
52499
0
            typed_array_get_length(ctx, p1) >= count &&
52500
0
            typed_array_get_length(ctx, p) >= start + count) {
52501
0
            memcpy(p1->u.array.u.uint8_ptr,
52502
0
                   p->u.array.u.uint8_ptr + (start << shift),
52503
0
                   count << shift);
52504
0
        } else {
52505
0
            for (n = 0; n < count; n++) {
52506
0
                val = JS_GetPropertyValue(ctx, this_val, JS_NewInt32(ctx, start + n));
52507
0
                if (JS_IsException(val))
52508
0
                    goto exception;
52509
0
                if (JS_SetPropertyValue(ctx, arr, JS_NewInt32(ctx, n), val,
52510
0
                                        JS_PROP_THROW) < 0)
52511
0
                    goto exception;
52512
0
            }
52513
0
        }
52514
0
    }
52515
0
    return arr;
52516
52517
0
 exception:
52518
0
    JS_FreeValue(ctx, arr);
52519
0
    return JS_EXCEPTION;
52520
0
}
52521
52522
static JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val,
52523
                                       int argc, JSValueConst *argv)
52524
0
{
52525
0
    JSValueConst args[4];
52526
0
    JSValue arr, byteOffset, ta_buffer;
52527
0
    JSObject *p;
52528
0
    int len, start, final, count, shift, offset;
52529
52530
0
    p = get_typed_array(ctx, this_val, 0);
52531
0
    if (!p)
52532
0
        goto exception;
52533
0
    len = p->u.array.count;
52534
0
    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
52535
0
        goto exception;
52536
52537
0
    final = len;
52538
0
    if (!JS_IsUndefined(argv[1])) {
52539
0
        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
52540
0
            goto exception;
52541
0
    }
52542
0
    count = max_int(final - start, 0);
52543
0
    byteOffset = js_typed_array_get_byteOffset(ctx, this_val, 0);
52544
0
    if (JS_IsException(byteOffset))
52545
0
        goto exception;
52546
0
    shift = typed_array_size_log2(p->class_id);
52547
0
    offset = JS_VALUE_GET_INT(byteOffset) + (start << shift);
52548
0
    JS_FreeValue(ctx, byteOffset);
52549
0
    ta_buffer = js_typed_array_get_buffer(ctx, this_val, 0);
52550
0
    if (JS_IsException(ta_buffer))
52551
0
        goto exception;
52552
0
    args[0] = this_val;
52553
0
    args[1] = ta_buffer;
52554
0
    args[2] = JS_NewInt32(ctx, offset);
52555
0
    args[3] = JS_NewInt32(ctx, count);
52556
0
    arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 4, args);
52557
0
    JS_FreeValue(ctx, ta_buffer);
52558
0
    return arr;
52559
52560
0
 exception:
52561
0
    return JS_EXCEPTION;
52562
0
}
52563
52564
/* TypedArray.prototype.sort */
52565
52566
static int js_cmp_doubles(double x, double y)
52567
0
{
52568
0
    if (isnan(x))    return isnan(y) ? 0 : +1;
52569
0
    if (isnan(y))    return -1;
52570
0
    if (x < y)       return -1;
52571
0
    if (x > y)       return 1;
52572
0
    if (x != 0)      return 0;
52573
0
    if (signbit(x))  return signbit(y) ? 0 : -1;
52574
0
    else             return signbit(y) ? 1 : 0;
52575
0
}
52576
52577
0
static int js_TA_cmp_int8(const void *a, const void *b, void *opaque) {
52578
0
    return *(const int8_t *)a - *(const int8_t *)b;
52579
0
}
52580
52581
0
static int js_TA_cmp_uint8(const void *a, const void *b, void *opaque) {
52582
0
    return *(const uint8_t *)a - *(const uint8_t *)b;
52583
0
}
52584
52585
0
static int js_TA_cmp_int16(const void *a, const void *b, void *opaque) {
52586
0
    return *(const int16_t *)a - *(const int16_t *)b;
52587
0
}
52588
52589
0
static int js_TA_cmp_uint16(const void *a, const void *b, void *opaque) {
52590
0
    return *(const uint16_t *)a - *(const uint16_t *)b;
52591
0
}
52592
52593
0
static int js_TA_cmp_int32(const void *a, const void *b, void *opaque) {
52594
0
    int32_t x = *(const int32_t *)a;
52595
0
    int32_t y = *(const int32_t *)b;
52596
0
    return (y < x) - (y > x);
52597
0
}
52598
52599
0
static int js_TA_cmp_uint32(const void *a, const void *b, void *opaque) {
52600
0
    uint32_t x = *(const uint32_t *)a;
52601
0
    uint32_t y = *(const uint32_t *)b;
52602
0
    return (y < x) - (y > x);
52603
0
}
52604
52605
#ifdef CONFIG_BIGNUM
52606
0
static int js_TA_cmp_int64(const void *a, const void *b, void *opaque) {
52607
0
    int64_t x = *(const int64_t *)a;
52608
0
    int64_t y = *(const int64_t *)b;
52609
0
    return (y < x) - (y > x);
52610
0
}
52611
52612
0
static int js_TA_cmp_uint64(const void *a, const void *b, void *opaque) {
52613
0
    uint64_t x = *(const uint64_t *)a;
52614
0
    uint64_t y = *(const uint64_t *)b;
52615
0
    return (y < x) - (y > x);
52616
0
}
52617
#endif
52618
52619
0
static int js_TA_cmp_float32(const void *a, const void *b, void *opaque) {
52620
0
    return js_cmp_doubles(*(const float *)a, *(const float *)b);
52621
0
}
52622
52623
0
static int js_TA_cmp_float64(const void *a, const void *b, void *opaque) {
52624
0
    return js_cmp_doubles(*(const double *)a, *(const double *)b);
52625
0
}
52626
52627
0
static JSValue js_TA_get_int8(JSContext *ctx, const void *a) {
52628
0
    return JS_NewInt32(ctx, *(const int8_t *)a);
52629
0
}
52630
52631
0
static JSValue js_TA_get_uint8(JSContext *ctx, const void *a) {
52632
0
    return JS_NewInt32(ctx, *(const uint8_t *)a);
52633
0
}
52634
52635
0
static JSValue js_TA_get_int16(JSContext *ctx, const void *a) {
52636
0
    return JS_NewInt32(ctx, *(const int16_t *)a);
52637
0
}
52638
52639
0
static JSValue js_TA_get_uint16(JSContext *ctx, const void *a) {
52640
0
    return JS_NewInt32(ctx, *(const uint16_t *)a);
52641
0
}
52642
52643
0
static JSValue js_TA_get_int32(JSContext *ctx, const void *a) {
52644
0
    return JS_NewInt32(ctx, *(const int32_t *)a);
52645
0
}
52646
52647
0
static JSValue js_TA_get_uint32(JSContext *ctx, const void *a) {
52648
0
    return JS_NewUint32(ctx, *(const uint32_t *)a);
52649
0
}
52650
52651
#ifdef CONFIG_BIGNUM
52652
0
static JSValue js_TA_get_int64(JSContext *ctx, const void *a) {
52653
0
    return JS_NewBigInt64(ctx, *(int64_t *)a);
52654
0
}
52655
52656
0
static JSValue js_TA_get_uint64(JSContext *ctx, const void *a) {
52657
0
    return JS_NewBigUint64(ctx, *(uint64_t *)a);
52658
0
}
52659
#endif
52660
52661
0
static JSValue js_TA_get_float32(JSContext *ctx, const void *a) {
52662
0
    return __JS_NewFloat64(ctx, *(const float *)a);
52663
0
}
52664
52665
0
static JSValue js_TA_get_float64(JSContext *ctx, const void *a) {
52666
0
    return __JS_NewFloat64(ctx, *(const double *)a);
52667
0
}
52668
52669
struct TA_sort_context {
52670
    JSContext *ctx;
52671
    int exception;
52672
    JSValueConst arr;
52673
    JSValueConst cmp;
52674
    JSValue (*getfun)(JSContext *ctx, const void *a);
52675
    uint8_t *array_ptr; /* cannot change unless the array is detached */
52676
    int elt_size;
52677
};
52678
52679
0
static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) {
52680
0
    struct TA_sort_context *psc = opaque;
52681
0
    JSContext *ctx = psc->ctx;
52682
0
    uint32_t a_idx, b_idx;
52683
0
    JSValueConst argv[2];
52684
0
    JSValue res;
52685
0
    int cmp;
52686
52687
0
    cmp = 0;
52688
0
    if (!psc->exception) {
52689
0
        a_idx = *(uint32_t *)a;
52690
0
        b_idx = *(uint32_t *)b;
52691
0
        argv[0] = psc->getfun(ctx, psc->array_ptr +
52692
0
                              a_idx * (size_t)psc->elt_size);
52693
0
        argv[1] = psc->getfun(ctx, psc->array_ptr +
52694
0
                              b_idx * (size_t)(psc->elt_size));
52695
0
        res = JS_Call(ctx, psc->cmp, JS_UNDEFINED, 2, argv);
52696
0
        if (JS_IsException(res)) {
52697
0
            psc->exception = 1;
52698
0
            goto done;
52699
0
        }
52700
0
        if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
52701
0
            int val = JS_VALUE_GET_INT(res);
52702
0
            cmp = (val > 0) - (val < 0);
52703
0
        } else {
52704
0
            double val;
52705
0
            if (JS_ToFloat64Free(ctx, &val, res) < 0) {
52706
0
                psc->exception = 1;
52707
0
                goto done;
52708
0
            } else {
52709
0
                cmp = (val > 0) - (val < 0);
52710
0
            }
52711
0
        }
52712
0
        if (cmp == 0) {
52713
            /* make sort stable: compare array offsets */
52714
0
            cmp = (a_idx > b_idx) - (a_idx < b_idx);
52715
0
        }
52716
0
        if (validate_typed_array(ctx, psc->arr) < 0) {
52717
0
            psc->exception = 1;
52718
0
        }
52719
0
    done:
52720
0
        JS_FreeValue(ctx, (JSValue)argv[0]);
52721
0
        JS_FreeValue(ctx, (JSValue)argv[1]);
52722
0
    }
52723
0
    return cmp;
52724
0
}
52725
52726
static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
52727
                                   int argc, JSValueConst *argv)
52728
0
{
52729
0
    JSObject *p;
52730
0
    int len;
52731
0
    size_t elt_size;
52732
0
    struct TA_sort_context tsc;
52733
0
    void *array_ptr;
52734
0
    int (*cmpfun)(const void *a, const void *b, void *opaque);
52735
52736
0
    tsc.ctx = ctx;
52737
0
    tsc.exception = 0;
52738
0
    tsc.arr = this_val;
52739
0
    tsc.cmp = argv[0];
52740
52741
0
    len = js_typed_array_get_length_internal(ctx, this_val);
52742
0
    if (len < 0)
52743
0
        return JS_EXCEPTION;
52744
0
    if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp))
52745
0
        return JS_EXCEPTION;
52746
52747
0
    if (len > 1) {
52748
0
        p = JS_VALUE_GET_OBJ(this_val);
52749
0
        switch (p->class_id) {
52750
0
        case JS_CLASS_INT8_ARRAY:
52751
0
            tsc.getfun = js_TA_get_int8;
52752
0
            cmpfun = js_TA_cmp_int8;
52753
0
            break;
52754
0
        case JS_CLASS_UINT8C_ARRAY:
52755
0
        case JS_CLASS_UINT8_ARRAY:
52756
0
            tsc.getfun = js_TA_get_uint8;
52757
0
            cmpfun = js_TA_cmp_uint8;
52758
0
            break;
52759
0
        case JS_CLASS_INT16_ARRAY:
52760
0
            tsc.getfun = js_TA_get_int16;
52761
0
            cmpfun = js_TA_cmp_int16;
52762
0
            break;
52763
0
        case JS_CLASS_UINT16_ARRAY:
52764
0
            tsc.getfun = js_TA_get_uint16;
52765
0
            cmpfun = js_TA_cmp_uint16;
52766
0
            break;
52767
0
        case JS_CLASS_INT32_ARRAY:
52768
0
            tsc.getfun = js_TA_get_int32;
52769
0
            cmpfun = js_TA_cmp_int32;
52770
0
            break;
52771
0
        case JS_CLASS_UINT32_ARRAY:
52772
0
            tsc.getfun = js_TA_get_uint32;
52773
0
            cmpfun = js_TA_cmp_uint32;
52774
0
            break;
52775
0
#ifdef CONFIG_BIGNUM
52776
0
        case JS_CLASS_BIG_INT64_ARRAY:
52777
0
            tsc.getfun = js_TA_get_int64;
52778
0
            cmpfun = js_TA_cmp_int64;
52779
0
            break;
52780
0
        case JS_CLASS_BIG_UINT64_ARRAY:
52781
0
            tsc.getfun = js_TA_get_uint64;
52782
0
            cmpfun = js_TA_cmp_uint64;
52783
0
            break;
52784
0
#endif
52785
0
        case JS_CLASS_FLOAT32_ARRAY:
52786
0
            tsc.getfun = js_TA_get_float32;
52787
0
            cmpfun = js_TA_cmp_float32;
52788
0
            break;
52789
0
        case JS_CLASS_FLOAT64_ARRAY:
52790
0
            tsc.getfun = js_TA_get_float64;
52791
0
            cmpfun = js_TA_cmp_float64;
52792
0
            break;
52793
0
        default:
52794
0
            abort();
52795
0
        }
52796
0
        array_ptr = p->u.array.u.ptr;
52797
0
        elt_size = 1 << typed_array_size_log2(p->class_id);
52798
0
        if (!JS_IsUndefined(tsc.cmp)) {
52799
0
            uint32_t *array_idx;
52800
0
            void *array_tmp;
52801
0
            size_t i, j;
52802
            
52803
            /* XXX: a stable sort would use less memory */
52804
0
            array_idx = js_malloc(ctx, len * sizeof(array_idx[0]));
52805
0
            if (!array_idx)
52806
0
                return JS_EXCEPTION;
52807
0
            for(i = 0; i < len; i++)
52808
0
                array_idx[i] = i;
52809
0
            tsc.array_ptr = array_ptr;
52810
0
            tsc.elt_size = elt_size;
52811
0
            rqsort(array_idx, len, sizeof(array_idx[0]),
52812
0
                   js_TA_cmp_generic, &tsc);
52813
0
            if (tsc.exception)
52814
0
                goto fail;
52815
0
            array_tmp = js_malloc(ctx, len * elt_size);
52816
0
            if (!array_tmp) {
52817
0
            fail:
52818
0
                js_free(ctx, array_idx);
52819
0
                return JS_EXCEPTION;
52820
0
            }
52821
0
            memcpy(array_tmp, array_ptr, len * elt_size);
52822
0
            switch(elt_size) {
52823
0
            case 1:
52824
0
                for(i = 0; i < len; i++) {
52825
0
                    j = array_idx[i];
52826
0
                    ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j];
52827
0
                }
52828
0
                break;
52829
0
            case 2:
52830
0
                for(i = 0; i < len; i++) {
52831
0
                    j = array_idx[i];
52832
0
                    ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j];
52833
0
                }
52834
0
                break;
52835
0
            case 4:
52836
0
                for(i = 0; i < len; i++) {
52837
0
                    j = array_idx[i];
52838
0
                    ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j];
52839
0
                }
52840
0
                break;
52841
0
            case 8:
52842
0
                for(i = 0; i < len; i++) {
52843
0
                    j = array_idx[i];
52844
0
                    ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j];
52845
0
                }
52846
0
                break;
52847
0
            default:
52848
0
                abort();
52849
0
            }
52850
0
            js_free(ctx, array_tmp);
52851
0
            js_free(ctx, array_idx);
52852
0
        } else {
52853
0
            rqsort(array_ptr, len, elt_size, cmpfun, &tsc);
52854
0
            if (tsc.exception)
52855
0
                return JS_EXCEPTION;
52856
0
        }
52857
0
    }
52858
0
    return JS_DupValue(ctx, this_val);
52859
0
}
52860
52861
static const JSCFunctionListEntry js_typed_array_base_funcs[] = {
52862
    JS_CFUNC_DEF("from", 1, js_typed_array_from ),
52863
    JS_CFUNC_DEF("of", 0, js_typed_array_of ),
52864
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
52865
    //JS_CFUNC_DEF("__getLength", 2, js_typed_array___getLength ),
52866
    //JS_CFUNC_DEF("__create", 2, js_typed_array___create ),
52867
    //JS_CFUNC_DEF("__speciesCreate", 2, js_typed_array___speciesCreate ),
52868
};
52869
52870
static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = {
52871
    JS_CGETSET_DEF("length", js_typed_array_get_length, NULL ),
52872
    JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 0 ),
52873
    JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 0 ),
52874
    JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 0 ),
52875
    JS_CFUNC_DEF("set", 1, js_typed_array_set ),
52876
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_VALUE ),
52877
    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
52878
    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY ),
52879
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
52880
    JS_CGETSET_DEF("[Symbol.toStringTag]", js_typed_array_get_toStringTag, NULL ),
52881
    JS_CFUNC_DEF("copyWithin", 2, js_typed_array_copyWithin ),
52882
    JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every | special_TA ),
52883
    JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some | special_TA ),
52884
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach | special_TA ),
52885
    JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map | special_TA ),
52886
    JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter | special_TA ),
52887
    JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA ),
52888
    JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA ),
52889
    JS_CFUNC_DEF("fill", 1, js_typed_array_fill ),
52890
    JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, 0 ),
52891
    JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, 1 ),
52892
    JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse ),
52893
    JS_CFUNC_DEF("slice", 2, js_typed_array_slice ),
52894
    JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray ),
52895
    JS_CFUNC_DEF("sort", 1, js_typed_array_sort ),
52896
    JS_CFUNC_MAGIC_DEF("join", 1, js_typed_array_join, 0 ),
52897
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_typed_array_join, 1 ),
52898
    JS_CFUNC_MAGIC_DEF("indexOf", 1, js_typed_array_indexOf, special_indexOf ),
52899
    JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_typed_array_indexOf, special_lastIndexOf ),
52900
    JS_CFUNC_MAGIC_DEF("includes", 1, js_typed_array_indexOf, special_includes ),
52901
    //JS_ALIAS_BASE_DEF("toString", "toString", 2 /* Array.prototype. */), @@@
52902
};
52903
52904
static JSValue js_typed_array_base_constructor(JSContext *ctx,
52905
                                               JSValueConst this_val,
52906
                                               int argc, JSValueConst *argv)
52907
0
{
52908
0
    return JS_ThrowTypeError(ctx, "cannot be called");
52909
0
}
52910
52911
/* 'obj' must be an allocated typed array object */
52912
static int typed_array_init(JSContext *ctx, JSValueConst obj,
52913
                            JSValue buffer, uint64_t offset, uint64_t len)
52914
0
{
52915
0
    JSTypedArray *ta;
52916
0
    JSObject *p, *pbuffer;
52917
0
    JSArrayBuffer *abuf;
52918
0
    int size_log2;
52919
52920
0
    p = JS_VALUE_GET_OBJ(obj);
52921
0
    size_log2 = typed_array_size_log2(p->class_id);
52922
0
    ta = js_malloc(ctx, sizeof(*ta));
52923
0
    if (!ta) {
52924
0
        JS_FreeValue(ctx, buffer);
52925
0
        return -1;
52926
0
    }
52927
0
    pbuffer = JS_VALUE_GET_OBJ(buffer);
52928
0
    abuf = pbuffer->u.array_buffer;
52929
0
    ta->obj = p;
52930
0
    ta->buffer = pbuffer;
52931
0
    ta->offset = offset;
52932
0
    ta->length = len << size_log2;
52933
0
    list_add_tail(&ta->link, &abuf->array_list);
52934
0
    p->u.typed_array = ta;
52935
0
    p->u.array.count = len;
52936
0
    p->u.array.u.ptr = abuf->data + offset;
52937
0
    return 0;
52938
0
}
52939
52940
52941
static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen,
52942
                                      JSValueConst obj, JSValueConst method)
52943
0
{
52944
0
    JSValue arr, iter, next_method = JS_UNDEFINED, val;
52945
0
    BOOL done;
52946
0
    uint32_t k;
52947
52948
0
    *plen = 0;
52949
0
    arr = JS_NewArray(ctx);
52950
0
    if (JS_IsException(arr))
52951
0
        return arr;
52952
0
    iter = JS_GetIterator2(ctx, obj, method);
52953
0
    if (JS_IsException(iter))
52954
0
        goto fail;
52955
0
    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
52956
0
    if (JS_IsException(next_method))
52957
0
        goto fail;
52958
0
    k = 0;
52959
0
    for(;;) {
52960
0
        val = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
52961
0
        if (JS_IsException(val))
52962
0
            goto fail;
52963
0
        if (done) {
52964
0
            JS_FreeValue(ctx, val);
52965
0
            break;
52966
0
        }
52967
0
        if (JS_CreateDataPropertyUint32(ctx, arr, k, val, JS_PROP_THROW) < 0)
52968
0
            goto fail;
52969
0
        k++;
52970
0
    }
52971
0
    JS_FreeValue(ctx, next_method);
52972
0
    JS_FreeValue(ctx, iter);
52973
0
    *plen = k;
52974
0
    return arr;
52975
0
 fail:
52976
0
    JS_FreeValue(ctx, next_method);
52977
0
    JS_FreeValue(ctx, iter);
52978
0
    JS_FreeValue(ctx, arr);
52979
0
    return JS_EXCEPTION;
52980
0
}
52981
52982
static JSValue js_typed_array_constructor_obj(JSContext *ctx,
52983
                                              JSValueConst new_target,
52984
                                              JSValueConst obj,
52985
                                              int classid)
52986
0
{
52987
0
    JSValue iter, ret, arr = JS_UNDEFINED, val, buffer;
52988
0
    uint32_t i;
52989
0
    int size_log2;
52990
0
    int64_t len;
52991
52992
0
    size_log2 = typed_array_size_log2(classid);
52993
0
    ret = js_create_from_ctor(ctx, new_target, classid);
52994
0
    if (JS_IsException(ret))
52995
0
        return JS_EXCEPTION;
52996
52997
0
    iter = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
52998
0
    if (JS_IsException(iter))
52999
0
        goto fail;
53000
0
    if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {
53001
0
        uint32_t len1;
53002
0
        arr = js_array_from_iterator(ctx, &len1, obj, iter);
53003
0
        JS_FreeValue(ctx, iter);
53004
0
        if (JS_IsException(arr))
53005
0
            goto fail;
53006
0
        len = len1;
53007
0
    } else {
53008
0
        if (js_get_length64(ctx, &len, obj))
53009
0
            goto fail;
53010
0
        arr = JS_DupValue(ctx, obj);
53011
0
    }
53012
53013
0
    buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
53014
0
                                          len << size_log2);
53015
0
    if (JS_IsException(buffer))
53016
0
        goto fail;
53017
0
    if (typed_array_init(ctx, ret, buffer, 0, len))
53018
0
        goto fail;
53019
53020
0
    for(i = 0; i < len; i++) {
53021
0
        val = JS_GetPropertyUint32(ctx, arr, i);
53022
0
        if (JS_IsException(val))
53023
0
            goto fail;
53024
0
        if (JS_SetPropertyUint32(ctx, ret, i, val) < 0)
53025
0
            goto fail;
53026
0
    }
53027
0
    JS_FreeValue(ctx, arr);
53028
0
    return ret;
53029
0
 fail:
53030
0
    JS_FreeValue(ctx, arr);
53031
0
    JS_FreeValue(ctx, ret);
53032
0
    return JS_EXCEPTION;
53033
0
}
53034
53035
static JSValue js_typed_array_constructor_ta(JSContext *ctx,
53036
                                             JSValueConst new_target,
53037
                                             JSValueConst src_obj,
53038
                                             int classid)
53039
0
{
53040
0
    JSObject *p, *src_buffer;
53041
0
    JSTypedArray *ta;
53042
0
    JSValue ctor, obj, buffer;
53043
0
    uint32_t len, i;
53044
0
    int size_log2;
53045
0
    JSArrayBuffer *src_abuf, *abuf;
53046
53047
0
    obj = js_create_from_ctor(ctx, new_target, classid);
53048
0
    if (JS_IsException(obj))
53049
0
        return obj;
53050
0
    p = JS_VALUE_GET_OBJ(src_obj);
53051
0
    if (typed_array_is_detached(ctx, p)) {
53052
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53053
0
        goto fail;
53054
0
    }
53055
0
    ta = p->u.typed_array;
53056
0
    len = p->u.array.count;
53057
0
    src_buffer = ta->buffer;
53058
0
    src_abuf = src_buffer->u.array_buffer;
53059
0
    if (!src_abuf->shared) {
53060
0
        ctor = JS_SpeciesConstructor(ctx, JS_MKPTR(JS_TAG_OBJECT, src_buffer),
53061
0
                                     JS_UNDEFINED);
53062
0
        if (JS_IsException(ctor))
53063
0
            goto fail;
53064
0
    } else {
53065
        /* force ArrayBuffer default constructor */
53066
0
        ctor = JS_UNDEFINED;
53067
0
    }
53068
0
    size_log2 = typed_array_size_log2(classid);
53069
0
    buffer = js_array_buffer_constructor1(ctx, ctor,
53070
0
                                          (uint64_t)len << size_log2);
53071
0
    JS_FreeValue(ctx, ctor);
53072
0
    if (JS_IsException(buffer))
53073
0
        goto fail;
53074
    /* necessary because it could have been detached */
53075
0
    if (typed_array_is_detached(ctx, p)) {
53076
0
        JS_FreeValue(ctx, buffer);
53077
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53078
0
        goto fail;
53079
0
    }
53080
0
    abuf = JS_GetOpaque(buffer, JS_CLASS_ARRAY_BUFFER);
53081
0
    if (typed_array_init(ctx, obj, buffer, 0, len))
53082
0
        goto fail;
53083
0
    if (p->class_id == classid) {
53084
        /* same type: copy the content */
53085
0
        memcpy(abuf->data, src_abuf->data + ta->offset, abuf->byte_length);
53086
0
    } else {
53087
0
        for(i = 0; i < len; i++) {
53088
0
            JSValue val;
53089
0
            val = JS_GetPropertyUint32(ctx, src_obj, i);
53090
0
            if (JS_IsException(val))
53091
0
                goto fail;
53092
0
            if (JS_SetPropertyUint32(ctx, obj, i, val) < 0)
53093
0
                goto fail;
53094
0
        }
53095
0
    }
53096
0
    return obj;
53097
0
 fail:
53098
0
    JS_FreeValue(ctx, obj);
53099
0
    return JS_EXCEPTION;
53100
0
}
53101
53102
static JSValue js_typed_array_constructor(JSContext *ctx,
53103
                                          JSValueConst new_target,
53104
                                          int argc, JSValueConst *argv,
53105
                                          int classid)
53106
0
{
53107
0
    JSValue buffer, obj;
53108
0
    JSArrayBuffer *abuf;
53109
0
    int size_log2;
53110
0
    uint64_t len, offset;
53111
53112
0
    size_log2 = typed_array_size_log2(classid);
53113
0
    if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) {
53114
0
        if (JS_ToIndex(ctx, &len, argv[0]))
53115
0
            return JS_EXCEPTION;
53116
0
        buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
53117
0
                                              len << size_log2);
53118
0
        if (JS_IsException(buffer))
53119
0
            return JS_EXCEPTION;
53120
0
        offset = 0;
53121
0
    } else {
53122
0
        JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
53123
0
        if (p->class_id == JS_CLASS_ARRAY_BUFFER ||
53124
0
            p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER) {
53125
0
            abuf = p->u.array_buffer;
53126
0
            if (JS_ToIndex(ctx, &offset, argv[1]))
53127
0
                return JS_EXCEPTION;
53128
0
            if (abuf->detached)
53129
0
                return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53130
0
            if ((offset & ((1 << size_log2) - 1)) != 0 ||
53131
0
                offset > abuf->byte_length)
53132
0
                return JS_ThrowRangeError(ctx, "invalid offset");
53133
0
            if (JS_IsUndefined(argv[2])) {
53134
0
                if ((abuf->byte_length & ((1 << size_log2) - 1)) != 0)
53135
0
                    goto invalid_length;
53136
0
                len = (abuf->byte_length - offset) >> size_log2;
53137
0
            } else {
53138
0
                if (JS_ToIndex(ctx, &len, argv[2]))
53139
0
                    return JS_EXCEPTION;
53140
0
                if (abuf->detached)
53141
0
                    return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53142
0
                if ((offset + (len << size_log2)) > abuf->byte_length) {
53143
0
                invalid_length:
53144
0
                    return JS_ThrowRangeError(ctx, "invalid length");
53145
0
                }
53146
0
            }
53147
0
            buffer = JS_DupValue(ctx, argv[0]);
53148
0
        } else {
53149
0
            if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
53150
0
                p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
53151
0
                return js_typed_array_constructor_ta(ctx, new_target, argv[0], classid);
53152
0
            } else {
53153
0
                return js_typed_array_constructor_obj(ctx, new_target, argv[0], classid);
53154
0
            }
53155
0
        }
53156
0
    }
53157
53158
0
    obj = js_create_from_ctor(ctx, new_target, classid);
53159
0
    if (JS_IsException(obj)) {
53160
0
        JS_FreeValue(ctx, buffer);
53161
0
        return JS_EXCEPTION;
53162
0
    }
53163
0
    if (typed_array_init(ctx, obj, buffer, offset, len)) {
53164
0
        JS_FreeValue(ctx, obj);
53165
0
        return JS_EXCEPTION;
53166
0
    }
53167
0
    return obj;
53168
0
}
53169
53170
static void js_typed_array_finalizer(JSRuntime *rt, JSValue val)
53171
0
{
53172
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
53173
0
    JSTypedArray *ta = p->u.typed_array;
53174
0
    if (ta) {
53175
        /* during the GC the finalizers are called in an arbitrary
53176
           order so the ArrayBuffer finalizer may have been called */
53177
0
        if (JS_IsLiveObject(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer))) {
53178
0
            list_del(&ta->link);
53179
0
        }
53180
0
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
53181
0
        js_free_rt(rt, ta);
53182
0
    }
53183
0
}
53184
53185
static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
53186
                                JS_MarkFunc *mark_func)
53187
0
{
53188
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
53189
0
    JSTypedArray *ta = p->u.typed_array;
53190
0
    if (ta) {
53191
0
        JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer), mark_func);
53192
0
    }
53193
0
}
53194
53195
static JSValue js_dataview_constructor(JSContext *ctx,
53196
                                       JSValueConst new_target,
53197
                                       int argc, JSValueConst *argv)
53198
0
{
53199
0
    JSArrayBuffer *abuf;
53200
0
    uint64_t offset;
53201
0
    uint32_t len;
53202
0
    JSValueConst buffer;
53203
0
    JSValue obj;
53204
0
    JSTypedArray *ta;
53205
0
    JSObject *p;
53206
53207
0
    buffer = argv[0];
53208
0
    abuf = js_get_array_buffer(ctx, buffer);
53209
0
    if (!abuf)
53210
0
        return JS_EXCEPTION;
53211
0
    offset = 0;
53212
0
    if (argc > 1) {
53213
0
        if (JS_ToIndex(ctx, &offset, argv[1]))
53214
0
            return JS_EXCEPTION;
53215
0
    }
53216
0
    if (abuf->detached)
53217
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53218
0
    if (offset > abuf->byte_length)
53219
0
        return JS_ThrowRangeError(ctx, "invalid byteOffset");
53220
0
    len = abuf->byte_length - offset;
53221
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
53222
0
        uint64_t l;
53223
0
        if (JS_ToIndex(ctx, &l, argv[2]))
53224
0
            return JS_EXCEPTION;
53225
0
        if (l > len)
53226
0
            return JS_ThrowRangeError(ctx, "invalid byteLength");
53227
0
        len = l;
53228
0
    }
53229
53230
0
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_DATAVIEW);
53231
0
    if (JS_IsException(obj))
53232
0
        return JS_EXCEPTION;
53233
0
    if (abuf->detached) {
53234
        /* could have been detached in js_create_from_ctor() */
53235
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53236
0
        goto fail;
53237
0
    }
53238
0
    ta = js_malloc(ctx, sizeof(*ta));
53239
0
    if (!ta) {
53240
0
    fail:
53241
0
        JS_FreeValue(ctx, obj);
53242
0
        return JS_EXCEPTION;
53243
0
    }
53244
0
    p = JS_VALUE_GET_OBJ(obj);
53245
0
    ta->obj = p;
53246
0
    ta->buffer = JS_VALUE_GET_OBJ(JS_DupValue(ctx, buffer));
53247
0
    ta->offset = offset;
53248
0
    ta->length = len;
53249
0
    list_add_tail(&ta->link, &abuf->array_list);
53250
0
    p->u.typed_array = ta;
53251
0
    return obj;
53252
0
}
53253
53254
static JSValue js_dataview_getValue(JSContext *ctx,
53255
                                    JSValueConst this_obj,
53256
                                    int argc, JSValueConst *argv, int class_id)
53257
0
{
53258
0
    JSTypedArray *ta;
53259
0
    JSArrayBuffer *abuf;
53260
0
    int is_swap, size;
53261
0
    uint8_t *ptr;
53262
0
    uint32_t v;
53263
0
    uint64_t pos;
53264
53265
0
    ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
53266
0
    if (!ta)
53267
0
        return JS_EXCEPTION;
53268
0
    size = 1 << typed_array_size_log2(class_id);
53269
0
    if (JS_ToIndex(ctx, &pos, argv[0]))
53270
0
        return JS_EXCEPTION;
53271
0
    is_swap = FALSE;
53272
0
    if (argc > 1)
53273
0
        is_swap = JS_ToBool(ctx, argv[1]);
53274
0
#ifndef WORDS_BIGENDIAN
53275
0
    is_swap ^= 1;
53276
0
#endif
53277
0
    abuf = ta->buffer->u.array_buffer;
53278
0
    if (abuf->detached)
53279
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53280
0
    if ((pos + size) > ta->length)
53281
0
        return JS_ThrowRangeError(ctx, "out of bound");
53282
0
    ptr = abuf->data + ta->offset + pos;
53283
53284
0
    switch(class_id) {
53285
0
    case JS_CLASS_INT8_ARRAY:
53286
0
        return JS_NewInt32(ctx, *(int8_t *)ptr);
53287
0
    case JS_CLASS_UINT8_ARRAY:
53288
0
        return JS_NewInt32(ctx, *(uint8_t *)ptr);
53289
0
    case JS_CLASS_INT16_ARRAY:
53290
0
        v = get_u16(ptr);
53291
0
        if (is_swap)
53292
0
            v = bswap16(v);
53293
0
        return JS_NewInt32(ctx, (int16_t)v);
53294
0
    case JS_CLASS_UINT16_ARRAY:
53295
0
        v = get_u16(ptr);
53296
0
        if (is_swap)
53297
0
            v = bswap16(v);
53298
0
        return JS_NewInt32(ctx, v);
53299
0
    case JS_CLASS_INT32_ARRAY:
53300
0
        v = get_u32(ptr);
53301
0
        if (is_swap)
53302
0
            v = bswap32(v);
53303
0
        return JS_NewInt32(ctx, v);
53304
0
    case JS_CLASS_UINT32_ARRAY:
53305
0
        v = get_u32(ptr);
53306
0
        if (is_swap)
53307
0
            v = bswap32(v);
53308
0
        return JS_NewUint32(ctx, v);
53309
0
#ifdef CONFIG_BIGNUM
53310
0
    case JS_CLASS_BIG_INT64_ARRAY:
53311
0
        {
53312
0
            uint64_t v;
53313
0
            v = get_u64(ptr);
53314
0
            if (is_swap)
53315
0
                v = bswap64(v);
53316
0
            return JS_NewBigInt64(ctx, v);
53317
0
        }
53318
0
        break;
53319
0
    case JS_CLASS_BIG_UINT64_ARRAY:
53320
0
        {
53321
0
            uint64_t v;
53322
0
            v = get_u64(ptr);
53323
0
            if (is_swap)
53324
0
                v = bswap64(v);
53325
0
            return JS_NewBigUint64(ctx, v);
53326
0
        }
53327
0
        break;
53328
0
#endif
53329
0
    case JS_CLASS_FLOAT32_ARRAY:
53330
0
        {
53331
0
            union {
53332
0
                float f;
53333
0
                uint32_t i;
53334
0
            } u;
53335
0
            v = get_u32(ptr);
53336
0
            if (is_swap)
53337
0
                v = bswap32(v);
53338
0
            u.i = v;
53339
0
            return __JS_NewFloat64(ctx, u.f);
53340
0
        }
53341
0
    case JS_CLASS_FLOAT64_ARRAY:
53342
0
        {
53343
0
            union {
53344
0
                double f;
53345
0
                uint64_t i;
53346
0
            } u;
53347
0
            u.i = get_u64(ptr);
53348
0
            if (is_swap)
53349
0
                u.i = bswap64(u.i);
53350
0
            return __JS_NewFloat64(ctx, u.f);
53351
0
        }
53352
0
    default:
53353
0
        abort();
53354
0
    }
53355
0
}
53356
53357
static JSValue js_dataview_setValue(JSContext *ctx,
53358
                                    JSValueConst this_obj,
53359
                                    int argc, JSValueConst *argv, int class_id)
53360
0
{
53361
0
    JSTypedArray *ta;
53362
0
    JSArrayBuffer *abuf;
53363
0
    int is_swap, size;
53364
0
    uint8_t *ptr;
53365
0
    uint64_t v64;
53366
0
    uint32_t v;
53367
0
    uint64_t pos;
53368
0
    JSValueConst val;
53369
53370
0
    ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
53371
0
    if (!ta)
53372
0
        return JS_EXCEPTION;
53373
0
    size = 1 << typed_array_size_log2(class_id);
53374
0
    if (JS_ToIndex(ctx, &pos, argv[0]))
53375
0
        return JS_EXCEPTION;
53376
0
    val = argv[1];
53377
0
    v = 0; /* avoid warning */
53378
0
    v64 = 0; /* avoid warning */
53379
0
    if (class_id <= JS_CLASS_UINT32_ARRAY) {
53380
0
        if (JS_ToUint32(ctx, &v, val))
53381
0
            return JS_EXCEPTION;
53382
0
    } else
53383
0
#ifdef CONFIG_BIGNUM
53384
0
    if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
53385
0
        if (JS_ToBigInt64(ctx, (int64_t *)&v64, val))
53386
0
            return JS_EXCEPTION;
53387
0
    } else
53388
0
#endif
53389
0
    {
53390
0
        double d;
53391
0
        if (JS_ToFloat64(ctx, &d, val))
53392
0
            return JS_EXCEPTION;
53393
0
        if (class_id == JS_CLASS_FLOAT32_ARRAY) {
53394
0
            union {
53395
0
                float f;
53396
0
                uint32_t i;
53397
0
            } u;
53398
0
            u.f = d;
53399
0
            v = u.i;
53400
0
        } else {
53401
0
            JSFloat64Union u;
53402
0
            u.d = d;
53403
0
            v64 = u.u64;
53404
0
        }
53405
0
    }
53406
0
    is_swap = FALSE;
53407
0
    if (argc > 2)
53408
0
        is_swap = JS_ToBool(ctx, argv[2]);
53409
0
#ifndef WORDS_BIGENDIAN
53410
0
    is_swap ^= 1;
53411
0
#endif
53412
0
    abuf = ta->buffer->u.array_buffer;
53413
0
    if (abuf->detached)
53414
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53415
0
    if ((pos + size) > ta->length)
53416
0
        return JS_ThrowRangeError(ctx, "out of bound");
53417
0
    ptr = abuf->data + ta->offset + pos;
53418
53419
0
    switch(class_id) {
53420
0
    case JS_CLASS_INT8_ARRAY:
53421
0
    case JS_CLASS_UINT8_ARRAY:
53422
0
        *ptr = v;
53423
0
        break;
53424
0
    case JS_CLASS_INT16_ARRAY:
53425
0
    case JS_CLASS_UINT16_ARRAY:
53426
0
        if (is_swap)
53427
0
            v = bswap16(v);
53428
0
        put_u16(ptr, v);
53429
0
        break;
53430
0
    case JS_CLASS_INT32_ARRAY:
53431
0
    case JS_CLASS_UINT32_ARRAY:
53432
0
    case JS_CLASS_FLOAT32_ARRAY:
53433
0
        if (is_swap)
53434
0
            v = bswap32(v);
53435
0
        put_u32(ptr, v);
53436
0
        break;
53437
0
#ifdef CONFIG_BIGNUM
53438
0
    case JS_CLASS_BIG_INT64_ARRAY:
53439
0
    case JS_CLASS_BIG_UINT64_ARRAY:
53440
0
#endif
53441
0
    case JS_CLASS_FLOAT64_ARRAY:
53442
0
        if (is_swap)
53443
0
            v64 = bswap64(v64);
53444
0
        put_u64(ptr, v64);
53445
0
        break;
53446
0
    default:
53447
0
        abort();
53448
0
    }
53449
0
    return JS_UNDEFINED;
53450
0
}
53451
53452
static const JSCFunctionListEntry js_dataview_proto_funcs[] = {
53453
    JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 1 ),
53454
    JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 1 ),
53455
    JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 1 ),
53456
    JS_CFUNC_MAGIC_DEF("getInt8", 1, js_dataview_getValue, JS_CLASS_INT8_ARRAY ),
53457
    JS_CFUNC_MAGIC_DEF("getUint8", 1, js_dataview_getValue, JS_CLASS_UINT8_ARRAY ),
53458
    JS_CFUNC_MAGIC_DEF("getInt16", 1, js_dataview_getValue, JS_CLASS_INT16_ARRAY ),
53459
    JS_CFUNC_MAGIC_DEF("getUint16", 1, js_dataview_getValue, JS_CLASS_UINT16_ARRAY ),
53460
    JS_CFUNC_MAGIC_DEF("getInt32", 1, js_dataview_getValue, JS_CLASS_INT32_ARRAY ),
53461
    JS_CFUNC_MAGIC_DEF("getUint32", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY ),
53462
#ifdef CONFIG_BIGNUM
53463
    JS_CFUNC_MAGIC_DEF("getBigInt64", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY ),
53464
    JS_CFUNC_MAGIC_DEF("getBigUint64", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY ),
53465
#endif
53466
    JS_CFUNC_MAGIC_DEF("getFloat32", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY ),
53467
    JS_CFUNC_MAGIC_DEF("getFloat64", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY ),
53468
    JS_CFUNC_MAGIC_DEF("setInt8", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY ),
53469
    JS_CFUNC_MAGIC_DEF("setUint8", 2, js_dataview_setValue, JS_CLASS_UINT8_ARRAY ),
53470
    JS_CFUNC_MAGIC_DEF("setInt16", 2, js_dataview_setValue, JS_CLASS_INT16_ARRAY ),
53471
    JS_CFUNC_MAGIC_DEF("setUint16", 2, js_dataview_setValue, JS_CLASS_UINT16_ARRAY ),
53472
    JS_CFUNC_MAGIC_DEF("setInt32", 2, js_dataview_setValue, JS_CLASS_INT32_ARRAY ),
53473
    JS_CFUNC_MAGIC_DEF("setUint32", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY ),
53474
#ifdef CONFIG_BIGNUM
53475
    JS_CFUNC_MAGIC_DEF("setBigInt64", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY ),
53476
    JS_CFUNC_MAGIC_DEF("setBigUint64", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY ),
53477
#endif
53478
    JS_CFUNC_MAGIC_DEF("setFloat32", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY ),
53479
    JS_CFUNC_MAGIC_DEF("setFloat64", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY ),
53480
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DataView", JS_PROP_CONFIGURABLE ),
53481
};
53482
53483
/* Atomics */
53484
#ifdef CONFIG_ATOMICS
53485
53486
typedef enum AtomicsOpEnum {
53487
    ATOMICS_OP_ADD,
53488
    ATOMICS_OP_AND,
53489
    ATOMICS_OP_OR,
53490
    ATOMICS_OP_SUB,
53491
    ATOMICS_OP_XOR,
53492
    ATOMICS_OP_EXCHANGE,
53493
    ATOMICS_OP_COMPARE_EXCHANGE,
53494
    ATOMICS_OP_LOAD,
53495
} AtomicsOpEnum;
53496
53497
static void *js_atomics_get_ptr(JSContext *ctx,
53498
                                JSArrayBuffer **pabuf,
53499
                                int *psize_log2, JSClassID *pclass_id,
53500
                                JSValueConst obj, JSValueConst idx_val,
53501
                                int is_waitable)
53502
0
{
53503
0
    JSObject *p;
53504
0
    JSTypedArray *ta;
53505
0
    JSArrayBuffer *abuf;
53506
0
    void *ptr;
53507
0
    uint64_t idx;
53508
0
    BOOL err;
53509
0
    int size_log2;
53510
53511
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
53512
0
        goto fail;
53513
0
    p = JS_VALUE_GET_OBJ(obj);
53514
0
#ifdef CONFIG_BIGNUM
53515
0
    if (is_waitable)
53516
0
        err = (p->class_id != JS_CLASS_INT32_ARRAY &&
53517
0
               p->class_id != JS_CLASS_BIG_INT64_ARRAY);
53518
0
    else
53519
0
        err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
53520
0
                p->class_id <= JS_CLASS_BIG_UINT64_ARRAY);
53521
#else
53522
    if (is_waitable)
53523
        err = (p->class_id != JS_CLASS_INT32_ARRAY);
53524
    else
53525
        err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
53526
                p->class_id <= JS_CLASS_UINT32_ARRAY);
53527
#endif
53528
0
    if (err) {
53529
0
    fail:
53530
0
        JS_ThrowTypeError(ctx, "integer TypedArray expected");
53531
0
        return NULL;
53532
0
    }
53533
0
    ta = p->u.typed_array;
53534
0
    abuf = ta->buffer->u.array_buffer;
53535
0
    if (!abuf->shared) {
53536
0
        if (is_waitable == 2) {
53537
0
            JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray");
53538
0
            return NULL;
53539
0
        }
53540
0
        if (abuf->detached) {
53541
0
            JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53542
0
            return NULL;
53543
0
        }
53544
0
    }
53545
0
    if (JS_ToIndex(ctx, &idx, idx_val)) {
53546
0
        return NULL;
53547
0
    }
53548
    /* if the array buffer is detached, p->u.array.count = 0 */
53549
0
    if (idx >= p->u.array.count) {
53550
0
        JS_ThrowRangeError(ctx, "out-of-bound access");
53551
0
        return NULL;
53552
0
    }
53553
0
    size_log2 = typed_array_size_log2(p->class_id);
53554
0
    ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);
53555
0
    if (pabuf)
53556
0
        *pabuf = abuf;
53557
0
    if (psize_log2)
53558
0
        *psize_log2 = size_log2;
53559
0
    if (pclass_id)
53560
0
        *pclass_id = p->class_id;
53561
0
    return ptr;
53562
0
}
53563
53564
static JSValue js_atomics_op(JSContext *ctx,
53565
                             JSValueConst this_obj,
53566
                             int argc, JSValueConst *argv, int op)
53567
0
{
53568
0
    int size_log2;
53569
0
#ifdef CONFIG_BIGNUM
53570
0
    uint64_t v, a, rep_val;
53571
#else
53572
    uint32_t v, a, rep_val;
53573
#endif
53574
0
    void *ptr;
53575
0
    JSValue ret;
53576
0
    JSClassID class_id;
53577
0
    JSArrayBuffer *abuf;
53578
53579
0
    ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, &class_id,
53580
0
                             argv[0], argv[1], 0);
53581
0
    if (!ptr)
53582
0
        return JS_EXCEPTION;
53583
0
    rep_val = 0;
53584
0
    if (op == ATOMICS_OP_LOAD) {
53585
0
        v = 0;
53586
0
    } else {
53587
0
#ifdef CONFIG_BIGNUM
53588
0
        if (size_log2 == 3) {
53589
0
            int64_t v64;
53590
0
            if (JS_ToBigInt64(ctx, &v64, argv[2]))
53591
0
                return JS_EXCEPTION;
53592
0
            v = v64;
53593
0
            if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
53594
0
                if (JS_ToBigInt64(ctx, &v64, argv[3]))
53595
0
                    return JS_EXCEPTION;
53596
0
                rep_val = v64;
53597
0
            }
53598
0
        } else
53599
0
#endif
53600
0
        {
53601
0
                uint32_t v32;
53602
0
                if (JS_ToUint32(ctx, &v32, argv[2]))
53603
0
                    return JS_EXCEPTION;
53604
0
                v = v32;
53605
0
                if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
53606
0
                    if (JS_ToUint32(ctx, &v32, argv[3]))
53607
0
                        return JS_EXCEPTION;
53608
0
                    rep_val = v32;
53609
0
                }
53610
0
        }
53611
0
        if (abuf->detached)
53612
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53613
0
   }
53614
53615
0
   switch(op | (size_log2 << 3)) {
53616
            
53617
0
#ifdef CONFIG_BIGNUM
53618
0
#define OP(op_name, func_name)                          \
53619
0
    case ATOMICS_OP_ ## op_name | (0 << 3):             \
53620
0
       a = func_name((_Atomic(uint8_t) *)ptr, v);       \
53621
0
       break;                                           \
53622
0
    case ATOMICS_OP_ ## op_name | (1 << 3):             \
53623
0
        a = func_name((_Atomic(uint16_t) *)ptr, v);     \
53624
0
        break;                                          \
53625
0
    case ATOMICS_OP_ ## op_name | (2 << 3):             \
53626
0
        a = func_name((_Atomic(uint32_t) *)ptr, v);     \
53627
0
        break;                                          \
53628
0
    case ATOMICS_OP_ ## op_name | (3 << 3):             \
53629
0
        a = func_name((_Atomic(uint64_t) *)ptr, v);     \
53630
0
        break;
53631
#else
53632
#define OP(op_name, func_name)                          \
53633
    case ATOMICS_OP_ ## op_name | (0 << 3):             \
53634
       a = func_name((_Atomic(uint8_t) *)ptr, v);       \
53635
       break;                                           \
53636
    case ATOMICS_OP_ ## op_name | (1 << 3):             \
53637
        a = func_name((_Atomic(uint16_t) *)ptr, v);     \
53638
        break;                                          \
53639
    case ATOMICS_OP_ ## op_name | (2 << 3):             \
53640
        a = func_name((_Atomic(uint32_t) *)ptr, v);     \
53641
        break;
53642
#endif
53643
0
        OP(ADD, atomic_fetch_add)
53644
0
        OP(AND, atomic_fetch_and)
53645
0
        OP(OR, atomic_fetch_or)
53646
0
        OP(SUB, atomic_fetch_sub)
53647
0
        OP(XOR, atomic_fetch_xor)
53648
0
        OP(EXCHANGE, atomic_exchange)
53649
0
#undef OP
53650
53651
0
    case ATOMICS_OP_LOAD | (0 << 3):
53652
0
        a = atomic_load((_Atomic(uint8_t) *)ptr);
53653
0
        break;
53654
0
    case ATOMICS_OP_LOAD | (1 << 3):
53655
0
        a = atomic_load((_Atomic(uint16_t) *)ptr);
53656
0
        break;
53657
0
    case ATOMICS_OP_LOAD | (2 << 3):
53658
0
        a = atomic_load((_Atomic(uint32_t) *)ptr);
53659
0
        break;
53660
0
#ifdef CONFIG_BIGNUM
53661
0
    case ATOMICS_OP_LOAD | (3 << 3):
53662
0
        a = atomic_load((_Atomic(uint64_t) *)ptr);
53663
0
        break;
53664
0
#endif
53665
        
53666
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3):
53667
0
        {
53668
0
            uint8_t v1 = v;
53669
0
            atomic_compare_exchange_strong((_Atomic(uint8_t) *)ptr, &v1, rep_val);
53670
0
            a = v1;
53671
0
        }
53672
0
        break;
53673
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (1 << 3):
53674
0
        {
53675
0
            uint16_t v1 = v;
53676
0
            atomic_compare_exchange_strong((_Atomic(uint16_t) *)ptr, &v1, rep_val);
53677
0
            a = v1;
53678
0
        }
53679
0
        break;
53680
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (2 << 3):
53681
0
        {
53682
0
            uint32_t v1 = v;
53683
0
            atomic_compare_exchange_strong((_Atomic(uint32_t) *)ptr, &v1, rep_val);
53684
0
            a = v1;
53685
0
        }
53686
0
        break;
53687
0
#ifdef CONFIG_BIGNUM
53688
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3):
53689
0
        {
53690
0
            uint64_t v1 = v;
53691
0
            atomic_compare_exchange_strong((_Atomic(uint64_t) *)ptr, &v1, rep_val);
53692
0
            a = v1;
53693
0
        }
53694
0
        break;
53695
0
#endif
53696
0
    default:
53697
0
        abort();
53698
0
    }
53699
53700
0
    switch(class_id) {
53701
0
    case JS_CLASS_INT8_ARRAY:
53702
0
        a = (int8_t)a;
53703
0
        goto done;
53704
0
    case JS_CLASS_UINT8_ARRAY:
53705
0
        a = (uint8_t)a;
53706
0
        goto done;
53707
0
    case JS_CLASS_INT16_ARRAY:
53708
0
        a = (int16_t)a;
53709
0
        goto done;
53710
0
    case JS_CLASS_UINT16_ARRAY:
53711
0
        a = (uint16_t)a;
53712
0
        goto done;
53713
0
    case JS_CLASS_INT32_ARRAY:
53714
0
    done:
53715
0
        ret = JS_NewInt32(ctx, a);
53716
0
        break;
53717
0
    case JS_CLASS_UINT32_ARRAY:
53718
0
        ret = JS_NewUint32(ctx, a);
53719
0
        break;
53720
0
#ifdef CONFIG_BIGNUM
53721
0
    case JS_CLASS_BIG_INT64_ARRAY:
53722
0
        ret = JS_NewBigInt64(ctx, a);
53723
0
        break;
53724
0
    case JS_CLASS_BIG_UINT64_ARRAY:
53725
0
        ret = JS_NewBigUint64(ctx, a);
53726
0
        break;
53727
0
#endif
53728
0
    default:
53729
0
        abort();
53730
0
    }
53731
0
    return ret;
53732
0
}
53733
53734
static JSValue js_atomics_store(JSContext *ctx,
53735
                                JSValueConst this_obj,
53736
                                int argc, JSValueConst *argv)
53737
0
{
53738
0
    int size_log2;
53739
0
    void *ptr;
53740
0
    JSValue ret;
53741
0
    JSArrayBuffer *abuf;
53742
53743
0
    ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, NULL,
53744
0
                             argv[0], argv[1], 0);
53745
0
    if (!ptr)
53746
0
        return JS_EXCEPTION;
53747
0
#ifdef CONFIG_BIGNUM
53748
0
    if (size_log2 == 3) {
53749
0
        int64_t v64;
53750
0
        ret = JS_ToBigIntValueFree(ctx, JS_DupValue(ctx, argv[2]));
53751
0
        if (JS_IsException(ret))
53752
0
            return ret;
53753
0
        if (JS_ToBigInt64(ctx, &v64, ret)) {
53754
0
            JS_FreeValue(ctx, ret);
53755
0
            return JS_EXCEPTION;
53756
0
        }
53757
0
        if (abuf->detached)
53758
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53759
0
        atomic_store((_Atomic(uint64_t) *)ptr, v64);
53760
0
    } else
53761
0
#endif
53762
0
    {
53763
0
        uint32_t v;
53764
        /* XXX: spec, would be simpler to return the written value */
53765
0
        ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2]));
53766
0
        if (JS_IsException(ret))
53767
0
            return ret;
53768
0
        if (JS_ToUint32(ctx, &v, ret)) {
53769
0
            JS_FreeValue(ctx, ret);
53770
0
            return JS_EXCEPTION;
53771
0
        }
53772
0
        if (abuf->detached)
53773
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53774
0
        switch(size_log2) {
53775
0
        case 0:
53776
0
            atomic_store((_Atomic(uint8_t) *)ptr, v);
53777
0
            break;
53778
0
        case 1:
53779
0
            atomic_store((_Atomic(uint16_t) *)ptr, v);
53780
0
            break;
53781
0
        case 2:
53782
0
            atomic_store((_Atomic(uint32_t) *)ptr, v);
53783
0
            break;
53784
0
        default:
53785
0
            abort();
53786
0
        }
53787
0
    }
53788
0
    return ret;
53789
0
}
53790
53791
static JSValue js_atomics_isLockFree(JSContext *ctx,
53792
                                     JSValueConst this_obj,
53793
                                     int argc, JSValueConst *argv)
53794
0
{
53795
0
    int v, ret;
53796
0
    if (JS_ToInt32Sat(ctx, &v, argv[0]))
53797
0
        return JS_EXCEPTION;
53798
0
    ret = (v == 1 || v == 2 || v == 4
53799
0
#ifdef CONFIG_BIGNUM
53800
0
           || v == 8
53801
0
#endif
53802
0
           );
53803
0
    return JS_NewBool(ctx, ret);
53804
0
}
53805
53806
typedef struct JSAtomicsWaiter {
53807
    struct list_head link;
53808
    BOOL linked;
53809
    pthread_cond_t cond;
53810
    int32_t *ptr;
53811
} JSAtomicsWaiter;
53812
53813
static pthread_mutex_t js_atomics_mutex = PTHREAD_MUTEX_INITIALIZER;
53814
static struct list_head js_atomics_waiter_list =
53815
    LIST_HEAD_INIT(js_atomics_waiter_list);
53816
53817
static JSValue js_atomics_wait(JSContext *ctx,
53818
                               JSValueConst this_obj,
53819
                               int argc, JSValueConst *argv)
53820
0
{
53821
0
    int64_t v;
53822
0
    int32_t v32;
53823
0
    void *ptr;
53824
0
    int64_t timeout;
53825
0
    struct timespec ts;
53826
0
    JSAtomicsWaiter waiter_s, *waiter;
53827
0
    int ret, size_log2, res;
53828
0
    double d;
53829
53830
0
    ptr = js_atomics_get_ptr(ctx, NULL, &size_log2, NULL,
53831
0
                             argv[0], argv[1], 2);
53832
0
    if (!ptr)
53833
0
        return JS_EXCEPTION;
53834
0
#ifdef CONFIG_BIGNUM
53835
0
    if (size_log2 == 3) {
53836
0
        if (JS_ToBigInt64(ctx, &v, argv[2]))
53837
0
            return JS_EXCEPTION;
53838
0
    } else
53839
0
#endif
53840
0
    {        
53841
0
        if (JS_ToInt32(ctx, &v32, argv[2]))
53842
0
            return JS_EXCEPTION;
53843
0
        v = v32;
53844
0
    }
53845
0
    if (JS_ToFloat64(ctx, &d, argv[3]))
53846
0
        return JS_EXCEPTION;
53847
0
    if (isnan(d) || d > INT64_MAX)
53848
0
        timeout = INT64_MAX;
53849
0
    else if (d < 0)
53850
0
        timeout = 0;
53851
0
    else
53852
0
        timeout = (int64_t)d;
53853
0
    if (!ctx->rt->can_block)
53854
0
        return JS_ThrowTypeError(ctx, "cannot block in this thread");
53855
53856
    /* XXX: inefficient if large number of waiters, should hash on
53857
       'ptr' value */
53858
    /* XXX: use Linux futexes when available ? */
53859
0
    pthread_mutex_lock(&js_atomics_mutex);
53860
0
    if (size_log2 == 3) {
53861
0
        res = *(int64_t *)ptr != v;
53862
0
    } else {
53863
0
        res = *(int32_t *)ptr != v;
53864
0
    }
53865
0
    if (res) {
53866
0
        pthread_mutex_unlock(&js_atomics_mutex);
53867
0
        return JS_AtomToString(ctx, JS_ATOM_not_equal);
53868
0
    }
53869
53870
0
    waiter = &waiter_s;
53871
0
    waiter->ptr = ptr;
53872
0
    pthread_cond_init(&waiter->cond, NULL);
53873
0
    waiter->linked = TRUE;
53874
0
    list_add_tail(&waiter->link, &js_atomics_waiter_list);
53875
53876
0
    if (timeout == INT64_MAX) {
53877
0
        pthread_cond_wait(&waiter->cond, &js_atomics_mutex);
53878
0
        ret = 0;
53879
0
    } else {
53880
        /* XXX: use clock monotonic */
53881
0
        clock_gettime(CLOCK_REALTIME, &ts);
53882
0
        ts.tv_sec += timeout / 1000;
53883
0
        ts.tv_nsec += (timeout % 1000) * 1000000;
53884
0
        if (ts.tv_nsec >= 1000000000) {
53885
0
            ts.tv_nsec -= 1000000000;
53886
0
            ts.tv_sec++;
53887
0
        }
53888
0
        ret = pthread_cond_timedwait(&waiter->cond, &js_atomics_mutex,
53889
0
                                     &ts);
53890
0
    }
53891
0
    if (waiter->linked)
53892
0
        list_del(&waiter->link);
53893
0
    pthread_mutex_unlock(&js_atomics_mutex);
53894
0
    pthread_cond_destroy(&waiter->cond);
53895
0
    if (ret == ETIMEDOUT) {
53896
0
        return JS_AtomToString(ctx, JS_ATOM_timed_out);
53897
0
    } else {
53898
0
        return JS_AtomToString(ctx, JS_ATOM_ok);
53899
0
    }
53900
0
}
53901
53902
static JSValue js_atomics_notify(JSContext *ctx,
53903
                                 JSValueConst this_obj,
53904
                                 int argc, JSValueConst *argv)
53905
0
{
53906
0
    struct list_head *el, *el1, waiter_list;
53907
0
    int32_t count, n;
53908
0
    void *ptr;
53909
0
    JSAtomicsWaiter *waiter;
53910
0
    JSArrayBuffer *abuf;
53911
53912
0
    ptr = js_atomics_get_ptr(ctx, &abuf, NULL, NULL, argv[0], argv[1], 1);
53913
0
    if (!ptr)
53914
0
        return JS_EXCEPTION;
53915
53916
0
    if (JS_IsUndefined(argv[2])) {
53917
0
        count = INT32_MAX;
53918
0
    } else {
53919
0
        if (JS_ToInt32Clamp(ctx, &count, argv[2], 0, INT32_MAX, 0))
53920
0
            return JS_EXCEPTION;
53921
0
    }
53922
0
    if (abuf->detached)
53923
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53924
53925
0
    n = 0;
53926
0
    if (abuf->shared && count > 0) {
53927
0
        pthread_mutex_lock(&js_atomics_mutex);
53928
0
        init_list_head(&waiter_list);
53929
0
        list_for_each_safe(el, el1, &js_atomics_waiter_list) {
53930
0
            waiter = list_entry(el, JSAtomicsWaiter, link);
53931
0
            if (waiter->ptr == ptr) {
53932
0
                list_del(&waiter->link);
53933
0
                waiter->linked = FALSE;
53934
0
                list_add_tail(&waiter->link, &waiter_list);
53935
0
                n++;
53936
0
                if (n >= count)
53937
0
                    break;
53938
0
            }
53939
0
        }
53940
0
        list_for_each(el, &waiter_list) {
53941
0
            waiter = list_entry(el, JSAtomicsWaiter, link);
53942
0
            pthread_cond_signal(&waiter->cond);
53943
0
        }
53944
0
        pthread_mutex_unlock(&js_atomics_mutex);
53945
0
    }
53946
0
    return JS_NewInt32(ctx, n);
53947
0
}
53948
53949
static const JSCFunctionListEntry js_atomics_funcs[] = {
53950
    JS_CFUNC_MAGIC_DEF("add", 3, js_atomics_op, ATOMICS_OP_ADD ),
53951
    JS_CFUNC_MAGIC_DEF("and", 3, js_atomics_op, ATOMICS_OP_AND ),
53952
    JS_CFUNC_MAGIC_DEF("or", 3, js_atomics_op, ATOMICS_OP_OR ),
53953
    JS_CFUNC_MAGIC_DEF("sub", 3, js_atomics_op, ATOMICS_OP_SUB ),
53954
    JS_CFUNC_MAGIC_DEF("xor", 3, js_atomics_op, ATOMICS_OP_XOR ),
53955
    JS_CFUNC_MAGIC_DEF("exchange", 3, js_atomics_op, ATOMICS_OP_EXCHANGE ),
53956
    JS_CFUNC_MAGIC_DEF("compareExchange", 4, js_atomics_op, ATOMICS_OP_COMPARE_EXCHANGE ),
53957
    JS_CFUNC_MAGIC_DEF("load", 2, js_atomics_op, ATOMICS_OP_LOAD ),
53958
    JS_CFUNC_DEF("store", 3, js_atomics_store ),
53959
    JS_CFUNC_DEF("isLockFree", 1, js_atomics_isLockFree ),
53960
    JS_CFUNC_DEF("wait", 4, js_atomics_wait ),
53961
    JS_CFUNC_DEF("notify", 3, js_atomics_notify ),
53962
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Atomics", JS_PROP_CONFIGURABLE ),
53963
};
53964
53965
static const JSCFunctionListEntry js_atomics_obj[] = {
53966
    JS_OBJECT_DEF("Atomics", js_atomics_funcs, countof(js_atomics_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
53967
};
53968
53969
void JS_AddIntrinsicAtomics(JSContext *ctx)
53970
2
{
53971
    /* add Atomics as autoinit object */
53972
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_atomics_obj, countof(js_atomics_obj));
53973
2
}
53974
53975
#endif /* CONFIG_ATOMICS */
53976
53977
void JS_AddIntrinsicTypedArrays(JSContext *ctx)
53978
2
{
53979
2
    JSValue typed_array_base_proto, typed_array_base_func;
53980
2
    JSValueConst array_buffer_func, shared_array_buffer_func;
53981
2
    int i;
53982
53983
2
    ctx->class_proto[JS_CLASS_ARRAY_BUFFER] = JS_NewObject(ctx);
53984
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_BUFFER],
53985
2
                               js_array_buffer_proto_funcs,
53986
2
                               countof(js_array_buffer_proto_funcs));
53987
53988
2
    array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "ArrayBuffer",
53989
2
                                                 js_array_buffer_constructor, 1,
53990
2
                                                 ctx->class_proto[JS_CLASS_ARRAY_BUFFER]);
53991
2
    JS_SetPropertyFunctionList(ctx, array_buffer_func,
53992
2
                               js_array_buffer_funcs,
53993
2
                               countof(js_array_buffer_funcs));
53994
53995
2
    ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER] = JS_NewObject(ctx);
53996
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER],
53997
2
                               js_shared_array_buffer_proto_funcs,
53998
2
                               countof(js_shared_array_buffer_proto_funcs));
53999
54000
2
    shared_array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "SharedArrayBuffer",
54001
2
                                                 js_shared_array_buffer_constructor, 1,
54002
2
                                                 ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER]);
54003
2
    JS_SetPropertyFunctionList(ctx, shared_array_buffer_func,
54004
2
                               js_shared_array_buffer_funcs,
54005
2
                               countof(js_shared_array_buffer_funcs));
54006
54007
2
    typed_array_base_proto = JS_NewObject(ctx);
54008
2
    JS_SetPropertyFunctionList(ctx, typed_array_base_proto,
54009
2
                               js_typed_array_base_proto_funcs,
54010
2
                               countof(js_typed_array_base_proto_funcs));
54011
54012
    /* TypedArray.prototype.toString must be the same object as Array.prototype.toString */
54013
2
    JSValue obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_toString);
54014
    /* XXX: should use alias method in JSCFunctionListEntry */ //@@@
54015
2
    JS_DefinePropertyValue(ctx, typed_array_base_proto, JS_ATOM_toString, obj,
54016
2
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
54017
54018
2
    typed_array_base_func = JS_NewCFunction(ctx, js_typed_array_base_constructor,
54019
2
                                            "TypedArray", 0);
54020
2
    JS_SetPropertyFunctionList(ctx, typed_array_base_func,
54021
2
                               js_typed_array_base_funcs,
54022
2
                               countof(js_typed_array_base_funcs));
54023
2
    JS_SetConstructor(ctx, typed_array_base_func, typed_array_base_proto);
54024
54025
24
    for(i = JS_CLASS_UINT8C_ARRAY; i < JS_CLASS_UINT8C_ARRAY + JS_TYPED_ARRAY_COUNT; i++) {
54026
22
        JSValue func_obj;
54027
22
        char buf[ATOM_GET_STR_BUF_SIZE];
54028
22
        const char *name;
54029
54030
22
        ctx->class_proto[i] = JS_NewObjectProto(ctx, typed_array_base_proto);
54031
22
        JS_DefinePropertyValueStr(ctx, ctx->class_proto[i],
54032
22
                                  "BYTES_PER_ELEMENT",
54033
22
                                  JS_NewInt32(ctx, 1 << typed_array_size_log2(i)),
54034
22
                                  0);
54035
22
        name = JS_AtomGetStr(ctx, buf, sizeof(buf),
54036
22
                             JS_ATOM_Uint8ClampedArray + i - JS_CLASS_UINT8C_ARRAY);
54037
22
        func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_typed_array_constructor,
54038
22
                                    name, 3, JS_CFUNC_constructor_magic, i,
54039
22
                                    typed_array_base_func);
54040
22
        JS_NewGlobalCConstructor2(ctx, func_obj, name, ctx->class_proto[i]);
54041
22
        JS_DefinePropertyValueStr(ctx, func_obj,
54042
22
                                  "BYTES_PER_ELEMENT",
54043
22
                                  JS_NewInt32(ctx, 1 << typed_array_size_log2(i)),
54044
22
                                  0);
54045
22
    }
54046
2
    JS_FreeValue(ctx, typed_array_base_proto);
54047
2
    JS_FreeValue(ctx, typed_array_base_func);
54048
54049
    /* DataView */
54050
2
    ctx->class_proto[JS_CLASS_DATAVIEW] = JS_NewObject(ctx);
54051
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATAVIEW],
54052
2
                               js_dataview_proto_funcs,
54053
2
                               countof(js_dataview_proto_funcs));
54054
2
    JS_NewGlobalCConstructorOnly(ctx, "DataView",
54055
2
                                 js_dataview_constructor, 1,
54056
2
                                 ctx->class_proto[JS_CLASS_DATAVIEW]);
54057
    /* Atomics */
54058
2
#ifdef CONFIG_ATOMICS
54059
2
    JS_AddIntrinsicAtomics(ctx);
54060
2
#endif
54061
2
}