Coverage Report

Created: 2024-05-13 06:32

/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
#include "libunicode.h"
48
#include "libbf.h"
49
50
3.54M
#define OPTIMIZE         1
51
#define SHORT_OPCODES    1
52
#if defined(EMSCRIPTEN)
53
#define DIRECT_DISPATCH  0
54
#else
55
#define DIRECT_DISPATCH  1
56
#endif
57
58
#if defined(__APPLE__)
59
#define MALLOC_OVERHEAD  0
60
#else
61
150k
#define MALLOC_OVERHEAD  8
62
#endif
63
64
#if !defined(_WIN32)
65
/* define it if printf uses the RNDN rounding mode instead of RNDNA */
66
#define CONFIG_PRINTF_RNDN
67
#endif
68
69
/* define to include Atomics.* operations which depend on the OS
70
   threads */
71
#if !defined(EMSCRIPTEN)
72
#define CONFIG_ATOMICS
73
#endif
74
75
#if !defined(EMSCRIPTEN)
76
/* enable stack limitation */
77
#define CONFIG_STACK_CHECK
78
#endif
79
80
81
/* dump object free */
82
//#define DUMP_FREE
83
//#define DUMP_CLOSURE
84
/* dump the bytecode of the compiled functions: combination of bits
85
   1: dump pass 3 final byte code
86
   2: dump pass 2 code
87
   4: dump pass 1 code
88
   8: dump stdlib functions
89
  16: dump bytecode in hex
90
  32: dump line number table
91
  64: dump compute_stack_size
92
 */
93
//#define DUMP_BYTECODE  (1)
94
/* dump the occurence of the automatic GC */
95
//#define DUMP_GC
96
/* dump objects freed by the garbage collector */
97
//#define DUMP_GC_FREE
98
/* dump objects leaking when freeing the runtime */
99
//#define DUMP_LEAKS  1
100
/* dump memory usage before running the garbage collector */
101
//#define DUMP_MEM
102
//#define DUMP_OBJECTS    /* dump objects in JS_FreeContext */
103
//#define DUMP_ATOMS      /* dump atoms in JS_FreeContext */
104
//#define DUMP_SHAPES     /* dump shapes in JS_FreeContext */
105
//#define DUMP_MODULE_RESOLVE
106
//#define DUMP_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
    JS_CLASS_BIG_INT64_ARRAY,   /* u.array (typed_array) */
148
    JS_CLASS_BIG_UINT64_ARRAY,  /* u.array (typed_array) */
149
    JS_CLASS_FLOAT32_ARRAY,     /* u.array (typed_array) */
150
    JS_CLASS_FLOAT64_ARRAY,     /* u.array (typed_array) */
151
    JS_CLASS_DATAVIEW,          /* u.typed_array */
152
    JS_CLASS_BIG_INT,           /* u.object_data */
153
#ifdef CONFIG_BIGNUM
154
    JS_CLASS_BIG_FLOAT,         /* u.object_data */
155
    JS_CLASS_FLOAT_ENV,         /* u.float_env */
156
    JS_CLASS_BIG_DECIMAL,       /* u.object_data */
157
    JS_CLASS_OPERATOR_SET,      /* u.operator_set */
158
#endif
159
    JS_CLASS_MAP,               /* u.map_state */
160
    JS_CLASS_SET,               /* u.map_state */
161
    JS_CLASS_WEAKMAP,           /* u.map_state */
162
    JS_CLASS_WEAKSET,           /* u.map_state */
163
    JS_CLASS_MAP_ITERATOR,      /* u.map_iterator_data */
164
    JS_CLASS_SET_ITERATOR,      /* u.map_iterator_data */
165
    JS_CLASS_ARRAY_ITERATOR,    /* u.array_iterator_data */
166
    JS_CLASS_STRING_ITERATOR,   /* u.array_iterator_data */
167
    JS_CLASS_REGEXP_STRING_ITERATOR,   /* u.regexp_string_iterator_data */
168
    JS_CLASS_GENERATOR,         /* u.generator_data */
169
    JS_CLASS_PROXY,             /* u.proxy_data */
170
    JS_CLASS_PROMISE,           /* u.promise_data */
171
    JS_CLASS_PROMISE_RESOLVE_FUNCTION,  /* u.promise_function_data */
172
    JS_CLASS_PROMISE_REJECT_FUNCTION,   /* u.promise_function_data */
173
    JS_CLASS_ASYNC_FUNCTION,            /* u.func */
174
    JS_CLASS_ASYNC_FUNCTION_RESOLVE,    /* u.async_function_data */
175
    JS_CLASS_ASYNC_FUNCTION_REJECT,     /* u.async_function_data */
176
    JS_CLASS_ASYNC_FROM_SYNC_ITERATOR,  /* u.async_from_sync_iterator_data */
177
    JS_CLASS_ASYNC_GENERATOR_FUNCTION,  /* u.func */
178
    JS_CLASS_ASYNC_GENERATOR,   /* u.async_generator_data */
179
180
    JS_CLASS_INIT_COUNT, /* last entry for predefined classes */
181
};
182
183
/* number of typed array types */
184
468
#define JS_TYPED_ARRAY_COUNT  (JS_CLASS_FLOAT64_ARRAY - JS_CLASS_UINT8C_ARRAY + 1)
185
static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT];
186
858
#define typed_array_size_log2(classid)  (typed_array_size_log2[(classid)- JS_CLASS_UINT8C_ARRAY])
187
188
typedef enum JSErrorEnum {
189
    JS_EVAL_ERROR,
190
    JS_RANGE_ERROR,
191
    JS_REFERENCE_ERROR,
192
    JS_SYNTAX_ERROR,
193
    JS_TYPE_ERROR,
194
    JS_URI_ERROR,
195
    JS_INTERNAL_ERROR,
196
    JS_AGGREGATE_ERROR,
197
198
    JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */
199
} JSErrorEnum;
200
201
114
#define JS_MAX_LOCAL_VARS 65535
202
321
#define JS_STACK_SIZE_MAX 65534
203
19.7k
#define JS_STRING_LEN_MAX ((1 << 30) - 1)
204
205
#define __exception __attribute__((warn_unused_result))
206
207
typedef struct JSShape JSShape;
208
typedef struct JSString JSString;
209
typedef struct JSString JSAtomStruct;
210
211
typedef enum {
212
    JS_GC_PHASE_NONE,
213
    JS_GC_PHASE_DECREF,
214
    JS_GC_PHASE_REMOVE_CYCLES,
215
} JSGCPhaseEnum;
216
217
typedef enum OPCodeEnum OPCodeEnum;
218
219
/* function pointers are used for numeric operations so that it is
220
   possible to remove some numeric types */
221
typedef struct {
222
    JSValue (*to_string)(JSContext *ctx, JSValueConst val);
223
    JSValue (*from_string)(JSContext *ctx, const char *buf,
224
                           int radix, int flags, slimb_t *pexponent);
225
    int (*unary_arith)(JSContext *ctx,
226
                       JSValue *pres, OPCodeEnum op, JSValue op1);
227
    int (*binary_arith)(JSContext *ctx, OPCodeEnum op,
228
                        JSValue *pres, JSValue op1, JSValue op2);
229
    int (*compare)(JSContext *ctx, OPCodeEnum op,
230
                   JSValue op1, JSValue op2);
231
    /* only for bigfloat: */
232
    JSValue (*mul_pow10_to_float64)(JSContext *ctx, const bf_t *a,
233
                                    int64_t exponent);
234
    int (*mul_pow10)(JSContext *ctx, JSValue *sp);
235
} JSNumericOperations;
236
237
struct JSRuntime {
238
    JSMallocFunctions mf;
239
    JSMallocState malloc_state;
240
    const char *rt_info;
241
242
    int atom_hash_size; /* power of two */
243
    int atom_count;
244
    int atom_size;
245
    int atom_count_resize; /* resize hash table at this count */
246
    uint32_t *atom_hash;
247
    JSAtomStruct **atom_array;
248
    int atom_free_index; /* 0 = none */
249
250
    int class_count;    /* size of class_array */
251
    JSClass *class_array;
252
253
    struct list_head context_list; /* list of JSContext.link */
254
    /* list of JSGCObjectHeader.link. List of allocated GC objects (used
255
       by the garbage collector) */
256
    struct list_head gc_obj_list;
257
    /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */
258
    struct list_head gc_zero_ref_count_list;
259
    struct list_head tmp_obj_list; /* used during GC */
260
    JSGCPhaseEnum gc_phase : 8;
261
    size_t malloc_gc_threshold;
262
#ifdef DUMP_LEAKS
263
    struct list_head string_list; /* list of JSString.link */
264
#endif
265
    /* stack limitation */
266
    uintptr_t stack_size; /* in bytes, 0 if no limit */
267
    uintptr_t stack_top;
268
    uintptr_t stack_limit; /* lower stack limit */
269
270
    JSValue current_exception;
271
    /* true if inside an out of memory error, to avoid recursing */
272
    BOOL in_out_of_memory : 8;
273
274
    struct JSStackFrame *current_stack_frame;
275
276
    JSInterruptHandler *interrupt_handler;
277
    void *interrupt_opaque;
278
279
    JSHostPromiseRejectionTracker *host_promise_rejection_tracker;
280
    void *host_promise_rejection_tracker_opaque;
281
282
    struct list_head job_list; /* list of JSJobEntry.link */
283
284
    JSModuleNormalizeFunc *module_normalize_func;
285
    JSModuleLoaderFunc *module_loader_func;
286
    void *module_loader_opaque;
287
    /* timestamp for internal use in module evaluation */
288
    int64_t module_async_evaluation_next_timestamp;
289
290
    BOOL can_block : 8; /* TRUE if Atomics.wait can block */
291
    /* used to allocate, free and clone SharedArrayBuffers */
292
    JSSharedArrayBufferFunctions sab_funcs;
293
294
    /* Shape hash table */
295
    int shape_hash_bits;
296
    int shape_hash_size;
297
    int shape_hash_count; /* number of hashed shapes */
298
    JSShape **shape_hash;
299
    bf_context_t bf_ctx;
300
    JSNumericOperations bigint_ops;
301
#ifdef CONFIG_BIGNUM
302
    JSNumericOperations bigfloat_ops;
303
    JSNumericOperations bigdecimal_ops;
304
    uint32_t operator_count;
305
#endif
306
    void *user_opaque;
307
};
308
309
struct JSClass {
310
    uint32_t class_id; /* 0 means free entry */
311
    JSAtom class_name;
312
    JSClassFinalizer *finalizer;
313
    JSClassGCMark *gc_mark;
314
    JSClassCall *call;
315
    /* pointers for exotic behavior, can be NULL if none are present */
316
    const JSClassExoticMethods *exotic;
317
};
318
319
295
#define JS_MODE_STRICT (1 << 0)
320
339
#define JS_MODE_STRIP  (1 << 1)
321
11.1M
#define JS_MODE_MATH   (1 << 2)
322
39
#define JS_MODE_ASYNC  (1 << 3) /* async function */
323
324
typedef struct JSStackFrame {
325
    struct JSStackFrame *prev_frame; /* NULL if first stack frame */
326
    JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */
327
    JSValue *arg_buf; /* arguments */
328
    JSValue *var_buf; /* variables */
329
    struct list_head var_ref_list; /* list of JSVarRef.var_ref_link */
330
    const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
331
                        instruction after the call */
332
    int arg_count;
333
    int js_mode; /* for C functions, only JS_MODE_MATH may be set */
334
    /* only used in generators. Current stack pointer value. NULL if
335
       the function is running. */
336
    JSValue *cur_sp;
337
} JSStackFrame;
338
339
typedef enum {
340
    JS_GC_OBJ_TYPE_JS_OBJECT,
341
    JS_GC_OBJ_TYPE_FUNCTION_BYTECODE,
342
    JS_GC_OBJ_TYPE_SHAPE,
343
    JS_GC_OBJ_TYPE_VAR_REF,
344
    JS_GC_OBJ_TYPE_ASYNC_FUNCTION,
345
    JS_GC_OBJ_TYPE_JS_CONTEXT,
346
} JSGCObjectTypeEnum;
347
348
/* header for GC objects. GC objects are C data structures with a
349
   reference count that can reference other GC objects. JS Objects are
350
   a particular type of GC object. */
351
struct JSGCObjectHeader {
352
    int ref_count; /* must come first, 32-bit */
353
    JSGCObjectTypeEnum gc_obj_type : 4;
354
    uint8_t mark : 4; /* used by the GC */
355
    uint8_t dummy1; /* not used by the GC */
356
    uint16_t dummy2; /* not used by the GC */
357
    struct list_head link;
358
};
359
360
typedef struct JSVarRef {
361
    union {
362
        JSGCObjectHeader header; /* must come first */
363
        struct {
364
            int __gc_ref_count; /* corresponds to header.ref_count */
365
            uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
366
            uint8_t is_detached : 1;
367
            uint8_t is_arg : 1;
368
            uint16_t var_idx; /* index of the corresponding function variable on
369
                                 the stack */
370
        };
371
    };
372
    JSValue *pvalue; /* pointer to the value, either on the stack or
373
                        to 'value' */
374
    union {
375
        JSValue value; /* used when is_detached = TRUE */
376
        struct {
377
            struct list_head var_ref_link; /* JSStackFrame.var_ref_list list */
378
            struct JSAsyncFunctionState *async_func; /* != NULL if async stack frame */
379
        }; /* used when is_detached = FALSE */
380
    };
381
} JSVarRef;
382
383
/* the same structure is used for big integers and big floats. Big
384
   integers are never infinite or NaNs */
385
typedef struct JSBigFloat {
386
    JSRefCountHeader header; /* must come first, 32-bit */
387
    bf_t num;
388
} JSBigFloat;
389
390
#ifdef CONFIG_BIGNUM
391
typedef struct JSFloatEnv {
392
    limb_t prec;
393
    bf_flags_t flags;
394
    unsigned int status;
395
} JSFloatEnv;
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
39
#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
    bf_context_t *bf_ctx;   /* points to rt->bf_ctx, shared by all contexts */
441
#ifdef CONFIG_BIGNUM
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
449
    struct list_head loaded_modules; /* list of JSModuleDef.link */
450
451
    /* if NULL, RegExp compilation is not supported */
452
    JSValue (*compile_regexp)(JSContext *ctx, JSValueConst pattern,
453
                              JSValueConst flags);
454
    /* if NULL, eval is not supported */
455
    JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj,
456
                             const char *input, size_t input_len,
457
                             const char *filename, int flags, int scope_idx);
458
    void *user_opaque;
459
};
460
461
typedef union JSFloat64Union {
462
    double d;
463
    uint64_t u64;
464
    uint32_t u32[2];
465
} JSFloat64Union;
466
467
enum {
468
    JS_ATOM_TYPE_STRING = 1,
469
    JS_ATOM_TYPE_GLOBAL_SYMBOL,
470
    JS_ATOM_TYPE_SYMBOL,
471
    JS_ATOM_TYPE_PRIVATE,
472
};
473
474
enum {
475
    JS_ATOM_HASH_SYMBOL,
476
    JS_ATOM_HASH_PRIVATE,
477
};
478
479
typedef enum {
480
    JS_ATOM_KIND_STRING,
481
    JS_ATOM_KIND_SYMBOL,
482
    JS_ATOM_KIND_PRIVATE,
483
} JSAtomKindEnum;
484
485
65.1k
#define JS_ATOM_HASH_MASK  ((1 << 30) - 1)
486
487
struct JSString {
488
    JSRefCountHeader header; /* must come first, 32-bit */
489
    uint32_t len : 31;
490
    uint8_t is_wide_char : 1; /* 0 = 8 bits, 1 = 16 bits characters */
491
    /* for JS_ATOM_TYPE_SYMBOL: hash = 0, atom_type = 3,
492
       for JS_ATOM_TYPE_PRIVATE: hash = 1, atom_type = 3
493
       XXX: could change encoding to have one more bit in hash */
494
    uint32_t hash : 30;
495
    uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */
496
    uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */
497
#ifdef DUMP_LEAKS
498
    struct list_head link; /* string list */
499
#endif
500
    union {
501
        uint8_t str8[0]; /* 8 bit strings will get an extra null terminator */
502
        uint16_t str16[0];
503
    } u;
504
};
505
506
typedef struct JSClosureVar {
507
    uint8_t is_local : 1;
508
    uint8_t is_arg : 1;
509
    uint8_t is_const : 1;
510
    uint8_t is_lexical : 1;
511
    uint8_t var_kind : 4; /* see JSVarKindEnum */
512
    /* 8 bits available */
513
    uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the
514
                    parent function. otherwise: index to a closure
515
                    variable of the parent function */
516
    JSAtom var_name;
517
} JSClosureVar;
518
519
0
#define ARG_SCOPE_INDEX 1
520
167
#define ARG_SCOPE_END (-2)
521
522
typedef struct JSVarScope {
523
    int parent;  /* index into fd->scopes of the enclosing scope */
524
    int first;   /* index into fd->vars of the last variable in this scope */
525
} JSVarScope;
526
527
typedef enum {
528
    /* XXX: add more variable kinds here instead of using bit fields */
529
    JS_VAR_NORMAL,
530
    JS_VAR_FUNCTION_DECL, /* lexical var with function declaration */
531
    JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator
532
                                 function declaration */
533
    JS_VAR_CATCH,
534
    JS_VAR_FUNCTION_NAME, /* function expression name */
535
    JS_VAR_PRIVATE_FIELD,
536
    JS_VAR_PRIVATE_METHOD,
537
    JS_VAR_PRIVATE_GETTER,
538
    JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */
539
    JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */
540
} JSVarKindEnum;
541
542
/* XXX: could use a different structure in bytecode functions to save
543
   memory */
544
typedef struct JSVarDef {
545
    JSAtom var_name;
546
    /* index into fd->scopes of this variable lexical scope */
547
    int scope_level;
548
    /* during compilation:
549
        - if scope_level = 0: scope in which the variable is defined
550
        - if scope_level != 0: index into fd->vars of the next
551
          variable in the same or enclosing lexical scope
552
       in a bytecode function:
553
       index into fd->vars of the next
554
       variable in the same or enclosing lexical scope
555
    */
556
    int scope_next;
557
    uint8_t is_const : 1;
558
    uint8_t is_lexical : 1;
559
    uint8_t is_captured : 1;
560
    uint8_t is_static_private : 1; /* only used during private class field parsing */
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
492
#define PC2LINE_BASE     (-1)
574
484
#define PC2LINE_RANGE    5
575
234
#define PC2LINE_OP_FIRST 1
576
117
#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
    uint8_t is_direct_or_indirect_eval : 1; /* used by JS_GetScriptOrModuleName() */
602
    /* XXX: 10 bits available */
603
    uint8_t *byte_code_buf; /* (self pointer) */
604
    int byte_code_len;
605
    JSAtom func_name;
606
    JSVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */
607
    JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */
608
    uint16_t arg_count;
609
    uint16_t var_count;
610
    uint16_t defined_arg_count; /* for length function property */
611
    uint16_t stack_size; /* maximum stack size */
612
    JSContext *realm; /* function realm */
613
    JSValue *cpool; /* constant pool (self pointer) */
614
    int cpool_count;
615
    int closure_var_count;
616
    struct {
617
        /* debug info, move to separate structure to save memory? */
618
        JSAtom filename;
619
        int line_num;
620
        int source_len;
621
        int pc2line_len;
622
        uint8_t *pc2line_buf;
623
        char *source;
624
    } debug;
625
} JSFunctionBytecode;
626
627
typedef struct JSBoundFunction {
628
    JSValue func_obj;
629
    JSValue this_val;
630
    int argc;
631
    JSValue argv[0];
632
} JSBoundFunction;
633
634
typedef enum JSIteratorKindEnum {
635
    JS_ITERATOR_KIND_KEY,
636
    JS_ITERATOR_KIND_VALUE,
637
    JS_ITERATOR_KIND_KEY_AND_VALUE,
638
} JSIteratorKindEnum;
639
640
typedef struct JSForInIterator {
641
    JSValue obj;
642
    uint32_t idx;
643
    uint32_t atom_count;
644
    uint8_t in_prototype_chain;
645
    uint8_t is_array;
646
    JSPropertyEnum *tab_atom; /* is_array = FALSE */
647
} JSForInIterator;
648
649
typedef struct JSRegExp {
650
    JSString *pattern;
651
    JSString *bytecode; /* also contains the flags */
652
} JSRegExp;
653
654
typedef struct JSProxyData {
655
    JSValue target;
656
    JSValue handler;
657
    uint8_t is_func;
658
    uint8_t is_revoked;
659
} JSProxyData;
660
661
typedef struct JSArrayBuffer {
662
    int byte_length; /* 0 if detached */
663
    uint8_t detached;
664
    uint8_t shared; /* if shared, the array buffer cannot be detached */
665
    uint8_t *data; /* NULL if detached */
666
    struct list_head array_list;
667
    void *opaque;
668
    JSFreeArrayBufferDataFunc *free_func;
669
} JSArrayBuffer;
670
671
typedef struct JSTypedArray {
672
    struct list_head link; /* link to arraybuffer */
673
    JSObject *obj; /* back pointer to the TypedArray/DataView object */
674
    JSObject *buffer; /* based array buffer */
675
    uint32_t offset; /* offset in the array buffer */
676
    uint32_t length; /* length in the array buffer */
677
} JSTypedArray;
678
679
typedef struct JSAsyncFunctionState {
680
    JSGCObjectHeader header;
681
    JSValue this_val; /* 'this' argument */
682
    int argc; /* number of function arguments */
683
    BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */
684
    BOOL is_completed; /* TRUE if the function has returned. The stack
685
                          frame is no longer valid */
686
    JSValue resolving_funcs[2]; /* only used in JS async functions */
687
    JSStackFrame frame;
688
} JSAsyncFunctionState;
689
690
typedef enum {
691
   /* binary operators */
692
   JS_OVOP_ADD,
693
   JS_OVOP_SUB,
694
   JS_OVOP_MUL,
695
   JS_OVOP_DIV,
696
   JS_OVOP_MOD,
697
   JS_OVOP_POW,
698
   JS_OVOP_OR,
699
   JS_OVOP_AND,
700
   JS_OVOP_XOR,
701
   JS_OVOP_SHL,
702
   JS_OVOP_SAR,
703
   JS_OVOP_SHR,
704
   JS_OVOP_EQ,
705
   JS_OVOP_LESS,
706
707
   JS_OVOP_BINARY_COUNT,
708
   /* unary operators */
709
   JS_OVOP_POS = JS_OVOP_BINARY_COUNT,
710
   JS_OVOP_NEG,
711
   JS_OVOP_INC,
712
   JS_OVOP_DEC,
713
   JS_OVOP_NOT,
714
715
   JS_OVOP_COUNT,
716
} JSOverloadableOperatorEnum;
717
718
typedef struct {
719
    uint32_t operator_index;
720
    JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */
721
} JSBinaryOperatorDefEntry;
722
723
typedef struct {
724
    int count;
725
    JSBinaryOperatorDefEntry *tab;
726
} JSBinaryOperatorDef;
727
728
typedef struct {
729
    uint32_t operator_counter;
730
    BOOL is_primitive; /* OperatorSet for a primitive type */
731
    /* NULL if no operator is defined */
732
    JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */
733
    JSBinaryOperatorDef left;
734
    JSBinaryOperatorDef right;
735
} JSOperatorSetData;
736
737
typedef struct JSReqModuleEntry {
738
    JSAtom module_name;
739
    JSModuleDef *module; /* used using resolution */
740
} JSReqModuleEntry;
741
742
typedef enum JSExportTypeEnum {
743
    JS_EXPORT_TYPE_LOCAL,
744
    JS_EXPORT_TYPE_INDIRECT,
745
} JSExportTypeEnum;
746
747
typedef struct JSExportEntry {
748
    union {
749
        struct {
750
            int var_idx; /* closure variable index */
751
            JSVarRef *var_ref; /* if != NULL, reference to the variable */
752
        } local; /* for local export */
753
        int req_module_idx; /* module for indirect export */
754
    } u;
755
    JSExportTypeEnum export_type;
756
    JSAtom local_name; /* '*' if export ns from. not used for local
757
                          export after compilation */
758
    JSAtom export_name; /* exported variable name */
759
} JSExportEntry;
760
761
typedef struct JSStarExportEntry {
762
    int req_module_idx; /* in req_module_entries */
763
} JSStarExportEntry;
764
765
typedef struct JSImportEntry {
766
    int var_idx; /* closure variable index */
767
    JSAtom import_name;
768
    int req_module_idx; /* in req_module_entries */
769
} JSImportEntry;
770
771
typedef enum {
772
    JS_MODULE_STATUS_UNLINKED,
773
    JS_MODULE_STATUS_LINKING,
774
    JS_MODULE_STATUS_LINKED,
775
    JS_MODULE_STATUS_EVALUATING,
776
    JS_MODULE_STATUS_EVALUATING_ASYNC,
777
    JS_MODULE_STATUS_EVALUATED,
778
} JSModuleStatus;
779
780
struct JSModuleDef {
781
    JSRefCountHeader header; /* must come first, 32-bit */
782
    JSAtom module_name;
783
    struct list_head link;
784
785
    JSReqModuleEntry *req_module_entries;
786
    int req_module_entries_count;
787
    int req_module_entries_size;
788
789
    JSExportEntry *export_entries;
790
    int export_entries_count;
791
    int export_entries_size;
792
793
    JSStarExportEntry *star_export_entries;
794
    int star_export_entries_count;
795
    int star_export_entries_size;
796
797
    JSImportEntry *import_entries;
798
    int import_entries_count;
799
    int import_entries_size;
800
801
    JSValue module_ns;
802
    JSValue func_obj; /* only used for JS modules */
803
    JSModuleInitFunc *init_func; /* only used for C modules */
804
    BOOL has_tla : 8; /* true if func_obj contains await */
805
    BOOL resolved : 8;
806
    BOOL func_created : 8;
807
    JSModuleStatus status : 8;
808
    /* temp use during js_module_link() & js_module_evaluate() */
809
    int dfs_index, dfs_ancestor_index;
810
    JSModuleDef *stack_prev;
811
    /* temp use during js_module_evaluate() */
812
    JSModuleDef **async_parent_modules;
813
    int async_parent_modules_count;
814
    int async_parent_modules_size;
815
    int pending_async_dependencies;
816
    BOOL async_evaluation;
817
    int64_t async_evaluation_timestamp;
818
    JSModuleDef *cycle_root;
819
    JSValue promise; /* corresponds to spec field: capability */
820
    JSValue resolving_funcs[2]; /* corresponds to spec field: capability */
821
822
    /* true if evaluation yielded an exception. It is saved in
823
       eval_exception */
824
    BOOL eval_has_exception : 8;
825
    JSValue eval_exception;
826
    JSValue meta_obj; /* for import.meta */
827
};
828
829
typedef struct JSJobEntry {
830
    struct list_head link;
831
    JSContext *ctx;
832
    JSJobFunc *job_func;
833
    int argc;
834
    JSValue argv[0];
835
} JSJobEntry;
836
837
typedef struct JSProperty {
838
    union {
839
        JSValue value;      /* JS_PROP_NORMAL */
840
        struct {            /* JS_PROP_GETSET */
841
            JSObject *getter; /* NULL if undefined */
842
            JSObject *setter; /* NULL if undefined */
843
        } getset;
844
        JSVarRef *var_ref;  /* JS_PROP_VARREF */
845
        struct {            /* JS_PROP_AUTOINIT */
846
            /* in order to use only 2 pointers, we compress the realm
847
               and the init function pointer */
848
            uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x)
849
                                       in the 2 low bits */
850
            void *opaque;
851
        } init;
852
    } u;
853
} JSProperty;
854
855
7.24k
#define JS_PROP_INITIAL_SIZE 2
856
7.28k
#define JS_PROP_INITIAL_HASH_SIZE 4 /* must be a power of two */
857
#define JS_ARRAY_INITIAL_SIZE 2
858
859
typedef struct JSShapeProperty {
860
    uint32_t hash_next : 26; /* 0 if last in list */
861
    uint32_t flags : 6;   /* JS_PROP_XXX */
862
    JSAtom atom; /* JS_ATOM_NULL = free property entry */
863
} JSShapeProperty;
864
865
struct JSShape {
866
    /* hash table of size hash_mask + 1 before the start of the
867
       structure (see prop_hash_end()). */
868
    JSGCObjectHeader header;
869
    /* true if the shape is inserted in the shape hash table. If not,
870
       JSShape.hash is not valid */
871
    uint8_t is_hashed;
872
    /* If true, the shape may have small array index properties 'n' with 0
873
       <= n <= 2^31-1. If false, the shape is guaranteed not to have
874
       small array index properties */
875
    uint8_t has_small_array_index;
876
    uint32_t hash; /* current hash value */
877
    uint32_t prop_hash_mask;
878
    int prop_size; /* allocated properties */
879
    int prop_count; /* include deleted properties */
880
    int deleted_prop_count;
881
    JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */
882
    JSObject *proto;
883
    JSShapeProperty prop[0]; /* prop_size elements */
884
};
885
886
struct JSObject {
887
    union {
888
        JSGCObjectHeader header;
889
        struct {
890
            int __gc_ref_count; /* corresponds to header.ref_count */
891
            uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
892
893
            uint8_t extensible : 1;
894
            uint8_t free_mark : 1; /* only used when freeing objects with cycles */
895
            uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */
896
            uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */
897
            uint8_t is_constructor : 1; /* TRUE if object is a constructor function */
898
            uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */
899
            uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */
900
            uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */
901
            uint16_t class_id; /* see JS_CLASS_x */
902
        };
903
    };
904
    /* byte offsets: 16/24 */
905
    JSShape *shape; /* prototype and property names + flag */
906
    JSProperty *prop; /* array of properties */
907
    /* byte offsets: 24/40 */
908
    struct JSMapRecord *first_weak_ref; /* XXX: use a bit and an external hash table? */
909
    /* byte offsets: 28/48 */
910
    union {
911
        void *opaque;
912
        struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */
913
        struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */
914
        struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */
915
        struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */
916
        struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */
917
#ifdef CONFIG_BIGNUM
918
        struct JSFloatEnv *float_env; /* JS_CLASS_FLOAT_ENV */
919
        struct JSOperatorSetData *operator_set; /* JS_CLASS_OPERATOR_SET */
920
#endif
921
        struct JSMapState *map_state;   /* JS_CLASS_MAP..JS_CLASS_WEAKSET */
922
        struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */
923
        struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */
924
        struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */
925
        struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */
926
        struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */
927
        struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */
928
        struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */
929
        struct JSAsyncFunctionState *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */
930
        struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
931
        struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */
932
        struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */
933
            /* also used by JS_CLASS_GENERATOR_FUNCTION, JS_CLASS_ASYNC_FUNCTION and JS_CLASS_ASYNC_GENERATOR_FUNCTION */
934
            struct JSFunctionBytecode *function_bytecode;
935
            JSVarRef **var_refs;
936
            JSObject *home_object; /* for 'super' access */
937
        } func;
938
        struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */
939
            JSContext *realm;
940
            JSCFunctionType c_function;
941
            uint8_t length;
942
            uint8_t cproto;
943
            int16_t magic;
944
        } cfunc;
945
        /* array part for fast arrays and typed arrays */
946
        struct { /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
947
            union {
948
                uint32_t size;          /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */
949
                struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
950
            } u1;
951
            union {
952
                JSValue *values;        /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */
953
                void *ptr;              /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
954
                int8_t *int8_ptr;       /* JS_CLASS_INT8_ARRAY */
955
                uint8_t *uint8_ptr;     /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */
956
                int16_t *int16_ptr;     /* JS_CLASS_INT16_ARRAY */
957
                uint16_t *uint16_ptr;   /* JS_CLASS_UINT16_ARRAY */
958
                int32_t *int32_ptr;     /* JS_CLASS_INT32_ARRAY */
959
                uint32_t *uint32_ptr;   /* JS_CLASS_UINT32_ARRAY */
960
                int64_t *int64_ptr;     /* JS_CLASS_INT64_ARRAY */
961
                uint64_t *uint64_ptr;   /* JS_CLASS_UINT64_ARRAY */
962
                float *float_ptr;       /* JS_CLASS_FLOAT32_ARRAY */
963
                double *double_ptr;     /* JS_CLASS_FLOAT64_ARRAY */
964
            } u;
965
            uint32_t count; /* <= 2^31-1. 0 for a detached typed array */
966
        } array;    /* 12/20 bytes */
967
        JSRegExp regexp;    /* JS_CLASS_REGEXP: 8/16 bytes */
968
        JSValue object_data;    /* for JS_SetObjectData(): 8/16/16 bytes */
969
    } u;
970
    /* byte sizes: 40/48/72 */
971
};
972
973
enum {
974
    __JS_ATOM_NULL = JS_ATOM_NULL,
975
#define DEF(name, str) JS_ATOM_ ## name,
976
#include "quickjs-atom.h"
977
#undef DEF
978
    JS_ATOM_END,
979
};
980
1.12k
#define JS_ATOM_LAST_KEYWORD JS_ATOM_super
981
970
#define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield
982
983
static const char js_atom_init[] =
984
#define DEF(name, str) str "\0"
985
#include "quickjs-atom.h"
986
#undef DEF
987
;
988
989
typedef enum OPCodeFormat {
990
#define FMT(f) OP_FMT_ ## f,
991
#define DEF(id, size, n_pop, n_push, f)
992
#include "quickjs-opcode.h"
993
#undef DEF
994
#undef FMT
995
} OPCodeFormat;
996
997
enum OPCodeEnum {
998
#define FMT(f)
999
#define DEF(id, size, n_pop, n_push, f) OP_ ## id,
1000
#define def(id, size, n_pop, n_push, f)
1001
#include "quickjs-opcode.h"
1002
#undef def
1003
#undef DEF
1004
#undef FMT
1005
    OP_COUNT, /* excluding temporary opcodes */
1006
    /* temporary opcodes : overlap with the short opcodes */
1007
    OP_TEMP_START = OP_nop + 1,
1008
    OP___dummy = OP_TEMP_START - 1,
1009
#define FMT(f)
1010
#define DEF(id, size, n_pop, n_push, f)
1011
#define def(id, size, n_pop, n_push, f) OP_ ## id,
1012
#include "quickjs-opcode.h"
1013
#undef def
1014
#undef DEF
1015
#undef FMT
1016
    OP_TEMP_END,
1017
};
1018
1019
static int JS_InitAtoms(JSRuntime *rt);
1020
static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
1021
                               int atom_type);
1022
static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p);
1023
static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b);
1024
static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
1025
                                  JSValueConst this_obj,
1026
                                  int argc, JSValueConst *argv, int flags);
1027
static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
1028
                                      JSValueConst this_obj,
1029
                                      int argc, JSValueConst *argv, int flags);
1030
static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
1031
                               JSValueConst this_obj, JSValueConst new_target,
1032
                               int argc, JSValue *argv, int flags);
1033
static JSValue JS_CallConstructorInternal(JSContext *ctx,
1034
                                          JSValueConst func_obj,
1035
                                          JSValueConst new_target,
1036
                                          int argc, JSValue *argv, int flags);
1037
static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
1038
                           int argc, JSValueConst *argv);
1039
static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
1040
                             int argc, JSValueConst *argv);
1041
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
1042
                                            JSValue val, BOOL is_array_ctor);
1043
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
1044
                             JSValueConst val, int flags, int scope_idx);
1045
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
1046
static __maybe_unused void JS_DumpAtoms(JSRuntime *rt);
1047
static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p);
1048
static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
1049
static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
1050
static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);
1051
static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, JSValueConst val);
1052
static __maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val);
1053
static __maybe_unused void JS_PrintValue(JSContext *ctx,
1054
                                                  const char *str,
1055
                                                  JSValueConst val);
1056
static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
1057
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
1058
                                 int argc, JSValueConst *argv, int magic);
1059
static void js_array_finalizer(JSRuntime *rt, JSValue val);
1060
static void js_array_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
1061
static void js_object_data_finalizer(JSRuntime *rt, JSValue val);
1062
static void js_object_data_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
1063
static void js_c_function_finalizer(JSRuntime *rt, JSValue val);
1064
static void js_c_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
1065
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val);
1066
static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
1067
                                JS_MarkFunc *mark_func);
1068
static void js_bound_function_finalizer(JSRuntime *rt, JSValue val);
1069
static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
1070
                                JS_MarkFunc *mark_func);
1071
static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val);
1072
static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
1073
                                JS_MarkFunc *mark_func);
1074
static void js_regexp_finalizer(JSRuntime *rt, JSValue val);
1075
static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val);
1076
static void js_typed_array_finalizer(JSRuntime *rt, JSValue val);
1077
static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
1078
                                JS_MarkFunc *mark_func);
1079
static void js_proxy_finalizer(JSRuntime *rt, JSValue val);
1080
static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
1081
                                JS_MarkFunc *mark_func);
1082
static void js_map_finalizer(JSRuntime *rt, JSValue val);
1083
static void js_map_mark(JSRuntime *rt, JSValueConst val,
1084
                                JS_MarkFunc *mark_func);
1085
static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val);
1086
static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
1087
                                JS_MarkFunc *mark_func);
1088
static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val);
1089
static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
1090
                                JS_MarkFunc *mark_func);
1091
static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val);
1092
static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
1093
                                JS_MarkFunc *mark_func);
1094
static void js_generator_finalizer(JSRuntime *rt, JSValue obj);
1095
static void js_generator_mark(JSRuntime *rt, JSValueConst val,
1096
                                JS_MarkFunc *mark_func);
1097
static void js_promise_finalizer(JSRuntime *rt, JSValue val);
1098
static void js_promise_mark(JSRuntime *rt, JSValueConst val,
1099
                                JS_MarkFunc *mark_func);
1100
static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val);
1101
static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
1102
                                JS_MarkFunc *mark_func);
1103
#ifdef CONFIG_BIGNUM
1104
static void js_operator_set_finalizer(JSRuntime *rt, JSValue val);
1105
static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
1106
                                 JS_MarkFunc *mark_func);
1107
#endif
1108
1109
0
#define HINT_STRING  0
1110
0
#define HINT_NUMBER  1
1111
0
#define HINT_NONE    2
1112
0
#define HINT_FORCE_ORDINARY (1 << 4) // don't try Symbol.toPrimitive
1113
static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint);
1114
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
1115
static int JS_ToBoolFree(JSContext *ctx, JSValue val);
1116
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
1117
static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val);
1118
static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val);
1119
static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
1120
                                 JSValueConst flags);
1121
static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
1122
                                              JSValue pattern, JSValue bc);
1123
static void gc_decref(JSRuntime *rt);
1124
static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
1125
                        const JSClassDef *class_def, JSAtom name);
1126
1127
typedef enum JSStrictEqModeEnum {
1128
    JS_EQ_STRICT,
1129
    JS_EQ_SAME_VALUE,
1130
    JS_EQ_SAME_VALUE_ZERO,
1131
} JSStrictEqModeEnum;
1132
1133
static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
1134
                          JSStrictEqModeEnum eq_mode);
1135
static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2);
1136
static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2);
1137
static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
1138
static JSValue JS_ToObject(JSContext *ctx, JSValueConst val);
1139
static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val);
1140
static JSProperty *add_property(JSContext *ctx,
1141
                                JSObject *p, JSAtom prop, int prop_flags);
1142
static JSValue JS_NewBigInt(JSContext *ctx);
1143
static inline bf_t *JS_GetBigInt(JSValueConst val)
1144
2
{
1145
2
    JSBigFloat *p = JS_VALUE_GET_PTR(val);
1146
2
    return &p->num;
1147
2
}
1148
static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
1149
                                 BOOL convert_to_safe_integer);
1150
static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val);
1151
static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
1152
static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);
1153
static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);
1154
#ifdef CONFIG_BIGNUM
1155
static void js_float_env_finalizer(JSRuntime *rt, JSValue val);
1156
static JSValue JS_NewBigFloat(JSContext *ctx);
1157
static inline bf_t *JS_GetBigFloat(JSValueConst val)
1158
0
{
1159
0
    JSBigFloat *p = JS_VALUE_GET_PTR(val);
1160
0
    return &p->num;
1161
0
}
1162
static JSValue JS_NewBigDecimal(JSContext *ctx);
1163
static inline bfdec_t *JS_GetBigDecimal(JSValueConst val)
1164
0
{
1165
0
    JSBigDecimal *p = JS_VALUE_GET_PTR(val);
1166
0
    return &p->num;
1167
0
}
1168
static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val);
1169
static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
1170
                                   BOOL allow_null_or_undefined);
1171
static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val);
1172
#endif
1173
JSValue JS_ThrowOutOfMemory(JSContext *ctx);
1174
static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);
1175
static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj);
1176
static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
1177
                                   JSValueConst proto_val, BOOL throw_flag);
1178
1179
static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, int throw_exception);
1180
static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj);
1181
static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj);
1182
static int JS_CreateProperty(JSContext *ctx, JSObject *p,
1183
                             JSAtom prop, JSValueConst val,
1184
                             JSValueConst getter, JSValueConst setter,
1185
                             int flags);
1186
static int js_string_memcmp(const JSString *p1, const JSString *p2, int len);
1187
static void reset_weak_ref(JSRuntime *rt, JSObject *p);
1188
static JSValue js_array_buffer_constructor3(JSContext *ctx,
1189
                                            JSValueConst new_target,
1190
                                            uint64_t len, JSClassID class_id,
1191
                                            uint8_t *buf,
1192
                                            JSFreeArrayBufferDataFunc *free_func,
1193
                                            void *opaque, BOOL alloc_flag);
1194
static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj);
1195
static JSValue js_typed_array_constructor(JSContext *ctx,
1196
                                          JSValueConst this_val,
1197
                                          int argc, JSValueConst *argv,
1198
                                          int classid);
1199
static JSValue js_typed_array_constructor_ta(JSContext *ctx,
1200
                                             JSValueConst new_target,
1201
                                             JSValueConst src_obj,
1202
                                             int classid);
1203
static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p);
1204
static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p);
1205
static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx);
1206
static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,
1207
                             BOOL is_arg);
1208
static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);
1209
static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);
1210
static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
1211
                                          JSValueConst this_obj,
1212
                                          int argc, JSValueConst *argv,
1213
                                          int flags);
1214
static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val);
1215
static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
1216
                                           JS_MarkFunc *mark_func);
1217
static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
1218
                               const char *input, size_t input_len,
1219
                               const char *filename, int flags, int scope_idx);
1220
static void js_free_module_def(JSContext *ctx, JSModuleDef *m);
1221
static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
1222
                               JS_MarkFunc *mark_func);
1223
static JSValue js_import_meta(JSContext *ctx);
1224
static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier);
1225
static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);
1226
static JSValue js_new_promise_capability(JSContext *ctx,
1227
                                         JSValue *resolving_funcs,
1228
                                         JSValueConst ctor);
1229
static __exception int perform_promise_then(JSContext *ctx,
1230
                                            JSValueConst promise,
1231
                                            JSValueConst *resolve_reject,
1232
                                            JSValueConst *cap_resolving_funcs);
1233
static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
1234
                                  int argc, JSValueConst *argv, int magic);
1235
static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
1236
                               int argc, JSValueConst *argv);
1237
static int js_string_compare(JSContext *ctx,
1238
                             const JSString *p1, const JSString *p2);
1239
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val);
1240
static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
1241
                               JSValue prop, JSValue val, int flags);
1242
static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val);
1243
static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val);
1244
static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val);
1245
static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
1246
                                     JSObject *p, JSAtom prop);
1247
static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc);
1248
static void JS_AddIntrinsicBasicObjects(JSContext *ctx);
1249
static void js_free_shape(JSRuntime *rt, JSShape *sh);
1250
static void js_free_shape_null(JSRuntime *rt, JSShape *sh);
1251
static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
1252
                                   JSShapeProperty **pprs);
1253
static int init_shape_hash(JSRuntime *rt);
1254
static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
1255
                                       JSValueConst obj);
1256
static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
1257
                                       JSValueConst obj);
1258
static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len);
1259
static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
1260
                               JSValueConst array_arg);
1261
static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
1262
                              JSValue **arrpp, uint32_t *countp);
1263
static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
1264
                                              JSValueConst sync_iter);
1265
static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val);
1266
static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
1267
                                    JS_MarkFunc *mark_func);
1268
static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
1269
                                       JSValueConst this_val,
1270
                                       int argc, JSValueConst *argv, int flags);
1271
static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val);
1272
static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
1273
                          JSGCObjectTypeEnum type);
1274
static void remove_gc_object(JSGCObjectHeader *h);
1275
static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
1276
static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
1277
                                 void *opaque);
1278
static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
1279
                                               JSAtom atom, void *opaque);
1280
static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val,
1281
                                 int argc, JSValueConst *argv, int is_map);
1282
1283
static const JSClassExoticMethods js_arguments_exotic_methods;
1284
static const JSClassExoticMethods js_string_exotic_methods;
1285
static const JSClassExoticMethods js_proxy_exotic_methods;
1286
static const JSClassExoticMethods js_module_ns_exotic_methods;
1287
static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;
1288
1289
static void js_trigger_gc(JSRuntime *rt, size_t size)
1290
10.3k
{
1291
10.3k
    BOOL force_gc;
1292
#ifdef FORCE_GC_AT_MALLOC
1293
    force_gc = TRUE;
1294
#else
1295
10.3k
    force_gc = ((rt->malloc_state.malloc_size + size) >
1296
10.3k
                rt->malloc_gc_threshold);
1297
10.3k
#endif
1298
10.3k
    if (force_gc) {
1299
#ifdef DUMP_GC
1300
        printf("GC: size=%" PRIu64 "\n",
1301
               (uint64_t)rt->malloc_state.malloc_size);
1302
#endif
1303
34
        JS_RunGC(rt);
1304
34
        rt->malloc_gc_threshold = rt->malloc_state.malloc_size +
1305
34
            (rt->malloc_state.malloc_size >> 1);
1306
34
    }
1307
10.3k
}
1308
1309
static size_t js_malloc_usable_size_unknown(const void *ptr)
1310
0
{
1311
0
    return 0;
1312
0
}
1313
1314
void *js_malloc_rt(JSRuntime *rt, size_t size)
1315
73.5k
{
1316
73.5k
    return rt->mf.js_malloc(&rt->malloc_state, size);
1317
73.5k
}
1318
1319
void js_free_rt(JSRuntime *rt, void *ptr)
1320
75.6k
{
1321
75.6k
    rt->mf.js_free(&rt->malloc_state, ptr);
1322
75.6k
}
1323
1324
void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size)
1325
18.5k
{
1326
18.5k
    return rt->mf.js_realloc(&rt->malloc_state, ptr, size);
1327
18.5k
}
1328
1329
size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr)
1330
2.80k
{
1331
2.80k
    return rt->mf.js_malloc_usable_size(ptr);
1332
2.80k
}
1333
1334
void *js_mallocz_rt(JSRuntime *rt, size_t size)
1335
1.18k
{
1336
1.18k
    void *ptr;
1337
1.18k
    ptr = js_malloc_rt(rt, size);
1338
1.18k
    if (!ptr)
1339
0
        return NULL;
1340
1.18k
    return memset(ptr, 0, size);
1341
1.18k
}
1342
1343
/* called by libbf */
1344
static void *js_bf_realloc(void *opaque, void *ptr, size_t size)
1345
1.26k
{
1346
1.26k
    JSRuntime *rt = opaque;
1347
1.26k
    return js_realloc_rt(rt, ptr, size);
1348
1.26k
}
1349
1350
/* Throw out of memory in case of error */
1351
void *js_malloc(JSContext *ctx, size_t size)
1352
45.3k
{
1353
45.3k
    void *ptr;
1354
45.3k
    ptr = js_malloc_rt(ctx->rt, size);
1355
45.3k
    if (unlikely(!ptr)) {
1356
0
        JS_ThrowOutOfMemory(ctx);
1357
0
        return NULL;
1358
0
    }
1359
45.3k
    return ptr;
1360
45.3k
}
1361
1362
/* Throw out of memory in case of error */
1363
void *js_mallocz(JSContext *ctx, size_t size)
1364
869
{
1365
869
    void *ptr;
1366
869
    ptr = js_mallocz_rt(ctx->rt, size);
1367
869
    if (unlikely(!ptr)) {
1368
0
        JS_ThrowOutOfMemory(ctx);
1369
0
        return NULL;
1370
0
    }
1371
869
    return ptr;
1372
869
}
1373
1374
void js_free(JSContext *ctx, void *ptr)
1375
11.2k
{
1376
11.2k
    js_free_rt(ctx->rt, ptr);
1377
11.2k
}
1378
1379
/* Throw out of memory in case of error */
1380
void *js_realloc(JSContext *ctx, void *ptr, size_t size)
1381
11.3k
{
1382
11.3k
    void *ret;
1383
11.3k
    ret = js_realloc_rt(ctx->rt, ptr, size);
1384
11.3k
    if (unlikely(!ret && size != 0)) {
1385
0
        JS_ThrowOutOfMemory(ctx);
1386
0
        return NULL;
1387
0
    }
1388
11.3k
    return ret;
1389
11.3k
}
1390
1391
/* store extra allocated size in *pslack if successful */
1392
void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack)
1393
2.80k
{
1394
2.80k
    void *ret;
1395
2.80k
    ret = js_realloc_rt(ctx->rt, ptr, size);
1396
2.80k
    if (unlikely(!ret && size != 0)) {
1397
0
        JS_ThrowOutOfMemory(ctx);
1398
0
        return NULL;
1399
0
    }
1400
2.80k
    if (pslack) {
1401
2.80k
        size_t new_size = js_malloc_usable_size_rt(ctx->rt, ret);
1402
2.80k
        *pslack = (new_size > size) ? new_size - size : 0;
1403
2.80k
    }
1404
2.80k
    return ret;
1405
2.80k
}
1406
1407
size_t js_malloc_usable_size(JSContext *ctx, const void *ptr)
1408
0
{
1409
0
    return js_malloc_usable_size_rt(ctx->rt, ptr);
1410
0
}
1411
1412
/* Throw out of memory exception in case of error */
1413
char *js_strndup(JSContext *ctx, const char *s, size_t n)
1414
78
{
1415
78
    char *ptr;
1416
78
    ptr = js_malloc(ctx, n + 1);
1417
78
    if (ptr) {
1418
78
        memcpy(ptr, s, n);
1419
78
        ptr[n] = '\0';
1420
78
    }
1421
78
    return ptr;
1422
78
}
1423
1424
char *js_strdup(JSContext *ctx, const char *str)
1425
78
{
1426
78
    return js_strndup(ctx, str, strlen(str));
1427
78
}
1428
1429
static no_inline int js_realloc_array(JSContext *ctx, void **parray,
1430
                                      int elem_size, int *psize, int req_size)
1431
2.01k
{
1432
2.01k
    int new_size;
1433
2.01k
    size_t slack;
1434
2.01k
    void *new_array;
1435
    /* XXX: potential arithmetic overflow */
1436
2.01k
    new_size = max_int(req_size, *psize * 3 / 2);
1437
2.01k
    new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack);
1438
2.01k
    if (!new_array)
1439
0
        return -1;
1440
2.01k
    new_size += slack / elem_size;
1441
2.01k
    *psize = new_size;
1442
2.01k
    *parray = new_array;
1443
2.01k
    return 0;
1444
2.01k
}
1445
1446
/* resize the array and update its size if req_size > *psize */
1447
static inline int js_resize_array(JSContext *ctx, void **parray, int elem_size,
1448
                                  int *psize, int req_size)
1449
7.09M
{
1450
7.09M
    if (unlikely(req_size > *psize))
1451
2.01k
        return js_realloc_array(ctx, parray, elem_size, psize, req_size);
1452
7.09M
    else
1453
7.09M
        return 0;
1454
7.09M
}
1455
1456
static inline void js_dbuf_init(JSContext *ctx, DynBuf *s)
1457
410
{
1458
410
    dbuf_init2(s, ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
1459
410
}
1460
1461
11.1M
static inline int is_digit(int c) {
1462
11.1M
    return c >= '0' && c <= '9';
1463
11.1M
}
1464
1465
13.4k
static inline int string_get(const JSString *p, int idx) {
1466
13.4k
    return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx];
1467
13.4k
}
1468
1469
typedef struct JSClassShortDef {
1470
    JSAtom class_name;
1471
    JSClassFinalizer *finalizer;
1472
    JSClassGCMark *gc_mark;
1473
} JSClassShortDef;
1474
1475
static JSClassShortDef const js_std_class_def[] = {
1476
    { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_OBJECT */
1477
    { JS_ATOM_Array, js_array_finalizer, js_array_mark },       /* JS_CLASS_ARRAY */
1478
    { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */
1479
    { JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */
1480
    { JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */
1481
    { JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */
1482
    { JS_ATOM_Symbol, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_SYMBOL */
1483
    { JS_ATOM_Arguments, js_array_finalizer, js_array_mark },   /* JS_CLASS_ARGUMENTS */
1484
    { JS_ATOM_Arguments, NULL, NULL },                          /* JS_CLASS_MAPPED_ARGUMENTS */
1485
    { JS_ATOM_Date, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_DATE */
1486
    { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_MODULE_NS */
1487
    { JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark }, /* JS_CLASS_C_FUNCTION */
1488
    { JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */
1489
    { JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */
1490
    { JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */
1491
    { JS_ATOM_GeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_GENERATOR_FUNCTION */
1492
    { JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark },      /* JS_CLASS_FOR_IN_ITERATOR */
1493
    { JS_ATOM_RegExp, js_regexp_finalizer, NULL },                              /* JS_CLASS_REGEXP */
1494
    { JS_ATOM_ArrayBuffer, js_array_buffer_finalizer, NULL },                   /* JS_CLASS_ARRAY_BUFFER */
1495
    { JS_ATOM_SharedArrayBuffer, js_array_buffer_finalizer, NULL },             /* JS_CLASS_SHARED_ARRAY_BUFFER */
1496
    { JS_ATOM_Uint8ClampedArray, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8C_ARRAY */
1497
    { JS_ATOM_Int8Array, js_typed_array_finalizer, js_typed_array_mark },       /* JS_CLASS_INT8_ARRAY */
1498
    { JS_ATOM_Uint8Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_UINT8_ARRAY */
1499
    { JS_ATOM_Int16Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT16_ARRAY */
1500
    { JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT16_ARRAY */
1501
    { JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT32_ARRAY */
1502
    { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT32_ARRAY */
1503
    { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark },   /* JS_CLASS_BIG_INT64_ARRAY */
1504
    { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark },  /* JS_CLASS_BIG_UINT64_ARRAY */
1505
    { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT32_ARRAY */
1506
    { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT64_ARRAY */
1507
    { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark },        /* JS_CLASS_DATAVIEW */
1508
    { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark },      /* JS_CLASS_BIG_INT */
1509
#ifdef CONFIG_BIGNUM
1510
    { JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark },    /* JS_CLASS_BIG_FLOAT */
1511
    { JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL },      /* JS_CLASS_FLOAT_ENV */
1512
    { JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark },    /* JS_CLASS_BIG_DECIMAL */
1513
    { JS_ATOM_OperatorSet, js_operator_set_finalizer, js_operator_set_mark },    /* JS_CLASS_OPERATOR_SET */
1514
#endif
1515
    { JS_ATOM_Map, js_map_finalizer, js_map_mark },             /* JS_CLASS_MAP */
1516
    { JS_ATOM_Set, js_map_finalizer, js_map_mark },             /* JS_CLASS_SET */
1517
    { JS_ATOM_WeakMap, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKMAP */
1518
    { JS_ATOM_WeakSet, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKSET */
1519
    { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */
1520
    { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */
1521
    { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */
1522
    { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */
1523
    { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */
1524
    { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */
1525
};
1526
1527
static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab,
1528
                            int start, int count)
1529
117
{
1530
117
    JSClassDef cm_s, *cm = &cm_s;
1531
117
    int i, class_id;
1532
1533
2.34k
    for(i = 0; i < count; i++) {
1534
2.22k
        class_id = i + start;
1535
2.22k
        memset(cm, 0, sizeof(*cm));
1536
2.22k
        cm->finalizer = tab[i].finalizer;
1537
2.22k
        cm->gc_mark = tab[i].gc_mark;
1538
2.22k
        if (JS_NewClass1(rt, class_id, cm, tab[i].class_name) < 0)
1539
0
            return -1;
1540
2.22k
    }
1541
117
    return 0;
1542
117
}
1543
1544
static JSValue JS_ThrowUnsupportedOperation(JSContext *ctx)
1545
0
{
1546
0
    return JS_ThrowTypeError(ctx, "unsupported operation");
1547
0
}
1548
1549
static JSValue invalid_to_string(JSContext *ctx, JSValueConst val)
1550
0
{
1551
0
    return JS_ThrowUnsupportedOperation(ctx);
1552
0
}
1553
1554
static JSValue invalid_from_string(JSContext *ctx, const char *buf,
1555
                                   int radix, int flags, slimb_t *pexponent)
1556
0
{
1557
0
    return JS_NAN;
1558
0
}
1559
1560
static int invalid_unary_arith(JSContext *ctx,
1561
                               JSValue *pres, OPCodeEnum op, JSValue op1)
1562
0
{
1563
0
    JS_FreeValue(ctx, op1);
1564
0
    JS_ThrowUnsupportedOperation(ctx);
1565
0
    return -1;
1566
0
}
1567
1568
static int invalid_binary_arith(JSContext *ctx, OPCodeEnum op,
1569
                                JSValue *pres, JSValue op1, JSValue op2)
1570
0
{
1571
0
    JS_FreeValue(ctx, op1);
1572
0
    JS_FreeValue(ctx, op2);
1573
0
    JS_ThrowUnsupportedOperation(ctx);
1574
0
    return -1;
1575
0
}
1576
1577
static JSValue invalid_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
1578
                                            int64_t exponent)
1579
0
{
1580
0
    return JS_ThrowUnsupportedOperation(ctx);
1581
0
}
1582
1583
static int invalid_mul_pow10(JSContext *ctx, JSValue *sp)
1584
0
{
1585
0
    JS_ThrowUnsupportedOperation(ctx);
1586
0
    return -1;
1587
0
}
1588
1589
static void set_dummy_numeric_ops(JSNumericOperations *ops)
1590
117
{
1591
117
    ops->to_string = invalid_to_string;
1592
117
    ops->from_string = invalid_from_string;
1593
117
    ops->unary_arith = invalid_unary_arith;
1594
117
    ops->binary_arith = invalid_binary_arith;
1595
117
    ops->mul_pow10_to_float64 = invalid_mul_pow10_to_float64;
1596
117
    ops->mul_pow10 = invalid_mul_pow10;
1597
117
}
1598
1599
#if !defined(CONFIG_STACK_CHECK)
1600
/* no stack limitation */
1601
static inline uintptr_t js_get_stack_pointer(void)
1602
{
1603
    return 0;
1604
}
1605
1606
static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
1607
{
1608
    return FALSE;
1609
}
1610
#else
1611
/* Note: OS and CPU dependent */
1612
static inline uintptr_t js_get_stack_pointer(void)
1613
22.3M
{
1614
22.3M
    return (uintptr_t)__builtin_frame_address(0);
1615
22.3M
}
1616
1617
static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
1618
22.3M
{
1619
22.3M
    uintptr_t sp;
1620
22.3M
    sp = js_get_stack_pointer() - alloca_size;
1621
22.3M
    return unlikely(sp < rt->stack_limit);
1622
22.3M
}
1623
#endif
1624
1625
JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
1626
39
{
1627
39
    JSRuntime *rt;
1628
39
    JSMallocState ms;
1629
1630
39
    memset(&ms, 0, sizeof(ms));
1631
39
    ms.opaque = opaque;
1632
39
    ms.malloc_limit = -1;
1633
1634
39
    rt = mf->js_malloc(&ms, sizeof(JSRuntime));
1635
39
    if (!rt)
1636
0
        return NULL;
1637
39
    memset(rt, 0, sizeof(*rt));
1638
39
    rt->mf = *mf;
1639
39
    if (!rt->mf.js_malloc_usable_size) {
1640
        /* use dummy function if none provided */
1641
0
        rt->mf.js_malloc_usable_size = js_malloc_usable_size_unknown;
1642
0
    }
1643
39
    rt->malloc_state = ms;
1644
39
    rt->malloc_gc_threshold = 256 * 1024;
1645
1646
39
    bf_context_init(&rt->bf_ctx, js_bf_realloc, rt);
1647
39
    set_dummy_numeric_ops(&rt->bigint_ops);
1648
39
#ifdef CONFIG_BIGNUM
1649
39
    set_dummy_numeric_ops(&rt->bigfloat_ops);
1650
39
    set_dummy_numeric_ops(&rt->bigdecimal_ops);
1651
39
#endif
1652
1653
39
    init_list_head(&rt->context_list);
1654
39
    init_list_head(&rt->gc_obj_list);
1655
39
    init_list_head(&rt->gc_zero_ref_count_list);
1656
39
    rt->gc_phase = JS_GC_PHASE_NONE;
1657
1658
#ifdef DUMP_LEAKS
1659
    init_list_head(&rt->string_list);
1660
#endif
1661
39
    init_list_head(&rt->job_list);
1662
1663
39
    if (JS_InitAtoms(rt))
1664
0
        goto fail;
1665
1666
    /* create the object, array and function classes */
1667
39
    if (init_class_range(rt, js_std_class_def, JS_CLASS_OBJECT,
1668
39
                         countof(js_std_class_def)) < 0)
1669
0
        goto fail;
1670
39
    rt->class_array[JS_CLASS_ARGUMENTS].exotic = &js_arguments_exotic_methods;
1671
39
    rt->class_array[JS_CLASS_STRING].exotic = &js_string_exotic_methods;
1672
39
    rt->class_array[JS_CLASS_MODULE_NS].exotic = &js_module_ns_exotic_methods;
1673
1674
39
    rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function;
1675
39
    rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_c_function_data_call;
1676
39
    rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function;
1677
39
    rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_generator_function_call;
1678
39
    if (init_shape_hash(rt))
1679
0
        goto fail;
1680
1681
39
    rt->stack_size = JS_DEFAULT_STACK_SIZE;
1682
39
    JS_UpdateStackTop(rt);
1683
1684
39
    rt->current_exception = JS_NULL;
1685
1686
39
    return rt;
1687
0
 fail:
1688
0
    JS_FreeRuntime(rt);
1689
0
    return NULL;
1690
39
}
1691
1692
void *JS_GetRuntimeOpaque(JSRuntime *rt)
1693
93
{
1694
93
    return rt->user_opaque;
1695
93
}
1696
1697
void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque)
1698
78
{
1699
78
    rt->user_opaque = opaque;
1700
78
}
1701
1702
/* default memory allocation functions with memory limitation */
1703
static size_t js_def_malloc_usable_size(const void *ptr)
1704
185k
{
1705
#if defined(__APPLE__)
1706
    return malloc_size(ptr);
1707
#elif defined(_WIN32)
1708
    return _msize((void *)ptr);
1709
#elif defined(EMSCRIPTEN)
1710
    return 0;
1711
#elif defined(__linux__)
1712
    return malloc_usable_size((void *)ptr);
1713
#else
1714
    /* change this to `return 0;` if compilation fails */
1715
    return malloc_usable_size((void *)ptr);
1716
#endif
1717
185k
}
1718
1719
static void *js_def_malloc(JSMallocState *s, size_t size)
1720
75.0k
{
1721
75.0k
    void *ptr;
1722
1723
    /* Do not allocate zero bytes: behavior is platform dependent */
1724
75.0k
    assert(size != 0);
1725
1726
75.0k
    if (unlikely(s->malloc_size + size > s->malloc_limit))
1727
0
        return NULL;
1728
1729
75.0k
    ptr = malloc(size);
1730
75.0k
    if (!ptr)
1731
0
        return NULL;
1732
1733
75.0k
    s->malloc_count++;
1734
75.0k
    s->malloc_size += js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
1735
75.0k
    return ptr;
1736
75.0k
}
1737
1738
static void js_def_free(JSMallocState *s, void *ptr)
1739
75.7k
{
1740
75.7k
    if (!ptr)
1741
1.45k
        return;
1742
1743
74.2k
    s->malloc_count--;
1744
74.2k
    s->malloc_size -= js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
1745
74.2k
    free(ptr);
1746
74.2k
}
1747
1748
static void *js_def_realloc(JSMallocState *s, void *ptr, size_t size)
1749
18.5k
{
1750
18.5k
    size_t old_size;
1751
1752
18.5k
    if (!ptr) {
1753
1.50k
        if (size == 0)
1754
19
            return NULL;
1755
1.48k
        return js_def_malloc(s, size);
1756
1.50k
    }
1757
17.0k
    old_size = js_def_malloc_usable_size(ptr);
1758
17.0k
    if (size == 0) {
1759
798
        s->malloc_count--;
1760
798
        s->malloc_size -= old_size + MALLOC_OVERHEAD;
1761
798
        free(ptr);
1762
798
        return NULL;
1763
798
    }
1764
16.2k
    if (s->malloc_size + size - old_size > s->malloc_limit)
1765
0
        return NULL;
1766
1767
16.2k
    ptr = realloc(ptr, size);
1768
16.2k
    if (!ptr)
1769
0
        return NULL;
1770
1771
16.2k
    s->malloc_size += js_def_malloc_usable_size(ptr) - old_size;
1772
16.2k
    return ptr;
1773
16.2k
}
1774
1775
static const JSMallocFunctions def_malloc_funcs = {
1776
    js_def_malloc,
1777
    js_def_free,
1778
    js_def_realloc,
1779
    js_def_malloc_usable_size,
1780
};
1781
1782
JSRuntime *JS_NewRuntime(void)
1783
39
{
1784
39
    return JS_NewRuntime2(&def_malloc_funcs, NULL);
1785
39
}
1786
1787
void JS_SetMemoryLimit(JSRuntime *rt, size_t limit)
1788
39
{
1789
39
    rt->malloc_state.malloc_limit = limit;
1790
39
}
1791
1792
/* use -1 to disable automatic GC */
1793
void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold)
1794
0
{
1795
0
    rt->malloc_gc_threshold = gc_threshold;
1796
0
}
1797
1798
#define malloc(s) malloc_is_forbidden(s)
1799
#define free(p) free_is_forbidden(p)
1800
#define realloc(p,s) realloc_is_forbidden(p,s)
1801
1802
void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque)
1803
39
{
1804
39
    rt->interrupt_handler = cb;
1805
39
    rt->interrupt_opaque = opaque;
1806
39
}
1807
1808
void JS_SetCanBlock(JSRuntime *rt, BOOL can_block)
1809
0
{
1810
0
    rt->can_block = can_block;
1811
0
}
1812
1813
void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
1814
                                      const JSSharedArrayBufferFunctions *sf)
1815
39
{
1816
39
    rt->sab_funcs = *sf;
1817
39
}
1818
1819
/* return 0 if OK, < 0 if exception */
1820
int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func,
1821
                  int argc, JSValueConst *argv)
1822
0
{
1823
0
    JSRuntime *rt = ctx->rt;
1824
0
    JSJobEntry *e;
1825
0
    int i;
1826
1827
0
    e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue));
1828
0
    if (!e)
1829
0
        return -1;
1830
0
    e->ctx = ctx;
1831
0
    e->job_func = job_func;
1832
0
    e->argc = argc;
1833
0
    for(i = 0; i < argc; i++) {
1834
0
        e->argv[i] = JS_DupValue(ctx, argv[i]);
1835
0
    }
1836
0
    list_add_tail(&e->link, &rt->job_list);
1837
0
    return 0;
1838
0
}
1839
1840
BOOL JS_IsJobPending(JSRuntime *rt)
1841
0
{
1842
0
    return !list_empty(&rt->job_list);
1843
0
}
1844
1845
/* return < 0 if exception, 0 if no job pending, 1 if a job was
1846
   executed successfully. the context of the job is stored in '*pctx' */
1847
int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx)
1848
15
{
1849
15
    JSContext *ctx;
1850
15
    JSJobEntry *e;
1851
15
    JSValue res;
1852
15
    int i, ret;
1853
1854
15
    if (list_empty(&rt->job_list)) {
1855
15
        *pctx = NULL;
1856
15
        return 0;
1857
15
    }
1858
1859
    /* get the first pending job and execute it */
1860
0
    e = list_entry(rt->job_list.next, JSJobEntry, link);
1861
0
    list_del(&e->link);
1862
0
    ctx = e->ctx;
1863
0
    res = e->job_func(e->ctx, e->argc, (JSValueConst *)e->argv);
1864
0
    for(i = 0; i < e->argc; i++)
1865
0
        JS_FreeValue(ctx, e->argv[i]);
1866
0
    if (JS_IsException(res))
1867
0
        ret = -1;
1868
0
    else
1869
0
        ret = 1;
1870
0
    JS_FreeValue(ctx, res);
1871
0
    js_free(ctx, e);
1872
0
    *pctx = ctx;
1873
0
    return ret;
1874
15
}
1875
1876
static inline uint32_t atom_get_free(const JSAtomStruct *p)
1877
26.7k
{
1878
26.7k
    return (uintptr_t)p >> 1;
1879
26.7k
}
1880
1881
static inline BOOL atom_is_free(const JSAtomStruct *p)
1882
28.8k
{
1883
28.8k
    return (uintptr_t)p & 1;
1884
28.8k
}
1885
1886
static inline JSAtomStruct *atom_set_free(uint32_t v)
1887
45.5k
{
1888
45.5k
    return (JSAtomStruct *)(((uintptr_t)v << 1) | 1);
1889
45.5k
}
1890
1891
/* Note: the string contents are uninitialized */
1892
static JSString *js_alloc_string_rt(JSRuntime *rt, int max_len, int is_wide_char)
1893
26.9k
{
1894
26.9k
    JSString *str;
1895
26.9k
    str = js_malloc_rt(rt, sizeof(JSString) + (max_len << is_wide_char) + 1 - is_wide_char);
1896
26.9k
    if (unlikely(!str))
1897
0
        return NULL;
1898
26.9k
    str->header.ref_count = 1;
1899
26.9k
    str->is_wide_char = is_wide_char;
1900
26.9k
    str->len = max_len;
1901
26.9k
    str->atom_type = 0;
1902
26.9k
    str->hash = 0;          /* optional but costless */
1903
26.9k
    str->hash_next = 0;     /* optional */
1904
#ifdef DUMP_LEAKS
1905
    list_add_tail(&str->link, &rt->string_list);
1906
#endif
1907
26.9k
    return str;
1908
26.9k
}
1909
1910
static JSString *js_alloc_string(JSContext *ctx, int max_len, int is_wide_char)
1911
18.1k
{
1912
18.1k
    JSString *p;
1913
18.1k
    p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char);
1914
18.1k
    if (unlikely(!p)) {
1915
0
        JS_ThrowOutOfMemory(ctx);
1916
0
        return NULL;
1917
0
    }
1918
18.1k
    return p;
1919
18.1k
}
1920
1921
/* same as JS_FreeValueRT() but faster */
1922
static inline void js_free_string(JSRuntime *rt, JSString *str)
1923
78
{
1924
78
    if (--str->header.ref_count <= 0) {
1925
0
        if (str->atom_type) {
1926
0
            JS_FreeAtomStruct(rt, str);
1927
0
        } else {
1928
#ifdef DUMP_LEAKS
1929
            list_del(&str->link);
1930
#endif
1931
0
            js_free_rt(rt, str);
1932
0
        }
1933
0
    }
1934
78
}
1935
1936
void JS_SetRuntimeInfo(JSRuntime *rt, const char *s)
1937
0
{
1938
0
    if (rt)
1939
0
        rt->rt_info = s;
1940
0
}
1941
1942
void JS_FreeRuntime(JSRuntime *rt)
1943
39
{
1944
39
    struct list_head *el, *el1;
1945
39
    int i;
1946
1947
39
    JS_FreeValueRT(rt, rt->current_exception);
1948
1949
39
    list_for_each_safe(el, el1, &rt->job_list) {
1950
0
        JSJobEntry *e = list_entry(el, JSJobEntry, link);
1951
0
        for(i = 0; i < e->argc; i++)
1952
0
            JS_FreeValueRT(rt, e->argv[i]);
1953
0
        js_free_rt(rt, e);
1954
0
    }
1955
39
    init_list_head(&rt->job_list);
1956
1957
39
    JS_RunGC(rt);
1958
1959
#ifdef DUMP_LEAKS
1960
    /* leaking objects */
1961
    {
1962
        BOOL header_done;
1963
        JSGCObjectHeader *p;
1964
        int count;
1965
1966
        /* remove the internal refcounts to display only the object
1967
           referenced externally */
1968
        list_for_each(el, &rt->gc_obj_list) {
1969
            p = list_entry(el, JSGCObjectHeader, link);
1970
            p->mark = 0;
1971
        }
1972
        gc_decref(rt);
1973
1974
        header_done = FALSE;
1975
        list_for_each(el, &rt->gc_obj_list) {
1976
            p = list_entry(el, JSGCObjectHeader, link);
1977
            if (p->ref_count != 0) {
1978
                if (!header_done) {
1979
                    printf("Object leaks:\n");
1980
                    JS_DumpObjectHeader(rt);
1981
                    header_done = TRUE;
1982
                }
1983
                JS_DumpGCObject(rt, p);
1984
            }
1985
        }
1986
1987
        count = 0;
1988
        list_for_each(el, &rt->gc_obj_list) {
1989
            p = list_entry(el, JSGCObjectHeader, link);
1990
            if (p->ref_count == 0) {
1991
                count++;
1992
            }
1993
        }
1994
        if (count != 0)
1995
            printf("Secondary object leaks: %d\n", count);
1996
    }
1997
#endif
1998
39
    assert(list_empty(&rt->gc_obj_list));
1999
2000
    /* free the classes */
2001
3.43k
    for(i = 0; i < rt->class_count; i++) {
2002
3.39k
        JSClass *cl = &rt->class_array[i];
2003
3.39k
        if (cl->class_id != 0) {
2004
2.30k
            JS_FreeAtomRT(rt, cl->class_name);
2005
2.30k
        }
2006
3.39k
    }
2007
39
    js_free_rt(rt, rt->class_array);
2008
2009
39
    bf_context_end(&rt->bf_ctx);
2010
2011
#ifdef DUMP_LEAKS
2012
    /* only the atoms defined in JS_InitAtoms() should be left */
2013
    {
2014
        BOOL header_done = FALSE;
2015
2016
        for(i = 0; i < rt->atom_size; i++) {
2017
            JSAtomStruct *p = rt->atom_array[i];
2018
            if (!atom_is_free(p) /* && p->str*/) {
2019
                if (i >= JS_ATOM_END || p->header.ref_count != 1) {
2020
                    if (!header_done) {
2021
                        header_done = TRUE;
2022
                        if (rt->rt_info) {
2023
                            printf("%s:1: atom leakage:", rt->rt_info);
2024
                        } else {
2025
                            printf("Atom leaks:\n"
2026
                                   "    %6s %6s %s\n",
2027
                                   "ID", "REFCNT", "NAME");
2028
                        }
2029
                    }
2030
                    if (rt->rt_info) {
2031
                        printf(" ");
2032
                    } else {
2033
                        printf("    %6u %6u ", i, p->header.ref_count);
2034
                    }
2035
                    switch (p->atom_type) {
2036
                    case JS_ATOM_TYPE_STRING:
2037
                        JS_DumpString(rt, p);
2038
                        break;
2039
                    case JS_ATOM_TYPE_GLOBAL_SYMBOL:
2040
                        printf("Symbol.for(");
2041
                        JS_DumpString(rt, p);
2042
                        printf(")");
2043
                        break;
2044
                    case JS_ATOM_TYPE_SYMBOL:
2045
                        if (p->hash == JS_ATOM_HASH_SYMBOL) {
2046
                            printf("Symbol(");
2047
                            JS_DumpString(rt, p);
2048
                            printf(")");
2049
                        } else {
2050
                            printf("Private(");
2051
                            JS_DumpString(rt, p);
2052
                            printf(")");
2053
                        }
2054
                        break;
2055
                    }
2056
                    if (rt->rt_info) {
2057
                        printf(":%u", p->header.ref_count);
2058
                    } else {
2059
                        printf("\n");
2060
                    }
2061
                }
2062
            }
2063
        }
2064
        if (rt->rt_info && header_done)
2065
            printf("\n");
2066
    }
2067
#endif
2068
2069
    /* free the atoms */
2070
27.7k
    for(i = 0; i < rt->atom_size; i++) {
2071
27.7k
        JSAtomStruct *p = rt->atom_array[i];
2072
27.7k
        if (!atom_is_free(p)) {
2073
#ifdef DUMP_LEAKS
2074
            list_del(&p->link);
2075
#endif
2076
8.85k
            js_free_rt(rt, p);
2077
8.85k
        }
2078
27.7k
    }
2079
39
    js_free_rt(rt, rt->atom_array);
2080
39
    js_free_rt(rt, rt->atom_hash);
2081
39
    js_free_rt(rt, rt->shape_hash);
2082
#ifdef DUMP_LEAKS
2083
    if (!list_empty(&rt->string_list)) {
2084
        if (rt->rt_info) {
2085
            printf("%s:1: string leakage:", rt->rt_info);
2086
        } else {
2087
            printf("String leaks:\n"
2088
                   "    %6s %s\n",
2089
                   "REFCNT", "VALUE");
2090
        }
2091
        list_for_each_safe(el, el1, &rt->string_list) {
2092
            JSString *str = list_entry(el, JSString, link);
2093
            if (rt->rt_info) {
2094
                printf(" ");
2095
            } else {
2096
                printf("    %6u ", str->header.ref_count);
2097
            }
2098
            JS_DumpString(rt, str);
2099
            if (rt->rt_info) {
2100
                printf(":%u", str->header.ref_count);
2101
            } else {
2102
                printf("\n");
2103
            }
2104
            list_del(&str->link);
2105
            js_free_rt(rt, str);
2106
        }
2107
        if (rt->rt_info)
2108
            printf("\n");
2109
    }
2110
    {
2111
        JSMallocState *s = &rt->malloc_state;
2112
        if (s->malloc_count > 1) {
2113
            if (rt->rt_info)
2114
                printf("%s:1: ", rt->rt_info);
2115
            printf("Memory leak: %"PRIu64" bytes lost in %"PRIu64" block%s\n",
2116
                   (uint64_t)(s->malloc_size - sizeof(JSRuntime)),
2117
                   (uint64_t)(s->malloc_count - 1), &"s"[s->malloc_count == 2]);
2118
        }
2119
    }
2120
#endif
2121
2122
39
    {
2123
39
        JSMallocState ms = rt->malloc_state;
2124
39
        rt->mf.js_free(&ms, rt);
2125
39
    }
2126
39
}
2127
2128
JSContext *JS_NewContextRaw(JSRuntime *rt)
2129
39
{
2130
39
    JSContext *ctx;
2131
39
    int i;
2132
2133
39
    ctx = js_mallocz_rt(rt, sizeof(JSContext));
2134
39
    if (!ctx)
2135
0
        return NULL;
2136
39
    ctx->header.ref_count = 1;
2137
39
    add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT);
2138
2139
39
    ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) *
2140
39
                                    rt->class_count);
2141
39
    if (!ctx->class_proto) {
2142
0
        js_free_rt(rt, ctx);
2143
0
        return NULL;
2144
0
    }
2145
39
    ctx->rt = rt;
2146
39
    list_add_tail(&ctx->link, &rt->context_list);
2147
39
    ctx->bf_ctx = &rt->bf_ctx;
2148
39
#ifdef CONFIG_BIGNUM
2149
39
    ctx->fp_env.prec = 113;
2150
39
    ctx->fp_env.flags = bf_set_exp_bits(15) | BF_RNDN | BF_FLAG_SUBNORMAL;
2151
39
#endif
2152
2.30k
    for(i = 0; i < rt->class_count; i++)
2153
2.26k
        ctx->class_proto[i] = JS_NULL;
2154
39
    ctx->array_ctor = JS_NULL;
2155
39
    ctx->regexp_ctor = JS_NULL;
2156
39
    ctx->promise_ctor = JS_NULL;
2157
39
    init_list_head(&ctx->loaded_modules);
2158
2159
39
    JS_AddIntrinsicBasicObjects(ctx);
2160
39
    return ctx;
2161
39
}
2162
2163
JSContext *JS_NewContext(JSRuntime *rt)
2164
39
{
2165
39
    JSContext *ctx;
2166
2167
39
    ctx = JS_NewContextRaw(rt);
2168
39
    if (!ctx)
2169
0
        return NULL;
2170
2171
39
    JS_AddIntrinsicBaseObjects(ctx);
2172
39
    JS_AddIntrinsicDate(ctx);
2173
39
    JS_AddIntrinsicEval(ctx);
2174
39
    JS_AddIntrinsicStringNormalize(ctx);
2175
39
    JS_AddIntrinsicRegExp(ctx);
2176
39
    JS_AddIntrinsicJSON(ctx);
2177
39
    JS_AddIntrinsicProxy(ctx);
2178
39
    JS_AddIntrinsicMapSet(ctx);
2179
39
    JS_AddIntrinsicTypedArrays(ctx);
2180
39
    JS_AddIntrinsicPromise(ctx);
2181
39
    JS_AddIntrinsicBigInt(ctx);
2182
39
    return ctx;
2183
39
}
2184
2185
void *JS_GetContextOpaque(JSContext *ctx)
2186
0
{
2187
0
    return ctx->user_opaque;
2188
0
}
2189
2190
void JS_SetContextOpaque(JSContext *ctx, void *opaque)
2191
0
{
2192
0
    ctx->user_opaque = opaque;
2193
0
}
2194
2195
/* set the new value and free the old value after (freeing the value
2196
   can reallocate the object data) */
2197
static inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val)
2198
1.89M
{
2199
1.89M
    JSValue old_val;
2200
1.89M
    old_val = *pval;
2201
1.89M
    *pval = new_val;
2202
1.89M
    JS_FreeValue(ctx, old_val);
2203
1.89M
}
2204
2205
void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj)
2206
78
{
2207
78
    JSRuntime *rt = ctx->rt;
2208
78
    assert(class_id < rt->class_count);
2209
78
    set_value(ctx, &ctx->class_proto[class_id], obj);
2210
78
}
2211
2212
JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id)
2213
0
{
2214
0
    JSRuntime *rt = ctx->rt;
2215
0
    assert(class_id < rt->class_count);
2216
0
    return JS_DupValue(ctx, ctx->class_proto[class_id]);
2217
0
}
2218
2219
typedef enum JSFreeModuleEnum {
2220
    JS_FREE_MODULE_ALL,
2221
    JS_FREE_MODULE_NOT_RESOLVED,
2222
} JSFreeModuleEnum;
2223
2224
/* XXX: would be more efficient with separate module lists */
2225
static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag)
2226
39
{
2227
39
    struct list_head *el, *el1;
2228
117
    list_for_each_safe(el, el1, &ctx->loaded_modules) {
2229
117
        JSModuleDef *m = list_entry(el, JSModuleDef, link);
2230
117
        if (flag == JS_FREE_MODULE_ALL ||
2231
117
            (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) {
2232
117
            js_free_module_def(ctx, m);
2233
117
        }
2234
117
    }
2235
39
}
2236
2237
JSContext *JS_DupContext(JSContext *ctx)
2238
24.0k
{
2239
24.0k
    ctx->header.ref_count++;
2240
24.0k
    return ctx;
2241
24.0k
}
2242
2243
/* used by the GC */
2244
static void JS_MarkContext(JSRuntime *rt, JSContext *ctx,
2245
                           JS_MarkFunc *mark_func)
2246
146
{
2247
146
    int i;
2248
146
    struct list_head *el;
2249
2250
    /* modules are not seen by the GC, so we directly mark the objects
2251
       referenced by each module */
2252
442
    list_for_each(el, &ctx->loaded_modules) {
2253
442
        JSModuleDef *m = list_entry(el, JSModuleDef, link);
2254
442
        js_mark_module_def(rt, m, mark_func);
2255
442
    }
2256
2257
146
    JS_MarkValue(rt, ctx->global_obj, mark_func);
2258
146
    JS_MarkValue(rt, ctx->global_var_obj, mark_func);
2259
2260
146
    JS_MarkValue(rt, ctx->throw_type_error, mark_func);
2261
146
    JS_MarkValue(rt, ctx->eval_obj, mark_func);
2262
2263
146
    JS_MarkValue(rt, ctx->array_proto_values, mark_func);
2264
1.31k
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
2265
1.16k
        JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);
2266
1.16k
    }
2267
12.8k
    for(i = 0; i < rt->class_count; i++) {
2268
12.7k
        JS_MarkValue(rt, ctx->class_proto[i], mark_func);
2269
12.7k
    }
2270
146
    JS_MarkValue(rt, ctx->iterator_proto, mark_func);
2271
146
    JS_MarkValue(rt, ctx->async_iterator_proto, mark_func);
2272
146
    JS_MarkValue(rt, ctx->promise_ctor, mark_func);
2273
146
    JS_MarkValue(rt, ctx->array_ctor, mark_func);
2274
146
    JS_MarkValue(rt, ctx->regexp_ctor, mark_func);
2275
146
    JS_MarkValue(rt, ctx->function_ctor, mark_func);
2276
146
    JS_MarkValue(rt, ctx->function_proto, mark_func);
2277
2278
146
    if (ctx->array_shape)
2279
146
        mark_func(rt, &ctx->array_shape->header);
2280
146
}
2281
2282
void JS_FreeContext(JSContext *ctx)
2283
24.0k
{
2284
24.0k
    JSRuntime *rt = ctx->rt;
2285
24.0k
    int i;
2286
2287
24.0k
    if (--ctx->header.ref_count > 0)
2288
24.0k
        return;
2289
39
    assert(ctx->header.ref_count == 0);
2290
2291
#ifdef DUMP_ATOMS
2292
    JS_DumpAtoms(ctx->rt);
2293
#endif
2294
#ifdef DUMP_SHAPES
2295
    JS_DumpShapes(ctx->rt);
2296
#endif
2297
#ifdef DUMP_OBJECTS
2298
    {
2299
        struct list_head *el;
2300
        JSGCObjectHeader *p;
2301
        printf("JSObjects: {\n");
2302
        JS_DumpObjectHeader(ctx->rt);
2303
        list_for_each(el, &rt->gc_obj_list) {
2304
            p = list_entry(el, JSGCObjectHeader, link);
2305
            JS_DumpGCObject(rt, p);
2306
        }
2307
        printf("}\n");
2308
    }
2309
#endif
2310
#ifdef DUMP_MEM
2311
    {
2312
        JSMemoryUsage stats;
2313
        JS_ComputeMemoryUsage(rt, &stats);
2314
        JS_DumpMemoryUsage(stdout, &stats, rt);
2315
    }
2316
#endif
2317
2318
39
    js_free_modules(ctx, JS_FREE_MODULE_ALL);
2319
2320
39
    JS_FreeValue(ctx, ctx->global_obj);
2321
39
    JS_FreeValue(ctx, ctx->global_var_obj);
2322
2323
39
    JS_FreeValue(ctx, ctx->throw_type_error);
2324
39
    JS_FreeValue(ctx, ctx->eval_obj);
2325
2326
39
    JS_FreeValue(ctx, ctx->array_proto_values);
2327
351
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
2328
312
        JS_FreeValue(ctx, ctx->native_error_proto[i]);
2329
312
    }
2330
3.43k
    for(i = 0; i < rt->class_count; i++) {
2331
3.39k
        JS_FreeValue(ctx, ctx->class_proto[i]);
2332
3.39k
    }
2333
39
    js_free_rt(rt, ctx->class_proto);
2334
39
    JS_FreeValue(ctx, ctx->iterator_proto);
2335
39
    JS_FreeValue(ctx, ctx->async_iterator_proto);
2336
39
    JS_FreeValue(ctx, ctx->promise_ctor);
2337
39
    JS_FreeValue(ctx, ctx->array_ctor);
2338
39
    JS_FreeValue(ctx, ctx->regexp_ctor);
2339
39
    JS_FreeValue(ctx, ctx->function_ctor);
2340
39
    JS_FreeValue(ctx, ctx->function_proto);
2341
2342
39
    js_free_shape_null(ctx->rt, ctx->array_shape);
2343
2344
39
    list_del(&ctx->link);
2345
39
    remove_gc_object(&ctx->header);
2346
39
    js_free_rt(ctx->rt, ctx);
2347
39
}
2348
2349
JSRuntime *JS_GetRuntime(JSContext *ctx)
2350
186
{
2351
186
    return ctx->rt;
2352
186
}
2353
2354
static void update_stack_limit(JSRuntime *rt)
2355
78
{
2356
78
    if (rt->stack_size == 0) {
2357
0
        rt->stack_limit = 0; /* no limit */
2358
78
    } else {
2359
78
        rt->stack_limit = rt->stack_top - rt->stack_size;
2360
78
    }
2361
78
}
2362
2363
void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size)
2364
39
{
2365
39
    rt->stack_size = stack_size;
2366
39
    update_stack_limit(rt);
2367
39
}
2368
2369
void JS_UpdateStackTop(JSRuntime *rt)
2370
39
{
2371
39
    rt->stack_top = js_get_stack_pointer();
2372
39
    update_stack_limit(rt);
2373
39
}
2374
2375
static inline BOOL is_strict_mode(JSContext *ctx)
2376
0
{
2377
0
    JSStackFrame *sf = ctx->rt->current_stack_frame;
2378
0
    return (sf && (sf->js_mode & JS_MODE_STRICT));
2379
0
}
2380
2381
#ifdef CONFIG_BIGNUM
2382
static inline BOOL is_math_mode(JSContext *ctx)
2383
0
{
2384
0
    JSStackFrame *sf = ctx->rt->current_stack_frame;
2385
0
    return (sf && (sf->js_mode & JS_MODE_MATH));
2386
0
}
2387
#else
2388
static inline BOOL is_math_mode(JSContext *ctx)
2389
{
2390
    return FALSE;
2391
}
2392
#endif
2393
2394
/* JSAtom support */
2395
2396
17.6M
#define JS_ATOM_TAG_INT (1U << 31)
2397
0
#define JS_ATOM_MAX_INT (JS_ATOM_TAG_INT - 1)
2398
156
#define JS_ATOM_MAX     ((1U << 30) - 1)
2399
2400
/* return the max count from the hash size */
2401
78
#define JS_ATOM_COUNT_RESIZE(n) ((n) * 2)
2402
2403
static inline BOOL __JS_AtomIsConst(JSAtom v)
2404
11.3M
{
2405
#if defined(DUMP_LEAKS) && DUMP_LEAKS > 1
2406
        return (int32_t)v <= 0;
2407
#else
2408
11.3M
        return (int32_t)v < JS_ATOM_END;
2409
11.3M
#endif
2410
11.3M
}
2411
2412
static inline BOOL __JS_AtomIsTaggedInt(JSAtom v)
2413
7.05M
{
2414
7.05M
    return (v & JS_ATOM_TAG_INT) != 0;
2415
7.05M
}
2416
2417
static inline JSAtom __JS_AtomFromUInt32(uint32_t v)
2418
6.44M
{
2419
6.44M
    return v | JS_ATOM_TAG_INT;
2420
6.44M
}
2421
2422
static inline uint32_t __JS_AtomToUInt32(JSAtom atom)
2423
4.10M
{
2424
4.10M
    return atom & ~JS_ATOM_TAG_INT;
2425
4.10M
}
2426
2427
static inline int is_num(int c)
2428
13.4k
{
2429
13.4k
    return c >= '0' && c <= '9';
2430
13.4k
}
2431
2432
/* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */
2433
static inline BOOL is_num_string(uint32_t *pval, const JSString *p)
2434
18.1k
{
2435
18.1k
    uint32_t n;
2436
18.1k
    uint64_t n64;
2437
18.1k
    int c, i, len;
2438
2439
18.1k
    len = p->len;
2440
18.1k
    if (len == 0 || len > 10)
2441
4.65k
        return FALSE;
2442
13.4k
    c = string_get(p, 0);
2443
13.4k
    if (is_num(c)) {
2444
0
        if (c == '0') {
2445
0
            if (len != 1)
2446
0
                return FALSE;
2447
0
            n = 0;
2448
0
        } else {
2449
0
            n = c - '0';
2450
0
            for(i = 1; i < len; i++) {
2451
0
                c = string_get(p, i);
2452
0
                if (!is_num(c))
2453
0
                    return FALSE;
2454
0
                n64 = (uint64_t)n * 10 + (c - '0');
2455
0
                if ((n64 >> 32) != 0)
2456
0
                    return FALSE;
2457
0
                n = n64;
2458
0
            }
2459
0
        }
2460
0
        *pval = n;
2461
0
        return TRUE;
2462
13.4k
    } else {
2463
13.4k
        return FALSE;
2464
13.4k
    }
2465
13.4k
}
2466
2467
/* XXX: could use faster version ? */
2468
static inline uint32_t hash_string8(const uint8_t *str, size_t len, uint32_t h)
2469
65.1k
{
2470
65.1k
    size_t i;
2471
2472
16.3M
    for(i = 0; i < len; i++)
2473
16.2M
        h = h * 263 + str[i];
2474
65.1k
    return h;
2475
65.1k
}
2476
2477
static inline uint32_t hash_string16(const uint16_t *str,
2478
                                     size_t len, uint32_t h)
2479
0
{
2480
0
    size_t i;
2481
2482
0
    for(i = 0; i < len; i++)
2483
0
        h = h * 263 + str[i];
2484
0
    return h;
2485
0
}
2486
2487
static uint32_t hash_string(const JSString *str, uint32_t h)
2488
26.2k
{
2489
26.2k
    if (str->is_wide_char)
2490
0
        h = hash_string16(str->u.str16, str->len, h);
2491
26.2k
    else
2492
26.2k
        h = hash_string8(str->u.str8, str->len, h);
2493
26.2k
    return h;
2494
26.2k
}
2495
2496
static __maybe_unused void JS_DumpChar(JSRuntime *rt, int c, int sep)
2497
0
{
2498
0
    if (c == sep || c == '\\') {
2499
0
        putchar('\\');
2500
0
        putchar(c);
2501
0
    } else if (c >= ' ' && c <= 126) {
2502
0
        putchar(c);
2503
0
    } else if (c == '\n') {
2504
0
        putchar('\\');
2505
0
        putchar('n');
2506
0
    } else {
2507
0
        printf("\\u%04x", c);
2508
0
    }
2509
0
}
2510
2511
static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p)
2512
0
{
2513
0
    int i, sep;
2514
0
2515
0
    if (p == NULL) {
2516
0
        printf("<null>");
2517
0
        return;
2518
0
    }
2519
0
    printf("%d", p->header.ref_count);
2520
0
    sep = (p->header.ref_count == 1) ? '\"' : '\'';
2521
0
    putchar(sep);
2522
0
    for(i = 0; i < p->len; i++) {
2523
0
        JS_DumpChar(rt, string_get(p, i), sep);
2524
0
    }
2525
0
    putchar(sep);
2526
0
}
2527
2528
static __maybe_unused void JS_DumpAtoms(JSRuntime *rt)
2529
0
{
2530
0
    JSAtomStruct *p;
2531
0
    int h, i;
2532
0
    /* This only dumps hashed atoms, not JS_ATOM_TYPE_SYMBOL atoms */
2533
0
    printf("JSAtom count=%d size=%d hash_size=%d:\n",
2534
0
           rt->atom_count, rt->atom_size, rt->atom_hash_size);
2535
0
    printf("JSAtom hash table: {\n");
2536
0
    for(i = 0; i < rt->atom_hash_size; i++) {
2537
0
        h = rt->atom_hash[i];
2538
0
        if (h) {
2539
0
            printf("  %d:", i);
2540
0
            while (h) {
2541
0
                p = rt->atom_array[h];
2542
0
                printf(" ");
2543
0
                JS_DumpString(rt, p);
2544
0
                h = p->hash_next;
2545
0
            }
2546
0
            printf("\n");
2547
0
        }
2548
0
    }
2549
0
    printf("}\n");
2550
0
    printf("JSAtom table: {\n");
2551
0
    for(i = 0; i < rt->atom_size; i++) {
2552
0
        p = rt->atom_array[i];
2553
0
        if (!atom_is_free(p)) {
2554
0
            printf("  %d: { %d %08x ", i, p->atom_type, p->hash);
2555
0
            if (!(p->len == 0 && p->is_wide_char != 0))
2556
0
                JS_DumpString(rt, p);
2557
0
            printf(" %d }\n", p->hash_next);
2558
0
        }
2559
0
    }
2560
0
    printf("}\n");
2561
0
}
2562
2563
static int JS_ResizeAtomHash(JSRuntime *rt, int new_hash_size)
2564
78
{
2565
78
    JSAtomStruct *p;
2566
78
    uint32_t new_hash_mask, h, i, hash_next1, j, *new_hash;
2567
2568
78
    assert((new_hash_size & (new_hash_size - 1)) == 0); /* power of two */
2569
78
    new_hash_mask = new_hash_size - 1;
2570
78
    new_hash = js_mallocz_rt(rt, sizeof(rt->atom_hash[0]) * new_hash_size);
2571
78
    if (!new_hash)
2572
0
        return -1;
2573
10.0k
    for(i = 0; i < rt->atom_hash_size; i++) {
2574
9.98k
        h = rt->atom_hash[i];
2575
29.3k
        while (h != 0) {
2576
19.3k
            p = rt->atom_array[h];
2577
19.3k
            hash_next1 = p->hash_next;
2578
            /* add in new hash table */
2579
19.3k
            j = p->hash & new_hash_mask;
2580
19.3k
            p->hash_next = new_hash[j];
2581
19.3k
            new_hash[j] = h;
2582
19.3k
            h = hash_next1;
2583
19.3k
        }
2584
9.98k
    }
2585
78
    js_free_rt(rt, rt->atom_hash);
2586
78
    rt->atom_hash = new_hash;
2587
78
    rt->atom_hash_size = new_hash_size;
2588
78
    rt->atom_count_resize = JS_ATOM_COUNT_RESIZE(new_hash_size);
2589
    //    JS_DumpAtoms(rt);
2590
78
    return 0;
2591
78
}
2592
2593
static int JS_InitAtoms(JSRuntime *rt)
2594
39
{
2595
39
    int i, len, atom_type;
2596
39
    const char *p;
2597
2598
39
    rt->atom_hash_size = 0;
2599
39
    rt->atom_hash = NULL;
2600
39
    rt->atom_count = 0;
2601
39
    rt->atom_size = 0;
2602
39
    rt->atom_free_index = 0;
2603
39
    if (JS_ResizeAtomHash(rt, 256))     /* there are at least 195 predefined atoms */
2604
0
        return -1;
2605
2606
39
    p = js_atom_init;
2607
8.85k
    for(i = 1; i < JS_ATOM_END; i++) {
2608
8.81k
        if (i == JS_ATOM_Private_brand)
2609
39
            atom_type = JS_ATOM_TYPE_PRIVATE;
2610
8.77k
        else if (i >= JS_ATOM_Symbol_toPrimitive)
2611
546
            atom_type = JS_ATOM_TYPE_SYMBOL;
2612
8.22k
        else
2613
8.22k
            atom_type = JS_ATOM_TYPE_STRING;
2614
8.81k
        len = strlen(p);
2615
8.81k
        if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL)
2616
0
            return -1;
2617
8.81k
        p = p + len + 1;
2618
8.81k
    }
2619
39
    return 0;
2620
39
}
2621
2622
static JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v)
2623
2.30k
{
2624
2.30k
    JSAtomStruct *p;
2625
2626
2.30k
    if (!__JS_AtomIsConst(v)) {
2627
78
        p = rt->atom_array[v];
2628
78
        p->header.ref_count++;
2629
78
    }
2630
2.30k
    return v;
2631
2.30k
}
2632
2633
JSAtom JS_DupAtom(JSContext *ctx, JSAtom v)
2634
2.92M
{
2635
2.92M
    JSRuntime *rt;
2636
2.92M
    JSAtomStruct *p;
2637
2638
2.92M
    if (!__JS_AtomIsConst(v)) {
2639
24.5k
        rt = ctx->rt;
2640
24.5k
        p = rt->atom_array[v];
2641
24.5k
        p->header.ref_count++;
2642
24.5k
    }
2643
2.92M
    return v;
2644
2.92M
}
2645
2646
static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v)
2647
156
{
2648
156
    JSRuntime *rt;
2649
156
    JSAtomStruct *p;
2650
2651
156
    rt = ctx->rt;
2652
156
    if (__JS_AtomIsTaggedInt(v))
2653
0
        return JS_ATOM_KIND_STRING;
2654
156
    p = rt->atom_array[v];
2655
156
    switch(p->atom_type) {
2656
156
    case JS_ATOM_TYPE_STRING:
2657
156
        return JS_ATOM_KIND_STRING;
2658
0
    case JS_ATOM_TYPE_GLOBAL_SYMBOL:
2659
0
        return JS_ATOM_KIND_SYMBOL;
2660
0
    case JS_ATOM_TYPE_SYMBOL:
2661
0
        switch(p->hash) {
2662
0
        case JS_ATOM_HASH_SYMBOL:
2663
0
            return JS_ATOM_KIND_SYMBOL;
2664
0
        case JS_ATOM_HASH_PRIVATE:
2665
0
            return JS_ATOM_KIND_PRIVATE;
2666
0
        default:
2667
0
            abort();
2668
0
        }
2669
0
    default:
2670
0
        abort();
2671
156
    }
2672
156
}
2673
2674
static BOOL JS_AtomIsString(JSContext *ctx, JSAtom v)
2675
0
{
2676
0
    return JS_AtomGetKind(ctx, v) == JS_ATOM_KIND_STRING;
2677
0
}
2678
2679
static JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p)
2680
2
{
2681
2
    uint32_t i = p->hash_next;  /* atom_index */
2682
2
    if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
2683
2
        JSAtomStruct *p1;
2684
2685
2
        i = rt->atom_hash[p->hash & (rt->atom_hash_size - 1)];
2686
2
        p1 = rt->atom_array[i];
2687
2
        while (p1 != p) {
2688
0
            assert(i != 0);
2689
0
            i = p1->hash_next;
2690
0
            p1 = rt->atom_array[i];
2691
0
        }
2692
2
    }
2693
2
    return i;
2694
2
}
2695
2696
/* string case (internal). Return JS_ATOM_NULL if error. 'str' is
2697
   freed. */
2698
static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
2699
26.7k
{
2700
26.7k
    uint32_t h, h1, i;
2701
26.7k
    JSAtomStruct *p;
2702
26.7k
    int len;
2703
2704
#if 0
2705
    printf("__JS_NewAtom: ");  JS_DumpString(rt, str); printf("\n");
2706
#endif
2707
26.7k
    if (atom_type < JS_ATOM_TYPE_SYMBOL) {
2708
        /* str is not NULL */
2709
26.2k
        if (str->atom_type == atom_type) {
2710
            /* str is the atom, return its index */
2711
2
            i = js_get_atom_index(rt, str);
2712
            /* reduce string refcount and increase atom's unless constant */
2713
2
            if (__JS_AtomIsConst(i))
2714
2
                str->header.ref_count--;
2715
2
            return i;
2716
2
        }
2717
        /* try and locate an already registered atom */
2718
26.2k
        len = str->len;
2719
26.2k
        h = hash_string(str, atom_type);
2720
26.2k
        h &= JS_ATOM_HASH_MASK;
2721
26.2k
        h1 = h & (rt->atom_hash_size - 1);
2722
26.2k
        i = rt->atom_hash[h1];
2723
54.9k
        while (i != 0) {
2724
28.7k
            p = rt->atom_array[i];
2725
28.7k
            if (p->hash == h &&
2726
28.7k
                p->atom_type == atom_type &&
2727
28.7k
                p->len == len &&
2728
28.7k
                js_string_memcmp(p, str, len) == 0) {
2729
78
                if (!__JS_AtomIsConst(i))
2730
78
                    p->header.ref_count++;
2731
78
                goto done;
2732
78
            }
2733
28.7k
            i = p->hash_next;
2734
28.7k
        }
2735
26.2k
    } else {
2736
585
        h1 = 0; /* avoid warning */
2737
585
        if (atom_type == JS_ATOM_TYPE_SYMBOL) {
2738
546
            h = JS_ATOM_HASH_SYMBOL;
2739
546
        } else {
2740
39
            h = JS_ATOM_HASH_PRIVATE;
2741
39
            atom_type = JS_ATOM_TYPE_SYMBOL;
2742
39
        }
2743
585
    }
2744
2745
26.7k
    if (rt->atom_free_index == 0) {
2746
        /* allow new atom entries */
2747
156
        uint32_t new_size, start;
2748
156
        JSAtomStruct **new_array;
2749
2750
        /* alloc new with size progression 3/2:
2751
           4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066 1599 2398 3597 5395 8092
2752
           preallocating space for predefined atoms (at least 195).
2753
         */
2754
156
        new_size = max_int(211, rt->atom_size * 3 / 2);
2755
156
        if (new_size > JS_ATOM_MAX)
2756
0
            goto fail;
2757
        /* XXX: should use realloc2 to use slack space */
2758
156
        new_array = js_realloc_rt(rt, rt->atom_array, sizeof(*new_array) * new_size);
2759
156
        if (!new_array)
2760
0
            goto fail;
2761
        /* Note: the atom 0 is not used */
2762
156
        start = rt->atom_size;
2763
156
        if (start == 0) {
2764
            /* JS_ATOM_NULL entry */
2765
39
            p = js_mallocz_rt(rt, sizeof(JSAtomStruct));
2766
39
            if (!p) {
2767
0
                js_free_rt(rt, new_array);
2768
0
                goto fail;
2769
0
            }
2770
39
            p->header.ref_count = 1;  /* not refcounted */
2771
39
            p->atom_type = JS_ATOM_TYPE_SYMBOL;
2772
#ifdef DUMP_LEAKS
2773
            list_add_tail(&p->link, &rt->string_list);
2774
#endif
2775
39
            new_array[0] = p;
2776
39
            rt->atom_count++;
2777
39
            start = 1;
2778
39
        }
2779
156
        rt->atom_size = new_size;
2780
156
        rt->atom_array = new_array;
2781
156
        rt->atom_free_index = start;
2782
27.8k
        for(i = start; i < new_size; i++) {
2783
27.6k
            uint32_t next;
2784
27.6k
            if (i == (new_size - 1))
2785
156
                next = 0;
2786
27.5k
            else
2787
27.5k
                next = i + 1;
2788
27.6k
            rt->atom_array[i] = atom_set_free(next);
2789
27.6k
        }
2790
156
    }
2791
2792
26.7k
    if (str) {
2793
26.7k
        if (str->atom_type == 0) {
2794
26.7k
            p = str;
2795
26.7k
            p->atom_type = atom_type;
2796
26.7k
        } else {
2797
0
            p = js_malloc_rt(rt, sizeof(JSString) +
2798
0
                             (str->len << str->is_wide_char) +
2799
0
                             1 - str->is_wide_char);
2800
0
            if (unlikely(!p))
2801
0
                goto fail;
2802
0
            p->header.ref_count = 1;
2803
0
            p->is_wide_char = str->is_wide_char;
2804
0
            p->len = str->len;
2805
#ifdef DUMP_LEAKS
2806
            list_add_tail(&p->link, &rt->string_list);
2807
#endif
2808
0
            memcpy(p->u.str8, str->u.str8, (str->len << str->is_wide_char) +
2809
0
                   1 - str->is_wide_char);
2810
0
            js_free_string(rt, str);
2811
0
        }
2812
26.7k
    } else {
2813
0
        p = js_malloc_rt(rt, sizeof(JSAtomStruct)); /* empty wide string */
2814
0
        if (!p)
2815
0
            return JS_ATOM_NULL;
2816
0
        p->header.ref_count = 1;
2817
0
        p->is_wide_char = 1;    /* Hack to represent NULL as a JSString */
2818
0
        p->len = 0;
2819
#ifdef DUMP_LEAKS
2820
        list_add_tail(&p->link, &rt->string_list);
2821
#endif
2822
0
    }
2823
2824
    /* use an already free entry */
2825
26.7k
    i = rt->atom_free_index;
2826
26.7k
    rt->atom_free_index = atom_get_free(rt->atom_array[i]);
2827
26.7k
    rt->atom_array[i] = p;
2828
2829
26.7k
    p->hash = h;
2830
26.7k
    p->hash_next = i;   /* atom_index */
2831
26.7k
    p->atom_type = atom_type;
2832
2833
26.7k
    rt->atom_count++;
2834
2835
26.7k
    if (atom_type != JS_ATOM_TYPE_SYMBOL) {
2836
26.1k
        p->hash_next = rt->atom_hash[h1];
2837
26.1k
        rt->atom_hash[h1] = i;
2838
26.1k
        if (unlikely(rt->atom_count >= rt->atom_count_resize))
2839
39
            JS_ResizeAtomHash(rt, rt->atom_hash_size * 2);
2840
26.1k
    }
2841
2842
    //    JS_DumpAtoms(rt);
2843
26.7k
    return i;
2844
2845
0
 fail:
2846
0
    i = JS_ATOM_NULL;
2847
78
 done:
2848
78
    if (str)
2849
78
        js_free_string(rt, str);
2850
78
    return i;
2851
0
}
2852
2853
/* only works with zero terminated 8 bit strings */
2854
static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
2855
                               int atom_type)
2856
8.85k
{
2857
8.85k
    JSString *p;
2858
8.85k
    p = js_alloc_string_rt(rt, len, 0);
2859
8.85k
    if (!p)
2860
0
        return JS_ATOM_NULL;
2861
8.85k
    memcpy(p->u.str8, str, len);
2862
8.85k
    p->u.str8[len] = '\0';
2863
8.85k
    return __JS_NewAtom(rt, p, atom_type);
2864
8.85k
}
2865
2866
/* Warning: str must be ASCII only */
2867
static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
2868
                            int atom_type)
2869
38.9k
{
2870
38.9k
    uint32_t h, h1, i;
2871
38.9k
    JSAtomStruct *p;
2872
2873
38.9k
    h = hash_string8((const uint8_t *)str, len, JS_ATOM_TYPE_STRING);
2874
38.9k
    h &= JS_ATOM_HASH_MASK;
2875
38.9k
    h1 = h & (rt->atom_hash_size - 1);
2876
38.9k
    i = rt->atom_hash[h1];
2877
73.9k
    while (i != 0) {
2878
56.0k
        p = rt->atom_array[i];
2879
56.0k
        if (p->hash == h &&
2880
56.0k
            p->atom_type == JS_ATOM_TYPE_STRING &&
2881
56.0k
            p->len == len &&
2882
56.0k
            p->is_wide_char == 0 &&
2883
56.0k
            memcmp(p->u.str8, str, len) == 0) {
2884
21.1k
            if (!__JS_AtomIsConst(i))
2885
12.2k
                p->header.ref_count++;
2886
21.1k
            return i;
2887
21.1k
        }
2888
34.9k
        i = p->hash_next;
2889
34.9k
    }
2890
17.8k
    return JS_ATOM_NULL;
2891
38.9k
}
2892
2893
static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p)
2894
17.8k
{
2895
#if 0   /* JS_ATOM_NULL is not refcounted: __JS_AtomIsConst() includes 0 */
2896
    if (unlikely(i == JS_ATOM_NULL)) {
2897
        p->header.ref_count = INT32_MAX / 2;
2898
        return;
2899
    }
2900
#endif
2901
17.8k
    uint32_t i = p->hash_next;  /* atom_index */
2902
17.8k
    if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
2903
17.8k
        JSAtomStruct *p0, *p1;
2904
17.8k
        uint32_t h0;
2905
2906
17.8k
        h0 = p->hash & (rt->atom_hash_size - 1);
2907
17.8k
        i = rt->atom_hash[h0];
2908
17.8k
        p1 = rt->atom_array[i];
2909
17.8k
        if (p1 == p) {
2910
11.1k
            rt->atom_hash[h0] = p1->hash_next;
2911
11.1k
        } else {
2912
10.2k
            for(;;) {
2913
10.2k
                assert(i != 0);
2914
10.2k
                p0 = p1;
2915
10.2k
                i = p1->hash_next;
2916
10.2k
                p1 = rt->atom_array[i];
2917
10.2k
                if (p1 == p) {
2918
6.72k
                    p0->hash_next = p1->hash_next;
2919
6.72k
                    break;
2920
6.72k
                }
2921
10.2k
            }
2922
6.72k
        }
2923
17.8k
    }
2924
    /* insert in free atom list */
2925
17.8k
    rt->atom_array[i] = atom_set_free(rt->atom_free_index);
2926
17.8k
    rt->atom_free_index = i;
2927
    /* free the string structure */
2928
#ifdef DUMP_LEAKS
2929
    list_del(&p->link);
2930
#endif
2931
17.8k
    js_free_rt(rt, p);
2932
17.8k
    rt->atom_count--;
2933
17.8k
    assert(rt->atom_count >= 0);
2934
17.8k
}
2935
2936
static void __JS_FreeAtom(JSRuntime *rt, uint32_t i)
2937
54.8k
{
2938
54.8k
    JSAtomStruct *p;
2939
2940
54.8k
    p = rt->atom_array[i];
2941
54.8k
    if (--p->header.ref_count > 0)
2942
39.1k
        return;
2943
15.7k
    JS_FreeAtomStruct(rt, p);
2944
15.7k
}
2945
2946
/* Warning: 'p' is freed */
2947
static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p)
2948
17.9k
{
2949
17.9k
    JSRuntime *rt = ctx->rt;
2950
17.9k
    uint32_t n;
2951
17.9k
    if (is_num_string(&n, p)) {
2952
0
        if (n <= JS_ATOM_MAX_INT) {
2953
0
            js_free_string(rt, p);
2954
0
            return __JS_AtomFromUInt32(n);
2955
0
        }
2956
0
    }
2957
    /* XXX: should generate an exception */
2958
17.9k
    return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING);
2959
17.9k
}
2960
2961
/* str is UTF-8 encoded */
2962
JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len)
2963
38.9k
{
2964
38.9k
    JSValue val;
2965
2966
38.9k
    if (len == 0 || !is_digit(*str)) {
2967
        // XXX: this will not work if UTF-8 encoded str contains non ASCII bytes
2968
38.9k
        JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);
2969
38.9k
        if (atom)
2970
21.0k
            return atom;
2971
38.9k
    }
2972
17.8k
    val = JS_NewStringLen(ctx, str, len);
2973
17.8k
    if (JS_IsException(val))
2974
0
        return JS_ATOM_NULL;
2975
17.8k
    return JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(val));
2976
17.8k
}
2977
2978
JSAtom JS_NewAtom(JSContext *ctx, const char *str)
2979
38.3k
{
2980
38.3k
    return JS_NewAtomLen(ctx, str, strlen(str));
2981
38.3k
}
2982
2983
JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
2984
0
{
2985
0
    if (n <= JS_ATOM_MAX_INT) {
2986
0
        return __JS_AtomFromUInt32(n);
2987
0
    } else {
2988
0
        char buf[11];
2989
0
        JSValue val;
2990
0
        snprintf(buf, sizeof(buf), "%u", n);
2991
0
        val = JS_NewString(ctx, buf);
2992
0
        if (JS_IsException(val))
2993
0
            return JS_ATOM_NULL;
2994
0
        return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
2995
0
                            JS_ATOM_TYPE_STRING);
2996
0
    }
2997
0
}
2998
2999
static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n)
3000
0
{
3001
0
    if ((uint64_t)n <= JS_ATOM_MAX_INT) {
3002
0
        return __JS_AtomFromUInt32((uint32_t)n);
3003
0
    } else {
3004
0
        char buf[24];
3005
0
        JSValue val;
3006
0
        snprintf(buf, sizeof(buf), "%" PRId64 , n);
3007
0
        val = JS_NewString(ctx, buf);
3008
0
        if (JS_IsException(val))
3009
0
            return JS_ATOM_NULL;
3010
0
        return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
3011
0
                            JS_ATOM_TYPE_STRING);
3012
0
    }
3013
0
}
3014
3015
/* 'p' is freed */
3016
static JSValue JS_NewSymbol(JSContext *ctx, JSString *p, int atom_type)
3017
0
{
3018
0
    JSRuntime *rt = ctx->rt;
3019
0
    JSAtom atom;
3020
0
    atom = __JS_NewAtom(rt, p, atom_type);
3021
0
    if (atom == JS_ATOM_NULL)
3022
0
        return JS_ThrowOutOfMemory(ctx);
3023
0
    return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]);
3024
0
}
3025
3026
/* descr must be a non-numeric string atom */
3027
static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,
3028
                                    int atom_type)
3029
0
{
3030
0
    JSRuntime *rt = ctx->rt;
3031
0
    JSString *p;
3032
3033
0
    assert(!__JS_AtomIsTaggedInt(descr));
3034
0
    assert(descr < rt->atom_size);
3035
0
    p = rt->atom_array[descr];
3036
0
    JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
3037
0
    return JS_NewSymbol(ctx, p, atom_type);
3038
0
}
3039
3040
#define ATOM_GET_STR_BUF_SIZE 64
3041
3042
/* Should only be used for debug. */
3043
static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,
3044
                                   JSAtom atom)
3045
1.14k
{
3046
1.14k
    if (__JS_AtomIsTaggedInt(atom)) {
3047
0
        snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom));
3048
1.14k
    } else {
3049
1.14k
        JSAtomStruct *p;
3050
1.14k
        assert(atom < rt->atom_size);
3051
1.14k
        if (atom == JS_ATOM_NULL) {
3052
0
            snprintf(buf, buf_size, "<null>");
3053
1.14k
        } else {
3054
1.14k
            int i, c;
3055
1.14k
            char *q;
3056
1.14k
            JSString *str;
3057
3058
1.14k
            q = buf;
3059
1.14k
            p = rt->atom_array[atom];
3060
1.14k
            assert(!atom_is_free(p));
3061
1.14k
            str = p;
3062
1.14k
            if (str) {
3063
1.14k
                if (!str->is_wide_char) {
3064
                    /* special case ASCII strings */
3065
1.14k
                    c = 0;
3066
1.06M
                    for(i = 0; i < str->len; i++) {
3067
1.06M
                        c |= str->u.str8[i];
3068
1.06M
                    }
3069
1.14k
                    if (c < 0x80)
3070
1.14k
                        return (const char *)str->u.str8;
3071
1.14k
                }
3072
0
                for(i = 0; i < str->len; i++) {
3073
0
                    c = string_get(str, i);
3074
0
                    if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX)
3075
0
                        break;
3076
0
                    if (c < 128) {
3077
0
                        *q++ = c;
3078
0
                    } else {
3079
0
                        q += unicode_to_utf8((uint8_t *)q, c);
3080
0
                    }
3081
0
                }
3082
0
            }
3083
0
            *q = '\0';
3084
0
        }
3085
1.14k
    }
3086
0
    return buf;
3087
1.14k
}
3088
3089
static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom)
3090
1.14k
{
3091
1.14k
    return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom);
3092
1.14k
}
3093
3094
static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string)
3095
47.2k
{
3096
47.2k
    char buf[ATOM_GET_STR_BUF_SIZE];
3097
3098
47.2k
    if (__JS_AtomIsTaggedInt(atom)) {
3099
0
        snprintf(buf, sizeof(buf), "%u", __JS_AtomToUInt32(atom));
3100
0
        return JS_NewString(ctx, buf);
3101
47.2k
    } else {
3102
47.2k
        JSRuntime *rt = ctx->rt;
3103
47.2k
        JSAtomStruct *p;
3104
47.2k
        assert(atom < rt->atom_size);
3105
47.2k
        p = rt->atom_array[atom];
3106
47.2k
        if (p->atom_type == JS_ATOM_TYPE_STRING) {
3107
46.7k
            goto ret_string;
3108
46.7k
        } else if (force_string) {
3109
0
            if (p->len == 0 && p->is_wide_char != 0) {
3110
                /* no description string */
3111
0
                p = rt->atom_array[JS_ATOM_empty_string];
3112
0
            }
3113
46.7k
        ret_string:
3114
46.7k
            return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
3115
546
        } else {
3116
546
            return JS_DupValue(ctx, JS_MKPTR(JS_TAG_SYMBOL, p));
3117
546
        }
3118
47.2k
    }
3119
47.2k
}
3120
3121
JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom)
3122
561
{
3123
561
    return __JS_AtomToValue(ctx, atom, FALSE);
3124
561
}
3125
3126
JSValue JS_AtomToString(JSContext *ctx, JSAtom atom)
3127
46.7k
{
3128
46.7k
    return __JS_AtomToValue(ctx, atom, TRUE);
3129
46.7k
}
3130
3131
/* return TRUE if the atom is an array index (i.e. 0 <= index <=
3132
   2^32-2 and return its value */
3133
static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom)
3134
1.88M
{
3135
1.88M
    if (__JS_AtomIsTaggedInt(atom)) {
3136
1.88M
        *pval = __JS_AtomToUInt32(atom);
3137
1.88M
        return TRUE;
3138
1.88M
    } else {
3139
273
        JSRuntime *rt = ctx->rt;
3140
273
        JSAtomStruct *p;
3141
273
        uint32_t val;
3142
3143
273
        assert(atom < rt->atom_size);
3144
273
        p = rt->atom_array[atom];
3145
273
        if (p->atom_type == JS_ATOM_TYPE_STRING &&
3146
273
            is_num_string(&val, p) && val != -1) {
3147
0
            *pval = val;
3148
0
            return TRUE;
3149
273
        } else {
3150
273
            *pval = 0;
3151
273
            return FALSE;
3152
273
        }
3153
273
    }
3154
1.88M
}
3155
3156
/* This test must be fast if atom is not a numeric index (e.g. a
3157
   method name). Return JS_UNDEFINED if not a numeric
3158
   index. JS_EXCEPTION can also be returned. */
3159
static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
3160
0
{
3161
0
    JSRuntime *rt = ctx->rt;
3162
0
    JSAtomStruct *p1;
3163
0
    JSString *p;
3164
0
    int c, len, ret;
3165
0
    JSValue num, str;
3166
3167
0
    if (__JS_AtomIsTaggedInt(atom))
3168
0
        return JS_NewInt32(ctx, __JS_AtomToUInt32(atom));
3169
0
    assert(atom < rt->atom_size);
3170
0
    p1 = rt->atom_array[atom];
3171
0
    if (p1->atom_type != JS_ATOM_TYPE_STRING)
3172
0
        return JS_UNDEFINED;
3173
0
    p = p1;
3174
0
    len = p->len;
3175
0
    if (p->is_wide_char) {
3176
0
        const uint16_t *r = p->u.str16, *r_end = p->u.str16 + len;
3177
0
        if (r >= r_end)
3178
0
            return JS_UNDEFINED;
3179
0
        c = *r;
3180
0
        if (c == '-') {
3181
0
            if (r >= r_end)
3182
0
                return JS_UNDEFINED;
3183
0
            r++;
3184
0
            c = *r;
3185
            /* -0 case is specific */
3186
0
            if (c == '0' && len == 2)
3187
0
                goto minus_zero;
3188
0
        }
3189
        /* XXX: should test NaN, but the tests do not check it */
3190
0
        if (!is_num(c)) {
3191
            /* XXX: String should be normalized, therefore 8-bit only */
3192
0
            const uint16_t nfinity16[7] = { 'n', 'f', 'i', 'n', 'i', 't', 'y' };
3193
0
            if (!(c =='I' && (r_end - r) == 8 &&
3194
0
                  !memcmp(r + 1, nfinity16, sizeof(nfinity16))))
3195
0
                return JS_UNDEFINED;
3196
0
        }
3197
0
    } else {
3198
0
        const uint8_t *r = p->u.str8, *r_end = p->u.str8 + len;
3199
0
        if (r >= r_end)
3200
0
            return JS_UNDEFINED;
3201
0
        c = *r;
3202
0
        if (c == '-') {
3203
0
            if (r >= r_end)
3204
0
                return JS_UNDEFINED;
3205
0
            r++;
3206
0
            c = *r;
3207
            /* -0 case is specific */
3208
0
            if (c == '0' && len == 2) {
3209
0
            minus_zero:
3210
0
                return __JS_NewFloat64(ctx, -0.0);
3211
0
            }
3212
0
        }
3213
0
        if (!is_num(c)) {
3214
0
            if (!(c =='I' && (r_end - r) == 8 &&
3215
0
                  !memcmp(r + 1, "nfinity", 7)))
3216
0
                return JS_UNDEFINED;
3217
0
        }
3218
0
    }
3219
    /* XXX: bignum: would be better to only accept integer to avoid
3220
       relying on current floating point precision */
3221
    /* this is ECMA CanonicalNumericIndexString primitive */
3222
0
    num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p));
3223
0
    if (JS_IsException(num))
3224
0
        return num;
3225
0
    str = JS_ToString(ctx, num);
3226
0
    if (JS_IsException(str)) {
3227
0
        JS_FreeValue(ctx, num);
3228
0
        return str;
3229
0
    }
3230
0
    ret = js_string_compare(ctx, p, JS_VALUE_GET_STRING(str));
3231
0
    JS_FreeValue(ctx, str);
3232
0
    if (ret == 0) {
3233
0
        return num;
3234
0
    } else {
3235
0
        JS_FreeValue(ctx, num);
3236
0
        return JS_UNDEFINED;
3237
0
    }
3238
0
}
3239
3240
/* return -1 if exception or TRUE/FALSE */
3241
static int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom)
3242
0
{
3243
0
    JSValue num;
3244
0
    num = JS_AtomIsNumericIndex1(ctx, atom);
3245
0
    if (likely(JS_IsUndefined(num)))
3246
0
        return FALSE;
3247
0
    if (JS_IsException(num))
3248
0
        return -1;
3249
0
    JS_FreeValue(ctx, num);
3250
0
    return TRUE;
3251
0
}
3252
3253
void JS_FreeAtom(JSContext *ctx, JSAtom v)
3254
48.9k
{
3255
48.9k
    if (!__JS_AtomIsConst(v))
3256
34.0k
        __JS_FreeAtom(ctx->rt, v);
3257
48.9k
}
3258
3259
void JS_FreeAtomRT(JSRuntime *rt, JSAtom v)
3260
8.37M
{
3261
8.37M
    if (!__JS_AtomIsConst(v))
3262
20.8k
        __JS_FreeAtom(rt, v);
3263
8.37M
}
3264
3265
/* return TRUE if 'v' is a symbol with a string description */
3266
static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)
3267
0
{
3268
0
    JSRuntime *rt;
3269
0
    JSAtomStruct *p;
3270
3271
0
    rt = ctx->rt;
3272
0
    if (__JS_AtomIsTaggedInt(v))
3273
0
        return FALSE;
3274
0
    p = rt->atom_array[v];
3275
0
    return (((p->atom_type == JS_ATOM_TYPE_SYMBOL &&
3276
0
              p->hash == JS_ATOM_HASH_SYMBOL) ||
3277
0
             p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL) &&
3278
0
            !(p->len == 0 && p->is_wide_char != 0));
3279
0
}
3280
3281
static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom)
3282
0
{
3283
0
    char buf[ATOM_GET_STR_BUF_SIZE];
3284
0
    const char *p;
3285
0
    int i;
3286
0
3287
0
    /* XXX: should handle embedded null characters */
3288
0
    /* XXX: should move encoding code to JS_AtomGetStr */
3289
0
    p = JS_AtomGetStr(ctx, buf, sizeof(buf), atom);
3290
0
    for (i = 0; p[i]; i++) {
3291
0
        int c = (unsigned char)p[i];
3292
0
        if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
3293
0
              (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0)))
3294
0
            break;
3295
0
    }
3296
0
    if (i > 0 && p[i] == '\0') {
3297
0
        printf("%s", p);
3298
0
    } else {
3299
0
        putchar('"');
3300
0
        printf("%.*s", i, p);
3301
0
        for (; p[i]; i++) {
3302
0
            int c = (unsigned char)p[i];
3303
0
            if (c == '\"' || c == '\\') {
3304
0
                putchar('\\');
3305
0
                putchar(c);
3306
0
            } else if (c >= ' ' && c <= 126) {
3307
0
                putchar(c);
3308
0
            } else if (c == '\n') {
3309
0
                putchar('\\');
3310
0
                putchar('n');
3311
0
            } else {
3312
0
                printf("\\u%04x", c);
3313
0
            }
3314
0
        }
3315
0
        putchar('\"');
3316
0
    }
3317
0
}
3318
3319
/* free with JS_FreeCString() */
3320
const char *JS_AtomToCString(JSContext *ctx, JSAtom atom)
3321
204
{
3322
204
    JSValue str;
3323
204
    const char *cstr;
3324
3325
204
    str = JS_AtomToString(ctx, atom);
3326
204
    if (JS_IsException(str))
3327
0
        return NULL;
3328
204
    cstr = JS_ToCString(ctx, str);
3329
204
    JS_FreeValue(ctx, str);
3330
204
    return cstr;
3331
204
}
3332
3333
/* return a string atom containing name concatenated with str1 */
3334
static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1)
3335
0
{
3336
0
    JSValue str;
3337
0
    JSAtom atom;
3338
0
    const char *cstr;
3339
0
    char *cstr2;
3340
0
    size_t len, len1;
3341
3342
0
    str = JS_AtomToString(ctx, name);
3343
0
    if (JS_IsException(str))
3344
0
        return JS_ATOM_NULL;
3345
0
    cstr = JS_ToCStringLen(ctx, &len, str);
3346
0
    if (!cstr)
3347
0
        goto fail;
3348
0
    len1 = strlen(str1);
3349
0
    cstr2 = js_malloc(ctx, len + len1 + 1);
3350
0
    if (!cstr2)
3351
0
        goto fail;
3352
0
    memcpy(cstr2, cstr, len);
3353
0
    memcpy(cstr2 + len, str1, len1);
3354
0
    cstr2[len + len1] = '\0';
3355
0
    atom = JS_NewAtomLen(ctx, cstr2, len + len1);
3356
0
    js_free(ctx, cstr2);
3357
0
    JS_FreeCString(ctx, cstr);
3358
0
    JS_FreeValue(ctx, str);
3359
0
    return atom;
3360
0
 fail:
3361
0
    JS_FreeCString(ctx, cstr);
3362
0
    JS_FreeValue(ctx, str);
3363
0
    return JS_ATOM_NULL;
3364
0
}
3365
3366
static JSAtom js_atom_concat_num(JSContext *ctx, JSAtom name, uint32_t n)
3367
0
{
3368
0
    char buf[16];
3369
0
    snprintf(buf, sizeof(buf), "%u", n);
3370
0
    return js_atom_concat_str(ctx, name, buf);
3371
0
}
3372
3373
static inline BOOL JS_IsEmptyString(JSValueConst v)
3374
0
{
3375
0
    return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0;
3376
0
}
3377
3378
/* JSClass support */
3379
3380
#ifdef CONFIG_ATOMICS
3381
static pthread_mutex_t js_class_id_mutex = PTHREAD_MUTEX_INITIALIZER;
3382
#endif
3383
3384
/* a new class ID is allocated if *pclass_id != 0 */
3385
JSClassID JS_NewClassID(JSClassID *pclass_id)
3386
78
{
3387
78
    JSClassID class_id;
3388
78
#ifdef CONFIG_ATOMICS
3389
78
    pthread_mutex_lock(&js_class_id_mutex);
3390
78
#endif
3391
78
    class_id = *pclass_id;
3392
78
    if (class_id == 0) {
3393
4
        class_id = js_class_id_alloc++;
3394
4
        *pclass_id = class_id;
3395
4
    }
3396
78
#ifdef CONFIG_ATOMICS
3397
78
    pthread_mutex_unlock(&js_class_id_mutex);
3398
78
#endif
3399
78
    return class_id;
3400
78
}
3401
3402
JSClassID JS_GetClassID(JSValue v)
3403
0
{
3404
0
    JSObject *p;
3405
0
    if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)
3406
0
        return JS_INVALID_CLASS_ID;
3407
0
    p = JS_VALUE_GET_OBJ(v);
3408
0
    return p->class_id;
3409
0
}
3410
3411
BOOL JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id)
3412
78
{
3413
78
    return (class_id < rt->class_count &&
3414
78
            rt->class_array[class_id].class_id != 0);
3415
78
}
3416
3417
/* create a new object internal class. Return -1 if error, 0 if
3418
   OK. The finalizer can be NULL if none is needed. */
3419
static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
3420
                        const JSClassDef *class_def, JSAtom name)
3421
2.30k
{
3422
2.30k
    int new_size, i;
3423
2.30k
    JSClass *cl, *new_class_array;
3424
2.30k
    struct list_head *el;
3425
3426
2.30k
    if (class_id >= (1 << 16))
3427
0
        return -1;
3428
2.30k
    if (class_id < rt->class_count &&
3429
2.30k
        rt->class_array[class_id].class_id != 0)
3430
0
        return -1;
3431
3432
2.30k
    if (class_id >= rt->class_count) {
3433
78
        new_size = max_int(JS_CLASS_INIT_COUNT,
3434
78
                           max_int(class_id + 1, rt->class_count * 3 / 2));
3435
3436
        /* reallocate the context class prototype array, if any */
3437
78
        list_for_each(el, &rt->context_list) {
3438
39
            JSContext *ctx = list_entry(el, JSContext, link);
3439
39
            JSValue *new_tab;
3440
39
            new_tab = js_realloc_rt(rt, ctx->class_proto,
3441
39
                                    sizeof(ctx->class_proto[0]) * new_size);
3442
39
            if (!new_tab)
3443
0
                return -1;
3444
1.17k
            for(i = rt->class_count; i < new_size; i++)
3445
1.13k
                new_tab[i] = JS_NULL;
3446
39
            ctx->class_proto = new_tab;
3447
39
        }
3448
        /* reallocate the class array */
3449
78
        new_class_array = js_realloc_rt(rt, rt->class_array,
3450
78
                                        sizeof(JSClass) * new_size);
3451
78
        if (!new_class_array)
3452
0
            return -1;
3453
78
        memset(new_class_array + rt->class_count, 0,
3454
78
               (new_size - rt->class_count) * sizeof(JSClass));
3455
78
        rt->class_array = new_class_array;
3456
78
        rt->class_count = new_size;
3457
78
    }
3458
2.30k
    cl = &rt->class_array[class_id];
3459
2.30k
    cl->class_id = class_id;
3460
2.30k
    cl->class_name = JS_DupAtomRT(rt, name);
3461
2.30k
    cl->finalizer = class_def->finalizer;
3462
2.30k
    cl->gc_mark = class_def->gc_mark;
3463
2.30k
    cl->call = class_def->call;
3464
2.30k
    cl->exotic = class_def->exotic;
3465
2.30k
    return 0;
3466
2.30k
}
3467
3468
int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def)
3469
78
{
3470
78
    int ret, len;
3471
78
    JSAtom name;
3472
3473
78
    len = strlen(class_def->class_name);
3474
78
    name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
3475
78
    if (name == JS_ATOM_NULL) {
3476
39
        name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
3477
39
        if (name == JS_ATOM_NULL)
3478
0
            return -1;
3479
39
    }
3480
78
    ret = JS_NewClass1(rt, class_id, class_def, name);
3481
78
    JS_FreeAtomRT(rt, name);
3482
78
    return ret;
3483
78
}
3484
3485
static JSValue js_new_string8(JSContext *ctx, const uint8_t *buf, int len)
3486
18.0k
{
3487
18.0k
    JSString *str;
3488
3489
18.0k
    if (len <= 0) {
3490
39
        return JS_AtomToString(ctx, JS_ATOM_empty_string);
3491
39
    }
3492
17.9k
    str = js_alloc_string(ctx, len, 0);
3493
17.9k
    if (!str)
3494
0
        return JS_EXCEPTION;
3495
17.9k
    memcpy(str->u.str8, buf, len);
3496
17.9k
    str->u.str8[len] = '\0';
3497
17.9k
    return JS_MKPTR(JS_TAG_STRING, str);
3498
17.9k
}
3499
3500
static JSValue js_new_string16(JSContext *ctx, const uint16_t *buf, int len)
3501
0
{
3502
0
    JSString *str;
3503
0
    str = js_alloc_string(ctx, len, 1);
3504
0
    if (!str)
3505
0
        return JS_EXCEPTION;
3506
0
    memcpy(str->u.str16, buf, len * 2);
3507
0
    return JS_MKPTR(JS_TAG_STRING, str);
3508
0
}
3509
3510
static JSValue js_new_string_char(JSContext *ctx, uint16_t c)
3511
0
{
3512
0
    if (c < 0x100) {
3513
0
        uint8_t ch8 = c;
3514
0
        return js_new_string8(ctx, &ch8, 1);
3515
0
    } else {
3516
0
        uint16_t ch16 = c;
3517
0
        return js_new_string16(ctx, &ch16, 1);
3518
0
    }
3519
0
}
3520
3521
static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end)
3522
0
{
3523
0
    int len = end - start;
3524
0
    if (start == 0 && end == p->len) {
3525
0
        return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
3526
0
    }
3527
0
    if (p->is_wide_char && len > 0) {
3528
0
        JSString *str;
3529
0
        int i;
3530
0
        uint16_t c = 0;
3531
0
        for (i = start; i < end; i++) {
3532
0
            c |= p->u.str16[i];
3533
0
        }
3534
0
        if (c > 0xFF)
3535
0
            return js_new_string16(ctx, p->u.str16 + start, len);
3536
3537
0
        str = js_alloc_string(ctx, len, 0);
3538
0
        if (!str)
3539
0
            return JS_EXCEPTION;
3540
0
        for (i = 0; i < len; i++) {
3541
0
            str->u.str8[i] = p->u.str16[start + i];
3542
0
        }
3543
0
        str->u.str8[len] = '\0';
3544
0
        return JS_MKPTR(JS_TAG_STRING, str);
3545
0
    } else {
3546
0
        return js_new_string8(ctx, p->u.str8 + start, len);
3547
0
    }
3548
0
}
3549
3550
typedef struct StringBuffer {
3551
    JSContext *ctx;
3552
    JSString *str;
3553
    int len;
3554
    int size;
3555
    int is_wide_char;
3556
    int error_status;
3557
} StringBuffer;
3558
3559
/* It is valid to call string_buffer_end() and all string_buffer functions even
3560
   if string_buffer_init() or another string_buffer function returns an error.
3561
   If the error_status is set, string_buffer_end() returns JS_EXCEPTION.
3562
 */
3563
static int string_buffer_init2(JSContext *ctx, StringBuffer *s, int size,
3564
                               int is_wide)
3565
117
{
3566
117
    s->ctx = ctx;
3567
117
    s->size = size;
3568
117
    s->len = 0;
3569
117
    s->is_wide_char = is_wide;
3570
117
    s->error_status = 0;
3571
117
    s->str = js_alloc_string(ctx, size, is_wide);
3572
117
    if (unlikely(!s->str)) {
3573
0
        s->size = 0;
3574
0
        return s->error_status = -1;
3575
0
    }
3576
#ifdef DUMP_LEAKS
3577
    /* the StringBuffer may reallocate the JSString, only link it at the end */
3578
    list_del(&s->str->link);
3579
#endif
3580
117
    return 0;
3581
117
}
3582
3583
static inline int string_buffer_init(JSContext *ctx, StringBuffer *s, int size)
3584
117
{
3585
117
    return string_buffer_init2(ctx, s, size, 0);
3586
117
}
3587
3588
static void string_buffer_free(StringBuffer *s)
3589
1
{
3590
1
    js_free(s->ctx, s->str);
3591
1
    s->str = NULL;
3592
1
}
3593
3594
static int string_buffer_set_error(StringBuffer *s)
3595
0
{
3596
0
    js_free(s->ctx, s->str);
3597
0
    s->str = NULL;
3598
0
    s->size = 0;
3599
0
    s->len = 0;
3600
0
    return s->error_status = -1;
3601
0
}
3602
3603
static no_inline int string_buffer_widen(StringBuffer *s, int size)
3604
1
{
3605
1
    JSString *str;
3606
1
    size_t slack;
3607
1
    int i;
3608
3609
1
    if (s->error_status)
3610
0
        return -1;
3611
3612
1
    str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack);
3613
1
    if (!str)
3614
0
        return string_buffer_set_error(s);
3615
1
    size += slack >> 1;
3616
70
    for(i = s->len; i-- > 0;) {
3617
69
        str->u.str16[i] = str->u.str8[i];
3618
69
    }
3619
1
    s->is_wide_char = 1;
3620
1
    s->size = size;
3621
1
    s->str = str;
3622
1
    return 0;
3623
1
}
3624
3625
static no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c)
3626
575
{
3627
575
    JSString *new_str;
3628
575
    int new_size;
3629
575
    size_t new_size_bytes, slack;
3630
3631
575
    if (s->error_status)
3632
0
        return -1;
3633
3634
575
    if (new_len > JS_STRING_LEN_MAX) {
3635
0
        JS_ThrowInternalError(s->ctx, "string too long");
3636
0
        return string_buffer_set_error(s);
3637
0
    }
3638
575
    new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX);
3639
575
    if (!s->is_wide_char && c >= 0x100) {
3640
0
        return string_buffer_widen(s, new_size);
3641
0
    }
3642
575
    new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char;
3643
575
    new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack);
3644
575
    if (!new_str)
3645
0
        return string_buffer_set_error(s);
3646
575
    new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX);
3647
575
    s->size = new_size;
3648
575
    s->str = new_str;
3649
575
    return 0;
3650
575
}
3651
3652
static no_inline int string_buffer_putc_slow(StringBuffer *s, uint32_t c)
3653
576
{
3654
576
    if (unlikely(s->len >= s->size)) {
3655
575
        if (string_buffer_realloc(s, s->len + 1, c))
3656
0
            return -1;
3657
575
    }
3658
576
    if (s->is_wide_char) {
3659
23
        s->str->u.str16[s->len++] = c;
3660
553
    } else if (c < 0x100) {
3661
552
        s->str->u.str8[s->len++] = c;
3662
552
    } else {
3663
1
        if (string_buffer_widen(s, s->size))
3664
0
            return -1;
3665
1
        s->str->u.str16[s->len++] = c;
3666
1
    }
3667
576
    return 0;
3668
576
}
3669
3670
/* 0 <= c <= 0xff */
3671
static int string_buffer_putc8(StringBuffer *s, uint32_t c)
3672
0
{
3673
0
    if (unlikely(s->len >= s->size)) {
3674
0
        if (string_buffer_realloc(s, s->len + 1, c))
3675
0
            return -1;
3676
0
    }
3677
0
    if (s->is_wide_char) {
3678
0
        s->str->u.str16[s->len++] = c;
3679
0
    } else {
3680
0
        s->str->u.str8[s->len++] = c;
3681
0
    }
3682
0
    return 0;
3683
0
}
3684
3685
/* 0 <= c <= 0xffff */
3686
static int string_buffer_putc16(StringBuffer *s, uint32_t c)
3687
24.0M
{
3688
24.0M
    if (likely(s->len < s->size)) {
3689
24.0M
        if (s->is_wide_char) {
3690
990k
            s->str->u.str16[s->len++] = c;
3691
990k
            return 0;
3692
23.0M
        } else if (c < 0x100) {
3693
23.0M
            s->str->u.str8[s->len++] = c;
3694
23.0M
            return 0;
3695
23.0M
        }
3696
24.0M
    }
3697
576
    return string_buffer_putc_slow(s, c);
3698
24.0M
}
3699
3700
/* 0 <= c <= 0x10ffff */
3701
static int string_buffer_putc(StringBuffer *s, uint32_t c)
3702
24.0M
{
3703
24.0M
    if (unlikely(c >= 0x10000)) {
3704
        /* surrogate pair */
3705
15.1k
        if (string_buffer_putc16(s, get_hi_surrogate(c)))
3706
0
            return -1;
3707
15.1k
        c = get_lo_surrogate(c);
3708
15.1k
    }
3709
24.0M
    return string_buffer_putc16(s, c);
3710
24.0M
}
3711
3712
static int string_getc(const JSString *p, int *pidx)
3713
0
{
3714
0
    int idx, c, c1;
3715
0
    idx = *pidx;
3716
0
    if (p->is_wide_char) {
3717
0
        c = p->u.str16[idx++];
3718
0
        if (is_hi_surrogate(c) && idx < p->len) {
3719
0
            c1 = p->u.str16[idx];
3720
0
            if (is_lo_surrogate(c1)) {
3721
0
                c = from_surrogate(c, c1);
3722
0
                idx++;
3723
0
            }
3724
0
        }
3725
0
    } else {
3726
0
        c = p->u.str8[idx++];
3727
0
    }
3728
0
    *pidx = idx;
3729
0
    return c;
3730
0
}
3731
3732
static int string_buffer_write8(StringBuffer *s, const uint8_t *p, int len)
3733
0
{
3734
0
    int i;
3735
3736
0
    if (s->len + len > s->size) {
3737
0
        if (string_buffer_realloc(s, s->len + len, 0))
3738
0
            return -1;
3739
0
    }
3740
0
    if (s->is_wide_char) {
3741
0
        for (i = 0; i < len; i++) {
3742
0
            s->str->u.str16[s->len + i] = p[i];
3743
0
        }
3744
0
        s->len += len;
3745
0
    } else {
3746
0
        memcpy(&s->str->u.str8[s->len], p, len);
3747
0
        s->len += len;
3748
0
    }
3749
0
    return 0;
3750
0
}
3751
3752
static int string_buffer_write16(StringBuffer *s, const uint16_t *p, int len)
3753
0
{
3754
0
    int c = 0, i;
3755
3756
0
    for (i = 0; i < len; i++) {
3757
0
        c |= p[i];
3758
0
    }
3759
0
    if (s->len + len > s->size) {
3760
0
        if (string_buffer_realloc(s, s->len + len, c))
3761
0
            return -1;
3762
0
    } else if (!s->is_wide_char && c >= 0x100) {
3763
0
        if (string_buffer_widen(s, s->size))
3764
0
            return -1;
3765
0
    }
3766
0
    if (s->is_wide_char) {
3767
0
        memcpy(&s->str->u.str16[s->len], p, len << 1);
3768
0
        s->len += len;
3769
0
    } else {
3770
0
        for (i = 0; i < len; i++) {
3771
0
            s->str->u.str8[s->len + i] = p[i];
3772
0
        }
3773
0
        s->len += len;
3774
0
    }
3775
0
    return 0;
3776
0
}
3777
3778
/* appending an ASCII string */
3779
static int string_buffer_puts8(StringBuffer *s, const char *str)
3780
0
{
3781
0
    return string_buffer_write8(s, (const uint8_t *)str, strlen(str));
3782
0
}
3783
3784
static int string_buffer_concat(StringBuffer *s, const JSString *p,
3785
                                uint32_t from, uint32_t to)
3786
0
{
3787
0
    if (to <= from)
3788
0
        return 0;
3789
0
    if (p->is_wide_char)
3790
0
        return string_buffer_write16(s, p->u.str16 + from, to - from);
3791
0
    else
3792
0
        return string_buffer_write8(s, p->u.str8 + from, to - from);
3793
0
}
3794
3795
static int string_buffer_concat_value(StringBuffer *s, JSValueConst v)
3796
0
{
3797
0
    JSString *p;
3798
0
    JSValue v1;
3799
0
    int res;
3800
3801
0
    if (s->error_status) {
3802
        /* prevent exception overload */
3803
0
        return -1;
3804
0
    }
3805
0
    if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
3806
0
        v1 = JS_ToString(s->ctx, v);
3807
0
        if (JS_IsException(v1))
3808
0
            return string_buffer_set_error(s);
3809
0
        p = JS_VALUE_GET_STRING(v1);
3810
0
        res = string_buffer_concat(s, p, 0, p->len);
3811
0
        JS_FreeValue(s->ctx, v1);
3812
0
        return res;
3813
0
    }
3814
0
    p = JS_VALUE_GET_STRING(v);
3815
0
    return string_buffer_concat(s, p, 0, p->len);
3816
0
}
3817
3818
static int string_buffer_concat_value_free(StringBuffer *s, JSValue v)
3819
0
{
3820
0
    JSString *p;
3821
0
    int res;
3822
3823
0
    if (s->error_status) {
3824
        /* prevent exception overload */
3825
0
        JS_FreeValue(s->ctx, v);
3826
0
        return -1;
3827
0
    }
3828
0
    if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
3829
0
        v = JS_ToStringFree(s->ctx, v);
3830
0
        if (JS_IsException(v))
3831
0
            return string_buffer_set_error(s);
3832
0
    }
3833
0
    p = JS_VALUE_GET_STRING(v);
3834
0
    res = string_buffer_concat(s, p, 0, p->len);
3835
0
    JS_FreeValue(s->ctx, v);
3836
0
    return res;
3837
0
}
3838
3839
static int string_buffer_fill(StringBuffer *s, int c, int count)
3840
0
{
3841
    /* XXX: optimize */
3842
0
    if (s->len + count > s->size) {
3843
0
        if (string_buffer_realloc(s, s->len + count, c))
3844
0
            return -1;
3845
0
    }
3846
0
    while (count-- > 0) {
3847
0
        if (string_buffer_putc16(s, c))
3848
0
            return -1;
3849
0
    }
3850
0
    return 0;
3851
0
}
3852
3853
static JSValue string_buffer_end(StringBuffer *s)
3854
116
{
3855
116
    JSString *str;
3856
116
    str = s->str;
3857
116
    if (s->error_status)
3858
0
        return JS_EXCEPTION;
3859
116
    if (s->len == 0) {
3860
2
        js_free(s->ctx, str);
3861
2
        s->str = NULL;
3862
2
        return JS_AtomToString(s->ctx, JS_ATOM_empty_string);
3863
2
    }
3864
114
    if (s->len < s->size) {
3865
        /* smaller size so js_realloc should not fail, but OK if it does */
3866
        /* XXX: should add some slack to avoid unnecessary calls */
3867
        /* XXX: might need to use malloc+free to ensure smaller size */
3868
114
        str = js_realloc_rt(s->ctx->rt, str, sizeof(JSString) +
3869
114
                            (s->len << s->is_wide_char) + 1 - s->is_wide_char);
3870
114
        if (str == NULL)
3871
0
            str = s->str;
3872
114
        s->str = str;
3873
114
    }
3874
114
    if (!s->is_wide_char)
3875
114
        str->u.str8[s->len] = 0;
3876
#ifdef DUMP_LEAKS
3877
    list_add_tail(&str->link, &s->ctx->rt->string_list);
3878
#endif
3879
114
    str->is_wide_char = s->is_wide_char;
3880
114
    str->len = s->len;
3881
114
    s->str = NULL;
3882
114
    return JS_MKPTR(JS_TAG_STRING, str);
3883
116
}
3884
3885
/* create a string from a UTF-8 buffer */
3886
JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)
3887
18.0k
{
3888
18.0k
    const uint8_t *p, *p_end, *p_start, *p_next;
3889
18.0k
    uint32_t c;
3890
18.0k
    StringBuffer b_s, *b = &b_s;
3891
18.0k
    size_t len1;
3892
3893
18.0k
    p_start = (const uint8_t *)buf;
3894
18.0k
    p_end = p_start + buf_len;
3895
18.0k
    p = p_start;
3896
2.26M
    while (p < p_end && *p < 128)
3897
2.24M
        p++;
3898
18.0k
    len1 = p - p_start;
3899
18.0k
    if (len1 > JS_STRING_LEN_MAX)
3900
0
        return JS_ThrowInternalError(ctx, "string too long");
3901
18.0k
    if (p == p_end) {
3902
        /* ASCII string */
3903
18.0k
        return js_new_string8(ctx, (const uint8_t *)buf, buf_len);
3904
18.0k
    } else {
3905
0
        if (string_buffer_init(ctx, b, buf_len))
3906
0
            goto fail;
3907
0
        string_buffer_write8(b, p_start, len1);
3908
0
        while (p < p_end) {
3909
0
            if (*p < 128) {
3910
0
                string_buffer_putc8(b, *p++);
3911
0
            } else {
3912
                /* parse utf-8 sequence, return 0xFFFFFFFF for error */
3913
0
                c = unicode_from_utf8(p, p_end - p, &p_next);
3914
0
                if (c < 0x10000) {
3915
0
                    p = p_next;
3916
0
                } else if (c <= 0x10FFFF) {
3917
0
                    p = p_next;
3918
                    /* surrogate pair */
3919
0
                    string_buffer_putc16(b, get_hi_surrogate(c));
3920
0
                    c = get_lo_surrogate(c);
3921
0
                } else {
3922
                    /* invalid char */
3923
0
                    c = 0xfffd;
3924
                    /* skip the invalid chars */
3925
                    /* XXX: seems incorrect. Why not just use c = *p++; ? */
3926
0
                    while (p < p_end && (*p >= 0x80 && *p < 0xc0))
3927
0
                        p++;
3928
0
                    if (p < p_end) {
3929
0
                        p++;
3930
0
                        while (p < p_end && (*p >= 0x80 && *p < 0xc0))
3931
0
                            p++;
3932
0
                    }
3933
0
                }
3934
0
                string_buffer_putc16(b, c);
3935
0
            }
3936
0
        }
3937
0
    }
3938
0
    return string_buffer_end(b);
3939
3940
0
 fail:
3941
0
    string_buffer_free(b);
3942
0
    return JS_EXCEPTION;
3943
18.0k
}
3944
3945
static JSValue JS_ConcatString3(JSContext *ctx, const char *str1,
3946
                                JSValue str2, const char *str3)
3947
0
{
3948
0
    StringBuffer b_s, *b = &b_s;
3949
0
    int len1, len3;
3950
0
    JSString *p;
3951
3952
0
    if (unlikely(JS_VALUE_GET_TAG(str2) != JS_TAG_STRING)) {
3953
0
        str2 = JS_ToStringFree(ctx, str2);
3954
0
        if (JS_IsException(str2))
3955
0
            goto fail;
3956
0
    }
3957
0
    p = JS_VALUE_GET_STRING(str2);
3958
0
    len1 = strlen(str1);
3959
0
    len3 = strlen(str3);
3960
3961
0
    if (string_buffer_init2(ctx, b, len1 + p->len + len3, p->is_wide_char))
3962
0
        goto fail;
3963
3964
0
    string_buffer_write8(b, (const uint8_t *)str1, len1);
3965
0
    string_buffer_concat(b, p, 0, p->len);
3966
0
    string_buffer_write8(b, (const uint8_t *)str3, len3);
3967
3968
0
    JS_FreeValue(ctx, str2);
3969
0
    return string_buffer_end(b);
3970
3971
0
 fail:
3972
0
    JS_FreeValue(ctx, str2);
3973
0
    return JS_EXCEPTION;
3974
0
}
3975
3976
JSValue JS_NewString(JSContext *ctx, const char *str)
3977
187
{
3978
187
    return JS_NewStringLen(ctx, str, strlen(str));
3979
187
}
3980
3981
JSValue JS_NewAtomString(JSContext *ctx, const char *str)
3982
312
{
3983
312
    JSAtom atom = JS_NewAtom(ctx, str);
3984
312
    if (atom == JS_ATOM_NULL)
3985
0
        return JS_EXCEPTION;
3986
312
    JSValue val = JS_AtomToString(ctx, atom);
3987
312
    JS_FreeAtom(ctx, atom);
3988
312
    return val;
3989
312
}
3990
3991
/* return (NULL, 0) if exception. */
3992
/* return pointer into a JSString with a live ref_count */
3993
/* cesu8 determines if non-BMP1 codepoints are encoded as 1 or 2 utf-8 sequences */
3994
const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, BOOL cesu8)
3995
213
{
3996
213
    JSValue val;
3997
213
    JSString *str, *str_new;
3998
213
    int pos, len, c, c1;
3999
213
    uint8_t *q;
4000
4001
213
    if (JS_VALUE_GET_TAG(val1) != JS_TAG_STRING) {
4002
0
        val = JS_ToString(ctx, val1);
4003
0
        if (JS_IsException(val))
4004
0
            goto fail;
4005
213
    } else {
4006
213
        val = JS_DupValue(ctx, val1);
4007
213
    }
4008
4009
213
    str = JS_VALUE_GET_STRING(val);
4010
213
    len = str->len;
4011
213
    if (!str->is_wide_char) {
4012
213
        const uint8_t *src = str->u.str8;
4013
213
        int count;
4014
4015
        /* count the number of non-ASCII characters */
4016
        /* Scanning the whole string is required for ASCII strings,
4017
           and computing the number of non-ASCII bytes is less expensive
4018
           than testing each byte, hence this method is faster for ASCII
4019
           strings, which is the most common case.
4020
         */
4021
213
        count = 0;
4022
1.33k
        for (pos = 0; pos < len; pos++) {
4023
1.12k
            count += src[pos] >> 7;
4024
1.12k
        }
4025
213
        if (count == 0) {
4026
213
            if (plen)
4027
0
                *plen = len;
4028
213
            return (const char *)src;
4029
213
        }
4030
0
        str_new = js_alloc_string(ctx, len + count, 0);
4031
0
        if (!str_new)
4032
0
            goto fail;
4033
0
        q = str_new->u.str8;
4034
0
        for (pos = 0; pos < len; pos++) {
4035
0
            c = src[pos];
4036
0
            if (c < 0x80) {
4037
0
                *q++ = c;
4038
0
            } else {
4039
0
                *q++ = (c >> 6) | 0xc0;
4040
0
                *q++ = (c & 0x3f) | 0x80;
4041
0
            }
4042
0
        }
4043
0
    } else {
4044
0
        const uint16_t *src = str->u.str16;
4045
        /* Allocate 3 bytes per 16 bit code point. Surrogate pairs may
4046
           produce 4 bytes but use 2 code points.
4047
         */
4048
0
        str_new = js_alloc_string(ctx, len * 3, 0);
4049
0
        if (!str_new)
4050
0
            goto fail;
4051
0
        q = str_new->u.str8;
4052
0
        pos = 0;
4053
0
        while (pos < len) {
4054
0
            c = src[pos++];
4055
0
            if (c < 0x80) {
4056
0
                *q++ = c;
4057
0
            } else {
4058
0
                if (is_hi_surrogate(c)) {
4059
0
                    if (pos < len && !cesu8) {
4060
0
                        c1 = src[pos];
4061
0
                        if (is_lo_surrogate(c1)) {
4062
0
                            pos++;
4063
0
                            c = from_surrogate(c, c1);
4064
0
                        } else {
4065
                            /* Keep unmatched surrogate code points */
4066
                            /* c = 0xfffd; */ /* error */
4067
0
                        }
4068
0
                    } else {
4069
                        /* Keep unmatched surrogate code points */
4070
                        /* c = 0xfffd; */ /* error */
4071
0
                    }
4072
0
                }
4073
0
                q += unicode_to_utf8(q, c);
4074
0
            }
4075
0
        }
4076
0
    }
4077
4078
0
    *q = '\0';
4079
0
    str_new->len = q - str_new->u.str8;
4080
0
    JS_FreeValue(ctx, val);
4081
0
    if (plen)
4082
0
        *plen = str_new->len;
4083
0
    return (const char *)str_new->u.str8;
4084
0
 fail:
4085
0
    if (plen)
4086
0
        *plen = 0;
4087
0
    return NULL;
4088
213
}
4089
4090
void JS_FreeCString(JSContext *ctx, const char *ptr)
4091
213
{
4092
213
    JSString *p;
4093
213
    if (!ptr)
4094
0
        return;
4095
    /* purposely removing constness */
4096
213
    p = container_of(ptr, JSString, u);
4097
213
    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
4098
213
}
4099
4100
static int memcmp16_8(const uint16_t *src1, const uint8_t *src2, int len)
4101
0
{
4102
0
    int c, i;
4103
0
    for(i = 0; i < len; i++) {
4104
0
        c = src1[i] - src2[i];
4105
0
        if (c != 0)
4106
0
            return c;
4107
0
    }
4108
0
    return 0;
4109
0
}
4110
4111
static int memcmp16(const uint16_t *src1, const uint16_t *src2, int len)
4112
0
{
4113
0
    int c, i;
4114
0
    for(i = 0; i < len; i++) {
4115
0
        c = src1[i] - src2[i];
4116
0
        if (c != 0)
4117
0
            return c;
4118
0
    }
4119
0
    return 0;
4120
0
}
4121
4122
static int js_string_memcmp(const JSString *p1, const JSString *p2, int len)
4123
19.3k
{
4124
19.3k
    int res;
4125
4126
19.3k
    if (likely(!p1->is_wide_char)) {
4127
19.3k
        if (likely(!p2->is_wide_char))
4128
19.3k
            res = memcmp(p1->u.str8, p2->u.str8, len);
4129
0
        else
4130
0
            res = -memcmp16_8(p2->u.str16, p1->u.str8, len);
4131
19.3k
    } else {
4132
0
        if (!p2->is_wide_char)
4133
0
            res = memcmp16_8(p1->u.str16, p2->u.str8, len);
4134
0
        else
4135
0
            res = memcmp16(p1->u.str16, p2->u.str16, len);
4136
0
    }
4137
19.3k
    return res;
4138
19.3k
}
4139
4140
/* return < 0, 0 or > 0 */
4141
static int js_string_compare(JSContext *ctx,
4142
                             const JSString *p1, const JSString *p2)
4143
19.2k
{
4144
19.2k
    int res, len;
4145
19.2k
    len = min_int(p1->len, p2->len);
4146
19.2k
    res = js_string_memcmp(p1, p2, len);
4147
19.2k
    if (res == 0) {
4148
234
        if (p1->len == p2->len)
4149
0
            res = 0;
4150
234
        else if (p1->len < p2->len)
4151
195
            res = -1;
4152
39
        else
4153
39
            res = 1;
4154
234
    }
4155
19.2k
    return res;
4156
19.2k
}
4157
4158
static void copy_str16(uint16_t *dst, const JSString *p, int offset, int len)
4159
0
{
4160
0
    if (p->is_wide_char) {
4161
0
        memcpy(dst, p->u.str16 + offset, len * 2);
4162
0
    } else {
4163
0
        const uint8_t *src1 = p->u.str8 + offset;
4164
0
        int i;
4165
4166
0
        for(i = 0; i < len; i++)
4167
0
            dst[i] = src1[i];
4168
0
    }
4169
0
}
4170
4171
static JSValue JS_ConcatString1(JSContext *ctx,
4172
                                const JSString *p1, const JSString *p2)
4173
0
{
4174
0
    JSString *p;
4175
0
    uint32_t len;
4176
0
    int is_wide_char;
4177
4178
0
    len = p1->len + p2->len;
4179
0
    if (len > JS_STRING_LEN_MAX)
4180
0
        return JS_ThrowInternalError(ctx, "string too long");
4181
0
    is_wide_char = p1->is_wide_char | p2->is_wide_char;
4182
0
    p = js_alloc_string(ctx, len, is_wide_char);
4183
0
    if (!p)
4184
0
        return JS_EXCEPTION;
4185
0
    if (!is_wide_char) {
4186
0
        memcpy(p->u.str8, p1->u.str8, p1->len);
4187
0
        memcpy(p->u.str8 + p1->len, p2->u.str8, p2->len);
4188
0
        p->u.str8[len] = '\0';
4189
0
    } else {
4190
0
        copy_str16(p->u.str16, p1, 0, p1->len);
4191
0
        copy_str16(p->u.str16 + p1->len, p2, 0, p2->len);
4192
0
    }
4193
0
    return JS_MKPTR(JS_TAG_STRING, p);
4194
0
}
4195
4196
1
static BOOL JS_ConcatStringInPlace(JSContext *ctx, JSString *p1, JSValueConst op2) {
4197
1
    if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
4198
1
        JSString *p2 = JS_VALUE_GET_STRING(op2);
4199
1
        size_t size1;
4200
4201
1
        if (p2->len == 0)
4202
1
            return TRUE;
4203
0
        if (p1->header.ref_count != 1)
4204
0
            return FALSE;
4205
0
        size1 = js_malloc_usable_size(ctx, p1);
4206
0
        if (p1->is_wide_char) {
4207
0
            if (size1 >= sizeof(*p1) + ((p1->len + p2->len) << 1)) {
4208
0
                if (p2->is_wide_char) {
4209
0
                    memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1);
4210
0
                    p1->len += p2->len;
4211
0
                    return TRUE;
4212
0
                } else {
4213
0
                    size_t i;
4214
0
                    for (i = 0; i < p2->len; i++) {
4215
0
                        p1->u.str16[p1->len++] = p2->u.str8[i];
4216
0
                    }
4217
0
                    return TRUE;
4218
0
                }
4219
0
            }
4220
0
        } else if (!p2->is_wide_char) {
4221
0
            if (size1 >= sizeof(*p1) + p1->len + p2->len + 1) {
4222
0
                memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len);
4223
0
                p1->len += p2->len;
4224
0
                p1->u.str8[p1->len] = '\0';
4225
0
                return TRUE;
4226
0
            }
4227
0
        }
4228
0
    }
4229
0
    return FALSE;
4230
1
}
4231
4232
/* op1 and op2 are converted to strings. For convenience, op1 or op2 =
4233
   JS_EXCEPTION are accepted and return JS_EXCEPTION.  */
4234
static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2)
4235
1
{
4236
1
    JSValue ret;
4237
1
    JSString *p1, *p2;
4238
4239
1
    if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING)) {
4240
1
        op1 = JS_ToStringFree(ctx, op1);
4241
1
        if (JS_IsException(op1)) {
4242
0
            JS_FreeValue(ctx, op2);
4243
0
            return JS_EXCEPTION;
4244
0
        }
4245
1
    }
4246
1
    if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING)) {
4247
0
        op2 = JS_ToStringFree(ctx, op2);
4248
0
        if (JS_IsException(op2)) {
4249
0
            JS_FreeValue(ctx, op1);
4250
0
            return JS_EXCEPTION;
4251
0
        }
4252
0
    }
4253
1
    p1 = JS_VALUE_GET_STRING(op1);
4254
1
    if (JS_ConcatStringInPlace(ctx, p1, op2)) {
4255
1
        JS_FreeValue(ctx, op2);
4256
1
        return op1;
4257
1
    }
4258
0
    p2 = JS_VALUE_GET_STRING(op2);
4259
0
    ret = JS_ConcatString1(ctx, p1, p2);
4260
0
    JS_FreeValue(ctx, op1);
4261
0
    JS_FreeValue(ctx, op2);
4262
0
    return ret;
4263
1
}
4264
4265
/* Shape support */
4266
4267
static inline size_t get_shape_size(size_t hash_size, size_t prop_size)
4268
20.1k
{
4269
20.1k
    return hash_size * sizeof(uint32_t) + sizeof(JSShape) +
4270
20.1k
        prop_size * sizeof(JSShapeProperty);
4271
20.1k
}
4272
4273
static inline JSShape *get_shape_from_alloc(void *sh_alloc, size_t hash_size)
4274
20.1k
{
4275
20.1k
    return (JSShape *)(void *)((uint32_t *)sh_alloc + hash_size);
4276
20.1k
}
4277
4278
static inline uint32_t *prop_hash_end(JSShape *sh)
4279
15.9M
{
4280
15.9M
    return (uint32_t *)sh;
4281
15.9M
}
4282
4283
static inline void *get_alloc_from_shape(JSShape *sh)
4284
23.7k
{
4285
23.7k
    return prop_hash_end(sh) - ((intptr_t)sh->prop_hash_mask + 1);
4286
23.7k
}
4287
4288
static inline JSShapeProperty *get_shape_prop(JSShape *sh)
4289
9.00M
{
4290
9.00M
    return sh->prop;
4291
9.00M
}
4292
4293
static int init_shape_hash(JSRuntime *rt)
4294
39
{
4295
39
    rt->shape_hash_bits = 4;   /* 16 shapes */
4296
39
    rt->shape_hash_size = 1 << rt->shape_hash_bits;
4297
39
    rt->shape_hash_count = 0;
4298
39
    rt->shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
4299
39
                                   rt->shape_hash_size);
4300
39
    if (!rt->shape_hash)
4301
0
        return -1;
4302
39
    return 0;
4303
39
}
4304
4305
/* same magic hash multiplier as the Linux kernel */
4306
static uint32_t shape_hash(uint32_t h, uint32_t val)
4307
184k
{
4308
184k
    return (h + val) * 0x9e370001;
4309
184k
}
4310
4311
/* truncate the shape hash to 'hash_bits' bits */
4312
static uint32_t get_shape_hash(uint32_t h, int hash_bits)
4313
141k
{
4314
141k
    return h >> (32 - hash_bits);
4315
141k
}
4316
4317
static uint32_t shape_initial_hash(JSObject *proto)
4318
17.5k
{
4319
17.5k
    uint32_t h;
4320
17.5k
    h = shape_hash(1, (uintptr_t)proto);
4321
17.5k
    if (sizeof(proto) > 4)
4322
17.5k
        h = shape_hash(h, (uint64_t)(uintptr_t)proto >> 32);
4323
17.5k
    return h;
4324
17.5k
}
4325
4326
static int resize_shape_hash(JSRuntime *rt, int new_shape_hash_bits)
4327
117
{
4328
117
    int new_shape_hash_size, i;
4329
117
    uint32_t h;
4330
117
    JSShape **new_shape_hash, *sh, *sh_next;
4331
4332
117
    new_shape_hash_size = 1 << new_shape_hash_bits;
4333
117
    new_shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
4334
117
                                   new_shape_hash_size);
4335
117
    if (!new_shape_hash)
4336
0
        return -1;
4337
4.48k
    for(i = 0; i < rt->shape_hash_size; i++) {
4338
6.55k
        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh_next) {
4339
2.18k
            sh_next = sh->shape_hash_next;
4340
2.18k
            h = get_shape_hash(sh->hash, new_shape_hash_bits);
4341
2.18k
            sh->shape_hash_next = new_shape_hash[h];
4342
2.18k
            new_shape_hash[h] = sh;
4343
2.18k
        }
4344
4.36k
    }
4345
117
    js_free_rt(rt, rt->shape_hash);
4346
117
    rt->shape_hash_bits = new_shape_hash_bits;
4347
117
    rt->shape_hash_size = new_shape_hash_size;
4348
117
    rt->shape_hash = new_shape_hash;
4349
117
    return 0;
4350
117
}
4351
4352
static void js_shape_hash_link(JSRuntime *rt, JSShape *sh)
4353
43.6k
{
4354
43.6k
    uint32_t h;
4355
43.6k
    h = get_shape_hash(sh->hash, rt->shape_hash_bits);
4356
43.6k
    sh->shape_hash_next = rt->shape_hash[h];
4357
43.6k
    rt->shape_hash[h] = sh;
4358
43.6k
    rt->shape_hash_count++;
4359
43.6k
}
4360
4361
static void js_shape_hash_unlink(JSRuntime *rt, JSShape *sh)
4362
43.6k
{
4363
43.6k
    uint32_t h;
4364
43.6k
    JSShape **psh;
4365
4366
43.6k
    h = get_shape_hash(sh->hash, rt->shape_hash_bits);
4367
43.6k
    psh = &rt->shape_hash[h];
4368
44.0k
    while (*psh != sh)
4369
440
        psh = &(*psh)->shape_hash_next;
4370
43.6k
    *psh = sh->shape_hash_next;
4371
43.6k
    rt->shape_hash_count--;
4372
43.6k
}
4373
4374
/* create a new empty shape with prototype 'proto' */
4375
static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto,
4376
                                        int hash_size, int prop_size)
4377
7.28k
{
4378
7.28k
    JSRuntime *rt = ctx->rt;
4379
7.28k
    void *sh_alloc;
4380
7.28k
    JSShape *sh;
4381
4382
    /* resize the shape hash table if necessary */
4383
7.28k
    if (2 * (rt->shape_hash_count + 1) > rt->shape_hash_size) {
4384
117
        resize_shape_hash(rt, rt->shape_hash_bits + 1);
4385
117
    }
4386
4387
7.28k
    sh_alloc = js_malloc(ctx, get_shape_size(hash_size, prop_size));
4388
7.28k
    if (!sh_alloc)
4389
0
        return NULL;
4390
7.28k
    sh = get_shape_from_alloc(sh_alloc, hash_size);
4391
7.28k
    sh->header.ref_count = 1;
4392
7.28k
    add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
4393
7.28k
    if (proto)
4394
7.24k
        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, proto));
4395
7.28k
    sh->proto = proto;
4396
7.28k
    memset(prop_hash_end(sh) - hash_size, 0, sizeof(prop_hash_end(sh)[0]) *
4397
7.28k
           hash_size);
4398
7.28k
    sh->prop_hash_mask = hash_size - 1;
4399
7.28k
    sh->prop_size = prop_size;
4400
7.28k
    sh->prop_count = 0;
4401
7.28k
    sh->deleted_prop_count = 0;
4402
4403
    /* insert in the hash table */
4404
7.28k
    sh->hash = shape_initial_hash(proto);
4405
7.28k
    sh->is_hashed = TRUE;
4406
7.28k
    sh->has_small_array_index = FALSE;
4407
7.28k
    js_shape_hash_link(ctx->rt, sh);
4408
7.28k
    return sh;
4409
7.28k
}
4410
4411
static JSShape *js_new_shape(JSContext *ctx, JSObject *proto)
4412
7.24k
{
4413
7.24k
    return js_new_shape2(ctx, proto, JS_PROP_INITIAL_HASH_SIZE,
4414
7.24k
                         JS_PROP_INITIAL_SIZE);
4415
7.24k
}
4416
4417
/* The shape is cloned. The new shape is not inserted in the shape
4418
   hash table */
4419
static JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1)
4420
3.57k
{
4421
3.57k
    JSShape *sh;
4422
3.57k
    void *sh_alloc, *sh_alloc1;
4423
3.57k
    size_t size;
4424
3.57k
    JSShapeProperty *pr;
4425
3.57k
    uint32_t i, hash_size;
4426
4427
3.57k
    hash_size = sh1->prop_hash_mask + 1;
4428
3.57k
    size = get_shape_size(hash_size, sh1->prop_size);
4429
3.57k
    sh_alloc = js_malloc(ctx, size);
4430
3.57k
    if (!sh_alloc)
4431
0
        return NULL;
4432
3.57k
    sh_alloc1 = get_alloc_from_shape(sh1);
4433
3.57k
    memcpy(sh_alloc, sh_alloc1, size);
4434
3.57k
    sh = get_shape_from_alloc(sh_alloc, hash_size);
4435
3.57k
    sh->header.ref_count = 1;
4436
3.57k
    add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
4437
3.57k
    sh->is_hashed = FALSE;
4438
3.57k
    if (sh->proto) {
4439
3.42k
        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
4440
3.42k
    }
4441
6.00k
    for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
4442
2.42k
        JS_DupAtom(ctx, pr->atom);
4443
2.42k
    }
4444
3.57k
    return sh;
4445
3.57k
}
4446
4447
static JSShape *js_dup_shape(JSShape *sh)
4448
12.2k
{
4449
12.2k
    sh->header.ref_count++;
4450
12.2k
    return sh;
4451
12.2k
}
4452
4453
static void js_free_shape0(JSRuntime *rt, JSShape *sh)
4454
10.8k
{
4455
10.8k
    uint32_t i;
4456
10.8k
    JSShapeProperty *pr;
4457
4458
10.8k
    assert(sh->header.ref_count == 0);
4459
10.8k
    if (sh->is_hashed)
4460
10.5k
        js_shape_hash_unlink(rt, sh);
4461
10.8k
    if (sh->proto != NULL) {
4462
10.6k
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
4463
10.6k
    }
4464
10.8k
    pr = get_shape_prop(sh);
4465
2.92M
    for(i = 0; i < sh->prop_count; i++) {
4466
2.91M
        JS_FreeAtomRT(rt, pr->atom);
4467
2.91M
        pr++;
4468
2.91M
    }
4469
10.8k
    remove_gc_object(&sh->header);
4470
10.8k
    js_free_rt(rt, get_alloc_from_shape(sh));
4471
10.8k
}
4472
4473
static void js_free_shape(JSRuntime *rt, JSShape *sh)
4474
23.1k
{
4475
23.1k
    if (unlikely(--sh->header.ref_count <= 0)) {
4476
10.8k
        js_free_shape0(rt, sh);
4477
10.8k
    }
4478
23.1k
}
4479
4480
static void js_free_shape_null(JSRuntime *rt, JSShape *sh)
4481
39
{
4482
39
    if (sh)
4483
39
        js_free_shape(rt, sh);
4484
39
}
4485
4486
/* make space to hold at least 'count' properties */
4487
static no_inline int resize_properties(JSContext *ctx, JSShape **psh,
4488
                                       JSObject *p, uint32_t count)
4489
9.30k
{
4490
9.30k
    JSShape *sh;
4491
9.30k
    uint32_t new_size, new_hash_size, new_hash_mask, i;
4492
9.30k
    JSShapeProperty *pr;
4493
9.30k
    void *sh_alloc;
4494
9.30k
    intptr_t h;
4495
9.30k
    JSShape *old_sh;
4496
4497
9.30k
    sh = *psh;
4498
9.30k
    new_size = max_int(count, sh->prop_size * 3 / 2);
4499
    /* Reallocate prop array first to avoid crash or size inconsistency
4500
       in case of memory allocation failure */
4501
9.30k
    if (p) {
4502
9.30k
        JSProperty *new_prop;
4503
9.30k
        new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
4504
9.30k
        if (unlikely(!new_prop))
4505
0
            return -1;
4506
9.30k
        p->prop = new_prop;
4507
9.30k
    }
4508
9.30k
    new_hash_size = sh->prop_hash_mask + 1;
4509
13.1k
    while (new_hash_size < new_size)
4510
3.81k
        new_hash_size = 2 * new_hash_size;
4511
    /* resize the property shapes. Using js_realloc() is not possible in
4512
       case the GC runs during the allocation */
4513
9.30k
    old_sh = sh;
4514
9.30k
    sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
4515
9.30k
    if (!sh_alloc)
4516
0
        return -1;
4517
9.30k
    sh = get_shape_from_alloc(sh_alloc, new_hash_size);
4518
9.30k
    list_del(&old_sh->header.link);
4519
    /* copy all the shape properties */
4520
9.30k
    memcpy(sh, old_sh,
4521
9.30k
           sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count);
4522
9.30k
    list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
4523
4524
9.30k
    if (new_hash_size != (sh->prop_hash_mask + 1)) {
4525
        /* resize the hash table and the properties */
4526
3.72k
        new_hash_mask = new_hash_size - 1;
4527
3.72k
        sh->prop_hash_mask = new_hash_mask;
4528
3.72k
        memset(prop_hash_end(sh) - new_hash_size, 0,
4529
3.72k
               sizeof(prop_hash_end(sh)[0]) * new_hash_size);
4530
3.54M
        for(i = 0, pr = sh->prop; i < sh->prop_count; i++, pr++) {
4531
3.54M
            if (pr->atom != JS_ATOM_NULL) {
4532
3.54M
                h = ((uintptr_t)pr->atom & new_hash_mask);
4533
3.54M
                pr->hash_next = prop_hash_end(sh)[-h - 1];
4534
3.54M
                prop_hash_end(sh)[-h - 1] = i + 1;
4535
3.54M
            }
4536
3.54M
        }
4537
5.57k
    } else {
4538
        /* just copy the previous hash table */
4539
5.57k
        memcpy(prop_hash_end(sh) - new_hash_size, prop_hash_end(old_sh) - new_hash_size,
4540
5.57k
               sizeof(prop_hash_end(sh)[0]) * new_hash_size);
4541
5.57k
    }
4542
9.30k
    js_free(ctx, get_alloc_from_shape(old_sh));
4543
9.30k
    *psh = sh;
4544
9.30k
    sh->prop_size = new_size;
4545
9.30k
    return 0;
4546
9.30k
}
4547
4548
/* remove the deleted properties. */
4549
static int compact_properties(JSContext *ctx, JSObject *p)
4550
0
{
4551
0
    JSShape *sh, *old_sh;
4552
0
    void *sh_alloc;
4553
0
    intptr_t h;
4554
0
    uint32_t new_hash_size, i, j, new_hash_mask, new_size;
4555
0
    JSShapeProperty *old_pr, *pr;
4556
0
    JSProperty *prop, *new_prop;
4557
4558
0
    sh = p->shape;
4559
0
    assert(!sh->is_hashed);
4560
4561
0
    new_size = max_int(JS_PROP_INITIAL_SIZE,
4562
0
                       sh->prop_count - sh->deleted_prop_count);
4563
0
    assert(new_size <= sh->prop_size);
4564
4565
0
    new_hash_size = sh->prop_hash_mask + 1;
4566
0
    while ((new_hash_size / 2) >= new_size)
4567
0
        new_hash_size = new_hash_size / 2;
4568
0
    new_hash_mask = new_hash_size - 1;
4569
4570
    /* resize the hash table and the properties */
4571
0
    old_sh = sh;
4572
0
    sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
4573
0
    if (!sh_alloc)
4574
0
        return -1;
4575
0
    sh = get_shape_from_alloc(sh_alloc, new_hash_size);
4576
0
    list_del(&old_sh->header.link);
4577
0
    memcpy(sh, old_sh, sizeof(JSShape));
4578
0
    list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
4579
4580
0
    memset(prop_hash_end(sh) - new_hash_size, 0,
4581
0
           sizeof(prop_hash_end(sh)[0]) * new_hash_size);
4582
4583
0
    j = 0;
4584
0
    old_pr = old_sh->prop;
4585
0
    pr = sh->prop;
4586
0
    prop = p->prop;
4587
0
    for(i = 0; i < sh->prop_count; i++) {
4588
0
        if (old_pr->atom != JS_ATOM_NULL) {
4589
0
            pr->atom = old_pr->atom;
4590
0
            pr->flags = old_pr->flags;
4591
0
            h = ((uintptr_t)old_pr->atom & new_hash_mask);
4592
0
            pr->hash_next = prop_hash_end(sh)[-h - 1];
4593
0
            prop_hash_end(sh)[-h - 1] = j + 1;
4594
0
            prop[j] = prop[i];
4595
0
            j++;
4596
0
            pr++;
4597
0
        }
4598
0
        old_pr++;
4599
0
    }
4600
0
    assert(j == (sh->prop_count - sh->deleted_prop_count));
4601
0
    sh->prop_hash_mask = new_hash_mask;
4602
0
    sh->prop_size = new_size;
4603
0
    sh->deleted_prop_count = 0;
4604
0
    sh->prop_count = j;
4605
4606
0
    p->shape = sh;
4607
0
    js_free(ctx, get_alloc_from_shape(old_sh));
4608
4609
    /* reduce the size of the object properties */
4610
0
    new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
4611
0
    if (new_prop)
4612
0
        p->prop = new_prop;
4613
0
    return 0;
4614
0
}
4615
4616
static int add_shape_property(JSContext *ctx, JSShape **psh,
4617
                              JSObject *p, JSAtom atom, int prop_flags)
4618
2.90M
{
4619
2.90M
    JSRuntime *rt = ctx->rt;
4620
2.90M
    JSShape *sh = *psh;
4621
2.90M
    JSShapeProperty *pr, *prop;
4622
2.90M
    uint32_t hash_mask, new_shape_hash = 0;
4623
2.90M
    intptr_t h;
4624
4625
    /* update the shape hash */
4626
2.90M
    if (sh->is_hashed) {
4627
32.8k
        js_shape_hash_unlink(rt, sh);
4628
32.8k
        new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags);
4629
32.8k
    }
4630
4631
2.90M
    if (unlikely(sh->prop_count >= sh->prop_size)) {
4632
9.30k
        if (resize_properties(ctx, psh, p, sh->prop_count + 1)) {
4633
            /* in case of error, reinsert in the hash table.
4634
               sh is still valid if resize_properties() failed */
4635
0
            if (sh->is_hashed)
4636
0
                js_shape_hash_link(rt, sh);
4637
0
            return -1;
4638
0
        }
4639
9.30k
        sh = *psh;
4640
9.30k
    }
4641
2.90M
    if (sh->is_hashed) {
4642
32.8k
        sh->hash = new_shape_hash;
4643
32.8k
        js_shape_hash_link(rt, sh);
4644
32.8k
    }
4645
    /* Initialize the new shape property.
4646
       The object property at p->prop[sh->prop_count] is uninitialized */
4647
2.90M
    prop = get_shape_prop(sh);
4648
2.90M
    pr = &prop[sh->prop_count++];
4649
2.90M
    pr->atom = JS_DupAtom(ctx, atom);
4650
2.90M
    pr->flags = prop_flags;
4651
2.90M
    sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom);
4652
    /* add in hash table */
4653
2.90M
    hash_mask = sh->prop_hash_mask;
4654
2.90M
    h = atom & hash_mask;
4655
2.90M
    pr->hash_next = prop_hash_end(sh)[-h - 1];
4656
2.90M
    prop_hash_end(sh)[-h - 1] = sh->prop_count;
4657
2.90M
    return 0;
4658
2.90M
}
4659
4660
/* find a hashed empty shape matching the prototype. Return NULL if
4661
   not found */
4662
static JSShape *find_hashed_shape_proto(JSRuntime *rt, JSObject *proto)
4663
10.2k
{
4664
10.2k
    JSShape *sh1;
4665
10.2k
    uint32_t h, h1;
4666
4667
10.2k
    h = shape_initial_hash(proto);
4668
10.2k
    h1 = get_shape_hash(h, rt->shape_hash_bits);
4669
13.4k
    for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
4670
6.25k
        if (sh1->hash == h &&
4671
6.25k
            sh1->proto == proto &&
4672
6.25k
            sh1->prop_count == 0) {
4673
3.02k
            return sh1;
4674
3.02k
        }
4675
6.25k
    }
4676
7.24k
    return NULL;
4677
10.2k
}
4678
4679
/* find a hashed shape matching sh + (prop, prop_flags). Return NULL if
4680
   not found */
4681
static JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh,
4682
                                       JSAtom atom, int prop_flags)
4683
41.9k
{
4684
41.9k
    JSShape *sh1;
4685
41.9k
    uint32_t h, h1, i, n;
4686
4687
41.9k
    h = sh->hash;
4688
41.9k
    h = shape_hash(h, atom);
4689
41.9k
    h = shape_hash(h, prop_flags);
4690
41.9k
    h1 = get_shape_hash(h, rt->shape_hash_bits);
4691
57.3k
    for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
4692
        /* we test the hash first so that the rest is done only if the
4693
           shapes really match */
4694
24.5k
        if (sh1->hash == h &&
4695
24.5k
            sh1->proto == sh->proto &&
4696
24.5k
            sh1->prop_count == ((n = sh->prop_count) + 1)) {
4697
21.1k
            for(i = 0; i < n; i++) {
4698
11.9k
                if (unlikely(sh1->prop[i].atom != sh->prop[i].atom) ||
4699
11.9k
                    unlikely(sh1->prop[i].flags != sh->prop[i].flags))
4700
0
                    goto next;
4701
11.9k
            }
4702
9.18k
            if (unlikely(sh1->prop[n].atom != atom) ||
4703
9.18k
                unlikely(sh1->prop[n].flags != prop_flags))
4704
0
                goto next;
4705
9.18k
            return sh1;
4706
9.18k
        }
4707
15.3k
    next: ;
4708
15.3k
    }
4709
32.7k
    return NULL;
4710
41.9k
}
4711
4712
static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
4713
0
{
4714
0
    char atom_buf[ATOM_GET_STR_BUF_SIZE];
4715
0
    int j;
4716
0
4717
0
    /* XXX: should output readable class prototype */
4718
0
    printf("%5d %3d%c %14p %5d %5d", i,
4719
0
           sh->header.ref_count, " *"[sh->is_hashed],
4720
0
           (void *)sh->proto, sh->prop_size, sh->prop_count);
4721
0
    for(j = 0; j < sh->prop_count; j++) {
4722
0
        printf(" %s", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf),
4723
0
                                      sh->prop[j].atom));
4724
0
    }
4725
0
    printf("\n");
4726
0
}
4727
4728
static __maybe_unused void JS_DumpShapes(JSRuntime *rt)
4729
0
{
4730
0
    int i;
4731
0
    JSShape *sh;
4732
0
    struct list_head *el;
4733
0
    JSObject *p;
4734
0
    JSGCObjectHeader *gp;
4735
0
4736
0
    printf("JSShapes: {\n");
4737
0
    printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS");
4738
0
    for(i = 0; i < rt->shape_hash_size; i++) {
4739
0
        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
4740
0
            JS_DumpShape(rt, i, sh);
4741
0
            assert(sh->is_hashed);
4742
0
        }
4743
0
    }
4744
0
    /* dump non-hashed shapes */
4745
0
    list_for_each(el, &rt->gc_obj_list) {
4746
0
        gp = list_entry(el, JSGCObjectHeader, link);
4747
0
        if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
4748
0
            p = (JSObject *)gp;
4749
0
            if (!p->shape->is_hashed) {
4750
0
                JS_DumpShape(rt, -1, p->shape);
4751
0
            }
4752
0
        }
4753
0
    }
4754
0
    printf("}\n");
4755
0
}
4756
4757
static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID class_id)
4758
10.3k
{
4759
10.3k
    JSObject *p;
4760
4761
10.3k
    js_trigger_gc(ctx->rt, sizeof(JSObject));
4762
10.3k
    p = js_malloc(ctx, sizeof(JSObject));
4763
10.3k
    if (unlikely(!p))
4764
0
        goto fail;
4765
10.3k
    p->class_id = class_id;
4766
10.3k
    p->extensible = TRUE;
4767
10.3k
    p->free_mark = 0;
4768
10.3k
    p->is_exotic = 0;
4769
10.3k
    p->fast_array = 0;
4770
10.3k
    p->is_constructor = 0;
4771
10.3k
    p->is_uncatchable_error = 0;
4772
10.3k
    p->tmp_mark = 0;
4773
10.3k
    p->is_HTMLDDA = 0;
4774
10.3k
    p->first_weak_ref = NULL;
4775
10.3k
    p->u.opaque = NULL;
4776
10.3k
    p->shape = sh;
4777
10.3k
    p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size);
4778
10.3k
    if (unlikely(!p->prop)) {
4779
0
        js_free(ctx, p);
4780
0
    fail:
4781
0
        js_free_shape(ctx->rt, sh);
4782
0
        return JS_EXCEPTION;
4783
0
    }
4784
4785
10.3k
    switch(class_id) {
4786
2.22k
    case JS_CLASS_OBJECT:
4787
2.22k
        break;
4788
91
    case JS_CLASS_ARRAY:
4789
91
        {
4790
91
            JSProperty *pr;
4791
91
            p->is_exotic = 1;
4792
91
            p->fast_array = 1;
4793
91
            p->u.array.u.values = NULL;
4794
91
            p->u.array.count = 0;
4795
91
            p->u.array.u1.size = 0;
4796
            /* the length property is always the first one */
4797
91
            if (likely(sh == ctx->array_shape)) {
4798
52
                pr = &p->prop[0];
4799
52
            } else {
4800
                /* only used for the first array */
4801
                /* cannot fail */
4802
39
                pr = add_property(ctx, p, JS_ATOM_length,
4803
39
                                  JS_PROP_WRITABLE | JS_PROP_LENGTH);
4804
39
            }
4805
91
            pr->u.value = JS_NewInt32(ctx, 0);
4806
91
        }
4807
91
        break;
4808
7.02k
    case JS_CLASS_C_FUNCTION:
4809
7.02k
        p->prop[0].u.value = JS_UNDEFINED;
4810
7.02k
        break;
4811
0
    case JS_CLASS_ARGUMENTS:
4812
0
    case JS_CLASS_UINT8C_ARRAY:
4813
0
    case JS_CLASS_INT8_ARRAY:
4814
0
    case JS_CLASS_UINT8_ARRAY:
4815
0
    case JS_CLASS_INT16_ARRAY:
4816
0
    case JS_CLASS_UINT16_ARRAY:
4817
0
    case JS_CLASS_INT32_ARRAY:
4818
0
    case JS_CLASS_UINT32_ARRAY:
4819
0
    case JS_CLASS_BIG_INT64_ARRAY:
4820
0
    case JS_CLASS_BIG_UINT64_ARRAY:
4821
0
    case JS_CLASS_FLOAT32_ARRAY:
4822
0
    case JS_CLASS_FLOAT64_ARRAY:
4823
0
        p->is_exotic = 1;
4824
0
        p->fast_array = 1;
4825
0
        p->u.array.u.ptr = NULL;
4826
0
        p->u.array.count = 0;
4827
0
        break;
4828
0
    case JS_CLASS_DATAVIEW:
4829
0
        p->u.array.u.ptr = NULL;
4830
0
        p->u.array.count = 0;
4831
0
        break;
4832
39
    case JS_CLASS_NUMBER:
4833
78
    case JS_CLASS_STRING:
4834
117
    case JS_CLASS_BOOLEAN:
4835
117
    case JS_CLASS_SYMBOL:
4836
117
    case JS_CLASS_DATE:
4837
117
    case JS_CLASS_BIG_INT:
4838
117
#ifdef CONFIG_BIGNUM
4839
117
    case JS_CLASS_BIG_FLOAT:
4840
117
    case JS_CLASS_BIG_DECIMAL:
4841
117
#endif
4842
117
        p->u.object_data = JS_UNDEFINED;
4843
117
        goto set_exotic;
4844
0
    case JS_CLASS_REGEXP:
4845
0
        p->u.regexp.pattern = NULL;
4846
0
        p->u.regexp.bytecode = NULL;
4847
0
        goto set_exotic;
4848
869
    default:
4849
986
    set_exotic:
4850
986
        if (ctx->rt->class_array[class_id].exotic) {
4851
117
            p->is_exotic = 1;
4852
117
        }
4853
986
        break;
4854
10.3k
    }
4855
10.3k
    p->header.ref_count = 1;
4856
10.3k
    add_gc_object(ctx->rt, &p->header, JS_GC_OBJ_TYPE_JS_OBJECT);
4857
10.3k
    return JS_MKPTR(JS_TAG_OBJECT, p);
4858
10.3k
}
4859
4860
static JSObject *get_proto_obj(JSValueConst proto_val)
4861
10.3k
{
4862
10.3k
    if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT)
4863
429
        return NULL;
4864
9.87k
    else
4865
9.87k
        return JS_VALUE_GET_OBJ(proto_val);
4866
10.3k
}
4867
4868
/* WARNING: proto must be an object or JS_NULL */
4869
JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto_val,
4870
                               JSClassID class_id)
4871
10.2k
{
4872
10.2k
    JSShape *sh;
4873
10.2k
    JSObject *proto;
4874
4875
10.2k
    proto = get_proto_obj(proto_val);
4876
10.2k
    sh = find_hashed_shape_proto(ctx->rt, proto);
4877
10.2k
    if (likely(sh)) {
4878
3.02k
        sh = js_dup_shape(sh);
4879
7.24k
    } else {
4880
7.24k
        sh = js_new_shape(ctx, proto);
4881
7.24k
        if (!sh)
4882
0
            return JS_EXCEPTION;
4883
7.24k
    }
4884
10.2k
    return JS_NewObjectFromShape(ctx, sh, class_id);
4885
10.2k
}
4886
4887
#if 0
4888
static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj)
4889
{
4890
    JSObject *p;
4891
4892
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
4893
        p = JS_VALUE_GET_OBJ(obj);
4894
        switch(p->class_id) {
4895
        case JS_CLASS_NUMBER:
4896
        case JS_CLASS_STRING:
4897
        case JS_CLASS_BOOLEAN:
4898
        case JS_CLASS_SYMBOL:
4899
        case JS_CLASS_DATE:
4900
        case JS_CLASS_BIG_INT:
4901
#ifdef CONFIG_BIGNUM
4902
        case JS_CLASS_BIG_FLOAT:
4903
        case JS_CLASS_BIG_DECIMAL:
4904
#endif
4905
            return JS_DupValue(ctx, p->u.object_data);
4906
        }
4907
    }
4908
    return JS_UNDEFINED;
4909
}
4910
#endif
4911
4912
static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val)
4913
117
{
4914
117
    JSObject *p;
4915
4916
117
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
4917
117
        p = JS_VALUE_GET_OBJ(obj);
4918
117
        switch(p->class_id) {
4919
39
        case JS_CLASS_NUMBER:
4920
78
        case JS_CLASS_STRING:
4921
117
        case JS_CLASS_BOOLEAN:
4922
117
        case JS_CLASS_SYMBOL:
4923
117
        case JS_CLASS_DATE:
4924
117
        case JS_CLASS_BIG_INT:
4925
117
#ifdef CONFIG_BIGNUM
4926
117
        case JS_CLASS_BIG_FLOAT:
4927
117
        case JS_CLASS_BIG_DECIMAL:
4928
117
#endif
4929
117
            JS_FreeValue(ctx, p->u.object_data);
4930
117
            p->u.object_data = val;
4931
117
            return 0;
4932
117
        }
4933
117
    }
4934
0
    JS_FreeValue(ctx, val);
4935
0
    if (!JS_IsException(obj))
4936
0
        JS_ThrowTypeError(ctx, "invalid object type");
4937
0
    return -1;
4938
117
}
4939
4940
JSValue JS_NewObjectClass(JSContext *ctx, int class_id)
4941
219
{
4942
219
    return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id);
4943
219
}
4944
4945
JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto)
4946
1.28k
{
4947
1.28k
    return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT);
4948
1.28k
}
4949
4950
JSValue JS_NewArray(JSContext *ctx)
4951
52
{
4952
52
    return JS_NewObjectFromShape(ctx, js_dup_shape(ctx->array_shape),
4953
52
                                 JS_CLASS_ARRAY);
4954
52
}
4955
4956
JSValue JS_NewObject(JSContext *ctx)
4957
936
{
4958
    /* inline JS_NewObjectClass(ctx, JS_CLASS_OBJECT); */
4959
936
    return JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT);
4960
936
}
4961
4962
static void js_function_set_properties(JSContext *ctx, JSValueConst func_obj,
4963
                                       JSAtom name, int len)
4964
7.27k
{
4965
    /* ES6 feature non compatible with ES5.1: length is configurable */
4966
7.27k
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, JS_NewInt32(ctx, len),
4967
7.27k
                           JS_PROP_CONFIGURABLE);
4968
7.27k
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name,
4969
7.27k
                           JS_AtomToString(ctx, name), JS_PROP_CONFIGURABLE);
4970
7.27k
}
4971
4972
static BOOL js_class_has_bytecode(JSClassID class_id)
4973
18
{
4974
18
    return (class_id == JS_CLASS_BYTECODE_FUNCTION ||
4975
18
            class_id == JS_CLASS_GENERATOR_FUNCTION ||
4976
18
            class_id == JS_CLASS_ASYNC_FUNCTION ||
4977
18
            class_id == JS_CLASS_ASYNC_GENERATOR_FUNCTION);
4978
18
}
4979
4980
/* return NULL without exception if not a function or no bytecode */
4981
static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val)
4982
9
{
4983
9
    JSObject *p;
4984
9
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
4985
0
        return NULL;
4986
9
    p = JS_VALUE_GET_OBJ(val);
4987
9
    if (!js_class_has_bytecode(p->class_id))
4988
0
        return NULL;
4989
9
    return p->u.func.function_bytecode;
4990
9
}
4991
4992
static void js_method_set_home_object(JSContext *ctx, JSValueConst func_obj,
4993
                                      JSValueConst home_obj)
4994
0
{
4995
0
    JSObject *p, *p1;
4996
0
    JSFunctionBytecode *b;
4997
4998
0
    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
4999
0
        return;
5000
0
    p = JS_VALUE_GET_OBJ(func_obj);
5001
0
    if (!js_class_has_bytecode(p->class_id))
5002
0
        return;
5003
0
    b = p->u.func.function_bytecode;
5004
0
    if (b->need_home_object) {
5005
0
        p1 = p->u.func.home_object;
5006
0
        if (p1) {
5007
0
            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
5008
0
        }
5009
0
        if (JS_VALUE_GET_TAG(home_obj) == JS_TAG_OBJECT)
5010
0
            p1 = JS_VALUE_GET_OBJ(JS_DupValue(ctx, home_obj));
5011
0
        else
5012
0
            p1 = NULL;
5013
0
        p->u.func.home_object = p1;
5014
0
    }
5015
0
}
5016
5017
static JSValue js_get_function_name(JSContext *ctx, JSAtom name)
5018
0
{
5019
0
    JSValue name_str;
5020
5021
0
    name_str = JS_AtomToString(ctx, name);
5022
0
    if (JS_AtomSymbolHasDescription(ctx, name)) {
5023
0
        name_str = JS_ConcatString3(ctx, "[", name_str, "]");
5024
0
    }
5025
0
    return name_str;
5026
0
}
5027
5028
/* Modify the name of a method according to the atom and
5029
   'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and
5030
   JS_PROP_HAS_SET. Also set the home object of the method.
5031
   Return < 0 if exception. */
5032
static int js_method_set_properties(JSContext *ctx, JSValueConst func_obj,
5033
                                    JSAtom name, int flags, JSValueConst home_obj)
5034
0
{
5035
0
    JSValue name_str;
5036
5037
0
    name_str = js_get_function_name(ctx, name);
5038
0
    if (flags & JS_PROP_HAS_GET) {
5039
0
        name_str = JS_ConcatString3(ctx, "get ", name_str, "");
5040
0
    } else if (flags & JS_PROP_HAS_SET) {
5041
0
        name_str = JS_ConcatString3(ctx, "set ", name_str, "");
5042
0
    }
5043
0
    if (JS_IsException(name_str))
5044
0
        return -1;
5045
0
    if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name_str,
5046
0
                               JS_PROP_CONFIGURABLE) < 0)
5047
0
        return -1;
5048
0
    js_method_set_home_object(ctx, func_obj, home_obj);
5049
0
    return 0;
5050
0
}
5051
5052
/* Note: at least 'length' arguments will be readable in 'argv' */
5053
static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
5054
                                const char *name,
5055
                                int length, JSCFunctionEnum cproto, int magic,
5056
                                JSValueConst proto_val)
5057
7.02k
{
5058
7.02k
    JSValue func_obj;
5059
7.02k
    JSObject *p;
5060
7.02k
    JSAtom name_atom;
5061
5062
7.02k
    func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION);
5063
7.02k
    if (JS_IsException(func_obj))
5064
0
        return func_obj;
5065
7.02k
    p = JS_VALUE_GET_OBJ(func_obj);
5066
7.02k
    p->u.cfunc.realm = JS_DupContext(ctx);
5067
7.02k
    p->u.cfunc.c_function.generic = func;
5068
7.02k
    p->u.cfunc.length = length;
5069
7.02k
    p->u.cfunc.cproto = cproto;
5070
7.02k
    p->u.cfunc.magic = magic;
5071
7.02k
    p->is_constructor = (cproto == JS_CFUNC_constructor ||
5072
7.02k
                         cproto == JS_CFUNC_constructor_magic ||
5073
7.02k
                         cproto == JS_CFUNC_constructor_or_func ||
5074
7.02k
                         cproto == JS_CFUNC_constructor_or_func_magic);
5075
7.02k
    if (!name)
5076
78
        name = "";
5077
7.02k
    name_atom = JS_NewAtom(ctx, name);
5078
7.02k
    js_function_set_properties(ctx, func_obj, name_atom, length);
5079
7.02k
    JS_FreeAtom(ctx, name_atom);
5080
7.02k
    return func_obj;
5081
7.02k
}
5082
5083
/* Note: at least 'length' arguments will be readable in 'argv' */
5084
JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
5085
                         const char *name,
5086
                         int length, JSCFunctionEnum cproto, int magic)
5087
6.16k
{
5088
6.16k
    return JS_NewCFunction3(ctx, func, name, length, cproto, magic,
5089
6.16k
                            ctx->function_proto);
5090
6.16k
}
5091
5092
typedef struct JSCFunctionDataRecord {
5093
    JSCFunctionData *func;
5094
    uint8_t length;
5095
    uint8_t data_len;
5096
    uint16_t magic;
5097
    JSValue data[0];
5098
} JSCFunctionDataRecord;
5099
5100
static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val)
5101
78
{
5102
78
    JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
5103
78
    int i;
5104
5105
78
    if (s) {
5106
234
        for(i = 0; i < s->data_len; i++) {
5107
156
            JS_FreeValueRT(rt, s->data[i]);
5108
156
        }
5109
78
        js_free_rt(rt, s);
5110
78
    }
5111
78
}
5112
5113
static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
5114
                                    JS_MarkFunc *mark_func)
5115
0
{
5116
0
    JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
5117
0
    int i;
5118
5119
0
    if (s) {
5120
0
        for(i = 0; i < s->data_len; i++) {
5121
0
            JS_MarkValue(rt, s->data[i], mark_func);
5122
0
        }
5123
0
    }
5124
0
}
5125
5126
static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
5127
                                       JSValueConst this_val,
5128
                                       int argc, JSValueConst *argv, int flags)
5129
78
{
5130
78
    JSCFunctionDataRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA);
5131
78
    JSValueConst *arg_buf;
5132
78
    int i;
5133
5134
    /* XXX: could add the function on the stack for debug */
5135
78
    if (unlikely(argc < s->length)) {
5136
0
        arg_buf = alloca(sizeof(arg_buf[0]) * s->length);
5137
0
        for(i = 0; i < argc; i++)
5138
0
            arg_buf[i] = argv[i];
5139
0
        for(i = argc; i < s->length; i++)
5140
0
            arg_buf[i] = JS_UNDEFINED;
5141
78
    } else {
5142
78
        arg_buf = argv;
5143
78
    }
5144
5145
78
    return s->func(ctx, this_val, argc, arg_buf, s->magic, s->data);
5146
78
}
5147
5148
JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
5149
                            int length, int magic, int data_len,
5150
                            JSValueConst *data)
5151
78
{
5152
78
    JSCFunctionDataRecord *s;
5153
78
    JSValue func_obj;
5154
78
    int i;
5155
5156
78
    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
5157
78
                                      JS_CLASS_C_FUNCTION_DATA);
5158
78
    if (JS_IsException(func_obj))
5159
0
        return func_obj;
5160
78
    s = js_malloc(ctx, sizeof(*s) + data_len * sizeof(JSValue));
5161
78
    if (!s) {
5162
0
        JS_FreeValue(ctx, func_obj);
5163
0
        return JS_EXCEPTION;
5164
0
    }
5165
78
    s->func = func;
5166
78
    s->length = length;
5167
78
    s->data_len = data_len;
5168
78
    s->magic = magic;
5169
234
    for(i = 0; i < data_len; i++)
5170
156
        s->data[i] = JS_DupValue(ctx, data[i]);
5171
78
    JS_SetOpaque(func_obj, s);
5172
78
    js_function_set_properties(ctx, func_obj,
5173
78
                               JS_ATOM_empty_string, length);
5174
78
    return func_obj;
5175
78
}
5176
5177
static JSContext *js_autoinit_get_realm(JSProperty *pr)
5178
79.4k
{
5179
79.4k
    return (JSContext *)(pr->u.init.realm_and_id & ~3);
5180
79.4k
}
5181
5182
static JSAutoInitIDEnum js_autoinit_get_id(JSProperty *pr)
5183
390
{
5184
390
    return pr->u.init.realm_and_id & 3;
5185
390
}
5186
5187
static void js_autoinit_free(JSRuntime *rt, JSProperty *pr)
5188
16.9k
{
5189
16.9k
    JS_FreeContext(js_autoinit_get_realm(pr));
5190
16.9k
}
5191
5192
static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr,
5193
                             JS_MarkFunc *mark_func)
5194
62.0k
{
5195
62.0k
    mark_func(rt, &js_autoinit_get_realm(pr)->header);
5196
62.0k
}
5197
5198
static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags)
5199
2.91M
{
5200
2.91M
    if (unlikely(prop_flags & JS_PROP_TMASK)) {
5201
22.4k
        if ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
5202
2.02k
            if (pr->u.getset.getter)
5203
2.02k
                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
5204
2.02k
            if (pr->u.getset.setter)
5205
507
                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
5206
20.3k
        } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
5207
3.82k
            free_var_ref(rt, pr->u.var_ref);
5208
16.5k
        } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
5209
16.5k
            js_autoinit_free(rt, pr);
5210
16.5k
        }
5211
2.89M
    } else {
5212
2.89M
        JS_FreeValueRT(rt, pr->u.value);
5213
2.89M
    }
5214
2.91M
}
5215
5216
static force_inline JSShapeProperty *find_own_property1(JSObject *p,
5217
                                                        JSAtom atom)
5218
9
{
5219
9
    JSShape *sh;
5220
9
    JSShapeProperty *pr, *prop;
5221
9
    intptr_t h;
5222
9
    sh = p->shape;
5223
9
    h = (uintptr_t)atom & sh->prop_hash_mask;
5224
9
    h = prop_hash_end(sh)[-h - 1];
5225
9
    prop = get_shape_prop(sh);
5226
9
    while (h) {
5227
0
        pr = &prop[h - 1];
5228
0
        if (likely(pr->atom == atom)) {
5229
0
            return pr;
5230
0
        }
5231
0
        h = pr->hash_next;
5232
0
    }
5233
9
    return NULL;
5234
9
}
5235
5236
static force_inline JSShapeProperty *find_own_property(JSProperty **ppr,
5237
                                                       JSObject *p,
5238
                                                       JSAtom atom)
5239
3.03M
{
5240
3.03M
    JSShape *sh;
5241
3.03M
    JSShapeProperty *pr, *prop;
5242
3.03M
    intptr_t h;
5243
3.03M
    sh = p->shape;
5244
3.03M
    h = (uintptr_t)atom & sh->prop_hash_mask;
5245
3.03M
    h = prop_hash_end(sh)[-h - 1];
5246
3.03M
    prop = get_shape_prop(sh);
5247
3.32M
    while (h) {
5248
290k
        pr = &prop[h - 1];
5249
290k
        if (likely(pr->atom == atom)) {
5250
1.10k
            *ppr = &p->prop[h - 1];
5251
            /* the compiler should be able to assume that pr != NULL here */
5252
1.10k
            return pr;
5253
1.10k
        }
5254
288k
        h = pr->hash_next;
5255
288k
    }
5256
3.03M
    *ppr = NULL;
5257
3.03M
    return NULL;
5258
3.03M
}
5259
5260
/* indicate that the object may be part of a function prototype cycle */
5261
static void set_cycle_flag(JSContext *ctx, JSValueConst obj)
5262
3.74k
{
5263
3.74k
}
5264
5265
static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref)
5266
7.72k
{
5267
7.72k
    if (var_ref) {
5268
7.72k
        assert(var_ref->header.ref_count > 0);
5269
7.72k
        if (--var_ref->header.ref_count == 0) {
5270
3.90k
            if (var_ref->is_detached) {
5271
3.90k
                JS_FreeValueRT(rt, var_ref->value);
5272
3.90k
            } else {
5273
0
                list_del(&var_ref->var_ref_link); /* still on the stack */
5274
0
                if (var_ref->async_func)
5275
0
                    async_func_free(rt, var_ref->async_func);
5276
0
            }
5277
3.90k
            remove_gc_object(&var_ref->header);
5278
3.90k
            js_free_rt(rt, var_ref);
5279
3.90k
        }
5280
7.72k
    }
5281
7.72k
}
5282
5283
static void js_array_finalizer(JSRuntime *rt, JSValue val)
5284
91
{
5285
91
    JSObject *p = JS_VALUE_GET_OBJ(val);
5286
91
    int i;
5287
5288
125k
    for(i = 0; i < p->u.array.count; i++) {
5289
125k
        JS_FreeValueRT(rt, p->u.array.u.values[i]);
5290
125k
    }
5291
91
    js_free_rt(rt, p->u.array.u.values);
5292
91
}
5293
5294
static void js_array_mark(JSRuntime *rt, JSValueConst val,
5295
                          JS_MarkFunc *mark_func)
5296
306
{
5297
306
    JSObject *p = JS_VALUE_GET_OBJ(val);
5298
306
    int i;
5299
5300
250k
    for(i = 0; i < p->u.array.count; i++) {
5301
250k
        JS_MarkValue(rt, p->u.array.u.values[i], mark_func);
5302
250k
    }
5303
306
}
5304
5305
static void js_object_data_finalizer(JSRuntime *rt, JSValue val)
5306
117
{
5307
117
    JSObject *p = JS_VALUE_GET_OBJ(val);
5308
117
    JS_FreeValueRT(rt, p->u.object_data);
5309
117
    p->u.object_data = JS_UNDEFINED;
5310
117
}
5311
5312
static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
5313
                                JS_MarkFunc *mark_func)
5314
438
{
5315
438
    JSObject *p = JS_VALUE_GET_OBJ(val);
5316
438
    JS_MarkValue(rt, p->u.object_data, mark_func);
5317
438
}
5318
5319
static void js_c_function_finalizer(JSRuntime *rt, JSValue val)
5320
7.02k
{
5321
7.02k
    JSObject *p = JS_VALUE_GET_OBJ(val);
5322
5323
7.02k
    if (p->u.cfunc.realm)
5324
7.02k
        JS_FreeContext(p->u.cfunc.realm);
5325
7.02k
}
5326
5327
static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
5328
                               JS_MarkFunc *mark_func)
5329
26.2k
{
5330
26.2k
    JSObject *p = JS_VALUE_GET_OBJ(val);
5331
5332
26.2k
    if (p->u.cfunc.realm)
5333
26.2k
        mark_func(rt, &p->u.cfunc.realm->header);
5334
26.2k
}
5335
5336
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val)
5337
63
{
5338
63
    JSObject *p1, *p = JS_VALUE_GET_OBJ(val);
5339
63
    JSFunctionBytecode *b;
5340
63
    JSVarRef **var_refs;
5341
63
    int i;
5342
5343
63
    p1 = p->u.func.home_object;
5344
63
    if (p1) {
5345
0
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, p1));
5346
0
    }
5347
63
    b = p->u.func.function_bytecode;
5348
63
    if (b) {
5349
63
        var_refs = p->u.func.var_refs;
5350
63
        if (var_refs) {
5351
117
            for(i = 0; i < b->closure_var_count; i++)
5352
78
                free_var_ref(rt, var_refs[i]);
5353
39
            js_free_rt(rt, var_refs);
5354
39
        }
5355
63
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b));
5356
63
    }
5357
63
}
5358
5359
static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
5360
                                      JS_MarkFunc *mark_func)
5361
160
{
5362
160
    JSObject *p = JS_VALUE_GET_OBJ(val);
5363
160
    JSVarRef **var_refs = p->u.func.var_refs;
5364
160
    JSFunctionBytecode *b = p->u.func.function_bytecode;
5365
160
    int i;
5366
5367
160
    if (p->u.func.home_object) {
5368
0
        JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object),
5369
0
                     mark_func);
5370
0
    }
5371
160
    if (b) {
5372
160
        if (var_refs) {
5373
438
            for(i = 0; i < b->closure_var_count; i++) {
5374
292
                JSVarRef *var_ref = var_refs[i];
5375
292
                if (var_ref) {
5376
292
                    mark_func(rt, &var_ref->header);
5377
292
                }
5378
292
            }
5379
146
        }
5380
        /* must mark the function bytecode because template objects may be
5381
           part of a cycle */
5382
160
        JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func);
5383
160
    }
5384
160
}
5385
5386
static void js_bound_function_finalizer(JSRuntime *rt, JSValue val)
5387
0
{
5388
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5389
0
    JSBoundFunction *bf = p->u.bound_function;
5390
0
    int i;
5391
5392
0
    JS_FreeValueRT(rt, bf->func_obj);
5393
0
    JS_FreeValueRT(rt, bf->this_val);
5394
0
    for(i = 0; i < bf->argc; i++) {
5395
0
        JS_FreeValueRT(rt, bf->argv[i]);
5396
0
    }
5397
0
    js_free_rt(rt, bf);
5398
0
}
5399
5400
static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
5401
                                JS_MarkFunc *mark_func)
5402
0
{
5403
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5404
0
    JSBoundFunction *bf = p->u.bound_function;
5405
0
    int i;
5406
5407
0
    JS_MarkValue(rt, bf->func_obj, mark_func);
5408
0
    JS_MarkValue(rt, bf->this_val, mark_func);
5409
0
    for(i = 0; i < bf->argc; i++)
5410
0
        JS_MarkValue(rt, bf->argv[i], mark_func);
5411
0
}
5412
5413
static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val)
5414
0
{
5415
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5416
0
    JSForInIterator *it = p->u.for_in_iterator;
5417
0
    int i;
5418
5419
0
    JS_FreeValueRT(rt, it->obj);
5420
0
    if (!it->is_array) {
5421
0
        for(i = 0; i < it->atom_count; i++) {
5422
0
            JS_FreeAtomRT(rt, it->tab_atom[i].atom);
5423
0
        }
5424
0
        js_free_rt(rt, it->tab_atom);
5425
0
    }
5426
0
    js_free_rt(rt, it);
5427
0
}
5428
5429
static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
5430
                                JS_MarkFunc *mark_func)
5431
0
{
5432
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5433
0
    JSForInIterator *it = p->u.for_in_iterator;
5434
0
    JS_MarkValue(rt, it->obj, mark_func);
5435
0
}
5436
5437
static void free_object(JSRuntime *rt, JSObject *p)
5438
10.3k
{
5439
10.3k
    int i;
5440
10.3k
    JSClassFinalizer *finalizer;
5441
10.3k
    JSShape *sh;
5442
10.3k
    JSShapeProperty *pr;
5443
5444
10.3k
    p->free_mark = 1; /* used to tell the object is invalid when
5445
                         freeing cycles */
5446
    /* free all the fields */
5447
10.3k
    sh = p->shape;
5448
10.3k
    pr = get_shape_prop(sh);
5449
2.92M
    for(i = 0; i < sh->prop_count; i++) {
5450
2.91M
        free_property(rt, &p->prop[i], pr->flags);
5451
2.91M
        pr++;
5452
2.91M
    }
5453
10.3k
    js_free_rt(rt, p->prop);
5454
    /* as an optimization we destroy the shape immediately without
5455
       putting it in gc_zero_ref_count_list */
5456
10.3k
    js_free_shape(rt, sh);
5457
5458
    /* fail safe */
5459
10.3k
    p->shape = NULL;
5460
10.3k
    p->prop = NULL;
5461
5462
10.3k
    if (unlikely(p->first_weak_ref)) {
5463
0
        reset_weak_ref(rt, p);
5464
0
    }
5465
5466
10.3k
    finalizer = rt->class_array[p->class_id].finalizer;
5467
10.3k
    if (finalizer)
5468
7.95k
        (*finalizer)(rt, JS_MKPTR(JS_TAG_OBJECT, p));
5469
5470
    /* fail safe */
5471
10.3k
    p->class_id = 0;
5472
10.3k
    p->u.opaque = NULL;
5473
10.3k
    p->u.func.var_refs = NULL;
5474
10.3k
    p->u.func.home_object = NULL;
5475
5476
10.3k
    remove_gc_object(&p->header);
5477
10.3k
    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && p->header.ref_count != 0) {
5478
6.01k
        list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list);
5479
6.01k
    } else {
5480
4.30k
        js_free_rt(rt, p);
5481
4.30k
    }
5482
10.3k
}
5483
5484
static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp)
5485
10.4k
{
5486
10.4k
    switch(gp->gc_obj_type) {
5487
10.3k
    case JS_GC_OBJ_TYPE_JS_OBJECT:
5488
10.3k
        free_object(rt, (JSObject *)gp);
5489
10.3k
        break;
5490
63
    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
5491
63
        free_function_bytecode(rt, (JSFunctionBytecode *)gp);
5492
63
        break;
5493
39
    case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
5494
39
        __async_func_free(rt, (JSAsyncFunctionState *)gp);
5495
39
        break;
5496
0
    default:
5497
0
        abort();
5498
10.4k
    }
5499
10.4k
}
5500
5501
static void free_zero_refcount(JSRuntime *rt)
5502
252
{
5503
252
    struct list_head *el;
5504
252
    JSGCObjectHeader *p;
5505
5506
252
    rt->gc_phase = JS_GC_PHASE_DECREF;
5507
612
    for(;;) {
5508
612
        el = rt->gc_zero_ref_count_list.next;
5509
612
        if (el == &rt->gc_zero_ref_count_list)
5510
252
            break;
5511
360
        p = list_entry(el, JSGCObjectHeader, link);
5512
360
        assert(p->ref_count == 0);
5513
360
        free_gc_object(rt, p);
5514
360
    }
5515
252
    rt->gc_phase = JS_GC_PHASE_NONE;
5516
252
}
5517
5518
/* called with the ref_count of 'v' reaches zero. */
5519
void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
5520
12.7k
{
5521
12.7k
    uint32_t tag = JS_VALUE_GET_TAG(v);
5522
5523
#ifdef DUMP_FREE
5524
    {
5525
        printf("Freeing ");
5526
        if (tag == JS_TAG_OBJECT) {
5527
            JS_DumpObject(rt, JS_VALUE_GET_OBJ(v));
5528
        } else {
5529
            JS_DumpValueShort(rt, v);
5530
            printf("\n");
5531
        }
5532
    }
5533
#endif
5534
5535
12.7k
    switch(tag) {
5536
2.36k
    case JS_TAG_STRING:
5537
2.36k
        {
5538
2.36k
            JSString *p = JS_VALUE_GET_STRING(v);
5539
2.36k
            if (p->atom_type) {
5540
2.12k
                JS_FreeAtomStruct(rt, p);
5541
2.12k
            } else {
5542
#ifdef DUMP_LEAKS
5543
                list_del(&p->link);
5544
#endif
5545
244
                js_free_rt(rt, p);
5546
244
            }
5547
2.36k
        }
5548
2.36k
        break;
5549
10.3k
    case JS_TAG_OBJECT:
5550
10.3k
    case JS_TAG_FUNCTION_BYTECODE:
5551
10.3k
        {
5552
10.3k
            JSGCObjectHeader *p = JS_VALUE_GET_PTR(v);
5553
10.3k
            if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
5554
321
                list_del(&p->link);
5555
321
                list_add(&p->link, &rt->gc_zero_ref_count_list);
5556
321
                if (rt->gc_phase == JS_GC_PHASE_NONE) {
5557
213
                    free_zero_refcount(rt);
5558
213
                }
5559
321
            }
5560
10.3k
        }
5561
10.3k
        break;
5562
0
    case JS_TAG_MODULE:
5563
0
        abort(); /* never freed here */
5564
0
        break;
5565
1
    case JS_TAG_BIG_INT:
5566
1
#ifdef CONFIG_BIGNUM
5567
1
    case JS_TAG_BIG_FLOAT:
5568
1
#endif
5569
1
        {
5570
1
            JSBigFloat *bf = JS_VALUE_GET_PTR(v);
5571
1
            bf_delete(&bf->num);
5572
1
            js_free_rt(rt, bf);
5573
1
        }
5574
1
        break;
5575
0
#ifdef CONFIG_BIGNUM
5576
0
    case JS_TAG_BIG_DECIMAL:
5577
0
        {
5578
0
            JSBigDecimal *bf = JS_VALUE_GET_PTR(v);
5579
0
            bfdec_delete(&bf->num);
5580
0
            js_free_rt(rt, bf);
5581
0
        }
5582
0
        break;
5583
0
#endif
5584
0
    case JS_TAG_SYMBOL:
5585
0
        {
5586
0
            JSAtomStruct *p = JS_VALUE_GET_PTR(v);
5587
0
            JS_FreeAtomStruct(rt, p);
5588
0
        }
5589
0
        break;
5590
0
    default:
5591
0
        printf("__JS_FreeValue: unknown tag=%d\n", tag);
5592
0
        abort();
5593
12.7k
    }
5594
12.7k
}
5595
5596
void __JS_FreeValue(JSContext *ctx, JSValue v)
5597
3.01k
{
5598
3.01k
    __JS_FreeValueRT(ctx->rt, v);
5599
3.01k
}
5600
5601
/* garbage collection */
5602
5603
static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
5604
                          JSGCObjectTypeEnum type)
5605
25.2k
{
5606
25.2k
    h->mark = 0;
5607
25.2k
    h->gc_obj_type = type;
5608
25.2k
    list_add_tail(&h->link, &rt->gc_obj_list);
5609
25.2k
}
5610
5611
static void remove_gc_object(JSGCObjectHeader *h)
5612
25.2k
{
5613
25.2k
    list_del(&h->link);
5614
25.2k
}
5615
5616
void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
5617
3.63M
{
5618
3.63M
    if (JS_VALUE_HAS_REF_COUNT(val)) {
5619
77.2k
        switch(JS_VALUE_GET_TAG(val)) {
5620
45.4k
        case JS_TAG_OBJECT:
5621
45.5k
        case JS_TAG_FUNCTION_BYTECODE:
5622
45.5k
            mark_func(rt, JS_VALUE_GET_PTR(val));
5623
45.5k
            break;
5624
31.6k
        default:
5625
31.6k
            break;
5626
77.2k
        }
5627
77.2k
    }
5628
3.63M
}
5629
5630
static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
5631
                          JS_MarkFunc *mark_func)
5632
62.4k
{
5633
62.4k
    switch(gp->gc_obj_type) {
5634
37.6k
    case JS_GC_OBJ_TYPE_JS_OBJECT:
5635
37.6k
        {
5636
37.6k
            JSObject *p = (JSObject *)gp;
5637
37.6k
            JSShapeProperty *prs;
5638
37.6k
            JSShape *sh;
5639
37.6k
            int i;
5640
37.6k
            sh = p->shape;
5641
37.6k
            mark_func(rt, &sh->header);
5642
            /* mark all the fields */
5643
37.6k
            prs = get_shape_prop(sh);
5644
3.47M
            for(i = 0; i < sh->prop_count; i++) {
5645
3.43M
                JSProperty *pr = &p->prop[i];
5646
3.43M
                if (prs->atom != JS_ATOM_NULL) {
5647
3.43M
                    if (prs->flags & JS_PROP_TMASK) {
5648
83.9k
                        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
5649
7.59k
                            if (pr->u.getset.getter)
5650
7.59k
                                mark_func(rt, &pr->u.getset.getter->header);
5651
7.59k
                            if (pr->u.getset.setter)
5652
1.89k
                                mark_func(rt, &pr->u.getset.setter->header);
5653
76.3k
                        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
5654
                            /* Note: the tag does not matter
5655
                               provided it is a GC object */
5656
14.3k
                            mark_func(rt, &pr->u.var_ref->header);
5657
62.0k
                        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
5658
62.0k
                            js_autoinit_mark(rt, pr, mark_func);
5659
62.0k
                        }
5660
3.35M
                    } else {
5661
3.35M
                        JS_MarkValue(rt, pr->u.value, mark_func);
5662
3.35M
                    }
5663
3.43M
                }
5664
3.43M
                prs++;
5665
3.43M
            }
5666
5667
37.6k
            if (p->class_id != JS_CLASS_OBJECT) {
5668
29.2k
                JSClassGCMark *gc_mark;
5669
29.2k
                gc_mark = rt->class_array[p->class_id].gc_mark;
5670
29.2k
                if (gc_mark)
5671
28.4k
                    gc_mark(rt, JS_MKPTR(JS_TAG_OBJECT, p), mark_func);
5672
29.2k
            }
5673
37.6k
        }
5674
37.6k
        break;
5675
198
    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
5676
        /* the template objects can be part of a cycle */
5677
198
        {
5678
198
            JSFunctionBytecode *b = (JSFunctionBytecode *)gp;
5679
198
            int i;
5680
198
            for(i = 0; i < b->cpool_count; i++) {
5681
0
                JS_MarkValue(rt, b->cpool[i], mark_func);
5682
0
            }
5683
198
            if (b->realm)
5684
198
                mark_func(rt, &b->realm->header);
5685
198
        }
5686
198
        break;
5687
14.6k
    case JS_GC_OBJ_TYPE_VAR_REF:
5688
14.6k
        {
5689
14.6k
            JSVarRef *var_ref = (JSVarRef *)gp;
5690
14.6k
            if (var_ref->is_detached) {
5691
14.6k
                JS_MarkValue(rt, *var_ref->pvalue, mark_func);
5692
14.6k
            } else if (var_ref->async_func) {
5693
0
                mark_func(rt, &var_ref->async_func->header);
5694
0
            }
5695
14.6k
        }
5696
14.6k
        break;
5697
0
    case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
5698
0
        {
5699
0
            JSAsyncFunctionState *s = (JSAsyncFunctionState *)gp;
5700
0
            JSStackFrame *sf = &s->frame;
5701
0
            JSValue *sp;
5702
5703
0
            if (!s->is_completed) {
5704
0
                JS_MarkValue(rt, sf->cur_func, mark_func);
5705
0
                JS_MarkValue(rt, s->this_val, mark_func);
5706
                /* sf->cur_sp = NULL if the function is running */
5707
0
                if (sf->cur_sp) {
5708
                    /* if the function is running, cur_sp is not known so we
5709
                       cannot mark the stack. Marking the variables is not needed
5710
                       because a running function cannot be part of a removable
5711
                       cycle */
5712
0
                    for(sp = sf->arg_buf; sp < sf->cur_sp; sp++)
5713
0
                        JS_MarkValue(rt, *sp, mark_func);
5714
0
                }
5715
0
            }
5716
0
            JS_MarkValue(rt, s->resolving_funcs[0], mark_func);
5717
0
            JS_MarkValue(rt, s->resolving_funcs[1], mark_func);
5718
0
        }
5719
0
        break;
5720
9.88k
    case JS_GC_OBJ_TYPE_SHAPE:
5721
9.88k
        {
5722
9.88k
            JSShape *sh = (JSShape *)gp;
5723
9.88k
            if (sh->proto != NULL) {
5724
9.15k
                mark_func(rt, &sh->proto->header);
5725
9.15k
            }
5726
9.88k
        }
5727
9.88k
        break;
5728
146
    case JS_GC_OBJ_TYPE_JS_CONTEXT:
5729
146
        {
5730
146
            JSContext *ctx = (JSContext *)gp;
5731
146
            JS_MarkContext(rt, ctx, mark_func);
5732
146
        }
5733
146
        break;
5734
0
    default:
5735
0
        abort();
5736
62.4k
    }
5737
62.4k
}
5738
5739
static void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p)
5740
109k
{
5741
109k
    assert(p->ref_count > 0);
5742
109k
    p->ref_count--;
5743
109k
    if (p->ref_count == 0 && p->mark == 1) {
5744
12.2k
        list_del(&p->link);
5745
12.2k
        list_add_tail(&p->link, &rt->tmp_obj_list);
5746
12.2k
    }
5747
109k
}
5748
5749
static void gc_decref(JSRuntime *rt)
5750
73
{
5751
73
    struct list_head *el, *el1;
5752
73
    JSGCObjectHeader *p;
5753
5754
73
    init_list_head(&rt->tmp_obj_list);
5755
5756
    /* decrement the refcount of all the children of all the GC
5757
       objects and move the GC objects with zero refcount to
5758
       tmp_obj_list */
5759
31.2k
    list_for_each_safe(el, el1, &rt->gc_obj_list) {
5760
31.2k
        p = list_entry(el, JSGCObjectHeader, link);
5761
31.2k
        assert(p->mark == 0);
5762
31.2k
        mark_children(rt, p, gc_decref_child);
5763
31.2k
        p->mark = 1;
5764
31.2k
        if (p->ref_count == 0) {
5765
18.7k
            list_del(&p->link);
5766
18.7k
            list_add_tail(&p->link, &rt->tmp_obj_list);
5767
18.7k
        }
5768
31.2k
    }
5769
73
}
5770
5771
static void gc_scan_incref_child(JSRuntime *rt, JSGCObjectHeader *p)
5772
51.1k
{
5773
51.1k
    p->ref_count++;
5774
51.1k
    if (p->ref_count == 1) {
5775
        /* ref_count was 0: remove from tmp_obj_list and add at the
5776
           end of gc_obj_list */
5777
14.4k
        list_del(&p->link);
5778
14.4k
        list_add_tail(&p->link, &rt->gc_obj_list);
5779
14.4k
        p->mark = 0; /* reset the mark for the next GC call */
5780
14.4k
    }
5781
51.1k
}
5782
5783
static void gc_scan_incref_child2(JSRuntime *rt, JSGCObjectHeader *p)
5784
58.5k
{
5785
58.5k
    p->ref_count++;
5786
58.5k
}
5787
5788
static void gc_scan(JSRuntime *rt)
5789
73
{
5790
73
    struct list_head *el;
5791
73
    JSGCObjectHeader *p;
5792
5793
    /* keep the objects with a refcount > 0 and their children. */
5794
14.6k
    list_for_each(el, &rt->gc_obj_list) {
5795
14.6k
        p = list_entry(el, JSGCObjectHeader, link);
5796
14.6k
        assert(p->ref_count > 0);
5797
14.6k
        p->mark = 0; /* reset the mark for the next GC call */
5798
14.6k
        mark_children(rt, p, gc_scan_incref_child);
5799
14.6k
    }
5800
5801
    /* restore the refcount of the objects to be deleted. */
5802
16.6k
    list_for_each(el, &rt->tmp_obj_list) {
5803
16.6k
        p = list_entry(el, JSGCObjectHeader, link);
5804
16.6k
        mark_children(rt, p, gc_scan_incref_child2);
5805
16.6k
    }
5806
73
}
5807
5808
static void gc_free_cycles(JSRuntime *rt)
5809
73
{
5810
73
    struct list_head *el, *el1;
5811
73
    JSGCObjectHeader *p;
5812
#ifdef DUMP_GC_FREE
5813
    BOOL header_done = FALSE;
5814
#endif
5815
5816
73
    rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES;
5817
5818
14.7k
    for(;;) {
5819
14.7k
        el = rt->tmp_obj_list.next;
5820
14.7k
        if (el == &rt->tmp_obj_list)
5821
73
            break;
5822
14.6k
        p = list_entry(el, JSGCObjectHeader, link);
5823
        /* Only need to free the GC object associated with JS values
5824
           or async functions. The rest will be automatically removed
5825
           because they must be referenced by them. */
5826
14.6k
        switch(p->gc_obj_type) {
5827
10.0k
        case JS_GC_OBJ_TYPE_JS_OBJECT:
5828
10.0k
        case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
5829
10.0k
        case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
5830
#ifdef DUMP_GC_FREE
5831
            if (!header_done) {
5832
                printf("Freeing cycles:\n");
5833
                JS_DumpObjectHeader(rt);
5834
                header_done = TRUE;
5835
            }
5836
            JS_DumpGCObject(rt, p);
5837
#endif
5838
10.0k
            free_gc_object(rt, p);
5839
10.0k
            break;
5840
4.61k
        default:
5841
4.61k
            list_del(&p->link);
5842
4.61k
            list_add_tail(&p->link, &rt->gc_zero_ref_count_list);
5843
4.61k
            break;
5844
14.6k
        }
5845
14.6k
    }
5846
73
    rt->gc_phase = JS_GC_PHASE_NONE;
5847
5848
6.02k
    list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) {
5849
6.02k
        p = list_entry(el, JSGCObjectHeader, link);
5850
6.02k
        assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT ||
5851
6.02k
               p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE ||
5852
6.02k
               p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
5853
6.02k
        js_free_rt(rt, p);
5854
6.02k
    }
5855
5856
73
    init_list_head(&rt->gc_zero_ref_count_list);
5857
73
}
5858
5859
void JS_RunGC(JSRuntime *rt)
5860
73
{
5861
    /* decrement the reference of the children of each object. mark =
5862
       1 after this pass. */
5863
73
    gc_decref(rt);
5864
5865
    /* keep the GC objects with a non zero refcount and their childs */
5866
73
    gc_scan(rt);
5867
5868
    /* free the GC objects in a cycle */
5869
73
    gc_free_cycles(rt);
5870
73
}
5871
5872
/* Return false if not an object or if the object has already been
5873
   freed (zombie objects are visible in finalizers when freeing
5874
   cycles). */
5875
BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj)
5876
0
{
5877
0
    JSObject *p;
5878
0
    if (!JS_IsObject(obj))
5879
0
        return FALSE;
5880
0
    p = JS_VALUE_GET_OBJ(obj);
5881
0
    return !p->free_mark;
5882
0
}
5883
5884
/* Compute memory used by various object types */
5885
/* XXX: poor man's approach to handling multiply referenced objects */
5886
typedef struct JSMemoryUsage_helper {
5887
    double memory_used_count;
5888
    double str_count;
5889
    double str_size;
5890
    int64_t js_func_count;
5891
    double js_func_size;
5892
    int64_t js_func_code_size;
5893
    int64_t js_func_pc2line_count;
5894
    int64_t js_func_pc2line_size;
5895
} JSMemoryUsage_helper;
5896
5897
static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp);
5898
5899
static void compute_jsstring_size(JSString *str, JSMemoryUsage_helper *hp)
5900
0
{
5901
0
    if (!str->atom_type) {  /* atoms are handled separately */
5902
0
        double s_ref_count = str->header.ref_count;
5903
0
        hp->str_count += 1 / s_ref_count;
5904
0
        hp->str_size += ((sizeof(*str) + (str->len << str->is_wide_char) +
5905
0
                          1 - str->is_wide_char) / s_ref_count);
5906
0
    }
5907
0
}
5908
5909
static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *hp)
5910
0
{
5911
0
    int memory_used_count, js_func_size, i;
5912
5913
0
    memory_used_count = 0;
5914
0
    js_func_size = offsetof(JSFunctionBytecode, debug);
5915
0
    if (b->vardefs) {
5916
0
        js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs);
5917
0
    }
5918
0
    if (b->cpool) {
5919
0
        js_func_size += b->cpool_count * sizeof(*b->cpool);
5920
0
        for (i = 0; i < b->cpool_count; i++) {
5921
0
            JSValueConst val = b->cpool[i];
5922
0
            compute_value_size(val, hp);
5923
0
        }
5924
0
    }
5925
0
    if (b->closure_var) {
5926
0
        js_func_size += b->closure_var_count * sizeof(*b->closure_var);
5927
0
    }
5928
0
    if (!b->read_only_bytecode && b->byte_code_buf) {
5929
0
        hp->js_func_code_size += b->byte_code_len;
5930
0
    }
5931
0
    if (b->has_debug) {
5932
0
        js_func_size += sizeof(*b) - offsetof(JSFunctionBytecode, debug);
5933
0
        if (b->debug.source) {
5934
0
            memory_used_count++;
5935
0
            js_func_size += b->debug.source_len + 1;
5936
0
        }
5937
0
        if (b->debug.pc2line_len) {
5938
0
            memory_used_count++;
5939
0
            hp->js_func_pc2line_count += 1;
5940
0
            hp->js_func_pc2line_size += b->debug.pc2line_len;
5941
0
        }
5942
0
    }
5943
0
    hp->js_func_size += js_func_size;
5944
0
    hp->js_func_count += 1;
5945
0
    hp->memory_used_count += memory_used_count;
5946
0
}
5947
5948
static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp)
5949
0
{
5950
0
    switch(JS_VALUE_GET_TAG(val)) {
5951
0
    case JS_TAG_STRING:
5952
0
        compute_jsstring_size(JS_VALUE_GET_STRING(val), hp);
5953
0
        break;
5954
0
    case JS_TAG_BIG_INT:
5955
0
#ifdef CONFIG_BIGNUM
5956
0
    case JS_TAG_BIG_FLOAT:
5957
0
    case JS_TAG_BIG_DECIMAL:
5958
0
#endif
5959
        /* should track JSBigFloat usage */
5960
0
        break;
5961
0
    }
5962
0
}
5963
5964
void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
5965
0
{
5966
0
    struct list_head *el, *el1;
5967
0
    int i;
5968
0
    JSMemoryUsage_helper mem = { 0 }, *hp = &mem;
5969
5970
0
    memset(s, 0, sizeof(*s));
5971
0
    s->malloc_count = rt->malloc_state.malloc_count;
5972
0
    s->malloc_size = rt->malloc_state.malloc_size;
5973
0
    s->malloc_limit = rt->malloc_state.malloc_limit;
5974
5975
0
    s->memory_used_count = 2; /* rt + rt->class_array */
5976
0
    s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count;
5977
5978
0
    list_for_each(el, &rt->context_list) {
5979
0
        JSContext *ctx = list_entry(el, JSContext, link);
5980
0
        JSShape *sh = ctx->array_shape;
5981
0
        s->memory_used_count += 2; /* ctx + ctx->class_proto */
5982
0
        s->memory_used_size += sizeof(JSContext) +
5983
0
            sizeof(JSValue) * rt->class_count;
5984
0
        s->binary_object_count += ctx->binary_object_count;
5985
0
        s->binary_object_size += ctx->binary_object_size;
5986
5987
        /* the hashed shapes are counted separately */
5988
0
        if (sh && !sh->is_hashed) {
5989
0
            int hash_size = sh->prop_hash_mask + 1;
5990
0
            s->shape_count++;
5991
0
            s->shape_size += get_shape_size(hash_size, sh->prop_size);
5992
0
        }
5993
0
        list_for_each(el1, &ctx->loaded_modules) {
5994
0
            JSModuleDef *m = list_entry(el1, JSModuleDef, link);
5995
0
            s->memory_used_count += 1;
5996
0
            s->memory_used_size += sizeof(*m);
5997
0
            if (m->req_module_entries) {
5998
0
                s->memory_used_count += 1;
5999
0
                s->memory_used_size += m->req_module_entries_count * sizeof(*m->req_module_entries);
6000
0
            }
6001
0
            if (m->export_entries) {
6002
0
                s->memory_used_count += 1;
6003
0
                s->memory_used_size += m->export_entries_count * sizeof(*m->export_entries);
6004
0
                for (i = 0; i < m->export_entries_count; i++) {
6005
0
                    JSExportEntry *me = &m->export_entries[i];
6006
0
                    if (me->export_type == JS_EXPORT_TYPE_LOCAL && me->u.local.var_ref) {
6007
                        /* potential multiple count */
6008
0
                        s->memory_used_count += 1;
6009
0
                        compute_value_size(me->u.local.var_ref->value, hp);
6010
0
                    }
6011
0
                }
6012
0
            }
6013
0
            if (m->star_export_entries) {
6014
0
                s->memory_used_count += 1;
6015
0
                s->memory_used_size += m->star_export_entries_count * sizeof(*m->star_export_entries);
6016
0
            }
6017
0
            if (m->import_entries) {
6018
0
                s->memory_used_count += 1;
6019
0
                s->memory_used_size += m->import_entries_count * sizeof(*m->import_entries);
6020
0
            }
6021
0
            compute_value_size(m->module_ns, hp);
6022
0
            compute_value_size(m->func_obj, hp);
6023
0
        }
6024
0
    }
6025
6026
0
    list_for_each(el, &rt->gc_obj_list) {
6027
0
        JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
6028
0
        JSObject *p;
6029
0
        JSShape *sh;
6030
0
        JSShapeProperty *prs;
6031
6032
        /* XXX: could count the other GC object types too */
6033
0
        if (gp->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) {
6034
0
            compute_bytecode_size((JSFunctionBytecode *)gp, hp);
6035
0
            continue;
6036
0
        } else if (gp->gc_obj_type != JS_GC_OBJ_TYPE_JS_OBJECT) {
6037
0
            continue;
6038
0
        }
6039
0
        p = (JSObject *)gp;
6040
0
        sh = p->shape;
6041
0
        s->obj_count++;
6042
0
        if (p->prop) {
6043
0
            s->memory_used_count++;
6044
0
            s->prop_size += sh->prop_size * sizeof(*p->prop);
6045
0
            s->prop_count += sh->prop_count;
6046
0
            prs = get_shape_prop(sh);
6047
0
            for(i = 0; i < sh->prop_count; i++) {
6048
0
                JSProperty *pr = &p->prop[i];
6049
0
                if (prs->atom != JS_ATOM_NULL && !(prs->flags & JS_PROP_TMASK)) {
6050
0
                    compute_value_size(pr->u.value, hp);
6051
0
                }
6052
0
                prs++;
6053
0
            }
6054
0
        }
6055
        /* the hashed shapes are counted separately */
6056
0
        if (!sh->is_hashed) {
6057
0
            int hash_size = sh->prop_hash_mask + 1;
6058
0
            s->shape_count++;
6059
0
            s->shape_size += get_shape_size(hash_size, sh->prop_size);
6060
0
        }
6061
6062
0
        switch(p->class_id) {
6063
0
        case JS_CLASS_ARRAY:             /* u.array | length */
6064
0
        case JS_CLASS_ARGUMENTS:         /* u.array | length */
6065
0
            s->array_count++;
6066
0
            if (p->fast_array) {
6067
0
                s->fast_array_count++;
6068
0
                if (p->u.array.u.values) {
6069
0
                    s->memory_used_count++;
6070
0
                    s->memory_used_size += p->u.array.count *
6071
0
                        sizeof(*p->u.array.u.values);
6072
0
                    s->fast_array_elements += p->u.array.count;
6073
0
                    for (i = 0; i < p->u.array.count; i++) {
6074
0
                        compute_value_size(p->u.array.u.values[i], hp);
6075
0
                    }
6076
0
                }
6077
0
            }
6078
0
            break;
6079
0
        case JS_CLASS_NUMBER:            /* u.object_data */
6080
0
        case JS_CLASS_STRING:            /* u.object_data */
6081
0
        case JS_CLASS_BOOLEAN:           /* u.object_data */
6082
0
        case JS_CLASS_SYMBOL:            /* u.object_data */
6083
0
        case JS_CLASS_DATE:              /* u.object_data */
6084
0
        case JS_CLASS_BIG_INT:           /* u.object_data */
6085
0
#ifdef CONFIG_BIGNUM
6086
0
        case JS_CLASS_BIG_FLOAT:         /* u.object_data */
6087
0
        case JS_CLASS_BIG_DECIMAL:         /* u.object_data */
6088
0
#endif
6089
0
            compute_value_size(p->u.object_data, hp);
6090
0
            break;
6091
0
        case JS_CLASS_C_FUNCTION:        /* u.cfunc */
6092
0
            s->c_func_count++;
6093
0
            break;
6094
0
        case JS_CLASS_BYTECODE_FUNCTION: /* u.func */
6095
0
            {
6096
0
                JSFunctionBytecode *b = p->u.func.function_bytecode;
6097
0
                JSVarRef **var_refs = p->u.func.var_refs;
6098
                /* home_object: object will be accounted for in list scan */
6099
0
                if (var_refs) {
6100
0
                    s->memory_used_count++;
6101
0
                    s->js_func_size += b->closure_var_count * sizeof(*var_refs);
6102
0
                    for (i = 0; i < b->closure_var_count; i++) {
6103
0
                        if (var_refs[i]) {
6104
0
                            double ref_count = var_refs[i]->header.ref_count;
6105
0
                            s->memory_used_count += 1 / ref_count;
6106
0
                            s->js_func_size += sizeof(*var_refs[i]) / ref_count;
6107
                            /* handle non object closed values */
6108
0
                            if (var_refs[i]->pvalue == &var_refs[i]->value) {
6109
                                /* potential multiple count */
6110
0
                                compute_value_size(var_refs[i]->value, hp);
6111
0
                            }
6112
0
                        }
6113
0
                    }
6114
0
                }
6115
0
            }
6116
0
            break;
6117
0
        case JS_CLASS_BOUND_FUNCTION:    /* u.bound_function */
6118
0
            {
6119
0
                JSBoundFunction *bf = p->u.bound_function;
6120
                /* func_obj and this_val are objects */
6121
0
                for (i = 0; i < bf->argc; i++) {
6122
0
                    compute_value_size(bf->argv[i], hp);
6123
0
                }
6124
0
                s->memory_used_count += 1;
6125
0
                s->memory_used_size += sizeof(*bf) + bf->argc * sizeof(*bf->argv);
6126
0
            }
6127
0
            break;
6128
0
        case JS_CLASS_C_FUNCTION_DATA:   /* u.c_function_data_record */
6129
0
            {
6130
0
                JSCFunctionDataRecord *fd = p->u.c_function_data_record;
6131
0
                if (fd) {
6132
0
                    for (i = 0; i < fd->data_len; i++) {
6133
0
                        compute_value_size(fd->data[i], hp);
6134
0
                    }
6135
0
                    s->memory_used_count += 1;
6136
0
                    s->memory_used_size += sizeof(*fd) + fd->data_len * sizeof(*fd->data);
6137
0
                }
6138
0
            }
6139
0
            break;
6140
0
        case JS_CLASS_REGEXP:            /* u.regexp */
6141
0
            compute_jsstring_size(p->u.regexp.pattern, hp);
6142
0
            compute_jsstring_size(p->u.regexp.bytecode, hp);
6143
0
            break;
6144
6145
0
        case JS_CLASS_FOR_IN_ITERATOR:   /* u.for_in_iterator */
6146
0
            {
6147
0
                JSForInIterator *it = p->u.for_in_iterator;
6148
0
                if (it) {
6149
0
                    compute_value_size(it->obj, hp);
6150
0
                    s->memory_used_count += 1;
6151
0
                    s->memory_used_size += sizeof(*it);
6152
0
                }
6153
0
            }
6154
0
            break;
6155
0
        case JS_CLASS_ARRAY_BUFFER:      /* u.array_buffer */
6156
0
        case JS_CLASS_SHARED_ARRAY_BUFFER: /* u.array_buffer */
6157
0
            {
6158
0
                JSArrayBuffer *abuf = p->u.array_buffer;
6159
0
                if (abuf) {
6160
0
                    s->memory_used_count += 1;
6161
0
                    s->memory_used_size += sizeof(*abuf);
6162
0
                    if (abuf->data) {
6163
0
                        s->memory_used_count += 1;
6164
0
                        s->memory_used_size += abuf->byte_length;
6165
0
                    }
6166
0
                }
6167
0
            }
6168
0
            break;
6169
0
        case JS_CLASS_GENERATOR:         /* u.generator_data */
6170
0
        case JS_CLASS_UINT8C_ARRAY:      /* u.typed_array / u.array */
6171
0
        case JS_CLASS_INT8_ARRAY:        /* u.typed_array / u.array */
6172
0
        case JS_CLASS_UINT8_ARRAY:       /* u.typed_array / u.array */
6173
0
        case JS_CLASS_INT16_ARRAY:       /* u.typed_array / u.array */
6174
0
        case JS_CLASS_UINT16_ARRAY:      /* u.typed_array / u.array */
6175
0
        case JS_CLASS_INT32_ARRAY:       /* u.typed_array / u.array */
6176
0
        case JS_CLASS_UINT32_ARRAY:      /* u.typed_array / u.array */
6177
0
        case JS_CLASS_BIG_INT64_ARRAY:   /* u.typed_array / u.array */
6178
0
        case JS_CLASS_BIG_UINT64_ARRAY:  /* u.typed_array / u.array */
6179
0
        case JS_CLASS_FLOAT32_ARRAY:     /* u.typed_array / u.array */
6180
0
        case JS_CLASS_FLOAT64_ARRAY:     /* u.typed_array / u.array */
6181
0
        case JS_CLASS_DATAVIEW:          /* u.typed_array */
6182
0
#ifdef CONFIG_BIGNUM
6183
0
        case JS_CLASS_FLOAT_ENV:         /* u.float_env */
6184
0
#endif
6185
0
        case JS_CLASS_MAP:               /* u.map_state */
6186
0
        case JS_CLASS_SET:               /* u.map_state */
6187
0
        case JS_CLASS_WEAKMAP:           /* u.map_state */
6188
0
        case JS_CLASS_WEAKSET:           /* u.map_state */
6189
0
        case JS_CLASS_MAP_ITERATOR:      /* u.map_iterator_data */
6190
0
        case JS_CLASS_SET_ITERATOR:      /* u.map_iterator_data */
6191
0
        case JS_CLASS_ARRAY_ITERATOR:    /* u.array_iterator_data */
6192
0
        case JS_CLASS_STRING_ITERATOR:   /* u.array_iterator_data */
6193
0
        case JS_CLASS_PROXY:             /* u.proxy_data */
6194
0
        case JS_CLASS_PROMISE:           /* u.promise_data */
6195
0
        case JS_CLASS_PROMISE_RESOLVE_FUNCTION:  /* u.promise_function_data */
6196
0
        case JS_CLASS_PROMISE_REJECT_FUNCTION:   /* u.promise_function_data */
6197
0
        case JS_CLASS_ASYNC_FUNCTION_RESOLVE:    /* u.async_function_data */
6198
0
        case JS_CLASS_ASYNC_FUNCTION_REJECT:     /* u.async_function_data */
6199
0
        case JS_CLASS_ASYNC_FROM_SYNC_ITERATOR:  /* u.async_from_sync_iterator_data */
6200
0
        case JS_CLASS_ASYNC_GENERATOR:   /* u.async_generator_data */
6201
            /* TODO */
6202
0
        default:
6203
            /* XXX: class definition should have an opaque block size */
6204
0
            if (p->u.opaque) {
6205
0
                s->memory_used_count += 1;
6206
0
            }
6207
0
            break;
6208
0
        }
6209
0
    }
6210
0
    s->obj_size += s->obj_count * sizeof(JSObject);
6211
6212
    /* hashed shapes */
6213
0
    s->memory_used_count++; /* rt->shape_hash */
6214
0
    s->memory_used_size += sizeof(rt->shape_hash[0]) * rt->shape_hash_size;
6215
0
    for(i = 0; i < rt->shape_hash_size; i++) {
6216
0
        JSShape *sh;
6217
0
        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
6218
0
            int hash_size = sh->prop_hash_mask + 1;
6219
0
            s->shape_count++;
6220
0
            s->shape_size += get_shape_size(hash_size, sh->prop_size);
6221
0
        }
6222
0
    }
6223
6224
    /* atoms */
6225
0
    s->memory_used_count += 2; /* rt->atom_array, rt->atom_hash */
6226
0
    s->atom_count = rt->atom_count;
6227
0
    s->atom_size = sizeof(rt->atom_array[0]) * rt->atom_size +
6228
0
        sizeof(rt->atom_hash[0]) * rt->atom_hash_size;
6229
0
    for(i = 0; i < rt->atom_size; i++) {
6230
0
        JSAtomStruct *p = rt->atom_array[i];
6231
0
        if (!atom_is_free(p)) {
6232
0
            s->atom_size += (sizeof(*p) + (p->len << p->is_wide_char) +
6233
0
                             1 - p->is_wide_char);
6234
0
        }
6235
0
    }
6236
0
    s->str_count = round(mem.str_count);
6237
0
    s->str_size = round(mem.str_size);
6238
0
    s->js_func_count = mem.js_func_count;
6239
0
    s->js_func_size = round(mem.js_func_size);
6240
0
    s->js_func_code_size = mem.js_func_code_size;
6241
0
    s->js_func_pc2line_count = mem.js_func_pc2line_count;
6242
0
    s->js_func_pc2line_size = mem.js_func_pc2line_size;
6243
0
    s->memory_used_count += round(mem.memory_used_count) +
6244
0
        s->atom_count + s->str_count +
6245
0
        s->obj_count + s->shape_count +
6246
0
        s->js_func_count + s->js_func_pc2line_count;
6247
0
    s->memory_used_size += s->atom_size + s->str_size +
6248
0
        s->obj_size + s->prop_size + s->shape_size +
6249
0
        s->js_func_size + s->js_func_code_size + s->js_func_pc2line_size;
6250
0
}
6251
6252
void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
6253
0
{
6254
0
    fprintf(fp, "QuickJS memory usage -- "
6255
0
#ifdef CONFIG_BIGNUM
6256
0
            "BigNum "
6257
0
#endif
6258
0
            CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n",
6259
0
            (int)sizeof(void *) * 8, s->malloc_limit);
6260
0
#if 1
6261
0
    if (rt) {
6262
0
        static const struct {
6263
0
            const char *name;
6264
0
            size_t size;
6265
0
        } object_types[] = {
6266
0
            { "JSRuntime", sizeof(JSRuntime) },
6267
0
            { "JSContext", sizeof(JSContext) },
6268
0
            { "JSObject", sizeof(JSObject) },
6269
0
            { "JSString", sizeof(JSString) },
6270
0
            { "JSFunctionBytecode", sizeof(JSFunctionBytecode) },
6271
0
        };
6272
0
        int i, usage_size_ok = 0;
6273
0
        for(i = 0; i < countof(object_types); i++) {
6274
0
            unsigned int size = object_types[i].size;
6275
0
            void *p = js_malloc_rt(rt, size);
6276
0
            if (p) {
6277
0
                unsigned int size1 = js_malloc_usable_size_rt(rt, p);
6278
0
                if (size1 >= size) {
6279
0
                    usage_size_ok = 1;
6280
0
                    fprintf(fp, "  %3u + %-2u  %s\n",
6281
0
                            size, size1 - size, object_types[i].name);
6282
0
                }
6283
0
                js_free_rt(rt, p);
6284
0
            }
6285
0
        }
6286
0
        if (!usage_size_ok) {
6287
0
            fprintf(fp, "  malloc_usable_size unavailable\n");
6288
0
        }
6289
0
        {
6290
0
            int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 };
6291
0
            int class_id;
6292
0
            struct list_head *el;
6293
0
            list_for_each(el, &rt->gc_obj_list) {
6294
0
                JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
6295
0
                JSObject *p;
6296
0
                if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
6297
0
                    p = (JSObject *)gp;
6298
0
                    obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++;
6299
0
                }
6300
0
            }
6301
0
            fprintf(fp, "\n" "JSObject classes\n");
6302
0
            if (obj_classes[0])
6303
0
                fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[0], 0, "none");
6304
0
            for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) {
6305
0
                if (obj_classes[class_id] && class_id < rt->class_count) {
6306
0
                    char buf[ATOM_GET_STR_BUF_SIZE];
6307
0
                    fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[class_id], class_id,
6308
0
                            JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name));
6309
0
                }
6310
0
            }
6311
0
            if (obj_classes[JS_CLASS_INIT_COUNT])
6312
0
                fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other");
6313
0
        }
6314
0
        fprintf(fp, "\n");
6315
0
    }
6316
0
#endif
6317
0
    fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE");
6318
6319
0
    if (s->malloc_count) {
6320
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per block)\n",
6321
0
                "memory allocated", s->malloc_count, s->malloc_size,
6322
0
                (double)s->malloc_size / s->malloc_count);
6323
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%d overhead, %0.1f average slack)\n",
6324
0
                "memory used", s->memory_used_count, s->memory_used_size,
6325
0
                MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) /
6326
0
                                  s->memory_used_count));
6327
0
    }
6328
0
    if (s->atom_count) {
6329
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per atom)\n",
6330
0
                "atoms", s->atom_count, s->atom_size,
6331
0
                (double)s->atom_size / s->atom_count);
6332
0
    }
6333
0
    if (s->str_count) {
6334
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per string)\n",
6335
0
                "strings", s->str_count, s->str_size,
6336
0
                (double)s->str_size / s->str_count);
6337
0
    }
6338
0
    if (s->obj_count) {
6339
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
6340
0
                "objects", s->obj_count, s->obj_size,
6341
0
                (double)s->obj_size / s->obj_count);
6342
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
6343
0
                "  properties", s->prop_count, s->prop_size,
6344
0
                (double)s->prop_count / s->obj_count);
6345
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per shape)\n",
6346
0
                "  shapes", s->shape_count, s->shape_size,
6347
0
                (double)s->shape_size / s->shape_count);
6348
0
    }
6349
0
    if (s->js_func_count) {
6350
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
6351
0
                "bytecode functions", s->js_func_count, s->js_func_size);
6352
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
6353
0
                "  bytecode", s->js_func_count, s->js_func_code_size,
6354
0
                (double)s->js_func_code_size / s->js_func_count);
6355
0
        if (s->js_func_pc2line_count) {
6356
0
            fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
6357
0
                    "  pc2line", s->js_func_pc2line_count,
6358
0
                    s->js_func_pc2line_size,
6359
0
                    (double)s->js_func_pc2line_size / s->js_func_pc2line_count);
6360
0
        }
6361
0
    }
6362
0
    if (s->c_func_count) {
6363
0
        fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count);
6364
0
    }
6365
0
    if (s->array_count) {
6366
0
        fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count);
6367
0
        if (s->fast_array_count) {
6368
0
            fprintf(fp, "%-20s %8"PRId64"\n", "  fast arrays", s->fast_array_count);
6369
0
            fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per fast array)\n",
6370
0
                    "  elements", s->fast_array_elements,
6371
0
                    s->fast_array_elements * (int)sizeof(JSValue),
6372
0
                    (double)s->fast_array_elements / s->fast_array_count);
6373
0
        }
6374
0
    }
6375
0
    if (s->binary_object_count) {
6376
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
6377
0
                "binary objects", s->binary_object_count, s->binary_object_size);
6378
0
    }
6379
0
}
6380
6381
JSValue JS_GetGlobalObject(JSContext *ctx)
6382
39
{
6383
39
    return JS_DupValue(ctx, ctx->global_obj);
6384
39
}
6385
6386
/* WARNING: obj is freed */
6387
JSValue JS_Throw(JSContext *ctx, JSValue obj)
6388
65
{
6389
65
    JSRuntime *rt = ctx->rt;
6390
65
    JS_FreeValue(ctx, rt->current_exception);
6391
65
    rt->current_exception = obj;
6392
65
    return JS_EXCEPTION;
6393
65
}
6394
6395
/* return the pending exception (cannot be called twice). */
6396
JSValue JS_GetException(JSContext *ctx)
6397
0
{
6398
0
    JSValue val;
6399
0
    JSRuntime *rt = ctx->rt;
6400
0
    val = rt->current_exception;
6401
0
    rt->current_exception = JS_NULL;
6402
0
    return val;
6403
0
}
6404
6405
JS_BOOL JS_HasException(JSContext *ctx)
6406
0
{
6407
0
    return !JS_IsNull(ctx->rt->current_exception);
6408
0
}
6409
6410
static void dbuf_put_leb128(DynBuf *s, uint32_t v)
6411
16
{
6412
16
    uint32_t a;
6413
32
    for(;;) {
6414
32
        a = v & 0x7f;
6415
32
        v >>= 7;
6416
32
        if (v != 0) {
6417
16
            dbuf_putc(s, a | 0x80);
6418
16
        } else {
6419
16
            dbuf_putc(s, a);
6420
16
            break;
6421
16
        }
6422
32
    }
6423
16
}
6424
6425
static void dbuf_put_sleb128(DynBuf *s, int32_t v1)
6426
8
{
6427
8
    uint32_t v = v1;
6428
8
    dbuf_put_leb128(s, (2 * v) ^ -(v >> 31));
6429
8
}
6430
6431
static int get_leb128(uint32_t *pval, const uint8_t *buf,
6432
                      const uint8_t *buf_end)
6433
14
{
6434
14
    const uint8_t *ptr = buf;
6435
14
    uint32_t v, a, i;
6436
14
    v = 0;
6437
28
    for(i = 0; i < 5; i++) {
6438
28
        if (unlikely(ptr >= buf_end))
6439
0
            break;
6440
28
        a = *ptr++;
6441
28
        v |= (a & 0x7f) << (i * 7);
6442
28
        if (!(a & 0x80)) {
6443
14
            *pval = v;
6444
14
            return ptr - buf;
6445
14
        }
6446
28
    }
6447
0
    *pval = 0;
6448
0
    return -1;
6449
14
}
6450
6451
static int get_sleb128(int32_t *pval, const uint8_t *buf,
6452
                       const uint8_t *buf_end)
6453
7
{
6454
7
    int ret;
6455
7
    uint32_t val;
6456
7
    ret = get_leb128(&val, buf, buf_end);
6457
7
    if (ret < 0) {
6458
0
        *pval = 0;
6459
0
        return -1;
6460
0
    }
6461
7
    *pval = (val >> 1) ^ -(val & 1);
6462
7
    return ret;
6463
7
}
6464
6465
static int find_line_num(JSContext *ctx, JSFunctionBytecode *b,
6466
                         uint32_t pc_value)
6467
9
{
6468
9
    const uint8_t *p_end, *p;
6469
9
    int new_line_num, line_num, pc, v, ret;
6470
9
    unsigned int op;
6471
6472
9
    if (!b->has_debug || !b->debug.pc2line_buf) {
6473
        /* function was stripped */
6474
4
        return -1;
6475
4
    }
6476
6477
5
    p = b->debug.pc2line_buf;
6478
5
    p_end = p + b->debug.pc2line_len;
6479
5
    pc = 0;
6480
5
    line_num = b->debug.line_num;
6481
11
    while (p < p_end) {
6482
7
        op = *p++;
6483
7
        if (op == 0) {
6484
7
            uint32_t val;
6485
7
            ret = get_leb128(&val, p, p_end);
6486
7
            if (ret < 0)
6487
0
                goto fail;
6488
7
            pc += val;
6489
7
            p += ret;
6490
7
            ret = get_sleb128(&v, p, p_end);
6491
7
            if (ret < 0) {
6492
0
            fail:
6493
                /* should never happen */
6494
0
                return b->debug.line_num;
6495
0
            }
6496
7
            p += ret;
6497
7
            new_line_num = line_num + v;
6498
7
        } else {
6499
0
            op -= PC2LINE_OP_FIRST;
6500
0
            pc += (op / PC2LINE_RANGE);
6501
0
            new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE;
6502
0
        }
6503
7
        if (pc_value < pc)
6504
1
            return line_num;
6505
6
        line_num = new_line_num;
6506
6
    }
6507
4
    return line_num;
6508
5
}
6509
6510
/* in order to avoid executing arbitrary code during the stack trace
6511
   generation, we only look at simple 'name' properties containing a
6512
   string. */
6513
static const char *get_func_name(JSContext *ctx, JSValueConst func)
6514
9
{
6515
9
    JSProperty *pr;
6516
9
    JSShapeProperty *prs;
6517
9
    JSValueConst val;
6518
6519
9
    if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)
6520
0
        return NULL;
6521
9
    prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name);
6522
9
    if (!prs)
6523
0
        return NULL;
6524
9
    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
6525
0
        return NULL;
6526
9
    val = pr->u.value;
6527
9
    if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
6528
0
        return NULL;
6529
9
    return JS_ToCString(ctx, val);
6530
9
}
6531
6532
9
#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)
6533
/* only taken into account if filename is provided */
6534
17
#define JS_BACKTRACE_FLAG_SINGLE_LEVEL     (1 << 1)
6535
6536
/* if filename != NULL, an additional level is added with the filename
6537
   and line number information (used for parse error). */
6538
static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
6539
                            const char *filename, int line_num,
6540
                            int backtrace_flags)
6541
65
{
6542
65
    JSStackFrame *sf;
6543
65
    JSValue str;
6544
65
    DynBuf dbuf;
6545
65
    const char *func_name_str;
6546
65
    const char *str1;
6547
65
    JSObject *p;
6548
65
    BOOL backtrace_barrier;
6549
6550
65
    js_dbuf_init(ctx, &dbuf);
6551
65
    if (filename) {
6552
17
        dbuf_printf(&dbuf, "    at %s", filename);
6553
17
        if (line_num != -1)
6554
17
            dbuf_printf(&dbuf, ":%d", line_num);
6555
17
        dbuf_putc(&dbuf, '\n');
6556
17
        str = JS_NewString(ctx, filename);
6557
17
        JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
6558
17
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6559
17
        JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
6560
17
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6561
17
        if (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL)
6562
0
            goto done;
6563
17
    }
6564
74
    for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
6565
9
        if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {
6566
0
            backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;
6567
0
            continue;
6568
0
        }
6569
9
        func_name_str = get_func_name(ctx, sf->cur_func);
6570
9
        if (!func_name_str || func_name_str[0] == '\0')
6571
0
            str1 = "<anonymous>";
6572
9
        else
6573
9
            str1 = func_name_str;
6574
9
        dbuf_printf(&dbuf, "    at %s", str1);
6575
9
        JS_FreeCString(ctx, func_name_str);
6576
6577
9
        p = JS_VALUE_GET_OBJ(sf->cur_func);
6578
9
        backtrace_barrier = FALSE;
6579
9
        if (js_class_has_bytecode(p->class_id)) {
6580
9
            JSFunctionBytecode *b;
6581
9
            const char *atom_str;
6582
9
            int line_num1;
6583
6584
9
            b = p->u.func.function_bytecode;
6585
9
            backtrace_barrier = b->backtrace_barrier;
6586
9
            if (b->has_debug) {
6587
9
                line_num1 = find_line_num(ctx, b,
6588
9
                                          sf->cur_pc - b->byte_code_buf - 1);
6589
9
                atom_str = JS_AtomToCString(ctx, b->debug.filename);
6590
9
                dbuf_printf(&dbuf, " (%s",
6591
9
                            atom_str ? atom_str : "<null>");
6592
9
                JS_FreeCString(ctx, atom_str);
6593
9
                if (line_num1 != -1)
6594
5
                    dbuf_printf(&dbuf, ":%d", line_num1);
6595
9
                dbuf_putc(&dbuf, ')');
6596
9
            }
6597
9
        } else {
6598
0
            dbuf_printf(&dbuf, " (native)");
6599
0
        }
6600
9
        dbuf_putc(&dbuf, '\n');
6601
        /* stop backtrace if JS_EVAL_FLAG_BACKTRACE_BARRIER was used */
6602
9
        if (backtrace_barrier)
6603
0
            break;
6604
9
    }
6605
65
 done:
6606
65
    dbuf_putc(&dbuf, '\0');
6607
65
    if (dbuf_error(&dbuf))
6608
0
        str = JS_NULL;
6609
65
    else
6610
65
        str = JS_NewString(ctx, (char *)dbuf.buf);
6611
65
    dbuf_free(&dbuf);
6612
65
    JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str,
6613
65
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6614
65
}
6615
6616
/* Note: it is important that no exception is returned by this function */
6617
static BOOL is_backtrace_needed(JSContext *ctx, JSValueConst obj)
6618
9
{
6619
9
    JSObject *p;
6620
9
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6621
0
        return FALSE;
6622
9
    p = JS_VALUE_GET_OBJ(obj);
6623
9
    if (p->class_id != JS_CLASS_ERROR)
6624
0
        return FALSE;
6625
9
    if (find_own_property1(p, JS_ATOM_stack))
6626
0
        return FALSE;
6627
9
    return TRUE;
6628
9
}
6629
6630
JSValue JS_NewError(JSContext *ctx)
6631
0
{
6632
0
    return JS_NewObjectClass(ctx, JS_CLASS_ERROR);
6633
0
}
6634
6635
static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num,
6636
                              const char *fmt, va_list ap, BOOL add_backtrace)
6637
65
{
6638
65
    char buf[256];
6639
65
    JSValue obj, ret;
6640
6641
65
    vsnprintf(buf, sizeof(buf), fmt, ap);
6642
65
    obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num],
6643
65
                                 JS_CLASS_ERROR);
6644
65
    if (unlikely(JS_IsException(obj))) {
6645
        /* out of memory: throw JS_NULL to avoid recursing */
6646
0
        obj = JS_NULL;
6647
65
    } else {
6648
65
        JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,
6649
65
                               JS_NewString(ctx, buf),
6650
65
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6651
65
    }
6652
65
    if (add_backtrace) {
6653
39
        build_backtrace(ctx, obj, NULL, 0, 0);
6654
39
    }
6655
65
    ret = JS_Throw(ctx, obj);
6656
65
    return ret;
6657
65
}
6658
6659
static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num,
6660
                             const char *fmt, va_list ap)
6661
48
{
6662
48
    JSRuntime *rt = ctx->rt;
6663
48
    JSStackFrame *sf;
6664
48
    BOOL add_backtrace;
6665
6666
    /* the backtrace is added later if called from a bytecode function */
6667
48
    sf = rt->current_stack_frame;
6668
48
    add_backtrace = !rt->in_out_of_memory &&
6669
48
        (!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL));
6670
48
    return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace);
6671
48
}
6672
6673
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...)
6674
0
{
6675
0
    JSValue val;
6676
0
    va_list ap;
6677
6678
0
    va_start(ap, fmt);
6679
0
    val = JS_ThrowError(ctx, JS_SYNTAX_ERROR, fmt, ap);
6680
0
    va_end(ap);
6681
0
    return val;
6682
0
}
6683
6684
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...)
6685
39
{
6686
39
    JSValue val;
6687
39
    va_list ap;
6688
6689
39
    va_start(ap, fmt);
6690
39
    val = JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
6691
39
    va_end(ap);
6692
39
    return val;
6693
39
}
6694
6695
static int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...)
6696
0
{
6697
0
    va_list ap;
6698
6699
0
    if ((flags & JS_PROP_THROW) ||
6700
0
        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
6701
0
        va_start(ap, fmt);
6702
0
        JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
6703
0
        va_end(ap);
6704
0
        return -1;
6705
0
    } else {
6706
0
        return FALSE;
6707
0
    }
6708
0
}
6709
6710
/* never use it directly */
6711
static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
6712
0
{
6713
0
    char buf[ATOM_GET_STR_BUF_SIZE];
6714
0
    return JS_ThrowTypeError(ctx, fmt,
6715
0
                             JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
6716
0
}
6717
6718
/* never use it directly */
6719
static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
6720
0
{
6721
0
    char buf[ATOM_GET_STR_BUF_SIZE];
6722
0
    return JS_ThrowSyntaxError(ctx, fmt,
6723
0
                             JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
6724
0
}
6725
6726
/* %s is replaced by 'atom'. The macro is used so that gcc can check
6727
    the format string. */
6728
0
#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, "")
6729
0
#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, "")
6730
6731
static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)
6732
0
{
6733
0
    if ((flags & JS_PROP_THROW) ||
6734
0
        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
6735
0
        JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom);
6736
0
        return -1;
6737
0
    } else {
6738
0
        return FALSE;
6739
0
    }
6740
0
}
6741
6742
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...)
6743
9
{
6744
9
    JSValue val;
6745
9
    va_list ap;
6746
6747
9
    va_start(ap, fmt);
6748
9
    val = JS_ThrowError(ctx, JS_REFERENCE_ERROR, fmt, ap);
6749
9
    va_end(ap);
6750
9
    return val;
6751
9
}
6752
6753
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...)
6754
0
{
6755
0
    JSValue val;
6756
0
    va_list ap;
6757
6758
0
    va_start(ap, fmt);
6759
0
    val = JS_ThrowError(ctx, JS_RANGE_ERROR, fmt, ap);
6760
0
    va_end(ap);
6761
0
    return val;
6762
0
}
6763
6764
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...)
6765
0
{
6766
0
    JSValue val;
6767
0
    va_list ap;
6768
6769
0
    va_start(ap, fmt);
6770
0
    val = JS_ThrowError(ctx, JS_INTERNAL_ERROR, fmt, ap);
6771
0
    va_end(ap);
6772
0
    return val;
6773
0
}
6774
6775
JSValue JS_ThrowOutOfMemory(JSContext *ctx)
6776
0
{
6777
0
    JSRuntime *rt = ctx->rt;
6778
0
    if (!rt->in_out_of_memory) {
6779
0
        rt->in_out_of_memory = TRUE;
6780
0
        JS_ThrowInternalError(ctx, "out of memory");
6781
0
        rt->in_out_of_memory = FALSE;
6782
0
    }
6783
0
    return JS_EXCEPTION;
6784
0
}
6785
6786
static JSValue JS_ThrowStackOverflow(JSContext *ctx)
6787
0
{
6788
0
    return JS_ThrowInternalError(ctx, "stack overflow");
6789
0
}
6790
6791
static JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx)
6792
0
{
6793
0
    return JS_ThrowTypeError(ctx, "not an object");
6794
0
}
6795
6796
static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx)
6797
0
{
6798
0
    return JS_ThrowTypeError(ctx, "not a symbol");
6799
0
}
6800
6801
static JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name)
6802
9
{
6803
9
    char buf[ATOM_GET_STR_BUF_SIZE];
6804
9
    return JS_ThrowReferenceError(ctx, "'%s' is not defined",
6805
9
                                  JS_AtomGetStr(ctx, buf, sizeof(buf), name));
6806
9
}
6807
6808
static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name)
6809
0
{
6810
0
    char buf[ATOM_GET_STR_BUF_SIZE];
6811
0
    return JS_ThrowReferenceError(ctx, "%s is not initialized",
6812
0
                                  name == JS_ATOM_NULL ? "lexical variable" :
6813
0
                                  JS_AtomGetStr(ctx, buf, sizeof(buf), name));
6814
0
}
6815
6816
static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx,
6817
                                                    JSFunctionBytecode *b,
6818
                                                    int idx, BOOL is_ref)
6819
0
{
6820
0
    JSAtom atom = JS_ATOM_NULL;
6821
0
    if (is_ref) {
6822
0
        atom = b->closure_var[idx].var_name;
6823
0
    } else {
6824
        /* not present if the function is stripped and contains no eval() */
6825
0
        if (b->vardefs)
6826
0
            atom = b->vardefs[b->arg_count + idx].var_name;
6827
0
    }
6828
0
    return JS_ThrowReferenceErrorUninitialized(ctx, atom);
6829
0
}
6830
6831
static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
6832
0
{
6833
0
    JSRuntime *rt = ctx->rt;
6834
0
    JSAtom name;
6835
0
    name = rt->class_array[class_id].class_name;
6836
0
    return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
6837
0
}
6838
6839
static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
6840
39
{
6841
39
    JSRuntime *rt = ctx->rt;
6842
39
    ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
6843
39
    if (rt->interrupt_handler) {
6844
39
        if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {
6845
            /* XXX: should set a specific flag to avoid catching */
6846
0
            JS_ThrowInternalError(ctx, "interrupted");
6847
0
            JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE);
6848
0
            return -1;
6849
0
        }
6850
39
    }
6851
39
    return 0;
6852
39
}
6853
6854
static inline __exception int js_poll_interrupts(JSContext *ctx)
6855
336
{
6856
336
    if (unlikely(--ctx->interrupt_counter <= 0)) {
6857
39
        return __js_poll_interrupts(ctx);
6858
297
    } else {
6859
297
        return 0;
6860
297
    }
6861
336
}
6862
6863
/* return -1 (exception) or TRUE/FALSE */
6864
static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj,
6865
                                   JSValueConst proto_val,
6866
                                   BOOL throw_flag)
6867
0
{
6868
0
    JSObject *proto, *p, *p1;
6869
0
    JSShape *sh;
6870
6871
0
    if (throw_flag) {
6872
0
        if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL ||
6873
0
            JS_VALUE_GET_TAG(obj) == JS_TAG_UNDEFINED)
6874
0
            goto not_obj;
6875
0
    } else {
6876
0
        if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6877
0
            goto not_obj;
6878
0
    }
6879
0
    p = JS_VALUE_GET_OBJ(obj);
6880
0
    if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) {
6881
0
        if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_NULL) {
6882
0
        not_obj:
6883
0
            JS_ThrowTypeErrorNotAnObject(ctx);
6884
0
            return -1;
6885
0
        }
6886
0
        proto = NULL;
6887
0
    } else {
6888
0
        proto = JS_VALUE_GET_OBJ(proto_val);
6889
0
    }
6890
6891
0
    if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6892
0
        return TRUE;
6893
6894
0
    if (unlikely(p->class_id == JS_CLASS_PROXY))
6895
0
        return js_proxy_setPrototypeOf(ctx, obj, proto_val, throw_flag);
6896
0
    sh = p->shape;
6897
0
    if (sh->proto == proto)
6898
0
        return TRUE;
6899
0
    if (!p->extensible) {
6900
0
        if (throw_flag) {
6901
0
            JS_ThrowTypeError(ctx, "object is not extensible");
6902
0
            return -1;
6903
0
        } else {
6904
0
            return FALSE;
6905
0
        }
6906
0
    }
6907
0
    if (proto) {
6908
        /* check if there is a cycle */
6909
0
        p1 = proto;
6910
0
        do {
6911
0
            if (p1 == p) {
6912
0
                if (throw_flag) {
6913
0
                    JS_ThrowTypeError(ctx, "circular prototype chain");
6914
0
                    return -1;
6915
0
                } else {
6916
0
                    return FALSE;
6917
0
                }
6918
0
            }
6919
            /* Note: for Proxy objects, proto is NULL */
6920
0
            p1 = p1->shape->proto;
6921
0
        } while (p1 != NULL);
6922
0
        JS_DupValue(ctx, proto_val);
6923
0
    }
6924
6925
0
    if (js_shape_prepare_update(ctx, p, NULL))
6926
0
        return -1;
6927
0
    sh = p->shape;
6928
0
    if (sh->proto)
6929
0
        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
6930
0
    sh->proto = proto;
6931
0
    return TRUE;
6932
0
}
6933
6934
/* return -1 (exception) or TRUE/FALSE */
6935
int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val)
6936
0
{
6937
0
    return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE);
6938
0
}
6939
6940
/* Only works for primitive types, otherwise return JS_NULL. */
6941
static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val)
6942
0
{
6943
0
    switch(JS_VALUE_GET_NORM_TAG(val)) {
6944
0
    case JS_TAG_BIG_INT:
6945
0
        val = ctx->class_proto[JS_CLASS_BIG_INT];
6946
0
        break;
6947
0
#ifdef CONFIG_BIGNUM
6948
0
    case JS_TAG_BIG_FLOAT:
6949
0
        val = ctx->class_proto[JS_CLASS_BIG_FLOAT];
6950
0
        break;
6951
0
    case JS_TAG_BIG_DECIMAL:
6952
0
        val = ctx->class_proto[JS_CLASS_BIG_DECIMAL];
6953
0
        break;
6954
0
#endif
6955
0
    case JS_TAG_INT:
6956
0
    case JS_TAG_FLOAT64:
6957
0
        val = ctx->class_proto[JS_CLASS_NUMBER];
6958
0
        break;
6959
0
    case JS_TAG_BOOL:
6960
0
        val = ctx->class_proto[JS_CLASS_BOOLEAN];
6961
0
        break;
6962
0
    case JS_TAG_STRING:
6963
0
        val = ctx->class_proto[JS_CLASS_STRING];
6964
0
        break;
6965
0
    case JS_TAG_SYMBOL:
6966
0
        val = ctx->class_proto[JS_CLASS_SYMBOL];
6967
0
        break;
6968
0
    case JS_TAG_OBJECT:
6969
0
    case JS_TAG_NULL:
6970
0
    case JS_TAG_UNDEFINED:
6971
0
    default:
6972
0
        val = JS_NULL;
6973
0
        break;
6974
0
    }
6975
0
    return val;
6976
0
}
6977
6978
/* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */
6979
JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj)
6980
0
{
6981
0
    JSValue val;
6982
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
6983
0
        JSObject *p;
6984
0
        p = JS_VALUE_GET_OBJ(obj);
6985
0
        if (unlikely(p->class_id == JS_CLASS_PROXY)) {
6986
0
            val = js_proxy_getPrototypeOf(ctx, obj);
6987
0
        } else {
6988
0
            p = p->shape->proto;
6989
0
            if (!p)
6990
0
                val = JS_NULL;
6991
0
            else
6992
0
                val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
6993
0
        }
6994
0
    } else {
6995
0
        val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj));
6996
0
    }
6997
0
    return val;
6998
0
}
6999
7000
static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj)
7001
0
{
7002
0
    JSValue obj1;
7003
0
    obj1 = JS_GetPrototype(ctx, obj);
7004
0
    JS_FreeValue(ctx, obj);
7005
0
    return obj1;
7006
0
}
7007
7008
/* return TRUE, FALSE or (-1) in case of exception */
7009
static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val,
7010
                                   JSValueConst obj)
7011
0
{
7012
0
    JSValue obj_proto;
7013
0
    JSObject *proto;
7014
0
    const JSObject *p, *proto1;
7015
0
    BOOL ret;
7016
7017
0
    if (!JS_IsFunction(ctx, obj))
7018
0
        return FALSE;
7019
0
    p = JS_VALUE_GET_OBJ(obj);
7020
0
    if (p->class_id == JS_CLASS_BOUND_FUNCTION) {
7021
0
        JSBoundFunction *s = p->u.bound_function;
7022
0
        return JS_IsInstanceOf(ctx, val, s->func_obj);
7023
0
    }
7024
7025
    /* Only explicitly boxed values are instances of constructors */
7026
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
7027
0
        return FALSE;
7028
0
    obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype);
7029
0
    if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) {
7030
0
        if (!JS_IsException(obj_proto))
7031
0
            JS_ThrowTypeError(ctx, "operand 'prototype' property is not an object");
7032
0
        ret = -1;
7033
0
        goto done;
7034
0
    }
7035
0
    proto = JS_VALUE_GET_OBJ(obj_proto);
7036
0
    p = JS_VALUE_GET_OBJ(val);
7037
0
    for(;;) {
7038
0
        proto1 = p->shape->proto;
7039
0
        if (!proto1) {
7040
            /* slow case if proxy in the prototype chain */
7041
0
            if (unlikely(p->class_id == JS_CLASS_PROXY)) {
7042
0
                JSValue obj1;
7043
0
                obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p));
7044
0
                for(;;) {
7045
0
                    obj1 = JS_GetPrototypeFree(ctx, obj1);
7046
0
                    if (JS_IsException(obj1)) {
7047
0
                        ret = -1;
7048
0
                        break;
7049
0
                    }
7050
0
                    if (JS_IsNull(obj1)) {
7051
0
                        ret = FALSE;
7052
0
                        break;
7053
0
                    }
7054
0
                    if (proto == JS_VALUE_GET_OBJ(obj1)) {
7055
0
                        JS_FreeValue(ctx, obj1);
7056
0
                        ret = TRUE;
7057
0
                        break;
7058
0
                    }
7059
                    /* must check for timeout to avoid infinite loop */
7060
0
                    if (js_poll_interrupts(ctx)) {
7061
0
                        JS_FreeValue(ctx, obj1);
7062
0
                        ret = -1;
7063
0
                        break;
7064
0
                    }
7065
0
                }
7066
0
            } else {
7067
0
                ret = FALSE;
7068
0
            }
7069
0
            break;
7070
0
        }
7071
0
        p = proto1;
7072
0
        if (proto == p) {
7073
0
            ret = TRUE;
7074
0
            break;
7075
0
        }
7076
0
    }
7077
0
done:
7078
0
    JS_FreeValue(ctx, obj_proto);
7079
0
    return ret;
7080
0
}
7081
7082
/* return TRUE, FALSE or (-1) in case of exception */
7083
int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj)
7084
0
{
7085
0
    JSValue method;
7086
7087
0
    if (!JS_IsObject(obj))
7088
0
        goto fail;
7089
0
    method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_hasInstance);
7090
0
    if (JS_IsException(method))
7091
0
        return -1;
7092
0
    if (!JS_IsNull(method) && !JS_IsUndefined(method)) {
7093
0
        JSValue ret;
7094
0
        ret = JS_CallFree(ctx, method, obj, 1, &val);
7095
0
        return JS_ToBoolFree(ctx, ret);
7096
0
    }
7097
7098
    /* legacy case */
7099
0
    if (!JS_IsFunction(ctx, obj)) {
7100
0
    fail:
7101
0
        JS_ThrowTypeError(ctx, "invalid 'instanceof' right operand");
7102
0
        return -1;
7103
0
    }
7104
0
    return JS_OrdinaryIsInstanceOf(ctx, val, obj);
7105
0
}
7106
7107
/* return the value associated to the autoinit property or an exception */
7108
typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
7109
7110
static JSAutoInitFunc *js_autoinit_func_table[] = {
7111
    js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */
7112
    js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */
7113
    JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */
7114
};
7115
7116
/* warning: 'prs' is reallocated after it */
7117
static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
7118
                               JSProperty *pr, JSShapeProperty *prs)
7119
390
{
7120
390
    JSValue val;
7121
390
    JSContext *realm;
7122
390
    JSAutoInitFunc *func;
7123
7124
390
    if (js_shape_prepare_update(ctx, p, &prs))
7125
0
        return -1;
7126
7127
390
    realm = js_autoinit_get_realm(pr);
7128
390
    func = js_autoinit_func_table[js_autoinit_get_id(pr)];
7129
    /* 'func' shall not modify the object properties 'pr' */
7130
390
    val = func(realm, p, prop, pr->u.init.opaque);
7131
390
    js_autoinit_free(ctx->rt, pr);
7132
390
    prs->flags &= ~JS_PROP_TMASK;
7133
390
    pr->u.value = JS_UNDEFINED;
7134
390
    if (JS_IsException(val))
7135
0
        return -1;
7136
390
    pr->u.value = val;
7137
390
    return 0;
7138
390
}
7139
7140
JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
7141
                               JSAtom prop, JSValueConst this_obj,
7142
                               BOOL throw_ref_error)
7143
555
{
7144
555
    JSObject *p;
7145
555
    JSProperty *pr;
7146
555
    JSShapeProperty *prs;
7147
555
    uint32_t tag;
7148
7149
555
    tag = JS_VALUE_GET_TAG(obj);
7150
555
    if (unlikely(tag != JS_TAG_OBJECT)) {
7151
0
        switch(tag) {
7152
0
        case JS_TAG_NULL:
7153
0
            return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop);
7154
0
        case JS_TAG_UNDEFINED:
7155
0
            return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop);
7156
0
        case JS_TAG_EXCEPTION:
7157
0
            return JS_EXCEPTION;
7158
0
        case JS_TAG_STRING:
7159
0
            {
7160
0
                JSString *p1 = JS_VALUE_GET_STRING(obj);
7161
0
                if (__JS_AtomIsTaggedInt(prop)) {
7162
0
                    uint32_t idx, ch;
7163
0
                    idx = __JS_AtomToUInt32(prop);
7164
0
                    if (idx < p1->len) {
7165
0
                        if (p1->is_wide_char)
7166
0
                            ch = p1->u.str16[idx];
7167
0
                        else
7168
0
                            ch = p1->u.str8[idx];
7169
0
                        return js_new_string_char(ctx, ch);
7170
0
                    }
7171
0
                } else if (prop == JS_ATOM_length) {
7172
0
                    return JS_NewInt32(ctx, p1->len);
7173
0
                }
7174
0
            }
7175
0
            break;
7176
0
        default:
7177
0
            break;
7178
0
        }
7179
        /* cannot raise an exception */
7180
0
        p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));
7181
0
        if (!p)
7182
0
            return JS_UNDEFINED;
7183
555
    } else {
7184
555
        p = JS_VALUE_GET_OBJ(obj);
7185
555
    }
7186
7187
954
    for(;;) {
7188
954
        prs = find_own_property(&pr, p, prop);
7189
954
        if (prs) {
7190
            /* found */
7191
936
            if (unlikely(prs->flags & JS_PROP_TMASK)) {
7192
390
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
7193
0
                    if (unlikely(!pr->u.getset.getter)) {
7194
0
                        return JS_UNDEFINED;
7195
0
                    } else {
7196
0
                        JSValue func = JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter);
7197
                        /* Note: the field could be removed in the getter */
7198
0
                        func = JS_DupValue(ctx, func);
7199
0
                        return JS_CallFree(ctx, func, this_obj, 0, NULL);
7200
0
                    }
7201
390
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
7202
0
                    JSValue val = *pr->u.var_ref->pvalue;
7203
0
                    if (unlikely(JS_IsUninitialized(val)))
7204
0
                        return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7205
0
                    return JS_DupValue(ctx, val);
7206
390
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
7207
                    /* Instantiate property and retry */
7208
390
                    if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
7209
0
                        return JS_EXCEPTION;
7210
390
                    continue;
7211
390
                }
7212
546
            } else {
7213
546
                return JS_DupValue(ctx, pr->u.value);
7214
546
            }
7215
936
        }
7216
18
        if (unlikely(p->is_exotic)) {
7217
            /* exotic behaviors */
7218
0
            if (p->fast_array) {
7219
0
                if (__JS_AtomIsTaggedInt(prop)) {
7220
0
                    uint32_t idx = __JS_AtomToUInt32(prop);
7221
0
                    if (idx < p->u.array.count) {
7222
                        /* we avoid duplicating the code */
7223
0
                        return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
7224
0
                    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
7225
0
                               p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
7226
0
                        return JS_UNDEFINED;
7227
0
                    }
7228
0
                } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
7229
0
                           p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
7230
0
                    int ret;
7231
0
                    ret = JS_AtomIsNumericIndex(ctx, prop);
7232
0
                    if (ret != 0) {
7233
0
                        if (ret < 0)
7234
0
                            return JS_EXCEPTION;
7235
0
                        return JS_UNDEFINED;
7236
0
                    }
7237
0
                }
7238
0
            } else {
7239
0
                const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7240
0
                if (em) {
7241
0
                    if (em->get_property) {
7242
0
                        JSValue obj1, retval;
7243
                        /* XXX: should pass throw_ref_error */
7244
                        /* Note: if 'p' is a prototype, it can be
7245
                           freed in the called function */
7246
0
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7247
0
                        retval = em->get_property(ctx, obj1, prop, this_obj);
7248
0
                        JS_FreeValue(ctx, obj1);
7249
0
                        return retval;
7250
0
                    }
7251
0
                    if (em->get_own_property) {
7252
0
                        JSPropertyDescriptor desc;
7253
0
                        int ret;
7254
0
                        JSValue obj1;
7255
7256
                        /* Note: if 'p' is a prototype, it can be
7257
                           freed in the called function */
7258
0
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7259
0
                        ret = em->get_own_property(ctx, &desc, obj1, prop);
7260
0
                        JS_FreeValue(ctx, obj1);
7261
0
                        if (ret < 0)
7262
0
                            return JS_EXCEPTION;
7263
0
                        if (ret) {
7264
0
                            if (desc.flags & JS_PROP_GETSET) {
7265
0
                                JS_FreeValue(ctx, desc.setter);
7266
0
                                return JS_CallFree(ctx, desc.getter, this_obj, 0, NULL);
7267
0
                            } else {
7268
0
                                return desc.value;
7269
0
                            }
7270
0
                        }
7271
0
                    }
7272
0
                }
7273
0
            }
7274
0
        }
7275
18
        p = p->shape->proto;
7276
18
        if (!p)
7277
9
            break;
7278
18
    }
7279
9
    if (unlikely(throw_ref_error)) {
7280
9
        return JS_ThrowReferenceErrorNotDefined(ctx, prop);
7281
9
    } else {
7282
0
        return JS_UNDEFINED;
7283
0
    }
7284
9
}
7285
7286
static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom)
7287
0
{
7288
0
    return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist",
7289
0
                                 atom);
7290
0
}
7291
7292
/* Private fields can be added even on non extensible objects or
7293
   Proxies */
7294
static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj,
7295
                                 JSValueConst name, JSValue val)
7296
0
{
7297
0
    JSObject *p;
7298
0
    JSShapeProperty *prs;
7299
0
    JSProperty *pr;
7300
0
    JSAtom prop;
7301
7302
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
7303
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7304
0
        goto fail;
7305
0
    }
7306
    /* safety check */
7307
0
    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
7308
0
        JS_ThrowTypeErrorNotASymbol(ctx);
7309
0
        goto fail;
7310
0
    }
7311
0
    prop = js_symbol_to_atom(ctx, (JSValue)name);
7312
0
    p = JS_VALUE_GET_OBJ(obj);
7313
0
    prs = find_own_property(&pr, p, prop);
7314
0
    if (prs) {
7315
0
        JS_ThrowTypeErrorAtom(ctx, "private class field '%s' already exists",
7316
0
                              prop);
7317
0
        goto fail;
7318
0
    }
7319
0
    pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
7320
0
    if (unlikely(!pr)) {
7321
0
    fail:
7322
0
        JS_FreeValue(ctx, val);
7323
0
        return -1;
7324
0
    }
7325
0
    pr->u.value = val;
7326
0
    return 0;
7327
0
}
7328
7329
static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj,
7330
                                  JSValueConst name)
7331
0
{
7332
0
    JSObject *p;
7333
0
    JSShapeProperty *prs;
7334
0
    JSProperty *pr;
7335
0
    JSAtom prop;
7336
7337
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7338
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
7339
    /* safety check */
7340
0
    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL))
7341
0
        return JS_ThrowTypeErrorNotASymbol(ctx);
7342
0
    prop = js_symbol_to_atom(ctx, (JSValue)name);
7343
0
    p = JS_VALUE_GET_OBJ(obj);
7344
0
    prs = find_own_property(&pr, p, prop);
7345
0
    if (!prs) {
7346
0
        JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
7347
0
        return JS_EXCEPTION;
7348
0
    }
7349
0
    return JS_DupValue(ctx, pr->u.value);
7350
0
}
7351
7352
static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj,
7353
                              JSValueConst name, JSValue val)
7354
0
{
7355
0
    JSObject *p;
7356
0
    JSShapeProperty *prs;
7357
0
    JSProperty *pr;
7358
0
    JSAtom prop;
7359
7360
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
7361
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7362
0
        goto fail;
7363
0
    }
7364
    /* safety check */
7365
0
    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
7366
0
        JS_ThrowTypeErrorNotASymbol(ctx);
7367
0
        goto fail;
7368
0
    }
7369
0
    prop = js_symbol_to_atom(ctx, (JSValue)name);
7370
0
    p = JS_VALUE_GET_OBJ(obj);
7371
0
    prs = find_own_property(&pr, p, prop);
7372
0
    if (!prs) {
7373
0
        JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
7374
0
    fail:
7375
0
        JS_FreeValue(ctx, val);
7376
0
        return -1;
7377
0
    }
7378
0
    set_value(ctx, &pr->u.value, val);
7379
0
    return 0;
7380
0
}
7381
7382
/* add a private brand field to 'home_obj' if not already present and
7383
   if obj is != null add a private brand to it */
7384
static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
7385
0
{
7386
0
    JSObject *p, *p1;
7387
0
    JSShapeProperty *prs;
7388
0
    JSProperty *pr;
7389
0
    JSValue brand;
7390
0
    JSAtom brand_atom;
7391
7392
0
    if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) {
7393
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7394
0
        return -1;
7395
0
    }
7396
0
    p = JS_VALUE_GET_OBJ(home_obj);
7397
0
    prs = find_own_property(&pr, p, JS_ATOM_Private_brand);
7398
0
    if (!prs) {
7399
        /* if the brand is not present, add it */
7400
0
        brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE);
7401
0
        if (JS_IsException(brand))
7402
0
            return -1;
7403
0
        pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E);
7404
0
        if (!pr) {
7405
0
            JS_FreeValue(ctx, brand);
7406
0
            return -1;
7407
0
        }
7408
0
        pr->u.value = JS_DupValue(ctx, brand);
7409
0
    } else {
7410
0
        brand = JS_DupValue(ctx, pr->u.value);
7411
0
    }
7412
0
    brand_atom = js_symbol_to_atom(ctx, brand);
7413
7414
0
    if (JS_IsObject(obj)) {
7415
0
        p1 = JS_VALUE_GET_OBJ(obj);
7416
0
        prs = find_own_property(&pr, p1, brand_atom);
7417
0
        if (unlikely(prs)) {
7418
0
            JS_FreeAtom(ctx, brand_atom);
7419
0
            JS_ThrowTypeError(ctx, "private method is already present");
7420
0
            return -1;
7421
0
        }
7422
0
        pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E);
7423
0
        JS_FreeAtom(ctx, brand_atom);
7424
0
        if (!pr)
7425
0
            return -1;
7426
0
        pr->u.value = JS_UNDEFINED;
7427
0
    } else {
7428
0
        JS_FreeAtom(ctx, brand_atom);
7429
0
    }
7430
0
    return 0;
7431
0
}
7432
7433
/* return a boolean telling if the brand of the home object of 'func'
7434
   is present on 'obj' or -1 in case of exception */
7435
static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
7436
0
{
7437
0
    JSObject *p, *p1, *home_obj;
7438
0
    JSShapeProperty *prs;
7439
0
    JSProperty *pr;
7440
0
    JSValueConst brand;
7441
7442
    /* get the home object of 'func' */
7443
0
    if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT))
7444
0
        goto not_obj;
7445
0
    p1 = JS_VALUE_GET_OBJ(func);
7446
0
    if (!js_class_has_bytecode(p1->class_id))
7447
0
        goto not_obj;
7448
0
    home_obj = p1->u.func.home_object;
7449
0
    if (!home_obj)
7450
0
        goto not_obj;
7451
0
    prs = find_own_property(&pr, home_obj, JS_ATOM_Private_brand);
7452
0
    if (!prs) {
7453
0
        JS_ThrowTypeError(ctx, "expecting <brand> private field");
7454
0
        return -1;
7455
0
    }
7456
0
    brand = pr->u.value;
7457
    /* safety check */
7458
0
    if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL))
7459
0
        goto not_obj;
7460
7461
    /* get the brand array of 'obj' */
7462
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
7463
0
    not_obj:
7464
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7465
0
        return -1;
7466
0
    }
7467
0
    p = JS_VALUE_GET_OBJ(obj);
7468
0
    prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand));
7469
0
    return (prs != NULL);
7470
0
}
7471
7472
static uint32_t js_string_obj_get_length(JSContext *ctx,
7473
                                         JSValueConst obj)
7474
0
{
7475
0
    JSObject *p;
7476
0
    JSString *p1;
7477
0
    uint32_t len = 0;
7478
7479
    /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
7480
0
    p = JS_VALUE_GET_OBJ(obj);
7481
0
    if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
7482
0
        p1 = JS_VALUE_GET_STRING(p->u.object_data);
7483
0
        len = p1->len;
7484
0
    }
7485
0
    return len;
7486
0
}
7487
7488
static int num_keys_cmp(const void *p1, const void *p2, void *opaque)
7489
0
{
7490
0
    JSContext *ctx = opaque;
7491
0
    JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom;
7492
0
    JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom;
7493
0
    uint32_t v1, v2;
7494
0
    BOOL atom1_is_integer, atom2_is_integer;
7495
7496
0
    atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1);
7497
0
    atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2);
7498
0
    assert(atom1_is_integer && atom2_is_integer);
7499
0
    if (v1 < v2)
7500
0
        return -1;
7501
0
    else if (v1 == v2)
7502
0
        return 0;
7503
0
    else
7504
0
        return 1;
7505
0
}
7506
7507
static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
7508
39
{
7509
39
    uint32_t i;
7510
39
    if (tab) {
7511
117
        for(i = 0; i < len; i++)
7512
78
            JS_FreeAtom(ctx, tab[i].atom);
7513
39
        js_free(ctx, tab);
7514
39
    }
7515
39
}
7516
7517
/* return < 0 in case if exception, 0 if OK. ptab and its atoms must
7518
   be freed by the user. */
7519
static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
7520
                                                      JSPropertyEnum **ptab,
7521
                                                      uint32_t *plen,
7522
                                                      JSObject *p, int flags)
7523
39
{
7524
39
    int i, j;
7525
39
    JSShape *sh;
7526
39
    JSShapeProperty *prs;
7527
39
    JSPropertyEnum *tab_atom, *tab_exotic;
7528
39
    JSAtom atom;
7529
39
    uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count;
7530
39
    uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count;
7531
39
    BOOL is_enumerable, num_sorted;
7532
39
    uint32_t num_key;
7533
39
    JSAtomKindEnum kind;
7534
7535
    /* clear pointer for consistency in case of failure */
7536
39
    *ptab = NULL;
7537
39
    *plen = 0;
7538
7539
    /* compute the number of returned properties */
7540
39
    num_keys_count = 0;
7541
39
    str_keys_count = 0;
7542
39
    sym_keys_count = 0;
7543
39
    exotic_keys_count = 0;
7544
39
    exotic_count = 0;
7545
39
    tab_exotic = NULL;
7546
39
    sh = p->shape;
7547
117
    for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
7548
78
        atom = prs->atom;
7549
78
        if (atom != JS_ATOM_NULL) {
7550
78
            is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
7551
78
            kind = JS_AtomGetKind(ctx, atom);
7552
78
            if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
7553
78
                ((flags >> kind) & 1) != 0) {
7554
                /* need to raise an exception in case of the module
7555
                   name space (implicit GetOwnProperty) */
7556
78
                if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) &&
7557
78
                    (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY))) {
7558
0
                    JSVarRef *var_ref = p->prop[i].u.var_ref;
7559
0
                    if (unlikely(JS_IsUninitialized(*var_ref->pvalue))) {
7560
0
                        JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7561
0
                        return -1;
7562
0
                    }
7563
0
                }
7564
78
                if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
7565
0
                    num_keys_count++;
7566
78
                } else if (kind == JS_ATOM_KIND_STRING) {
7567
78
                    str_keys_count++;
7568
78
                } else {
7569
0
                    sym_keys_count++;
7570
0
                }
7571
78
            }
7572
78
        }
7573
78
    }
7574
7575
39
    if (p->is_exotic) {
7576
0
        if (p->fast_array) {
7577
0
            if (flags & JS_GPN_STRING_MASK) {
7578
0
                num_keys_count += p->u.array.count;
7579
0
            }
7580
0
        } else if (p->class_id == JS_CLASS_STRING) {
7581
0
            if (flags & JS_GPN_STRING_MASK) {
7582
0
                num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7583
0
            }
7584
0
        } else {
7585
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7586
0
            if (em && em->get_own_property_names) {
7587
0
                if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count,
7588
0
                                               JS_MKPTR(JS_TAG_OBJECT, p)))
7589
0
                    return -1;
7590
0
                for(i = 0; i < exotic_count; i++) {
7591
0
                    atom = tab_exotic[i].atom;
7592
0
                    kind = JS_AtomGetKind(ctx, atom);
7593
0
                    if (((flags >> kind) & 1) != 0) {
7594
0
                        is_enumerable = FALSE;
7595
0
                        if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) {
7596
0
                            JSPropertyDescriptor desc;
7597
0
                            int res;
7598
                            /* set the "is_enumerable" field if necessary */
7599
0
                            res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
7600
0
                            if (res < 0) {
7601
0
                                js_free_prop_enum(ctx, tab_exotic, exotic_count);
7602
0
                                return -1;
7603
0
                            }
7604
0
                            if (res) {
7605
0
                                is_enumerable =
7606
0
                                    ((desc.flags & JS_PROP_ENUMERABLE) != 0);
7607
0
                                js_free_desc(ctx, &desc);
7608
0
                            }
7609
0
                            tab_exotic[i].is_enumerable = is_enumerable;
7610
0
                        }
7611
0
                        if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) {
7612
0
                            exotic_keys_count++;
7613
0
                        }
7614
0
                    }
7615
0
                }
7616
0
            }
7617
0
        }
7618
0
    }
7619
7620
    /* fill them */
7621
7622
39
    atom_count = num_keys_count + str_keys_count + sym_keys_count + exotic_keys_count;
7623
    /* avoid allocating 0 bytes */
7624
39
    tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));
7625
39
    if (!tab_atom) {
7626
0
        js_free_prop_enum(ctx, tab_exotic, exotic_count);
7627
0
        return -1;
7628
0
    }
7629
7630
39
    num_index = 0;
7631
39
    str_index = num_keys_count;
7632
39
    sym_index = str_index + str_keys_count;
7633
7634
39
    num_sorted = TRUE;
7635
39
    sh = p->shape;
7636
117
    for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
7637
78
        atom = prs->atom;
7638
78
        if (atom != JS_ATOM_NULL) {
7639
78
            is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
7640
78
            kind = JS_AtomGetKind(ctx, atom);
7641
78
            if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
7642
78
                ((flags >> kind) & 1) != 0) {
7643
78
                if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
7644
0
                    j = num_index++;
7645
0
                    num_sorted = FALSE;
7646
78
                } else if (kind == JS_ATOM_KIND_STRING) {
7647
78
                    j = str_index++;
7648
78
                } else {
7649
0
                    j = sym_index++;
7650
0
                }
7651
78
                tab_atom[j].atom = JS_DupAtom(ctx, atom);
7652
78
                tab_atom[j].is_enumerable = is_enumerable;
7653
78
            }
7654
78
        }
7655
78
    }
7656
7657
39
    if (p->is_exotic) {
7658
0
        int len;
7659
0
        if (p->fast_array) {
7660
0
            if (flags & JS_GPN_STRING_MASK) {
7661
0
                len = p->u.array.count;
7662
0
                goto add_array_keys;
7663
0
            }
7664
0
        } else if (p->class_id == JS_CLASS_STRING) {
7665
0
            if (flags & JS_GPN_STRING_MASK) {
7666
0
                len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7667
0
            add_array_keys:
7668
0
                for(i = 0; i < len; i++) {
7669
0
                    tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
7670
0
                    if (tab_atom[num_index].atom == JS_ATOM_NULL) {
7671
0
                        js_free_prop_enum(ctx, tab_atom, num_index);
7672
0
                        return -1;
7673
0
                    }
7674
0
                    tab_atom[num_index].is_enumerable = TRUE;
7675
0
                    num_index++;
7676
0
                }
7677
0
            }
7678
0
        } else {
7679
            /* Note: exotic keys are not reordered and comes after the object own properties. */
7680
0
            for(i = 0; i < exotic_count; i++) {
7681
0
                atom = tab_exotic[i].atom;
7682
0
                is_enumerable = tab_exotic[i].is_enumerable;
7683
0
                kind = JS_AtomGetKind(ctx, atom);
7684
0
                if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
7685
0
                    ((flags >> kind) & 1) != 0) {
7686
0
                    tab_atom[sym_index].atom = atom;
7687
0
                    tab_atom[sym_index].is_enumerable = is_enumerable;
7688
0
                    sym_index++;
7689
0
                } else {
7690
0
                    JS_FreeAtom(ctx, atom);
7691
0
                }
7692
0
            }
7693
0
            js_free(ctx, tab_exotic);
7694
0
        }
7695
0
    }
7696
7697
39
    assert(num_index == num_keys_count);
7698
39
    assert(str_index == num_keys_count + str_keys_count);
7699
39
    assert(sym_index == atom_count);
7700
7701
39
    if (num_keys_count != 0 && !num_sorted) {
7702
0
        rqsort(tab_atom, num_keys_count, sizeof(tab_atom[0]), num_keys_cmp,
7703
0
               ctx);
7704
0
    }
7705
39
    *ptab = tab_atom;
7706
39
    *plen = atom_count;
7707
39
    return 0;
7708
39
}
7709
7710
int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
7711
                           uint32_t *plen, JSValueConst obj, int flags)
7712
0
{
7713
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
7714
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7715
0
        return -1;
7716
0
    }
7717
0
    return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
7718
0
                                          JS_VALUE_GET_OBJ(obj), flags);
7719
0
}
7720
7721
/* Return -1 if exception,
7722
   FALSE if the property does not exist, TRUE if it exists. If TRUE is
7723
   returned, the property descriptor 'desc' is filled present. */
7724
static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
7725
                                     JSObject *p, JSAtom prop)
7726
78
{
7727
78
    JSShapeProperty *prs;
7728
78
    JSProperty *pr;
7729
7730
78
retry:
7731
78
    prs = find_own_property(&pr, p, prop);
7732
78
    if (prs) {
7733
78
        if (desc) {
7734
78
            desc->flags = prs->flags & JS_PROP_C_W_E;
7735
78
            desc->getter = JS_UNDEFINED;
7736
78
            desc->setter = JS_UNDEFINED;
7737
78
            desc->value = JS_UNDEFINED;
7738
78
            if (unlikely(prs->flags & JS_PROP_TMASK)) {
7739
0
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
7740
0
                    desc->flags |= JS_PROP_GETSET;
7741
0
                    if (pr->u.getset.getter)
7742
0
                        desc->getter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
7743
0
                    if (pr->u.getset.setter)
7744
0
                        desc->setter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
7745
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
7746
0
                    JSValue val = *pr->u.var_ref->pvalue;
7747
0
                    if (unlikely(JS_IsUninitialized(val))) {
7748
0
                        JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7749
0
                        return -1;
7750
0
                    }
7751
0
                    desc->value = JS_DupValue(ctx, val);
7752
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
7753
                    /* Instantiate property and retry */
7754
0
                    if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
7755
0
                        return -1;
7756
0
                    goto retry;
7757
0
                }
7758
78
            } else {
7759
78
                desc->value = JS_DupValue(ctx, pr->u.value);
7760
78
            }
7761
78
        } else {
7762
            /* for consistency, send the exception even if desc is NULL */
7763
0
            if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF)) {
7764
0
                if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) {
7765
0
                    JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7766
0
                    return -1;
7767
0
                }
7768
0
            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
7769
                /* nothing to do: delay instantiation until actual value and/or attributes are read */
7770
0
            }
7771
0
        }
7772
78
        return TRUE;
7773
78
    }
7774
0
    if (p->is_exotic) {
7775
0
        if (p->fast_array) {
7776
            /* specific case for fast arrays */
7777
0
            if (__JS_AtomIsTaggedInt(prop)) {
7778
0
                uint32_t idx;
7779
0
                idx = __JS_AtomToUInt32(prop);
7780
0
                if (idx < p->u.array.count) {
7781
0
                    if (desc) {
7782
0
                        desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE |
7783
0
                            JS_PROP_CONFIGURABLE;
7784
0
                        desc->getter = JS_UNDEFINED;
7785
0
                        desc->setter = JS_UNDEFINED;
7786
0
                        desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
7787
0
                    }
7788
0
                    return TRUE;
7789
0
                }
7790
0
            }
7791
0
        } else {
7792
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7793
0
            if (em && em->get_own_property) {
7794
0
                return em->get_own_property(ctx, desc,
7795
0
                                            JS_MKPTR(JS_TAG_OBJECT, p), prop);
7796
0
            }
7797
0
        }
7798
0
    }
7799
0
    return FALSE;
7800
0
}
7801
7802
int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
7803
                      JSValueConst obj, JSAtom prop)
7804
0
{
7805
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
7806
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7807
0
        return -1;
7808
0
    }
7809
0
    return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop);
7810
0
}
7811
7812
/* return -1 if exception (Proxy object only) or TRUE/FALSE */
7813
int JS_IsExtensible(JSContext *ctx, JSValueConst obj)
7814
78
{
7815
78
    JSObject *p;
7816
7817
78
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7818
0
        return FALSE;
7819
78
    p = JS_VALUE_GET_OBJ(obj);
7820
78
    if (unlikely(p->class_id == JS_CLASS_PROXY))
7821
0
        return js_proxy_isExtensible(ctx, obj);
7822
78
    else
7823
78
        return p->extensible;
7824
78
}
7825
7826
/* return -1 if exception (Proxy object only) or TRUE/FALSE */
7827
int JS_PreventExtensions(JSContext *ctx, JSValueConst obj)
7828
39
{
7829
39
    JSObject *p;
7830
7831
39
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7832
0
        return FALSE;
7833
39
    p = JS_VALUE_GET_OBJ(obj);
7834
39
    if (unlikely(p->class_id == JS_CLASS_PROXY))
7835
0
        return js_proxy_preventExtensions(ctx, obj);
7836
39
    p->extensible = FALSE;
7837
39
    return TRUE;
7838
39
}
7839
7840
/* return -1 if exception otherwise TRUE or FALSE */
7841
int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop)
7842
0
{
7843
0
    JSObject *p;
7844
0
    int ret;
7845
0
    JSValue obj1;
7846
7847
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7848
0
        return FALSE;
7849
0
    p = JS_VALUE_GET_OBJ(obj);
7850
0
    for(;;) {
7851
0
        if (p->is_exotic) {
7852
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7853
0
            if (em && em->has_property) {
7854
                /* has_property can free the prototype */
7855
0
                obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7856
0
                ret = em->has_property(ctx, obj1, prop);
7857
0
                JS_FreeValue(ctx, obj1);
7858
0
                return ret;
7859
0
            }
7860
0
        }
7861
        /* JS_GetOwnPropertyInternal can free the prototype */
7862
0
        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7863
0
        ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop);
7864
0
        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7865
0
        if (ret != 0)
7866
0
            return ret;
7867
0
        if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
7868
0
            p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
7869
0
            ret = JS_AtomIsNumericIndex(ctx, prop);
7870
0
            if (ret != 0) {
7871
0
                if (ret < 0)
7872
0
                    return -1;
7873
0
                return FALSE;
7874
0
            }
7875
0
        }
7876
0
        p = p->shape->proto;
7877
0
        if (!p)
7878
0
            break;
7879
0
    }
7880
0
    return FALSE;
7881
0
}
7882
7883
/* val must be a symbol */
7884
static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val)
7885
0
{
7886
0
    JSAtomStruct *p = JS_VALUE_GET_PTR(val);
7887
0
    return js_get_atom_index(ctx->rt, p);
7888
0
}
7889
7890
/* return JS_ATOM_NULL in case of exception */
7891
JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
7892
78
{
7893
78
    JSAtom atom;
7894
78
    uint32_t tag;
7895
78
    tag = JS_VALUE_GET_TAG(val);
7896
78
    if (tag == JS_TAG_INT &&
7897
78
        (uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) {
7898
        /* fast path for integer values */
7899
0
        atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val));
7900
78
    } else if (tag == JS_TAG_SYMBOL) {
7901
0
        JSAtomStruct *p = JS_VALUE_GET_PTR(val);
7902
0
        atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p));
7903
78
    } else {
7904
78
        JSValue str;
7905
78
        str = JS_ToPropertyKey(ctx, val);
7906
78
        if (JS_IsException(str))
7907
0
            return JS_ATOM_NULL;
7908
78
        if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) {
7909
0
            atom = js_symbol_to_atom(ctx, str);
7910
78
        } else {
7911
78
            atom = JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(str));
7912
78
        }
7913
78
    }
7914
78
    return atom;
7915
78
}
7916
7917
static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
7918
                                   JSValue prop)
7919
0
{
7920
0
    JSAtom atom;
7921
0
    JSValue ret;
7922
7923
0
    if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
7924
0
               JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
7925
0
        JSObject *p;
7926
0
        uint32_t idx;
7927
        /* fast path for array access */
7928
0
        p = JS_VALUE_GET_OBJ(this_obj);
7929
0
        idx = JS_VALUE_GET_INT(prop);
7930
0
        switch(p->class_id) {
7931
0
        case JS_CLASS_ARRAY:
7932
0
        case JS_CLASS_ARGUMENTS:
7933
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
7934
0
            return JS_DupValue(ctx, p->u.array.u.values[idx]);
7935
0
        case JS_CLASS_INT8_ARRAY:
7936
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
7937
0
            return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]);
7938
0
        case JS_CLASS_UINT8C_ARRAY:
7939
0
        case JS_CLASS_UINT8_ARRAY:
7940
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
7941
0
            return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]);
7942
0
        case JS_CLASS_INT16_ARRAY:
7943
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
7944
0
            return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]);
7945
0
        case JS_CLASS_UINT16_ARRAY:
7946
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
7947
0
            return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]);
7948
0
        case JS_CLASS_INT32_ARRAY:
7949
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
7950
0
            return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]);
7951
0
        case JS_CLASS_UINT32_ARRAY:
7952
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
7953
0
            return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]);
7954
0
        case JS_CLASS_BIG_INT64_ARRAY:
7955
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
7956
0
            return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
7957
0
        case JS_CLASS_BIG_UINT64_ARRAY:
7958
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
7959
0
            return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
7960
0
        case JS_CLASS_FLOAT32_ARRAY:
7961
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
7962
0
            return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]);
7963
0
        case JS_CLASS_FLOAT64_ARRAY:
7964
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
7965
0
            return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]);
7966
0
        default:
7967
0
            goto slow_path;
7968
0
        }
7969
0
    } else {
7970
0
    slow_path:
7971
0
        atom = JS_ValueToAtom(ctx, prop);
7972
0
        JS_FreeValue(ctx, prop);
7973
0
        if (unlikely(atom == JS_ATOM_NULL))
7974
0
            return JS_EXCEPTION;
7975
0
        ret = JS_GetProperty(ctx, this_obj, atom);
7976
0
        JS_FreeAtom(ctx, atom);
7977
0
        return ret;
7978
0
    }
7979
0
}
7980
7981
JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
7982
                             uint32_t idx)
7983
0
{
7984
0
    return JS_GetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx));
7985
0
}
7986
7987
/* Check if an object has a generalized numeric property. Return value:
7988
   -1 for exception,
7989
   TRUE if property exists, stored into *pval,
7990
   FALSE if proprty does not exist.
7991
 */
7992
static int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, JSValue *pval)
7993
0
{
7994
0
    JSValue val = JS_UNDEFINED;
7995
0
    JSAtom prop;
7996
0
    int present;
7997
7998
0
    if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) {
7999
        /* fast path */
8000
0
        present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx));
8001
0
        if (present > 0) {
8002
0
            val = JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
8003
0
            if (unlikely(JS_IsException(val)))
8004
0
                present = -1;
8005
0
        }
8006
0
    } else {
8007
0
        prop = JS_NewAtomInt64(ctx, idx);
8008
0
        present = -1;
8009
0
        if (likely(prop != JS_ATOM_NULL)) {
8010
0
            present = JS_HasProperty(ctx, obj, prop);
8011
0
            if (present > 0) {
8012
0
                val = JS_GetProperty(ctx, obj, prop);
8013
0
                if (unlikely(JS_IsException(val)))
8014
0
                    present = -1;
8015
0
            }
8016
0
            JS_FreeAtom(ctx, prop);
8017
0
        }
8018
0
    }
8019
0
    *pval = val;
8020
0
    return present;
8021
0
}
8022
8023
static JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx)
8024
0
{
8025
0
    JSAtom prop;
8026
0
    JSValue val;
8027
8028
0
    if ((uint64_t)idx <= INT32_MAX) {
8029
        /* fast path for fast arrays */
8030
0
        return JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
8031
0
    }
8032
0
    prop = JS_NewAtomInt64(ctx, idx);
8033
0
    if (prop == JS_ATOM_NULL)
8034
0
        return JS_EXCEPTION;
8035
8036
0
    val = JS_GetProperty(ctx, obj, prop);
8037
0
    JS_FreeAtom(ctx, prop);
8038
0
    return val;
8039
0
}
8040
8041
JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
8042
                          const char *prop)
8043
0
{
8044
0
    JSAtom atom;
8045
0
    JSValue ret;
8046
0
    atom = JS_NewAtom(ctx, prop);
8047
0
    ret = JS_GetProperty(ctx, this_obj, atom);
8048
0
    JS_FreeAtom(ctx, atom);
8049
0
    return ret;
8050
0
}
8051
8052
/* Note: the property value is not initialized. Return NULL if memory
8053
   error. */
8054
static JSProperty *add_property(JSContext *ctx,
8055
                                JSObject *p, JSAtom prop, int prop_flags)
8056
2.91M
{
8057
2.91M
    JSShape *sh, *new_sh;
8058
8059
2.91M
    sh = p->shape;
8060
2.91M
    if (sh->is_hashed) {
8061
        /* try to find an existing shape */
8062
41.9k
        new_sh = find_hashed_shape_prop(ctx->rt, sh, prop, prop_flags);
8063
41.9k
        if (new_sh) {
8064
            /* matching shape found: use it */
8065
            /*  the property array may need to be resized */
8066
9.18k
            if (new_sh->prop_size != sh->prop_size) {
8067
1.95k
                JSProperty *new_prop;
8068
1.95k
                new_prop = js_realloc(ctx, p->prop, sizeof(p->prop[0]) *
8069
1.95k
                                      new_sh->prop_size);
8070
1.95k
                if (!new_prop)
8071
0
                    return NULL;
8072
1.95k
                p->prop = new_prop;
8073
1.95k
            }
8074
9.18k
            p->shape = js_dup_shape(new_sh);
8075
9.18k
            js_free_shape(ctx->rt, sh);
8076
9.18k
            return &p->prop[new_sh->prop_count - 1];
8077
32.7k
        } else if (sh->header.ref_count != 1) {
8078
            /* if the shape is shared, clone it */
8079
3.53k
            new_sh = js_clone_shape(ctx, sh);
8080
3.53k
            if (!new_sh)
8081
0
                return NULL;
8082
            /* hash the cloned shape */
8083
3.53k
            new_sh->is_hashed = TRUE;
8084
3.53k
            js_shape_hash_link(ctx->rt, new_sh);
8085
3.53k
            js_free_shape(ctx->rt, p->shape);
8086
3.53k
            p->shape = new_sh;
8087
3.53k
        }
8088
41.9k
    }
8089
2.90M
    assert(p->shape->header.ref_count == 1);
8090
2.90M
    if (add_shape_property(ctx, &p->shape, p, prop, prop_flags))
8091
0
        return NULL;
8092
2.90M
    return &p->prop[p->shape->prop_count - 1];
8093
2.90M
}
8094
8095
/* can be called on Array or Arguments objects. return < 0 if
8096
   memory alloc error. */
8097
static no_inline __exception int convert_fast_array_to_array(JSContext *ctx,
8098
                                                             JSObject *p)
8099
6
{
8100
6
    JSProperty *pr;
8101
6
    JSShape *sh;
8102
6
    JSValue *tab;
8103
6
    uint32_t i, len, new_count;
8104
8105
6
    if (js_shape_prepare_update(ctx, p, NULL))
8106
0
        return -1;
8107
6
    len = p->u.array.count;
8108
    /* resize the properties once to simplify the error handling */
8109
6
    sh = p->shape;
8110
6
    new_count = sh->prop_count + len;
8111
6
    if (new_count > sh->prop_size) {
8112
6
        if (resize_properties(ctx, &p->shape, p, new_count))
8113
0
            return -1;
8114
6
    }
8115
8116
6
    tab = p->u.array.u.values;
8117
982k
    for(i = 0; i < len; i++) {
8118
        /* add_property cannot fail here but
8119
           __JS_AtomFromUInt32(i) fails for i > INT32_MAX */
8120
982k
        pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E);
8121
982k
        pr->u.value = *tab++;
8122
982k
    }
8123
6
    js_free(ctx, p->u.array.u.values);
8124
6
    p->u.array.count = 0;
8125
6
    p->u.array.u.values = NULL; /* fail safe */
8126
6
    p->u.array.u1.size = 0;
8127
6
    p->fast_array = 0;
8128
6
    return 0;
8129
6
}
8130
8131
static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom)
8132
0
{
8133
0
    JSShape *sh;
8134
0
    JSShapeProperty *pr, *lpr, *prop;
8135
0
    JSProperty *pr1;
8136
0
    uint32_t lpr_idx;
8137
0
    intptr_t h, h1;
8138
8139
0
 redo:
8140
0
    sh = p->shape;
8141
0
    h1 = atom & sh->prop_hash_mask;
8142
0
    h = prop_hash_end(sh)[-h1 - 1];
8143
0
    prop = get_shape_prop(sh);
8144
0
    lpr = NULL;
8145
0
    lpr_idx = 0;   /* prevent warning */
8146
0
    while (h != 0) {
8147
0
        pr = &prop[h - 1];
8148
0
        if (likely(pr->atom == atom)) {
8149
            /* found ! */
8150
0
            if (!(pr->flags & JS_PROP_CONFIGURABLE))
8151
0
                return FALSE;
8152
            /* realloc the shape if needed */
8153
0
            if (lpr)
8154
0
                lpr_idx = lpr - get_shape_prop(sh);
8155
0
            if (js_shape_prepare_update(ctx, p, &pr))
8156
0
                return -1;
8157
0
            sh = p->shape;
8158
            /* remove property */
8159
0
            if (lpr) {
8160
0
                lpr = get_shape_prop(sh) + lpr_idx;
8161
0
                lpr->hash_next = pr->hash_next;
8162
0
            } else {
8163
0
                prop_hash_end(sh)[-h1 - 1] = pr->hash_next;
8164
0
            }
8165
0
            sh->deleted_prop_count++;
8166
            /* free the entry */
8167
0
            pr1 = &p->prop[h - 1];
8168
0
            free_property(ctx->rt, pr1, pr->flags);
8169
0
            JS_FreeAtom(ctx, pr->atom);
8170
            /* put default values */
8171
0
            pr->flags = 0;
8172
0
            pr->atom = JS_ATOM_NULL;
8173
0
            pr1->u.value = JS_UNDEFINED;
8174
8175
            /* compact the properties if too many deleted properties */
8176
0
            if (sh->deleted_prop_count >= 8 &&
8177
0
                sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) {
8178
0
                compact_properties(ctx, p);
8179
0
            }
8180
0
            return TRUE;
8181
0
        }
8182
0
        lpr = pr;
8183
0
        h = pr->hash_next;
8184
0
    }
8185
8186
0
    if (p->is_exotic) {
8187
0
        if (p->fast_array) {
8188
0
            uint32_t idx;
8189
0
            if (JS_AtomIsArrayIndex(ctx, &idx, atom) &&
8190
0
                idx < p->u.array.count) {
8191
0
                if (p->class_id == JS_CLASS_ARRAY ||
8192
0
                    p->class_id == JS_CLASS_ARGUMENTS) {
8193
                    /* Special case deleting the last element of a fast Array */
8194
0
                    if (idx == p->u.array.count - 1) {
8195
0
                        JS_FreeValue(ctx, p->u.array.u.values[idx]);
8196
0
                        p->u.array.count = idx;
8197
0
                        return TRUE;
8198
0
                    }
8199
0
                    if (convert_fast_array_to_array(ctx, p))
8200
0
                        return -1;
8201
0
                    goto redo;
8202
0
                } else {
8203
0
                    return FALSE;
8204
0
                }
8205
0
            }
8206
0
        } else {
8207
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8208
0
            if (em && em->delete_property) {
8209
0
                return em->delete_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), atom);
8210
0
            }
8211
0
        }
8212
0
    }
8213
    /* not found */
8214
0
    return TRUE;
8215
0
}
8216
8217
static int call_setter(JSContext *ctx, JSObject *setter,
8218
                       JSValueConst this_obj, JSValue val, int flags)
8219
0
{
8220
0
    JSValue ret, func;
8221
0
    if (likely(setter)) {
8222
0
        func = JS_MKPTR(JS_TAG_OBJECT, setter);
8223
        /* Note: the field could be removed in the setter */
8224
0
        func = JS_DupValue(ctx, func);
8225
0
        ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst *)&val);
8226
0
        JS_FreeValue(ctx, val);
8227
0
        if (JS_IsException(ret))
8228
0
            return -1;
8229
0
        JS_FreeValue(ctx, ret);
8230
0
        return TRUE;
8231
0
    } else {
8232
0
        JS_FreeValue(ctx, val);
8233
0
        if ((flags & JS_PROP_THROW) ||
8234
0
            ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
8235
0
            JS_ThrowTypeError(ctx, "no setter for property");
8236
0
            return -1;
8237
0
        }
8238
0
        return FALSE;
8239
0
    }
8240
0
}
8241
8242
/* set the array length and remove the array elements if necessary. */
8243
static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
8244
                            int flags)
8245
0
{
8246
0
    uint32_t len, idx, cur_len;
8247
0
    int i, ret;
8248
8249
    /* Note: this call can reallocate the properties of 'p' */
8250
0
    ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE);
8251
0
    if (ret)
8252
0
        return -1;
8253
    /* JS_ToArrayLengthFree() must be done before the read-only test */
8254
0
    if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE)))
8255
0
        return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
8256
8257
0
    if (likely(p->fast_array)) {
8258
0
        uint32_t old_len = p->u.array.count;
8259
0
        if (len < old_len) {
8260
0
            for(i = len; i < old_len; i++) {
8261
0
                JS_FreeValue(ctx, p->u.array.u.values[i]);
8262
0
            }
8263
0
            p->u.array.count = len;
8264
0
        }
8265
0
        p->prop[0].u.value = JS_NewUint32(ctx, len);
8266
0
    } else {
8267
        /* Note: length is always a uint32 because the object is an
8268
           array */
8269
0
        JS_ToUint32(ctx, &cur_len, p->prop[0].u.value);
8270
0
        if (len < cur_len) {
8271
0
            uint32_t d;
8272
0
            JSShape *sh;
8273
0
            JSShapeProperty *pr;
8274
8275
0
            d = cur_len - len;
8276
0
            sh = p->shape;
8277
0
            if (d <= sh->prop_count) {
8278
0
                JSAtom atom;
8279
8280
                /* faster to iterate */
8281
0
                while (cur_len > len) {
8282
0
                    atom = JS_NewAtomUInt32(ctx, cur_len - 1);
8283
0
                    ret = delete_property(ctx, p, atom);
8284
0
                    JS_FreeAtom(ctx, atom);
8285
0
                    if (unlikely(!ret)) {
8286
                        /* unlikely case: property is not
8287
                           configurable */
8288
0
                        break;
8289
0
                    }
8290
0
                    cur_len--;
8291
0
                }
8292
0
            } else {
8293
                /* faster to iterate thru all the properties. Need two
8294
                   passes in case one of the property is not
8295
                   configurable */
8296
0
                cur_len = len;
8297
0
                for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
8298
0
                    i++, pr++) {
8299
0
                    if (pr->atom != JS_ATOM_NULL &&
8300
0
                        JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
8301
0
                        if (idx >= cur_len &&
8302
0
                            !(pr->flags & JS_PROP_CONFIGURABLE)) {
8303
0
                            cur_len = idx + 1;
8304
0
                        }
8305
0
                    }
8306
0
                }
8307
8308
0
                for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
8309
0
                    i++, pr++) {
8310
0
                    if (pr->atom != JS_ATOM_NULL &&
8311
0
                        JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
8312
0
                        if (idx >= cur_len) {
8313
                            /* remove the property */
8314
0
                            delete_property(ctx, p, pr->atom);
8315
                            /* WARNING: the shape may have been modified */
8316
0
                            sh = p->shape;
8317
0
                            pr = get_shape_prop(sh) + i;
8318
0
                        }
8319
0
                    }
8320
0
                }
8321
0
            }
8322
0
        } else {
8323
0
            cur_len = len;
8324
0
        }
8325
0
        set_value(ctx, &p->prop[0].u.value, JS_NewUint32(ctx, cur_len));
8326
0
        if (unlikely(cur_len > len)) {
8327
0
            return JS_ThrowTypeErrorOrFalse(ctx, flags, "not configurable");
8328
0
        }
8329
0
    }
8330
0
    return TRUE;
8331
0
}
8332
8333
/* return -1 if exception */
8334
static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len)
8335
210
{
8336
210
    uint32_t new_size;
8337
210
    size_t slack;
8338
210
    JSValue *new_array_prop;
8339
    /* XXX: potential arithmetic overflow */
8340
210
    new_size = max_int(new_len, p->u.array.u1.size * 3 / 2);
8341
210
    new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack);
8342
210
    if (!new_array_prop)
8343
0
        return -1;
8344
210
    new_size += slack / sizeof(*new_array_prop);
8345
210
    p->u.array.u.values = new_array_prop;
8346
210
    p->u.array.u1.size = new_size;
8347
210
    return 0;
8348
210
}
8349
8350
/* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array =
8351
   TRUE and p->extensible = TRUE */
8352
static int add_fast_array_element(JSContext *ctx, JSObject *p,
8353
                                  JSValue val, int flags)
8354
1.10M
{
8355
1.10M
    uint32_t new_len, array_len;
8356
    /* extend the array by one */
8357
    /* XXX: convert to slow array if new_len > 2^31-1 elements */
8358
1.10M
    new_len = p->u.array.count + 1;
8359
    /* update the length if necessary. We assume that if the length is
8360
       not an integer, then if it >= 2^31.  */
8361
1.10M
    if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) {
8362
1.10M
        array_len = JS_VALUE_GET_INT(p->prop[0].u.value);
8363
1.10M
        if (new_len > array_len) {
8364
1.10M
            if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) {
8365
0
                JS_FreeValue(ctx, val);
8366
0
                return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
8367
0
            }
8368
1.10M
            p->prop[0].u.value = JS_NewInt32(ctx, new_len);
8369
1.10M
        }
8370
1.10M
    }
8371
1.10M
    if (unlikely(new_len > p->u.array.u1.size)) {
8372
210
        if (expand_fast_array(ctx, p, new_len)) {
8373
0
            JS_FreeValue(ctx, val);
8374
0
            return -1;
8375
0
        }
8376
210
    }
8377
1.10M
    p->u.array.u.values[new_len - 1] = val;
8378
1.10M
    p->u.array.count = new_len;
8379
1.10M
    return TRUE;
8380
1.10M
}
8381
8382
/* Allocate a new fast array. Its 'length' property is set to zero. It
8383
   maximum size is 2^31-1 elements. For convenience, 'len' is a 64 bit
8384
   integer. WARNING: the content of the array is not initialized. */
8385
static JSValue js_allocate_fast_array(JSContext *ctx, int64_t len)
8386
0
{
8387
0
    JSValue arr;
8388
0
    JSObject *p;
8389
8390
0
    if (len > INT32_MAX)
8391
0
        return JS_ThrowRangeError(ctx, "invalid array length");
8392
0
    arr = JS_NewArray(ctx);
8393
0
    if (JS_IsException(arr))
8394
0
        return arr;
8395
0
    if (len > 0) {
8396
0
        p = JS_VALUE_GET_OBJ(arr);
8397
0
        if (expand_fast_array(ctx, p, len) < 0) {
8398
0
            JS_FreeValue(ctx, arr);
8399
0
            return JS_EXCEPTION;
8400
0
        }
8401
0
        p->u.array.count = len;
8402
0
    }
8403
0
    return arr;
8404
0
}
8405
8406
static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
8407
78
{
8408
78
    JS_FreeValue(ctx, desc->getter);
8409
78
    JS_FreeValue(ctx, desc->setter);
8410
78
    JS_FreeValue(ctx, desc->value);
8411
78
}
8412
8413
/* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is
8414
   freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD,
8415
   JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set,
8416
   the new property is not added and an error is raised. 'this_obj' is
8417
   the receiver. If obj != this_obj, then obj must be an object
8418
   (Reflect.set case). */
8419
int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj,
8420
                           JSAtom prop, JSValue val, JSValueConst this_obj, int flags)
8421
273
{
8422
273
    JSObject *p, *p1;
8423
273
    JSShapeProperty *prs;
8424
273
    JSProperty *pr;
8425
273
    uint32_t tag;
8426
273
    JSPropertyDescriptor desc;
8427
273
    int ret;
8428
#if 0
8429
    printf("JS_SetPropertyInternal: "); print_atom(ctx, prop); printf("\n");
8430
#endif
8431
273
    tag = JS_VALUE_GET_TAG(this_obj);
8432
273
    if (unlikely(tag != JS_TAG_OBJECT)) {
8433
0
        if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
8434
0
            p = NULL;
8435
0
            p1 = JS_VALUE_GET_OBJ(obj);
8436
0
            goto prototype_lookup;
8437
0
        } else {
8438
0
            switch(tag) {
8439
0
            case JS_TAG_NULL:
8440
0
                JS_FreeValue(ctx, val);
8441
0
                JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop);
8442
0
                return -1;
8443
0
            case JS_TAG_UNDEFINED:
8444
0
                JS_FreeValue(ctx, val);
8445
0
                JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop);
8446
0
                return -1;
8447
0
            default:
8448
                /* even on a primitive type we can have setters on the prototype */
8449
0
                p = NULL;
8450
0
                p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));
8451
0
                goto prototype_lookup;
8452
0
            }
8453
0
        }
8454
273
    } else {
8455
273
        p = JS_VALUE_GET_OBJ(this_obj);
8456
273
        p1 = JS_VALUE_GET_OBJ(obj);
8457
273
        if (unlikely(p != p1))
8458
0
            goto retry2;
8459
273
    }
8460
8461
    /* fast path if obj == this_obj */
8462
273
 retry:
8463
273
    prs = find_own_property(&pr, p1, prop);
8464
273
    if (prs) {
8465
0
        if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE |
8466
0
                                  JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) {
8467
            /* fast case */
8468
0
            set_value(ctx, &pr->u.value, val);
8469
0
            return TRUE;
8470
0
        } else if (prs->flags & JS_PROP_LENGTH) {
8471
0
            assert(p->class_id == JS_CLASS_ARRAY);
8472
0
            assert(prop == JS_ATOM_length);
8473
0
            return set_array_length(ctx, p, val, flags);
8474
0
        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
8475
0
            return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
8476
0
        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
8477
            /* JS_PROP_WRITABLE is always true for variable
8478
               references, but they are write protected in module name
8479
               spaces. */
8480
0
            if (p->class_id == JS_CLASS_MODULE_NS)
8481
0
                goto read_only_prop;
8482
0
            set_value(ctx, pr->u.var_ref->pvalue, val);
8483
0
            return TRUE;
8484
0
        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
8485
            /* Instantiate property and retry (potentially useless) */
8486
0
            if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) {
8487
0
                JS_FreeValue(ctx, val);
8488
0
                return -1;
8489
0
            }
8490
0
            goto retry;
8491
0
        } else {
8492
0
            goto read_only_prop;
8493
0
        }
8494
0
    }
8495
8496
546
    for(;;) {
8497
546
        if (p1->is_exotic) {
8498
0
            if (p1->fast_array) {
8499
0
                if (__JS_AtomIsTaggedInt(prop)) {
8500
0
                    uint32_t idx = __JS_AtomToUInt32(prop);
8501
0
                    if (idx < p1->u.array.count) {
8502
0
                        if (unlikely(p == p1))
8503
0
                            return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, flags);
8504
0
                        else
8505
0
                            break;
8506
0
                    } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&
8507
0
                               p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
8508
0
                        goto typed_array_oob;
8509
0
                    }
8510
0
                } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&
8511
0
                           p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
8512
0
                    ret = JS_AtomIsNumericIndex(ctx, prop);
8513
0
                    if (ret != 0) {
8514
0
                        if (ret < 0) {
8515
0
                            JS_FreeValue(ctx, val);
8516
0
                            return -1;
8517
0
                        }
8518
0
                    typed_array_oob:
8519
                        /* must convert the argument even if out of bound access */
8520
0
                        if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY ||
8521
0
                            p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
8522
0
                            int64_t v;
8523
0
                            if (JS_ToBigInt64Free(ctx, &v, val))
8524
0
                                return -1;
8525
0
                        } else {
8526
0
                            val = JS_ToNumberFree(ctx, val);
8527
0
                            JS_FreeValue(ctx, val);
8528
0
                            if (JS_IsException(val))
8529
0
                                return -1;
8530
0
                        }
8531
0
                        return TRUE;
8532
0
                    }
8533
0
                }
8534
0
            } else {
8535
0
                const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic;
8536
0
                if (em) {
8537
0
                    JSValue obj1;
8538
0
                    if (em->set_property) {
8539
                        /* set_property can free the prototype */
8540
0
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
8541
0
                        ret = em->set_property(ctx, obj1, prop,
8542
0
                                               val, this_obj, flags);
8543
0
                        JS_FreeValue(ctx, obj1);
8544
0
                        JS_FreeValue(ctx, val);
8545
0
                        return ret;
8546
0
                    }
8547
0
                    if (em->get_own_property) {
8548
                        /* get_own_property can free the prototype */
8549
0
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
8550
0
                        ret = em->get_own_property(ctx, &desc,
8551
0
                                                   obj1, prop);
8552
0
                        JS_FreeValue(ctx, obj1);
8553
0
                        if (ret < 0) {
8554
0
                            JS_FreeValue(ctx, val);
8555
0
                            return ret;
8556
0
                        }
8557
0
                        if (ret) {
8558
0
                            if (desc.flags & JS_PROP_GETSET) {
8559
0
                                JSObject *setter;
8560
0
                                if (JS_IsUndefined(desc.setter))
8561
0
                                    setter = NULL;
8562
0
                                else
8563
0
                                    setter = JS_VALUE_GET_OBJ(desc.setter);
8564
0
                                ret = call_setter(ctx, setter, this_obj, val, flags);
8565
0
                                JS_FreeValue(ctx, desc.getter);
8566
0
                                JS_FreeValue(ctx, desc.setter);
8567
0
                                return ret;
8568
0
                            } else {
8569
0
                                JS_FreeValue(ctx, desc.value);
8570
0
                                if (!(desc.flags & JS_PROP_WRITABLE))
8571
0
                                    goto read_only_prop;
8572
0
                                if (likely(p == p1)) {
8573
0
                                    ret = JS_DefineProperty(ctx, this_obj, prop, val,
8574
0
                                                            JS_UNDEFINED, JS_UNDEFINED,
8575
0
                                                            JS_PROP_HAS_VALUE);
8576
0
                                    JS_FreeValue(ctx, val);
8577
0
                                    return ret;
8578
0
                                } else {
8579
0
                                    break;
8580
0
                                }
8581
0
                            }
8582
0
                        }
8583
0
                    }
8584
0
                }
8585
0
            }
8586
0
        }
8587
546
        p1 = p1->shape->proto;
8588
546
    prototype_lookup:
8589
546
        if (!p1)
8590
273
            break;
8591
8592
273
    retry2:
8593
273
        prs = find_own_property(&pr, p1, prop);
8594
273
        if (prs) {
8595
0
            if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
8596
0
                return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
8597
0
            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
8598
                /* Instantiate property and retry (potentially useless) */
8599
0
                if (JS_AutoInitProperty(ctx, p1, prop, pr, prs))
8600
0
                    return -1;
8601
0
                goto retry2;
8602
0
            } else if (!(prs->flags & JS_PROP_WRITABLE)) {
8603
0
                goto read_only_prop;
8604
0
            }
8605
0
        }
8606
273
    }
8607
8608
273
    if (unlikely(flags & JS_PROP_NO_ADD)) {
8609
0
        JS_FreeValue(ctx, val);
8610
0
        JS_ThrowReferenceErrorNotDefined(ctx, prop);
8611
0
        return -1;
8612
0
    }
8613
8614
273
    if (unlikely(!p)) {
8615
0
        JS_FreeValue(ctx, val);
8616
0
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "not an object");
8617
0
    }
8618
8619
273
    if (unlikely(!p->extensible)) {
8620
0
        JS_FreeValue(ctx, val);
8621
0
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
8622
0
    }
8623
8624
273
    if (likely(p == JS_VALUE_GET_OBJ(obj))) {
8625
273
        if (p->is_exotic) {
8626
0
            if (p->class_id == JS_CLASS_ARRAY && p->fast_array &&
8627
0
                __JS_AtomIsTaggedInt(prop)) {
8628
0
                uint32_t idx = __JS_AtomToUInt32(prop);
8629
0
                if (idx == p->u.array.count) {
8630
                    /* fast case */
8631
0
                    return add_fast_array_element(ctx, p, val, flags);
8632
0
                } else {
8633
0
                    goto generic_create_prop;
8634
0
                }
8635
0
            } else {
8636
0
                goto generic_create_prop;
8637
0
            }
8638
273
        } else {
8639
273
            pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
8640
273
            if (unlikely(!pr)) {
8641
0
                JS_FreeValue(ctx, val);
8642
0
                return -1;
8643
0
            }
8644
273
            pr->u.value = val;
8645
273
            return TRUE;
8646
273
        }
8647
273
    } else {
8648
        /* generic case: modify the property in this_obj if it already exists */
8649
0
        ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
8650
0
        if (ret < 0) {
8651
0
            JS_FreeValue(ctx, val);
8652
0
            return ret;
8653
0
        }
8654
0
        if (ret) {
8655
0
            if (desc.flags & JS_PROP_GETSET) {
8656
0
                JS_FreeValue(ctx, desc.getter);
8657
0
                JS_FreeValue(ctx, desc.setter);
8658
0
                JS_FreeValue(ctx, val);
8659
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden");
8660
0
            } else {
8661
0
                JS_FreeValue(ctx, desc.value);
8662
0
                if (!(desc.flags & JS_PROP_WRITABLE) ||
8663
0
                    p->class_id == JS_CLASS_MODULE_NS) {
8664
0
                read_only_prop:
8665
0
                    JS_FreeValue(ctx, val);
8666
0
                    return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
8667
0
                }
8668
0
            }
8669
0
            ret = JS_DefineProperty(ctx, this_obj, prop, val,
8670
0
                                    JS_UNDEFINED, JS_UNDEFINED,
8671
0
                                    JS_PROP_HAS_VALUE);
8672
0
            JS_FreeValue(ctx, val);
8673
0
            return ret;
8674
0
        } else {
8675
0
        generic_create_prop:
8676
0
            ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,
8677
0
                                    flags |
8678
0
                                    JS_PROP_HAS_VALUE |
8679
0
                                    JS_PROP_HAS_ENUMERABLE |
8680
0
                                    JS_PROP_HAS_WRITABLE |
8681
0
                                    JS_PROP_HAS_CONFIGURABLE |
8682
0
                                    JS_PROP_C_W_E);
8683
0
            JS_FreeValue(ctx, val);
8684
0
            return ret;
8685
0
        }
8686
0
    }
8687
273
}
8688
8689
/* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */
8690
static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
8691
                               JSValue prop, JSValue val, int flags)
8692
0
{
8693
0
    if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
8694
0
               JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
8695
0
        JSObject *p;
8696
0
        uint32_t idx;
8697
0
        double d;
8698
0
        int32_t v;
8699
8700
        /* fast path for array access */
8701
0
        p = JS_VALUE_GET_OBJ(this_obj);
8702
0
        idx = JS_VALUE_GET_INT(prop);
8703
0
        switch(p->class_id) {
8704
0
        case JS_CLASS_ARRAY:
8705
0
            if (unlikely(idx >= (uint32_t)p->u.array.count)) {
8706
0
                JSObject *p1;
8707
0
                JSShape *sh1;
8708
8709
                /* fast path to add an element to the array */
8710
0
                if (idx != (uint32_t)p->u.array.count ||
8711
0
                    !p->fast_array || !p->extensible)
8712
0
                    goto slow_path;
8713
                /* check if prototype chain has a numeric property */
8714
0
                p1 = p->shape->proto;
8715
0
                while (p1 != NULL) {
8716
0
                    sh1 = p1->shape;
8717
0
                    if (p1->class_id == JS_CLASS_ARRAY) {
8718
0
                        if (unlikely(!p1->fast_array))
8719
0
                            goto slow_path;
8720
0
                    } else if (p1->class_id == JS_CLASS_OBJECT) {
8721
0
                        if (unlikely(sh1->has_small_array_index))
8722
0
                            goto slow_path;
8723
0
                    } else {
8724
0
                        goto slow_path;
8725
0
                    }
8726
0
                    p1 = sh1->proto;
8727
0
                }
8728
                /* add element */
8729
0
                return add_fast_array_element(ctx, p, val, flags);
8730
0
            }
8731
0
            set_value(ctx, &p->u.array.u.values[idx], val);
8732
0
            break;
8733
0
        case JS_CLASS_ARGUMENTS:
8734
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8735
0
                goto slow_path;
8736
0
            set_value(ctx, &p->u.array.u.values[idx], val);
8737
0
            break;
8738
0
        case JS_CLASS_UINT8C_ARRAY:
8739
0
            if (JS_ToUint8ClampFree(ctx, &v, val))
8740
0
                return -1;
8741
            /* Note: the conversion can detach the typed array, so the
8742
               array bound check must be done after */
8743
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8744
0
                goto ta_out_of_bound;
8745
0
            p->u.array.u.uint8_ptr[idx] = v;
8746
0
            break;
8747
0
        case JS_CLASS_INT8_ARRAY:
8748
0
        case JS_CLASS_UINT8_ARRAY:
8749
0
            if (JS_ToInt32Free(ctx, &v, val))
8750
0
                return -1;
8751
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8752
0
                goto ta_out_of_bound;
8753
0
            p->u.array.u.uint8_ptr[idx] = v;
8754
0
            break;
8755
0
        case JS_CLASS_INT16_ARRAY:
8756
0
        case JS_CLASS_UINT16_ARRAY:
8757
0
            if (JS_ToInt32Free(ctx, &v, val))
8758
0
                return -1;
8759
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8760
0
                goto ta_out_of_bound;
8761
0
            p->u.array.u.uint16_ptr[idx] = v;
8762
0
            break;
8763
0
        case JS_CLASS_INT32_ARRAY:
8764
0
        case JS_CLASS_UINT32_ARRAY:
8765
0
            if (JS_ToInt32Free(ctx, &v, val))
8766
0
                return -1;
8767
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8768
0
                goto ta_out_of_bound;
8769
0
            p->u.array.u.uint32_ptr[idx] = v;
8770
0
            break;
8771
0
        case JS_CLASS_BIG_INT64_ARRAY:
8772
0
        case JS_CLASS_BIG_UINT64_ARRAY:
8773
            /* XXX: need specific conversion function */
8774
0
            {
8775
0
                int64_t v;
8776
0
                if (JS_ToBigInt64Free(ctx, &v, val))
8777
0
                    return -1;
8778
0
                if (unlikely(idx >= (uint32_t)p->u.array.count))
8779
0
                    goto ta_out_of_bound;
8780
0
                p->u.array.u.uint64_ptr[idx] = v;
8781
0
            }
8782
0
            break;
8783
0
        case JS_CLASS_FLOAT32_ARRAY:
8784
0
            if (JS_ToFloat64Free(ctx, &d, val))
8785
0
                return -1;
8786
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8787
0
                goto ta_out_of_bound;
8788
0
            p->u.array.u.float_ptr[idx] = d;
8789
0
            break;
8790
0
        case JS_CLASS_FLOAT64_ARRAY:
8791
0
            if (JS_ToFloat64Free(ctx, &d, val))
8792
0
                return -1;
8793
0
            if (unlikely(idx >= (uint32_t)p->u.array.count)) {
8794
0
            ta_out_of_bound:
8795
0
                return TRUE;
8796
0
            }
8797
0
            p->u.array.u.double_ptr[idx] = d;
8798
0
            break;
8799
0
        default:
8800
0
            goto slow_path;
8801
0
        }
8802
0
        return TRUE;
8803
0
    } else {
8804
0
        JSAtom atom;
8805
0
        int ret;
8806
0
    slow_path:
8807
0
        atom = JS_ValueToAtom(ctx, prop);
8808
0
        JS_FreeValue(ctx, prop);
8809
0
        if (unlikely(atom == JS_ATOM_NULL)) {
8810
0
            JS_FreeValue(ctx, val);
8811
0
            return -1;
8812
0
        }
8813
0
        ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, flags);
8814
0
        JS_FreeAtom(ctx, atom);
8815
0
        return ret;
8816
0
    }
8817
0
}
8818
8819
int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
8820
                         uint32_t idx, JSValue val)
8821
0
{
8822
0
    return JS_SetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx), val,
8823
0
                               JS_PROP_THROW);
8824
0
}
8825
8826
int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj,
8827
                        int64_t idx, JSValue val)
8828
0
{
8829
0
    JSAtom prop;
8830
0
    int res;
8831
8832
0
    if ((uint64_t)idx <= INT32_MAX) {
8833
        /* fast path for fast arrays */
8834
0
        return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val,
8835
0
                                   JS_PROP_THROW);
8836
0
    }
8837
0
    prop = JS_NewAtomInt64(ctx, idx);
8838
0
    if (prop == JS_ATOM_NULL) {
8839
0
        JS_FreeValue(ctx, val);
8840
0
        return -1;
8841
0
    }
8842
0
    res = JS_SetProperty(ctx, this_obj, prop, val);
8843
0
    JS_FreeAtom(ctx, prop);
8844
0
    return res;
8845
0
}
8846
8847
int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
8848
                      const char *prop, JSValue val)
8849
195
{
8850
195
    JSAtom atom;
8851
195
    int ret;
8852
195
    atom = JS_NewAtom(ctx, prop);
8853
195
    ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, JS_PROP_THROW);
8854
195
    JS_FreeAtom(ctx, atom);
8855
195
    return ret;
8856
195
}
8857
8858
/* compute the property flags. For each flag: (JS_PROP_HAS_x forces
8859
   it, otherwise def_flags is used)
8860
   Note: makes assumption about the bit pattern of the flags
8861
*/
8862
static int get_prop_flags(int flags, int def_flags)
8863
1.10M
{
8864
1.10M
    int mask;
8865
1.10M
    mask = (flags >> JS_PROP_HAS_SHIFT) & JS_PROP_C_W_E;
8866
1.10M
    return (flags & mask) | (def_flags & ~mask);
8867
1.10M
}
8868
8869
static int JS_CreateProperty(JSContext *ctx, JSObject *p,
8870
                             JSAtom prop, JSValueConst val,
8871
                             JSValueConst getter, JSValueConst setter,
8872
                             int flags)
8873
3.02M
{
8874
3.02M
    JSProperty *pr;
8875
3.02M
    int ret, prop_flags;
8876
8877
    /* add a new property or modify an existing exotic one */
8878
3.02M
    if (p->is_exotic) {
8879
2.99M
        if (p->class_id == JS_CLASS_ARRAY) {
8880
2.99M
            uint32_t idx, len;
8881
8882
2.99M
            if (p->fast_array) {
8883
1.10M
                if (__JS_AtomIsTaggedInt(prop)) {
8884
1.10M
                    idx = __JS_AtomToUInt32(prop);
8885
1.10M
                    if (idx == p->u.array.count) {
8886
1.10M
                        if (!p->extensible)
8887
0
                            goto not_extensible;
8888
1.10M
                        if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET))
8889
0
                            goto convert_to_array;
8890
1.10M
                        prop_flags = get_prop_flags(flags, 0);
8891
1.10M
                        if (prop_flags != JS_PROP_C_W_E)
8892
0
                            goto convert_to_array;
8893
1.10M
                        return add_fast_array_element(ctx, p,
8894
1.10M
                                                      JS_DupValue(ctx, val), flags);
8895
1.10M
                    } else {
8896
6
                        goto convert_to_array;
8897
6
                    }
8898
1.10M
                } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
8899
                    /* convert the fast array to normal array */
8900
6
                convert_to_array:
8901
6
                    if (convert_fast_array_to_array(ctx, p))
8902
0
                        return -1;
8903
6
                    goto generic_array;
8904
6
                }
8905
1.88M
            } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
8906
1.88M
                JSProperty *plen;
8907
1.88M
                JSShapeProperty *pslen;
8908
1.88M
            generic_array:
8909
                /* update the length field */
8910
1.88M
                plen = &p->prop[0];
8911
1.88M
                JS_ToUint32(ctx, &len, plen->u.value);
8912
1.88M
                if ((idx + 1) > len) {
8913
1.88M
                    pslen = get_shape_prop(p->shape);
8914
1.88M
                    if (unlikely(!(pslen->flags & JS_PROP_WRITABLE)))
8915
0
                        return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
8916
                    /* XXX: should update the length after defining
8917
                       the property */
8918
1.88M
                    len = idx + 1;
8919
1.88M
                    set_value(ctx, &plen->u.value, JS_NewUint32(ctx, len));
8920
1.88M
                }
8921
1.88M
            }
8922
2.99M
        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
8923
468
                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
8924
0
            ret = JS_AtomIsNumericIndex(ctx, prop);
8925
0
            if (ret != 0) {
8926
0
                if (ret < 0)
8927
0
                    return -1;
8928
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "cannot create numeric index in typed array");
8929
0
            }
8930
468
        } else if (!(flags & JS_PROP_NO_EXOTIC)) {
8931
273
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8932
273
            if (em) {
8933
273
                if (em->define_own_property) {
8934
195
                    return em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p),
8935
195
                                                   prop, val, getter, setter, flags);
8936
195
                }
8937
78
                ret = JS_IsExtensible(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
8938
78
                if (ret < 0)
8939
0
                    return -1;
8940
78
                if (!ret)
8941
0
                    goto not_extensible;
8942
78
            }
8943
273
        }
8944
2.99M
    }
8945
8946
1.91M
    if (!p->extensible) {
8947
0
    not_extensible:
8948
0
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
8949
0
    }
8950
8951
1.91M
    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
8952
2.02k
        prop_flags = (flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
8953
2.02k
            JS_PROP_GETSET;
8954
1.91M
    } else {
8955
1.91M
        prop_flags = flags & JS_PROP_C_W_E;
8956
1.91M
    }
8957
1.91M
    pr = add_property(ctx, p, prop, prop_flags);
8958
1.91M
    if (unlikely(!pr))
8959
0
        return -1;
8960
1.91M
    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
8961
2.02k
        pr->u.getset.getter = NULL;
8962
2.02k
        if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) {
8963
2.02k
            pr->u.getset.getter =
8964
2.02k
                JS_VALUE_GET_OBJ(JS_DupValue(ctx, getter));
8965
2.02k
        }
8966
2.02k
        pr->u.getset.setter = NULL;
8967
2.02k
        if ((flags & JS_PROP_HAS_SET) && JS_IsFunction(ctx, setter)) {
8968
507
            pr->u.getset.setter =
8969
507
                JS_VALUE_GET_OBJ(JS_DupValue(ctx, setter));
8970
507
        }
8971
1.91M
    } else {
8972
1.91M
        if (flags & JS_PROP_HAS_VALUE) {
8973
1.91M
            pr->u.value = JS_DupValue(ctx, val);
8974
1.91M
        } else {
8975
0
            pr->u.value = JS_UNDEFINED;
8976
0
        }
8977
1.91M
    }
8978
1.91M
    return TRUE;
8979
1.91M
}
8980
8981
/* return FALSE if not OK */
8982
static BOOL check_define_prop_flags(int prop_flags, int flags)
8983
78
{
8984
78
    BOOL has_accessor, is_getset;
8985
8986
78
    if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
8987
0
        if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) ==
8988
0
            (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) {
8989
0
            return FALSE;
8990
0
        }
8991
0
        if ((flags & JS_PROP_HAS_ENUMERABLE) &&
8992
0
            (flags & JS_PROP_ENUMERABLE) != (prop_flags & JS_PROP_ENUMERABLE))
8993
0
            return FALSE;
8994
0
    }
8995
78
    if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
8996
78
                 JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
8997
0
        if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
8998
0
            has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0);
8999
0
            is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET);
9000
0
            if (has_accessor != is_getset)
9001
0
                return FALSE;
9002
0
            if (!has_accessor && !is_getset && !(prop_flags & JS_PROP_WRITABLE)) {
9003
                /* not writable: cannot set the writable bit */
9004
0
                if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
9005
0
                    (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE))
9006
0
                    return FALSE;
9007
0
            }
9008
0
        }
9009
0
    }
9010
78
    return TRUE;
9011
78
}
9012
9013
/* ensure that the shape can be safely modified */
9014
static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
9015
                                   JSShapeProperty **pprs)
9016
474
{
9017
474
    JSShape *sh;
9018
474
    uint32_t idx = 0;    /* prevent warning */
9019
9020
474
    sh = p->shape;
9021
474
    if (sh->is_hashed) {
9022
318
        if (sh->header.ref_count != 1) {
9023
45
            if (pprs)
9024
39
                idx = *pprs - get_shape_prop(sh);
9025
            /* clone the shape (the resulting one is no longer hashed) */
9026
45
            sh = js_clone_shape(ctx, sh);
9027
45
            if (!sh)
9028
0
                return -1;
9029
45
            js_free_shape(ctx->rt, p->shape);
9030
45
            p->shape = sh;
9031
45
            if (pprs)
9032
39
                *pprs = get_shape_prop(sh) + idx;
9033
273
        } else {
9034
273
            js_shape_hash_unlink(ctx->rt, sh);
9035
273
            sh->is_hashed = FALSE;
9036
273
        }
9037
318
    }
9038
474
    return 0;
9039
474
}
9040
9041
static int js_update_property_flags(JSContext *ctx, JSObject *p,
9042
                                    JSShapeProperty **pprs, int flags)
9043
78
{
9044
78
    if (flags != (*pprs)->flags) {
9045
78
        if (js_shape_prepare_update(ctx, p, pprs))
9046
0
            return -1;
9047
78
        (*pprs)->flags = flags;
9048
78
    }
9049
78
    return 0;
9050
78
}
9051
9052
/* allowed flags:
9053
   JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE
9054
   JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE,
9055
   JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE,
9056
   JS_PROP_THROW, JS_PROP_NO_EXOTIC.
9057
   If JS_PROP_THROW is set, return an exception instead of FALSE.
9058
   if JS_PROP_NO_EXOTIC is set, do not call the exotic
9059
   define_own_property callback.
9060
   return -1 (exception), FALSE or TRUE.
9061
*/
9062
int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
9063
                      JSAtom prop, JSValueConst val,
9064
                      JSValueConst getter, JSValueConst setter, int flags)
9065
3.02M
{
9066
3.02M
    JSObject *p;
9067
3.02M
    JSShapeProperty *prs;
9068
3.02M
    JSProperty *pr;
9069
3.02M
    int mask, res;
9070
9071
3.02M
    if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) {
9072
0
        JS_ThrowTypeErrorNotAnObject(ctx);
9073
0
        return -1;
9074
0
    }
9075
3.02M
    p = JS_VALUE_GET_OBJ(this_obj);
9076
9077
3.02M
 redo_prop_update:
9078
3.02M
    prs = find_own_property(&pr, p, prop);
9079
3.02M
    if (prs) {
9080
        /* the range of the Array length property is always tested before */
9081
78
        if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) {
9082
0
            uint32_t array_length;
9083
0
            if (JS_ToArrayLengthFree(ctx, &array_length,
9084
0
                                     JS_DupValue(ctx, val), FALSE)) {
9085
0
                return -1;
9086
0
            }
9087
            /* this code relies on the fact that Uint32 are never allocated */
9088
0
            val = (JSValueConst)JS_NewUint32(ctx, array_length);
9089
            /* prs may have been modified */
9090
0
            prs = find_own_property(&pr, p, prop);
9091
0
            assert(prs != NULL);
9092
0
        }
9093
        /* property already exists */
9094
78
        if (!check_define_prop_flags(prs->flags, flags)) {
9095
0
        not_configurable:
9096
0
            return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
9097
0
        }
9098
9099
78
        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
9100
            /* Instantiate property and retry */
9101
0
            if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
9102
0
                return -1;
9103
0
            goto redo_prop_update;
9104
0
        }
9105
9106
78
        if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
9107
78
                     JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9108
0
            if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9109
0
                JSObject *new_getter, *new_setter;
9110
9111
0
                if (JS_IsFunction(ctx, getter)) {
9112
0
                    new_getter = JS_VALUE_GET_OBJ(getter);
9113
0
                } else {
9114
0
                    new_getter = NULL;
9115
0
                }
9116
0
                if (JS_IsFunction(ctx, setter)) {
9117
0
                    new_setter = JS_VALUE_GET_OBJ(setter);
9118
0
                } else {
9119
0
                    new_setter = NULL;
9120
0
                }
9121
9122
0
                if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET) {
9123
0
                    if (js_shape_prepare_update(ctx, p, &prs))
9124
0
                        return -1;
9125
                    /* convert to getset */
9126
0
                    if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
9127
0
                        free_var_ref(ctx->rt, pr->u.var_ref);
9128
0
                    } else {
9129
0
                        JS_FreeValue(ctx, pr->u.value);
9130
0
                    }
9131
0
                    prs->flags = (prs->flags &
9132
0
                                  (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
9133
0
                        JS_PROP_GETSET;
9134
0
                    pr->u.getset.getter = NULL;
9135
0
                    pr->u.getset.setter = NULL;
9136
0
                } else {
9137
0
                    if (!(prs->flags & JS_PROP_CONFIGURABLE)) {
9138
0
                        if ((flags & JS_PROP_HAS_GET) &&
9139
0
                            new_getter != pr->u.getset.getter) {
9140
0
                            goto not_configurable;
9141
0
                        }
9142
0
                        if ((flags & JS_PROP_HAS_SET) &&
9143
0
                            new_setter != pr->u.getset.setter) {
9144
0
                            goto not_configurable;
9145
0
                        }
9146
0
                    }
9147
0
                }
9148
0
                if (flags & JS_PROP_HAS_GET) {
9149
0
                    if (pr->u.getset.getter)
9150
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
9151
0
                    if (new_getter)
9152
0
                        JS_DupValue(ctx, getter);
9153
0
                    pr->u.getset.getter = new_getter;
9154
0
                }
9155
0
                if (flags & JS_PROP_HAS_SET) {
9156
0
                    if (pr->u.getset.setter)
9157
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
9158
0
                    if (new_setter)
9159
0
                        JS_DupValue(ctx, setter);
9160
0
                    pr->u.getset.setter = new_setter;
9161
0
                }
9162
0
            } else {
9163
0
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
9164
                    /* convert to data descriptor */
9165
0
                    if (js_shape_prepare_update(ctx, p, &prs))
9166
0
                        return -1;
9167
0
                    if (pr->u.getset.getter)
9168
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
9169
0
                    if (pr->u.getset.setter)
9170
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
9171
0
                    prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
9172
0
                    pr->u.value = JS_UNDEFINED;
9173
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
9174
                    /* Note: JS_PROP_VARREF is always writable */
9175
0
                } else {
9176
0
                    if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
9177
0
                        (flags & JS_PROP_HAS_VALUE)) {
9178
0
                        if (!js_same_value(ctx, val, pr->u.value)) {
9179
0
                            goto not_configurable;
9180
0
                        } else {
9181
0
                            return TRUE;
9182
0
                        }
9183
0
                    }
9184
0
                }
9185
0
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
9186
0
                    if (flags & JS_PROP_HAS_VALUE) {
9187
0
                        if (p->class_id == JS_CLASS_MODULE_NS) {
9188
                            /* JS_PROP_WRITABLE is always true for variable
9189
                               references, but they are write protected in module name
9190
                               spaces. */
9191
0
                            if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue))
9192
0
                                goto not_configurable;
9193
0
                        } else {
9194
                            /* update the reference */
9195
0
                            set_value(ctx, pr->u.var_ref->pvalue,
9196
0
                                      JS_DupValue(ctx, val));
9197
0
                        }
9198
0
                    }
9199
                    /* if writable is set to false, no longer a
9200
                       reference (for mapped arguments) */
9201
0
                    if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
9202
0
                        JSValue val1;
9203
0
                        if (p->class_id == JS_CLASS_MODULE_NS) {
9204
0
                            return JS_ThrowTypeErrorOrFalse(ctx, flags, "module namespace properties have writable = false");
9205
0
                        }
9206
0
                        if (js_shape_prepare_update(ctx, p, &prs))
9207
0
                            return -1;
9208
0
                        val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue);
9209
0
                        free_var_ref(ctx->rt, pr->u.var_ref);
9210
0
                        pr->u.value = val1;
9211
0
                        prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
9212
0
                    }
9213
0
                } else if (prs->flags & JS_PROP_LENGTH) {
9214
0
                    if (flags & JS_PROP_HAS_VALUE) {
9215
                        /* Note: no JS code is executable because
9216
                           'val' is guaranted to be a Uint32 */
9217
0
                        res = set_array_length(ctx, p, JS_DupValue(ctx, val),
9218
0
                                               flags);
9219
0
                    } else {
9220
0
                        res = TRUE;
9221
0
                    }
9222
                    /* still need to reset the writable flag if
9223
                       needed.  The JS_PROP_LENGTH is kept because the
9224
                       Uint32 test is still done if the length
9225
                       property is read-only. */
9226
0
                    if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
9227
0
                        JS_PROP_HAS_WRITABLE) {
9228
0
                        prs = get_shape_prop(p->shape);
9229
0
                        if (js_update_property_flags(ctx, p, &prs,
9230
0
                                                     prs->flags & ~JS_PROP_WRITABLE))
9231
0
                            return -1;
9232
0
                    }
9233
0
                    return res;
9234
0
                } else {
9235
0
                    if (flags & JS_PROP_HAS_VALUE) {
9236
0
                        JS_FreeValue(ctx, pr->u.value);
9237
0
                        pr->u.value = JS_DupValue(ctx, val);
9238
0
                    }
9239
0
                    if (flags & JS_PROP_HAS_WRITABLE) {
9240
0
                        if (js_update_property_flags(ctx, p, &prs,
9241
0
                                                     (prs->flags & ~JS_PROP_WRITABLE) |
9242
0
                                                     (flags & JS_PROP_WRITABLE)))
9243
0
                            return -1;
9244
0
                    }
9245
0
                }
9246
0
            }
9247
0
        }
9248
78
        mask = 0;
9249
78
        if (flags & JS_PROP_HAS_CONFIGURABLE)
9250
78
            mask |= JS_PROP_CONFIGURABLE;
9251
78
        if (flags & JS_PROP_HAS_ENUMERABLE)
9252
0
            mask |= JS_PROP_ENUMERABLE;
9253
78
        if (js_update_property_flags(ctx, p, &prs,
9254
78
                                     (prs->flags & ~mask) | (flags & mask)))
9255
0
            return -1;
9256
78
        return TRUE;
9257
78
    }
9258
9259
    /* handle modification of fast array elements */
9260
3.02M
    if (p->fast_array) {
9261
1.10M
        uint32_t idx;
9262
1.10M
        uint32_t prop_flags;
9263
1.10M
        if (p->class_id == JS_CLASS_ARRAY) {
9264
1.10M
            if (__JS_AtomIsTaggedInt(prop)) {
9265
1.10M
                idx = __JS_AtomToUInt32(prop);
9266
1.10M
                if (idx < p->u.array.count) {
9267
0
                    prop_flags = get_prop_flags(flags, JS_PROP_C_W_E);
9268
0
                    if (prop_flags != JS_PROP_C_W_E)
9269
0
                        goto convert_to_slow_array;
9270
0
                    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9271
0
                    convert_to_slow_array:
9272
0
                        if (convert_fast_array_to_array(ctx, p))
9273
0
                            return -1;
9274
0
                        else
9275
0
                            goto redo_prop_update;
9276
0
                    }
9277
0
                    if (flags & JS_PROP_HAS_VALUE) {
9278
0
                        set_value(ctx, &p->u.array.u.values[idx], JS_DupValue(ctx, val));
9279
0
                    }
9280
0
                    return TRUE;
9281
0
                }
9282
1.10M
            }
9283
1.10M
        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
9284
0
                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
9285
0
            JSValue num;
9286
0
            int ret;
9287
9288
0
            if (!__JS_AtomIsTaggedInt(prop)) {
9289
                /* slow path with to handle all numeric indexes */
9290
0
                num = JS_AtomIsNumericIndex1(ctx, prop);
9291
0
                if (JS_IsUndefined(num))
9292
0
                    goto typed_array_done;
9293
0
                if (JS_IsException(num))
9294
0
                    return -1;
9295
0
                ret = JS_NumberIsInteger(ctx, num);
9296
0
                if (ret < 0) {
9297
0
                    JS_FreeValue(ctx, num);
9298
0
                    return -1;
9299
0
                }
9300
0
                if (!ret) {
9301
0
                    JS_FreeValue(ctx, num);
9302
0
                    return JS_ThrowTypeErrorOrFalse(ctx, flags, "non integer index in typed array");
9303
0
                }
9304
0
                ret = JS_NumberIsNegativeOrMinusZero(ctx, num);
9305
0
                JS_FreeValue(ctx, num);
9306
0
                if (ret) {
9307
0
                    return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array");
9308
0
                }
9309
0
                if (!__JS_AtomIsTaggedInt(prop))
9310
0
                    goto typed_array_oob;
9311
0
            }
9312
0
            idx = __JS_AtomToUInt32(prop);
9313
            /* if the typed array is detached, p->u.array.count = 0 */
9314
0
            if (idx >= p->u.array.count) {
9315
0
            typed_array_oob:
9316
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array");
9317
0
            }
9318
0
            prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
9319
0
            if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) ||
9320
0
                prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) {
9321
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags");
9322
0
            }
9323
0
            if (flags & JS_PROP_HAS_VALUE) {
9324
0
                return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), JS_DupValue(ctx, val), flags);
9325
0
            }
9326
0
            return TRUE;
9327
0
        typed_array_done: ;
9328
0
        }
9329
1.10M
    }
9330
9331
3.02M
    return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags);
9332
3.02M
}
9333
9334
static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj,
9335
                                     JSAtom prop, JSAutoInitIDEnum id,
9336
                                     void *opaque, int flags)
9337
16.9k
{
9338
16.9k
    JSObject *p;
9339
16.9k
    JSProperty *pr;
9340
9341
16.9k
    if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT)
9342
0
        return FALSE;
9343
9344
16.9k
    p = JS_VALUE_GET_OBJ(this_obj);
9345
9346
16.9k
    if (find_own_property(&pr, p, prop)) {
9347
        /* property already exists */
9348
0
        abort();
9349
0
        return FALSE;
9350
0
    }
9351
9352
    /* Specialized CreateProperty */
9353
16.9k
    pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT);
9354
16.9k
    if (unlikely(!pr))
9355
0
        return -1;
9356
16.9k
    pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx);
9357
16.9k
    assert((pr->u.init.realm_and_id & 3) == 0);
9358
16.9k
    assert(id <= 3);
9359
16.9k
    pr->u.init.realm_and_id |= id;
9360
16.9k
    pr->u.init.opaque = opaque;
9361
16.9k
    return TRUE;
9362
16.9k
}
9363
9364
/* shortcut to add or redefine a new property value */
9365
int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj,
9366
                           JSAtom prop, JSValue val, int flags)
9367
3.01M
{
9368
3.01M
    int ret;
9369
3.01M
    ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED,
9370
3.01M
                            flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE);
9371
3.01M
    JS_FreeValue(ctx, val);
9372
3.01M
    return ret;
9373
3.01M
}
9374
9375
int JS_DefinePropertyValueValue(JSContext *ctx, JSValueConst this_obj,
9376
                                JSValue prop, JSValue val, int flags)
9377
0
{
9378
0
    JSAtom atom;
9379
0
    int ret;
9380
0
    atom = JS_ValueToAtom(ctx, prop);
9381
0
    JS_FreeValue(ctx, prop);
9382
0
    if (unlikely(atom == JS_ATOM_NULL)) {
9383
0
        JS_FreeValue(ctx, val);
9384
0
        return -1;
9385
0
    }
9386
0
    ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
9387
0
    JS_FreeAtom(ctx, atom);
9388
0
    return ret;
9389
0
}
9390
9391
int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj,
9392
                                 uint32_t idx, JSValue val, int flags)
9393
0
{
9394
0
    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewUint32(ctx, idx),
9395
0
                                       val, flags);
9396
0
}
9397
9398
int JS_DefinePropertyValueInt64(JSContext *ctx, JSValueConst this_obj,
9399
                                int64_t idx, JSValue val, int flags)
9400
0
{
9401
0
    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),
9402
0
                                       val, flags);
9403
0
}
9404
9405
int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
9406
                              const char *prop, JSValue val, int flags)
9407
3.62k
{
9408
3.62k
    JSAtom atom;
9409
3.62k
    int ret;
9410
3.62k
    atom = JS_NewAtom(ctx, prop);
9411
3.62k
    ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
9412
3.62k
    JS_FreeAtom(ctx, atom);
9413
3.62k
    return ret;
9414
3.62k
}
9415
9416
/* shortcut to add getter & setter */
9417
int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,
9418
                            JSAtom prop, JSValue getter, JSValue setter,
9419
                            int flags)
9420
1.95k
{
9421
1.95k
    int ret;
9422
1.95k
    ret = JS_DefineProperty(ctx, this_obj, prop, JS_UNDEFINED, getter, setter,
9423
1.95k
                            flags | JS_PROP_HAS_GET | JS_PROP_HAS_SET |
9424
1.95k
                            JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE);
9425
1.95k
    JS_FreeValue(ctx, getter);
9426
1.95k
    JS_FreeValue(ctx, setter);
9427
1.95k
    return ret;
9428
1.95k
}
9429
9430
static int JS_CreateDataPropertyUint32(JSContext *ctx, JSValueConst this_obj,
9431
                                       int64_t idx, JSValue val, int flags)
9432
0
{
9433
0
    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),
9434
0
                                       val, flags | JS_PROP_CONFIGURABLE |
9435
0
                                       JS_PROP_ENUMERABLE | JS_PROP_WRITABLE);
9436
0
}
9437
9438
9439
/* return TRUE if 'obj' has a non empty 'name' string */
9440
static BOOL js_object_has_name(JSContext *ctx, JSValueConst obj)
9441
0
{
9442
0
    JSProperty *pr;
9443
0
    JSShapeProperty *prs;
9444
0
    JSValueConst val;
9445
0
    JSString *p;
9446
9447
0
    prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name);
9448
0
    if (!prs)
9449
0
        return FALSE;
9450
0
    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
9451
0
        return TRUE;
9452
0
    val = pr->u.value;
9453
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
9454
0
        return TRUE;
9455
0
    p = JS_VALUE_GET_STRING(val);
9456
0
    return (p->len != 0);
9457
0
}
9458
9459
static int JS_DefineObjectName(JSContext *ctx, JSValueConst obj,
9460
                               JSAtom name, int flags)
9461
0
{
9462
0
    if (name != JS_ATOM_NULL
9463
0
    &&  JS_IsObject(obj)
9464
0
    &&  !js_object_has_name(ctx, obj)
9465
0
    &&  JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, JS_AtomToString(ctx, name), flags) < 0) {
9466
0
        return -1;
9467
0
    }
9468
0
    return 0;
9469
0
}
9470
9471
static int JS_DefineObjectNameComputed(JSContext *ctx, JSValueConst obj,
9472
                                       JSValueConst str, int flags)
9473
0
{
9474
0
    if (JS_IsObject(obj) &&
9475
0
        !js_object_has_name(ctx, obj)) {
9476
0
        JSAtom prop;
9477
0
        JSValue name_str;
9478
0
        prop = JS_ValueToAtom(ctx, str);
9479
0
        if (prop == JS_ATOM_NULL)
9480
0
            return -1;
9481
0
        name_str = js_get_function_name(ctx, prop);
9482
0
        JS_FreeAtom(ctx, prop);
9483
0
        if (JS_IsException(name_str))
9484
0
            return -1;
9485
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name_str, flags) < 0)
9486
0
            return -1;
9487
0
    }
9488
0
    return 0;
9489
0
}
9490
9491
0
#define DEFINE_GLOBAL_LEX_VAR (1 << 7)
9492
0
#define DEFINE_GLOBAL_FUNC_VAR (1 << 6)
9493
9494
static JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop)
9495
0
{
9496
0
    return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop);
9497
0
}
9498
9499
/* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */
9500
/* XXX: could support exotic global object. */
9501
static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags)
9502
0
{
9503
0
    JSObject *p;
9504
0
    JSShapeProperty *prs;
9505
9506
0
    p = JS_VALUE_GET_OBJ(ctx->global_obj);
9507
0
    prs = find_own_property1(p, prop);
9508
    /* XXX: should handle JS_PROP_AUTOINIT */
9509
0
    if (flags & DEFINE_GLOBAL_LEX_VAR) {
9510
0
        if (prs && !(prs->flags & JS_PROP_CONFIGURABLE))
9511
0
            goto fail_redeclaration;
9512
0
    } else {
9513
0
        if (!prs && !p->extensible)
9514
0
            goto define_error;
9515
0
        if (flags & DEFINE_GLOBAL_FUNC_VAR) {
9516
0
            if (prs) {
9517
0
                if (!(prs->flags & JS_PROP_CONFIGURABLE) &&
9518
0
                    ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET ||
9519
0
                     ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) !=
9520
0
                      (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) {
9521
0
                define_error:
9522
0
                    JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'",
9523
0
                                          prop);
9524
0
                    return -1;
9525
0
                }
9526
0
            }
9527
0
        }
9528
0
    }
9529
    /* check if there already is a lexical declaration */
9530
0
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9531
0
    prs = find_own_property1(p, prop);
9532
0
    if (prs) {
9533
0
    fail_redeclaration:
9534
0
        JS_ThrowSyntaxErrorVarRedeclaration(ctx, prop);
9535
0
        return -1;
9536
0
    }
9537
0
    return 0;
9538
0
}
9539
9540
/* def_flags is (0, DEFINE_GLOBAL_LEX_VAR) |
9541
   JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE */
9542
/* XXX: could support exotic global object. */
9543
static int JS_DefineGlobalVar(JSContext *ctx, JSAtom prop, int def_flags)
9544
0
{
9545
0
    JSObject *p;
9546
0
    JSShapeProperty *prs;
9547
0
    JSProperty *pr;
9548
0
    JSValue val;
9549
0
    int flags;
9550
9551
0
    if (def_flags & DEFINE_GLOBAL_LEX_VAR) {
9552
0
        p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9553
0
        flags = JS_PROP_ENUMERABLE | (def_flags & JS_PROP_WRITABLE) |
9554
0
            JS_PROP_CONFIGURABLE;
9555
0
        val = JS_UNINITIALIZED;
9556
0
    } else {
9557
0
        p = JS_VALUE_GET_OBJ(ctx->global_obj);
9558
0
        flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
9559
0
            (def_flags & JS_PROP_CONFIGURABLE);
9560
0
        val = JS_UNDEFINED;
9561
0
    }
9562
0
    prs = find_own_property1(p, prop);
9563
0
    if (prs)
9564
0
        return 0;
9565
0
    if (!p->extensible)
9566
0
        return 0;
9567
0
    pr = add_property(ctx, p, prop, flags);
9568
0
    if (unlikely(!pr))
9569
0
        return -1;
9570
0
    pr->u.value = val;
9571
0
    return 0;
9572
0
}
9573
9574
/* 'def_flags' is 0 or JS_PROP_CONFIGURABLE. */
9575
/* XXX: could support exotic global object. */
9576
static int JS_DefineGlobalFunction(JSContext *ctx, JSAtom prop,
9577
                                   JSValueConst func, int def_flags)
9578
0
{
9579
9580
0
    JSObject *p;
9581
0
    JSShapeProperty *prs;
9582
0
    int flags;
9583
9584
0
    p = JS_VALUE_GET_OBJ(ctx->global_obj);
9585
0
    prs = find_own_property1(p, prop);
9586
0
    flags = JS_PROP_HAS_VALUE | JS_PROP_THROW;
9587
0
    if (!prs || (prs->flags & JS_PROP_CONFIGURABLE)) {
9588
0
        flags |= JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | def_flags |
9589
0
            JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE;
9590
0
    }
9591
0
    if (JS_DefineProperty(ctx, ctx->global_obj, prop, func,
9592
0
                          JS_UNDEFINED, JS_UNDEFINED, flags) < 0)
9593
0
        return -1;
9594
0
    return 0;
9595
0
}
9596
9597
static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop,
9598
                               BOOL throw_ref_error)
9599
87
{
9600
87
    JSObject *p;
9601
87
    JSShapeProperty *prs;
9602
87
    JSProperty *pr;
9603
9604
    /* no exotic behavior is possible in global_var_obj */
9605
87
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9606
87
    prs = find_own_property(&pr, p, prop);
9607
87
    if (prs) {
9608
        /* XXX: should handle JS_PROP_TMASK properties */
9609
0
        if (unlikely(JS_IsUninitialized(pr->u.value)))
9610
0
            return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
9611
0
        return JS_DupValue(ctx, pr->u.value);
9612
0
    }
9613
87
    return JS_GetPropertyInternal(ctx, ctx->global_obj, prop,
9614
87
                                 ctx->global_obj, throw_ref_error);
9615
87
}
9616
9617
/* construct a reference to a global variable */
9618
static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom prop, JSValue *sp)
9619
0
{
9620
0
    JSObject *p;
9621
0
    JSShapeProperty *prs;
9622
0
    JSProperty *pr;
9623
9624
    /* no exotic behavior is possible in global_var_obj */
9625
0
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9626
0
    prs = find_own_property(&pr, p, prop);
9627
0
    if (prs) {
9628
        /* XXX: should handle JS_PROP_AUTOINIT properties? */
9629
        /* XXX: conformance: do these tests in
9630
           OP_put_var_ref/OP_get_var_ref ? */
9631
0
        if (unlikely(JS_IsUninitialized(pr->u.value))) {
9632
0
            JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
9633
0
            return -1;
9634
0
        }
9635
0
        if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
9636
0
            return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
9637
0
        }
9638
0
        sp[0] = JS_DupValue(ctx, ctx->global_var_obj);
9639
0
    } else {
9640
0
        int ret;
9641
0
        ret = JS_HasProperty(ctx, ctx->global_obj, prop);
9642
0
        if (ret < 0)
9643
0
            return -1;
9644
0
        if (ret) {
9645
0
            sp[0] = JS_DupValue(ctx, ctx->global_obj);
9646
0
        } else {
9647
0
            sp[0] = JS_UNDEFINED;
9648
0
        }
9649
0
    }
9650
0
    sp[1] = JS_AtomToValue(ctx, prop);
9651
0
    return 0;
9652
0
}
9653
9654
/* use for strict variable access: test if the variable exists */
9655
static int JS_CheckGlobalVar(JSContext *ctx, JSAtom prop)
9656
0
{
9657
0
    JSObject *p;
9658
0
    JSShapeProperty *prs;
9659
0
    int ret;
9660
9661
    /* no exotic behavior is possible in global_var_obj */
9662
0
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9663
0
    prs = find_own_property1(p, prop);
9664
0
    if (prs) {
9665
0
        ret = TRUE;
9666
0
    } else {
9667
0
        ret = JS_HasProperty(ctx, ctx->global_obj, prop);
9668
0
        if (ret < 0)
9669
0
            return -1;
9670
0
    }
9671
0
    return ret;
9672
0
}
9673
9674
/* flag = 0: normal variable write
9675
   flag = 1: initialize lexical variable
9676
   flag = 2: normal variable write, strict check was done before
9677
*/
9678
static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val,
9679
                           int flag)
9680
0
{
9681
0
    JSObject *p;
9682
0
    JSShapeProperty *prs;
9683
0
    JSProperty *pr;
9684
0
    int flags;
9685
9686
    /* no exotic behavior is possible in global_var_obj */
9687
0
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9688
0
    prs = find_own_property(&pr, p, prop);
9689
0
    if (prs) {
9690
        /* XXX: should handle JS_PROP_AUTOINIT properties? */
9691
0
        if (flag != 1) {
9692
0
            if (unlikely(JS_IsUninitialized(pr->u.value))) {
9693
0
                JS_FreeValue(ctx, val);
9694
0
                JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
9695
0
                return -1;
9696
0
            }
9697
0
            if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
9698
0
                JS_FreeValue(ctx, val);
9699
0
                return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
9700
0
            }
9701
0
        }
9702
0
        set_value(ctx, &pr->u.value, val);
9703
0
        return 0;
9704
0
    }
9705
0
    flags = JS_PROP_THROW_STRICT;
9706
0
    if (is_strict_mode(ctx))
9707
0
        flags |= JS_PROP_NO_ADD;
9708
0
    return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, ctx->global_obj, flags);
9709
0
}
9710
9711
/* return -1, FALSE or TRUE. return FALSE if not configurable or
9712
   invalid object. return -1 in case of exception.
9713
   flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */
9714
int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags)
9715
0
{
9716
0
    JSValue obj1;
9717
0
    JSObject *p;
9718
0
    int res;
9719
9720
0
    obj1 = JS_ToObject(ctx, obj);
9721
0
    if (JS_IsException(obj1))
9722
0
        return -1;
9723
0
    p = JS_VALUE_GET_OBJ(obj1);
9724
0
    res = delete_property(ctx, p, prop);
9725
0
    JS_FreeValue(ctx, obj1);
9726
0
    if (res != FALSE)
9727
0
        return res;
9728
0
    if ((flags & JS_PROP_THROW) ||
9729
0
        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
9730
0
        JS_ThrowTypeError(ctx, "could not delete property");
9731
0
        return -1;
9732
0
    }
9733
0
    return FALSE;
9734
0
}
9735
9736
int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int flags)
9737
0
{
9738
0
    JSAtom prop;
9739
0
    int res;
9740
9741
0
    if ((uint64_t)idx <= JS_ATOM_MAX_INT) {
9742
        /* fast path for fast arrays */
9743
0
        return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags);
9744
0
    }
9745
0
    prop = JS_NewAtomInt64(ctx, idx);
9746
0
    if (prop == JS_ATOM_NULL)
9747
0
        return -1;
9748
0
    res = JS_DeleteProperty(ctx, obj, prop, flags);
9749
0
    JS_FreeAtom(ctx, prop);
9750
0
    return res;
9751
0
}
9752
9753
BOOL JS_IsFunction(JSContext *ctx, JSValueConst val)
9754
4.29k
{
9755
4.29k
    JSObject *p;
9756
4.29k
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9757
1.52k
        return FALSE;
9758
2.76k
    p = JS_VALUE_GET_OBJ(val);
9759
2.76k
    switch(p->class_id) {
9760
0
    case JS_CLASS_BYTECODE_FUNCTION:
9761
0
        return TRUE;
9762
0
    case JS_CLASS_PROXY:
9763
0
        return p->u.proxy_data->is_func;
9764
2.76k
    default:
9765
2.76k
        return (ctx->rt->class_array[p->class_id].call != NULL);
9766
2.76k
    }
9767
2.76k
}
9768
9769
BOOL JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func, int magic)
9770
0
{
9771
0
    JSObject *p;
9772
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9773
0
        return FALSE;
9774
0
    p = JS_VALUE_GET_OBJ(val);
9775
0
    if (p->class_id == JS_CLASS_C_FUNCTION)
9776
0
        return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic);
9777
0
    else
9778
0
        return FALSE;
9779
0
}
9780
9781
BOOL JS_IsConstructor(JSContext *ctx, JSValueConst val)
9782
0
{
9783
0
    JSObject *p;
9784
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9785
0
        return FALSE;
9786
0
    p = JS_VALUE_GET_OBJ(val);
9787
0
    return p->is_constructor;
9788
0
}
9789
9790
BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, BOOL val)
9791
39
{
9792
39
    JSObject *p;
9793
39
    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
9794
0
        return FALSE;
9795
39
    p = JS_VALUE_GET_OBJ(func_obj);
9796
39
    p->is_constructor = val;
9797
39
    return TRUE;
9798
39
}
9799
9800
BOOL JS_IsError(JSContext *ctx, JSValueConst val)
9801
0
{
9802
0
    JSObject *p;
9803
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9804
0
        return FALSE;
9805
0
    p = JS_VALUE_GET_OBJ(val);
9806
0
    return (p->class_id == JS_CLASS_ERROR);
9807
0
}
9808
9809
/* used to avoid catching interrupt exceptions */
9810
BOOL JS_IsUncatchableError(JSContext *ctx, JSValueConst val)
9811
9
{
9812
9
    JSObject *p;
9813
9
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9814
0
        return FALSE;
9815
9
    p = JS_VALUE_GET_OBJ(val);
9816
9
    return p->class_id == JS_CLASS_ERROR && p->is_uncatchable_error;
9817
9
}
9818
9819
void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag)
9820
0
{
9821
0
    JSObject *p;
9822
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9823
0
        return;
9824
0
    p = JS_VALUE_GET_OBJ(val);
9825
0
    if (p->class_id == JS_CLASS_ERROR)
9826
0
        p->is_uncatchable_error = flag;
9827
0
}
9828
9829
void JS_ResetUncatchableError(JSContext *ctx)
9830
0
{
9831
0
    JS_SetUncatchableError(ctx, ctx->rt->current_exception, FALSE);
9832
0
}
9833
9834
void JS_SetOpaque(JSValue obj, void *opaque)
9835
663
{
9836
663
   JSObject *p;
9837
663
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
9838
663
        p = JS_VALUE_GET_OBJ(obj);
9839
663
        p->u.opaque = opaque;
9840
663
    }
9841
663
}
9842
9843
/* return NULL if not an object of class class_id */
9844
void *JS_GetOpaque(JSValueConst obj, JSClassID class_id)
9845
1.88k
{
9846
1.88k
    JSObject *p;
9847
1.88k
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
9848
0
        return NULL;
9849
1.88k
    p = JS_VALUE_GET_OBJ(obj);
9850
1.88k
    if (p->class_id != class_id)
9851
0
        return NULL;
9852
1.88k
    return p->u.opaque;
9853
1.88k
}
9854
9855
void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id)
9856
0
{
9857
0
    void *p = JS_GetOpaque(obj, class_id);
9858
0
    if (unlikely(!p)) {
9859
0
        JS_ThrowTypeErrorInvalidClass(ctx, class_id);
9860
0
    }
9861
0
    return p;
9862
0
}
9863
9864
static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)
9865
0
{
9866
0
    int i;
9867
0
    BOOL force_ordinary;
9868
9869
0
    JSAtom method_name;
9870
0
    JSValue method, ret;
9871
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9872
0
        return val;
9873
0
    force_ordinary = hint & HINT_FORCE_ORDINARY;
9874
0
    hint &= ~HINT_FORCE_ORDINARY;
9875
0
    if (!force_ordinary) {
9876
0
        method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive);
9877
0
        if (JS_IsException(method))
9878
0
            goto exception;
9879
        /* ECMA says *If exoticToPrim is not undefined* but tests in
9880
           test262 use null as a non callable converter */
9881
0
        if (!JS_IsUndefined(method) && !JS_IsNull(method)) {
9882
0
            JSAtom atom;
9883
0
            JSValue arg;
9884
0
            switch(hint) {
9885
0
            case HINT_STRING:
9886
0
                atom = JS_ATOM_string;
9887
0
                break;
9888
0
            case HINT_NUMBER:
9889
0
                atom = JS_ATOM_number;
9890
0
                break;
9891
0
            default:
9892
0
            case HINT_NONE:
9893
0
                atom = JS_ATOM_default;
9894
0
                break;
9895
0
            }
9896
0
            arg = JS_AtomToString(ctx, atom);
9897
0
            ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);
9898
0
            JS_FreeValue(ctx, arg);
9899
0
            if (JS_IsException(ret))
9900
0
                goto exception;
9901
0
            JS_FreeValue(ctx, val);
9902
0
            if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT)
9903
0
                return ret;
9904
0
            JS_FreeValue(ctx, ret);
9905
0
            return JS_ThrowTypeError(ctx, "toPrimitive");
9906
0
        }
9907
0
    }
9908
0
    if (hint != HINT_STRING)
9909
0
        hint = HINT_NUMBER;
9910
0
    for(i = 0; i < 2; i++) {
9911
0
        if ((i ^ hint) == 0) {
9912
0
            method_name = JS_ATOM_toString;
9913
0
        } else {
9914
0
            method_name = JS_ATOM_valueOf;
9915
0
        }
9916
0
        method = JS_GetProperty(ctx, val, method_name);
9917
0
        if (JS_IsException(method))
9918
0
            goto exception;
9919
0
        if (JS_IsFunction(ctx, method)) {
9920
0
            ret = JS_CallFree(ctx, method, val, 0, NULL);
9921
0
            if (JS_IsException(ret))
9922
0
                goto exception;
9923
0
            if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
9924
0
                JS_FreeValue(ctx, val);
9925
0
                return ret;
9926
0
            }
9927
0
            JS_FreeValue(ctx, ret);
9928
0
        } else {
9929
0
            JS_FreeValue(ctx, method);
9930
0
        }
9931
0
    }
9932
0
    JS_ThrowTypeError(ctx, "toPrimitive");
9933
0
exception:
9934
0
    JS_FreeValue(ctx, val);
9935
0
    return JS_EXCEPTION;
9936
0
}
9937
9938
static JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint)
9939
0
{
9940
0
    return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint);
9941
0
}
9942
9943
void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj)
9944
0
{
9945
0
    JSObject *p;
9946
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
9947
0
        return;
9948
0
    p = JS_VALUE_GET_OBJ(obj);
9949
0
    p->is_HTMLDDA = TRUE;
9950
0
}
9951
9952
static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj)
9953
0
{
9954
0
    JSObject *p;
9955
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
9956
0
        return FALSE;
9957
0
    p = JS_VALUE_GET_OBJ(obj);
9958
0
    return p->is_HTMLDDA;
9959
0
}
9960
9961
static int JS_ToBoolFree(JSContext *ctx, JSValue val)
9962
0
{
9963
0
    uint32_t tag = JS_VALUE_GET_TAG(val);
9964
0
    switch(tag) {
9965
0
    case JS_TAG_INT:
9966
0
        return JS_VALUE_GET_INT(val) != 0;
9967
0
    case JS_TAG_BOOL:
9968
0
    case JS_TAG_NULL:
9969
0
    case JS_TAG_UNDEFINED:
9970
0
        return JS_VALUE_GET_INT(val);
9971
0
    case JS_TAG_EXCEPTION:
9972
0
        return -1;
9973
0
    case JS_TAG_STRING:
9974
0
        {
9975
0
            BOOL ret = JS_VALUE_GET_STRING(val)->len != 0;
9976
0
            JS_FreeValue(ctx, val);
9977
0
            return ret;
9978
0
        }
9979
0
    case JS_TAG_BIG_INT:
9980
0
#ifdef CONFIG_BIGNUM
9981
0
    case JS_TAG_BIG_FLOAT:
9982
0
#endif
9983
0
        {
9984
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
9985
0
            BOOL ret;
9986
0
            ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
9987
0
            JS_FreeValue(ctx, val);
9988
0
            return ret;
9989
0
        }
9990
0
#ifdef CONFIG_BIGNUM
9991
0
    case JS_TAG_BIG_DECIMAL:
9992
0
        {
9993
0
            JSBigDecimal *p = JS_VALUE_GET_PTR(val);
9994
0
            BOOL ret;
9995
0
            ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
9996
0
            JS_FreeValue(ctx, val);
9997
0
            return ret;
9998
0
        }
9999
0
#endif
10000
0
    case JS_TAG_OBJECT:
10001
0
        {
10002
0
            JSObject *p = JS_VALUE_GET_OBJ(val);
10003
0
            BOOL ret;
10004
0
            ret = !p->is_HTMLDDA;
10005
0
            JS_FreeValue(ctx, val);
10006
0
            return ret;
10007
0
        }
10008
0
        break;
10009
0
    default:
10010
0
        if (JS_TAG_IS_FLOAT64(tag)) {
10011
0
            double d = JS_VALUE_GET_FLOAT64(val);
10012
0
            return !isnan(d) && d != 0;
10013
0
        } else {
10014
0
            JS_FreeValue(ctx, val);
10015
0
            return TRUE;
10016
0
        }
10017
0
    }
10018
0
}
10019
10020
int JS_ToBool(JSContext *ctx, JSValueConst val)
10021
0
{
10022
0
    return JS_ToBoolFree(ctx, JS_DupValue(ctx, val));
10023
0
}
10024
10025
static int skip_spaces(const char *pc)
10026
0
{
10027
0
    const uint8_t *p, *p_next, *p_start;
10028
0
    uint32_t c;
10029
10030
0
    p = p_start = (const uint8_t *)pc;
10031
0
    for (;;) {
10032
0
        c = *p;
10033
0
        if (c < 128) {
10034
0
            if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20)))
10035
0
                break;
10036
0
            p++;
10037
0
        } else {
10038
0
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
10039
0
            if (!lre_is_space(c))
10040
0
                break;
10041
0
            p = p_next;
10042
0
        }
10043
0
    }
10044
0
    return p - p_start;
10045
0
}
10046
10047
static inline int to_digit(int c)
10048
27.2M
{
10049
27.2M
    if (c >= '0' && c <= '9')
10050
16.0M
        return c - '0';
10051
11.1M
    else if (c >= 'A' && c <= 'Z')
10052
0
        return c - 'A' + 10;
10053
11.1M
    else if (c >= 'a' && c <= 'z')
10054
5
        return c - 'a' + 10;
10055
11.1M
    else
10056
11.1M
        return 36;
10057
27.2M
}
10058
10059
/* XXX: remove */
10060
static double js_strtod(const char *str, int radix, BOOL is_float)
10061
11.1M
{
10062
11.1M
    double d;
10063
11.1M
    int c;
10064
10065
11.1M
    if (!is_float || radix != 10) {
10066
11.1M
        const char *p = str;
10067
11.1M
        uint64_t n_max, n;
10068
11.1M
        int int_exp, is_neg;
10069
10070
11.1M
        is_neg = 0;
10071
11.1M
        if (*p == '-') {
10072
0
            is_neg = 1;
10073
0
            p++;
10074
0
        }
10075
10076
        /* skip leading zeros */
10077
21.1M
        while (*p == '0')
10078
9.94M
            p++;
10079
11.1M
        n = 0;
10080
11.1M
        if (radix == 10)
10081
11.1M
            n_max = ((uint64_t)-1 - 9) / 10; /* most common case */
10082
174
        else
10083
174
            n_max = ((uint64_t)-1 - (radix - 1)) / radix;
10084
        /* XXX: could be more precise */
10085
11.1M
        int_exp = 0;
10086
12.6M
        while (*p != '\0') {
10087
1.48M
            c = to_digit((uint8_t)*p);
10088
1.48M
            if (c >= radix)
10089
0
                break;
10090
1.48M
            if (n <= n_max) {
10091
1.21M
                n = n * radix + c;
10092
1.21M
            } else {
10093
261k
                if (radix == 10)
10094
5
                    goto strtod_case;
10095
261k
                int_exp++;
10096
261k
            }
10097
1.48M
            p++;
10098
1.48M
        }
10099
11.1M
        d = n;
10100
11.1M
        if (int_exp != 0) {
10101
1
            d *= pow(radix, int_exp);
10102
1
        }
10103
11.1M
        if (is_neg)
10104
0
            d = -d;
10105
11.1M
    } else {
10106
14
    strtod_case:
10107
14
        d = strtod(str, NULL);
10108
14
    }
10109
11.1M
    return d;
10110
11.1M
}
10111
10112
12.3M
#define ATOD_INT_ONLY        (1 << 0)
10113
/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
10114
11.1M
#define ATOD_ACCEPT_BIN_OCT  (1 << 2)
10115
/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
10116
11.1M
#define ATOD_ACCEPT_LEGACY_OCTAL  (1 << 4)
10117
/* accept _ between digits as a digit separator */
10118
22.3M
#define ATOD_ACCEPT_UNDERSCORES  (1 << 5)
10119
/* allow a suffix to override the type */
10120
22.3M
#define ATOD_ACCEPT_SUFFIX    (1 << 6)
10121
/* default type */
10122
11.1M
#define ATOD_TYPE_MASK        (3 << 7)
10123
13.6M
#define ATOD_TYPE_FLOAT64     (0 << 7)
10124
2
#define ATOD_TYPE_BIG_INT     (1 << 7)
10125
#ifdef CONFIG_BIGNUM
10126
0
#define ATOD_TYPE_BIG_FLOAT   (2 << 7)
10127
0
#define ATOD_TYPE_BIG_DECIMAL (3 << 7)
10128
/* assume bigint mode: floats are parsed as integers if no decimal
10129
   point nor exponent */
10130
11.1M
#define ATOD_MODE_BIGINT      (1 << 9)
10131
#endif
10132
/* accept -0x1 */
10133
0
#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10)
10134
10135
static JSValue js_string_to_bigint(JSContext *ctx, const char *buf,
10136
                                   int radix, int flags, slimb_t *pexponent)
10137
1
{
10138
1
    bf_t a_s, *a = &a_s;
10139
1
    int ret;
10140
1
    JSValue val;
10141
1
    val = JS_NewBigInt(ctx);
10142
1
    if (JS_IsException(val))
10143
0
        return val;
10144
1
    a = JS_GetBigInt(val);
10145
1
    ret = bf_atof(a, buf, NULL, radix, BF_PREC_INF, BF_RNDZ);
10146
1
    if (ret & BF_ST_MEM_ERROR) {
10147
0
        JS_FreeValue(ctx, val);
10148
0
        return JS_ThrowOutOfMemory(ctx);
10149
0
    }
10150
1
#ifdef CONFIG_BIGNUM
10151
1
    val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0);
10152
#else
10153
    val = JS_CompactBigInt1(ctx, val, FALSE);
10154
#endif
10155
1
    return val;
10156
1
}
10157
10158
#ifdef CONFIG_BIGNUM
10159
static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf,
10160
                                     int radix, int flags, slimb_t *pexponent)
10161
0
{
10162
0
    bf_t *a;
10163
0
    int ret;
10164
0
    JSValue val;
10165
10166
0
    val = JS_NewBigFloat(ctx);
10167
0
    if (JS_IsException(val))
10168
0
        return val;
10169
0
    a = JS_GetBigFloat(val);
10170
0
    if (flags & ATOD_ACCEPT_SUFFIX) {
10171
        /* return the exponent to get infinite precision */
10172
0
        ret = bf_atof2(a, pexponent, buf, NULL, radix, BF_PREC_INF,
10173
0
                       BF_RNDZ | BF_ATOF_EXPONENT);
10174
0
    } else {
10175
0
        ret = bf_atof(a, buf, NULL, radix, ctx->fp_env.prec,
10176
0
                      ctx->fp_env.flags);
10177
0
    }
10178
0
    if (ret & BF_ST_MEM_ERROR) {
10179
0
        JS_FreeValue(ctx, val);
10180
0
        return JS_ThrowOutOfMemory(ctx);
10181
0
    }
10182
0
    return val;
10183
0
}
10184
10185
static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf,
10186
                                       int radix, int flags, slimb_t *pexponent)
10187
0
{
10188
0
    bfdec_t *a;
10189
0
    int ret;
10190
0
    JSValue val;
10191
10192
0
    val = JS_NewBigDecimal(ctx);
10193
0
    if (JS_IsException(val))
10194
0
        return val;
10195
0
    a = JS_GetBigDecimal(val);
10196
0
    ret = bfdec_atof(a, buf, NULL, BF_PREC_INF,
10197
0
                     BF_RNDZ | BF_ATOF_NO_NAN_INF);
10198
0
    if (ret & BF_ST_MEM_ERROR) {
10199
0
        JS_FreeValue(ctx, val);
10200
0
        return JS_ThrowOutOfMemory(ctx);
10201
0
    }
10202
0
    return val;
10203
0
}
10204
#endif
10205
10206
/* return an exception in case of memory error. Return JS_NAN if
10207
   invalid syntax */
10208
#ifdef CONFIG_BIGNUM
10209
static JSValue js_atof2(JSContext *ctx, const char *str, const char **pp,
10210
                        int radix, int flags, slimb_t *pexponent)
10211
#else
10212
static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
10213
                       int radix, int flags)
10214
#endif
10215
11.1M
{
10216
11.1M
    const char *p, *p_start;
10217
11.1M
    int sep, is_neg;
10218
11.1M
    BOOL is_float, has_legacy_octal;
10219
11.1M
    int atod_type = flags & ATOD_TYPE_MASK;
10220
11.1M
    char buf1[64], *buf;
10221
11.1M
    int i, j, len;
10222
11.1M
    BOOL buf_allocated = FALSE;
10223
11.1M
    JSValue val;
10224
10225
    /* optional separator between digits */
10226
11.1M
    sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;
10227
11.1M
    has_legacy_octal = FALSE;
10228
10229
11.1M
    p = str;
10230
11.1M
    p_start = p;
10231
11.1M
    is_neg = 0;
10232
11.1M
    if (p[0] == '+') {
10233
0
        p++;
10234
0
        p_start++;
10235
0
        if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
10236
0
            goto no_radix_prefix;
10237
11.1M
    } else if (p[0] == '-') {
10238
0
        p++;
10239
0
        p_start++;
10240
0
        is_neg = 1;
10241
0
        if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
10242
0
            goto no_radix_prefix;
10243
0
    }
10244
11.1M
    if (p[0] == '0') {
10245
9.94M
        if ((p[1] == 'x' || p[1] == 'X') &&
10246
9.94M
            (radix == 0 || radix == 16)) {
10247
0
            p += 2;
10248
0
            radix = 16;
10249
9.94M
        } else if ((p[1] == 'o' || p[1] == 'O') &&
10250
9.94M
                   radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
10251
0
            p += 2;
10252
0
            radix = 8;
10253
9.94M
        } else if ((p[1] == 'b' || p[1] == 'B') &&
10254
9.94M
                   radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
10255
0
            p += 2;
10256
0
            radix = 2;
10257
9.94M
        } else if ((p[1] >= '0' && p[1] <= '9') &&
10258
9.94M
                   radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) {
10259
174
            int i;
10260
174
            has_legacy_octal = TRUE;
10261
174
            sep = 256;
10262
265k
            for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++)
10263
264k
                continue;
10264
174
            if (p[i] == '8' || p[i] == '9')
10265
0
                goto no_prefix;
10266
174
            p += 1;
10267
174
            radix = 8;
10268
9.94M
        } else {
10269
9.94M
            goto no_prefix;
10270
9.94M
        }
10271
        /* there must be a digit after the prefix */
10272
174
        if (to_digit((uint8_t)*p) >= radix)
10273
0
            goto fail;
10274
9.94M
    no_prefix: ;
10275
9.94M
    } else {
10276
1.21M
 no_radix_prefix:
10277
1.21M
        if (!(flags & ATOD_INT_ONLY) &&
10278
1.21M
            (atod_type == ATOD_TYPE_FLOAT64
10279
1.21M
#ifdef CONFIG_BIGNUM
10280
1.21M
             || atod_type == ATOD_TYPE_BIG_FLOAT
10281
1.21M
#endif
10282
1.21M
             ) &&
10283
1.21M
            strstart(p, "Infinity", &p)) {
10284
0
#ifdef CONFIG_BIGNUM
10285
0
            if (atod_type == ATOD_TYPE_BIG_FLOAT) {
10286
0
                bf_t *a;
10287
0
                val = JS_NewBigFloat(ctx);
10288
0
                if (JS_IsException(val))
10289
0
                    goto done;
10290
0
                a = JS_GetBigFloat(val);
10291
0
                bf_set_inf(a, is_neg);
10292
0
            } else
10293
0
#endif
10294
0
            {
10295
0
                double d = 1.0 / 0.0;
10296
0
                if (is_neg)
10297
0
                    d = -d;
10298
0
                val = JS_NewFloat64(ctx, d);
10299
0
            }
10300
0
            goto done;
10301
0
        }
10302
1.21M
    }
10303
11.1M
    if (radix == 0)
10304
11.1M
        radix = 10;
10305
11.1M
    is_float = FALSE;
10306
11.1M
    p_start = p;
10307
24.6M
    while (to_digit((uint8_t)*p) < radix
10308
24.6M
           ||  (*p == sep && (radix != 10 ||
10309
0
                              p != p_start + 1 || p[-1] != '0') &&
10310
13.5M
                to_digit((uint8_t)p[1]) < radix)) {
10311
13.5M
        p++;
10312
13.5M
    }
10313
11.1M
    if (!(flags & ATOD_INT_ONLY)) {
10314
11.1M
        if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) {
10315
9
            is_float = TRUE;
10316
9
            p++;
10317
9
            if (*p == sep)
10318
0
                goto fail;
10319
1.06M
            while (to_digit((uint8_t)*p) < radix ||
10320
1.06M
                   (*p == sep && to_digit((uint8_t)p[1]) < radix))
10321
1.06M
                p++;
10322
9
        }
10323
11.1M
        if (p > p_start &&
10324
11.1M
            (((*p == 'e' || *p == 'E') && radix == 10) ||
10325
11.1M
             ((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) {
10326
3
            const char *p1 = p + 1;
10327
3
            is_float = TRUE;
10328
3
            if (*p1 == '+') {
10329
0
                p1++;
10330
3
            } else if (*p1 == '-') {
10331
0
                p1++;
10332
0
            }
10333
3
            if (is_digit((uint8_t)*p1)) {
10334
3
                p = p1 + 1;
10335
1.18M
                while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1])))
10336
1.18M
                    p++;
10337
3
            }
10338
3
        }
10339
11.1M
    }
10340
11.1M
    if (p == p_start)
10341
0
        goto fail;
10342
10343
11.1M
    buf = buf1;
10344
11.1M
    buf_allocated = FALSE;
10345
11.1M
    len = p - p_start;
10346
11.1M
    if (unlikely((len + 2) > sizeof(buf1))) {
10347
7
        buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */
10348
7
        if (!buf)
10349
0
            goto mem_error;
10350
7
        buf_allocated = TRUE;
10351
7
    }
10352
    /* remove the separators and the radix prefixes */
10353
11.1M
    j = 0;
10354
11.1M
    if (is_neg)
10355
0
        buf[j++] = '-';
10356
26.9M
    for (i = 0; i < len; i++) {
10357
15.7M
        if (p_start[i] != '_')
10358
15.7M
            buf[j++] = p_start[i];
10359
15.7M
    }
10360
11.1M
    buf[j] = '\0';
10361
10362
11.1M
    if (flags & ATOD_ACCEPT_SUFFIX) {
10363
11.1M
        if (*p == 'n') {
10364
1
            p++;
10365
1
            atod_type = ATOD_TYPE_BIG_INT;
10366
1
        } else
10367
11.1M
#ifdef CONFIG_BIGNUM
10368
11.1M
        if (*p == 'l') {
10369
0
            p++;
10370
0
            atod_type = ATOD_TYPE_BIG_FLOAT;
10371
11.1M
        } else if (*p == 'm') {
10372
0
            p++;
10373
0
            atod_type = ATOD_TYPE_BIG_DECIMAL;
10374
11.1M
        } else if (flags & ATOD_MODE_BIGINT) {
10375
0
            if (!is_float)
10376
0
                atod_type = ATOD_TYPE_BIG_INT;
10377
0
            if (has_legacy_octal)
10378
0
                goto fail;
10379
0
        } else
10380
11.1M
#endif
10381
11.1M
        {
10382
11.1M
            if (is_float && radix != 10)
10383
0
                goto fail;
10384
11.1M
        }
10385
11.1M
    } else {
10386
0
        if (atod_type == ATOD_TYPE_FLOAT64) {
10387
0
#ifdef CONFIG_BIGNUM
10388
0
            if (flags & ATOD_MODE_BIGINT) {
10389
0
                if (!is_float)
10390
0
                    atod_type = ATOD_TYPE_BIG_INT;
10391
0
                if (has_legacy_octal)
10392
0
                    goto fail;
10393
0
            } else
10394
0
#endif
10395
0
            {
10396
0
                if (is_float && radix != 10)
10397
0
                    goto fail;
10398
0
            }
10399
0
        }
10400
0
    }
10401
10402
11.1M
    switch(atod_type) {
10403
11.1M
    case ATOD_TYPE_FLOAT64:
10404
11.1M
        {
10405
11.1M
            double d;
10406
11.1M
            d = js_strtod(buf, radix, is_float);
10407
            /* return int or float64 */
10408
11.1M
            val = JS_NewFloat64(ctx, d);
10409
11.1M
        }
10410
11.1M
        break;
10411
1
    case ATOD_TYPE_BIG_INT:
10412
1
        if (has_legacy_octal || is_float)
10413
0
            goto fail;
10414
1
        val = ctx->rt->bigint_ops.from_string(ctx, buf, radix, flags, NULL);
10415
1
        break;
10416
0
#ifdef CONFIG_BIGNUM
10417
0
    case ATOD_TYPE_BIG_FLOAT:
10418
0
        if (has_legacy_octal)
10419
0
            goto fail;
10420
0
        val = ctx->rt->bigfloat_ops.from_string(ctx, buf, radix, flags,
10421
0
                                                pexponent);
10422
0
        break;
10423
0
    case ATOD_TYPE_BIG_DECIMAL:
10424
0
        if (radix != 10)
10425
0
            goto fail;
10426
0
        val = ctx->rt->bigdecimal_ops.from_string(ctx, buf, radix, flags, NULL);
10427
0
        break;
10428
0
#endif
10429
0
    default:
10430
0
        abort();
10431
11.1M
    }
10432
10433
11.1M
done:
10434
11.1M
    if (buf_allocated)
10435
7
        js_free_rt(ctx->rt, buf);
10436
11.1M
    if (pp)
10437
11.1M
        *pp = p;
10438
11.1M
    return val;
10439
0
 fail:
10440
0
    val = JS_NAN;
10441
0
    goto done;
10442
0
 mem_error:
10443
0
    val = JS_ThrowOutOfMemory(ctx);
10444
0
    goto done;
10445
11.1M
}
10446
10447
#ifdef CONFIG_BIGNUM
10448
static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
10449
                       int radix, int flags)
10450
0
{
10451
0
    return js_atof2(ctx, str, pp, radix, flags, NULL);
10452
0
}
10453
#endif
10454
10455
typedef enum JSToNumberHintEnum {
10456
    TON_FLAG_NUMBER,
10457
    TON_FLAG_NUMERIC,
10458
} JSToNumberHintEnum;
10459
10460
static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
10461
                                   JSToNumberHintEnum flag)
10462
0
{
10463
0
    uint32_t tag;
10464
0
    JSValue ret;
10465
10466
0
 redo:
10467
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10468
0
    switch(tag) {
10469
0
    case JS_TAG_BIG_INT:
10470
0
        if (flag != TON_FLAG_NUMERIC) {
10471
0
            JS_FreeValue(ctx, val);
10472
0
            return JS_ThrowTypeError(ctx, "cannot convert bigint to number");
10473
0
        }
10474
0
        ret = val;
10475
0
        break;
10476
0
#ifdef CONFIG_BIGNUM
10477
0
    case JS_TAG_BIG_DECIMAL:
10478
0
        if (flag != TON_FLAG_NUMERIC) {
10479
0
            JS_FreeValue(ctx, val);
10480
0
            return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number");
10481
0
        }
10482
0
        ret = val;
10483
0
        break;
10484
0
    case JS_TAG_BIG_FLOAT:
10485
0
        if (flag != TON_FLAG_NUMERIC) {
10486
0
            JS_FreeValue(ctx, val);
10487
0
            return JS_ThrowTypeError(ctx, "cannot convert bigfloat to number");
10488
0
        }
10489
0
        ret = val;
10490
0
        break;
10491
0
#endif
10492
0
    case JS_TAG_FLOAT64:
10493
0
    case JS_TAG_INT:
10494
0
    case JS_TAG_EXCEPTION:
10495
0
        ret = val;
10496
0
        break;
10497
0
    case JS_TAG_BOOL:
10498
0
    case JS_TAG_NULL:
10499
0
        ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
10500
0
        break;
10501
0
    case JS_TAG_UNDEFINED:
10502
0
        ret = JS_NAN;
10503
0
        break;
10504
0
    case JS_TAG_OBJECT:
10505
0
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
10506
0
        if (JS_IsException(val))
10507
0
            return JS_EXCEPTION;
10508
0
        goto redo;
10509
0
    case JS_TAG_STRING:
10510
0
        {
10511
0
            const char *str;
10512
0
            const char *p;
10513
0
            size_t len;
10514
10515
0
            str = JS_ToCStringLen(ctx, &len, val);
10516
0
            JS_FreeValue(ctx, val);
10517
0
            if (!str)
10518
0
                return JS_EXCEPTION;
10519
0
            p = str;
10520
0
            p += skip_spaces(p);
10521
0
            if ((p - str) == len) {
10522
0
                ret = JS_NewInt32(ctx, 0);
10523
0
            } else {
10524
0
                int flags = ATOD_ACCEPT_BIN_OCT;
10525
0
                ret = js_atof(ctx, p, &p, 0, flags);
10526
0
                if (!JS_IsException(ret)) {
10527
0
                    p += skip_spaces(p);
10528
0
                    if ((p - str) != len) {
10529
0
                        JS_FreeValue(ctx, ret);
10530
0
                        ret = JS_NAN;
10531
0
                    }
10532
0
                }
10533
0
            }
10534
0
            JS_FreeCString(ctx, str);
10535
0
        }
10536
0
        break;
10537
0
    case JS_TAG_SYMBOL:
10538
0
        JS_FreeValue(ctx, val);
10539
0
        return JS_ThrowTypeError(ctx, "cannot convert symbol to number");
10540
0
    default:
10541
0
        JS_FreeValue(ctx, val);
10542
0
        ret = JS_NAN;
10543
0
        break;
10544
0
    }
10545
0
    return ret;
10546
0
}
10547
10548
static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val)
10549
0
{
10550
0
    return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
10551
0
}
10552
10553
static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)
10554
0
{
10555
0
    return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
10556
0
}
10557
10558
static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)
10559
0
{
10560
0
    return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
10561
0
}
10562
10563
static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
10564
                                          JSValue val)
10565
0
{
10566
0
    double d;
10567
0
    uint32_t tag;
10568
10569
0
    val = JS_ToNumberFree(ctx, val);
10570
0
    if (JS_IsException(val)) {
10571
0
        *pres = JS_FLOAT64_NAN;
10572
0
        return -1;
10573
0
    }
10574
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10575
0
    switch(tag) {
10576
0
    case JS_TAG_INT:
10577
0
        d = JS_VALUE_GET_INT(val);
10578
0
        break;
10579
0
    case JS_TAG_FLOAT64:
10580
0
        d = JS_VALUE_GET_FLOAT64(val);
10581
0
        break;
10582
0
    case JS_TAG_BIG_INT:
10583
0
#ifdef CONFIG_BIGNUM
10584
0
    case JS_TAG_BIG_FLOAT:
10585
0
#endif
10586
0
        {
10587
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10588
            /* XXX: there can be a double rounding issue with some
10589
               primitives (such as JS_ToUint8ClampFree()), but it is
10590
               not critical to fix it. */
10591
0
            bf_get_float64(&p->num, &d, BF_RNDN);
10592
0
            JS_FreeValue(ctx, val);
10593
0
        }
10594
0
        break;
10595
0
    default:
10596
0
        abort();
10597
0
    }
10598
0
    *pres = d;
10599
0
    return 0;
10600
0
}
10601
10602
static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val)
10603
0
{
10604
0
    uint32_t tag;
10605
10606
0
    tag = JS_VALUE_GET_TAG(val);
10607
0
    if (tag <= JS_TAG_NULL) {
10608
0
        *pres = JS_VALUE_GET_INT(val);
10609
0
        return 0;
10610
0
    } else if (JS_TAG_IS_FLOAT64(tag)) {
10611
0
        *pres = JS_VALUE_GET_FLOAT64(val);
10612
0
        return 0;
10613
0
    } else {
10614
0
        return __JS_ToFloat64Free(ctx, pres, val);
10615
0
    }
10616
0
}
10617
10618
int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val)
10619
0
{
10620
0
    return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val));
10621
0
}
10622
10623
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
10624
0
{
10625
0
    return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
10626
0
}
10627
10628
/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
10629
static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
10630
0
{
10631
0
    uint32_t tag;
10632
0
    JSValue ret;
10633
10634
0
 redo:
10635
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10636
0
    switch(tag) {
10637
0
    case JS_TAG_INT:
10638
0
    case JS_TAG_BOOL:
10639
0
    case JS_TAG_NULL:
10640
0
    case JS_TAG_UNDEFINED:
10641
0
        ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
10642
0
        break;
10643
0
    case JS_TAG_FLOAT64:
10644
0
        {
10645
0
            double d = JS_VALUE_GET_FLOAT64(val);
10646
0
            if (isnan(d)) {
10647
0
                ret = JS_NewInt32(ctx, 0);
10648
0
            } else {
10649
                /* convert -0 to +0 */
10650
0
                d = trunc(d) + 0.0;
10651
0
                ret = JS_NewFloat64(ctx, d);
10652
0
            }
10653
0
        }
10654
0
        break;
10655
0
#ifdef CONFIG_BIGNUM
10656
0
    case JS_TAG_BIG_FLOAT:
10657
0
        {
10658
0
            bf_t a_s, *a, r_s, *r = &r_s;
10659
0
            BOOL is_nan;
10660
10661
0
            a = JS_ToBigFloat(ctx, &a_s, val);
10662
0
            if (!a) {
10663
0
                JS_FreeValue(ctx, val);
10664
0
                return JS_EXCEPTION;
10665
0
            }
10666
0
            if (!bf_is_finite(a)) {
10667
0
                is_nan = bf_is_nan(a);
10668
0
                if (is_nan)
10669
0
                    ret = JS_NewInt32(ctx, 0);
10670
0
                else
10671
0
                    ret = JS_DupValue(ctx, val);
10672
0
            } else {
10673
0
                ret = JS_NewBigInt(ctx);
10674
0
                if (!JS_IsException(ret)) {
10675
0
                    r = JS_GetBigInt(ret);
10676
0
                    bf_set(r, a);
10677
0
                    bf_rint(r, BF_RNDZ);
10678
0
                    ret = JS_CompactBigInt(ctx, ret);
10679
0
                }
10680
0
            }
10681
0
            if (a == &a_s)
10682
0
                bf_delete(a);
10683
0
            JS_FreeValue(ctx, val);
10684
0
        }
10685
0
        break;
10686
0
#endif
10687
0
    default:
10688
0
        val = JS_ToNumberFree(ctx, val);
10689
0
        if (JS_IsException(val))
10690
0
            return val;
10691
0
        goto redo;
10692
0
    }
10693
0
    return ret;
10694
0
}
10695
10696
/* Note: the integer value is satured to 32 bits */
10697
static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val)
10698
0
{
10699
0
    uint32_t tag;
10700
0
    int ret;
10701
10702
0
 redo:
10703
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10704
0
    switch(tag) {
10705
0
    case JS_TAG_INT:
10706
0
    case JS_TAG_BOOL:
10707
0
    case JS_TAG_NULL:
10708
0
    case JS_TAG_UNDEFINED:
10709
0
        ret = JS_VALUE_GET_INT(val);
10710
0
        break;
10711
0
    case JS_TAG_EXCEPTION:
10712
0
        *pres = 0;
10713
0
        return -1;
10714
0
    case JS_TAG_FLOAT64:
10715
0
        {
10716
0
            double d = JS_VALUE_GET_FLOAT64(val);
10717
0
            if (isnan(d)) {
10718
0
                ret = 0;
10719
0
            } else {
10720
0
                if (d < INT32_MIN)
10721
0
                    ret = INT32_MIN;
10722
0
                else if (d > INT32_MAX)
10723
0
                    ret = INT32_MAX;
10724
0
                else
10725
0
                    ret = (int)d;
10726
0
            }
10727
0
        }
10728
0
        break;
10729
0
#ifdef CONFIG_BIGNUM
10730
0
    case JS_TAG_BIG_FLOAT:
10731
0
        {
10732
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10733
0
            bf_get_int32(&ret, &p->num, 0);
10734
0
            JS_FreeValue(ctx, val);
10735
0
        }
10736
0
        break;
10737
0
#endif
10738
0
    default:
10739
0
        val = JS_ToNumberFree(ctx, val);
10740
0
        if (JS_IsException(val)) {
10741
0
            *pres = 0;
10742
0
            return -1;
10743
0
        }
10744
0
        goto redo;
10745
0
    }
10746
0
    *pres = ret;
10747
0
    return 0;
10748
0
}
10749
10750
int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val)
10751
0
{
10752
0
    return JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
10753
0
}
10754
10755
int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val,
10756
                    int min, int max, int min_offset)
10757
0
{
10758
0
    int res = JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
10759
0
    if (res == 0) {
10760
0
        if (*pres < min) {
10761
0
            *pres += min_offset;
10762
0
            if (*pres < min)
10763
0
                *pres = min;
10764
0
        } else {
10765
0
            if (*pres > max)
10766
0
                *pres = max;
10767
0
        }
10768
0
    }
10769
0
    return res;
10770
0
}
10771
10772
static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val)
10773
0
{
10774
0
    uint32_t tag;
10775
10776
0
 redo:
10777
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10778
0
    switch(tag) {
10779
0
    case JS_TAG_INT:
10780
0
    case JS_TAG_BOOL:
10781
0
    case JS_TAG_NULL:
10782
0
    case JS_TAG_UNDEFINED:
10783
0
        *pres = JS_VALUE_GET_INT(val);
10784
0
        return 0;
10785
0
    case JS_TAG_EXCEPTION:
10786
0
        *pres = 0;
10787
0
        return -1;
10788
0
    case JS_TAG_FLOAT64:
10789
0
        {
10790
0
            double d = JS_VALUE_GET_FLOAT64(val);
10791
0
            if (isnan(d)) {
10792
0
                *pres = 0;
10793
0
            } else {
10794
0
                if (d < INT64_MIN)
10795
0
                    *pres = INT64_MIN;
10796
0
                else if (d >= 0x1p63) /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */
10797
0
                    *pres = INT64_MAX;
10798
0
                else
10799
0
                    *pres = (int64_t)d;
10800
0
            }
10801
0
        }
10802
0
        return 0;
10803
0
#ifdef CONFIG_BIGNUM
10804
0
    case JS_TAG_BIG_FLOAT:
10805
0
        {
10806
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10807
0
            bf_get_int64(pres, &p->num, 0);
10808
0
            JS_FreeValue(ctx, val);
10809
0
        }
10810
0
        return 0;
10811
0
#endif
10812
0
    default:
10813
0
        val = JS_ToNumberFree(ctx, val);
10814
0
        if (JS_IsException(val)) {
10815
0
            *pres = 0;
10816
0
            return -1;
10817
0
        }
10818
0
        goto redo;
10819
0
    }
10820
0
}
10821
10822
int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val)
10823
0
{
10824
0
    return JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
10825
0
}
10826
10827
int JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValueConst val,
10828
                    int64_t min, int64_t max, int64_t neg_offset)
10829
0
{
10830
0
    int res = JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
10831
0
    if (res == 0) {
10832
0
        if (*pres < 0)
10833
0
            *pres += neg_offset;
10834
0
        if (*pres < min)
10835
0
            *pres = min;
10836
0
        else if (*pres > max)
10837
0
            *pres = max;
10838
0
    }
10839
0
    return res;
10840
0
}
10841
10842
/* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0)
10843
   in case of exception */
10844
static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
10845
0
{
10846
0
    uint32_t tag;
10847
0
    int64_t ret;
10848
10849
0
 redo:
10850
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10851
0
    switch(tag) {
10852
0
    case JS_TAG_INT:
10853
0
    case JS_TAG_BOOL:
10854
0
    case JS_TAG_NULL:
10855
0
    case JS_TAG_UNDEFINED:
10856
0
        ret = JS_VALUE_GET_INT(val);
10857
0
        break;
10858
0
    case JS_TAG_FLOAT64:
10859
0
        {
10860
0
            JSFloat64Union u;
10861
0
            double d;
10862
0
            int e;
10863
0
            d = JS_VALUE_GET_FLOAT64(val);
10864
0
            u.d = d;
10865
            /* we avoid doing fmod(x, 2^64) */
10866
0
            e = (u.u64 >> 52) & 0x7ff;
10867
0
            if (likely(e <= (1023 + 62))) {
10868
                /* fast case */
10869
0
                ret = (int64_t)d;
10870
0
            } else if (e <= (1023 + 62 + 53)) {
10871
0
                uint64_t v;
10872
                /* remainder modulo 2^64 */
10873
0
                v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
10874
0
                ret = v << ((e - 1023) - 52);
10875
                /* take the sign into account */
10876
0
                if (u.u64 >> 63)
10877
0
                    ret = -ret;
10878
0
            } else {
10879
0
                ret = 0; /* also handles NaN and +inf */
10880
0
            }
10881
0
        }
10882
0
        break;
10883
0
#ifdef CONFIG_BIGNUM
10884
0
    case JS_TAG_BIG_FLOAT:
10885
0
        {
10886
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10887
0
            bf_get_int64(&ret, &p->num, BF_GET_INT_MOD);
10888
0
            JS_FreeValue(ctx, val);
10889
0
        }
10890
0
        break;
10891
0
#endif
10892
0
    default:
10893
0
        val = JS_ToNumberFree(ctx, val);
10894
0
        if (JS_IsException(val)) {
10895
0
            *pres = 0;
10896
0
            return -1;
10897
0
        }
10898
0
        goto redo;
10899
0
    }
10900
0
    *pres = ret;
10901
0
    return 0;
10902
0
}
10903
10904
int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
10905
0
{
10906
0
    return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val));
10907
0
}
10908
10909
int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val)
10910
0
{
10911
0
    if (JS_IsBigInt(ctx, val))
10912
0
        return JS_ToBigInt64(ctx, pres, val);
10913
0
    else
10914
0
        return JS_ToInt64(ctx, pres, val);
10915
0
}
10916
10917
/* return (<0, 0) in case of exception */
10918
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)
10919
1.88M
{
10920
1.88M
    uint32_t tag;
10921
1.88M
    int32_t ret;
10922
10923
1.88M
 redo:
10924
1.88M
    tag = JS_VALUE_GET_NORM_TAG(val);
10925
1.88M
    switch(tag) {
10926
1.88M
    case JS_TAG_INT:
10927
1.88M
    case JS_TAG_BOOL:
10928
1.88M
    case JS_TAG_NULL:
10929
1.88M
    case JS_TAG_UNDEFINED:
10930
1.88M
        ret = JS_VALUE_GET_INT(val);
10931
1.88M
        break;
10932
0
    case JS_TAG_FLOAT64:
10933
0
        {
10934
0
            JSFloat64Union u;
10935
0
            double d;
10936
0
            int e;
10937
0
            d = JS_VALUE_GET_FLOAT64(val);
10938
0
            u.d = d;
10939
            /* we avoid doing fmod(x, 2^32) */
10940
0
            e = (u.u64 >> 52) & 0x7ff;
10941
0
            if (likely(e <= (1023 + 30))) {
10942
                /* fast case */
10943
0
                ret = (int32_t)d;
10944
0
            } else if (e <= (1023 + 30 + 53)) {
10945
0
                uint64_t v;
10946
                /* remainder modulo 2^32 */
10947
0
                v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
10948
0
                v = v << ((e - 1023) - 52 + 32);
10949
0
                ret = v >> 32;
10950
                /* take the sign into account */
10951
0
                if (u.u64 >> 63)
10952
0
                    ret = -ret;
10953
0
            } else {
10954
0
                ret = 0; /* also handles NaN and +inf */
10955
0
            }
10956
0
        }
10957
0
        break;
10958
0
#ifdef CONFIG_BIGNUM
10959
0
    case JS_TAG_BIG_FLOAT:
10960
0
        {
10961
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10962
0
            bf_get_int32(&ret, &p->num, BF_GET_INT_MOD);
10963
0
            JS_FreeValue(ctx, val);
10964
0
        }
10965
0
        break;
10966
0
#endif
10967
0
    default:
10968
0
        val = JS_ToNumberFree(ctx, val);
10969
0
        if (JS_IsException(val)) {
10970
0
            *pres = 0;
10971
0
            return -1;
10972
0
        }
10973
0
        goto redo;
10974
1.88M
    }
10975
1.88M
    *pres = ret;
10976
1.88M
    return 0;
10977
1.88M
}
10978
10979
int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val)
10980
1.88M
{
10981
1.88M
    return JS_ToInt32Free(ctx, pres, JS_DupValue(ctx, val));
10982
1.88M
}
10983
10984
static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val)
10985
0
{
10986
0
    return JS_ToInt32Free(ctx, (int32_t *)pres, val);
10987
0
}
10988
10989
static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
10990
0
{
10991
0
    uint32_t tag;
10992
0
    int res;
10993
10994
0
 redo:
10995
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10996
0
    switch(tag) {
10997
0
    case JS_TAG_INT:
10998
0
    case JS_TAG_BOOL:
10999
0
    case JS_TAG_NULL:
11000
0
    case JS_TAG_UNDEFINED:
11001
0
        res = JS_VALUE_GET_INT(val);
11002
0
#ifdef CONFIG_BIGNUM
11003
0
    int_clamp:
11004
0
#endif
11005
0
        res = max_int(0, min_int(255, res));
11006
0
        break;
11007
0
    case JS_TAG_FLOAT64:
11008
0
        {
11009
0
            double d = JS_VALUE_GET_FLOAT64(val);
11010
0
            if (isnan(d)) {
11011
0
                res = 0;
11012
0
            } else {
11013
0
                if (d < 0)
11014
0
                    res = 0;
11015
0
                else if (d > 255)
11016
0
                    res = 255;
11017
0
                else
11018
0
                    res = lrint(d);
11019
0
            }
11020
0
        }
11021
0
        break;
11022
0
#ifdef CONFIG_BIGNUM
11023
0
    case JS_TAG_BIG_FLOAT:
11024
0
        {
11025
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11026
0
            bf_t r_s, *r = &r_s;
11027
0
            bf_init(ctx->bf_ctx, r);
11028
0
            bf_set(r, &p->num);
11029
0
            bf_rint(r, BF_RNDN);
11030
0
            bf_get_int32(&res, r, 0);
11031
0
            bf_delete(r);
11032
0
            JS_FreeValue(ctx, val);
11033
0
        }
11034
0
        goto int_clamp;
11035
0
#endif
11036
0
    default:
11037
0
        val = JS_ToNumberFree(ctx, val);
11038
0
        if (JS_IsException(val)) {
11039
0
            *pres = 0;
11040
0
            return -1;
11041
0
        }
11042
0
        goto redo;
11043
0
    }
11044
0
    *pres = res;
11045
0
    return 0;
11046
0
}
11047
11048
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
11049
                                            JSValue val, BOOL is_array_ctor)
11050
0
{
11051
0
    uint32_t tag, len;
11052
11053
0
    tag = JS_VALUE_GET_TAG(val);
11054
0
    switch(tag) {
11055
0
    case JS_TAG_INT:
11056
0
    case JS_TAG_BOOL:
11057
0
    case JS_TAG_NULL:
11058
0
        {
11059
0
            int v;
11060
0
            v = JS_VALUE_GET_INT(val);
11061
0
            if (v < 0)
11062
0
                goto fail;
11063
0
            len = v;
11064
0
        }
11065
0
        break;
11066
0
    case JS_TAG_BIG_INT:
11067
0
#ifdef CONFIG_BIGNUM
11068
0
    case JS_TAG_BIG_FLOAT:
11069
0
#endif
11070
0
        {
11071
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11072
0
            bf_t a;
11073
0
            BOOL res;
11074
0
            bf_get_int32((int32_t *)&len, &p->num, BF_GET_INT_MOD);
11075
0
            bf_init(ctx->bf_ctx, &a);
11076
0
            bf_set_ui(&a, len);
11077
0
            res = bf_cmp_eq(&a, &p->num);
11078
0
            bf_delete(&a);
11079
0
            JS_FreeValue(ctx, val);
11080
0
            if (!res)
11081
0
                goto fail;
11082
0
        }
11083
0
        break;
11084
0
    default:
11085
0
        if (JS_TAG_IS_FLOAT64(tag)) {
11086
0
            double d;
11087
0
            d = JS_VALUE_GET_FLOAT64(val);
11088
0
            if (!(d >= 0 && d <= UINT32_MAX))
11089
0
                goto fail;
11090
0
            len = (uint32_t)d;
11091
0
            if (len != d)
11092
0
                goto fail;
11093
0
        } else {
11094
0
            uint32_t len1;
11095
11096
0
            if (is_array_ctor) {
11097
0
                val = JS_ToNumberFree(ctx, val);
11098
0
                if (JS_IsException(val))
11099
0
                    return -1;
11100
                /* cannot recurse because val is a number */
11101
0
                if (JS_ToArrayLengthFree(ctx, &len, val, TRUE))
11102
0
                    return -1;
11103
0
            } else {
11104
                /* legacy behavior: must do the conversion twice and compare */
11105
0
                if (JS_ToUint32(ctx, &len, val)) {
11106
0
                    JS_FreeValue(ctx, val);
11107
0
                    return -1;
11108
0
                }
11109
0
                val = JS_ToNumberFree(ctx, val);
11110
0
                if (JS_IsException(val))
11111
0
                    return -1;
11112
                /* cannot recurse because val is a number */
11113
0
                if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE))
11114
0
                    return -1;
11115
0
                if (len1 != len) {
11116
0
                fail:
11117
0
                    JS_ThrowRangeError(ctx, "invalid array length");
11118
0
                    return -1;
11119
0
                }
11120
0
            }
11121
0
        }
11122
0
        break;
11123
0
    }
11124
0
    *plen = len;
11125
0
    return 0;
11126
0
}
11127
11128
1
#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
11129
11130
static BOOL is_safe_integer(double d)
11131
0
{
11132
0
    return isfinite(d) && floor(d) == d &&
11133
0
        fabs(d) <= (double)MAX_SAFE_INTEGER;
11134
0
}
11135
11136
int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
11137
0
{
11138
0
    int64_t v;
11139
0
    if (JS_ToInt64Sat(ctx, &v, val))
11140
0
        return -1;
11141
0
    if (v < 0 || v > MAX_SAFE_INTEGER) {
11142
0
        JS_ThrowRangeError(ctx, "invalid array index");
11143
0
        *plen = 0;
11144
0
        return -1;
11145
0
    }
11146
0
    *plen = v;
11147
0
    return 0;
11148
0
}
11149
11150
/* convert a value to a length between 0 and MAX_SAFE_INTEGER.
11151
   return -1 for exception */
11152
static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
11153
                                       JSValue val)
11154
0
{
11155
0
    int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0);
11156
0
    JS_FreeValue(ctx, val);
11157
0
    return res;
11158
0
}
11159
11160
/* Note: can return an exception */
11161
static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)
11162
0
{
11163
0
    double d;
11164
0
    if (!JS_IsNumber(val))
11165
0
        return FALSE;
11166
0
    if (unlikely(JS_ToFloat64(ctx, &d, val)))
11167
0
        return -1;
11168
0
    return isfinite(d) && floor(d) == d;
11169
0
}
11170
11171
static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val)
11172
0
{
11173
0
    uint32_t tag;
11174
11175
0
    tag = JS_VALUE_GET_NORM_TAG(val);
11176
0
    switch(tag) {
11177
0
    case JS_TAG_INT:
11178
0
        {
11179
0
            int v;
11180
0
            v = JS_VALUE_GET_INT(val);
11181
0
            return (v < 0);
11182
0
        }
11183
0
    case JS_TAG_FLOAT64:
11184
0
        {
11185
0
            JSFloat64Union u;
11186
0
            u.d = JS_VALUE_GET_FLOAT64(val);
11187
0
            return (u.u64 >> 63);
11188
0
        }
11189
0
    case JS_TAG_BIG_INT:
11190
0
        {
11191
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11192
            /* Note: integer zeros are not necessarily positive */
11193
0
            return p->num.sign && !bf_is_zero(&p->num);
11194
0
        }
11195
0
#ifdef CONFIG_BIGNUM
11196
0
    case JS_TAG_BIG_FLOAT:
11197
0
        {
11198
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11199
0
            return p->num.sign;
11200
0
        }
11201
0
        break;
11202
0
    case JS_TAG_BIG_DECIMAL:
11203
0
        {
11204
0
            JSBigDecimal *p = JS_VALUE_GET_PTR(val);
11205
0
            return p->num.sign;
11206
0
        }
11207
0
        break;
11208
0
#endif
11209
0
    default:
11210
0
        return FALSE;
11211
0
    }
11212
0
}
11213
11214
static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)
11215
0
{
11216
0
    JSValue ret;
11217
0
    bf_t a_s, *a;
11218
0
    char *str;
11219
0
    int saved_sign;
11220
11221
0
    a = JS_ToBigInt(ctx, &a_s, val);
11222
0
    if (!a)
11223
0
        return JS_EXCEPTION;
11224
0
    saved_sign = a->sign;
11225
0
    if (a->expn == BF_EXP_ZERO)
11226
0
        a->sign = 0;
11227
0
    str = bf_ftoa(NULL, a, radix, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC |
11228
0
                  BF_FTOA_JS_QUIRKS);
11229
0
    a->sign = saved_sign;
11230
0
    JS_FreeBigInt(ctx, a, &a_s);
11231
0
    if (!str)
11232
0
        return JS_ThrowOutOfMemory(ctx);
11233
0
    ret = JS_NewString(ctx, str);
11234
0
    bf_free(ctx->bf_ctx, str);
11235
0
    return ret;
11236
0
}
11237
11238
static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val)
11239
0
{
11240
0
    return js_bigint_to_string1(ctx, val, 10);
11241
0
}
11242
11243
#ifdef CONFIG_BIGNUM
11244
11245
static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix,
11246
                       limb_t prec, bf_flags_t flags)
11247
0
{
11248
0
    JSValue val, ret;
11249
0
    bf_t a_s, *a;
11250
0
    char *str;
11251
0
    int saved_sign;
11252
11253
0
    val = JS_ToNumeric(ctx, val1);
11254
0
    if (JS_IsException(val))
11255
0
        return val;
11256
0
    a = JS_ToBigFloat(ctx, &a_s, val);
11257
0
    if (!a) {
11258
0
        JS_FreeValue(ctx, val);
11259
0
        return JS_EXCEPTION;
11260
0
    }
11261
0
    saved_sign = a->sign;
11262
0
    if (a->expn == BF_EXP_ZERO)
11263
0
        a->sign = 0;
11264
0
    flags |= BF_FTOA_JS_QUIRKS;
11265
0
    if ((flags & BF_FTOA_FORMAT_MASK) == BF_FTOA_FORMAT_FREE_MIN) {
11266
        /* Note: for floating point numbers with a radix which is not
11267
           a power of two, the current precision is used to compute
11268
           the number of digits. */
11269
0
        if ((radix & (radix - 1)) != 0) {
11270
0
            bf_t r_s, *r = &r_s;
11271
0
            int prec, flags1;
11272
            /* must round first */
11273
0
            if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
11274
0
                prec = ctx->fp_env.prec;
11275
0
                flags1 = ctx->fp_env.flags &
11276
0
                    (BF_FLAG_SUBNORMAL | (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT));
11277
0
            } else {
11278
0
                prec = 53;
11279
0
                flags1 = bf_set_exp_bits(11) | BF_FLAG_SUBNORMAL;
11280
0
            }
11281
0
            bf_init(ctx->bf_ctx, r);
11282
0
            bf_set(r, a);
11283
0
            bf_round(r, prec, flags1 | BF_RNDN);
11284
0
            str = bf_ftoa(NULL, r, radix, prec, flags1 | flags);
11285
0
            bf_delete(r);
11286
0
        } else {
11287
0
            str = bf_ftoa(NULL, a, radix, BF_PREC_INF, flags);
11288
0
        }
11289
0
    } else {
11290
0
        str = bf_ftoa(NULL, a, radix, prec, flags);
11291
0
    }
11292
0
    a->sign = saved_sign;
11293
0
    if (a == &a_s)
11294
0
        bf_delete(a);
11295
0
    JS_FreeValue(ctx, val);
11296
0
    if (!str)
11297
0
        return JS_ThrowOutOfMemory(ctx);
11298
0
    ret = JS_NewString(ctx, str);
11299
0
    bf_free(ctx->bf_ctx, str);
11300
0
    return ret;
11301
0
}
11302
11303
static JSValue js_bigfloat_to_string(JSContext *ctx, JSValueConst val)
11304
0
{
11305
0
    return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
11306
0
}
11307
11308
static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val,
11309
                                        limb_t prec, int flags)
11310
0
{
11311
0
    JSValue ret;
11312
0
    bfdec_t *a;
11313
0
    char *str;
11314
0
    int saved_sign;
11315
11316
0
    a = JS_ToBigDecimal(ctx, val);
11317
0
    if (!a)
11318
0
        return JS_EXCEPTION;
11319
0
    saved_sign = a->sign;
11320
0
    if (a->expn == BF_EXP_ZERO)
11321
0
        a->sign = 0;
11322
0
    str = bfdec_ftoa(NULL, a, prec, flags | BF_FTOA_JS_QUIRKS);
11323
0
    a->sign = saved_sign;
11324
0
    if (!str)
11325
0
        return JS_ThrowOutOfMemory(ctx);
11326
0
    ret = JS_NewString(ctx, str);
11327
0
    bf_free(ctx->bf_ctx, str);
11328
0
    return ret;
11329
0
}
11330
11331
static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
11332
0
{
11333
0
    return js_bigdecimal_to_string1(ctx, val, 0,
11334
0
                                    BF_RNDZ | BF_FTOA_FORMAT_FREE);
11335
0
}
11336
11337
#endif /* CONFIG_BIGNUM */
11338
11339
/* 2 <= base <= 36 */
11340
static char const digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
11341
11342
static char *i64toa(char *buf_end, int64_t n, unsigned int base)
11343
0
{
11344
0
    char *q = buf_end;
11345
0
    int digit, is_neg;
11346
11347
0
    is_neg = 0;
11348
0
    if (n < 0) {
11349
0
        is_neg = 1;
11350
0
        n = -n;
11351
0
    }
11352
0
    *--q = '\0';
11353
0
    if (base == 10) {
11354
        /* division by known base uses multiplication */
11355
0
        do {
11356
0
            digit = (uint64_t)n % 10;
11357
0
            n = (uint64_t)n / 10;
11358
0
            *--q = '0' + digit;
11359
0
        } while (n != 0);
11360
0
    } else {
11361
0
        do {
11362
0
            digit = (uint64_t)n % base;
11363
0
            n = (uint64_t)n / base;
11364
0
            *--q = digits[digit];
11365
0
        } while (n != 0);
11366
0
    }
11367
0
    if (is_neg)
11368
0
        *--q = '-';
11369
0
    return q;
11370
0
}
11371
11372
/* buf1 contains the printf result */
11373
static void js_ecvt1(double d, int n_digits, int *decpt, int *sign, char *buf,
11374
                     int rounding_mode, char *buf1, int buf1_size)
11375
0
{
11376
0
    if (rounding_mode != FE_TONEAREST)
11377
0
        fesetround(rounding_mode);
11378
0
    snprintf(buf1, buf1_size, "%+.*e", n_digits - 1, d);
11379
0
    if (rounding_mode != FE_TONEAREST)
11380
0
        fesetround(FE_TONEAREST);
11381
0
    *sign = (buf1[0] == '-');
11382
    /* mantissa */
11383
0
    buf[0] = buf1[1];
11384
0
    if (n_digits > 1)
11385
0
        memcpy(buf + 1, buf1 + 3, n_digits - 1);
11386
0
    buf[n_digits] = '\0';
11387
    /* exponent */
11388
0
    *decpt = atoi(buf1 + n_digits + 2 + (n_digits > 1)) + 1;
11389
0
}
11390
11391
/* maximum buffer size for js_dtoa */
11392
#define JS_DTOA_BUF_SIZE 128
11393
11394
/* needed because ecvt usually limits the number of digits to
11395
   17. Return the number of digits. */
11396
static int js_ecvt(double d, int n_digits, int *decpt, int *sign, char *buf,
11397
                   BOOL is_fixed)
11398
0
{
11399
0
    int rounding_mode;
11400
0
    char buf_tmp[JS_DTOA_BUF_SIZE];
11401
11402
0
    if (!is_fixed) {
11403
0
        unsigned int n_digits_min, n_digits_max;
11404
        /* find the minimum amount of digits (XXX: inefficient but simple) */
11405
0
        n_digits_min = 1;
11406
0
        n_digits_max = 17;
11407
0
        while (n_digits_min < n_digits_max) {
11408
0
            n_digits = (n_digits_min + n_digits_max) / 2;
11409
0
            js_ecvt1(d, n_digits, decpt, sign, buf, FE_TONEAREST,
11410
0
                     buf_tmp, sizeof(buf_tmp));
11411
0
            if (strtod(buf_tmp, NULL) == d) {
11412
                /* no need to keep the trailing zeros */
11413
0
                while (n_digits >= 2 && buf[n_digits - 1] == '0')
11414
0
                    n_digits--;
11415
0
                n_digits_max = n_digits;
11416
0
            } else {
11417
0
                n_digits_min = n_digits + 1;
11418
0
            }
11419
0
        }
11420
0
        n_digits = n_digits_max;
11421
0
        rounding_mode = FE_TONEAREST;
11422
0
    } else {
11423
0
        rounding_mode = FE_TONEAREST;
11424
0
#ifdef CONFIG_PRINTF_RNDN
11425
0
        {
11426
0
            char buf1[JS_DTOA_BUF_SIZE], buf2[JS_DTOA_BUF_SIZE];
11427
0
            int decpt1, sign1, decpt2, sign2;
11428
            /* The JS rounding is specified as round to nearest ties away
11429
               from zero (RNDNA), but in printf the "ties" case is not
11430
               specified (for example it is RNDN for glibc, RNDNA for
11431
               Windows), so we must round manually. */
11432
0
            js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_TONEAREST,
11433
0
                     buf_tmp, sizeof(buf_tmp));
11434
            /* XXX: could use 2 digits to reduce the average running time */
11435
0
            if (buf1[n_digits] == '5') {
11436
0
                js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_DOWNWARD,
11437
0
                         buf_tmp, sizeof(buf_tmp));
11438
0
                js_ecvt1(d, n_digits + 1, &decpt2, &sign2, buf2, FE_UPWARD,
11439
0
                         buf_tmp, sizeof(buf_tmp));
11440
0
                if (memcmp(buf1, buf2, n_digits + 1) == 0 && decpt1 == decpt2) {
11441
                    /* exact result: round away from zero */
11442
0
                    if (sign1)
11443
0
                        rounding_mode = FE_DOWNWARD;
11444
0
                    else
11445
0
                        rounding_mode = FE_UPWARD;
11446
0
                }
11447
0
            }
11448
0
        }
11449
0
#endif /* CONFIG_PRINTF_RNDN */
11450
0
    }
11451
0
    js_ecvt1(d, n_digits, decpt, sign, buf, rounding_mode,
11452
0
             buf_tmp, sizeof(buf_tmp));
11453
0
    return n_digits;
11454
0
}
11455
11456
static int js_fcvt1(char (*buf)[JS_DTOA_BUF_SIZE], double d, int n_digits,
11457
                    int rounding_mode)
11458
0
{
11459
0
    int n;
11460
0
    if (rounding_mode != FE_TONEAREST)
11461
0
        fesetround(rounding_mode);
11462
0
    n = snprintf(*buf, sizeof(*buf), "%.*f", n_digits, d);
11463
0
    if (rounding_mode != FE_TONEAREST)
11464
0
        fesetround(FE_TONEAREST);
11465
0
    assert(n < sizeof(*buf));
11466
0
    return n;
11467
0
}
11468
11469
static void js_fcvt(char (*buf)[JS_DTOA_BUF_SIZE], double d, int n_digits)
11470
0
{
11471
0
    int rounding_mode;
11472
0
    rounding_mode = FE_TONEAREST;
11473
0
#ifdef CONFIG_PRINTF_RNDN
11474
0
    {
11475
0
        int n1, n2;
11476
0
        char buf1[JS_DTOA_BUF_SIZE];
11477
0
        char buf2[JS_DTOA_BUF_SIZE];
11478
11479
        /* The JS rounding is specified as round to nearest ties away from
11480
           zero (RNDNA), but in printf the "ties" case is not specified
11481
           (for example it is RNDN for glibc, RNDNA for Windows), so we
11482
           must round manually. */
11483
0
        n1 = js_fcvt1(&buf1, d, n_digits + 1, FE_TONEAREST);
11484
0
        rounding_mode = FE_TONEAREST;
11485
        /* XXX: could use 2 digits to reduce the average running time */
11486
0
        if (buf1[n1 - 1] == '5') {
11487
0
            n1 = js_fcvt1(&buf1, d, n_digits + 1, FE_DOWNWARD);
11488
0
            n2 = js_fcvt1(&buf2, d, n_digits + 1, FE_UPWARD);
11489
0
            if (n1 == n2 && memcmp(buf1, buf2, n1) == 0) {
11490
                /* exact result: round away from zero */
11491
0
                if (buf1[0] == '-')
11492
0
                    rounding_mode = FE_DOWNWARD;
11493
0
                else
11494
0
                    rounding_mode = FE_UPWARD;
11495
0
            }
11496
0
        }
11497
0
    }
11498
0
#endif /* CONFIG_PRINTF_RNDN */
11499
0
    js_fcvt1(buf, d, n_digits, rounding_mode);
11500
0
}
11501
11502
/* radix != 10 is only supported with flags = JS_DTOA_VAR_FORMAT */
11503
/* use as many digits as necessary */
11504
0
#define JS_DTOA_VAR_FORMAT   (0 << 0)
11505
/* use n_digits significant digits (1 <= n_digits <= 101) */
11506
0
#define JS_DTOA_FIXED_FORMAT (1 << 0)
11507
/* force fractional format: [-]dd.dd with n_digits fractional digits */
11508
0
#define JS_DTOA_FRAC_FORMAT  (2 << 0)
11509
/* force exponential notation either in fixed or variable format */
11510
0
#define JS_DTOA_FORCE_EXP    (1 << 2)
11511
11512
/* XXX: slow and maybe not fully correct. Use libbf when it is fast enough.
11513
   XXX: radix != 10 is only supported for small integers
11514
*/
11515
static void js_dtoa1(char (*buf)[JS_DTOA_BUF_SIZE], double d,
11516
                     int radix, int n_digits, int flags)
11517
0
{
11518
0
    char *q;
11519
11520
0
    if (!isfinite(d)) {
11521
0
        if (isnan(d)) {
11522
0
            pstrcpy(*buf, sizeof(*buf), "NaN");
11523
0
        } else if (d < 0) {
11524
0
            pstrcpy(*buf, sizeof(*buf), "-Infinity");
11525
0
        } else {
11526
0
            pstrcpy(*buf, sizeof(*buf), "Infinity");
11527
0
        }
11528
0
    } else if (flags == JS_DTOA_VAR_FORMAT) {
11529
0
        int64_t i64;
11530
0
        char buf1[70], *ptr;
11531
0
        if (d > (double)MAX_SAFE_INTEGER || d < (double)-MAX_SAFE_INTEGER)
11532
0
            goto generic_conv;
11533
0
        i64 = (int64_t)d;
11534
0
        if (d != i64)
11535
0
            goto generic_conv;
11536
        /* fast path for integers */
11537
0
        ptr = i64toa(buf1 + sizeof(buf1), i64, radix);
11538
0
        pstrcpy(*buf, sizeof(*buf), ptr);
11539
0
    } else {
11540
0
        if (d == 0.0)
11541
0
            d = 0.0; /* convert -0 to 0 */
11542
0
        if (flags == JS_DTOA_FRAC_FORMAT) {
11543
0
            js_fcvt(buf, d, n_digits);
11544
0
        } else {
11545
0
            char buf1[JS_DTOA_BUF_SIZE];
11546
0
            int sign, decpt, k, n, i, p, n_max;
11547
0
            BOOL is_fixed;
11548
0
        generic_conv:
11549
0
            is_fixed = ((flags & 3) == JS_DTOA_FIXED_FORMAT);
11550
0
            if (is_fixed) {
11551
0
                n_max = n_digits;
11552
0
            } else {
11553
0
                n_max = 21;
11554
0
            }
11555
            /* the number has k digits (k >= 1) */
11556
0
            k = js_ecvt(d, n_digits, &decpt, &sign, buf1, is_fixed);
11557
0
            n = decpt; /* d=10^(n-k)*(buf1) i.e. d= < x.yyyy 10^(n-1) */
11558
0
            q = *buf;
11559
0
            if (sign)
11560
0
                *q++ = '-';
11561
0
            if (flags & JS_DTOA_FORCE_EXP)
11562
0
                goto force_exp;
11563
0
            if (n >= 1 && n <= n_max) {
11564
0
                if (k <= n) {
11565
0
                    memcpy(q, buf1, k);
11566
0
                    q += k;
11567
0
                    for(i = 0; i < (n - k); i++)
11568
0
                        *q++ = '0';
11569
0
                    *q = '\0';
11570
0
                } else {
11571
                    /* k > n */
11572
0
                    memcpy(q, buf1, n);
11573
0
                    q += n;
11574
0
                    *q++ = '.';
11575
0
                    for(i = 0; i < (k - n); i++)
11576
0
                        *q++ = buf1[n + i];
11577
0
                    *q = '\0';
11578
0
                }
11579
0
            } else if (n >= -5 && n <= 0) {
11580
0
                *q++ = '0';
11581
0
                *q++ = '.';
11582
0
                for(i = 0; i < -n; i++)
11583
0
                    *q++ = '0';
11584
0
                memcpy(q, buf1, k);
11585
0
                q += k;
11586
0
                *q = '\0';
11587
0
            } else {
11588
0
            force_exp:
11589
                /* exponential notation */
11590
0
                *q++ = buf1[0];
11591
0
                if (k > 1) {
11592
0
                    *q++ = '.';
11593
0
                    for(i = 1; i < k; i++)
11594
0
                        *q++ = buf1[i];
11595
0
                }
11596
0
                *q++ = 'e';
11597
0
                p = n - 1;
11598
0
                if (p >= 0)
11599
0
                    *q++ = '+';
11600
0
                snprintf(q, *buf + sizeof(*buf) - q, "%d", p);
11601
0
            }
11602
0
        }
11603
0
    }
11604
0
}
11605
11606
static JSValue js_dtoa(JSContext *ctx,
11607
                       double d, int radix, int n_digits, int flags)
11608
0
{
11609
0
    char buf[JS_DTOA_BUF_SIZE];
11610
0
    js_dtoa1(&buf, d, radix, n_digits, flags);
11611
0
    return JS_NewString(ctx, buf);
11612
0
}
11613
11614
static JSValue js_dtoa_radix(JSContext *ctx, double d, int radix)
11615
0
{
11616
0
    char buf[2200], *ptr, *ptr2;
11617
    /* d is finite */
11618
0
    int sign = d < 0;
11619
0
    int digit;
11620
0
    double frac, d0;
11621
0
    int64_t n0 = 0;
11622
0
    d = fabs(d);
11623
0
    d0 = trunc(d);
11624
0
    frac = d - d0;
11625
0
    ptr = buf + 1100;
11626
0
    *ptr = '\0';
11627
0
    if (d0 <= MAX_SAFE_INTEGER) {
11628
0
        int64_t n = n0 = (int64_t)d0;
11629
0
        while (n >= radix) {
11630
0
            digit = n % radix;
11631
0
            n = n / radix;
11632
0
            *--ptr = digits[digit];
11633
0
        }
11634
0
        *--ptr = digits[(int)n];
11635
0
    } else {
11636
        /* no decimals */
11637
0
        while (d0 >= radix) {
11638
0
            digit = fmod(d0, radix);
11639
0
            d0 = trunc(d0 / radix);
11640
0
            if (d0 >= MAX_SAFE_INTEGER)
11641
0
                digit = 0;
11642
0
            *--ptr = digits[digit];
11643
0
        }
11644
0
        *--ptr = digits[(int)d0];
11645
0
        goto done;
11646
0
    }
11647
0
    if (frac != 0) {
11648
0
        double log2_radix = log2(radix);
11649
0
        double prec = 1023 + 51;  // handle subnormals
11650
0
        ptr2 = buf + 1100;
11651
0
        *ptr2++ = '.';
11652
0
        while (frac != 0 && n0 <= MAX_SAFE_INTEGER/2 && prec > 0) {
11653
0
            frac *= radix;
11654
0
            digit = trunc(frac);
11655
0
            frac -= digit;
11656
0
            *ptr2++ = digits[digit];
11657
0
            n0 = n0 * radix + digit;
11658
0
            prec -= log2_radix;
11659
0
        }
11660
0
        *ptr2 = '\0';
11661
0
        if (frac * radix >= radix / 2) {
11662
0
            char nine = digits[radix - 1];
11663
            // round to closest
11664
0
            while (ptr2[-1] == nine)
11665
0
                *--ptr2 = '\0';
11666
0
            if (ptr2[-1] == '.') {
11667
0
                *--ptr2 = '\0';
11668
0
                while (ptr2[-1] == nine)
11669
0
                    *--ptr2 = '0';
11670
0
            }
11671
0
            if (ptr2 - 1 == ptr)
11672
0
                *--ptr = '1';
11673
0
            else
11674
0
                ptr2[-1] += 1;
11675
0
        } else {
11676
0
            while (ptr2[-1] == '0')
11677
0
                *--ptr2 = '\0';
11678
0
            if (ptr2[-1] == '.')
11679
0
                *--ptr2 = '\0';
11680
0
        }
11681
0
    }
11682
0
done:
11683
0
    ptr[-1] = '-';
11684
0
    ptr -= sign;
11685
0
    return JS_NewString(ctx, ptr);
11686
0
}
11687
11688
JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey)
11689
79
{
11690
79
    uint32_t tag;
11691
79
    const char *str;
11692
79
    char buf[32];
11693
11694
79
    tag = JS_VALUE_GET_NORM_TAG(val);
11695
79
    switch(tag) {
11696
78
    case JS_TAG_STRING:
11697
78
        return JS_DupValue(ctx, val);
11698
1
    case JS_TAG_INT:
11699
1
        snprintf(buf, sizeof(buf), "%d", JS_VALUE_GET_INT(val));
11700
1
        str = buf;
11701
1
        goto new_string;
11702
0
    case JS_TAG_BOOL:
11703
0
        return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
11704
0
                          JS_ATOM_true : JS_ATOM_false);
11705
0
    case JS_TAG_NULL:
11706
0
        return JS_AtomToString(ctx, JS_ATOM_null);
11707
0
    case JS_TAG_UNDEFINED:
11708
0
        return JS_AtomToString(ctx, JS_ATOM_undefined);
11709
0
    case JS_TAG_EXCEPTION:
11710
0
        return JS_EXCEPTION;
11711
0
    case JS_TAG_OBJECT:
11712
0
        {
11713
0
            JSValue val1, ret;
11714
0
            val1 = JS_ToPrimitive(ctx, val, HINT_STRING);
11715
0
            if (JS_IsException(val1))
11716
0
                return val1;
11717
0
            ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey);
11718
0
            JS_FreeValue(ctx, val1);
11719
0
            return ret;
11720
0
        }
11721
0
        break;
11722
0
    case JS_TAG_FUNCTION_BYTECODE:
11723
0
        str = "[function bytecode]";
11724
0
        goto new_string;
11725
0
    case JS_TAG_SYMBOL:
11726
0
        if (is_ToPropertyKey) {
11727
0
            return JS_DupValue(ctx, val);
11728
0
        } else {
11729
0
            return JS_ThrowTypeError(ctx, "cannot convert symbol to string");
11730
0
        }
11731
0
    case JS_TAG_FLOAT64:
11732
0
        return js_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0,
11733
0
                       JS_DTOA_VAR_FORMAT);
11734
0
    case JS_TAG_BIG_INT:
11735
0
        return ctx->rt->bigint_ops.to_string(ctx, val);
11736
0
#ifdef CONFIG_BIGNUM
11737
0
    case JS_TAG_BIG_FLOAT:
11738
0
        return ctx->rt->bigfloat_ops.to_string(ctx, val);
11739
0
    case JS_TAG_BIG_DECIMAL:
11740
0
        return ctx->rt->bigdecimal_ops.to_string(ctx, val);
11741
0
#endif
11742
0
    default:
11743
0
        str = "[unsupported type]";
11744
1
    new_string:
11745
1
        return JS_NewString(ctx, str);
11746
79
    }
11747
79
}
11748
11749
JSValue JS_ToString(JSContext *ctx, JSValueConst val)
11750
1
{
11751
1
    return JS_ToStringInternal(ctx, val, FALSE);
11752
1
}
11753
11754
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val)
11755
1
{
11756
1
    JSValue ret;
11757
1
    ret = JS_ToString(ctx, val);
11758
1
    JS_FreeValue(ctx, val);
11759
1
    return ret;
11760
1
}
11761
11762
static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val)
11763
0
{
11764
0
    if (JS_IsUndefined(val) || JS_IsNull(val))
11765
0
        return JS_ToStringFree(ctx, val);
11766
0
    return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL);
11767
0
}
11768
11769
JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val)
11770
78
{
11771
78
    return JS_ToStringInternal(ctx, val, TRUE);
11772
78
}
11773
11774
static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val)
11775
0
{
11776
0
    uint32_t tag = JS_VALUE_GET_TAG(val);
11777
0
    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
11778
0
        return JS_ThrowTypeError(ctx, "null or undefined are forbidden");
11779
0
    return JS_ToString(ctx, val);
11780
0
}
11781
11782
static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
11783
0
{
11784
0
    JSValue val;
11785
0
    JSString *p;
11786
0
    int i;
11787
0
    uint32_t c;
11788
0
    StringBuffer b_s, *b = &b_s;
11789
0
    char buf[16];
11790
11791
0
    val = JS_ToStringCheckObject(ctx, val1);
11792
0
    if (JS_IsException(val))
11793
0
        return val;
11794
0
    p = JS_VALUE_GET_STRING(val);
11795
11796
0
    if (string_buffer_init(ctx, b, p->len + 2))
11797
0
        goto fail;
11798
11799
0
    if (string_buffer_putc8(b, '\"'))
11800
0
        goto fail;
11801
0
    for(i = 0; i < p->len; ) {
11802
0
        c = string_getc(p, &i);
11803
0
        switch(c) {
11804
0
        case '\t':
11805
0
            c = 't';
11806
0
            goto quote;
11807
0
        case '\r':
11808
0
            c = 'r';
11809
0
            goto quote;
11810
0
        case '\n':
11811
0
            c = 'n';
11812
0
            goto quote;
11813
0
        case '\b':
11814
0
            c = 'b';
11815
0
            goto quote;
11816
0
        case '\f':
11817
0
            c = 'f';
11818
0
            goto quote;
11819
0
        case '\"':
11820
0
        case '\\':
11821
0
        quote:
11822
0
            if (string_buffer_putc8(b, '\\'))
11823
0
                goto fail;
11824
0
            if (string_buffer_putc8(b, c))
11825
0
                goto fail;
11826
0
            break;
11827
0
        default:
11828
0
            if (c < 32 || is_surrogate(c)) {
11829
0
                snprintf(buf, sizeof(buf), "\\u%04x", c);
11830
0
                if (string_buffer_puts8(b, buf))
11831
0
                    goto fail;
11832
0
            } else {
11833
0
                if (string_buffer_putc(b, c))
11834
0
                    goto fail;
11835
0
            }
11836
0
            break;
11837
0
        }
11838
0
    }
11839
0
    if (string_buffer_putc8(b, '\"'))
11840
0
        goto fail;
11841
0
    JS_FreeValue(ctx, val);
11842
0
    return string_buffer_end(b);
11843
0
 fail:
11844
0
    JS_FreeValue(ctx, val);
11845
0
    string_buffer_free(b);
11846
0
    return JS_EXCEPTION;
11847
0
}
11848
11849
static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
11850
0
{
11851
0
    printf("%14s %4s %4s %14s %10s %s\n",
11852
0
           "ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS");
11853
0
}
11854
11855
/* for debug only: dump an object without side effect */
11856
static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
11857
0
{
11858
0
    uint32_t i;
11859
0
    char atom_buf[ATOM_GET_STR_BUF_SIZE];
11860
0
    JSShape *sh;
11861
0
    JSShapeProperty *prs;
11862
0
    JSProperty *pr;
11863
0
    BOOL is_first = TRUE;
11864
0
11865
0
    /* XXX: should encode atoms with special characters */
11866
0
    sh = p->shape; /* the shape can be NULL while freeing an object */
11867
0
    printf("%14p %4d ",
11868
0
           (void *)p,
11869
0
           p->header.ref_count);
11870
0
    if (sh) {
11871
0
        printf("%3d%c %14p ",
11872
0
               sh->header.ref_count,
11873
0
               " *"[sh->is_hashed],
11874
0
               (void *)sh->proto);
11875
0
    } else {
11876
0
        printf("%3s  %14s ", "-", "-");
11877
0
    }
11878
0
    printf("%10s ",
11879
0
           JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), rt->class_array[p->class_id].class_name));
11880
0
    if (p->is_exotic && p->fast_array) {
11881
0
        printf("[ ");
11882
0
        for(i = 0; i < p->u.array.count; i++) {
11883
0
            if (i != 0)
11884
0
                printf(", ");
11885
0
            switch (p->class_id) {
11886
0
            case JS_CLASS_ARRAY:
11887
0
            case JS_CLASS_ARGUMENTS:
11888
0
                JS_DumpValueShort(rt, p->u.array.u.values[i]);
11889
0
                break;
11890
0
            case JS_CLASS_UINT8C_ARRAY:
11891
0
            case JS_CLASS_INT8_ARRAY:
11892
0
            case JS_CLASS_UINT8_ARRAY:
11893
0
            case JS_CLASS_INT16_ARRAY:
11894
0
            case JS_CLASS_UINT16_ARRAY:
11895
0
            case JS_CLASS_INT32_ARRAY:
11896
0
            case JS_CLASS_UINT32_ARRAY:
11897
0
            case JS_CLASS_BIG_INT64_ARRAY:
11898
0
            case JS_CLASS_BIG_UINT64_ARRAY:
11899
0
            case JS_CLASS_FLOAT32_ARRAY:
11900
0
            case JS_CLASS_FLOAT64_ARRAY:
11901
0
                {
11902
0
                    int size = 1 << typed_array_size_log2(p->class_id);
11903
0
                    const uint8_t *b = p->u.array.u.uint8_ptr + i * size;
11904
0
                    while (size-- > 0)
11905
0
                        printf("%02X", *b++);
11906
0
                }
11907
0
                break;
11908
0
            }
11909
0
        }
11910
0
        printf(" ] ");
11911
0
    }
11912
0
11913
0
    if (sh) {
11914
0
        printf("{ ");
11915
0
        for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
11916
0
            if (prs->atom != JS_ATOM_NULL) {
11917
0
                pr = &p->prop[i];
11918
0
                if (!is_first)
11919
0
                    printf(", ");
11920
0
                printf("%s: ",
11921
0
                       JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), prs->atom));
11922
0
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
11923
0
                    printf("[getset %p %p]", (void *)pr->u.getset.getter,
11924
0
                           (void *)pr->u.getset.setter);
11925
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
11926
0
                    printf("[varref %p]", (void *)pr->u.var_ref);
11927
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
11928
0
                    printf("[autoinit %p %d %p]",
11929
0
                           (void *)js_autoinit_get_realm(pr),
11930
0
                           js_autoinit_get_id(pr),
11931
0
                           (void *)pr->u.init.opaque);
11932
0
                } else {
11933
0
                    JS_DumpValueShort(rt, pr->u.value);
11934
0
                }
11935
0
                is_first = FALSE;
11936
0
            }
11937
0
        }
11938
0
        printf(" }");
11939
0
    }
11940
0
11941
0
    if (js_class_has_bytecode(p->class_id)) {
11942
0
        JSFunctionBytecode *b = p->u.func.function_bytecode;
11943
0
        JSVarRef **var_refs;
11944
0
        if (b->closure_var_count) {
11945
0
            var_refs = p->u.func.var_refs;
11946
0
            printf(" Closure:");
11947
0
            for(i = 0; i < b->closure_var_count; i++) {
11948
0
                printf(" ");
11949
0
                JS_DumpValueShort(rt, var_refs[i]->value);
11950
0
            }
11951
0
            if (p->u.func.home_object) {
11952
0
                printf(" HomeObject: ");
11953
0
                JS_DumpValueShort(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));
11954
0
            }
11955
0
        }
11956
0
    }
11957
0
    printf("\n");
11958
0
}
11959
11960
static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
11961
0
{
11962
0
    if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
11963
0
        JS_DumpObject(rt, (JSObject *)p);
11964
0
    } else {
11965
0
        printf("%14p %4d ",
11966
0
               (void *)p,
11967
0
               p->ref_count);
11968
0
        switch(p->gc_obj_type) {
11969
0
        case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
11970
0
            printf("[function bytecode]");
11971
0
            break;
11972
0
        case JS_GC_OBJ_TYPE_SHAPE:
11973
0
            printf("[shape]");
11974
0
            break;
11975
0
        case JS_GC_OBJ_TYPE_VAR_REF:
11976
0
            printf("[var_ref]");
11977
0
            break;
11978
0
        case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
11979
0
            printf("[async_function]");
11980
0
            break;
11981
0
        case JS_GC_OBJ_TYPE_JS_CONTEXT:
11982
0
            printf("[js_context]");
11983
0
            break;
11984
0
        default:
11985
0
            printf("[unknown %d]", p->gc_obj_type);
11986
0
            break;
11987
0
        }
11988
0
        printf("\n");
11989
0
    }
11990
0
}
11991
11992
static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
11993
                                                      JSValueConst val)
11994
0
{
11995
0
    uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
11996
0
    const char *str;
11997
0
11998
0
    switch(tag) {
11999
0
    case JS_TAG_INT:
12000
0
        printf("%d", JS_VALUE_GET_INT(val));
12001
0
        break;
12002
0
    case JS_TAG_BOOL:
12003
0
        if (JS_VALUE_GET_BOOL(val))
12004
0
            str = "true";
12005
0
        else
12006
0
            str = "false";
12007
0
        goto print_str;
12008
0
    case JS_TAG_NULL:
12009
0
        str = "null";
12010
0
        goto print_str;
12011
0
    case JS_TAG_EXCEPTION:
12012
0
        str = "exception";
12013
0
        goto print_str;
12014
0
    case JS_TAG_UNINITIALIZED:
12015
0
        str = "uninitialized";
12016
0
        goto print_str;
12017
0
    case JS_TAG_UNDEFINED:
12018
0
        str = "undefined";
12019
0
    print_str:
12020
0
        printf("%s", str);
12021
0
        break;
12022
0
    case JS_TAG_FLOAT64:
12023
0
        printf("%.14g", JS_VALUE_GET_FLOAT64(val));
12024
0
        break;
12025
0
    case JS_TAG_BIG_INT:
12026
0
        {
12027
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
12028
0
            char *str;
12029
0
            str = bf_ftoa(NULL, &p->num, 10, 0,
12030
0
                          BF_RNDZ | BF_FTOA_FORMAT_FRAC);
12031
0
            printf("%sn", str);
12032
0
            bf_realloc(&rt->bf_ctx, str, 0);
12033
0
        }
12034
0
        break;
12035
0
#ifdef CONFIG_BIGNUM
12036
0
    case JS_TAG_BIG_FLOAT:
12037
0
        {
12038
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
12039
0
            char *str;
12040
0
            str = bf_ftoa(NULL, &p->num, 16, BF_PREC_INF,
12041
0
                          BF_RNDZ | BF_FTOA_FORMAT_FREE | BF_FTOA_ADD_PREFIX);
12042
0
            printf("%sl", str);
12043
0
            bf_free(&rt->bf_ctx, str);
12044
0
        }
12045
0
        break;
12046
0
    case JS_TAG_BIG_DECIMAL:
12047
0
        {
12048
0
            JSBigDecimal *p = JS_VALUE_GET_PTR(val);
12049
0
            char *str;
12050
0
            str = bfdec_ftoa(NULL, &p->num, BF_PREC_INF,
12051
0
                             BF_RNDZ | BF_FTOA_FORMAT_FREE);
12052
0
            printf("%sm", str);
12053
0
            bf_free(&rt->bf_ctx, str);
12054
0
        }
12055
0
        break;
12056
0
#endif
12057
0
    case JS_TAG_STRING:
12058
0
        {
12059
0
            JSString *p;
12060
0
            p = JS_VALUE_GET_STRING(val);
12061
0
            JS_DumpString(rt, p);
12062
0
        }
12063
0
        break;
12064
0
    case JS_TAG_FUNCTION_BYTECODE:
12065
0
        {
12066
0
            JSFunctionBytecode *b = JS_VALUE_GET_PTR(val);
12067
0
            char buf[ATOM_GET_STR_BUF_SIZE];
12068
0
            printf("[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
12069
0
        }
12070
0
        break;
12071
0
    case JS_TAG_OBJECT:
12072
0
        {
12073
0
            JSObject *p = JS_VALUE_GET_OBJ(val);
12074
0
            JSAtom atom = rt->class_array[p->class_id].class_name;
12075
0
            char atom_buf[ATOM_GET_STR_BUF_SIZE];
12076
0
            printf("[%s %p]",
12077
0
                   JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), atom), (void *)p);
12078
0
        }
12079
0
        break;
12080
0
    case JS_TAG_SYMBOL:
12081
0
        {
12082
0
            JSAtomStruct *p = JS_VALUE_GET_PTR(val);
12083
0
            char atom_buf[ATOM_GET_STR_BUF_SIZE];
12084
0
            printf("Symbol(%s)",
12085
0
                   JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), js_get_atom_index(rt, p)));
12086
0
        }
12087
0
        break;
12088
0
    case JS_TAG_MODULE:
12089
0
        printf("[module]");
12090
0
        break;
12091
0
    default:
12092
0
        printf("[unknown tag %d]", tag);
12093
0
        break;
12094
0
    }
12095
0
}
12096
12097
static __maybe_unused void JS_DumpValue(JSContext *ctx,
12098
                                                 JSValueConst val)
12099
0
{
12100
0
    JS_DumpValueShort(ctx->rt, val);
12101
0
}
12102
12103
static __maybe_unused void JS_PrintValue(JSContext *ctx,
12104
                                                  const char *str,
12105
                                                  JSValueConst val)
12106
0
{
12107
0
    printf("%s=", str);
12108
0
    JS_DumpValueShort(ctx->rt, val);
12109
0
    printf("\n");
12110
0
}
12111
12112
/* return -1 if exception (proxy case) or TRUE/FALSE */
12113
// TODO: should take flags to make proxy resolution and exceptions optional
12114
int JS_IsArray(JSContext *ctx, JSValueConst val)
12115
0
{
12116
0
    if (js_resolve_proxy(ctx, &val, TRUE))
12117
0
        return -1;
12118
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
12119
0
        JSObject *p = JS_VALUE_GET_OBJ(val);
12120
0
        return p->class_id == JS_CLASS_ARRAY;
12121
0
    } else {
12122
0
        return FALSE;
12123
0
    }
12124
0
}
12125
12126
static double js_pow(double a, double b)
12127
0
{
12128
0
    if (unlikely(!isfinite(b)) && fabs(a) == 1) {
12129
        /* not compatible with IEEE 754 */
12130
0
        return JS_FLOAT64_NAN;
12131
0
    } else {
12132
0
        return pow(a, b);
12133
0
    }
12134
0
}
12135
12136
JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v)
12137
0
{
12138
0
    JSValue val;
12139
0
    bf_t *a;
12140
0
    val = JS_NewBigInt(ctx);
12141
0
    if (JS_IsException(val))
12142
0
        return val;
12143
0
    a = JS_GetBigInt(val);
12144
0
    if (bf_set_si(a, v)) {
12145
0
        JS_FreeValue(ctx, val);
12146
0
        return JS_ThrowOutOfMemory(ctx);
12147
0
    }
12148
0
    return val;
12149
0
}
12150
12151
JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
12152
0
{
12153
0
    if (is_math_mode(ctx) &&
12154
0
        v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
12155
0
        return JS_NewInt64(ctx, v);
12156
0
    } else {
12157
0
        return JS_NewBigInt64_1(ctx, v);
12158
0
    }
12159
0
}
12160
12161
JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
12162
0
{
12163
0
    JSValue val;
12164
0
    if (is_math_mode(ctx) && v <= MAX_SAFE_INTEGER) {
12165
0
        val = JS_NewInt64(ctx, v);
12166
0
    } else {
12167
0
        bf_t *a;
12168
0
        val = JS_NewBigInt(ctx);
12169
0
        if (JS_IsException(val))
12170
0
            return val;
12171
0
        a = JS_GetBigInt(val);
12172
0
        if (bf_set_ui(a, v)) {
12173
0
            JS_FreeValue(ctx, val);
12174
0
            return JS_ThrowOutOfMemory(ctx);
12175
0
        }
12176
0
    }
12177
0
    return val;
12178
0
}
12179
12180
/* return NaN if bad bigint literal */
12181
static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
12182
0
{
12183
0
    const char *str, *p;
12184
0
    size_t len;
12185
0
    int flags;
12186
12187
0
    str = JS_ToCStringLen(ctx, &len, val);
12188
0
    JS_FreeValue(ctx, val);
12189
0
    if (!str)
12190
0
        return JS_EXCEPTION;
12191
0
    p = str;
12192
0
    p += skip_spaces(p);
12193
0
    if ((p - str) == len) {
12194
0
        val = JS_NewBigInt64(ctx, 0);
12195
0
    } else {
12196
0
        flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
12197
0
#ifdef CONFIG_BIGNUM
12198
0
        if (is_math_mode(ctx))
12199
0
            flags |= ATOD_MODE_BIGINT;
12200
0
#endif
12201
0
        val = js_atof(ctx, p, &p, 0, flags);
12202
0
        p += skip_spaces(p);
12203
0
        if (!JS_IsException(val)) {
12204
0
            if ((p - str) != len) {
12205
0
                JS_FreeValue(ctx, val);
12206
0
                val = JS_NAN;
12207
0
            }
12208
0
        }
12209
0
    }
12210
0
    JS_FreeCString(ctx, str);
12211
0
    return val;
12212
0
}
12213
12214
static JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val)
12215
0
{
12216
0
    val = JS_StringToBigInt(ctx, val);
12217
0
    if (JS_VALUE_IS_NAN(val))
12218
0
        return JS_ThrowSyntaxError(ctx, "invalid bigint literal");
12219
0
    return val;
12220
0
}
12221
12222
/* if the returned bigfloat is allocated it is equal to
12223
   'buf'. Otherwise it is a pointer to the bigfloat in 'val'. */
12224
static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
12225
0
{
12226
0
    uint32_t tag;
12227
0
    bf_t *r;
12228
0
    JSBigFloat *p;
12229
12230
0
 redo:
12231
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12232
0
    switch(tag) {
12233
0
    case JS_TAG_INT:
12234
0
    case JS_TAG_NULL:
12235
0
    case JS_TAG_UNDEFINED:
12236
0
        if (!is_math_mode(ctx))
12237
0
            goto fail;
12238
        /* fall tru */
12239
0
    case JS_TAG_BOOL:
12240
0
        r = buf;
12241
0
        bf_init(ctx->bf_ctx, r);
12242
0
        bf_set_si(r, JS_VALUE_GET_INT(val));
12243
0
        break;
12244
0
    case JS_TAG_FLOAT64:
12245
0
        {
12246
0
            double d = JS_VALUE_GET_FLOAT64(val);
12247
0
            if (!is_math_mode(ctx))
12248
0
                goto fail;
12249
0
            if (!isfinite(d))
12250
0
                goto fail;
12251
0
            r = buf;
12252
0
            bf_init(ctx->bf_ctx, r);
12253
0
            d = trunc(d);
12254
0
            bf_set_float64(r, d);
12255
0
        }
12256
0
        break;
12257
0
    case JS_TAG_BIG_INT:
12258
0
        p = JS_VALUE_GET_PTR(val);
12259
0
        r = &p->num;
12260
0
        break;
12261
0
#ifdef CONFIG_BIGNUM
12262
0
    case JS_TAG_BIG_FLOAT:
12263
0
        if (!is_math_mode(ctx))
12264
0
            goto fail;
12265
0
        p = JS_VALUE_GET_PTR(val);
12266
0
        if (!bf_is_finite(&p->num))
12267
0
            goto fail;
12268
0
        r = buf;
12269
0
        bf_init(ctx->bf_ctx, r);
12270
0
        bf_set(r, &p->num);
12271
0
        bf_rint(r, BF_RNDZ);
12272
0
        JS_FreeValue(ctx, val);
12273
0
        break;
12274
0
#endif
12275
0
    case JS_TAG_STRING:
12276
0
        val = JS_StringToBigIntErr(ctx, val);
12277
0
        if (JS_IsException(val))
12278
0
            return NULL;
12279
0
        goto redo;
12280
0
    case JS_TAG_OBJECT:
12281
0
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
12282
0
        if (JS_IsException(val))
12283
0
            return NULL;
12284
0
        goto redo;
12285
0
    default:
12286
0
    fail:
12287
0
        JS_FreeValue(ctx, val);
12288
0
        JS_ThrowTypeError(ctx, "cannot convert to bigint");
12289
0
        return NULL;
12290
0
    }
12291
0
    return r;
12292
0
}
12293
12294
static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val)
12295
0
{
12296
0
    return JS_ToBigIntFree(ctx, buf, JS_DupValue(ctx, val));
12297
0
}
12298
12299
static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val)
12300
0
{
12301
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {
12302
0
        return val;
12303
0
    } else {
12304
0
        bf_t a_s, *a, *r;
12305
0
        int ret;
12306
0
        JSValue res;
12307
12308
0
        res = JS_NewBigInt(ctx);
12309
0
        if (JS_IsException(res))
12310
0
            return JS_EXCEPTION;
12311
0
        a = JS_ToBigIntFree(ctx, &a_s, val);
12312
0
        if (!a) {
12313
0
            JS_FreeValue(ctx, res);
12314
0
            return JS_EXCEPTION;
12315
0
        }
12316
0
        r = JS_GetBigInt(res);
12317
0
        ret = bf_set(r, a);
12318
0
        JS_FreeBigInt(ctx, a, &a_s);
12319
0
        if (ret) {
12320
0
            JS_FreeValue(ctx, res);
12321
0
            return JS_ThrowOutOfMemory(ctx);
12322
0
        }
12323
0
        return JS_CompactBigInt(ctx, res);
12324
0
    }
12325
0
}
12326
12327
/* free the bf_t allocated by JS_ToBigInt */
12328
static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf)
12329
0
{
12330
0
    if (a == buf) {
12331
0
        bf_delete(a);
12332
0
    } else {
12333
0
        JSBigFloat *p = (JSBigFloat *)((uint8_t *)a -
12334
0
                                       offsetof(JSBigFloat, num));
12335
0
        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_INT, p));
12336
0
    }
12337
0
}
12338
12339
/* XXX: merge with JS_ToInt64Free with a specific flag */
12340
static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
12341
0
{
12342
0
    bf_t a_s, *a;
12343
12344
0
    a = JS_ToBigIntFree(ctx, &a_s, val);
12345
0
    if (!a) {
12346
0
        *pres = 0;
12347
0
        return -1;
12348
0
    }
12349
0
    bf_get_int64(pres, a, BF_GET_INT_MOD);
12350
0
    JS_FreeBigInt(ctx, a, &a_s);
12351
0
    return 0;
12352
0
}
12353
12354
int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
12355
0
{
12356
0
    return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val));
12357
0
}
12358
12359
static JSBigFloat *js_new_bf(JSContext *ctx)
12360
0
{
12361
0
    JSBigFloat *p;
12362
0
    p = js_malloc(ctx, sizeof(*p));
12363
0
    if (!p)
12364
0
        return NULL;
12365
0
    p->header.ref_count = 1;
12366
0
    bf_init(ctx->bf_ctx, &p->num);
12367
0
    return p;
12368
0
}
12369
12370
static JSValue JS_NewBigInt(JSContext *ctx)
12371
1
{
12372
1
    JSBigFloat *p;
12373
1
    p = js_malloc(ctx, sizeof(*p));
12374
1
    if (!p)
12375
0
        return JS_EXCEPTION;
12376
1
    p->header.ref_count = 1;
12377
1
    bf_init(ctx->bf_ctx, &p->num);
12378
1
    return JS_MKPTR(JS_TAG_BIG_INT, p);
12379
1
}
12380
12381
static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
12382
                                 BOOL convert_to_safe_integer)
12383
1
{
12384
1
    int64_t v;
12385
1
    bf_t *a;
12386
12387
1
    if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT)
12388
0
        return val; /* fail safe */
12389
1
    a = JS_GetBigInt(val);
12390
1
    if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 &&
12391
1
        v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
12392
0
        JS_FreeValue(ctx, val);
12393
0
        return JS_NewInt64(ctx, v);
12394
1
    } else if (a->expn == BF_EXP_ZERO && a->sign) {
12395
0
        JSBigFloat *p = JS_VALUE_GET_PTR(val);
12396
0
        assert(p->header.ref_count == 1);
12397
0
        a->sign = 0;
12398
0
    }
12399
1
    return val;
12400
1
}
12401
12402
/* Convert the big int to a safe integer if in math mode. normalize
12403
   the zero representation. Could also be used to convert the bigint
12404
   to a short bigint value. The reference count of the value must be
12405
   1. Cannot fail */
12406
static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
12407
0
{
12408
0
    return JS_CompactBigInt1(ctx, val, is_math_mode(ctx));
12409
0
}
12410
12411
static JSValue throw_bf_exception(JSContext *ctx, int status)
12412
0
{
12413
0
    const char *str;
12414
0
    if (status & BF_ST_MEM_ERROR)
12415
0
        return JS_ThrowOutOfMemory(ctx);
12416
0
    if (status & BF_ST_DIVIDE_ZERO) {
12417
0
        str = "division by zero";
12418
0
    } else if (status & BF_ST_INVALID_OP) {
12419
0
        str = "invalid operation";
12420
0
    } else {
12421
0
        str = "integer overflow";
12422
0
    }
12423
0
    return JS_ThrowRangeError(ctx, "%s", str);
12424
0
}
12425
12426
/* if the returned bigfloat is allocated it is equal to
12427
   'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return
12428
   NULL in case of error. */
12429
static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val)
12430
0
{
12431
0
    uint32_t tag;
12432
0
    bf_t *r;
12433
0
    JSBigFloat *p;
12434
12435
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12436
0
    switch(tag) {
12437
0
    case JS_TAG_INT:
12438
0
    case JS_TAG_BOOL:
12439
0
    case JS_TAG_NULL:
12440
0
        r = buf;
12441
0
        bf_init(ctx->bf_ctx, r);
12442
0
        if (bf_set_si(r, JS_VALUE_GET_INT(val)))
12443
0
            goto fail;
12444
0
        break;
12445
0
    case JS_TAG_FLOAT64:
12446
0
        r = buf;
12447
0
        bf_init(ctx->bf_ctx, r);
12448
0
        if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) {
12449
0
        fail:
12450
0
            bf_delete(r);
12451
0
            return NULL;
12452
0
        }
12453
0
        break;
12454
0
    case JS_TAG_BIG_INT:
12455
0
#ifdef CONFIG_BIGNUM
12456
0
    case JS_TAG_BIG_FLOAT:
12457
0
#endif
12458
0
        p = JS_VALUE_GET_PTR(val);
12459
0
        r = &p->num;
12460
0
        break;
12461
0
    case JS_TAG_UNDEFINED:
12462
0
    default:
12463
0
        r = buf;
12464
0
        bf_init(ctx->bf_ctx, r);
12465
0
        bf_set_nan(r);
12466
0
        break;
12467
0
    }
12468
0
    return r;
12469
0
}
12470
12471
#ifdef CONFIG_BIGNUM
12472
/* return NULL if invalid type */
12473
static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val)
12474
0
{
12475
0
    uint32_t tag;
12476
0
    JSBigDecimal *p;
12477
0
    bfdec_t *r;
12478
12479
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12480
0
    switch(tag) {
12481
0
    case JS_TAG_BIG_DECIMAL:
12482
0
        p = JS_VALUE_GET_PTR(val);
12483
0
        r = &p->num;
12484
0
        break;
12485
0
    default:
12486
0
        JS_ThrowTypeError(ctx, "bigdecimal expected");
12487
0
        r = NULL;
12488
0
        break;
12489
0
    }
12490
0
    return r;
12491
0
}
12492
12493
static JSValue JS_NewBigFloat(JSContext *ctx)
12494
0
{
12495
0
    JSBigFloat *p;
12496
0
    p = js_malloc(ctx, sizeof(*p));
12497
0
    if (!p)
12498
0
        return JS_EXCEPTION;
12499
0
    p->header.ref_count = 1;
12500
0
    bf_init(ctx->bf_ctx, &p->num);
12501
0
    return JS_MKPTR(JS_TAG_BIG_FLOAT, p);
12502
0
}
12503
12504
static JSValue JS_NewBigDecimal(JSContext *ctx)
12505
0
{
12506
0
    JSBigDecimal *p;
12507
0
    p = js_malloc(ctx, sizeof(*p));
12508
0
    if (!p)
12509
0
        return JS_EXCEPTION;
12510
0
    p->header.ref_count = 1;
12511
0
    bfdec_init(ctx->bf_ctx, &p->num);
12512
0
    return JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
12513
0
}
12514
12515
/* must be kept in sync with JSOverloadableOperatorEnum */
12516
/* XXX: use atoms ? */
12517
static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = {
12518
    "+",
12519
    "-",
12520
    "*",
12521
    "/",
12522
    "%",
12523
    "**",
12524
    "|",
12525
    "&",
12526
    "^",
12527
    "<<",
12528
    ">>",
12529
    ">>>",
12530
    "==",
12531
    "<",
12532
    "pos",
12533
    "neg",
12534
    "++",
12535
    "--",
12536
    "~",
12537
};
12538
12539
static int get_ovop_from_opcode(OPCodeEnum op)
12540
0
{
12541
0
    switch(op) {
12542
0
    case OP_add:
12543
0
        return JS_OVOP_ADD;
12544
0
    case OP_sub:
12545
0
        return JS_OVOP_SUB;
12546
0
    case OP_mul:
12547
0
        return JS_OVOP_MUL;
12548
0
    case OP_div:
12549
0
        return JS_OVOP_DIV;
12550
0
    case OP_mod:
12551
0
    case OP_math_mod:
12552
0
        return JS_OVOP_MOD;
12553
0
    case OP_pow:
12554
0
        return JS_OVOP_POW;
12555
0
    case OP_or:
12556
0
        return JS_OVOP_OR;
12557
0
    case OP_and:
12558
0
        return JS_OVOP_AND;
12559
0
    case OP_xor:
12560
0
        return JS_OVOP_XOR;
12561
0
    case OP_shl:
12562
0
        return JS_OVOP_SHL;
12563
0
    case OP_sar:
12564
0
        return JS_OVOP_SAR;
12565
0
    case OP_shr:
12566
0
        return JS_OVOP_SHR;
12567
0
    case OP_eq:
12568
0
    case OP_neq:
12569
0
        return JS_OVOP_EQ;
12570
0
    case OP_lt:
12571
0
    case OP_lte:
12572
0
    case OP_gt:
12573
0
    case OP_gte:
12574
0
        return JS_OVOP_LESS;
12575
0
    case OP_plus:
12576
0
        return JS_OVOP_POS;
12577
0
    case OP_neg:
12578
0
        return JS_OVOP_NEG;
12579
0
    case OP_inc:
12580
0
        return JS_OVOP_INC;
12581
0
    case OP_dec:
12582
0
        return JS_OVOP_DEC;
12583
0
    default:
12584
0
        abort();
12585
0
    }
12586
0
}
12587
12588
/* return NULL if not present */
12589
static JSObject *find_binary_op(JSBinaryOperatorDef *def,
12590
                                uint32_t operator_index,
12591
                                JSOverloadableOperatorEnum op)
12592
0
{
12593
0
    JSBinaryOperatorDefEntry *ent;
12594
0
    int i;
12595
0
    for(i = 0; i < def->count; i++) {
12596
0
        ent = &def->tab[i];
12597
0
        if (ent->operator_index == operator_index)
12598
0
            return ent->ops[op];
12599
0
    }
12600
0
    return NULL;
12601
0
}
12602
12603
/* return -1 if exception, 0 if no operator overloading, 1 if
12604
   overloaded operator called */
12605
static __exception int js_call_binary_op_fallback(JSContext *ctx,
12606
                                                  JSValue *pret,
12607
                                                  JSValueConst op1,
12608
                                                  JSValueConst op2,
12609
                                                  OPCodeEnum op,
12610
                                                  BOOL is_numeric,
12611
                                                  int hint)
12612
0
{
12613
0
    JSValue opset1_obj, opset2_obj, method, ret, new_op1, new_op2;
12614
0
    JSOperatorSetData *opset1, *opset2;
12615
0
    JSOverloadableOperatorEnum ovop;
12616
0
    JSObject *p;
12617
0
    JSValueConst args[2];
12618
12619
0
    if (!ctx->allow_operator_overloading)
12620
0
        return 0;
12621
12622
0
    opset2_obj = JS_UNDEFINED;
12623
0
    opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
12624
0
    if (JS_IsException(opset1_obj))
12625
0
        goto exception;
12626
0
    if (JS_IsUndefined(opset1_obj))
12627
0
        return 0;
12628
0
    opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
12629
0
    if (!opset1)
12630
0
        goto exception;
12631
12632
0
    opset2_obj = JS_GetProperty(ctx, op2, JS_ATOM_Symbol_operatorSet);
12633
0
    if (JS_IsException(opset2_obj))
12634
0
        goto exception;
12635
0
    if (JS_IsUndefined(opset2_obj)) {
12636
0
        JS_FreeValue(ctx, opset1_obj);
12637
0
        return 0;
12638
0
    }
12639
0
    opset2 = JS_GetOpaque2(ctx, opset2_obj, JS_CLASS_OPERATOR_SET);
12640
0
    if (!opset2)
12641
0
        goto exception;
12642
12643
0
    if (opset1->is_primitive && opset2->is_primitive) {
12644
0
        JS_FreeValue(ctx, opset1_obj);
12645
0
        JS_FreeValue(ctx, opset2_obj);
12646
0
        return 0;
12647
0
    }
12648
12649
0
    ovop = get_ovop_from_opcode(op);
12650
12651
0
    if (opset1->operator_counter == opset2->operator_counter) {
12652
0
        p = opset1->self_ops[ovop];
12653
0
    } else if (opset1->operator_counter > opset2->operator_counter) {
12654
0
        p = find_binary_op(&opset1->left, opset2->operator_counter, ovop);
12655
0
    } else {
12656
0
        p = find_binary_op(&opset2->right, opset1->operator_counter, ovop);
12657
0
    }
12658
0
    if (!p) {
12659
0
        JS_ThrowTypeError(ctx, "operator %s: no function defined",
12660
0
                          js_overloadable_operator_names[ovop]);
12661
0
        goto exception;
12662
0
    }
12663
12664
0
    if (opset1->is_primitive) {
12665
0
        if (is_numeric) {
12666
0
            new_op1 = JS_ToNumeric(ctx, op1);
12667
0
        } else {
12668
0
            new_op1 = JS_ToPrimitive(ctx, op1, hint);
12669
0
        }
12670
0
        if (JS_IsException(new_op1))
12671
0
            goto exception;
12672
0
    } else {
12673
0
        new_op1 = JS_DupValue(ctx, op1);
12674
0
    }
12675
12676
0
    if (opset2->is_primitive) {
12677
0
        if (is_numeric) {
12678
0
            new_op2 = JS_ToNumeric(ctx, op2);
12679
0
        } else {
12680
0
            new_op2 = JS_ToPrimitive(ctx, op2, hint);
12681
0
        }
12682
0
        if (JS_IsException(new_op2)) {
12683
0
            JS_FreeValue(ctx, new_op1);
12684
0
            goto exception;
12685
0
        }
12686
0
    } else {
12687
0
        new_op2 = JS_DupValue(ctx, op2);
12688
0
    }
12689
12690
    /* XXX: could apply JS_ToPrimitive() if primitive type so that the
12691
       operator function does not get a value object */
12692
12693
0
    method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12694
0
    if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) {
12695
0
        args[0] = new_op2;
12696
0
        args[1] = new_op1;
12697
0
    } else {
12698
0
        args[0] = new_op1;
12699
0
        args[1] = new_op2;
12700
0
    }
12701
0
    ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
12702
0
    JS_FreeValue(ctx, new_op1);
12703
0
    JS_FreeValue(ctx, new_op2);
12704
0
    if (JS_IsException(ret))
12705
0
        goto exception;
12706
0
    if (ovop == JS_OVOP_EQ) {
12707
0
        BOOL res = JS_ToBoolFree(ctx, ret);
12708
0
        if (op == OP_neq)
12709
0
            res ^= 1;
12710
0
        ret = JS_NewBool(ctx, res);
12711
0
    } else if (ovop == JS_OVOP_LESS) {
12712
0
        if (JS_IsUndefined(ret)) {
12713
0
            ret = JS_FALSE;
12714
0
        } else {
12715
0
            BOOL res = JS_ToBoolFree(ctx, ret);
12716
0
            if (op == OP_lte || op == OP_gte)
12717
0
                res ^= 1;
12718
0
            ret = JS_NewBool(ctx, res);
12719
0
        }
12720
0
    }
12721
0
    JS_FreeValue(ctx, opset1_obj);
12722
0
    JS_FreeValue(ctx, opset2_obj);
12723
0
    *pret = ret;
12724
0
    return 1;
12725
0
 exception:
12726
0
    JS_FreeValue(ctx, opset1_obj);
12727
0
    JS_FreeValue(ctx, opset2_obj);
12728
0
    *pret = JS_UNDEFINED;
12729
0
    return -1;
12730
0
}
12731
12732
/* try to call the operation on the operatorSet field of 'obj'. Only
12733
   used for "/" and "**" on the BigInt prototype in math mode */
12734
static __exception int js_call_binary_op_simple(JSContext *ctx,
12735
                                                JSValue *pret,
12736
                                                JSValueConst obj,
12737
                                                JSValueConst op1,
12738
                                                JSValueConst op2,
12739
                                                OPCodeEnum op)
12740
0
{
12741
0
    JSValue opset1_obj, method, ret, new_op1, new_op2;
12742
0
    JSOperatorSetData *opset1;
12743
0
    JSOverloadableOperatorEnum ovop;
12744
0
    JSObject *p;
12745
0
    JSValueConst args[2];
12746
12747
0
    opset1_obj = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
12748
0
    if (JS_IsException(opset1_obj))
12749
0
        goto exception;
12750
0
    if (JS_IsUndefined(opset1_obj))
12751
0
        return 0;
12752
0
    opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
12753
0
    if (!opset1)
12754
0
        goto exception;
12755
0
    ovop = get_ovop_from_opcode(op);
12756
12757
0
    p = opset1->self_ops[ovop];
12758
0
    if (!p) {
12759
0
        JS_FreeValue(ctx, opset1_obj);
12760
0
        return 0;
12761
0
    }
12762
12763
0
    new_op1 = JS_ToNumeric(ctx, op1);
12764
0
    if (JS_IsException(new_op1))
12765
0
        goto exception;
12766
0
    new_op2 = JS_ToNumeric(ctx, op2);
12767
0
    if (JS_IsException(new_op2)) {
12768
0
        JS_FreeValue(ctx, new_op1);
12769
0
        goto exception;
12770
0
    }
12771
12772
0
    method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12773
0
    args[0] = new_op1;
12774
0
    args[1] = new_op2;
12775
0
    ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
12776
0
    JS_FreeValue(ctx, new_op1);
12777
0
    JS_FreeValue(ctx, new_op2);
12778
0
    if (JS_IsException(ret))
12779
0
        goto exception;
12780
0
    JS_FreeValue(ctx, opset1_obj);
12781
0
    *pret = ret;
12782
0
    return 1;
12783
0
 exception:
12784
0
    JS_FreeValue(ctx, opset1_obj);
12785
0
    *pret = JS_UNDEFINED;
12786
0
    return -1;
12787
0
}
12788
12789
/* return -1 if exception, 0 if no operator overloading, 1 if
12790
   overloaded operator called */
12791
static __exception int js_call_unary_op_fallback(JSContext *ctx,
12792
                                                 JSValue *pret,
12793
                                                 JSValueConst op1,
12794
                                                 OPCodeEnum op)
12795
0
{
12796
0
    JSValue opset1_obj, method, ret;
12797
0
    JSOperatorSetData *opset1;
12798
0
    JSOverloadableOperatorEnum ovop;
12799
0
    JSObject *p;
12800
12801
0
    if (!ctx->allow_operator_overloading)
12802
0
        return 0;
12803
12804
0
    opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
12805
0
    if (JS_IsException(opset1_obj))
12806
0
        goto exception;
12807
0
    if (JS_IsUndefined(opset1_obj))
12808
0
        return 0;
12809
0
    opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
12810
0
    if (!opset1)
12811
0
        goto exception;
12812
0
    if (opset1->is_primitive) {
12813
0
        JS_FreeValue(ctx, opset1_obj);
12814
0
        return 0;
12815
0
    }
12816
12817
0
    ovop = get_ovop_from_opcode(op);
12818
12819
0
    p = opset1->self_ops[ovop];
12820
0
    if (!p) {
12821
0
        JS_ThrowTypeError(ctx, "no overloaded operator %s",
12822
0
                          js_overloadable_operator_names[ovop]);
12823
0
        goto exception;
12824
0
    }
12825
0
    method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12826
0
    ret = JS_CallFree(ctx, method, JS_UNDEFINED, 1, &op1);
12827
0
    if (JS_IsException(ret))
12828
0
        goto exception;
12829
0
    JS_FreeValue(ctx, opset1_obj);
12830
0
    *pret = ret;
12831
0
    return 1;
12832
0
 exception:
12833
0
    JS_FreeValue(ctx, opset1_obj);
12834
0
    *pret = JS_UNDEFINED;
12835
0
    return -1;
12836
0
}
12837
12838
static int js_unary_arith_bigfloat(JSContext *ctx,
12839
                                   JSValue *pres, OPCodeEnum op, JSValue op1)
12840
0
{
12841
0
    bf_t a_s, *r, *a;
12842
0
    int ret, v;
12843
0
    JSValue res;
12844
12845
0
    if (op == OP_plus && !is_math_mode(ctx)) {
12846
0
        JS_ThrowTypeError(ctx, "bigfloat argument with unary +");
12847
0
        JS_FreeValue(ctx, op1);
12848
0
        return -1;
12849
0
    }
12850
12851
0
    res = JS_NewBigFloat(ctx);
12852
0
    if (JS_IsException(res)) {
12853
0
        JS_FreeValue(ctx, op1);
12854
0
        return -1;
12855
0
    }
12856
0
    r = JS_GetBigFloat(res);
12857
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
12858
0
    if (!a) {
12859
0
        JS_FreeValue(ctx, res);
12860
0
        JS_FreeValue(ctx, op1);
12861
0
        return -1;
12862
0
    }
12863
0
    ret = 0;
12864
0
    switch(op) {
12865
0
    case OP_inc:
12866
0
    case OP_dec:
12867
0
        v = 2 * (op - OP_dec) - 1;
12868
0
        ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags);
12869
0
        break;
12870
0
    case OP_plus:
12871
0
        ret = bf_set(r, a);
12872
0
        break;
12873
0
    case OP_neg:
12874
0
        ret = bf_set(r, a);
12875
0
        bf_neg(r);
12876
0
        break;
12877
0
    default:
12878
0
        abort();
12879
0
    }
12880
0
    if (a == &a_s)
12881
0
        bf_delete(a);
12882
0
    JS_FreeValue(ctx, op1);
12883
0
    if (unlikely(ret & BF_ST_MEM_ERROR)) {
12884
0
        JS_FreeValue(ctx, res);
12885
0
        throw_bf_exception(ctx, ret);
12886
0
        return -1;
12887
0
    }
12888
0
    *pres = res;
12889
0
    return 0;
12890
0
}
12891
12892
static int js_unary_arith_bigdecimal(JSContext *ctx,
12893
                                     JSValue *pres, OPCodeEnum op, JSValue op1)
12894
0
{
12895
0
    bfdec_t *r, *a;
12896
0
    int ret, v;
12897
0
    JSValue res;
12898
12899
0
    if (op == OP_plus && !is_math_mode(ctx)) {
12900
0
        JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");
12901
0
        JS_FreeValue(ctx, op1);
12902
0
        return -1;
12903
0
    }
12904
12905
0
    res = JS_NewBigDecimal(ctx);
12906
0
    if (JS_IsException(res)) {
12907
0
        JS_FreeValue(ctx, op1);
12908
0
        return -1;
12909
0
    }
12910
0
    r = JS_GetBigDecimal(res);
12911
0
    a = JS_ToBigDecimal(ctx, op1);
12912
0
    if (!a) {
12913
0
        JS_FreeValue(ctx, res);
12914
0
        JS_FreeValue(ctx, op1);
12915
0
        return -1;
12916
0
    }
12917
0
    ret = 0;
12918
0
    switch(op) {
12919
0
    case OP_inc:
12920
0
    case OP_dec:
12921
0
        v = 2 * (op - OP_dec) - 1;
12922
0
        ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
12923
0
        break;
12924
0
    case OP_plus:
12925
0
        ret = bfdec_set(r, a);
12926
0
        break;
12927
0
    case OP_neg:
12928
0
        ret = bfdec_set(r, a);
12929
0
        bfdec_neg(r);
12930
0
        break;
12931
0
    default:
12932
0
        abort();
12933
0
    }
12934
0
    JS_FreeValue(ctx, op1);
12935
0
    if (unlikely(ret)) {
12936
0
        JS_FreeValue(ctx, res);
12937
0
        throw_bf_exception(ctx, ret);
12938
0
        return -1;
12939
0
    }
12940
0
    *pres = res;
12941
0
    return 0;
12942
0
}
12943
12944
#endif /* CONFIG_BIGNUM */
12945
12946
static int js_unary_arith_bigint(JSContext *ctx,
12947
                                 JSValue *pres, OPCodeEnum op, JSValue op1)
12948
0
{
12949
0
    bf_t a_s, *r, *a;
12950
0
    int ret, v;
12951
0
    JSValue res;
12952
12953
0
    if (op == OP_plus && !is_math_mode(ctx)) {
12954
0
        JS_ThrowTypeError(ctx, "bigint argument with unary +");
12955
0
        JS_FreeValue(ctx, op1);
12956
0
        return -1;
12957
0
    }
12958
0
    res = JS_NewBigInt(ctx);
12959
0
    if (JS_IsException(res)) {
12960
0
        JS_FreeValue(ctx, op1);
12961
0
        return -1;
12962
0
    }
12963
0
    r = JS_GetBigInt(res);
12964
0
    a = JS_ToBigInt(ctx, &a_s, op1);
12965
0
    if (!a) {
12966
0
        JS_FreeValue(ctx, res);
12967
0
        JS_FreeValue(ctx, op1);
12968
0
        return -1;
12969
0
    }
12970
0
    ret = 0;
12971
0
    switch(op) {
12972
0
    case OP_inc:
12973
0
    case OP_dec:
12974
0
        v = 2 * (op - OP_dec) - 1;
12975
0
        ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
12976
0
        break;
12977
0
    case OP_plus:
12978
0
        ret = bf_set(r, a);
12979
0
        break;
12980
0
    case OP_neg:
12981
0
        ret = bf_set(r, a);
12982
0
        bf_neg(r);
12983
0
        break;
12984
0
    case OP_not:
12985
0
        ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ);
12986
0
        bf_neg(r);
12987
0
        break;
12988
0
    default:
12989
0
        abort();
12990
0
    }
12991
0
    JS_FreeBigInt(ctx, a, &a_s);
12992
0
    JS_FreeValue(ctx, op1);
12993
0
    if (unlikely(ret)) {
12994
0
        JS_FreeValue(ctx, res);
12995
0
        throw_bf_exception(ctx, ret);
12996
0
        return -1;
12997
0
    }
12998
0
    res = JS_CompactBigInt(ctx, res);
12999
0
    *pres = res;
13000
0
    return 0;
13001
0
}
13002
13003
static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
13004
                                                     JSValue *sp,
13005
                                                     OPCodeEnum op)
13006
0
{
13007
0
    JSValue op1;
13008
0
    int v;
13009
0
    uint32_t tag;
13010
13011
0
    op1 = sp[-1];
13012
    /* fast path for float64 */
13013
0
    if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
13014
0
        goto handle_float64;
13015
0
#ifdef CONFIG_BIGNUM
13016
0
    if (JS_IsObject(op1)) {
13017
0
        JSValue val;
13018
0
        int ret = js_call_unary_op_fallback(ctx, &val, op1, op);
13019
0
        if (ret < 0)
13020
0
            return -1;
13021
0
        if (ret) {
13022
0
            JS_FreeValue(ctx, op1);
13023
0
            sp[-1] = val;
13024
0
            return 0;
13025
0
        }
13026
0
    }
13027
0
#endif
13028
0
    op1 = JS_ToNumericFree(ctx, op1);
13029
0
    if (JS_IsException(op1))
13030
0
        goto exception;
13031
0
    tag = JS_VALUE_GET_TAG(op1);
13032
0
    switch(tag) {
13033
0
    case JS_TAG_INT:
13034
0
        {
13035
0
            int64_t v64;
13036
0
            v64 = JS_VALUE_GET_INT(op1);
13037
0
            switch(op) {
13038
0
            case OP_inc:
13039
0
            case OP_dec:
13040
0
                v = 2 * (op - OP_dec) - 1;
13041
0
                v64 += v;
13042
0
                break;
13043
0
            case OP_plus:
13044
0
                break;
13045
0
            case OP_neg:
13046
0
                if (v64 == 0) {
13047
0
                    sp[-1] = __JS_NewFloat64(ctx, -0.0);
13048
0
                    return 0;
13049
0
                } else {
13050
0
                    v64 = -v64;
13051
0
                }
13052
0
                break;
13053
0
            default:
13054
0
                abort();
13055
0
            }
13056
0
            sp[-1] = JS_NewInt64(ctx, v64);
13057
0
        }
13058
0
        break;
13059
0
    case JS_TAG_BIG_INT:
13060
0
    handle_bigint:
13061
0
        if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1))
13062
0
            goto exception;
13063
0
        break;
13064
0
#ifdef CONFIG_BIGNUM
13065
0
    case JS_TAG_BIG_FLOAT:
13066
0
        if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1))
13067
0
            goto exception;
13068
0
        break;
13069
0
    case JS_TAG_BIG_DECIMAL:
13070
0
        if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1))
13071
0
            goto exception;
13072
0
        break;
13073
0
#endif
13074
0
    default:
13075
0
    handle_float64:
13076
0
        {
13077
0
            double d;
13078
0
            if (is_math_mode(ctx))
13079
0
                goto handle_bigint;
13080
0
            d = JS_VALUE_GET_FLOAT64(op1);
13081
0
            switch(op) {
13082
0
            case OP_inc:
13083
0
            case OP_dec:
13084
0
                v = 2 * (op - OP_dec) - 1;
13085
0
                d += v;
13086
0
                break;
13087
0
            case OP_plus:
13088
0
                break;
13089
0
            case OP_neg:
13090
0
                d = -d;
13091
0
                break;
13092
0
            default:
13093
0
                abort();
13094
0
            }
13095
0
            sp[-1] = __JS_NewFloat64(ctx, d);
13096
0
        }
13097
0
        break;
13098
0
    }
13099
0
    return 0;
13100
0
 exception:
13101
0
    sp[-1] = JS_UNDEFINED;
13102
0
    return -1;
13103
0
}
13104
13105
static __exception int js_post_inc_slow(JSContext *ctx,
13106
                                        JSValue *sp, OPCodeEnum op)
13107
0
{
13108
0
    JSValue op1;
13109
13110
    /* XXX: allow custom operators */
13111
0
    op1 = sp[-1];
13112
0
    op1 = JS_ToNumericFree(ctx, op1);
13113
0
    if (JS_IsException(op1)) {
13114
0
        sp[-1] = JS_UNDEFINED;
13115
0
        return -1;
13116
0
    }
13117
0
    sp[-1] = op1;
13118
0
    sp[0] = JS_DupValue(ctx, op1);
13119
0
    return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec);
13120
0
}
13121
13122
static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
13123
0
{
13124
0
    JSValue op1;
13125
13126
0
    op1 = sp[-1];
13127
0
#ifdef CONFIG_BIGNUM
13128
0
    if (JS_IsObject(op1)) {
13129
0
        JSValue val;
13130
0
        int ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not);
13131
0
        if (ret < 0)
13132
0
            return -1;
13133
0
        if (ret) {
13134
0
            JS_FreeValue(ctx, op1);
13135
0
            sp[-1] = val;
13136
0
            return 0;
13137
0
        }
13138
0
    }
13139
0
#endif
13140
0
    op1 = JS_ToNumericFree(ctx, op1);
13141
0
    if (JS_IsException(op1))
13142
0
        goto exception;
13143
0
    if (is_math_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
13144
0
        if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1))
13145
0
            goto exception;
13146
0
    } else {
13147
0
        int32_t v1;
13148
0
        if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
13149
0
            goto exception;
13150
0
        sp[-1] = JS_NewInt32(ctx, ~v1);
13151
0
    }
13152
0
    return 0;
13153
0
 exception:
13154
0
    sp[-1] = JS_UNDEFINED;
13155
0
    return -1;
13156
0
}
13157
13158
static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
13159
                                  JSValue *pres, JSValue op1, JSValue op2)
13160
0
{
13161
0
    bf_t a_s, b_s, *r, *a, *b;
13162
0
    int ret;
13163
0
    JSValue res;
13164
13165
0
    res = JS_NewBigInt(ctx);
13166
0
    if (JS_IsException(res))
13167
0
        goto fail;
13168
0
    a = JS_ToBigInt(ctx, &a_s, op1);
13169
0
    if (!a)
13170
0
        goto fail;
13171
0
    b = JS_ToBigInt(ctx, &b_s, op2);
13172
0
    if (!b) {
13173
0
        JS_FreeBigInt(ctx, a, &a_s);
13174
0
        goto fail;
13175
0
    }
13176
0
    r = JS_GetBigInt(res);
13177
0
    ret = 0;
13178
0
    switch(op) {
13179
0
    case OP_add:
13180
0
        ret = bf_add(r, a, b, BF_PREC_INF, BF_RNDZ);
13181
0
        break;
13182
0
    case OP_sub:
13183
0
        ret = bf_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
13184
0
        break;
13185
0
    case OP_mul:
13186
0
        ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
13187
0
        break;
13188
0
    case OP_div:
13189
0
        if (!is_math_mode(ctx)) {
13190
0
            bf_t rem_s, *rem = &rem_s;
13191
0
            bf_init(ctx->bf_ctx, rem);
13192
0
            ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ,
13193
0
                            BF_RNDZ);
13194
0
            bf_delete(rem);
13195
0
        } else {
13196
0
            goto math_mode_div_pow;
13197
0
        }
13198
0
        break;
13199
0
#ifdef CONFIG_BIGNUM
13200
0
    case OP_math_mod:
13201
        /* Euclidian remainder */
13202
0
        ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
13203
0
                     BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP;
13204
0
        break;
13205
0
#endif
13206
0
    case OP_mod:
13207
0
        ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
13208
0
                     BF_RNDZ) & BF_ST_INVALID_OP;
13209
0
        break;
13210
0
    case OP_pow:
13211
0
        if (b->sign) {
13212
0
            if (!is_math_mode(ctx)) {
13213
0
                ret = BF_ST_INVALID_OP;
13214
0
            } else {
13215
0
            math_mode_div_pow:
13216
0
#ifdef CONFIG_BIGNUM
13217
0
                JS_FreeValue(ctx, res);
13218
0
                ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op);
13219
0
                if (ret != 0) {
13220
0
                    JS_FreeBigInt(ctx, a, &a_s);
13221
0
                    JS_FreeBigInt(ctx, b, &b_s);
13222
0
                    JS_FreeValue(ctx, op1);
13223
0
                    JS_FreeValue(ctx, op2);
13224
0
                    if (ret < 0) {
13225
0
                        return -1;
13226
0
                    } else {
13227
0
                        *pres = res;
13228
0
                        return 0;
13229
0
                    }
13230
0
                }
13231
                /* if no BigInt power operator defined, return a
13232
                   bigfloat */
13233
0
                res = JS_NewBigFloat(ctx);
13234
0
                if (JS_IsException(res)) {
13235
0
                    JS_FreeBigInt(ctx, a, &a_s);
13236
0
                    JS_FreeBigInt(ctx, b, &b_s);
13237
0
                    goto fail;
13238
0
                }
13239
0
                r = JS_GetBigFloat(res);
13240
0
                if (op == OP_div) {
13241
0
                    ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags) & BF_ST_MEM_ERROR;
13242
0
                } else {
13243
0
                    ret = bf_pow(r, a, b, ctx->fp_env.prec,
13244
0
                                 ctx->fp_env.flags | BF_POW_JS_QUIRKS) & BF_ST_MEM_ERROR;
13245
0
                }
13246
0
                JS_FreeBigInt(ctx, a, &a_s);
13247
0
                JS_FreeBigInt(ctx, b, &b_s);
13248
0
                JS_FreeValue(ctx, op1);
13249
0
                JS_FreeValue(ctx, op2);
13250
0
                if (unlikely(ret)) {
13251
0
                    JS_FreeValue(ctx, res);
13252
0
                    throw_bf_exception(ctx, ret);
13253
0
                    return -1;
13254
0
                }
13255
0
                *pres = res;
13256
0
                return 0;
13257
#else
13258
                abort();
13259
#endif
13260
0
            }
13261
0
        } else {
13262
0
            ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS);
13263
0
        }
13264
0
        break;
13265
13266
        /* logical operations */
13267
0
    case OP_shl:
13268
0
    case OP_sar:
13269
0
        {
13270
0
            slimb_t v2;
13271
#if LIMB_BITS == 32
13272
            bf_get_int32(&v2, b, 0);
13273
            if (v2 == INT32_MIN)
13274
                v2 = INT32_MIN + 1;
13275
#else
13276
0
            bf_get_int64(&v2, b, 0);
13277
0
            if (v2 == INT64_MIN)
13278
0
                v2 = INT64_MIN + 1;
13279
0
#endif
13280
0
            if (op == OP_sar)
13281
0
                v2 = -v2;
13282
0
            ret = bf_set(r, a);
13283
0
            ret |= bf_mul_2exp(r, v2, BF_PREC_INF, BF_RNDZ);
13284
0
            if (v2 < 0) {
13285
0
                ret |= bf_rint(r, BF_RNDD) & (BF_ST_OVERFLOW | BF_ST_MEM_ERROR);
13286
0
            }
13287
0
        }
13288
0
        break;
13289
0
    case OP_and:
13290
0
        ret = bf_logic_and(r, a, b);
13291
0
        break;
13292
0
    case OP_or:
13293
0
        ret = bf_logic_or(r, a, b);
13294
0
        break;
13295
0
    case OP_xor:
13296
0
        ret = bf_logic_xor(r, a, b);
13297
0
        break;
13298
0
    default:
13299
0
        abort();
13300
0
    }
13301
0
    JS_FreeBigInt(ctx, a, &a_s);
13302
0
    JS_FreeBigInt(ctx, b, &b_s);
13303
0
    JS_FreeValue(ctx, op1);
13304
0
    JS_FreeValue(ctx, op2);
13305
0
    if (unlikely(ret)) {
13306
0
        JS_FreeValue(ctx, res);
13307
0
        throw_bf_exception(ctx, ret);
13308
0
        return -1;
13309
0
    }
13310
0
    *pres = JS_CompactBigInt(ctx, res);
13311
0
    return 0;
13312
0
 fail:
13313
0
    JS_FreeValue(ctx, res);
13314
0
    JS_FreeValue(ctx, op1);
13315
0
    JS_FreeValue(ctx, op2);
13316
0
    return -1;
13317
0
}
13318
13319
#ifdef CONFIG_BIGNUM
13320
static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
13321
                                    JSValue *pres, JSValue op1, JSValue op2)
13322
0
{
13323
0
    bf_t a_s, b_s, *r, *a, *b;
13324
0
    int ret;
13325
0
    JSValue res;
13326
13327
0
    res = JS_NewBigFloat(ctx);
13328
0
    if (JS_IsException(res))
13329
0
        goto fail;
13330
0
    r = JS_GetBigFloat(res);
13331
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
13332
0
    if (!a) {
13333
0
        JS_FreeValue(ctx, res);
13334
0
        goto fail;
13335
0
    }
13336
0
    b = JS_ToBigFloat(ctx, &b_s, op2);
13337
0
    if (!b) {
13338
0
        if (a == &a_s)
13339
0
            bf_delete(a);
13340
0
        JS_FreeValue(ctx, res);
13341
0
        goto fail;
13342
0
    }
13343
0
    bf_init(ctx->bf_ctx, r);
13344
0
    switch(op) {
13345
0
    case OP_add:
13346
0
        ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
13347
0
        break;
13348
0
    case OP_sub:
13349
0
        ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
13350
0
        break;
13351
0
    case OP_mul:
13352
0
        ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
13353
0
        break;
13354
0
    case OP_div:
13355
0
        ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
13356
0
        break;
13357
0
    case OP_math_mod:
13358
        /* Euclidian remainder */
13359
0
        ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
13360
0
                     BF_DIVREM_EUCLIDIAN);
13361
0
        break;
13362
0
    case OP_mod:
13363
0
        ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
13364
0
                     BF_RNDZ);
13365
0
        break;
13366
0
    case OP_pow:
13367
0
        ret = bf_pow(r, a, b, ctx->fp_env.prec,
13368
0
                     ctx->fp_env.flags | BF_POW_JS_QUIRKS);
13369
0
        break;
13370
0
    default:
13371
0
        abort();
13372
0
    }
13373
0
    if (a == &a_s)
13374
0
        bf_delete(a);
13375
0
    if (b == &b_s)
13376
0
        bf_delete(b);
13377
0
    JS_FreeValue(ctx, op1);
13378
0
    JS_FreeValue(ctx, op2);
13379
0
    if (unlikely(ret & BF_ST_MEM_ERROR)) {
13380
0
        JS_FreeValue(ctx, res);
13381
0
        throw_bf_exception(ctx, ret);
13382
0
        return -1;
13383
0
    }
13384
0
    *pres = res;
13385
0
    return 0;
13386
0
 fail:
13387
0
    JS_FreeValue(ctx, op1);
13388
0
    JS_FreeValue(ctx, op2);
13389
0
    return -1;
13390
0
}
13391
13392
/* b must be a positive integer */
13393
static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b)
13394
0
{
13395
0
    bfdec_t b1;
13396
0
    int32_t b2;
13397
0
    int ret;
13398
13399
0
    bfdec_init(b->ctx, &b1);
13400
0
    ret = bfdec_set(&b1, b);
13401
0
    if (ret) {
13402
0
        bfdec_delete(&b1);
13403
0
        return ret;
13404
0
    }
13405
0
    ret = bfdec_rint(&b1, BF_RNDZ);
13406
0
    if (ret) {
13407
0
        bfdec_delete(&b1);
13408
0
        return BF_ST_INVALID_OP; /* must be an integer */
13409
0
    }
13410
0
    ret = bfdec_get_int32(&b2, &b1);
13411
0
    bfdec_delete(&b1);
13412
0
    if (ret)
13413
0
        return ret; /* overflow */
13414
0
    if (b2 < 0)
13415
0
        return BF_ST_INVALID_OP; /* must be positive */
13416
0
    return bfdec_pow_ui(r, a, b2);
13417
0
}
13418
13419
static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
13420
                                      JSValue *pres, JSValue op1, JSValue op2)
13421
0
{
13422
0
    bfdec_t *r, *a, *b;
13423
0
    int ret;
13424
0
    JSValue res;
13425
13426
0
    res = JS_NewBigDecimal(ctx);
13427
0
    if (JS_IsException(res))
13428
0
        goto fail;
13429
0
    r = JS_GetBigDecimal(res);
13430
13431
0
    a = JS_ToBigDecimal(ctx, op1);
13432
0
    if (!a)
13433
0
        goto fail;
13434
0
    b = JS_ToBigDecimal(ctx, op2);
13435
0
    if (!b)
13436
0
        goto fail;
13437
0
    switch(op) {
13438
0
    case OP_add:
13439
0
        ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ);
13440
0
        break;
13441
0
    case OP_sub:
13442
0
        ret = bfdec_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
13443
0
        break;
13444
0
    case OP_mul:
13445
0
        ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
13446
0
        break;
13447
0
    case OP_div:
13448
0
        ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ);
13449
0
        break;
13450
0
    case OP_math_mod:
13451
        /* Euclidian remainder */
13452
0
        ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN);
13453
0
        break;
13454
0
    case OP_mod:
13455
0
        ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ);
13456
0
        break;
13457
0
    case OP_pow:
13458
0
        ret = js_bfdec_pow(r, a, b);
13459
0
        break;
13460
0
    default:
13461
0
        abort();
13462
0
    }
13463
0
    JS_FreeValue(ctx, op1);
13464
0
    JS_FreeValue(ctx, op2);
13465
0
    if (unlikely(ret)) {
13466
0
        JS_FreeValue(ctx, res);
13467
0
        throw_bf_exception(ctx, ret);
13468
0
        return -1;
13469
0
    }
13470
0
    *pres = res;
13471
0
    return 0;
13472
0
 fail:
13473
0
    JS_FreeValue(ctx, res);
13474
0
    JS_FreeValue(ctx, op1);
13475
0
    JS_FreeValue(ctx, op2);
13476
0
    return -1;
13477
0
}
13478
#endif /* CONFIG_BIGNUM */
13479
13480
static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
13481
                                                      OPCodeEnum op)
13482
0
{
13483
0
    JSValue op1, op2;
13484
0
    uint32_t tag1, tag2;
13485
0
    double d1, d2;
13486
13487
0
    op1 = sp[-2];
13488
0
    op2 = sp[-1];
13489
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13490
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13491
    /* fast path for float operations */
13492
0
    if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
13493
0
        d1 = JS_VALUE_GET_FLOAT64(op1);
13494
0
        d2 = JS_VALUE_GET_FLOAT64(op2);
13495
0
        goto handle_float64;
13496
0
    }
13497
13498
0
#ifdef CONFIG_BIGNUM
13499
    /* try to call an overloaded operator */
13500
0
    if ((tag1 == JS_TAG_OBJECT &&
13501
0
         (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
13502
0
        (tag2 == JS_TAG_OBJECT &&
13503
0
         (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
13504
0
        JSValue res;
13505
0
        int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
13506
0
        if (ret != 0) {
13507
0
            JS_FreeValue(ctx, op1);
13508
0
            JS_FreeValue(ctx, op2);
13509
0
            if (ret < 0) {
13510
0
                goto exception;
13511
0
            } else {
13512
0
                sp[-2] = res;
13513
0
                return 0;
13514
0
            }
13515
0
        }
13516
0
    }
13517
0
#endif
13518
13519
0
    op1 = JS_ToNumericFree(ctx, op1);
13520
0
    if (JS_IsException(op1)) {
13521
0
        JS_FreeValue(ctx, op2);
13522
0
        goto exception;
13523
0
    }
13524
0
    op2 = JS_ToNumericFree(ctx, op2);
13525
0
    if (JS_IsException(op2)) {
13526
0
        JS_FreeValue(ctx, op1);
13527
0
        goto exception;
13528
0
    }
13529
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13530
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13531
13532
0
    if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
13533
0
        int32_t v1, v2;
13534
0
        int64_t v;
13535
0
        v1 = JS_VALUE_GET_INT(op1);
13536
0
        v2 = JS_VALUE_GET_INT(op2);
13537
0
        switch(op) {
13538
0
        case OP_sub:
13539
0
            v = (int64_t)v1 - (int64_t)v2;
13540
0
            break;
13541
0
        case OP_mul:
13542
0
            v = (int64_t)v1 * (int64_t)v2;
13543
0
            if (is_math_mode(ctx) &&
13544
0
                (v < -MAX_SAFE_INTEGER || v > MAX_SAFE_INTEGER))
13545
0
                goto handle_bigint;
13546
0
            if (v == 0 && (v1 | v2) < 0) {
13547
0
                sp[-2] = __JS_NewFloat64(ctx, -0.0);
13548
0
                return 0;
13549
0
            }
13550
0
            break;
13551
0
        case OP_div:
13552
0
            if (is_math_mode(ctx))
13553
0
                goto handle_bigint;
13554
0
            sp[-2] = __JS_NewFloat64(ctx, (double)v1 / (double)v2);
13555
0
            return 0;
13556
0
#ifdef CONFIG_BIGNUM
13557
0
        case OP_math_mod:
13558
0
            if (unlikely(v2 == 0)) {
13559
0
                throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO);
13560
0
                goto exception;
13561
0
            }
13562
0
            v = (int64_t)v1 % (int64_t)v2;
13563
0
            if (v < 0) {
13564
0
                if (v2 < 0)
13565
0
                    v -= v2;
13566
0
                else
13567
0
                    v += v2;
13568
0
            }
13569
0
            break;
13570
0
#endif
13571
0
        case OP_mod:
13572
0
            if (v1 < 0 || v2 <= 0) {
13573
0
                sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));
13574
0
                return 0;
13575
0
            } else {
13576
0
                v = (int64_t)v1 % (int64_t)v2;
13577
0
            }
13578
0
            break;
13579
0
        case OP_pow:
13580
0
            if (!is_math_mode(ctx)) {
13581
0
                sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));
13582
0
                return 0;
13583
0
            } else {
13584
0
                goto handle_bigint;
13585
0
            }
13586
0
            break;
13587
0
        default:
13588
0
            abort();
13589
0
        }
13590
0
        sp[-2] = JS_NewInt64(ctx, v);
13591
0
    } else
13592
0
#ifdef CONFIG_BIGNUM
13593
0
    if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
13594
0
        if (ctx->rt->bigdecimal_ops.binary_arith(ctx, op, sp - 2, op1, op2))
13595
0
            goto exception;
13596
0
    } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
13597
0
        if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2))
13598
0
            goto exception;
13599
0
    } else
13600
0
#endif
13601
0
    if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
13602
0
    handle_bigint:
13603
0
        if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
13604
0
            goto exception;
13605
0
    } else {
13606
0
        double dr;
13607
        /* float64 result */
13608
0
        if (JS_ToFloat64Free(ctx, &d1, op1)) {
13609
0
            JS_FreeValue(ctx, op2);
13610
0
            goto exception;
13611
0
        }
13612
0
        if (JS_ToFloat64Free(ctx, &d2, op2))
13613
0
            goto exception;
13614
0
    handle_float64:
13615
0
        if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
13616
0
            goto handle_bigint;
13617
0
        switch(op) {
13618
0
        case OP_sub:
13619
0
            dr = d1 - d2;
13620
0
            break;
13621
0
        case OP_mul:
13622
0
            dr = d1 * d2;
13623
0
            break;
13624
0
        case OP_div:
13625
0
            dr = d1 / d2;
13626
0
            break;
13627
0
        case OP_mod:
13628
0
            dr = fmod(d1, d2);
13629
0
            break;
13630
0
#ifdef CONFIG_BIGNUM
13631
0
        case OP_math_mod:
13632
0
            d2 = fabs(d2);
13633
0
            dr = fmod(d1, d2);
13634
            /* XXX: loss of accuracy if dr < 0 */
13635
0
            if (dr < 0)
13636
0
                dr += d2;
13637
0
            break;
13638
0
#endif
13639
0
        case OP_pow:
13640
0
            dr = js_pow(d1, d2);
13641
0
            break;
13642
0
        default:
13643
0
            abort();
13644
0
        }
13645
0
        sp[-2] = __JS_NewFloat64(ctx, dr);
13646
0
    }
13647
0
    return 0;
13648
0
 exception:
13649
0
    sp[-2] = JS_UNDEFINED;
13650
0
    sp[-1] = JS_UNDEFINED;
13651
0
    return -1;
13652
0
}
13653
13654
static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
13655
1
{
13656
1
    JSValue op1, op2;
13657
1
    uint32_t tag1, tag2;
13658
13659
1
    op1 = sp[-2];
13660
1
    op2 = sp[-1];
13661
13662
1
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13663
1
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13664
    /* fast path for float64 */
13665
1
    if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
13666
0
        double d1, d2;
13667
0
        d1 = JS_VALUE_GET_FLOAT64(op1);
13668
0
        d2 = JS_VALUE_GET_FLOAT64(op2);
13669
0
        sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
13670
0
        return 0;
13671
0
    }
13672
13673
1
    if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
13674
0
#ifdef CONFIG_BIGNUM
13675
        /* try to call an overloaded operator */
13676
0
        if ((tag1 == JS_TAG_OBJECT &&
13677
0
             (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED &&
13678
0
              tag2 != JS_TAG_STRING)) ||
13679
0
            (tag2 == JS_TAG_OBJECT &&
13680
0
             (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED &&
13681
0
              tag1 != JS_TAG_STRING))) {
13682
0
            JSValue res;
13683
0
            int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add,
13684
0
                                                 FALSE, HINT_NONE);
13685
0
            if (ret != 0) {
13686
0
                JS_FreeValue(ctx, op1);
13687
0
                JS_FreeValue(ctx, op2);
13688
0
                if (ret < 0) {
13689
0
                    goto exception;
13690
0
                } else {
13691
0
                    sp[-2] = res;
13692
0
                    return 0;
13693
0
                }
13694
0
            }
13695
0
        }
13696
0
#endif
13697
0
        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
13698
0
        if (JS_IsException(op1)) {
13699
0
            JS_FreeValue(ctx, op2);
13700
0
            goto exception;
13701
0
        }
13702
13703
0
        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
13704
0
        if (JS_IsException(op2)) {
13705
0
            JS_FreeValue(ctx, op1);
13706
0
            goto exception;
13707
0
        }
13708
0
        tag1 = JS_VALUE_GET_NORM_TAG(op1);
13709
0
        tag2 = JS_VALUE_GET_NORM_TAG(op2);
13710
0
    }
13711
13712
1
    if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
13713
1
        sp[-2] = JS_ConcatString(ctx, op1, op2);
13714
1
        if (JS_IsException(sp[-2]))
13715
0
            goto exception;
13716
1
        return 0;
13717
1
    }
13718
13719
0
    op1 = JS_ToNumericFree(ctx, op1);
13720
0
    if (JS_IsException(op1)) {
13721
0
        JS_FreeValue(ctx, op2);
13722
0
        goto exception;
13723
0
    }
13724
0
    op2 = JS_ToNumericFree(ctx, op2);
13725
0
    if (JS_IsException(op2)) {
13726
0
        JS_FreeValue(ctx, op1);
13727
0
        goto exception;
13728
0
    }
13729
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13730
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13731
13732
0
    if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
13733
0
        int32_t v1, v2;
13734
0
        int64_t v;
13735
0
        v1 = JS_VALUE_GET_INT(op1);
13736
0
        v2 = JS_VALUE_GET_INT(op2);
13737
0
        v = (int64_t)v1 + (int64_t)v2;
13738
0
        sp[-2] = JS_NewInt64(ctx, v);
13739
0
    } else
13740
0
#ifdef CONFIG_BIGNUM
13741
0
    if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
13742
0
        if (ctx->rt->bigdecimal_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
13743
0
            goto exception;
13744
0
    } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
13745
0
        if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
13746
0
            goto exception;
13747
0
    } else
13748
0
#endif
13749
0
    if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
13750
0
    handle_bigint:
13751
0
        if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
13752
0
            goto exception;
13753
0
    } else {
13754
0
        double d1, d2;
13755
        /* float64 result */
13756
0
        if (JS_ToFloat64Free(ctx, &d1, op1)) {
13757
0
            JS_FreeValue(ctx, op2);
13758
0
            goto exception;
13759
0
        }
13760
0
        if (JS_ToFloat64Free(ctx, &d2, op2))
13761
0
            goto exception;
13762
0
        if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
13763
0
            goto handle_bigint;
13764
0
        sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
13765
0
    }
13766
0
    return 0;
13767
0
 exception:
13768
0
    sp[-2] = JS_UNDEFINED;
13769
0
    sp[-1] = JS_UNDEFINED;
13770
0
    return -1;
13771
0
}
13772
13773
static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
13774
                                                      JSValue *sp,
13775
                                                      OPCodeEnum op)
13776
0
{
13777
0
    JSValue op1, op2;
13778
0
    uint32_t tag1, tag2;
13779
0
    uint32_t v1, v2, r;
13780
13781
0
    op1 = sp[-2];
13782
0
    op2 = sp[-1];
13783
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13784
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13785
13786
0
#ifdef CONFIG_BIGNUM
13787
    /* try to call an overloaded operator */
13788
0
    if ((tag1 == JS_TAG_OBJECT &&
13789
0
         (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
13790
0
        (tag2 == JS_TAG_OBJECT &&
13791
0
         (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
13792
0
        JSValue res;
13793
0
        int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
13794
0
        if (ret != 0) {
13795
0
            JS_FreeValue(ctx, op1);
13796
0
            JS_FreeValue(ctx, op2);
13797
0
            if (ret < 0) {
13798
0
                goto exception;
13799
0
            } else {
13800
0
                sp[-2] = res;
13801
0
                return 0;
13802
0
            }
13803
0
        }
13804
0
    }
13805
0
#endif
13806
13807
0
    op1 = JS_ToNumericFree(ctx, op1);
13808
0
    if (JS_IsException(op1)) {
13809
0
        JS_FreeValue(ctx, op2);
13810
0
        goto exception;
13811
0
    }
13812
0
    op2 = JS_ToNumericFree(ctx, op2);
13813
0
    if (JS_IsException(op2)) {
13814
0
        JS_FreeValue(ctx, op1);
13815
0
        goto exception;
13816
0
    }
13817
13818
0
    if (is_math_mode(ctx))
13819
0
        goto bigint_op;
13820
13821
0
    tag1 = JS_VALUE_GET_TAG(op1);
13822
0
    tag2 = JS_VALUE_GET_TAG(op2);
13823
0
    if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
13824
0
        if (tag1 != tag2) {
13825
0
            JS_FreeValue(ctx, op1);
13826
0
            JS_FreeValue(ctx, op2);
13827
0
            JS_ThrowTypeError(ctx, "both operands must be bigint");
13828
0
            goto exception;
13829
0
        } else {
13830
0
        bigint_op:
13831
0
            if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
13832
0
                goto exception;
13833
0
        }
13834
0
    } else {
13835
0
        if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
13836
0
            JS_FreeValue(ctx, op2);
13837
0
            goto exception;
13838
0
        }
13839
0
        if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
13840
0
            goto exception;
13841
0
        switch(op) {
13842
0
        case OP_shl:
13843
0
            r = v1 << (v2 & 0x1f);
13844
0
            break;
13845
0
        case OP_sar:
13846
0
            r = (int)v1 >> (v2 & 0x1f);
13847
0
            break;
13848
0
        case OP_and:
13849
0
            r = v1 & v2;
13850
0
            break;
13851
0
        case OP_or:
13852
0
            r = v1 | v2;
13853
0
            break;
13854
0
        case OP_xor:
13855
0
            r = v1 ^ v2;
13856
0
            break;
13857
0
        default:
13858
0
            abort();
13859
0
        }
13860
0
        sp[-2] = JS_NewInt32(ctx, r);
13861
0
    }
13862
0
    return 0;
13863
0
 exception:
13864
0
    sp[-2] = JS_UNDEFINED;
13865
0
    sp[-1] = JS_UNDEFINED;
13866
0
    return -1;
13867
0
}
13868
13869
/* Note: also used for bigint */
13870
static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op,
13871
                               JSValue op1, JSValue op2)
13872
0
{
13873
0
    bf_t a_s, b_s, *a, *b;
13874
0
    int res;
13875
13876
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
13877
0
    if (!a) {
13878
0
        JS_FreeValue(ctx, op2);
13879
0
        return -1;
13880
0
    }
13881
0
    b = JS_ToBigFloat(ctx, &b_s, op2);
13882
0
    if (!b) {
13883
0
        if (a == &a_s)
13884
0
            bf_delete(a);
13885
0
        JS_FreeValue(ctx, op1);
13886
0
        return -1;
13887
0
    }
13888
0
    switch(op) {
13889
0
    case OP_lt:
13890
0
        res = bf_cmp_lt(a, b); /* if NaN return false */
13891
0
        break;
13892
0
    case OP_lte:
13893
0
        res = bf_cmp_le(a, b); /* if NaN return false */
13894
0
        break;
13895
0
    case OP_gt:
13896
0
        res = bf_cmp_lt(b, a); /* if NaN return false */
13897
0
        break;
13898
0
    case OP_gte:
13899
0
        res = bf_cmp_le(b, a); /* if NaN return false */
13900
0
        break;
13901
0
    case OP_eq:
13902
0
        res = bf_cmp_eq(a, b); /* if NaN return false */
13903
0
        break;
13904
0
    default:
13905
0
        abort();
13906
0
    }
13907
0
    if (a == &a_s)
13908
0
        bf_delete(a);
13909
0
    if (b == &b_s)
13910
0
        bf_delete(b);
13911
0
    JS_FreeValue(ctx, op1);
13912
0
    JS_FreeValue(ctx, op2);
13913
0
    return res;
13914
0
}
13915
13916
#ifdef CONFIG_BIGNUM
13917
static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op,
13918
                                 JSValue op1, JSValue op2)
13919
0
{
13920
0
    bfdec_t *a, *b;
13921
0
    int res;
13922
13923
    /* Note: binary floats are converted to bigdecimal with
13924
       toString(). It is not mathematically correct but is consistent
13925
       with the BigDecimal() constructor behavior */
13926
0
    op1 = JS_ToBigDecimalFree(ctx, op1, TRUE);
13927
0
    if (JS_IsException(op1)) {
13928
0
        JS_FreeValue(ctx, op2);
13929
0
        return -1;
13930
0
    }
13931
0
    op2 = JS_ToBigDecimalFree(ctx, op2, TRUE);
13932
0
    if (JS_IsException(op2)) {
13933
0
        JS_FreeValue(ctx, op1);
13934
0
        return -1;
13935
0
    }
13936
0
    a = JS_ToBigDecimal(ctx, op1); /* cannot fail */
13937
0
    b = JS_ToBigDecimal(ctx, op2); /* cannot fail */
13938
13939
0
    switch(op) {
13940
0
    case OP_lt:
13941
0
        res = bfdec_cmp_lt(a, b); /* if NaN return false */
13942
0
        break;
13943
0
    case OP_lte:
13944
0
        res = bfdec_cmp_le(a, b); /* if NaN return false */
13945
0
        break;
13946
0
    case OP_gt:
13947
0
        res = bfdec_cmp_lt(b, a); /* if NaN return false */
13948
0
        break;
13949
0
    case OP_gte:
13950
0
        res = bfdec_cmp_le(b, a); /* if NaN return false */
13951
0
        break;
13952
0
    case OP_eq:
13953
0
        res = bfdec_cmp_eq(a, b); /* if NaN return false */
13954
0
        break;
13955
0
    default:
13956
0
        abort();
13957
0
    }
13958
0
    JS_FreeValue(ctx, op1);
13959
0
    JS_FreeValue(ctx, op2);
13960
0
    return res;
13961
0
}
13962
#endif /* !CONFIG_BIGNUM */
13963
13964
static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
13965
                                        OPCodeEnum op)
13966
0
{
13967
0
    JSValue op1, op2;
13968
0
    int res;
13969
0
    uint32_t tag1, tag2;
13970
13971
0
    op1 = sp[-2];
13972
0
    op2 = sp[-1];
13973
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13974
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13975
0
#ifdef CONFIG_BIGNUM
13976
    /* try to call an overloaded operator */
13977
0
    if ((tag1 == JS_TAG_OBJECT &&
13978
0
         (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
13979
0
        (tag2 == JS_TAG_OBJECT &&
13980
0
         (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
13981
0
        JSValue ret;
13982
0
        res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op,
13983
0
                                         FALSE, HINT_NUMBER);
13984
0
        if (res != 0) {
13985
0
            JS_FreeValue(ctx, op1);
13986
0
            JS_FreeValue(ctx, op2);
13987
0
            if (res < 0) {
13988
0
                goto exception;
13989
0
            } else {
13990
0
                sp[-2] = ret;
13991
0
                return 0;
13992
0
            }
13993
0
        }
13994
0
    }
13995
0
#endif
13996
0
    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
13997
0
    if (JS_IsException(op1)) {
13998
0
        JS_FreeValue(ctx, op2);
13999
0
        goto exception;
14000
0
    }
14001
0
    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
14002
0
    if (JS_IsException(op2)) {
14003
0
        JS_FreeValue(ctx, op1);
14004
0
        goto exception;
14005
0
    }
14006
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14007
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14008
14009
0
    if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
14010
0
        JSString *p1, *p2;
14011
0
        p1 = JS_VALUE_GET_STRING(op1);
14012
0
        p2 = JS_VALUE_GET_STRING(op2);
14013
0
        res = js_string_compare(ctx, p1, p2);
14014
0
        switch(op) {
14015
0
        case OP_lt:
14016
0
            res = (res < 0);
14017
0
            break;
14018
0
        case OP_lte:
14019
0
            res = (res <= 0);
14020
0
            break;
14021
0
        case OP_gt:
14022
0
            res = (res > 0);
14023
0
            break;
14024
0
        default:
14025
0
        case OP_gte:
14026
0
            res = (res >= 0);
14027
0
            break;
14028
0
        }
14029
0
        JS_FreeValue(ctx, op1);
14030
0
        JS_FreeValue(ctx, op2);
14031
0
    } else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) &&
14032
0
               (tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) {
14033
        /* fast path for float64/int */
14034
0
        goto float64_compare;
14035
0
    } else {
14036
0
        if (((tag1 == JS_TAG_BIG_INT && tag2 == JS_TAG_STRING) ||
14037
0
             (tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING)) &&
14038
0
            !is_math_mode(ctx)) {
14039
0
            if (tag1 == JS_TAG_STRING) {
14040
0
                op1 = JS_StringToBigInt(ctx, op1);
14041
0
                if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
14042
0
                    goto invalid_bigint_string;
14043
0
            }
14044
0
            if (tag2 == JS_TAG_STRING) {
14045
0
                op2 = JS_StringToBigInt(ctx, op2);
14046
0
                if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) {
14047
0
                invalid_bigint_string:
14048
0
                    JS_FreeValue(ctx, op1);
14049
0
                    JS_FreeValue(ctx, op2);
14050
0
                    res = FALSE;
14051
0
                    goto done;
14052
0
                }
14053
0
            }
14054
0
        } else {
14055
0
            op1 = JS_ToNumericFree(ctx, op1);
14056
0
            if (JS_IsException(op1)) {
14057
0
                JS_FreeValue(ctx, op2);
14058
0
                goto exception;
14059
0
            }
14060
0
            op2 = JS_ToNumericFree(ctx, op2);
14061
0
            if (JS_IsException(op2)) {
14062
0
                JS_FreeValue(ctx, op1);
14063
0
                goto exception;
14064
0
            }
14065
0
        }
14066
14067
0
        tag1 = JS_VALUE_GET_NORM_TAG(op1);
14068
0
        tag2 = JS_VALUE_GET_NORM_TAG(op2);
14069
14070
0
#ifdef CONFIG_BIGNUM
14071
0
        if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
14072
0
            res = ctx->rt->bigdecimal_ops.compare(ctx, op, op1, op2);
14073
0
            if (res < 0)
14074
0
                goto exception;
14075
0
        } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
14076
0
            res = ctx->rt->bigfloat_ops.compare(ctx, op, op1, op2);
14077
0
            if (res < 0)
14078
0
                goto exception;
14079
0
        } else
14080
0
#endif
14081
0
        if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
14082
0
            res = ctx->rt->bigint_ops.compare(ctx, op, op1, op2);
14083
0
            if (res < 0)
14084
0
                goto exception;
14085
0
        } else {
14086
0
            double d1, d2;
14087
14088
0
        float64_compare:
14089
            /* can use floating point comparison */
14090
0
            if (tag1 == JS_TAG_FLOAT64) {
14091
0
                d1 = JS_VALUE_GET_FLOAT64(op1);
14092
0
            } else {
14093
0
                d1 = JS_VALUE_GET_INT(op1);
14094
0
            }
14095
0
            if (tag2 == JS_TAG_FLOAT64) {
14096
0
                d2 = JS_VALUE_GET_FLOAT64(op2);
14097
0
            } else {
14098
0
                d2 = JS_VALUE_GET_INT(op2);
14099
0
            }
14100
0
            switch(op) {
14101
0
            case OP_lt:
14102
0
                res = (d1 < d2); /* if NaN return false */
14103
0
                break;
14104
0
            case OP_lte:
14105
0
                res = (d1 <= d2); /* if NaN return false */
14106
0
                break;
14107
0
            case OP_gt:
14108
0
                res = (d1 > d2); /* if NaN return false */
14109
0
                break;
14110
0
            default:
14111
0
            case OP_gte:
14112
0
                res = (d1 >= d2); /* if NaN return false */
14113
0
                break;
14114
0
            }
14115
0
        }
14116
0
    }
14117
0
 done:
14118
0
    sp[-2] = JS_NewBool(ctx, res);
14119
0
    return 0;
14120
0
 exception:
14121
0
    sp[-2] = JS_UNDEFINED;
14122
0
    sp[-1] = JS_UNDEFINED;
14123
0
    return -1;
14124
0
}
14125
14126
static BOOL tag_is_number(uint32_t tag)
14127
0
{
14128
0
    return (tag == JS_TAG_INT || tag == JS_TAG_BIG_INT ||
14129
0
            tag == JS_TAG_FLOAT64
14130
0
#ifdef CONFIG_BIGNUM
14131
0
            || tag == JS_TAG_BIG_FLOAT || tag == JS_TAG_BIG_DECIMAL
14132
0
#endif
14133
0
            );
14134
0
}
14135
14136
static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
14137
                                            BOOL is_neq)
14138
0
{
14139
0
    JSValue op1, op2;
14140
0
#ifdef CONFIG_BIGNUM
14141
0
    JSValue ret;
14142
0
#endif
14143
0
    int res;
14144
0
    uint32_t tag1, tag2;
14145
14146
0
    op1 = sp[-2];
14147
0
    op2 = sp[-1];
14148
0
 redo:
14149
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14150
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14151
0
    if (tag_is_number(tag1) && tag_is_number(tag2)) {
14152
0
        if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
14153
0
            res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
14154
0
        } else if ((tag1 == JS_TAG_FLOAT64 &&
14155
0
                    (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) ||
14156
0
                   (tag2 == JS_TAG_FLOAT64 &&
14157
0
                    (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) {
14158
0
            double d1, d2;
14159
0
            if (tag1 == JS_TAG_FLOAT64) {
14160
0
                d1 = JS_VALUE_GET_FLOAT64(op1);
14161
0
            } else {
14162
0
                d1 = JS_VALUE_GET_INT(op1);
14163
0
            }
14164
0
            if (tag2 == JS_TAG_FLOAT64) {
14165
0
                d2 = JS_VALUE_GET_FLOAT64(op2);
14166
0
            } else {
14167
0
                d2 = JS_VALUE_GET_INT(op2);
14168
0
            }
14169
0
            res = (d1 == d2);
14170
0
        } else
14171
0
#ifdef CONFIG_BIGNUM
14172
0
        if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
14173
0
            res = ctx->rt->bigdecimal_ops.compare(ctx, OP_eq, op1, op2);
14174
0
            if (res < 0)
14175
0
                goto exception;
14176
0
        } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
14177
0
            res = ctx->rt->bigfloat_ops.compare(ctx, OP_eq, op1, op2);
14178
0
            if (res < 0)
14179
0
                goto exception;
14180
0
        } else
14181
0
#endif
14182
0
        {
14183
0
            res = ctx->rt->bigint_ops.compare(ctx, OP_eq, op1, op2);
14184
0
            if (res < 0)
14185
0
                goto exception;
14186
0
        }
14187
0
    } else if (tag1 == tag2) {
14188
0
#ifdef CONFIG_BIGNUM
14189
0
        if (tag1 == JS_TAG_OBJECT) {
14190
            /* try the fallback operator */
14191
0
            res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
14192
0
                                             is_neq ? OP_neq : OP_eq,
14193
0
                                             FALSE, HINT_NONE);
14194
0
            if (res != 0) {
14195
0
                JS_FreeValue(ctx, op1);
14196
0
                JS_FreeValue(ctx, op2);
14197
0
                if (res < 0) {
14198
0
                    goto exception;
14199
0
                } else {
14200
0
                    sp[-2] = ret;
14201
0
                    return 0;
14202
0
                }
14203
0
            }
14204
0
        }
14205
0
#endif
14206
0
        res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
14207
0
    } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
14208
0
               (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
14209
0
        res = TRUE;
14210
0
    } else if ((tag1 == JS_TAG_STRING && tag_is_number(tag2)) ||
14211
0
               (tag2 == JS_TAG_STRING && tag_is_number(tag1))) {
14212
14213
0
        if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) &&
14214
0
            !is_math_mode(ctx)) {
14215
0
            if (tag1 == JS_TAG_STRING) {
14216
0
                op1 = JS_StringToBigInt(ctx, op1);
14217
0
                if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
14218
0
                    goto invalid_bigint_string;
14219
0
            }
14220
0
            if (tag2 == JS_TAG_STRING) {
14221
0
                op2 = JS_StringToBigInt(ctx, op2);
14222
0
                if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) {
14223
0
                invalid_bigint_string:
14224
0
                    JS_FreeValue(ctx, op1);
14225
0
                    JS_FreeValue(ctx, op2);
14226
0
                    res = FALSE;
14227
0
                    goto done;
14228
0
                }
14229
0
            }
14230
0
        } else {
14231
0
            op1 = JS_ToNumericFree(ctx, op1);
14232
0
            if (JS_IsException(op1)) {
14233
0
                JS_FreeValue(ctx, op2);
14234
0
                goto exception;
14235
0
            }
14236
0
            op2 = JS_ToNumericFree(ctx, op2);
14237
0
            if (JS_IsException(op2)) {
14238
0
                JS_FreeValue(ctx, op1);
14239
0
                goto exception;
14240
0
            }
14241
0
        }
14242
0
        res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
14243
0
    } else if (tag1 == JS_TAG_BOOL) {
14244
0
        op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
14245
0
        goto redo;
14246
0
    } else if (tag2 == JS_TAG_BOOL) {
14247
0
        op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
14248
0
        goto redo;
14249
0
    } else if ((tag1 == JS_TAG_OBJECT &&
14250
0
                (tag_is_number(tag2) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) ||
14251
0
               (tag2 == JS_TAG_OBJECT &&
14252
0
                (tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) {
14253
0
#ifdef CONFIG_BIGNUM
14254
        /* try the fallback operator */
14255
0
        res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
14256
0
                                         is_neq ? OP_neq : OP_eq,
14257
0
                                         FALSE, HINT_NONE);
14258
0
        if (res != 0) {
14259
0
            JS_FreeValue(ctx, op1);
14260
0
            JS_FreeValue(ctx, op2);
14261
0
            if (res < 0) {
14262
0
                goto exception;
14263
0
            } else {
14264
0
                sp[-2] = ret;
14265
0
                return 0;
14266
0
            }
14267
0
        }
14268
0
#endif
14269
0
        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
14270
0
        if (JS_IsException(op1)) {
14271
0
            JS_FreeValue(ctx, op2);
14272
0
            goto exception;
14273
0
        }
14274
0
        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
14275
0
        if (JS_IsException(op2)) {
14276
0
            JS_FreeValue(ctx, op1);
14277
0
            goto exception;
14278
0
        }
14279
0
        goto redo;
14280
0
    } else {
14281
        /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
14282
0
        if ((JS_IsHTMLDDA(ctx, op1) &&
14283
0
             (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
14284
0
            (JS_IsHTMLDDA(ctx, op2) &&
14285
0
             (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
14286
0
            res = TRUE;
14287
0
        } else {
14288
0
            res = FALSE;
14289
0
        }
14290
0
        JS_FreeValue(ctx, op1);
14291
0
        JS_FreeValue(ctx, op2);
14292
0
    }
14293
0
 done:
14294
0
    sp[-2] = JS_NewBool(ctx, res ^ is_neq);
14295
0
    return 0;
14296
0
 exception:
14297
0
    sp[-2] = JS_UNDEFINED;
14298
0
    sp[-1] = JS_UNDEFINED;
14299
0
    return -1;
14300
0
}
14301
14302
static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
14303
0
{
14304
0
    JSValue op1, op2;
14305
0
    uint32_t v1, v2, r;
14306
14307
0
    op1 = sp[-2];
14308
0
    op2 = sp[-1];
14309
0
    op1 = JS_ToNumericFree(ctx, op1);
14310
0
    if (JS_IsException(op1)) {
14311
0
        JS_FreeValue(ctx, op2);
14312
0
        goto exception;
14313
0
    }
14314
0
    op2 = JS_ToNumericFree(ctx, op2);
14315
0
    if (JS_IsException(op2)) {
14316
0
        JS_FreeValue(ctx, op1);
14317
0
        goto exception;
14318
0
    }
14319
    /* XXX: could forbid >>> in bignum mode */
14320
0
    if (!is_math_mode(ctx) &&
14321
0
        (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||
14322
0
         JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT)) {
14323
0
        JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>");
14324
0
        JS_FreeValue(ctx, op1);
14325
0
        JS_FreeValue(ctx, op2);
14326
0
        goto exception;
14327
0
    }
14328
    /* cannot give an exception */
14329
0
    JS_ToUint32Free(ctx, &v1, op1);
14330
0
    JS_ToUint32Free(ctx, &v2, op2);
14331
0
    r = v1 >> (v2 & 0x1f);
14332
0
    sp[-2] = JS_NewUint32(ctx, r);
14333
0
    return 0;
14334
0
 exception:
14335
0
    sp[-2] = JS_UNDEFINED;
14336
0
    sp[-1] = JS_UNDEFINED;
14337
0
    return -1;
14338
0
}
14339
14340
#ifdef CONFIG_BIGNUM
14341
static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
14342
                                       int64_t exponent)
14343
0
{
14344
0
    bf_t r_s, *r = &r_s;
14345
0
    double d;
14346
0
    int ret;
14347
14348
    /* always convert to Float64 */
14349
0
    bf_init(ctx->bf_ctx, r);
14350
0
    ret = bf_mul_pow_radix(r, a, 10, exponent,
14351
0
                           53, bf_set_exp_bits(11) | BF_RNDN |
14352
0
                           BF_FLAG_SUBNORMAL);
14353
0
    bf_get_float64(r, &d, BF_RNDN);
14354
0
    bf_delete(r);
14355
0
    if (ret & BF_ST_MEM_ERROR)
14356
0
        return JS_ThrowOutOfMemory(ctx);
14357
0
    else
14358
0
        return __JS_NewFloat64(ctx, d);
14359
0
}
14360
14361
static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
14362
0
{
14363
0
    bf_t a_s, *a, *r;
14364
0
    JSValue op1, op2, res;
14365
0
    int64_t e;
14366
0
    int ret;
14367
14368
0
    res = JS_NewBigFloat(ctx);
14369
0
    if (JS_IsException(res))
14370
0
        return -1;
14371
0
    r = JS_GetBigFloat(res);
14372
0
    op1 = sp[-2];
14373
0
    op2 = sp[-1];
14374
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
14375
0
    if (!a) {
14376
0
        JS_FreeValue(ctx, res);
14377
0
        return -1;
14378
0
    }
14379
0
    if (JS_IsBigInt(ctx, op2)) {
14380
0
        ret = JS_ToBigInt64(ctx, &e, op2);
14381
0
    } else {
14382
0
        ret = JS_ToInt64(ctx, &e, op2);
14383
0
    }
14384
0
    if (ret) {
14385
0
        if (a == &a_s)
14386
0
            bf_delete(a);
14387
0
        JS_FreeValue(ctx, res);
14388
0
        return -1;
14389
0
    }
14390
14391
0
    bf_mul_pow_radix(r, a, 10, e, ctx->fp_env.prec, ctx->fp_env.flags);
14392
0
    if (a == &a_s)
14393
0
        bf_delete(a);
14394
0
    JS_FreeValue(ctx, op1);
14395
0
    JS_FreeValue(ctx, op2);
14396
0
    sp[-2] = res;
14397
0
    return 0;
14398
0
}
14399
#endif
14400
14401
/* XXX: Should take JSValueConst arguments */
14402
static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
14403
                          JSStrictEqModeEnum eq_mode)
14404
0
{
14405
0
    BOOL res;
14406
0
    int tag1, tag2;
14407
0
    double d1, d2;
14408
14409
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14410
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14411
0
    switch(tag1) {
14412
0
    case JS_TAG_BOOL:
14413
0
        if (tag1 != tag2) {
14414
0
            res = FALSE;
14415
0
        } else {
14416
0
            res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
14417
0
            goto done_no_free;
14418
0
        }
14419
0
        break;
14420
0
    case JS_TAG_NULL:
14421
0
    case JS_TAG_UNDEFINED:
14422
0
        res = (tag1 == tag2);
14423
0
        break;
14424
0
    case JS_TAG_STRING:
14425
0
        {
14426
0
            JSString *p1, *p2;
14427
0
            if (tag1 != tag2) {
14428
0
                res = FALSE;
14429
0
            } else {
14430
0
                p1 = JS_VALUE_GET_STRING(op1);
14431
0
                p2 = JS_VALUE_GET_STRING(op2);
14432
0
                res = (js_string_compare(ctx, p1, p2) == 0);
14433
0
            }
14434
0
        }
14435
0
        break;
14436
0
    case JS_TAG_SYMBOL:
14437
0
        {
14438
0
            JSAtomStruct *p1, *p2;
14439
0
            if (tag1 != tag2) {
14440
0
                res = FALSE;
14441
0
            } else {
14442
0
                p1 = JS_VALUE_GET_PTR(op1);
14443
0
                p2 = JS_VALUE_GET_PTR(op2);
14444
0
                res = (p1 == p2);
14445
0
            }
14446
0
        }
14447
0
        break;
14448
0
    case JS_TAG_OBJECT:
14449
0
        if (tag1 != tag2)
14450
0
            res = FALSE;
14451
0
        else
14452
0
            res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2);
14453
0
        break;
14454
0
    case JS_TAG_INT:
14455
0
        d1 = JS_VALUE_GET_INT(op1);
14456
0
        if (tag2 == JS_TAG_INT) {
14457
0
            d2 = JS_VALUE_GET_INT(op2);
14458
0
            goto number_test;
14459
0
        } else if (tag2 == JS_TAG_FLOAT64) {
14460
0
            d2 = JS_VALUE_GET_FLOAT64(op2);
14461
0
            goto number_test;
14462
0
        } else {
14463
0
            res = FALSE;
14464
0
        }
14465
0
        break;
14466
0
    case JS_TAG_FLOAT64:
14467
0
        d1 = JS_VALUE_GET_FLOAT64(op1);
14468
0
        if (tag2 == JS_TAG_FLOAT64) {
14469
0
            d2 = JS_VALUE_GET_FLOAT64(op2);
14470
0
        } else if (tag2 == JS_TAG_INT) {
14471
0
            d2 = JS_VALUE_GET_INT(op2);
14472
0
        } else {
14473
0
            res = FALSE;
14474
0
            break;
14475
0
        }
14476
0
    number_test:
14477
0
        if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
14478
0
            JSFloat64Union u1, u2;
14479
            /* NaN is not always normalized, so this test is necessary */
14480
0
            if (isnan(d1) || isnan(d2)) {
14481
0
                res = isnan(d1) == isnan(d2);
14482
0
            } else if (eq_mode == JS_EQ_SAME_VALUE_ZERO) {
14483
0
                res = (d1 == d2); /* +0 == -0 */
14484
0
            } else {
14485
0
                u1.d = d1;
14486
0
                u2.d = d2;
14487
0
                res = (u1.u64 == u2.u64); /* +0 != -0 */
14488
0
            }
14489
0
        } else {
14490
0
            res = (d1 == d2); /* if NaN return false and +0 == -0 */
14491
0
        }
14492
0
        goto done_no_free;
14493
0
    case JS_TAG_BIG_INT:
14494
0
        {
14495
0
            bf_t a_s, *a, b_s, *b;
14496
0
            if (tag1 != tag2) {
14497
0
                res = FALSE;
14498
0
                break;
14499
0
            }
14500
0
            a = JS_ToBigFloat(ctx, &a_s, op1); /* cannot fail */
14501
0
            b = JS_ToBigFloat(ctx, &b_s, op2); /* cannot fail */
14502
0
            res = bf_cmp_eq(a, b);
14503
0
            if (a == &a_s)
14504
0
                bf_delete(a);
14505
0
            if (b == &b_s)
14506
0
                bf_delete(b);
14507
0
        }
14508
0
        break;
14509
0
#ifdef CONFIG_BIGNUM
14510
0
    case JS_TAG_BIG_FLOAT:
14511
0
        {
14512
0
            JSBigFloat *p1, *p2;
14513
0
            const bf_t *a, *b;
14514
0
            if (tag1 != tag2) {
14515
0
                res = FALSE;
14516
0
                break;
14517
0
            }
14518
0
            p1 = JS_VALUE_GET_PTR(op1);
14519
0
            p2 = JS_VALUE_GET_PTR(op2);
14520
0
            a = &p1->num;
14521
0
            b = &p2->num;
14522
0
            if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
14523
0
                if (eq_mode == JS_EQ_SAME_VALUE_ZERO &&
14524
0
                           a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO) {
14525
0
                    res = TRUE;
14526
0
                } else {
14527
0
                    res = (bf_cmp_full(a, b) == 0);
14528
0
                }
14529
0
            } else {
14530
0
                res = bf_cmp_eq(a, b);
14531
0
            }
14532
0
        }
14533
0
        break;
14534
0
    case JS_TAG_BIG_DECIMAL:
14535
0
        {
14536
0
            JSBigDecimal *p1, *p2;
14537
0
            const bfdec_t *a, *b;
14538
0
            if (tag1 != tag2) {
14539
0
                res = FALSE;
14540
0
                break;
14541
0
            }
14542
0
            p1 = JS_VALUE_GET_PTR(op1);
14543
0
            p2 = JS_VALUE_GET_PTR(op2);
14544
0
            a = &p1->num;
14545
0
            b = &p2->num;
14546
0
            res = bfdec_cmp_eq(a, b);
14547
0
        }
14548
0
        break;
14549
0
#endif
14550
0
    default:
14551
0
        res = FALSE;
14552
0
        break;
14553
0
    }
14554
0
    JS_FreeValue(ctx, op1);
14555
0
    JS_FreeValue(ctx, op2);
14556
0
 done_no_free:
14557
0
    return res;
14558
0
}
14559
14560
static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2)
14561
0
{
14562
0
    return js_strict_eq2(ctx,
14563
0
                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
14564
0
                         JS_EQ_STRICT);
14565
0
}
14566
14567
BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2)
14568
0
{
14569
0
    return js_strict_eq(ctx, op1, op2);
14570
0
}
14571
14572
static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2)
14573
0
{
14574
0
    return js_strict_eq2(ctx,
14575
0
                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
14576
0
                         JS_EQ_SAME_VALUE);
14577
0
}
14578
14579
BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2)
14580
0
{
14581
0
    return js_same_value(ctx, op1, op2);
14582
0
}
14583
14584
static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
14585
0
{
14586
0
    return js_strict_eq2(ctx,
14587
0
                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
14588
0
                         JS_EQ_SAME_VALUE_ZERO);
14589
0
}
14590
14591
BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
14592
0
{
14593
0
    return js_same_value_zero(ctx, op1, op2);
14594
0
}
14595
14596
static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp,
14597
                                       BOOL is_neq)
14598
0
{
14599
0
    BOOL res;
14600
0
    res = js_strict_eq2(ctx, sp[-2], sp[-1], JS_EQ_STRICT);
14601
0
    sp[-2] = JS_NewBool(ctx, res ^ is_neq);
14602
0
    return 0;
14603
0
}
14604
14605
static __exception int js_operator_in(JSContext *ctx, JSValue *sp)
14606
0
{
14607
0
    JSValue op1, op2;
14608
0
    JSAtom atom;
14609
0
    int ret;
14610
14611
0
    op1 = sp[-2];
14612
0
    op2 = sp[-1];
14613
14614
0
    if (JS_VALUE_GET_TAG(op2) != JS_TAG_OBJECT) {
14615
0
        JS_ThrowTypeError(ctx, "invalid 'in' operand");
14616
0
        return -1;
14617
0
    }
14618
0
    atom = JS_ValueToAtom(ctx, op1);
14619
0
    if (unlikely(atom == JS_ATOM_NULL))
14620
0
        return -1;
14621
0
    ret = JS_HasProperty(ctx, op2, atom);
14622
0
    JS_FreeAtom(ctx, atom);
14623
0
    if (ret < 0)
14624
0
        return -1;
14625
0
    JS_FreeValue(ctx, op1);
14626
0
    JS_FreeValue(ctx, op2);
14627
0
    sp[-2] = JS_NewBool(ctx, ret);
14628
0
    return 0;
14629
0
}
14630
14631
static __exception int js_operator_private_in(JSContext *ctx, JSValue *sp)
14632
0
{
14633
0
    JSValue op1, op2;
14634
0
    int ret;
14635
14636
0
    op1 = sp[-2]; /* object */
14637
0
    op2 = sp[-1]; /* field name or method function */
14638
14639
0
    if (JS_VALUE_GET_TAG(op1) != JS_TAG_OBJECT) {
14640
0
        JS_ThrowTypeError(ctx, "invalid 'in' operand");
14641
0
        return -1;
14642
0
    }
14643
0
    if (JS_IsObject(op2)) {
14644
        /* method: use the brand */
14645
0
        ret = JS_CheckBrand(ctx, op1, op2);
14646
0
        if (ret < 0)
14647
0
            return -1;
14648
0
    } else {
14649
0
        JSAtom atom;
14650
0
        JSObject *p;
14651
0
        JSShapeProperty *prs;
14652
0
        JSProperty *pr;
14653
        /* field */
14654
0
        atom = JS_ValueToAtom(ctx, op2);
14655
0
        if (unlikely(atom == JS_ATOM_NULL))
14656
0
            return -1;
14657
0
        p = JS_VALUE_GET_OBJ(op1);
14658
0
        prs = find_own_property(&pr, p, atom);
14659
0
        JS_FreeAtom(ctx, atom);
14660
0
        ret = (prs != NULL);
14661
0
    }
14662
0
    JS_FreeValue(ctx, op1);
14663
0
    JS_FreeValue(ctx, op2);
14664
0
    sp[-2] = JS_NewBool(ctx, ret);
14665
0
    return 0;
14666
0
}
14667
14668
static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj,
14669
                                         JSAtom atom)
14670
0
{
14671
0
    JSValue arr, val;
14672
0
    int ret;
14673
14674
0
    arr = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_unscopables);
14675
0
    if (JS_IsException(arr))
14676
0
        return -1;
14677
0
    ret = 0;
14678
0
    if (JS_IsObject(arr)) {
14679
0
        val = JS_GetProperty(ctx, arr, atom);
14680
0
        ret = JS_ToBoolFree(ctx, val);
14681
0
    }
14682
0
    JS_FreeValue(ctx, arr);
14683
0
    return ret;
14684
0
}
14685
14686
static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp)
14687
0
{
14688
0
    JSValue op1, op2;
14689
0
    BOOL ret;
14690
14691
0
    op1 = sp[-2];
14692
0
    op2 = sp[-1];
14693
0
    ret = JS_IsInstanceOf(ctx, op1, op2);
14694
0
    if (ret < 0)
14695
0
        return ret;
14696
0
    JS_FreeValue(ctx, op1);
14697
0
    JS_FreeValue(ctx, op2);
14698
0
    sp[-2] = JS_NewBool(ctx, ret);
14699
0
    return 0;
14700
0
}
14701
14702
static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1)
14703
0
{
14704
0
    JSAtom atom;
14705
0
    uint32_t tag;
14706
14707
0
    tag = JS_VALUE_GET_NORM_TAG(op1);
14708
0
    switch(tag) {
14709
0
    case JS_TAG_BIG_INT:
14710
0
        atom = JS_ATOM_bigint;
14711
0
        break;
14712
0
#ifdef CONFIG_BIGNUM
14713
0
    case JS_TAG_BIG_FLOAT:
14714
0
        atom = JS_ATOM_bigfloat;
14715
0
        break;
14716
0
    case JS_TAG_BIG_DECIMAL:
14717
0
        atom = JS_ATOM_bigdecimal;
14718
0
        break;
14719
0
#endif
14720
0
    case JS_TAG_INT:
14721
0
    case JS_TAG_FLOAT64:
14722
0
        atom = JS_ATOM_number;
14723
0
        break;
14724
0
    case JS_TAG_UNDEFINED:
14725
0
        atom = JS_ATOM_undefined;
14726
0
        break;
14727
0
    case JS_TAG_BOOL:
14728
0
        atom = JS_ATOM_boolean;
14729
0
        break;
14730
0
    case JS_TAG_STRING:
14731
0
        atom = JS_ATOM_string;
14732
0
        break;
14733
0
    case JS_TAG_OBJECT:
14734
0
        {
14735
0
            JSObject *p;
14736
0
            p = JS_VALUE_GET_OBJ(op1);
14737
0
            if (unlikely(p->is_HTMLDDA))
14738
0
                atom = JS_ATOM_undefined;
14739
0
            else if (JS_IsFunction(ctx, op1))
14740
0
                atom = JS_ATOM_function;
14741
0
            else
14742
0
                goto obj_type;
14743
0
        }
14744
0
        break;
14745
0
    case JS_TAG_NULL:
14746
0
    obj_type:
14747
0
        atom = JS_ATOM_object;
14748
0
        break;
14749
0
    case JS_TAG_SYMBOL:
14750
0
        atom = JS_ATOM_symbol;
14751
0
        break;
14752
0
    default:
14753
0
        atom = JS_ATOM_unknown;
14754
0
        break;
14755
0
    }
14756
0
    return atom;
14757
0
}
14758
14759
static __exception int js_operator_delete(JSContext *ctx, JSValue *sp)
14760
0
{
14761
0
    JSValue op1, op2;
14762
0
    JSAtom atom;
14763
0
    int ret;
14764
14765
0
    op1 = sp[-2];
14766
0
    op2 = sp[-1];
14767
0
    atom = JS_ValueToAtom(ctx, op2);
14768
0
    if (unlikely(atom == JS_ATOM_NULL))
14769
0
        return -1;
14770
0
    ret = JS_DeleteProperty(ctx, op1, atom, JS_PROP_THROW_STRICT);
14771
0
    JS_FreeAtom(ctx, atom);
14772
0
    if (unlikely(ret < 0))
14773
0
        return -1;
14774
0
    JS_FreeValue(ctx, op1);
14775
0
    JS_FreeValue(ctx, op2);
14776
0
    sp[-2] = JS_NewBool(ctx, ret);
14777
0
    return 0;
14778
0
}
14779
14780
static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val,
14781
                                   int argc, JSValueConst *argv)
14782
0
{
14783
0
    return JS_ThrowTypeError(ctx, "invalid property access");
14784
0
}
14785
14786
/* XXX: not 100% compatible, but mozilla seems to use a similar
14787
   implementation to ensure that caller in non strict mode does not
14788
   throw (ES5 compatibility) */
14789
static JSValue js_function_proto_caller(JSContext *ctx, JSValueConst this_val,
14790
                                        int argc, JSValueConst *argv)
14791
0
{
14792
0
    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
14793
0
    if (!b || (b->js_mode & JS_MODE_STRICT) || !b->has_prototype) {
14794
0
        return js_throw_type_error(ctx, this_val, 0, NULL);
14795
0
    }
14796
0
    return JS_UNDEFINED;
14797
0
}
14798
14799
static JSValue js_function_proto_fileName(JSContext *ctx,
14800
                                          JSValueConst this_val)
14801
0
{
14802
0
    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
14803
0
    if (b && b->has_debug) {
14804
0
        return JS_AtomToString(ctx, b->debug.filename);
14805
0
    }
14806
0
    return JS_UNDEFINED;
14807
0
}
14808
14809
static JSValue js_function_proto_lineNumber(JSContext *ctx,
14810
                                            JSValueConst this_val)
14811
0
{
14812
0
    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
14813
0
    if (b && b->has_debug) {
14814
0
        return JS_NewInt32(ctx, b->debug.line_num);
14815
0
    }
14816
0
    return JS_UNDEFINED;
14817
0
}
14818
14819
static int js_arguments_define_own_property(JSContext *ctx,
14820
                                            JSValueConst this_obj,
14821
                                            JSAtom prop, JSValueConst val,
14822
                                            JSValueConst getter, JSValueConst setter, int flags)
14823
0
{
14824
0
    JSObject *p;
14825
0
    uint32_t idx;
14826
0
    p = JS_VALUE_GET_OBJ(this_obj);
14827
    /* convert to normal array when redefining an existing numeric field */
14828
0
    if (p->fast_array && JS_AtomIsArrayIndex(ctx, &idx, prop) &&
14829
0
        idx < p->u.array.count) {
14830
0
        if (convert_fast_array_to_array(ctx, p))
14831
0
            return -1;
14832
0
    }
14833
    /* run the default define own property */
14834
0
    return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
14835
0
                             flags | JS_PROP_NO_EXOTIC);
14836
0
}
14837
14838
static const JSClassExoticMethods js_arguments_exotic_methods = {
14839
    .define_own_property = js_arguments_define_own_property,
14840
};
14841
14842
static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv)
14843
0
{
14844
0
    JSValue val, *tab;
14845
0
    JSProperty *pr;
14846
0
    JSObject *p;
14847
0
    int i;
14848
14849
0
    val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
14850
0
                                 JS_CLASS_ARGUMENTS);
14851
0
    if (JS_IsException(val))
14852
0
        return val;
14853
0
    p = JS_VALUE_GET_OBJ(val);
14854
14855
    /* add the length field (cannot fail) */
14856
0
    pr = add_property(ctx, p, JS_ATOM_length,
14857
0
                      JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
14858
0
    pr->u.value = JS_NewInt32(ctx, argc);
14859
14860
    /* initialize the fast array part */
14861
0
    tab = NULL;
14862
0
    if (argc > 0) {
14863
0
        tab = js_malloc(ctx, sizeof(tab[0]) * argc);
14864
0
        if (!tab) {
14865
0
            JS_FreeValue(ctx, val);
14866
0
            return JS_EXCEPTION;
14867
0
        }
14868
0
        for(i = 0; i < argc; i++) {
14869
0
            tab[i] = JS_DupValue(ctx, argv[i]);
14870
0
        }
14871
0
    }
14872
0
    p->u.array.u.values = tab;
14873
0
    p->u.array.count = argc;
14874
14875
0
    JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator,
14876
0
                           JS_DupValue(ctx, ctx->array_proto_values),
14877
0
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
14878
    /* add callee property to throw a TypeError in strict mode */
14879
0
    JS_DefineProperty(ctx, val, JS_ATOM_callee, JS_UNDEFINED,
14880
0
                      ctx->throw_type_error, ctx->throw_type_error,
14881
0
                      JS_PROP_HAS_GET | JS_PROP_HAS_SET);
14882
0
    return val;
14883
0
}
14884
14885
0
#define GLOBAL_VAR_OFFSET 0x40000000
14886
0
#define ARGUMENT_VAR_OFFSET 0x20000000
14887
14888
/* legacy arguments object: add references to the function arguments */
14889
static JSValue js_build_mapped_arguments(JSContext *ctx, int argc,
14890
                                         JSValueConst *argv,
14891
                                         JSStackFrame *sf, int arg_count)
14892
0
{
14893
0
    JSValue val;
14894
0
    JSProperty *pr;
14895
0
    JSObject *p;
14896
0
    int i;
14897
14898
0
    val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
14899
0
                                 JS_CLASS_MAPPED_ARGUMENTS);
14900
0
    if (JS_IsException(val))
14901
0
        return val;
14902
0
    p = JS_VALUE_GET_OBJ(val);
14903
14904
    /* add the length field (cannot fail) */
14905
0
    pr = add_property(ctx, p, JS_ATOM_length,
14906
0
                      JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
14907
0
    pr->u.value = JS_NewInt32(ctx, argc);
14908
14909
0
    for(i = 0; i < arg_count; i++) {
14910
0
        JSVarRef *var_ref;
14911
0
        var_ref = get_var_ref(ctx, sf, i, TRUE);
14912
0
        if (!var_ref)
14913
0
            goto fail;
14914
0
        pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF);
14915
0
        if (!pr) {
14916
0
            free_var_ref(ctx->rt, var_ref);
14917
0
            goto fail;
14918
0
        }
14919
0
        pr->u.var_ref = var_ref;
14920
0
    }
14921
14922
    /* the arguments not mapped to the arguments of the function can
14923
       be normal properties */
14924
0
    for(i = arg_count; i < argc; i++) {
14925
0
        if (JS_DefinePropertyValueUint32(ctx, val, i,
14926
0
                                         JS_DupValue(ctx, argv[i]),
14927
0
                                         JS_PROP_C_W_E) < 0)
14928
0
            goto fail;
14929
0
    }
14930
14931
0
    JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator,
14932
0
                           JS_DupValue(ctx, ctx->array_proto_values),
14933
0
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
14934
    /* callee returns this function in non strict mode */
14935
0
    JS_DefinePropertyValue(ctx, val, JS_ATOM_callee,
14936
0
                           JS_DupValue(ctx, ctx->rt->current_stack_frame->cur_func),
14937
0
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
14938
0
    return val;
14939
0
 fail:
14940
0
    JS_FreeValue(ctx, val);
14941
0
    return JS_EXCEPTION;
14942
0
}
14943
14944
static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *argv)
14945
0
{
14946
0
    JSValue val;
14947
0
    int i, ret;
14948
14949
0
    val = JS_NewArray(ctx);
14950
0
    if (JS_IsException(val))
14951
0
        return val;
14952
0
    for (i = first; i < argc; i++) {
14953
0
        ret = JS_DefinePropertyValueUint32(ctx, val, i - first,
14954
0
                                           JS_DupValue(ctx, argv[i]),
14955
0
                                           JS_PROP_C_W_E);
14956
0
        if (ret < 0) {
14957
0
            JS_FreeValue(ctx, val);
14958
0
            return JS_EXCEPTION;
14959
0
        }
14960
0
    }
14961
0
    return val;
14962
0
}
14963
14964
static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
14965
0
{
14966
0
    JSObject *p, *p1;
14967
0
    JSPropertyEnum *tab_atom;
14968
0
    int i;
14969
0
    JSValue enum_obj;
14970
0
    JSForInIterator *it;
14971
0
    uint32_t tag, tab_atom_count;
14972
14973
0
    tag = JS_VALUE_GET_TAG(obj);
14974
0
    if (tag != JS_TAG_OBJECT && tag != JS_TAG_NULL && tag != JS_TAG_UNDEFINED) {
14975
0
        obj = JS_ToObjectFree(ctx, obj);
14976
0
    }
14977
14978
0
    it = js_malloc(ctx, sizeof(*it));
14979
0
    if (!it) {
14980
0
        JS_FreeValue(ctx, obj);
14981
0
        return JS_EXCEPTION;
14982
0
    }
14983
0
    enum_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_FOR_IN_ITERATOR);
14984
0
    if (JS_IsException(enum_obj)) {
14985
0
        js_free(ctx, it);
14986
0
        JS_FreeValue(ctx, obj);
14987
0
        return JS_EXCEPTION;
14988
0
    }
14989
0
    it->is_array = FALSE;
14990
0
    it->obj = obj;
14991
0
    it->idx = 0;
14992
0
    it->tab_atom = NULL;
14993
0
    it->atom_count = 0;
14994
0
    it->in_prototype_chain = FALSE;
14995
0
    p1 = JS_VALUE_GET_OBJ(enum_obj);
14996
0
    p1->u.for_in_iterator = it;
14997
14998
0
    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
14999
0
        return enum_obj;
15000
15001
0
    p = JS_VALUE_GET_OBJ(obj);
15002
0
    if (p->fast_array) {
15003
0
        JSShape *sh;
15004
0
        JSShapeProperty *prs;
15005
        /* check that there are no enumerable normal fields */
15006
0
        sh = p->shape;
15007
0
        for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
15008
0
            if (prs->flags & JS_PROP_ENUMERABLE)
15009
0
                goto normal_case;
15010
0
        }
15011
        /* for fast arrays, we only store the number of elements */
15012
0
        it->is_array = TRUE;
15013
0
        it->atom_count = p->u.array.count;
15014
0
    } else {
15015
0
    normal_case:
15016
0
        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
15017
0
                                           JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
15018
0
            JS_FreeValue(ctx, enum_obj);
15019
0
            return JS_EXCEPTION;
15020
0
        }
15021
0
        it->tab_atom = tab_atom;
15022
0
        it->atom_count = tab_atom_count;
15023
0
    }
15024
0
    return enum_obj;
15025
0
}
15026
15027
/* obj -> enum_obj */
15028
static __exception int js_for_in_start(JSContext *ctx, JSValue *sp)
15029
0
{
15030
0
    sp[-1] = build_for_in_iterator(ctx, sp[-1]);
15031
0
    if (JS_IsException(sp[-1]))
15032
0
        return -1;
15033
0
    return 0;
15034
0
}
15035
15036
/* return -1 if exception, 0 if slow case, 1 if the enumeration is finished */
15037
static __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx,
15038
                                                              JSValueConst enum_obj)
15039
0
{
15040
0
    JSObject *p;
15041
0
    JSForInIterator *it;
15042
0
    JSPropertyEnum *tab_atom;
15043
0
    uint32_t tab_atom_count, i;
15044
0
    JSValue obj1;
15045
15046
0
    p = JS_VALUE_GET_OBJ(enum_obj);
15047
0
    it = p->u.for_in_iterator;
15048
15049
    /* check if there are enumerable properties in the prototype chain (fast path) */
15050
0
    obj1 = JS_DupValue(ctx, it->obj);
15051
0
    for(;;) {
15052
0
        obj1 = JS_GetPrototypeFree(ctx, obj1);
15053
0
        if (JS_IsNull(obj1))
15054
0
            break;
15055
0
        if (JS_IsException(obj1))
15056
0
            goto fail;
15057
0
        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
15058
0
                                           JS_VALUE_GET_OBJ(obj1),
15059
0
                                           JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
15060
0
            JS_FreeValue(ctx, obj1);
15061
0
            goto fail;
15062
0
        }
15063
0
        js_free_prop_enum(ctx, tab_atom, tab_atom_count);
15064
0
        if (tab_atom_count != 0) {
15065
0
            JS_FreeValue(ctx, obj1);
15066
0
            goto slow_path;
15067
0
        }
15068
        /* must check for timeout to avoid infinite loop */
15069
0
        if (js_poll_interrupts(ctx)) {
15070
0
            JS_FreeValue(ctx, obj1);
15071
0
            goto fail;
15072
0
        }
15073
0
    }
15074
0
    JS_FreeValue(ctx, obj1);
15075
0
    return 1;
15076
15077
0
 slow_path:
15078
    /* add the visited properties, even if they are not enumerable */
15079
0
    if (it->is_array) {
15080
0
        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
15081
0
                                           JS_VALUE_GET_OBJ(it->obj),
15082
0
                                           JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
15083
0
            goto fail;
15084
0
        }
15085
0
        it->is_array = FALSE;
15086
0
        it->tab_atom = tab_atom;
15087
0
        it->atom_count = tab_atom_count;
15088
0
    }
15089
15090
0
    for(i = 0; i < it->atom_count; i++) {
15091
0
        if (JS_DefinePropertyValue(ctx, enum_obj, it->tab_atom[i].atom, JS_NULL, JS_PROP_ENUMERABLE) < 0)
15092
0
            goto fail;
15093
0
    }
15094
0
    return 0;
15095
0
 fail:
15096
0
    return -1;
15097
0
}
15098
15099
/* enum_obj -> enum_obj value done */
15100
static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
15101
0
{
15102
0
    JSValueConst enum_obj;
15103
0
    JSObject *p;
15104
0
    JSAtom prop;
15105
0
    JSForInIterator *it;
15106
0
    JSPropertyEnum *tab_atom;
15107
0
    uint32_t tab_atom_count;
15108
0
    int ret;
15109
15110
0
    enum_obj = sp[-1];
15111
    /* fail safe */
15112
0
    if (JS_VALUE_GET_TAG(enum_obj) != JS_TAG_OBJECT)
15113
0
        goto done;
15114
0
    p = JS_VALUE_GET_OBJ(enum_obj);
15115
0
    if (p->class_id != JS_CLASS_FOR_IN_ITERATOR)
15116
0
        goto done;
15117
0
    it = p->u.for_in_iterator;
15118
15119
0
    for(;;) {
15120
0
        if (it->idx >= it->atom_count) {
15121
0
            if (JS_IsNull(it->obj) || JS_IsUndefined(it->obj))
15122
0
                goto done; /* not an object */
15123
            /* no more property in the current object: look in the prototype */
15124
0
            if (!it->in_prototype_chain) {
15125
0
                ret = js_for_in_prepare_prototype_chain_enum(ctx, enum_obj);
15126
0
                if (ret < 0)
15127
0
                    return -1;
15128
0
                if (ret)
15129
0
                    goto done;
15130
0
                it->in_prototype_chain = TRUE;
15131
0
            }
15132
0
            it->obj = JS_GetPrototypeFree(ctx, it->obj);
15133
0
            if (JS_IsException(it->obj))
15134
0
                return -1;
15135
0
            if (JS_IsNull(it->obj))
15136
0
                goto done; /* no more prototype */
15137
15138
            /* must check for timeout to avoid infinite loop */
15139
0
            if (js_poll_interrupts(ctx))
15140
0
                return -1;
15141
15142
0
            if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
15143
0
                                               JS_VALUE_GET_OBJ(it->obj),
15144
0
                                               JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
15145
0
                return -1;
15146
0
            }
15147
0
            js_free_prop_enum(ctx, it->tab_atom, it->atom_count);
15148
0
            it->tab_atom = tab_atom;
15149
0
            it->atom_count = tab_atom_count;
15150
0
            it->idx = 0;
15151
0
        } else {
15152
0
            if (it->is_array) {
15153
0
                prop = __JS_AtomFromUInt32(it->idx);
15154
0
                it->idx++;
15155
0
            } else {
15156
0
                BOOL is_enumerable;
15157
0
                prop = it->tab_atom[it->idx].atom;
15158
0
                is_enumerable = it->tab_atom[it->idx].is_enumerable;
15159
0
                it->idx++;
15160
0
                if (it->in_prototype_chain) {
15161
                    /* slow case: we are in the prototype chain */
15162
0
                    ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(enum_obj), prop);
15163
0
                    if (ret < 0)
15164
0
                        return ret;
15165
0
                    if (ret)
15166
0
                        continue; /* already visited */
15167
                    /* add to the visited property list */
15168
0
                    if (JS_DefinePropertyValue(ctx, enum_obj, prop, JS_NULL,
15169
0
                                               JS_PROP_ENUMERABLE) < 0)
15170
0
                        return -1;
15171
0
                }
15172
0
                if (!is_enumerable)
15173
0
                    continue;
15174
0
            }
15175
            /* check if the property was deleted */
15176
0
            ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(it->obj), prop);
15177
0
            if (ret < 0)
15178
0
                return ret;
15179
0
            if (ret)
15180
0
                break;
15181
0
        }
15182
0
    }
15183
    /* return the property */
15184
0
    sp[0] = JS_AtomToValue(ctx, prop);
15185
0
    sp[1] = JS_FALSE;
15186
0
    return 0;
15187
0
 done:
15188
    /* return the end */
15189
0
    sp[0] = JS_UNDEFINED;
15190
0
    sp[1] = JS_TRUE;
15191
0
    return 0;
15192
0
}
15193
15194
static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj,
15195
                               JSValueConst method)
15196
0
{
15197
0
    JSValue enum_obj;
15198
15199
0
    enum_obj = JS_Call(ctx, method, obj, 0, NULL);
15200
0
    if (JS_IsException(enum_obj))
15201
0
        return enum_obj;
15202
0
    if (!JS_IsObject(enum_obj)) {
15203
0
        JS_FreeValue(ctx, enum_obj);
15204
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
15205
0
    }
15206
0
    return enum_obj;
15207
0
}
15208
15209
static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, BOOL is_async)
15210
0
{
15211
0
    JSValue method, ret, sync_iter;
15212
15213
0
    if (is_async) {
15214
0
        method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_asyncIterator);
15215
0
        if (JS_IsException(method))
15216
0
            return method;
15217
0
        if (JS_IsUndefined(method) || JS_IsNull(method)) {
15218
0
            method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
15219
0
            if (JS_IsException(method))
15220
0
                return method;
15221
0
            sync_iter = JS_GetIterator2(ctx, obj, method);
15222
0
            JS_FreeValue(ctx, method);
15223
0
            if (JS_IsException(sync_iter))
15224
0
                return sync_iter;
15225
0
            ret = JS_CreateAsyncFromSyncIterator(ctx, sync_iter);
15226
0
            JS_FreeValue(ctx, sync_iter);
15227
0
            return ret;
15228
0
        }
15229
0
    } else {
15230
0
        method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
15231
0
        if (JS_IsException(method))
15232
0
            return method;
15233
0
    }
15234
0
    if (!JS_IsFunction(ctx, method)) {
15235
0
        JS_FreeValue(ctx, method);
15236
0
        return JS_ThrowTypeError(ctx, "value is not iterable");
15237
0
    }
15238
0
    ret = JS_GetIterator2(ctx, obj, method);
15239
0
    JS_FreeValue(ctx, method);
15240
0
    return ret;
15241
0
}
15242
15243
/* return *pdone = 2 if the iterator object is not parsed */
15244
static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj,
15245
                                JSValueConst method,
15246
                                int argc, JSValueConst *argv, int *pdone)
15247
0
{
15248
0
    JSValue obj;
15249
15250
    /* fast path for the built-in iterators (avoid creating the
15251
       intermediate result object) */
15252
0
    if (JS_IsObject(method)) {
15253
0
        JSObject *p = JS_VALUE_GET_OBJ(method);
15254
0
        if (p->class_id == JS_CLASS_C_FUNCTION &&
15255
0
            p->u.cfunc.cproto == JS_CFUNC_iterator_next) {
15256
0
            JSCFunctionType func;
15257
0
            JSValueConst args[1];
15258
15259
            /* in case the function expects one argument */
15260
0
            if (argc == 0) {
15261
0
                args[0] = JS_UNDEFINED;
15262
0
                argv = args;
15263
0
            }
15264
0
            func = p->u.cfunc.c_function;
15265
0
            return func.iterator_next(ctx, enum_obj, argc, argv,
15266
0
                                      pdone, p->u.cfunc.magic);
15267
0
        }
15268
0
    }
15269
0
    obj = JS_Call(ctx, method, enum_obj, argc, argv);
15270
0
    if (JS_IsException(obj))
15271
0
        goto fail;
15272
0
    if (!JS_IsObject(obj)) {
15273
0
        JS_FreeValue(ctx, obj);
15274
0
        JS_ThrowTypeError(ctx, "iterator must return an object");
15275
0
        goto fail;
15276
0
    }
15277
0
    *pdone = 2;
15278
0
    return obj;
15279
0
 fail:
15280
0
    *pdone = FALSE;
15281
0
    return JS_EXCEPTION;
15282
0
}
15283
15284
static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj,
15285
                               JSValueConst method,
15286
                               int argc, JSValueConst *argv, BOOL *pdone)
15287
0
{
15288
0
    JSValue obj, value, done_val;
15289
0
    int done;
15290
15291
0
    obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done);
15292
0
    if (JS_IsException(obj))
15293
0
        goto fail;
15294
0
    if (done != 2) {
15295
0
        *pdone = done;
15296
0
        return obj;
15297
0
    } else {
15298
0
        done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
15299
0
        if (JS_IsException(done_val))
15300
0
            goto fail;
15301
0
        *pdone = JS_ToBoolFree(ctx, done_val);
15302
0
        value = JS_UNDEFINED;
15303
0
        if (!*pdone) {
15304
0
            value = JS_GetProperty(ctx, obj, JS_ATOM_value);
15305
0
        }
15306
0
        JS_FreeValue(ctx, obj);
15307
0
        return value;
15308
0
    }
15309
0
 fail:
15310
0
    JS_FreeValue(ctx, obj);
15311
0
    *pdone = FALSE;
15312
0
    return JS_EXCEPTION;
15313
0
}
15314
15315
/* return < 0 in case of exception */
15316
static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
15317
                            BOOL is_exception_pending)
15318
0
{
15319
0
    JSValue method, ret, ex_obj;
15320
0
    int res;
15321
15322
0
    if (is_exception_pending) {
15323
0
        ex_obj = ctx->rt->current_exception;
15324
0
        ctx->rt->current_exception = JS_NULL;
15325
0
        res = -1;
15326
0
    } else {
15327
0
        ex_obj = JS_UNDEFINED;
15328
0
        res = 0;
15329
0
    }
15330
0
    method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return);
15331
0
    if (JS_IsException(method)) {
15332
0
        res = -1;
15333
0
        goto done;
15334
0
    }
15335
0
    if (JS_IsUndefined(method) || JS_IsNull(method)) {
15336
0
        goto done;
15337
0
    }
15338
0
    ret = JS_CallFree(ctx, method, enum_obj, 0, NULL);
15339
0
    if (!is_exception_pending) {
15340
0
        if (JS_IsException(ret)) {
15341
0
            res = -1;
15342
0
        } else if (!JS_IsObject(ret)) {
15343
0
            JS_ThrowTypeErrorNotAnObject(ctx);
15344
0
            res = -1;
15345
0
        }
15346
0
    }
15347
0
    JS_FreeValue(ctx, ret);
15348
0
 done:
15349
0
    if (is_exception_pending) {
15350
0
        JS_Throw(ctx, ex_obj);
15351
0
    }
15352
0
    return res;
15353
0
}
15354
15355
/* obj -> enum_rec (3 slots) */
15356
static __exception int js_for_of_start(JSContext *ctx, JSValue *sp,
15357
                                       BOOL is_async)
15358
0
{
15359
0
    JSValue op1, obj, method;
15360
0
    op1 = sp[-1];
15361
0
    obj = JS_GetIterator(ctx, op1, is_async);
15362
0
    if (JS_IsException(obj))
15363
0
        return -1;
15364
0
    JS_FreeValue(ctx, op1);
15365
0
    sp[-1] = obj;
15366
0
    method = JS_GetProperty(ctx, obj, JS_ATOM_next);
15367
0
    if (JS_IsException(method))
15368
0
        return -1;
15369
0
    sp[0] = method;
15370
0
    return 0;
15371
0
}
15372
15373
/* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset'
15374
   objs. If 'done' is true or in case of exception, 'enum_rec' is set
15375
   to undefined. If 'done' is true, 'value' is always set to
15376
   undefined. */
15377
static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
15378
0
{
15379
0
    JSValue value = JS_UNDEFINED;
15380
0
    int done = 1;
15381
15382
0
    if (likely(!JS_IsUndefined(sp[offset]))) {
15383
0
        value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done);
15384
0
        if (JS_IsException(value))
15385
0
            done = -1;
15386
0
        if (done) {
15387
            /* value is JS_UNDEFINED or JS_EXCEPTION */
15388
            /* replace the iteration object with undefined */
15389
0
            JS_FreeValue(ctx, sp[offset]);
15390
0
            sp[offset] = JS_UNDEFINED;
15391
0
            if (done < 0) {
15392
0
                return -1;
15393
0
            } else {
15394
0
                JS_FreeValue(ctx, value);
15395
0
                value = JS_UNDEFINED;
15396
0
            }
15397
0
        }
15398
0
    }
15399
0
    sp[0] = value;
15400
0
    sp[1] = JS_NewBool(ctx, done);
15401
0
    return 0;
15402
0
}
15403
15404
static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj,
15405
                                           BOOL *pdone)
15406
0
{
15407
0
    JSValue done_val, value;
15408
0
    BOOL done;
15409
0
    done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
15410
0
    if (JS_IsException(done_val))
15411
0
        goto fail;
15412
0
    done = JS_ToBoolFree(ctx, done_val);
15413
0
    value = JS_GetProperty(ctx, obj, JS_ATOM_value);
15414
0
    if (JS_IsException(value))
15415
0
        goto fail;
15416
0
    *pdone = done;
15417
0
    return value;
15418
0
 fail:
15419
0
    *pdone = FALSE;
15420
0
    return JS_EXCEPTION;
15421
0
}
15422
15423
static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)
15424
0
{
15425
0
    JSValue obj, value;
15426
0
    BOOL done;
15427
0
    obj = sp[-1];
15428
0
    if (!JS_IsObject(obj)) {
15429
0
        JS_ThrowTypeError(ctx, "iterator must return an object");
15430
0
        return -1;
15431
0
    }
15432
0
    value = JS_IteratorGetCompleteValue(ctx, obj, &done);
15433
0
    if (JS_IsException(value))
15434
0
        return -1;
15435
0
    JS_FreeValue(ctx, obj);
15436
0
    sp[-1] = value;
15437
0
    sp[0] = JS_NewBool(ctx, done);
15438
0
    return 0;
15439
0
}
15440
15441
static JSValue js_create_iterator_result(JSContext *ctx,
15442
                                         JSValue val,
15443
                                         BOOL done)
15444
0
{
15445
0
    JSValue obj;
15446
0
    obj = JS_NewObject(ctx);
15447
0
    if (JS_IsException(obj)) {
15448
0
        JS_FreeValue(ctx, val);
15449
0
        return obj;
15450
0
    }
15451
0
    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_value,
15452
0
                               val, JS_PROP_C_W_E) < 0) {
15453
0
        goto fail;
15454
0
    }
15455
0
    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done,
15456
0
                               JS_NewBool(ctx, done), JS_PROP_C_W_E) < 0) {
15457
0
    fail:
15458
0
        JS_FreeValue(ctx, obj);
15459
0
        return JS_EXCEPTION;
15460
0
    }
15461
0
    return obj;
15462
0
}
15463
15464
static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
15465
                                      int argc, JSValueConst *argv,
15466
                                      BOOL *pdone, int magic);
15467
15468
static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
15469
                                        int argc, JSValueConst *argv, int magic);
15470
15471
static BOOL js_is_fast_array(JSContext *ctx, JSValueConst obj)
15472
0
{
15473
    /* Try and handle fast arrays explicitly */
15474
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
15475
0
        JSObject *p = JS_VALUE_GET_OBJ(obj);
15476
0
        if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
15477
0
            return TRUE;
15478
0
        }
15479
0
    }
15480
0
    return FALSE;
15481
0
}
15482
15483
/* Access an Array's internal JSValue array if available */
15484
static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
15485
                              JSValue **arrpp, uint32_t *countp)
15486
0
{
15487
    /* Try and handle fast arrays explicitly */
15488
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
15489
0
        JSObject *p = JS_VALUE_GET_OBJ(obj);
15490
0
        if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
15491
0
            *countp = p->u.array.count;
15492
0
            *arrpp = p->u.array.u.values;
15493
0
            return TRUE;
15494
0
        }
15495
0
    }
15496
0
    return FALSE;
15497
0
}
15498
15499
static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp)
15500
0
{
15501
0
    JSValue iterator, enumobj, method, value;
15502
0
    int is_array_iterator;
15503
0
    JSValue *arrp;
15504
0
    uint32_t i, count32, pos;
15505
15506
0
    if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) {
15507
0
        JS_ThrowInternalError(ctx, "invalid index for append");
15508
0
        return -1;
15509
0
    }
15510
15511
0
    pos = JS_VALUE_GET_INT(sp[-2]);
15512
15513
    /* XXX: further optimisations:
15514
       - use ctx->array_proto_values?
15515
       - check if array_iterator_prototype next method is built-in and
15516
         avoid constructing actual iterator object?
15517
       - build this into js_for_of_start and use in all `for (x of o)` loops
15518
     */
15519
0
    iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator);
15520
0
    if (JS_IsException(iterator))
15521
0
        return -1;
15522
0
    is_array_iterator = JS_IsCFunction(ctx, iterator,
15523
0
                                       (JSCFunction *)js_create_array_iterator,
15524
0
                                       JS_ITERATOR_KIND_VALUE);
15525
0
    JS_FreeValue(ctx, iterator);
15526
15527
0
    enumobj = JS_GetIterator(ctx, sp[-1], FALSE);
15528
0
    if (JS_IsException(enumobj))
15529
0
        return -1;
15530
0
    method = JS_GetProperty(ctx, enumobj, JS_ATOM_next);
15531
0
    if (JS_IsException(method)) {
15532
0
        JS_FreeValue(ctx, enumobj);
15533
0
        return -1;
15534
0
    }
15535
0
    if (is_array_iterator
15536
0
    &&  JS_IsCFunction(ctx, method, (JSCFunction *)js_array_iterator_next, 0)
15537
0
    &&  js_get_fast_array(ctx, sp[-1], &arrp, &count32)) {
15538
0
        uint32_t len;
15539
0
        if (js_get_length32(ctx, &len, sp[-1]))
15540
0
            goto exception;
15541
        /* if len > count32, the elements >= count32 might be read in
15542
           the prototypes and might have side effects */
15543
0
        if (len != count32)
15544
0
            goto general_case;
15545
        /* Handle fast arrays explicitly */
15546
0
        for (i = 0; i < count32; i++) {
15547
0
            if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++,
15548
0
                                             JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0)
15549
0
                goto exception;
15550
0
        }
15551
0
    } else {
15552
0
    general_case:
15553
0
        for (;;) {
15554
0
            BOOL done;
15555
0
            value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done);
15556
0
            if (JS_IsException(value))
15557
0
                goto exception;
15558
0
            if (done) {
15559
                /* value is JS_UNDEFINED */
15560
0
                break;
15561
0
            }
15562
0
            if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0)
15563
0
                goto exception;
15564
0
        }
15565
0
    }
15566
    /* Note: could raise an error if too many elements */
15567
0
    sp[-2] = JS_NewInt32(ctx, pos);
15568
0
    JS_FreeValue(ctx, enumobj);
15569
0
    JS_FreeValue(ctx, method);
15570
0
    return 0;
15571
15572
0
exception:
15573
0
    JS_IteratorClose(ctx, enumobj, TRUE);
15574
0
    JS_FreeValue(ctx, enumobj);
15575
0
    JS_FreeValue(ctx, method);
15576
0
    return -1;
15577
0
}
15578
15579
static __exception int JS_CopyDataProperties(JSContext *ctx,
15580
                                             JSValueConst target,
15581
                                             JSValueConst source,
15582
                                             JSValueConst excluded,
15583
                                             BOOL setprop)
15584
0
{
15585
0
    JSPropertyEnum *tab_atom;
15586
0
    JSValue val;
15587
0
    uint32_t i, tab_atom_count;
15588
0
    JSObject *p;
15589
0
    JSObject *pexcl = NULL;
15590
0
    int ret, gpn_flags;
15591
0
    JSPropertyDescriptor desc;
15592
0
    BOOL is_enumerable;
15593
15594
0
    if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT)
15595
0
        return 0;
15596
15597
0
    if (JS_VALUE_GET_TAG(excluded) == JS_TAG_OBJECT)
15598
0
        pexcl = JS_VALUE_GET_OBJ(excluded);
15599
15600
0
    p = JS_VALUE_GET_OBJ(source);
15601
15602
0
    gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY;
15603
0
    if (p->is_exotic) {
15604
0
        const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
15605
        /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it
15606
           introduces a visible change */
15607
0
        if (em && em->get_own_property_names) {
15608
0
            gpn_flags &= ~JS_GPN_ENUM_ONLY;
15609
0
        }
15610
0
    }
15611
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
15612
0
                                       gpn_flags))
15613
0
        return -1;
15614
15615
0
    for (i = 0; i < tab_atom_count; i++) {
15616
0
        if (pexcl) {
15617
0
            ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom);
15618
0
            if (ret) {
15619
0
                if (ret < 0)
15620
0
                    goto exception;
15621
0
                continue;
15622
0
            }
15623
0
        }
15624
0
        if (!(gpn_flags & JS_GPN_ENUM_ONLY)) {
15625
            /* test if the property is enumerable */
15626
0
            ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom);
15627
0
            if (ret < 0)
15628
0
                goto exception;
15629
0
            if (!ret)
15630
0
                continue;
15631
0
            is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0;
15632
0
            js_free_desc(ctx, &desc);
15633
0
            if (!is_enumerable)
15634
0
                continue;
15635
0
        }
15636
0
        val = JS_GetProperty(ctx, source, tab_atom[i].atom);
15637
0
        if (JS_IsException(val))
15638
0
            goto exception;
15639
0
        if (setprop)
15640
0
            ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val);
15641
0
        else
15642
0
            ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val,
15643
0
                                         JS_PROP_C_W_E);
15644
0
        if (ret < 0)
15645
0
            goto exception;
15646
0
    }
15647
0
    js_free_prop_enum(ctx, tab_atom, tab_atom_count);
15648
0
    return 0;
15649
0
 exception:
15650
0
    js_free_prop_enum(ctx, tab_atom, tab_atom_count);
15651
0
    return -1;
15652
0
}
15653
15654
/* only valid inside C functions */
15655
static JSValueConst JS_GetActiveFunction(JSContext *ctx)
15656
0
{
15657
0
    return ctx->rt->current_stack_frame->cur_func;
15658
0
}
15659
15660
static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
15661
                             int var_idx, BOOL is_arg)
15662
0
{
15663
0
    JSVarRef *var_ref;
15664
0
    struct list_head *el;
15665
15666
0
    list_for_each(el, &sf->var_ref_list) {
15667
0
        var_ref = list_entry(el, JSVarRef, var_ref_link);
15668
0
        if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) {
15669
0
            var_ref->header.ref_count++;
15670
0
            return var_ref;
15671
0
        }
15672
0
    }
15673
    /* create a new one */
15674
0
    var_ref = js_malloc(ctx, sizeof(JSVarRef));
15675
0
    if (!var_ref)
15676
0
        return NULL;
15677
0
    var_ref->header.ref_count = 1;
15678
0
    add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
15679
0
    var_ref->is_detached = FALSE;
15680
0
    var_ref->is_arg = is_arg;
15681
0
    var_ref->var_idx = var_idx;
15682
0
    list_add_tail(&var_ref->var_ref_link, &sf->var_ref_list);
15683
0
    if (sf->js_mode & JS_MODE_ASYNC) {
15684
        /* The stack frame is detached and may be destroyed at any
15685
           time so its reference count must be increased. Calling
15686
           close_var_refs() when destroying the stack frame is not
15687
           possible because it would change the graph between the GC
15688
           objects. Another solution could be to temporarily detach
15689
           the JSVarRef of async functions during the GC. It would
15690
           have the advantage of allowing the release of unused stack
15691
           frames in a cycle. */
15692
0
        var_ref->async_func = container_of(sf, JSAsyncFunctionState, frame);
15693
0
        var_ref->async_func->header.ref_count++;
15694
0
    } else {
15695
0
        var_ref->async_func = NULL;
15696
0
    }
15697
0
    if (is_arg)
15698
0
        var_ref->pvalue = &sf->arg_buf[var_idx];
15699
0
    else
15700
0
        var_ref->pvalue = &sf->var_buf[var_idx];
15701
0
    return var_ref;
15702
0
}
15703
15704
static JSValue js_closure2(JSContext *ctx, JSValue func_obj,
15705
                           JSFunctionBytecode *b,
15706
                           JSVarRef **cur_var_refs,
15707
                           JSStackFrame *sf)
15708
24
{
15709
24
    JSObject *p;
15710
24
    JSVarRef **var_refs;
15711
24
    int i;
15712
15713
24
    p = JS_VALUE_GET_OBJ(func_obj);
15714
24
    p->u.func.function_bytecode = b;
15715
24
    p->u.func.home_object = NULL;
15716
24
    p->u.func.var_refs = NULL;
15717
24
    if (b->closure_var_count) {
15718
0
        var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
15719
0
        if (!var_refs)
15720
0
            goto fail;
15721
0
        p->u.func.var_refs = var_refs;
15722
0
        for(i = 0; i < b->closure_var_count; i++) {
15723
0
            JSClosureVar *cv = &b->closure_var[i];
15724
0
            JSVarRef *var_ref;
15725
0
            if (cv->is_local) {
15726
                /* reuse the existing variable reference if it already exists */
15727
0
                var_ref = get_var_ref(ctx, sf, cv->var_idx, cv->is_arg);
15728
0
                if (!var_ref)
15729
0
                    goto fail;
15730
0
            } else {
15731
0
                var_ref = cur_var_refs[cv->var_idx];
15732
0
                var_ref->header.ref_count++;
15733
0
            }
15734
0
            var_refs[i] = var_ref;
15735
0
        }
15736
0
    }
15737
24
    return func_obj;
15738
0
 fail:
15739
    /* bfunc is freed when func_obj is freed */
15740
0
    JS_FreeValue(ctx, func_obj);
15741
0
    return JS_EXCEPTION;
15742
24
}
15743
15744
static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque)
15745
0
{
15746
0
    JSValue obj, this_val;
15747
0
    int ret;
15748
15749
0
    this_val = JS_MKPTR(JS_TAG_OBJECT, p);
15750
0
    obj = JS_NewObject(ctx);
15751
0
    if (JS_IsException(obj))
15752
0
        return JS_EXCEPTION;
15753
0
    set_cycle_flag(ctx, obj);
15754
0
    set_cycle_flag(ctx, this_val);
15755
0
    ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor,
15756
0
                                 JS_DupValue(ctx, this_val),
15757
0
                                 JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
15758
0
    if (ret < 0) {
15759
0
        JS_FreeValue(ctx, obj);
15760
0
        return JS_EXCEPTION;
15761
0
    }
15762
0
    return obj;
15763
0
}
15764
15765
static const uint16_t func_kind_to_class_id[] = {
15766
    [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION,
15767
    [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION,
15768
    [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION,
15769
    [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION,
15770
};
15771
15772
static JSValue js_closure(JSContext *ctx, JSValue bfunc,
15773
                          JSVarRef **cur_var_refs,
15774
                          JSStackFrame *sf)
15775
24
{
15776
24
    JSFunctionBytecode *b;
15777
24
    JSValue func_obj;
15778
24
    JSAtom name_atom;
15779
15780
24
    b = JS_VALUE_GET_PTR(bfunc);
15781
24
    func_obj = JS_NewObjectClass(ctx, func_kind_to_class_id[b->func_kind]);
15782
24
    if (JS_IsException(func_obj)) {
15783
0
        JS_FreeValue(ctx, bfunc);
15784
0
        return JS_EXCEPTION;
15785
0
    }
15786
24
    func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf);
15787
24
    if (JS_IsException(func_obj)) {
15788
        /* bfunc has been freed */
15789
0
        goto fail;
15790
0
    }
15791
24
    name_atom = b->func_name;
15792
24
    if (name_atom == JS_ATOM_NULL)
15793
0
        name_atom = JS_ATOM_empty_string;
15794
24
    js_function_set_properties(ctx, func_obj, name_atom,
15795
24
                               b->defined_arg_count);
15796
15797
24
    if (b->func_kind & JS_FUNC_GENERATOR) {
15798
0
        JSValue proto;
15799
0
        int proto_class_id;
15800
        /* generators have a prototype field which is used as
15801
           prototype for the generator object */
15802
0
        if (b->func_kind == JS_FUNC_ASYNC_GENERATOR)
15803
0
            proto_class_id = JS_CLASS_ASYNC_GENERATOR;
15804
0
        else
15805
0
            proto_class_id = JS_CLASS_GENERATOR;
15806
0
        proto = JS_NewObjectProto(ctx, ctx->class_proto[proto_class_id]);
15807
0
        if (JS_IsException(proto))
15808
0
            goto fail;
15809
0
        JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, proto,
15810
0
                               JS_PROP_WRITABLE);
15811
24
    } else if (b->has_prototype) {
15812
        /* add the 'prototype' property: delay instantiation to avoid
15813
           creating cycles for every javascript function. The prototype
15814
           object is created on the fly when first accessed */
15815
0
        JS_SetConstructorBit(ctx, func_obj, TRUE);
15816
0
        JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype,
15817
0
                                  JS_AUTOINIT_ID_PROTOTYPE, NULL,
15818
0
                                  JS_PROP_WRITABLE);
15819
0
    }
15820
24
    return func_obj;
15821
0
 fail:
15822
    /* bfunc is freed when func_obj is freed */
15823
0
    JS_FreeValue(ctx, func_obj);
15824
0
    return JS_EXCEPTION;
15825
24
}
15826
15827
0
#define JS_DEFINE_CLASS_HAS_HERITAGE     (1 << 0)
15828
15829
static int js_op_define_class(JSContext *ctx, JSValue *sp,
15830
                              JSAtom class_name, int class_flags,
15831
                              JSVarRef **cur_var_refs,
15832
                              JSStackFrame *sf, BOOL is_computed_name)
15833
0
{
15834
0
    JSValue bfunc, parent_class, proto = JS_UNDEFINED;
15835
0
    JSValue ctor = JS_UNDEFINED, parent_proto = JS_UNDEFINED;
15836
0
    JSFunctionBytecode *b;
15837
15838
0
    parent_class = sp[-2];
15839
0
    bfunc = sp[-1];
15840
15841
0
    if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) {
15842
0
        if (JS_IsNull(parent_class)) {
15843
0
            parent_proto = JS_NULL;
15844
0
            parent_class = JS_DupValue(ctx, ctx->function_proto);
15845
0
        } else {
15846
0
            if (!JS_IsConstructor(ctx, parent_class)) {
15847
0
                JS_ThrowTypeError(ctx, "parent class must be constructor");
15848
0
                goto fail;
15849
0
            }
15850
0
            parent_proto = JS_GetProperty(ctx, parent_class, JS_ATOM_prototype);
15851
0
            if (JS_IsException(parent_proto))
15852
0
                goto fail;
15853
0
            if (!JS_IsNull(parent_proto) && !JS_IsObject(parent_proto)) {
15854
0
                JS_ThrowTypeError(ctx, "parent prototype must be an object or null");
15855
0
                goto fail;
15856
0
            }
15857
0
        }
15858
0
    } else {
15859
        /* parent_class is JS_UNDEFINED in this case */
15860
0
        parent_proto = JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]);
15861
0
        parent_class = JS_DupValue(ctx, ctx->function_proto);
15862
0
    }
15863
0
    proto = JS_NewObjectProto(ctx, parent_proto);
15864
0
    if (JS_IsException(proto))
15865
0
        goto fail;
15866
15867
0
    b = JS_VALUE_GET_PTR(bfunc);
15868
0
    assert(b->func_kind == JS_FUNC_NORMAL);
15869
0
    ctor = JS_NewObjectProtoClass(ctx, parent_class,
15870
0
                                  JS_CLASS_BYTECODE_FUNCTION);
15871
0
    if (JS_IsException(ctor))
15872
0
        goto fail;
15873
0
    ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf);
15874
0
    bfunc = JS_UNDEFINED;
15875
0
    if (JS_IsException(ctor))
15876
0
        goto fail;
15877
0
    js_method_set_home_object(ctx, ctor, proto);
15878
0
    JS_SetConstructorBit(ctx, ctor, TRUE);
15879
15880
0
    JS_DefinePropertyValue(ctx, ctor, JS_ATOM_length,
15881
0
                           JS_NewInt32(ctx, b->defined_arg_count),
15882
0
                           JS_PROP_CONFIGURABLE);
15883
15884
0
    if (is_computed_name) {
15885
0
        if (JS_DefineObjectNameComputed(ctx, ctor, sp[-3],
15886
0
                                        JS_PROP_CONFIGURABLE) < 0)
15887
0
            goto fail;
15888
0
    } else {
15889
0
        if (JS_DefineObjectName(ctx, ctor, class_name, JS_PROP_CONFIGURABLE) < 0)
15890
0
            goto fail;
15891
0
    }
15892
15893
    /* the constructor property must be first. It can be overriden by
15894
       computed property names */
15895
0
    if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
15896
0
                               JS_DupValue(ctx, ctor),
15897
0
                               JS_PROP_CONFIGURABLE |
15898
0
                               JS_PROP_WRITABLE | JS_PROP_THROW) < 0)
15899
0
        goto fail;
15900
    /* set the prototype property */
15901
0
    if (JS_DefinePropertyValue(ctx, ctor, JS_ATOM_prototype,
15902
0
                               JS_DupValue(ctx, proto), JS_PROP_THROW) < 0)
15903
0
        goto fail;
15904
0
    set_cycle_flag(ctx, ctor);
15905
0
    set_cycle_flag(ctx, proto);
15906
15907
0
    JS_FreeValue(ctx, parent_proto);
15908
0
    JS_FreeValue(ctx, parent_class);
15909
15910
0
    sp[-2] = ctor;
15911
0
    sp[-1] = proto;
15912
0
    return 0;
15913
0
 fail:
15914
0
    JS_FreeValue(ctx, parent_class);
15915
0
    JS_FreeValue(ctx, parent_proto);
15916
0
    JS_FreeValue(ctx, bfunc);
15917
0
    JS_FreeValue(ctx, proto);
15918
0
    JS_FreeValue(ctx, ctor);
15919
0
    sp[-2] = JS_UNDEFINED;
15920
0
    sp[-1] = JS_UNDEFINED;
15921
0
    return -1;
15922
0
}
15923
15924
static void close_var_refs(JSRuntime *rt, JSStackFrame *sf)
15925
39
{
15926
39
    struct list_head *el, *el1;
15927
39
    JSVarRef *var_ref;
15928
39
    int var_idx;
15929
15930
39
    list_for_each_safe(el, el1, &sf->var_ref_list) {
15931
0
        var_ref = list_entry(el, JSVarRef, var_ref_link);
15932
        /* no need to unlink var_ref->var_ref_link as the list is never used afterwards */
15933
0
        if (var_ref->async_func)
15934
0
            async_func_free(rt, var_ref->async_func);
15935
0
        var_idx = var_ref->var_idx;
15936
0
        if (var_ref->is_arg)
15937
0
            var_ref->value = JS_DupValueRT(rt, sf->arg_buf[var_idx]);
15938
0
        else
15939
0
            var_ref->value = JS_DupValueRT(rt, sf->var_buf[var_idx]);
15940
0
        var_ref->pvalue = &var_ref->value;
15941
        /* the reference is no longer to a local variable */
15942
0
        var_ref->is_detached = TRUE;
15943
0
    }
15944
39
}
15945
15946
static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_arg)
15947
0
{
15948
0
    struct list_head *el, *el1;
15949
0
    JSVarRef *var_ref;
15950
0
    int var_idx = idx;
15951
15952
0
    list_for_each_safe(el, el1, &sf->var_ref_list) {
15953
0
        var_ref = list_entry(el, JSVarRef, var_ref_link);
15954
0
        if (var_idx == var_ref->var_idx && var_ref->is_arg == is_arg) {
15955
0
            list_del(&var_ref->var_ref_link);
15956
0
            if (var_ref->async_func)
15957
0
                async_func_free(ctx->rt, var_ref->async_func);
15958
0
            var_ref->value = JS_DupValue(ctx, sf->var_buf[var_idx]);
15959
0
            var_ref->pvalue = &var_ref->value;
15960
            /* the reference is no longer to a local variable */
15961
0
            var_ref->is_detached = TRUE;
15962
0
        }
15963
0
    }
15964
0
}
15965
15966
219
#define JS_CALL_FLAG_COPY_ARGV   (1 << 1)
15967
78
#define JS_CALL_FLAG_GENERATOR   (1 << 2)
15968
15969
static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
15970
                                  JSValueConst this_obj,
15971
                                  int argc, JSValueConst *argv, int flags)
15972
0
{
15973
0
    JSRuntime *rt = ctx->rt;
15974
0
    JSCFunctionType func;
15975
0
    JSObject *p;
15976
0
    JSStackFrame sf_s, *sf = &sf_s, *prev_sf;
15977
0
    JSValue ret_val;
15978
0
    JSValueConst *arg_buf;
15979
0
    int arg_count, i;
15980
0
    JSCFunctionEnum cproto;
15981
15982
0
    p = JS_VALUE_GET_OBJ(func_obj);
15983
0
    cproto = p->u.cfunc.cproto;
15984
0
    arg_count = p->u.cfunc.length;
15985
15986
    /* better to always check stack overflow */
15987
0
    if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count))
15988
0
        return JS_ThrowStackOverflow(ctx);
15989
15990
0
    prev_sf = rt->current_stack_frame;
15991
0
    sf->prev_frame = prev_sf;
15992
0
    rt->current_stack_frame = sf;
15993
0
    ctx = p->u.cfunc.realm; /* change the current realm */
15994
15995
0
#ifdef CONFIG_BIGNUM
15996
    /* we only propagate the bignum mode as some runtime functions
15997
       test it */
15998
0
    if (prev_sf)
15999
0
        sf->js_mode = prev_sf->js_mode & JS_MODE_MATH;
16000
0
    else
16001
0
        sf->js_mode = 0;
16002
#else
16003
    sf->js_mode = 0;
16004
#endif
16005
0
    sf->cur_func = (JSValue)func_obj;
16006
0
    sf->arg_count = argc;
16007
0
    arg_buf = argv;
16008
16009
0
    if (unlikely(argc < arg_count)) {
16010
        /* ensure that at least argc_count arguments are readable */
16011
0
        arg_buf = alloca(sizeof(arg_buf[0]) * arg_count);
16012
0
        for(i = 0; i < argc; i++)
16013
0
            arg_buf[i] = argv[i];
16014
0
        for(i = argc; i < arg_count; i++)
16015
0
            arg_buf[i] = JS_UNDEFINED;
16016
0
        sf->arg_count = arg_count;
16017
0
    }
16018
0
    sf->arg_buf = (JSValue*)arg_buf;
16019
16020
0
    func = p->u.cfunc.c_function;
16021
0
    switch(cproto) {
16022
0
    case JS_CFUNC_constructor:
16023
0
    case JS_CFUNC_constructor_or_func:
16024
0
        if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
16025
0
            if (cproto == JS_CFUNC_constructor) {
16026
0
            not_a_constructor:
16027
0
                ret_val = JS_ThrowTypeError(ctx, "must be called with new");
16028
0
                break;
16029
0
            } else {
16030
0
                this_obj = JS_UNDEFINED;
16031
0
            }
16032
0
        }
16033
        /* here this_obj is new_target */
16034
        /* fall thru */
16035
0
    case JS_CFUNC_generic:
16036
0
        ret_val = func.generic(ctx, this_obj, argc, arg_buf);
16037
0
        break;
16038
0
    case JS_CFUNC_constructor_magic:
16039
0
    case JS_CFUNC_constructor_or_func_magic:
16040
0
        if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
16041
0
            if (cproto == JS_CFUNC_constructor_magic) {
16042
0
                goto not_a_constructor;
16043
0
            } else {
16044
0
                this_obj = JS_UNDEFINED;
16045
0
            }
16046
0
        }
16047
        /* fall thru */
16048
0
    case JS_CFUNC_generic_magic:
16049
0
        ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf,
16050
0
                                     p->u.cfunc.magic);
16051
0
        break;
16052
0
    case JS_CFUNC_getter:
16053
0
        ret_val = func.getter(ctx, this_obj);
16054
0
        break;
16055
0
    case JS_CFUNC_setter:
16056
0
        ret_val = func.setter(ctx, this_obj, arg_buf[0]);
16057
0
        break;
16058
0
    case JS_CFUNC_getter_magic:
16059
0
        ret_val = func.getter_magic(ctx, this_obj, p->u.cfunc.magic);
16060
0
        break;
16061
0
    case JS_CFUNC_setter_magic:
16062
0
        ret_val = func.setter_magic(ctx, this_obj, arg_buf[0], p->u.cfunc.magic);
16063
0
        break;
16064
0
    case JS_CFUNC_f_f:
16065
0
        {
16066
0
            double d1;
16067
16068
0
            if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
16069
0
                ret_val = JS_EXCEPTION;
16070
0
                break;
16071
0
            }
16072
0
            ret_val = JS_NewFloat64(ctx, func.f_f(d1));
16073
0
        }
16074
0
        break;
16075
0
    case JS_CFUNC_f_f_f:
16076
0
        {
16077
0
            double d1, d2;
16078
16079
0
            if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
16080
0
                ret_val = JS_EXCEPTION;
16081
0
                break;
16082
0
            }
16083
0
            if (unlikely(JS_ToFloat64(ctx, &d2, arg_buf[1]))) {
16084
0
                ret_val = JS_EXCEPTION;
16085
0
                break;
16086
0
            }
16087
0
            ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2));
16088
0
        }
16089
0
        break;
16090
0
    case JS_CFUNC_iterator_next:
16091
0
        {
16092
0
            int done;
16093
0
            ret_val = func.iterator_next(ctx, this_obj, argc, arg_buf,
16094
0
                                         &done, p->u.cfunc.magic);
16095
0
            if (!JS_IsException(ret_val) && done != 2) {
16096
0
                ret_val = js_create_iterator_result(ctx, ret_val, done);
16097
0
            }
16098
0
        }
16099
0
        break;
16100
0
    default:
16101
0
        abort();
16102
0
    }
16103
16104
0
    rt->current_stack_frame = sf->prev_frame;
16105
0
    return ret_val;
16106
0
}
16107
16108
static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
16109
                                      JSValueConst this_obj,
16110
                                      int argc, JSValueConst *argv, int flags)
16111
0
{
16112
0
    JSObject *p;
16113
0
    JSBoundFunction *bf;
16114
0
    JSValueConst *arg_buf, new_target;
16115
0
    int arg_count, i;
16116
16117
0
    p = JS_VALUE_GET_OBJ(func_obj);
16118
0
    bf = p->u.bound_function;
16119
0
    arg_count = bf->argc + argc;
16120
0
    if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count))
16121
0
        return JS_ThrowStackOverflow(ctx);
16122
0
    arg_buf = alloca(sizeof(JSValue) * arg_count);
16123
0
    for(i = 0; i < bf->argc; i++) {
16124
0
        arg_buf[i] = bf->argv[i];
16125
0
    }
16126
0
    for(i = 0; i < argc; i++) {
16127
0
        arg_buf[bf->argc + i] = argv[i];
16128
0
    }
16129
0
    if (flags & JS_CALL_FLAG_CONSTRUCTOR) {
16130
0
        new_target = this_obj;
16131
0
        if (js_same_value(ctx, func_obj, new_target))
16132
0
            new_target = bf->func_obj;
16133
0
        return JS_CallConstructor2(ctx, bf->func_obj, new_target,
16134
0
                                   arg_count, arg_buf);
16135
0
    } else {
16136
0
        return JS_Call(ctx, bf->func_obj, bf->this_val,
16137
0
                       arg_count, arg_buf);
16138
0
    }
16139
0
}
16140
16141
/* argument of OP_special_object */
16142
typedef enum {
16143
    OP_SPECIAL_OBJECT_ARGUMENTS,
16144
    OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS,
16145
    OP_SPECIAL_OBJECT_THIS_FUNC,
16146
    OP_SPECIAL_OBJECT_NEW_TARGET,
16147
    OP_SPECIAL_OBJECT_HOME_OBJECT,
16148
    OP_SPECIAL_OBJECT_VAR_OBJECT,
16149
    OP_SPECIAL_OBJECT_IMPORT_META,
16150
} OPSpecialObjectEnum;
16151
16152
0
#define FUNC_RET_AWAIT         0
16153
0
#define FUNC_RET_YIELD         1
16154
0
#define FUNC_RET_YIELD_STAR    2
16155
0
#define FUNC_RET_INITIAL_YIELD 3
16156
16157
/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
16158
static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
16159
                               JSValueConst this_obj, JSValueConst new_target,
16160
                               int argc, JSValue *argv, int flags)
16161
258
{
16162
258
    JSRuntime *rt = caller_ctx->rt;
16163
258
    JSContext *ctx;
16164
258
    JSObject *p;
16165
258
    JSFunctionBytecode *b;
16166
258
    JSStackFrame sf_s, *sf = &sf_s;
16167
258
    const uint8_t *pc;
16168
258
    int opcode, arg_allocated_size, i;
16169
258
    JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval;
16170
258
    JSVarRef **var_refs;
16171
258
    size_t alloca_size;
16172
16173
#if !DIRECT_DISPATCH
16174
#define SWITCH(pc)      switch (opcode = *pc++)
16175
#define CASE(op)        case op
16176
#define DEFAULT         default
16177
#define BREAK           break
16178
#else
16179
258
    static const void * const dispatch_table[256] = {
16180
63.9k
#define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id,
16181
258
#if SHORT_OPCODES
16182
258
#define def(id, size, n_pop, n_push, f)
16183
#else
16184
#define def(id, size, n_pop, n_push, f) && case_default,
16185
#endif
16186
258
#include "quickjs-opcode.h"
16187
258
        [ OP_COUNT ... 255 ] = &&case_default
16188
258
    };
16189
5.98M
#define SWITCH(pc)      goto *dispatch_table[opcode = *pc++];
16190
26.0M
#define CASE(op)        case_ ## op
16191
258
#define DEFAULT         case_default
16192
5.98M
#define BREAK           SWITCH(pc)
16193
258
#endif
16194
16195
258
    if (js_poll_interrupts(caller_ctx))
16196
0
        return JS_EXCEPTION;
16197
258
    if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) {
16198
39
        if (flags & JS_CALL_FLAG_GENERATOR) {
16199
39
            JSAsyncFunctionState *s = JS_VALUE_GET_PTR(func_obj);
16200
            /* func_obj get contains a pointer to JSFuncAsyncState */
16201
            /* the stack frame is already allocated */
16202
39
            sf = &s->frame;
16203
39
            p = JS_VALUE_GET_OBJ(sf->cur_func);
16204
39
            b = p->u.func.function_bytecode;
16205
39
            ctx = b->realm;
16206
39
            var_refs = p->u.func.var_refs;
16207
39
            local_buf = arg_buf = sf->arg_buf;
16208
39
            var_buf = sf->var_buf;
16209
39
            stack_buf = sf->var_buf + b->var_count;
16210
39
            sp = sf->cur_sp;
16211
39
            sf->cur_sp = NULL; /* cur_sp is NULL if the function is running */
16212
39
            pc = sf->cur_pc;
16213
39
            sf->prev_frame = rt->current_stack_frame;
16214
39
            rt->current_stack_frame = sf;
16215
39
            if (s->throw_flag)
16216
0
                goto exception;
16217
39
            else
16218
39
                goto restart;
16219
39
        } else {
16220
0
            goto not_a_function;
16221
0
        }
16222
39
    }
16223
219
    p = JS_VALUE_GET_OBJ(func_obj);
16224
219
    if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
16225
156
        JSClassCall *call_func;
16226
156
        call_func = rt->class_array[p->class_id].call;
16227
156
        if (!call_func) {
16228
0
        not_a_function:
16229
0
            return JS_ThrowTypeError(caller_ctx, "not a function");
16230
0
        }
16231
156
        return call_func(caller_ctx, func_obj, this_obj, argc,
16232
156
                         (JSValueConst *)argv, flags);
16233
156
    }
16234
63
    b = p->u.func.function_bytecode;
16235
16236
63
    if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) {
16237
63
        arg_allocated_size = b->arg_count;
16238
63
    } else {
16239
0
        arg_allocated_size = 0;
16240
0
    }
16241
16242
63
    alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count +
16243
63
                                     b->stack_size);
16244
63
    if (js_check_stack_overflow(rt, alloca_size))
16245
0
        return JS_ThrowStackOverflow(caller_ctx);
16246
16247
63
    sf->js_mode = b->js_mode;
16248
63
    arg_buf = argv;
16249
63
    sf->arg_count = argc;
16250
63
    sf->cur_func = (JSValue)func_obj;
16251
63
    init_list_head(&sf->var_ref_list);
16252
63
    var_refs = p->u.func.var_refs;
16253
16254
63
    local_buf = alloca(alloca_size);
16255
63
    if (unlikely(arg_allocated_size)) {
16256
0
        int n = min_int(argc, b->arg_count);
16257
0
        arg_buf = local_buf;
16258
0
        for(i = 0; i < n; i++)
16259
0
            arg_buf[i] = JS_DupValue(caller_ctx, argv[i]);
16260
0
        for(; i < b->arg_count; i++)
16261
0
            arg_buf[i] = JS_UNDEFINED;
16262
0
        sf->arg_count = b->arg_count;
16263
0
    }
16264
63
    var_buf = local_buf + arg_allocated_size;
16265
63
    sf->var_buf = var_buf;
16266
63
    sf->arg_buf = arg_buf;
16267
16268
87
    for(i = 0; i < b->var_count; i++)
16269
63
        var_buf[i] = JS_UNDEFINED;
16270
16271
63
    stack_buf = var_buf + b->var_count;
16272
63
    sp = stack_buf;
16273
63
    pc = b->byte_code_buf;
16274
63
    sf->prev_frame = rt->current_stack_frame;
16275
63
    rt->current_stack_frame = sf;
16276
63
    ctx = b->realm; /* set the current realm */
16277
16278
102
 restart:
16279
102
    for(;;) {
16280
102
        int call_argc;
16281
102
        JSValue *call_argv;
16282
16283
102
        SWITCH(pc) {
16284
102
        CASE(OP_push_i32):
16285
0
            *sp++ = JS_NewInt32(ctx, get_u32(pc));
16286
0
            pc += 4;
16287
0
            BREAK;
16288
0
        CASE(OP_push_const):
16289
0
            *sp++ = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
16290
0
            pc += 4;
16291
0
            BREAK;
16292
0
#if SHORT_OPCODES
16293
0
        CASE(OP_push_minus1):
16294
2.66M
        CASE(OP_push_0):
16295
2.85M
        CASE(OP_push_1):
16296
2.85M
        CASE(OP_push_2):
16297
2.85M
        CASE(OP_push_3):
16298
2.85M
        CASE(OP_push_4):
16299
2.99M
        CASE(OP_push_5):
16300
2.99M
        CASE(OP_push_6):
16301
2.99M
        CASE(OP_push_7):
16302
2.99M
            *sp++ = JS_NewInt32(ctx, opcode - OP_push_0);
16303
2.99M
            BREAK;
16304
2.99M
        CASE(OP_push_i8):
16305
1.57k
            *sp++ = JS_NewInt32(ctx, get_i8(pc));
16306
1.57k
            pc += 1;
16307
1.57k
            BREAK;
16308
1.57k
        CASE(OP_push_i16):
16309
0
            *sp++ = JS_NewInt32(ctx, get_i16(pc));
16310
0
            pc += 2;
16311
0
            BREAK;
16312
0
        CASE(OP_push_const8):
16313
0
            *sp++ = JS_DupValue(ctx, b->cpool[*pc++]);
16314
0
            BREAK;
16315
0
        CASE(OP_fclosure8):
16316
0
            *sp++ = js_closure(ctx, JS_DupValue(ctx, b->cpool[*pc++]), var_refs, sf);
16317
0
            if (unlikely(JS_IsException(sp[-1])))
16318
0
                goto exception;
16319
0
            BREAK;
16320
1
        CASE(OP_push_empty_string):
16321
1
            *sp++ = JS_AtomToString(ctx, JS_ATOM_empty_string);
16322
1
            BREAK;
16323
1
        CASE(OP_get_length):
16324
0
            {
16325
0
                JSValue val;
16326
16327
0
                val = JS_GetProperty(ctx, sp[-1], JS_ATOM_length);
16328
0
                if (unlikely(JS_IsException(val)))
16329
0
                    goto exception;
16330
0
                JS_FreeValue(ctx, sp[-1]);
16331
0
                sp[-1] = val;
16332
0
            }
16333
0
            BREAK;
16334
0
#endif
16335
15
        CASE(OP_push_atom_value):
16336
15
            *sp++ = JS_AtomToValue(ctx, get_u32(pc));
16337
15
            pc += 4;
16338
15
            BREAK;
16339
39
        CASE(OP_undefined):
16340
39
            *sp++ = JS_UNDEFINED;
16341
39
            BREAK;
16342
39
        CASE(OP_null):
16343
0
            *sp++ = JS_NULL;
16344
0
            BREAK;
16345
78
        CASE(OP_push_this):
16346
            /* OP_push_this is only called at the start of a function */
16347
78
            {
16348
78
                JSValue val;
16349
78
                if (!(b->js_mode & JS_MODE_STRICT)) {
16350
0
                    uint32_t tag = JS_VALUE_GET_TAG(this_obj);
16351
0
                    if (likely(tag == JS_TAG_OBJECT))
16352
0
                        goto normal_this;
16353
0
                    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) {
16354
0
                        val = JS_DupValue(ctx, ctx->global_obj);
16355
0
                    } else {
16356
0
                        val = JS_ToObject(ctx, this_obj);
16357
0
                        if (JS_IsException(val))
16358
0
                            goto exception;
16359
0
                    }
16360
78
                } else {
16361
78
                normal_this:
16362
78
                    val = JS_DupValue(ctx, this_obj);
16363
78
                }
16364
78
                *sp++ = val;
16365
78
            }
16366
78
            BREAK;
16367
78
        CASE(OP_push_false):
16368
0
            *sp++ = JS_FALSE;
16369
0
            BREAK;
16370
0
        CASE(OP_push_true):
16371
0
            *sp++ = JS_TRUE;
16372
0
            BREAK;
16373
0
        CASE(OP_object):
16374
0
            *sp++ = JS_NewObject(ctx);
16375
0
            if (unlikely(JS_IsException(sp[-1])))
16376
0
                goto exception;
16377
0
            BREAK;
16378
0
        CASE(OP_special_object):
16379
0
            {
16380
0
                int arg = *pc++;
16381
0
                switch(arg) {
16382
0
                case OP_SPECIAL_OBJECT_ARGUMENTS:
16383
0
                    *sp++ = js_build_arguments(ctx, argc, (JSValueConst *)argv);
16384
0
                    if (unlikely(JS_IsException(sp[-1])))
16385
0
                        goto exception;
16386
0
                    break;
16387
0
                case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS:
16388
0
                    *sp++ = js_build_mapped_arguments(ctx, argc, (JSValueConst *)argv,
16389
0
                                                      sf, min_int(argc, b->arg_count));
16390
0
                    if (unlikely(JS_IsException(sp[-1])))
16391
0
                        goto exception;
16392
0
                    break;
16393
0
                case OP_SPECIAL_OBJECT_THIS_FUNC:
16394
0
                    *sp++ = JS_DupValue(ctx, sf->cur_func);
16395
0
                    break;
16396
0
                case OP_SPECIAL_OBJECT_NEW_TARGET:
16397
0
                    *sp++ = JS_DupValue(ctx, new_target);
16398
0
                    break;
16399
0
                case OP_SPECIAL_OBJECT_HOME_OBJECT:
16400
0
                    {
16401
0
                        JSObject *p1;
16402
0
                        p1 = p->u.func.home_object;
16403
0
                        if (unlikely(!p1))
16404
0
                            *sp++ = JS_UNDEFINED;
16405
0
                        else
16406
0
                            *sp++ = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
16407
0
                    }
16408
0
                    break;
16409
0
                case OP_SPECIAL_OBJECT_VAR_OBJECT:
16410
0
                    *sp++ = JS_NewObjectProto(ctx, JS_NULL);
16411
0
                    if (unlikely(JS_IsException(sp[-1])))
16412
0
                        goto exception;
16413
0
                    break;
16414
0
                case OP_SPECIAL_OBJECT_IMPORT_META:
16415
0
                    *sp++ = js_import_meta(ctx);
16416
0
                    if (unlikely(JS_IsException(sp[-1])))
16417
0
                        goto exception;
16418
0
                    break;
16419
0
                default:
16420
0
                    abort();
16421
0
                }
16422
0
            }
16423
0
            BREAK;
16424
0
        CASE(OP_rest):
16425
0
            {
16426
0
                int first = get_u16(pc);
16427
0
                pc += 2;
16428
0
                *sp++ = js_build_rest(ctx, first, argc, (JSValueConst *)argv);
16429
0
                if (unlikely(JS_IsException(sp[-1])))
16430
0
                    goto exception;
16431
0
            }
16432
0
            BREAK;
16433
16434
0
        CASE(OP_drop):
16435
0
            JS_FreeValue(ctx, sp[-1]);
16436
0
            sp--;
16437
0
            BREAK;
16438
0
        CASE(OP_nip):
16439
0
            JS_FreeValue(ctx, sp[-2]);
16440
0
            sp[-2] = sp[-1];
16441
0
            sp--;
16442
0
            BREAK;
16443
0
        CASE(OP_nip1): /* a b c -> b c */
16444
0
            JS_FreeValue(ctx, sp[-3]);
16445
0
            sp[-3] = sp[-2];
16446
0
            sp[-2] = sp[-1];
16447
0
            sp--;
16448
0
            BREAK;
16449
0
        CASE(OP_dup):
16450
0
            sp[0] = JS_DupValue(ctx, sp[-1]);
16451
0
            sp++;
16452
0
            BREAK;
16453
0
        CASE(OP_dup2): /* a b -> a b a b */
16454
0
            sp[0] = JS_DupValue(ctx, sp[-2]);
16455
0
            sp[1] = JS_DupValue(ctx, sp[-1]);
16456
0
            sp += 2;
16457
0
            BREAK;
16458
0
        CASE(OP_dup3): /* a b c -> a b c a b c */
16459
0
            sp[0] = JS_DupValue(ctx, sp[-3]);
16460
0
            sp[1] = JS_DupValue(ctx, sp[-2]);
16461
0
            sp[2] = JS_DupValue(ctx, sp[-1]);
16462
0
            sp += 3;
16463
0
            BREAK;
16464
0
        CASE(OP_dup1): /* a b -> a a b */
16465
0
            sp[0] = sp[-1];
16466
0
            sp[-1] = JS_DupValue(ctx, sp[-2]);
16467
0
            sp++;
16468
0
            BREAK;
16469
0
        CASE(OP_insert2): /* obj a -> a obj a (dup_x1) */
16470
0
            sp[0] = sp[-1];
16471
0
            sp[-1] = sp[-2];
16472
0
            sp[-2] = JS_DupValue(ctx, sp[0]);
16473
0
            sp++;
16474
0
            BREAK;
16475
0
        CASE(OP_insert3): /* obj prop a -> a obj prop a (dup_x2) */
16476
0
            sp[0] = sp[-1];
16477
0
            sp[-1] = sp[-2];
16478
0
            sp[-2] = sp[-3];
16479
0
            sp[-3] = JS_DupValue(ctx, sp[0]);
16480
0
            sp++;
16481
0
            BREAK;
16482
0
        CASE(OP_insert4): /* this obj prop a -> a this obj prop a */
16483
0
            sp[0] = sp[-1];
16484
0
            sp[-1] = sp[-2];
16485
0
            sp[-2] = sp[-3];
16486
0
            sp[-3] = sp[-4];
16487
0
            sp[-4] = JS_DupValue(ctx, sp[0]);
16488
0
            sp++;
16489
0
            BREAK;
16490
0
        CASE(OP_perm3): /* obj a b -> a obj b (213) */
16491
0
            {
16492
0
                JSValue tmp;
16493
0
                tmp = sp[-2];
16494
0
                sp[-2] = sp[-3];
16495
0
                sp[-3] = tmp;
16496
0
            }
16497
0
            BREAK;
16498
0
        CASE(OP_rot3l): /* x a b -> a b x (231) */
16499
0
            {
16500
0
                JSValue tmp;
16501
0
                tmp = sp[-3];
16502
0
                sp[-3] = sp[-2];
16503
0
                sp[-2] = sp[-1];
16504
0
                sp[-1] = tmp;
16505
0
            }
16506
0
            BREAK;
16507
0
        CASE(OP_rot4l): /* x a b c -> a b c x */
16508
0
            {
16509
0
                JSValue tmp;
16510
0
                tmp = sp[-4];
16511
0
                sp[-4] = sp[-3];
16512
0
                sp[-3] = sp[-2];
16513
0
                sp[-2] = sp[-1];
16514
0
                sp[-1] = tmp;
16515
0
            }
16516
0
            BREAK;
16517
0
        CASE(OP_rot5l): /* x a b c d -> a b c d x */
16518
0
            {
16519
0
                JSValue tmp;
16520
0
                tmp = sp[-5];
16521
0
                sp[-5] = sp[-4];
16522
0
                sp[-4] = sp[-3];
16523
0
                sp[-3] = sp[-2];
16524
0
                sp[-2] = sp[-1];
16525
0
                sp[-1] = tmp;
16526
0
            }
16527
0
            BREAK;
16528
0
        CASE(OP_rot3r): /* a b x -> x a b (312) */
16529
0
            {
16530
0
                JSValue tmp;
16531
0
                tmp = sp[-1];
16532
0
                sp[-1] = sp[-2];
16533
0
                sp[-2] = sp[-3];
16534
0
                sp[-3] = tmp;
16535
0
            }
16536
0
            BREAK;
16537
0
        CASE(OP_perm4): /* obj prop a b -> a obj prop b */
16538
0
            {
16539
0
                JSValue tmp;
16540
0
                tmp = sp[-2];
16541
0
                sp[-2] = sp[-3];
16542
0
                sp[-3] = sp[-4];
16543
0
                sp[-4] = tmp;
16544
0
            }
16545
0
            BREAK;
16546
0
        CASE(OP_perm5): /* this obj prop a b -> a this obj prop b */
16547
0
            {
16548
0
                JSValue tmp;
16549
0
                tmp = sp[-2];
16550
0
                sp[-2] = sp[-3];
16551
0
                sp[-3] = sp[-4];
16552
0
                sp[-4] = sp[-5];
16553
0
                sp[-5] = tmp;
16554
0
            }
16555
0
            BREAK;
16556
0
        CASE(OP_swap): /* a b -> b a */
16557
0
            {
16558
0
                JSValue tmp;
16559
0
                tmp = sp[-2];
16560
0
                sp[-2] = sp[-1];
16561
0
                sp[-1] = tmp;
16562
0
            }
16563
0
            BREAK;
16564
0
        CASE(OP_swap2): /* a b c d -> c d a b */
16565
0
            {
16566
0
                JSValue tmp1, tmp2;
16567
0
                tmp1 = sp[-4];
16568
0
                tmp2 = sp[-3];
16569
0
                sp[-4] = sp[-2];
16570
0
                sp[-3] = sp[-1];
16571
0
                sp[-2] = tmp1;
16572
0
                sp[-1] = tmp2;
16573
0
            }
16574
0
            BREAK;
16575
16576
0
        CASE(OP_fclosure):
16577
0
            {
16578
0
                JSValue bfunc = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
16579
0
                pc += 4;
16580
0
                *sp++ = js_closure(ctx, bfunc, var_refs, sf);
16581
0
                if (unlikely(JS_IsException(sp[-1])))
16582
0
                    goto exception;
16583
0
            }
16584
0
            BREAK;
16585
0
#if SHORT_OPCODES
16586
0
        CASE(OP_call0):
16587
0
        CASE(OP_call1):
16588
0
        CASE(OP_call2):
16589
0
        CASE(OP_call3):
16590
0
            call_argc = opcode - OP_call0;
16591
0
            goto has_call_argc;
16592
0
#endif
16593
0
        CASE(OP_call):
16594
0
        CASE(OP_tail_call):
16595
0
            {
16596
0
                call_argc = get_u16(pc);
16597
0
                pc += 2;
16598
0
                goto has_call_argc;
16599
0
            has_call_argc:
16600
0
                call_argv = sp - call_argc;
16601
0
                sf->cur_pc = pc;
16602
0
                ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
16603
0
                                          JS_UNDEFINED, call_argc, call_argv, 0);
16604
0
                if (unlikely(JS_IsException(ret_val)))
16605
0
                    goto exception;
16606
0
                if (opcode == OP_tail_call)
16607
0
                    goto done;
16608
0
                for(i = -1; i < call_argc; i++)
16609
0
                    JS_FreeValue(ctx, call_argv[i]);
16610
0
                sp -= call_argc + 1;
16611
0
                *sp++ = ret_val;
16612
0
            }
16613
0
            BREAK;
16614
0
        CASE(OP_call_constructor):
16615
0
            {
16616
0
                call_argc = get_u16(pc);
16617
0
                pc += 2;
16618
0
                call_argv = sp - call_argc;
16619
0
                sf->cur_pc = pc;
16620
0
                ret_val = JS_CallConstructorInternal(ctx, call_argv[-2],
16621
0
                                                     call_argv[-1],
16622
0
                                                     call_argc, call_argv, 0);
16623
0
                if (unlikely(JS_IsException(ret_val)))
16624
0
                    goto exception;
16625
0
                for(i = -2; i < call_argc; i++)
16626
0
                    JS_FreeValue(ctx, call_argv[i]);
16627
0
                sp -= call_argc + 2;
16628
0
                *sp++ = ret_val;
16629
0
            }
16630
0
            BREAK;
16631
0
        CASE(OP_call_method):
16632
0
        CASE(OP_tail_call_method):
16633
0
            {
16634
0
                call_argc = get_u16(pc);
16635
0
                pc += 2;
16636
0
                call_argv = sp - call_argc;
16637
0
                sf->cur_pc = pc;
16638
0
                ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2],
16639
0
                                          JS_UNDEFINED, call_argc, call_argv, 0);
16640
0
                if (unlikely(JS_IsException(ret_val)))
16641
0
                    goto exception;
16642
0
                if (opcode == OP_tail_call_method)
16643
0
                    goto done;
16644
0
                for(i = -2; i < call_argc; i++)
16645
0
                    JS_FreeValue(ctx, call_argv[i]);
16646
0
                sp -= call_argc + 2;
16647
0
                *sp++ = ret_val;
16648
0
            }
16649
0
            BREAK;
16650
13
        CASE(OP_array_from):
16651
13
            {
16652
13
                int i, ret;
16653
16654
13
                call_argc = get_u16(pc);
16655
13
                pc += 2;
16656
13
                ret_val = JS_NewArray(ctx);
16657
13
                if (unlikely(JS_IsException(ret_val)))
16658
0
                    goto exception;
16659
13
                call_argv = sp - call_argc;
16660
237
                for(i = 0; i < call_argc; i++) {
16661
224
                    ret = JS_DefinePropertyValue(ctx, ret_val, __JS_AtomFromUInt32(i), call_argv[i],
16662
224
                                                 JS_PROP_C_W_E | JS_PROP_THROW);
16663
224
                    call_argv[i] = JS_UNDEFINED;
16664
224
                    if (ret < 0) {
16665
0
                        JS_FreeValue(ctx, ret_val);
16666
0
                        goto exception;
16667
0
                    }
16668
224
                }
16669
13
                sp -= call_argc;
16670
13
                *sp++ = ret_val;
16671
13
            }
16672
13
            BREAK;
16673
16674
13
        CASE(OP_apply):
16675
0
            {
16676
0
                int magic;
16677
0
                magic = get_u16(pc);
16678
0
                pc += 2;
16679
16680
0
                ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic);
16681
0
                if (unlikely(JS_IsException(ret_val)))
16682
0
                    goto exception;
16683
0
                JS_FreeValue(ctx, sp[-3]);
16684
0
                JS_FreeValue(ctx, sp[-2]);
16685
0
                JS_FreeValue(ctx, sp[-1]);
16686
0
                sp -= 3;
16687
0
                *sp++ = ret_val;
16688
0
            }
16689
0
            BREAK;
16690
15
        CASE(OP_return):
16691
15
            ret_val = *--sp;
16692
15
            goto done;
16693
39
        CASE(OP_return_undef):
16694
39
            ret_val = JS_UNDEFINED;
16695
39
            goto done;
16696
16697
0
        CASE(OP_check_ctor_return):
16698
            /* return TRUE if 'this' should be returned */
16699
0
            if (!JS_IsObject(sp[-1])) {
16700
0
                if (!JS_IsUndefined(sp[-1])) {
16701
0
                    JS_ThrowTypeError(caller_ctx, "derived class constructor must return an object or undefined");
16702
0
                    goto exception;
16703
0
                }
16704
0
                sp[0] = JS_TRUE;
16705
0
            } else {
16706
0
                sp[0] = JS_FALSE;
16707
0
            }
16708
0
            sp++;
16709
0
            BREAK;
16710
0
        CASE(OP_check_ctor):
16711
0
            if (JS_IsUndefined(new_target)) {
16712
0
                JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'");
16713
0
                goto exception;
16714
0
            }
16715
0
            BREAK;
16716
0
        CASE(OP_check_brand):
16717
0
            {
16718
0
                int ret = JS_CheckBrand(ctx, sp[-2], sp[-1]);
16719
0
                if (ret < 0)
16720
0
                    goto exception;
16721
0
                if (!ret) {
16722
0
                    JS_ThrowTypeError(ctx, "invalid brand on object");
16723
0
                    goto exception;
16724
0
                }
16725
0
            }
16726
0
            BREAK;
16727
0
        CASE(OP_add_brand):
16728
0
            if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0)
16729
0
                goto exception;
16730
0
            JS_FreeValue(ctx, sp[-2]);
16731
0
            JS_FreeValue(ctx, sp[-1]);
16732
0
            sp -= 2;
16733
0
            BREAK;
16734
16735
0
        CASE(OP_throw):
16736
0
            JS_Throw(ctx, *--sp);
16737
0
            goto exception;
16738
16739
0
        CASE(OP_throw_error):
16740
0
#define JS_THROW_VAR_RO             0
16741
0
#define JS_THROW_VAR_REDECL         1
16742
0
#define JS_THROW_VAR_UNINITIALIZED  2
16743
0
#define JS_THROW_ERROR_DELETE_SUPER   3
16744
0
#define JS_THROW_ERROR_ITERATOR_THROW 4
16745
0
            {
16746
0
                JSAtom atom;
16747
0
                int type;
16748
0
                atom = get_u32(pc);
16749
0
                type = pc[4];
16750
0
                pc += 5;
16751
0
                if (type == JS_THROW_VAR_RO)
16752
0
                    JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, atom);
16753
0
                else
16754
0
                if (type == JS_THROW_VAR_REDECL)
16755
0
                    JS_ThrowSyntaxErrorVarRedeclaration(ctx, atom);
16756
0
                else
16757
0
                if (type == JS_THROW_VAR_UNINITIALIZED)
16758
0
                    JS_ThrowReferenceErrorUninitialized(ctx, atom);
16759
0
                else
16760
0
                if (type == JS_THROW_ERROR_DELETE_SUPER)
16761
0
                    JS_ThrowReferenceError(ctx, "unsupported reference to 'super'");
16762
0
                else
16763
0
                if (type == JS_THROW_ERROR_ITERATOR_THROW)
16764
0
                    JS_ThrowTypeError(ctx, "iterator does not have a throw method");
16765
0
                else
16766
0
                    JS_ThrowInternalError(ctx, "invalid throw var type %d", type);
16767
0
            }
16768
0
            goto exception;
16769
16770
0
        CASE(OP_eval):
16771
0
            {
16772
0
                JSValueConst obj;
16773
0
                int scope_idx;
16774
0
                call_argc = get_u16(pc);
16775
0
                scope_idx = get_u16(pc + 2) - 1;
16776
0
                pc += 4;
16777
0
                call_argv = sp - call_argc;
16778
0
                sf->cur_pc = pc;
16779
0
                if (js_same_value(ctx, call_argv[-1], ctx->eval_obj)) {
16780
0
                    if (call_argc >= 1)
16781
0
                        obj = call_argv[0];
16782
0
                    else
16783
0
                        obj = JS_UNDEFINED;
16784
0
                    ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
16785
0
                                            JS_EVAL_TYPE_DIRECT, scope_idx);
16786
0
                } else {
16787
0
                    ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
16788
0
                                              JS_UNDEFINED, call_argc, call_argv, 0);
16789
0
                }
16790
0
                if (unlikely(JS_IsException(ret_val)))
16791
0
                    goto exception;
16792
0
                for(i = -1; i < call_argc; i++)
16793
0
                    JS_FreeValue(ctx, call_argv[i]);
16794
0
                sp -= call_argc + 1;
16795
0
                *sp++ = ret_val;
16796
0
            }
16797
0
            BREAK;
16798
            /* could merge with OP_apply */
16799
0
        CASE(OP_apply_eval):
16800
0
            {
16801
0
                int scope_idx;
16802
0
                uint32_t len;
16803
0
                JSValue *tab;
16804
0
                JSValueConst obj;
16805
16806
0
                scope_idx = get_u16(pc) - 1;
16807
0
                pc += 2;
16808
0
                tab = build_arg_list(ctx, &len, sp[-1]);
16809
0
                if (!tab)
16810
0
                    goto exception;
16811
0
                if (js_same_value(ctx, sp[-2], ctx->eval_obj)) {
16812
0
                    if (len >= 1)
16813
0
                        obj = tab[0];
16814
0
                    else
16815
0
                        obj = JS_UNDEFINED;
16816
0
                    ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
16817
0
                                            JS_EVAL_TYPE_DIRECT, scope_idx);
16818
0
                } else {
16819
0
                    ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len,
16820
0
                                      (JSValueConst *)tab);
16821
0
                }
16822
0
                free_arg_list(ctx, tab, len);
16823
0
                if (unlikely(JS_IsException(ret_val)))
16824
0
                    goto exception;
16825
0
                JS_FreeValue(ctx, sp[-2]);
16826
0
                JS_FreeValue(ctx, sp[-1]);
16827
0
                sp -= 2;
16828
0
                *sp++ = ret_val;
16829
0
            }
16830
0
            BREAK;
16831
16832
0
        CASE(OP_regexp):
16833
0
            {
16834
0
                sp[-2] = js_regexp_constructor_internal(ctx, JS_UNDEFINED,
16835
0
                                                        sp[-2], sp[-1]);
16836
0
                sp--;
16837
0
            }
16838
0
            BREAK;
16839
16840
0
        CASE(OP_get_super):
16841
0
            {
16842
0
                JSValue proto;
16843
0
                proto = JS_GetPrototype(ctx, sp[-1]);
16844
0
                if (JS_IsException(proto))
16845
0
                    goto exception;
16846
0
                JS_FreeValue(ctx, sp[-1]);
16847
0
                sp[-1] = proto;
16848
0
            }
16849
0
            BREAK;
16850
16851
0
        CASE(OP_import):
16852
0
            {
16853
0
                JSValue val;
16854
0
                val = js_dynamic_import(ctx, sp[-1]);
16855
0
                if (JS_IsException(val))
16856
0
                    goto exception;
16857
0
                JS_FreeValue(ctx, sp[-1]);
16858
0
                sp[-1] = val;
16859
0
            }
16860
0
            BREAK;
16861
16862
0
        CASE(OP_check_var):
16863
0
            {
16864
0
                int ret;
16865
0
                JSAtom atom;
16866
0
                atom = get_u32(pc);
16867
0
                pc += 4;
16868
16869
0
                ret = JS_CheckGlobalVar(ctx, atom);
16870
0
                if (ret < 0)
16871
0
                    goto exception;
16872
0
                *sp++ = JS_NewBool(ctx, ret);
16873
0
            }
16874
0
            BREAK;
16875
16876
0
        CASE(OP_get_var_undef):
16877
87
        CASE(OP_get_var):
16878
87
            {
16879
87
                JSValue val;
16880
87
                JSAtom atom;
16881
87
                atom = get_u32(pc);
16882
87
                pc += 4;
16883
16884
87
                val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef);
16885
87
                if (unlikely(JS_IsException(val)))
16886
9
                    goto exception;
16887
78
                *sp++ = val;
16888
78
            }
16889
78
            BREAK;
16890
16891
78
        CASE(OP_put_var):
16892
0
        CASE(OP_put_var_init):
16893
0
            {
16894
0
                int ret;
16895
0
                JSAtom atom;
16896
0
                atom = get_u32(pc);
16897
0
                pc += 4;
16898
16899
0
                ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var);
16900
0
                sp--;
16901
0
                if (unlikely(ret < 0))
16902
0
                    goto exception;
16903
0
            }
16904
0
            BREAK;
16905
16906
0
        CASE(OP_put_var_strict):
16907
0
            {
16908
0
                int ret;
16909
0
                JSAtom atom;
16910
0
                atom = get_u32(pc);
16911
0
                pc += 4;
16912
16913
                /* sp[-2] is JS_TRUE or JS_FALSE */
16914
0
                if (unlikely(!JS_VALUE_GET_INT(sp[-2]))) {
16915
0
                    JS_ThrowReferenceErrorNotDefined(ctx, atom);
16916
0
                    goto exception;
16917
0
                }
16918
0
                ret = JS_SetGlobalVar(ctx, atom, sp[-1], 2);
16919
0
                sp -= 2;
16920
0
                if (unlikely(ret < 0))
16921
0
                    goto exception;
16922
0
            }
16923
0
            BREAK;
16924
16925
0
        CASE(OP_check_define_var):
16926
0
            {
16927
0
                JSAtom atom;
16928
0
                int flags;
16929
0
                atom = get_u32(pc);
16930
0
                flags = pc[4];
16931
0
                pc += 5;
16932
0
                if (JS_CheckDefineGlobalVar(ctx, atom, flags))
16933
0
                    goto exception;
16934
0
            }
16935
0
            BREAK;
16936
0
        CASE(OP_define_var):
16937
0
            {
16938
0
                JSAtom atom;
16939
0
                int flags;
16940
0
                atom = get_u32(pc);
16941
0
                flags = pc[4];
16942
0
                pc += 5;
16943
0
                if (JS_DefineGlobalVar(ctx, atom, flags))
16944
0
                    goto exception;
16945
0
            }
16946
0
            BREAK;
16947
0
        CASE(OP_define_func):
16948
0
            {
16949
0
                JSAtom atom;
16950
0
                int flags;
16951
0
                atom = get_u32(pc);
16952
0
                flags = pc[4];
16953
0
                pc += 5;
16954
0
                if (JS_DefineGlobalFunction(ctx, atom, sp[-1], flags))
16955
0
                    goto exception;
16956
0
                JS_FreeValue(ctx, sp[-1]);
16957
0
                sp--;
16958
0
            }
16959
0
            BREAK;
16960
16961
0
        CASE(OP_get_loc):
16962
0
            {
16963
0
                int idx;
16964
0
                idx = get_u16(pc);
16965
0
                pc += 2;
16966
0
                sp[0] = JS_DupValue(ctx, var_buf[idx]);
16967
0
                sp++;
16968
0
            }
16969
0
            BREAK;
16970
0
        CASE(OP_put_loc):
16971
0
            {
16972
0
                int idx;
16973
0
                idx = get_u16(pc);
16974
0
                pc += 2;
16975
0
                set_value(ctx, &var_buf[idx], sp[-1]);
16976
0
                sp--;
16977
0
            }
16978
0
            BREAK;
16979
0
        CASE(OP_set_loc):
16980
0
            {
16981
0
                int idx;
16982
0
                idx = get_u16(pc);
16983
0
                pc += 2;
16984
0
                set_value(ctx, &var_buf[idx], JS_DupValue(ctx, sp[-1]));
16985
0
            }
16986
0
            BREAK;
16987
0
        CASE(OP_get_arg):
16988
0
            {
16989
0
                int idx;
16990
0
                idx = get_u16(pc);
16991
0
                pc += 2;
16992
0
                sp[0] = JS_DupValue(ctx, arg_buf[idx]);
16993
0
                sp++;
16994
0
            }
16995
0
            BREAK;
16996
0
        CASE(OP_put_arg):
16997
0
            {
16998
0
                int idx;
16999
0
                idx = get_u16(pc);
17000
0
                pc += 2;
17001
0
                set_value(ctx, &arg_buf[idx], sp[-1]);
17002
0
                sp--;
17003
0
            }
17004
0
            BREAK;
17005
0
        CASE(OP_set_arg):
17006
0
            {
17007
0
                int idx;
17008
0
                idx = get_u16(pc);
17009
0
                pc += 2;
17010
0
                set_value(ctx, &arg_buf[idx], JS_DupValue(ctx, sp[-1]));
17011
0
            }
17012
0
            BREAK;
17013
17014
0
#if SHORT_OPCODES
17015
0
        CASE(OP_get_loc8): *sp++ = JS_DupValue(ctx, var_buf[*pc++]); BREAK;
17016
0
        CASE(OP_put_loc8): set_value(ctx, &var_buf[*pc++], *--sp); BREAK;
17017
0
        CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], JS_DupValue(ctx, sp[-1])); BREAK;
17018
17019
0
        CASE(OP_get_loc0): *sp++ = JS_DupValue(ctx, var_buf[0]); BREAK;
17020
0
        CASE(OP_get_loc1): *sp++ = JS_DupValue(ctx, var_buf[1]); BREAK;
17021
0
        CASE(OP_get_loc2): *sp++ = JS_DupValue(ctx, var_buf[2]); BREAK;
17022
0
        CASE(OP_get_loc3): *sp++ = JS_DupValue(ctx, var_buf[3]); BREAK;
17023
1
        CASE(OP_put_loc0): set_value(ctx, &var_buf[0], *--sp); BREAK;
17024
1
        CASE(OP_put_loc1): set_value(ctx, &var_buf[1], *--sp); BREAK;
17025
0
        CASE(OP_put_loc2): set_value(ctx, &var_buf[2], *--sp); BREAK;
17026
0
        CASE(OP_put_loc3): set_value(ctx, &var_buf[3], *--sp); BREAK;
17027
15
        CASE(OP_set_loc0): set_value(ctx, &var_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;
17028
15
        CASE(OP_set_loc1): set_value(ctx, &var_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;
17029
0
        CASE(OP_set_loc2): set_value(ctx, &var_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;
17030
0
        CASE(OP_set_loc3): set_value(ctx, &var_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;
17031
0
        CASE(OP_get_arg0): *sp++ = JS_DupValue(ctx, arg_buf[0]); BREAK;
17032
0
        CASE(OP_get_arg1): *sp++ = JS_DupValue(ctx, arg_buf[1]); BREAK;
17033
0
        CASE(OP_get_arg2): *sp++ = JS_DupValue(ctx, arg_buf[2]); BREAK;
17034
0
        CASE(OP_get_arg3): *sp++ = JS_DupValue(ctx, arg_buf[3]); BREAK;
17035
0
        CASE(OP_put_arg0): set_value(ctx, &arg_buf[0], *--sp); BREAK;
17036
0
        CASE(OP_put_arg1): set_value(ctx, &arg_buf[1], *--sp); BREAK;
17037
0
        CASE(OP_put_arg2): set_value(ctx, &arg_buf[2], *--sp); BREAK;
17038
0
        CASE(OP_put_arg3): set_value(ctx, &arg_buf[3], *--sp); BREAK;
17039
0
        CASE(OP_set_arg0): set_value(ctx, &arg_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;
17040
0
        CASE(OP_set_arg1): set_value(ctx, &arg_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;
17041
0
        CASE(OP_set_arg2): set_value(ctx, &arg_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;
17042
0
        CASE(OP_set_arg3): set_value(ctx, &arg_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;
17043
0
        CASE(OP_get_var_ref0): *sp++ = JS_DupValue(ctx, *var_refs[0]->pvalue); BREAK;
17044
0
        CASE(OP_get_var_ref1): *sp++ = JS_DupValue(ctx, *var_refs[1]->pvalue); BREAK;
17045
0
        CASE(OP_get_var_ref2): *sp++ = JS_DupValue(ctx, *var_refs[2]->pvalue); BREAK;
17046
0
        CASE(OP_get_var_ref3): *sp++ = JS_DupValue(ctx, *var_refs[3]->pvalue); BREAK;
17047
0
        CASE(OP_put_var_ref0): set_value(ctx, var_refs[0]->pvalue, *--sp); BREAK;
17048
0
        CASE(OP_put_var_ref1): set_value(ctx, var_refs[1]->pvalue, *--sp); BREAK;
17049
0
        CASE(OP_put_var_ref2): set_value(ctx, var_refs[2]->pvalue, *--sp); BREAK;
17050
0
        CASE(OP_put_var_ref3): set_value(ctx, var_refs[3]->pvalue, *--sp); BREAK;
17051
0
        CASE(OP_set_var_ref0): set_value(ctx, var_refs[0]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17052
0
        CASE(OP_set_var_ref1): set_value(ctx, var_refs[1]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17053
0
        CASE(OP_set_var_ref2): set_value(ctx, var_refs[2]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17054
0
        CASE(OP_set_var_ref3): set_value(ctx, var_refs[3]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17055
0
#endif
17056
17057
0
        CASE(OP_get_var_ref):
17058
0
            {
17059
0
                int idx;
17060
0
                JSValue val;
17061
0
                idx = get_u16(pc);
17062
0
                pc += 2;
17063
0
                val = *var_refs[idx]->pvalue;
17064
0
                sp[0] = JS_DupValue(ctx, val);
17065
0
                sp++;
17066
0
            }
17067
0
            BREAK;
17068
0
        CASE(OP_put_var_ref):
17069
0
            {
17070
0
                int idx;
17071
0
                idx = get_u16(pc);
17072
0
                pc += 2;
17073
0
                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
17074
0
                sp--;
17075
0
            }
17076
0
            BREAK;
17077
0
        CASE(OP_set_var_ref):
17078
0
            {
17079
0
                int idx;
17080
0
                idx = get_u16(pc);
17081
0
                pc += 2;
17082
0
                set_value(ctx, var_refs[idx]->pvalue, JS_DupValue(ctx, sp[-1]));
17083
0
            }
17084
0
            BREAK;
17085
78
        CASE(OP_get_var_ref_check):
17086
78
            {
17087
78
                int idx;
17088
78
                JSValue val;
17089
78
                idx = get_u16(pc);
17090
78
                pc += 2;
17091
78
                val = *var_refs[idx]->pvalue;
17092
78
                if (unlikely(JS_IsUninitialized(val))) {
17093
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
17094
0
                    goto exception;
17095
0
                }
17096
78
                sp[0] = JS_DupValue(ctx, val);
17097
78
                sp++;
17098
78
            }
17099
78
            BREAK;
17100
78
        CASE(OP_put_var_ref_check):
17101
0
            {
17102
0
                int idx;
17103
0
                idx = get_u16(pc);
17104
0
                pc += 2;
17105
0
                if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) {
17106
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
17107
0
                    goto exception;
17108
0
                }
17109
0
                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
17110
0
                sp--;
17111
0
            }
17112
0
            BREAK;
17113
0
        CASE(OP_put_var_ref_check_init):
17114
0
            {
17115
0
                int idx;
17116
0
                idx = get_u16(pc);
17117
0
                pc += 2;
17118
0
                if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) {
17119
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
17120
0
                    goto exception;
17121
0
                }
17122
0
                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
17123
0
                sp--;
17124
0
            }
17125
0
            BREAK;
17126
0
        CASE(OP_set_loc_uninitialized):
17127
0
            {
17128
0
                int idx;
17129
0
                idx = get_u16(pc);
17130
0
                pc += 2;
17131
0
                set_value(ctx, &var_buf[idx], JS_UNINITIALIZED);
17132
0
            }
17133
0
            BREAK;
17134
0
        CASE(OP_get_loc_check):
17135
0
            {
17136
0
                int idx;
17137
0
                idx = get_u16(pc);
17138
0
                pc += 2;
17139
0
                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
17140
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
17141
0
                    goto exception;
17142
0
                }
17143
0
                sp[0] = JS_DupValue(ctx, var_buf[idx]);
17144
0
                sp++;
17145
0
            }
17146
0
            BREAK;
17147
0
        CASE(OP_get_loc_checkthis):
17148
0
            {
17149
0
                int idx;
17150
0
                idx = get_u16(pc);
17151
0
                pc += 2;
17152
0
                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
17153
0
                    JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, FALSE);
17154
0
                    goto exception;
17155
0
                }
17156
0
                sp[0] = JS_DupValue(ctx, var_buf[idx]);
17157
0
                sp++;
17158
0
            }
17159
0
            BREAK;
17160
0
        CASE(OP_put_loc_check):
17161
0
            {
17162
0
                int idx;
17163
0
                idx = get_u16(pc);
17164
0
                pc += 2;
17165
0
                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
17166
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
17167
0
                    goto exception;
17168
0
                }
17169
0
                set_value(ctx, &var_buf[idx], sp[-1]);
17170
0
                sp--;
17171
0
            }
17172
0
            BREAK;
17173
0
        CASE(OP_put_loc_check_init):
17174
0
            {
17175
0
                int idx;
17176
0
                idx = get_u16(pc);
17177
0
                pc += 2;
17178
0
                if (unlikely(!JS_IsUninitialized(var_buf[idx]))) {
17179
0
                    JS_ThrowReferenceError(ctx, "'this' can be initialized only once");
17180
0
                    goto exception;
17181
0
                }
17182
0
                set_value(ctx, &var_buf[idx], sp[-1]);
17183
0
                sp--;
17184
0
            }
17185
0
            BREAK;
17186
0
        CASE(OP_close_loc):
17187
0
            {
17188
0
                int idx;
17189
0
                idx = get_u16(pc);
17190
0
                pc += 2;
17191
0
                close_lexical_var(ctx, sf, idx, FALSE);
17192
0
            }
17193
0
            BREAK;
17194
17195
0
        CASE(OP_make_loc_ref):
17196
0
        CASE(OP_make_arg_ref):
17197
0
        CASE(OP_make_var_ref_ref):
17198
0
            {
17199
0
                JSVarRef *var_ref;
17200
0
                JSProperty *pr;
17201
0
                JSAtom atom;
17202
0
                int idx;
17203
0
                atom = get_u32(pc);
17204
0
                idx = get_u16(pc + 4);
17205
0
                pc += 6;
17206
0
                *sp++ = JS_NewObjectProto(ctx, JS_NULL);
17207
0
                if (unlikely(JS_IsException(sp[-1])))
17208
0
                    goto exception;
17209
0
                if (opcode == OP_make_var_ref_ref) {
17210
0
                    var_ref = var_refs[idx];
17211
0
                    var_ref->header.ref_count++;
17212
0
                } else {
17213
0
                    var_ref = get_var_ref(ctx, sf, idx, opcode == OP_make_arg_ref);
17214
0
                    if (!var_ref)
17215
0
                        goto exception;
17216
0
                }
17217
0
                pr = add_property(ctx, JS_VALUE_GET_OBJ(sp[-1]), atom,
17218
0
                                  JS_PROP_WRITABLE | JS_PROP_VARREF);
17219
0
                if (!pr) {
17220
0
                    free_var_ref(rt, var_ref);
17221
0
                    goto exception;
17222
0
                }
17223
0
                pr->u.var_ref = var_ref;
17224
0
                *sp++ = JS_AtomToValue(ctx, atom);
17225
0
            }
17226
0
            BREAK;
17227
0
        CASE(OP_make_var_ref):
17228
0
            {
17229
0
                JSAtom atom;
17230
0
                atom = get_u32(pc);
17231
0
                pc += 4;
17232
17233
0
                if (JS_GetGlobalVarRef(ctx, atom, sp))
17234
0
                    goto exception;
17235
0
                sp += 2;
17236
0
            }
17237
0
            BREAK;
17238
17239
0
        CASE(OP_goto):
17240
0
            pc += (int32_t)get_u32(pc);
17241
0
            if (unlikely(js_poll_interrupts(ctx)))
17242
0
                goto exception;
17243
0
            BREAK;
17244
0
#if SHORT_OPCODES
17245
0
        CASE(OP_goto16):
17246
0
            pc += (int16_t)get_u16(pc);
17247
0
            if (unlikely(js_poll_interrupts(ctx)))
17248
0
                goto exception;
17249
0
            BREAK;
17250
0
        CASE(OP_goto8):
17251
0
            pc += (int8_t)pc[0];
17252
0
            if (unlikely(js_poll_interrupts(ctx)))
17253
0
                goto exception;
17254
0
            BREAK;
17255
0
#endif
17256
0
        CASE(OP_if_true):
17257
0
            {
17258
0
                int res;
17259
0
                JSValue op1;
17260
17261
0
                op1 = sp[-1];
17262
0
                pc += 4;
17263
0
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17264
0
                    res = JS_VALUE_GET_INT(op1);
17265
0
                } else {
17266
0
                    res = JS_ToBoolFree(ctx, op1);
17267
0
                }
17268
0
                sp--;
17269
0
                if (res) {
17270
0
                    pc += (int32_t)get_u32(pc - 4) - 4;
17271
0
                }
17272
0
                if (unlikely(js_poll_interrupts(ctx)))
17273
0
                    goto exception;
17274
0
            }
17275
0
            BREAK;
17276
0
        CASE(OP_if_false):
17277
0
            {
17278
0
                int res;
17279
0
                JSValue op1;
17280
17281
0
                op1 = sp[-1];
17282
0
                pc += 4;
17283
                /* quick and dirty test for JS_TAG_INT, JS_TAG_BOOL, JS_TAG_NULL and JS_TAG_UNDEFINED */
17284
0
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17285
0
                    res = JS_VALUE_GET_INT(op1);
17286
0
                } else {
17287
0
                    res = JS_ToBoolFree(ctx, op1);
17288
0
                }
17289
0
                sp--;
17290
0
                if (!res) {
17291
0
                    pc += (int32_t)get_u32(pc - 4) - 4;
17292
0
                }
17293
0
                if (unlikely(js_poll_interrupts(ctx)))
17294
0
                    goto exception;
17295
0
            }
17296
0
            BREAK;
17297
0
#if SHORT_OPCODES
17298
0
        CASE(OP_if_true8):
17299
0
            {
17300
0
                int res;
17301
0
                JSValue op1;
17302
17303
0
                op1 = sp[-1];
17304
0
                pc += 1;
17305
0
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17306
0
                    res = JS_VALUE_GET_INT(op1);
17307
0
                } else {
17308
0
                    res = JS_ToBoolFree(ctx, op1);
17309
0
                }
17310
0
                sp--;
17311
0
                if (res) {
17312
0
                    pc += (int8_t)pc[-1] - 1;
17313
0
                }
17314
0
                if (unlikely(js_poll_interrupts(ctx)))
17315
0
                    goto exception;
17316
0
            }
17317
0
            BREAK;
17318
78
        CASE(OP_if_false8):
17319
78
            {
17320
78
                int res;
17321
78
                JSValue op1;
17322
17323
78
                op1 = sp[-1];
17324
78
                pc += 1;
17325
78
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17326
78
                    res = JS_VALUE_GET_INT(op1);
17327
78
                } else {
17328
0
                    res = JS_ToBoolFree(ctx, op1);
17329
0
                }
17330
78
                sp--;
17331
78
                if (!res) {
17332
39
                    pc += (int8_t)pc[-1] - 1;
17333
39
                }
17334
78
                if (unlikely(js_poll_interrupts(ctx)))
17335
0
                    goto exception;
17336
78
            }
17337
78
            BREAK;
17338
78
#endif
17339
78
        CASE(OP_catch):
17340
0
            {
17341
0
                int32_t diff;
17342
0
                diff = get_u32(pc);
17343
0
                sp[0] = JS_NewCatchOffset(ctx, pc + diff - b->byte_code_buf);
17344
0
                sp++;
17345
0
                pc += 4;
17346
0
            }
17347
0
            BREAK;
17348
0
        CASE(OP_gosub):
17349
0
            {
17350
0
                int32_t diff;
17351
0
                diff = get_u32(pc);
17352
                /* XXX: should have a different tag to avoid security flaw */
17353
0
                sp[0] = JS_NewInt32(ctx, pc + 4 - b->byte_code_buf);
17354
0
                sp++;
17355
0
                pc += diff;
17356
0
            }
17357
0
            BREAK;
17358
0
        CASE(OP_ret):
17359
0
            {
17360
0
                JSValue op1;
17361
0
                uint32_t pos;
17362
0
                op1 = sp[-1];
17363
0
                if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_INT))
17364
0
                    goto ret_fail;
17365
0
                pos = JS_VALUE_GET_INT(op1);
17366
0
                if (unlikely(pos >= b->byte_code_len)) {
17367
0
                ret_fail:
17368
0
                    JS_ThrowInternalError(ctx, "invalid ret value");
17369
0
                    goto exception;
17370
0
                }
17371
0
                sp--;
17372
0
                pc = b->byte_code_buf + pos;
17373
0
            }
17374
0
            BREAK;
17375
17376
0
        CASE(OP_for_in_start):
17377
0
            if (js_for_in_start(ctx, sp))
17378
0
                goto exception;
17379
0
            BREAK;
17380
0
        CASE(OP_for_in_next):
17381
0
            if (js_for_in_next(ctx, sp))
17382
0
                goto exception;
17383
0
            sp += 2;
17384
0
            BREAK;
17385
0
        CASE(OP_for_of_start):
17386
0
            if (js_for_of_start(ctx, sp, FALSE))
17387
0
                goto exception;
17388
0
            sp += 1;
17389
0
            *sp++ = JS_NewCatchOffset(ctx, 0);
17390
0
            BREAK;
17391
0
        CASE(OP_for_of_next):
17392
0
            {
17393
0
                int offset = -3 - pc[0];
17394
0
                pc += 1;
17395
0
                if (js_for_of_next(ctx, sp, offset))
17396
0
                    goto exception;
17397
0
                sp += 2;
17398
0
            }
17399
0
            BREAK;
17400
0
        CASE(OP_for_await_of_start):
17401
0
            if (js_for_of_start(ctx, sp, TRUE))
17402
0
                goto exception;
17403
0
            sp += 1;
17404
0
            *sp++ = JS_NewCatchOffset(ctx, 0);
17405
0
            BREAK;
17406
0
        CASE(OP_iterator_get_value_done):
17407
0
            if (js_iterator_get_value_done(ctx, sp))
17408
0
                goto exception;
17409
0
            sp += 1;
17410
0
            BREAK;
17411
0
        CASE(OP_iterator_check_object):
17412
0
            if (unlikely(!JS_IsObject(sp[-1]))) {
17413
0
                JS_ThrowTypeError(ctx, "iterator must return an object");
17414
0
                goto exception;
17415
0
            }
17416
0
            BREAK;
17417
17418
0
        CASE(OP_iterator_close):
17419
            /* iter_obj next catch_offset -> */
17420
0
            sp--; /* drop the catch offset to avoid getting caught by exception */
17421
0
            JS_FreeValue(ctx, sp[-1]); /* drop the next method */
17422
0
            sp--;
17423
0
            if (!JS_IsUndefined(sp[-1])) {
17424
0
                if (JS_IteratorClose(ctx, sp[-1], FALSE))
17425
0
                    goto exception;
17426
0
                JS_FreeValue(ctx, sp[-1]);
17427
0
            }
17428
0
            sp--;
17429
0
            BREAK;
17430
0
        CASE(OP_nip_catch):
17431
0
            {
17432
0
                JSValue ret_val;
17433
                /* catch_offset ... ret_val -> ret_eval */
17434
0
                ret_val = *--sp;
17435
0
                while (sp > stack_buf &&
17436
0
                       JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) {
17437
0
                    JS_FreeValue(ctx, *--sp);
17438
0
                }
17439
0
                if (unlikely(sp == stack_buf)) {
17440
0
                    JS_ThrowInternalError(ctx, "nip_catch");
17441
0
                    JS_FreeValue(ctx, ret_val);
17442
0
                    goto exception;
17443
0
                }
17444
0
                sp[-1] = ret_val;
17445
0
            }
17446
0
            BREAK;
17447
17448
0
        CASE(OP_iterator_next):
17449
            /* stack: iter_obj next catch_offset val */
17450
0
            {
17451
0
                JSValue ret;
17452
0
                ret = JS_Call(ctx, sp[-3], sp[-4],
17453
0
                              1, (JSValueConst *)(sp - 1));
17454
0
                if (JS_IsException(ret))
17455
0
                    goto exception;
17456
0
                JS_FreeValue(ctx, sp[-1]);
17457
0
                sp[-1] = ret;
17458
0
            }
17459
0
            BREAK;
17460
17461
0
        CASE(OP_iterator_call):
17462
            /* stack: iter_obj next catch_offset val */
17463
0
            {
17464
0
                JSValue method, ret;
17465
0
                BOOL ret_flag;
17466
0
                int flags;
17467
0
                flags = *pc++;
17468
0
                method = JS_GetProperty(ctx, sp[-4], (flags & 1) ?
17469
0
                                        JS_ATOM_throw : JS_ATOM_return);
17470
0
                if (JS_IsException(method))
17471
0
                    goto exception;
17472
0
                if (JS_IsUndefined(method) || JS_IsNull(method)) {
17473
0
                    ret_flag = TRUE;
17474
0
                } else {
17475
0
                    if (flags & 2) {
17476
                        /* no argument */
17477
0
                        ret = JS_CallFree(ctx, method, sp[-4],
17478
0
                                          0, NULL);
17479
0
                    } else {
17480
0
                        ret = JS_CallFree(ctx, method, sp[-4],
17481
0
                                          1, (JSValueConst *)(sp - 1));
17482
0
                    }
17483
0
                    if (JS_IsException(ret))
17484
0
                        goto exception;
17485
0
                    JS_FreeValue(ctx, sp[-1]);
17486
0
                    sp[-1] = ret;
17487
0
                    ret_flag = FALSE;
17488
0
                }
17489
0
                sp[0] = JS_NewBool(ctx, ret_flag);
17490
0
                sp += 1;
17491
0
            }
17492
0
            BREAK;
17493
17494
0
        CASE(OP_lnot):
17495
0
            {
17496
0
                int res;
17497
0
                JSValue op1;
17498
17499
0
                op1 = sp[-1];
17500
0
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17501
0
                    res = JS_VALUE_GET_INT(op1) != 0;
17502
0
                } else {
17503
0
                    res = JS_ToBoolFree(ctx, op1);
17504
0
                }
17505
0
                sp[-1] = JS_NewBool(ctx, !res);
17506
0
            }
17507
0
            BREAK;
17508
17509
0
        CASE(OP_get_field):
17510
0
            {
17511
0
                JSValue val;
17512
0
                JSAtom atom;
17513
0
                atom = get_u32(pc);
17514
0
                pc += 4;
17515
17516
0
                val = JS_GetProperty(ctx, sp[-1], atom);
17517
0
                if (unlikely(JS_IsException(val)))
17518
0
                    goto exception;
17519
0
                JS_FreeValue(ctx, sp[-1]);
17520
0
                sp[-1] = val;
17521
0
            }
17522
0
            BREAK;
17523
17524
0
        CASE(OP_get_field2):
17525
0
            {
17526
0
                JSValue val;
17527
0
                JSAtom atom;
17528
0
                atom = get_u32(pc);
17529
0
                pc += 4;
17530
17531
0
                val = JS_GetProperty(ctx, sp[-1], atom);
17532
0
                if (unlikely(JS_IsException(val)))
17533
0
                    goto exception;
17534
0
                *sp++ = val;
17535
0
            }
17536
0
            BREAK;
17537
17538
78
        CASE(OP_put_field):
17539
78
            {
17540
78
                int ret;
17541
78
                JSAtom atom;
17542
78
                atom = get_u32(pc);
17543
78
                pc += 4;
17544
17545
78
                ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], sp[-2],
17546
78
                                             JS_PROP_THROW_STRICT);
17547
78
                JS_FreeValue(ctx, sp[-2]);
17548
78
                sp -= 2;
17549
78
                if (unlikely(ret < 0))
17550
0
                    goto exception;
17551
78
            }
17552
78
            BREAK;
17553
17554
78
        CASE(OP_private_symbol):
17555
0
            {
17556
0
                JSAtom atom;
17557
0
                JSValue val;
17558
17559
0
                atom = get_u32(pc);
17560
0
                pc += 4;
17561
0
                val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE);
17562
0
                if (JS_IsException(val))
17563
0
                    goto exception;
17564
0
                *sp++ = val;
17565
0
            }
17566
0
            BREAK;
17567
17568
0
        CASE(OP_get_private_field):
17569
0
            {
17570
0
                JSValue val;
17571
17572
0
                val = JS_GetPrivateField(ctx, sp[-2], sp[-1]);
17573
0
                JS_FreeValue(ctx, sp[-1]);
17574
0
                JS_FreeValue(ctx, sp[-2]);
17575
0
                sp[-2] = val;
17576
0
                sp--;
17577
0
                if (unlikely(JS_IsException(val)))
17578
0
                    goto exception;
17579
0
            }
17580
0
            BREAK;
17581
17582
0
        CASE(OP_put_private_field):
17583
0
            {
17584
0
                int ret;
17585
0
                ret = JS_SetPrivateField(ctx, sp[-3], sp[-1], sp[-2]);
17586
0
                JS_FreeValue(ctx, sp[-3]);
17587
0
                JS_FreeValue(ctx, sp[-1]);
17588
0
                sp -= 3;
17589
0
                if (unlikely(ret < 0))
17590
0
                    goto exception;
17591
0
            }
17592
0
            BREAK;
17593
17594
0
        CASE(OP_define_private_field):
17595
0
            {
17596
0
                int ret;
17597
0
                ret = JS_DefinePrivateField(ctx, sp[-3], sp[-2], sp[-1]);
17598
0
                JS_FreeValue(ctx, sp[-2]);
17599
0
                sp -= 2;
17600
0
                if (unlikely(ret < 0))
17601
0
                    goto exception;
17602
0
            }
17603
0
            BREAK;
17604
17605
2.99M
        CASE(OP_define_field):
17606
2.99M
            {
17607
2.99M
                int ret;
17608
2.99M
                JSAtom atom;
17609
2.99M
                atom = get_u32(pc);
17610
2.99M
                pc += 4;
17611
17612
2.99M
                ret = JS_DefinePropertyValue(ctx, sp[-2], atom, sp[-1],
17613
2.99M
                                             JS_PROP_C_W_E | JS_PROP_THROW);
17614
2.99M
                sp--;
17615
2.99M
                if (unlikely(ret < 0))
17616
0
                    goto exception;
17617
2.99M
            }
17618
2.99M
            BREAK;
17619
17620
2.99M
        CASE(OP_set_name):
17621
0
            {
17622
0
                int ret;
17623
0
                JSAtom atom;
17624
0
                atom = get_u32(pc);
17625
0
                pc += 4;
17626
17627
0
                ret = JS_DefineObjectName(ctx, sp[-1], atom, JS_PROP_CONFIGURABLE);
17628
0
                if (unlikely(ret < 0))
17629
0
                    goto exception;
17630
0
            }
17631
0
            BREAK;
17632
0
        CASE(OP_set_name_computed):
17633
0
            {
17634
0
                int ret;
17635
0
                ret = JS_DefineObjectNameComputed(ctx, sp[-1], sp[-2], JS_PROP_CONFIGURABLE);
17636
0
                if (unlikely(ret < 0))
17637
0
                    goto exception;
17638
0
            }
17639
0
            BREAK;
17640
0
        CASE(OP_set_proto):
17641
0
            {
17642
0
                JSValue proto;
17643
0
                proto = sp[-1];
17644
0
                if (JS_IsObject(proto) || JS_IsNull(proto)) {
17645
0
                    if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0)
17646
0
                        goto exception;
17647
0
                }
17648
0
                JS_FreeValue(ctx, proto);
17649
0
                sp--;
17650
0
            }
17651
0
            BREAK;
17652
0
        CASE(OP_set_home_object):
17653
0
            js_method_set_home_object(ctx, sp[-1], sp[-2]);
17654
0
            BREAK;
17655
0
        CASE(OP_define_method):
17656
0
        CASE(OP_define_method_computed):
17657
0
            {
17658
0
                JSValue getter, setter, value;
17659
0
                JSValueConst obj;
17660
0
                JSAtom atom;
17661
0
                int flags, ret, op_flags;
17662
0
                BOOL is_computed;
17663
0
#define OP_DEFINE_METHOD_METHOD 0
17664
0
#define OP_DEFINE_METHOD_GETTER 1
17665
0
#define OP_DEFINE_METHOD_SETTER 2
17666
0
#define OP_DEFINE_METHOD_ENUMERABLE 4
17667
17668
0
                is_computed = (opcode == OP_define_method_computed);
17669
0
                if (is_computed) {
17670
0
                    atom = JS_ValueToAtom(ctx, sp[-2]);
17671
0
                    if (unlikely(atom == JS_ATOM_NULL))
17672
0
                        goto exception;
17673
0
                    opcode += OP_define_method - OP_define_method_computed;
17674
0
                } else {
17675
0
                    atom = get_u32(pc);
17676
0
                    pc += 4;
17677
0
                }
17678
0
                op_flags = *pc++;
17679
17680
0
                obj = sp[-2 - is_computed];
17681
0
                flags = JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE |
17682
0
                    JS_PROP_HAS_ENUMERABLE | JS_PROP_THROW;
17683
0
                if (op_flags & OP_DEFINE_METHOD_ENUMERABLE)
17684
0
                    flags |= JS_PROP_ENUMERABLE;
17685
0
                op_flags &= 3;
17686
0
                value = JS_UNDEFINED;
17687
0
                getter = JS_UNDEFINED;
17688
0
                setter = JS_UNDEFINED;
17689
0
                if (op_flags == OP_DEFINE_METHOD_METHOD) {
17690
0
                    value = sp[-1];
17691
0
                    flags |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE;
17692
0
                } else if (op_flags == OP_DEFINE_METHOD_GETTER) {
17693
0
                    getter = sp[-1];
17694
0
                    flags |= JS_PROP_HAS_GET;
17695
0
                } else {
17696
0
                    setter = sp[-1];
17697
0
                    flags |= JS_PROP_HAS_SET;
17698
0
                }
17699
0
                ret = js_method_set_properties(ctx, sp[-1], atom, flags, obj);
17700
0
                if (ret >= 0) {
17701
0
                    ret = JS_DefineProperty(ctx, obj, atom, value,
17702
0
                                            getter, setter, flags);
17703
0
                }
17704
0
                JS_FreeValue(ctx, sp[-1]);
17705
0
                if (is_computed) {
17706
0
                    JS_FreeAtom(ctx, atom);
17707
0
                    JS_FreeValue(ctx, sp[-2]);
17708
0
                }
17709
0
                sp -= 1 + is_computed;
17710
0
                if (unlikely(ret < 0))
17711
0
                    goto exception;
17712
0
            }
17713
0
            BREAK;
17714
17715
0
        CASE(OP_define_class):
17716
0
        CASE(OP_define_class_computed):
17717
0
            {
17718
0
                int class_flags;
17719
0
                JSAtom atom;
17720
17721
0
                atom = get_u32(pc);
17722
0
                class_flags = pc[4];
17723
0
                pc += 5;
17724
0
                if (js_op_define_class(ctx, sp, atom, class_flags,
17725
0
                                       var_refs, sf,
17726
0
                                       (opcode == OP_define_class_computed)) < 0)
17727
0
                    goto exception;
17728
0
            }
17729
0
            BREAK;
17730
17731
0
        CASE(OP_get_array_el):
17732
0
            {
17733
0
                JSValue val;
17734
17735
0
                val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
17736
0
                JS_FreeValue(ctx, sp[-2]);
17737
0
                sp[-2] = val;
17738
0
                sp--;
17739
0
                if (unlikely(JS_IsException(val)))
17740
0
                    goto exception;
17741
0
            }
17742
0
            BREAK;
17743
17744
0
        CASE(OP_get_array_el2):
17745
0
            {
17746
0
                JSValue val;
17747
17748
0
                val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
17749
0
                sp[-1] = val;
17750
0
                if (unlikely(JS_IsException(val)))
17751
0
                    goto exception;
17752
0
            }
17753
0
            BREAK;
17754
17755
0
        CASE(OP_get_ref_value):
17756
0
            {
17757
0
                JSValue val;
17758
0
                if (unlikely(JS_IsUndefined(sp[-2]))) {
17759
0
                    JSAtom atom = JS_ValueToAtom(ctx, sp[-1]);
17760
0
                    if (atom != JS_ATOM_NULL) {
17761
0
                        JS_ThrowReferenceErrorNotDefined(ctx, atom);
17762
0
                        JS_FreeAtom(ctx, atom);
17763
0
                    }
17764
0
                    goto exception;
17765
0
                }
17766
0
                val = JS_GetPropertyValue(ctx, sp[-2],
17767
0
                                          JS_DupValue(ctx, sp[-1]));
17768
0
                if (unlikely(JS_IsException(val)))
17769
0
                    goto exception;
17770
0
                sp[0] = val;
17771
0
                sp++;
17772
0
            }
17773
0
            BREAK;
17774
17775
0
        CASE(OP_get_super_value):
17776
0
            {
17777
0
                JSValue val;
17778
0
                JSAtom atom;
17779
0
                atom = JS_ValueToAtom(ctx, sp[-1]);
17780
0
                if (unlikely(atom == JS_ATOM_NULL))
17781
0
                    goto exception;
17782
0
                val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], FALSE);
17783
0
                JS_FreeAtom(ctx, atom);
17784
0
                if (unlikely(JS_IsException(val)))
17785
0
                    goto exception;
17786
0
                JS_FreeValue(ctx, sp[-1]);
17787
0
                JS_FreeValue(ctx, sp[-2]);
17788
0
                JS_FreeValue(ctx, sp[-3]);
17789
0
                sp[-3] = val;
17790
0
                sp -= 2;
17791
0
            }
17792
0
            BREAK;
17793
17794
0
        CASE(OP_put_array_el):
17795
0
            {
17796
0
                int ret;
17797
17798
0
                ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
17799
0
                JS_FreeValue(ctx, sp[-3]);
17800
0
                sp -= 3;
17801
0
                if (unlikely(ret < 0))
17802
0
                    goto exception;
17803
0
            }
17804
0
            BREAK;
17805
17806
0
        CASE(OP_put_ref_value):
17807
0
            {
17808
0
                int ret, flags;
17809
0
                flags = JS_PROP_THROW_STRICT;
17810
0
                if (unlikely(JS_IsUndefined(sp[-3]))) {
17811
0
                    if (is_strict_mode(ctx)) {
17812
0
                        JSAtom atom = JS_ValueToAtom(ctx, sp[-2]);
17813
0
                        if (atom != JS_ATOM_NULL) {
17814
0
                            JS_ThrowReferenceErrorNotDefined(ctx, atom);
17815
0
                            JS_FreeAtom(ctx, atom);
17816
0
                        }
17817
0
                        goto exception;
17818
0
                    } else {
17819
0
                        sp[-3] = JS_DupValue(ctx, ctx->global_obj);
17820
0
                    }
17821
0
                } else {
17822
0
                    if (is_strict_mode(ctx))
17823
0
                        flags |= JS_PROP_NO_ADD;
17824
0
                }
17825
0
                ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], flags);
17826
0
                JS_FreeValue(ctx, sp[-3]);
17827
0
                sp -= 3;
17828
0
                if (unlikely(ret < 0))
17829
0
                    goto exception;
17830
0
            }
17831
0
            BREAK;
17832
17833
0
        CASE(OP_put_super_value):
17834
0
            {
17835
0
                int ret;
17836
0
                JSAtom atom;
17837
0
                if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) {
17838
0
                    JS_ThrowTypeErrorNotAnObject(ctx);
17839
0
                    goto exception;
17840
0
                }
17841
0
                atom = JS_ValueToAtom(ctx, sp[-2]);
17842
0
                if (unlikely(atom == JS_ATOM_NULL))
17843
0
                    goto exception;
17844
0
                ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-4],
17845
0
                                             JS_PROP_THROW_STRICT);
17846
0
                JS_FreeAtom(ctx, atom);
17847
0
                JS_FreeValue(ctx, sp[-4]);
17848
0
                JS_FreeValue(ctx, sp[-3]);
17849
0
                JS_FreeValue(ctx, sp[-2]);
17850
0
                sp -= 4;
17851
0
                if (ret < 0)
17852
0
                    goto exception;
17853
0
            }
17854
0
            BREAK;
17855
17856
0
        CASE(OP_define_array_el):
17857
0
            {
17858
0
                int ret;
17859
0
                ret = JS_DefinePropertyValueValue(ctx, sp[-3], JS_DupValue(ctx, sp[-2]), sp[-1],
17860
0
                                                  JS_PROP_C_W_E | JS_PROP_THROW);
17861
0
                sp -= 1;
17862
0
                if (unlikely(ret < 0))
17863
0
                    goto exception;
17864
0
            }
17865
0
            BREAK;
17866
17867
0
        CASE(OP_append):    /* array pos enumobj -- array pos */
17868
0
            {
17869
0
                if (js_append_enumerate(ctx, sp))
17870
0
                    goto exception;
17871
0
                JS_FreeValue(ctx, *--sp);
17872
0
            }
17873
0
            BREAK;
17874
17875
0
        CASE(OP_copy_data_properties):    /* target source excludeList */
17876
0
            {
17877
                /* stack offsets (-1 based):
17878
                   2 bits for target,
17879
                   3 bits for source,
17880
                   2 bits for exclusionList */
17881
0
                int mask;
17882
17883
0
                mask = *pc++;
17884
0
                if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)],
17885
0
                                          sp[-1 - ((mask >> 2) & 7)],
17886
0
                                          sp[-1 - ((mask >> 5) & 7)], 0))
17887
0
                    goto exception;
17888
0
            }
17889
0
            BREAK;
17890
17891
1
        CASE(OP_add):
17892
1
            {
17893
1
                JSValue op1, op2;
17894
1
                op1 = sp[-2];
17895
1
                op2 = sp[-1];
17896
1
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
17897
0
                    int64_t r;
17898
0
                    r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2);
17899
0
                    if (unlikely((int)r != r))
17900
0
                        goto add_slow;
17901
0
                    sp[-2] = JS_NewInt32(ctx, r);
17902
0
                    sp--;
17903
1
                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
17904
0
                    sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) +
17905
0
                                             JS_VALUE_GET_FLOAT64(op2));
17906
0
                    sp--;
17907
1
                } else if (JS_IsString(op1) && JS_IsString(op2)) {
17908
0
                    sp[-2] = JS_ConcatString(ctx, op1, op2);
17909
0
                    sp--;
17910
0
                    if (JS_IsException(sp[-1]))
17911
0
                        goto exception;
17912
1
                } else {
17913
1
                add_slow:
17914
1
                    if (js_add_slow(ctx, sp))
17915
0
                        goto exception;
17916
1
                    sp--;
17917
1
                }
17918
1
            }
17919
1
            BREAK;
17920
1
        CASE(OP_add_loc):
17921
0
            {
17922
0
                JSValue op2;
17923
0
                JSValue *pv;
17924
0
                int idx;
17925
0
                idx = *pc;
17926
0
                pc += 1;
17927
17928
0
                op2 = sp[-1];
17929
0
                pv = &var_buf[idx];
17930
0
                if (likely(JS_VALUE_IS_BOTH_INT(*pv, op2))) {
17931
0
                    int64_t r;
17932
0
                    r = (int64_t)JS_VALUE_GET_INT(*pv) + JS_VALUE_GET_INT(op2);
17933
0
                    if (unlikely((int)r != r))
17934
0
                        goto add_loc_slow;
17935
0
                    *pv = JS_NewInt32(ctx, r);
17936
0
                    sp--;
17937
0
                } else if (JS_VALUE_IS_BOTH_FLOAT(*pv, op2)) {
17938
0
                    *pv = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(*pv) +
17939
0
                                               JS_VALUE_GET_FLOAT64(op2));
17940
0
                    sp--;
17941
0
                } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) {
17942
0
                    sp--;
17943
0
                    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
17944
0
                    if (JS_IsException(op2))
17945
0
                        goto exception;
17946
0
                    if (JS_ConcatStringInPlace(ctx, JS_VALUE_GET_STRING(*pv), op2)) {
17947
0
                        JS_FreeValue(ctx, op2);
17948
0
                    } else {
17949
0
                        op2 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op2);
17950
0
                        if (JS_IsException(op2))
17951
0
                            goto exception;
17952
0
                        set_value(ctx, pv, op2);
17953
0
                    }
17954
0
                } else {
17955
0
                    JSValue ops[2];
17956
0
                add_loc_slow:
17957
                    /* In case of exception, js_add_slow frees ops[0]
17958
                       and ops[1], so we must duplicate *pv */
17959
0
                    ops[0] = JS_DupValue(ctx, *pv);
17960
0
                    ops[1] = op2;
17961
0
                    sp--;
17962
0
                    if (js_add_slow(ctx, ops + 2))
17963
0
                        goto exception;
17964
0
                    set_value(ctx, pv, ops[0]);
17965
0
                }
17966
0
            }
17967
0
            BREAK;
17968
0
        CASE(OP_sub):
17969
0
            {
17970
0
                JSValue op1, op2;
17971
0
                op1 = sp[-2];
17972
0
                op2 = sp[-1];
17973
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
17974
0
                    int64_t r;
17975
0
                    r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2);
17976
0
                    if (unlikely((int)r != r))
17977
0
                        goto binary_arith_slow;
17978
0
                    sp[-2] = JS_NewInt32(ctx, r);
17979
0
                    sp--;
17980
0
                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
17981
0
                    sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) -
17982
0
                                             JS_VALUE_GET_FLOAT64(op2));
17983
0
                    sp--;
17984
0
                } else {
17985
0
                    goto binary_arith_slow;
17986
0
                }
17987
0
            }
17988
0
            BREAK;
17989
0
        CASE(OP_mul):
17990
0
            {
17991
0
                JSValue op1, op2;
17992
0
                double d;
17993
0
                op1 = sp[-2];
17994
0
                op2 = sp[-1];
17995
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
17996
0
                    int32_t v1, v2;
17997
0
                    int64_t r;
17998
0
                    v1 = JS_VALUE_GET_INT(op1);
17999
0
                    v2 = JS_VALUE_GET_INT(op2);
18000
0
                    r = (int64_t)v1 * v2;
18001
0
                    if (unlikely((int)r != r)) {
18002
0
#ifdef CONFIG_BIGNUM
18003
0
                        if (unlikely(sf->js_mode & JS_MODE_MATH) &&
18004
0
                            (r < -MAX_SAFE_INTEGER || r > MAX_SAFE_INTEGER))
18005
0
                            goto binary_arith_slow;
18006
0
#endif
18007
0
                        d = (double)r;
18008
0
                        goto mul_fp_res;
18009
0
                    }
18010
                    /* need to test zero case for -0 result */
18011
0
                    if (unlikely(r == 0 && (v1 | v2) < 0)) {
18012
0
                        d = -0.0;
18013
0
                        goto mul_fp_res;
18014
0
                    }
18015
0
                    sp[-2] = JS_NewInt32(ctx, r);
18016
0
                    sp--;
18017
0
                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
18018
0
#ifdef CONFIG_BIGNUM
18019
0
                    if (unlikely(sf->js_mode & JS_MODE_MATH))
18020
0
                        goto binary_arith_slow;
18021
0
#endif
18022
0
                    d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);
18023
0
                mul_fp_res:
18024
0
                    sp[-2] = __JS_NewFloat64(ctx, d);
18025
0
                    sp--;
18026
0
                } else {
18027
0
                    goto binary_arith_slow;
18028
0
                }
18029
0
            }
18030
0
            BREAK;
18031
0
        CASE(OP_div):
18032
0
            {
18033
0
                JSValue op1, op2;
18034
0
                op1 = sp[-2];
18035
0
                op2 = sp[-1];
18036
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18037
0
                    int v1, v2;
18038
0
                    if (unlikely(sf->js_mode & JS_MODE_MATH))
18039
0
                        goto binary_arith_slow;
18040
0
                    v1 = JS_VALUE_GET_INT(op1);
18041
0
                    v2 = JS_VALUE_GET_INT(op2);
18042
0
                    sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
18043
0
                    sp--;
18044
0
                } else {
18045
0
                    goto binary_arith_slow;
18046
0
                }
18047
0
            }
18048
0
            BREAK;
18049
0
        CASE(OP_mod):
18050
0
#ifdef CONFIG_BIGNUM
18051
0
        CASE(OP_math_mod):
18052
0
#endif
18053
0
            {
18054
0
                JSValue op1, op2;
18055
0
                op1 = sp[-2];
18056
0
                op2 = sp[-1];
18057
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18058
0
                    int v1, v2, r;
18059
0
                    v1 = JS_VALUE_GET_INT(op1);
18060
0
                    v2 = JS_VALUE_GET_INT(op2);
18061
                    /* We must avoid v2 = 0, v1 = INT32_MIN and v2 =
18062
                       -1 and the cases where the result is -0. */
18063
0
                    if (unlikely(v1 < 0 || v2 <= 0))
18064
0
                        goto binary_arith_slow;
18065
0
                    r = v1 % v2;
18066
0
                    sp[-2] = JS_NewInt32(ctx, r);
18067
0
                    sp--;
18068
0
                } else {
18069
0
                    goto binary_arith_slow;
18070
0
                }
18071
0
            }
18072
0
            BREAK;
18073
0
        CASE(OP_pow):
18074
0
        binary_arith_slow:
18075
0
            if (js_binary_arith_slow(ctx, sp, opcode))
18076
0
                goto exception;
18077
0
            sp--;
18078
0
            BREAK;
18079
18080
0
        CASE(OP_plus):
18081
0
            {
18082
0
                JSValue op1;
18083
0
                uint32_t tag;
18084
0
                op1 = sp[-1];
18085
0
                tag = JS_VALUE_GET_TAG(op1);
18086
0
                if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) {
18087
0
                } else {
18088
0
                    if (js_unary_arith_slow(ctx, sp, opcode))
18089
0
                        goto exception;
18090
0
                }
18091
0
            }
18092
0
            BREAK;
18093
0
        CASE(OP_neg):
18094
0
            {
18095
0
                JSValue op1;
18096
0
                uint32_t tag;
18097
0
                int val;
18098
0
                double d;
18099
0
                op1 = sp[-1];
18100
0
                tag = JS_VALUE_GET_TAG(op1);
18101
0
                if (tag == JS_TAG_INT) {
18102
0
                    val = JS_VALUE_GET_INT(op1);
18103
                    /* Note: -0 cannot be expressed as integer */
18104
0
                    if (unlikely(val == 0)) {
18105
0
                        d = -0.0;
18106
0
                        goto neg_fp_res;
18107
0
                    }
18108
0
                    if (unlikely(val == INT32_MIN)) {
18109
0
                        d = -(double)val;
18110
0
                        goto neg_fp_res;
18111
0
                    }
18112
0
                    sp[-1] = JS_NewInt32(ctx, -val);
18113
0
                } else if (JS_TAG_IS_FLOAT64(tag)) {
18114
0
                    d = -JS_VALUE_GET_FLOAT64(op1);
18115
0
                neg_fp_res:
18116
0
                    sp[-1] = __JS_NewFloat64(ctx, d);
18117
0
                } else {
18118
0
                    if (js_unary_arith_slow(ctx, sp, opcode))
18119
0
                        goto exception;
18120
0
                }
18121
0
            }
18122
0
            BREAK;
18123
0
        CASE(OP_inc):
18124
0
            {
18125
0
                JSValue op1;
18126
0
                int val;
18127
0
                op1 = sp[-1];
18128
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18129
0
                    val = JS_VALUE_GET_INT(op1);
18130
0
                    if (unlikely(val == INT32_MAX))
18131
0
                        goto inc_slow;
18132
0
                    sp[-1] = JS_NewInt32(ctx, val + 1);
18133
0
                } else {
18134
0
                inc_slow:
18135
0
                    if (js_unary_arith_slow(ctx, sp, opcode))
18136
0
                        goto exception;
18137
0
                }
18138
0
            }
18139
0
            BREAK;
18140
0
        CASE(OP_dec):
18141
0
            {
18142
0
                JSValue op1;
18143
0
                int val;
18144
0
                op1 = sp[-1];
18145
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18146
0
                    val = JS_VALUE_GET_INT(op1);
18147
0
                    if (unlikely(val == INT32_MIN))
18148
0
                        goto dec_slow;
18149
0
                    sp[-1] = JS_NewInt32(ctx, val - 1);
18150
0
                } else {
18151
0
                dec_slow:
18152
0
                    if (js_unary_arith_slow(ctx, sp, opcode))
18153
0
                        goto exception;
18154
0
                }
18155
0
            }
18156
0
            BREAK;
18157
0
        CASE(OP_post_inc):
18158
0
        CASE(OP_post_dec):
18159
0
            if (js_post_inc_slow(ctx, sp, opcode))
18160
0
                goto exception;
18161
0
            sp++;
18162
0
            BREAK;
18163
0
        CASE(OP_inc_loc):
18164
0
            {
18165
0
                JSValue op1;
18166
0
                int val;
18167
0
                int idx;
18168
0
                idx = *pc;
18169
0
                pc += 1;
18170
18171
0
                op1 = var_buf[idx];
18172
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18173
0
                    val = JS_VALUE_GET_INT(op1);
18174
0
                    if (unlikely(val == INT32_MAX))
18175
0
                        goto inc_loc_slow;
18176
0
                    var_buf[idx] = JS_NewInt32(ctx, val + 1);
18177
0
                } else {
18178
0
                inc_loc_slow:
18179
                    /* must duplicate otherwise the variable value may
18180
                       be destroyed before JS code accesses it */
18181
0
                    op1 = JS_DupValue(ctx, op1);
18182
0
                    if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc))
18183
0
                        goto exception;
18184
0
                    set_value(ctx, &var_buf[idx], op1);
18185
0
                }
18186
0
            }
18187
0
            BREAK;
18188
0
        CASE(OP_dec_loc):
18189
0
            {
18190
0
                JSValue op1;
18191
0
                int val;
18192
0
                int idx;
18193
0
                idx = *pc;
18194
0
                pc += 1;
18195
18196
0
                op1 = var_buf[idx];
18197
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18198
0
                    val = JS_VALUE_GET_INT(op1);
18199
0
                    if (unlikely(val == INT32_MIN))
18200
0
                        goto dec_loc_slow;
18201
0
                    var_buf[idx] = JS_NewInt32(ctx, val - 1);
18202
0
                } else {
18203
0
                dec_loc_slow:
18204
                    /* must duplicate otherwise the variable value may
18205
                       be destroyed before JS code accesses it */
18206
0
                    op1 = JS_DupValue(ctx, op1);
18207
0
                    if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec))
18208
0
                        goto exception;
18209
0
                    set_value(ctx, &var_buf[idx], op1);
18210
0
                }
18211
0
            }
18212
0
            BREAK;
18213
0
        CASE(OP_not):
18214
0
            {
18215
0
                JSValue op1;
18216
0
                op1 = sp[-1];
18217
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18218
0
                    sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1));
18219
0
                } else {
18220
0
                    if (js_not_slow(ctx, sp))
18221
0
                        goto exception;
18222
0
                }
18223
0
            }
18224
0
            BREAK;
18225
18226
0
        CASE(OP_shl):
18227
0
            {
18228
0
                JSValue op1, op2;
18229
0
                op1 = sp[-2];
18230
0
                op2 = sp[-1];
18231
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18232
0
                    uint32_t v1, v2;
18233
0
                    v1 = JS_VALUE_GET_INT(op1);
18234
0
                    v2 = JS_VALUE_GET_INT(op2);
18235
0
#ifdef CONFIG_BIGNUM
18236
0
                    {
18237
0
                        int64_t r;
18238
0
                        if (unlikely(sf->js_mode & JS_MODE_MATH)) {
18239
0
                            if (v2 > 0x1f)
18240
0
                                goto shl_slow;
18241
0
                            r = (int64_t)v1 << v2;
18242
0
                            if ((int)r != r)
18243
0
                                goto shl_slow;
18244
0
                        } else {
18245
0
                            v2 &= 0x1f;
18246
0
                        }
18247
0
                    }
18248
#else
18249
                    v2 &= 0x1f;
18250
#endif
18251
0
                    sp[-2] = JS_NewInt32(ctx, v1 << v2);
18252
0
                    sp--;
18253
0
                } else {
18254
0
#ifdef CONFIG_BIGNUM
18255
0
                shl_slow:
18256
0
#endif
18257
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
18258
0
                        goto exception;
18259
0
                    sp--;
18260
0
                }
18261
0
            }
18262
0
            BREAK;
18263
0
        CASE(OP_shr):
18264
0
            {
18265
0
                JSValue op1, op2;
18266
0
                op1 = sp[-2];
18267
0
                op2 = sp[-1];
18268
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18269
0
                    uint32_t v2;
18270
0
                    v2 = JS_VALUE_GET_INT(op2);
18271
                    /* v1 >>> v2 retains its JS semantics if CONFIG_BIGNUM */
18272
0
                    v2 &= 0x1f;
18273
0
                    sp[-2] = JS_NewUint32(ctx,
18274
0
                                          (uint32_t)JS_VALUE_GET_INT(op1) >>
18275
0
                                          v2);
18276
0
                    sp--;
18277
0
                } else {
18278
0
                    if (js_shr_slow(ctx, sp))
18279
0
                        goto exception;
18280
0
                    sp--;
18281
0
                }
18282
0
            }
18283
0
            BREAK;
18284
0
        CASE(OP_sar):
18285
0
            {
18286
0
                JSValue op1, op2;
18287
0
                op1 = sp[-2];
18288
0
                op2 = sp[-1];
18289
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18290
0
                    uint32_t v2;
18291
0
                    v2 = JS_VALUE_GET_INT(op2);
18292
0
#ifdef CONFIG_BIGNUM
18293
0
                    if (unlikely(v2 > 0x1f)) {
18294
0
                        if (unlikely(sf->js_mode & JS_MODE_MATH))
18295
0
                            goto sar_slow;
18296
0
                        else
18297
0
                            v2 &= 0x1f;
18298
0
                    }
18299
#else
18300
                    v2 &= 0x1f;
18301
#endif
18302
0
                    sp[-2] = JS_NewInt32(ctx,
18303
0
                                          (int)JS_VALUE_GET_INT(op1) >> v2);
18304
0
                    sp--;
18305
0
                } else {
18306
0
#ifdef CONFIG_BIGNUM
18307
0
                sar_slow:
18308
0
#endif
18309
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
18310
0
                        goto exception;
18311
0
                    sp--;
18312
0
                }
18313
0
            }
18314
0
            BREAK;
18315
0
        CASE(OP_and):
18316
0
            {
18317
0
                JSValue op1, op2;
18318
0
                op1 = sp[-2];
18319
0
                op2 = sp[-1];
18320
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18321
0
                    sp[-2] = JS_NewInt32(ctx,
18322
0
                                         JS_VALUE_GET_INT(op1) &
18323
0
                                         JS_VALUE_GET_INT(op2));
18324
0
                    sp--;
18325
0
                } else {
18326
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
18327
0
                        goto exception;
18328
0
                    sp--;
18329
0
                }
18330
0
            }
18331
0
            BREAK;
18332
0
        CASE(OP_or):
18333
0
            {
18334
0
                JSValue op1, op2;
18335
0
                op1 = sp[-2];
18336
0
                op2 = sp[-1];
18337
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18338
0
                    sp[-2] = JS_NewInt32(ctx,
18339
0
                                         JS_VALUE_GET_INT(op1) |
18340
0
                                         JS_VALUE_GET_INT(op2));
18341
0
                    sp--;
18342
0
                } else {
18343
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
18344
0
                        goto exception;
18345
0
                    sp--;
18346
0
                }
18347
0
            }
18348
0
            BREAK;
18349
0
        CASE(OP_xor):
18350
0
            {
18351
0
                JSValue op1, op2;
18352
0
                op1 = sp[-2];
18353
0
                op2 = sp[-1];
18354
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18355
0
                    sp[-2] = JS_NewInt32(ctx,
18356
0
                                         JS_VALUE_GET_INT(op1) ^
18357
0
                                         JS_VALUE_GET_INT(op2));
18358
0
                    sp--;
18359
0
                } else {
18360
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
18361
0
                        goto exception;
18362
0
                    sp--;
18363
0
                }
18364
0
            }
18365
0
            BREAK;
18366
18367
18368
0
#define OP_CMP(opcode, binary_op, slow_call)              \
18369
0
            CASE(opcode):                                 \
18370
0
                {                                         \
18371
0
                JSValue op1, op2;                         \
18372
0
                op1 = sp[-2];                             \
18373
0
                op2 = sp[-1];                                   \
18374
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {           \
18375
0
                    sp[-2] = JS_NewBool(ctx, JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \
18376
0
                    sp--;                                               \
18377
0
                } else {                                                \
18378
0
                    if (slow_call)                                      \
18379
0
                        goto exception;                                 \
18380
0
                    sp--;                                               \
18381
0
                }                                                       \
18382
0
                }                                                       \
18383
0
            BREAK
18384
18385
0
            OP_CMP(OP_lt, <, js_relational_slow(ctx, sp, opcode));
18386
0
            OP_CMP(OP_lte, <=, js_relational_slow(ctx, sp, opcode));
18387
0
            OP_CMP(OP_gt, >, js_relational_slow(ctx, sp, opcode));
18388
0
            OP_CMP(OP_gte, >=, js_relational_slow(ctx, sp, opcode));
18389
0
            OP_CMP(OP_eq, ==, js_eq_slow(ctx, sp, 0));
18390
0
            OP_CMP(OP_neq, !=, js_eq_slow(ctx, sp, 1));
18391
0
            OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0));
18392
0
            OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1));
18393
18394
0
#ifdef CONFIG_BIGNUM
18395
0
        CASE(OP_mul_pow10):
18396
0
            if (rt->bigfloat_ops.mul_pow10(ctx, sp))
18397
0
                goto exception;
18398
0
            sp--;
18399
0
            BREAK;
18400
0
#endif
18401
0
        CASE(OP_in):
18402
0
            if (js_operator_in(ctx, sp))
18403
0
                goto exception;
18404
0
            sp--;
18405
0
            BREAK;
18406
0
        CASE(OP_private_in):
18407
0
            if (js_operator_private_in(ctx, sp))
18408
0
                goto exception;
18409
0
            sp--;
18410
0
            BREAK;
18411
0
        CASE(OP_instanceof):
18412
0
            if (js_operator_instanceof(ctx, sp))
18413
0
                goto exception;
18414
0
            sp--;
18415
0
            BREAK;
18416
0
        CASE(OP_typeof):
18417
0
            {
18418
0
                JSValue op1;
18419
0
                JSAtom atom;
18420
18421
0
                op1 = sp[-1];
18422
0
                atom = js_operator_typeof(ctx, op1);
18423
0
                JS_FreeValue(ctx, op1);
18424
0
                sp[-1] = JS_AtomToString(ctx, atom);
18425
0
            }
18426
0
            BREAK;
18427
0
        CASE(OP_delete):
18428
0
            if (js_operator_delete(ctx, sp))
18429
0
                goto exception;
18430
0
            sp--;
18431
0
            BREAK;
18432
0
        CASE(OP_delete_var):
18433
0
            {
18434
0
                JSAtom atom;
18435
0
                int ret;
18436
18437
0
                atom = get_u32(pc);
18438
0
                pc += 4;
18439
18440
0
                ret = JS_DeleteProperty(ctx, ctx->global_obj, atom, 0);
18441
0
                if (unlikely(ret < 0))
18442
0
                    goto exception;
18443
0
                *sp++ = JS_NewBool(ctx, ret);
18444
0
            }
18445
0
            BREAK;
18446
18447
0
        CASE(OP_to_object):
18448
0
            if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) {
18449
0
                ret_val = JS_ToObject(ctx, sp[-1]);
18450
0
                if (JS_IsException(ret_val))
18451
0
                    goto exception;
18452
0
                JS_FreeValue(ctx, sp[-1]);
18453
0
                sp[-1] = ret_val;
18454
0
            }
18455
0
            BREAK;
18456
18457
0
        CASE(OP_to_propkey):
18458
0
            switch (JS_VALUE_GET_TAG(sp[-1])) {
18459
0
            case JS_TAG_INT:
18460
0
            case JS_TAG_STRING:
18461
0
            case JS_TAG_SYMBOL:
18462
0
                break;
18463
0
            default:
18464
0
                ret_val = JS_ToPropertyKey(ctx, sp[-1]);
18465
0
                if (JS_IsException(ret_val))
18466
0
                    goto exception;
18467
0
                JS_FreeValue(ctx, sp[-1]);
18468
0
                sp[-1] = ret_val;
18469
0
                break;
18470
0
            }
18471
0
            BREAK;
18472
18473
0
        CASE(OP_to_propkey2):
18474
            /* must be tested first */
18475
0
            if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
18476
0
                JS_ThrowTypeError(ctx, "value has no property");
18477
0
                goto exception;
18478
0
            }
18479
0
            switch (JS_VALUE_GET_TAG(sp[-1])) {
18480
0
            case JS_TAG_INT:
18481
0
            case JS_TAG_STRING:
18482
0
            case JS_TAG_SYMBOL:
18483
0
                break;
18484
0
            default:
18485
0
                ret_val = JS_ToPropertyKey(ctx, sp[-1]);
18486
0
                if (JS_IsException(ret_val))
18487
0
                    goto exception;
18488
0
                JS_FreeValue(ctx, sp[-1]);
18489
0
                sp[-1] = ret_val;
18490
0
                break;
18491
0
            }
18492
0
            BREAK;
18493
#if 0
18494
        CASE(OP_to_string):
18495
            if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_STRING) {
18496
                ret_val = JS_ToString(ctx, sp[-1]);
18497
                if (JS_IsException(ret_val))
18498
                    goto exception;
18499
                JS_FreeValue(ctx, sp[-1]);
18500
                sp[-1] = ret_val;
18501
            }
18502
            BREAK;
18503
#endif
18504
0
        CASE(OP_with_get_var):
18505
0
        CASE(OP_with_put_var):
18506
0
        CASE(OP_with_delete_var):
18507
0
        CASE(OP_with_make_ref):
18508
0
        CASE(OP_with_get_ref):
18509
0
        CASE(OP_with_get_ref_undef):
18510
0
            {
18511
0
                JSAtom atom;
18512
0
                int32_t diff;
18513
0
                JSValue obj, val;
18514
0
                int ret, is_with;
18515
0
                atom = get_u32(pc);
18516
0
                diff = get_u32(pc + 4);
18517
0
                is_with = pc[8];
18518
0
                pc += 9;
18519
18520
0
                obj = sp[-1];
18521
0
                ret = JS_HasProperty(ctx, obj, atom);
18522
0
                if (unlikely(ret < 0))
18523
0
                    goto exception;
18524
0
                if (ret) {
18525
0
                    if (is_with) {
18526
0
                        ret = js_has_unscopable(ctx, obj, atom);
18527
0
                        if (unlikely(ret < 0))
18528
0
                            goto exception;
18529
0
                        if (ret)
18530
0
                            goto no_with;
18531
0
                    }
18532
0
                    switch (opcode) {
18533
0
                    case OP_with_get_var:
18534
0
                        val = JS_GetProperty(ctx, obj, atom);
18535
0
                        if (unlikely(JS_IsException(val)))
18536
0
                            goto exception;
18537
0
                        set_value(ctx, &sp[-1], val);
18538
0
                        break;
18539
0
                    case OP_with_put_var:
18540
                        /* XXX: check if strict mode */
18541
0
                        ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], obj,
18542
0
                                                     JS_PROP_THROW_STRICT);
18543
0
                        JS_FreeValue(ctx, sp[-1]);
18544
0
                        sp -= 2;
18545
0
                        if (unlikely(ret < 0))
18546
0
                            goto exception;
18547
0
                        break;
18548
0
                    case OP_with_delete_var:
18549
0
                        ret = JS_DeleteProperty(ctx, obj, atom, 0);
18550
0
                        if (unlikely(ret < 0))
18551
0
                            goto exception;
18552
0
                        JS_FreeValue(ctx, sp[-1]);
18553
0
                        sp[-1] = JS_NewBool(ctx, ret);
18554
0
                        break;
18555
0
                    case OP_with_make_ref:
18556
                        /* produce a pair object/propname on the stack */
18557
0
                        *sp++ = JS_AtomToValue(ctx, atom);
18558
0
                        break;
18559
0
                    case OP_with_get_ref:
18560
                        /* produce a pair object/method on the stack */
18561
0
                        val = JS_GetProperty(ctx, obj, atom);
18562
0
                        if (unlikely(JS_IsException(val)))
18563
0
                            goto exception;
18564
0
                        *sp++ = val;
18565
0
                        break;
18566
0
                    case OP_with_get_ref_undef:
18567
                        /* produce a pair undefined/function on the stack */
18568
0
                        val = JS_GetProperty(ctx, obj, atom);
18569
0
                        if (unlikely(JS_IsException(val)))
18570
0
                            goto exception;
18571
0
                        JS_FreeValue(ctx, sp[-1]);
18572
0
                        sp[-1] = JS_UNDEFINED;
18573
0
                        *sp++ = val;
18574
0
                        break;
18575
0
                    }
18576
0
                    pc += diff - 5;
18577
0
                } else {
18578
0
                no_with:
18579
                    /* if not jumping, drop the object argument */
18580
0
                    JS_FreeValue(ctx, sp[-1]);
18581
0
                    sp--;
18582
0
                }
18583
0
            }
18584
0
            BREAK;
18585
18586
0
        CASE(OP_await):
18587
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_AWAIT);
18588
0
            goto done_generator;
18589
0
        CASE(OP_yield):
18590
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD);
18591
0
            goto done_generator;
18592
0
        CASE(OP_yield_star):
18593
0
        CASE(OP_async_yield_star):
18594
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR);
18595
0
            goto done_generator;
18596
39
        CASE(OP_return_async):
18597
39
            ret_val = JS_UNDEFINED;
18598
39
            goto done_generator;
18599
0
        CASE(OP_initial_yield):
18600
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_INITIAL_YIELD);
18601
0
            goto done_generator;
18602
18603
0
        CASE(OP_nop):
18604
0
            BREAK;
18605
0
        CASE(OP_is_undefined_or_null):
18606
0
            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED ||
18607
0
                JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
18608
0
                goto set_true;
18609
0
            } else {
18610
0
                goto free_and_set_false;
18611
0
            }
18612
0
#if SHORT_OPCODES
18613
0
        CASE(OP_is_undefined):
18614
0
            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED) {
18615
0
                goto set_true;
18616
0
            } else {
18617
0
                goto free_and_set_false;
18618
0
            }
18619
0
        CASE(OP_is_null):
18620
0
            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
18621
0
                goto set_true;
18622
0
            } else {
18623
0
                goto free_and_set_false;
18624
0
            }
18625
            /* XXX: could merge to a single opcode */
18626
0
        CASE(OP_typeof_is_undefined):
18627
            /* different from OP_is_undefined because of isHTMLDDA */
18628
0
            if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) {
18629
0
                goto free_and_set_true;
18630
0
            } else {
18631
0
                goto free_and_set_false;
18632
0
            }
18633
0
        CASE(OP_typeof_is_function):
18634
0
            if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) {
18635
0
                goto free_and_set_true;
18636
0
            } else {
18637
0
                goto free_and_set_false;
18638
0
            }
18639
0
        free_and_set_true:
18640
0
            JS_FreeValue(ctx, sp[-1]);
18641
0
#endif
18642
0
        set_true:
18643
0
            sp[-1] = JS_TRUE;
18644
0
            BREAK;
18645
0
        free_and_set_false:
18646
0
            JS_FreeValue(ctx, sp[-1]);
18647
0
            sp[-1] = JS_FALSE;
18648
0
            BREAK;
18649
0
        CASE(OP_invalid):
18650
0
        DEFAULT:
18651
0
            JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x",
18652
0
                                  (int)(pc - b->byte_code_buf - 1), opcode);
18653
0
            goto exception;
18654
0
        }
18655
0
    }
18656
9
 exception:
18657
9
    if (is_backtrace_needed(ctx, rt->current_exception)) {
18658
        /* add the backtrace information now (it is not done
18659
           before if the exception happens in a bytecode
18660
           operation */
18661
9
        sf->cur_pc = pc;
18662
9
        build_backtrace(ctx, rt->current_exception, NULL, 0, 0);
18663
9
    }
18664
9
    if (!JS_IsUncatchableError(ctx, rt->current_exception)) {
18665
12
        while (sp > stack_buf) {
18666
3
            JSValue val = *--sp;
18667
3
            JS_FreeValue(ctx, val);
18668
3
            if (JS_VALUE_GET_TAG(val) == JS_TAG_CATCH_OFFSET) {
18669
0
                int pos = JS_VALUE_GET_INT(val);
18670
0
                if (pos == 0) {
18671
                    /* enumerator: close it with a throw */
18672
0
                    JS_FreeValue(ctx, sp[-1]); /* drop the next method */
18673
0
                    sp--;
18674
0
                    JS_IteratorClose(ctx, sp[-1], TRUE);
18675
0
                } else {
18676
0
                    *sp++ = rt->current_exception;
18677
0
                    rt->current_exception = JS_NULL;
18678
0
                    pc = b->byte_code_buf + pos;
18679
0
                    goto restart;
18680
0
                }
18681
0
            }
18682
3
        }
18683
9
    }
18684
9
    ret_val = JS_EXCEPTION;
18685
    /* the local variables are freed by the caller in the generator
18686
       case. Hence the label 'done' should never be reached in a
18687
       generator function. */
18688
9
    if (b->func_kind != JS_FUNC_NORMAL) {
18689
39
    done_generator:
18690
39
        sf->cur_pc = pc;
18691
39
        sf->cur_sp = sp;
18692
39
    } else {
18693
63
    done:
18694
63
        if (unlikely(!list_empty(&sf->var_ref_list))) {
18695
            /* variable references reference the stack: must close them */
18696
0
            close_var_refs(rt, sf);
18697
0
        }
18698
        /* free the local variables and stack */
18699
87
        for(pval = local_buf; pval < sp; pval++) {
18700
24
            JS_FreeValue(ctx, *pval);
18701
24
        }
18702
63
    }
18703
102
    rt->current_stack_frame = sf->prev_frame;
18704
102
    return ret_val;
18705
9
}
18706
18707
JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,
18708
                int argc, JSValueConst *argv)
18709
195
{
18710
195
    return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
18711
195
                           argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
18712
195
}
18713
18714
static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
18715
                           int argc, JSValueConst *argv)
18716
24
{
18717
24
    JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
18718
24
                                  argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
18719
24
    JS_FreeValue(ctx, func_obj);
18720
24
    return res;
18721
24
}
18722
18723
/* warning: the refcount of the context is not incremented. Return
18724
   NULL in case of exception (case of revoked proxy only) */
18725
static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj)
18726
0
{
18727
0
    JSObject *p;
18728
0
    JSContext *realm;
18729
18730
0
    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
18731
0
        return ctx;
18732
0
    p = JS_VALUE_GET_OBJ(func_obj);
18733
0
    switch(p->class_id) {
18734
0
    case JS_CLASS_C_FUNCTION:
18735
0
        realm = p->u.cfunc.realm;
18736
0
        break;
18737
0
    case JS_CLASS_BYTECODE_FUNCTION:
18738
0
    case JS_CLASS_GENERATOR_FUNCTION:
18739
0
    case JS_CLASS_ASYNC_FUNCTION:
18740
0
    case JS_CLASS_ASYNC_GENERATOR_FUNCTION:
18741
0
        {
18742
0
            JSFunctionBytecode *b;
18743
0
            b = p->u.func.function_bytecode;
18744
0
            realm = b->realm;
18745
0
        }
18746
0
        break;
18747
0
    case JS_CLASS_PROXY:
18748
0
        {
18749
0
            JSProxyData *s = p->u.opaque;
18750
0
            if (!s)
18751
0
                return ctx;
18752
0
            if (s->is_revoked) {
18753
0
                JS_ThrowTypeErrorRevokedProxy(ctx);
18754
0
                return NULL;
18755
0
            } else {
18756
0
                realm = JS_GetFunctionRealm(ctx, s->target);
18757
0
            }
18758
0
        }
18759
0
        break;
18760
0
    case JS_CLASS_BOUND_FUNCTION:
18761
0
        {
18762
0
            JSBoundFunction *bf = p->u.bound_function;
18763
0
            realm = JS_GetFunctionRealm(ctx, bf->func_obj);
18764
0
        }
18765
0
        break;
18766
0
    default:
18767
0
        realm = ctx;
18768
0
        break;
18769
0
    }
18770
0
    return realm;
18771
0
}
18772
18773
static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor,
18774
                                   int class_id)
18775
78
{
18776
78
    JSValue proto, obj;
18777
78
    JSContext *realm;
18778
18779
78
    if (JS_IsUndefined(ctor)) {
18780
78
        proto = JS_DupValue(ctx, ctx->class_proto[class_id]);
18781
78
    } else {
18782
0
        proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
18783
0
        if (JS_IsException(proto))
18784
0
            return proto;
18785
0
        if (!JS_IsObject(proto)) {
18786
0
            JS_FreeValue(ctx, proto);
18787
0
            realm = JS_GetFunctionRealm(ctx, ctor);
18788
0
            if (!realm)
18789
0
                return JS_EXCEPTION;
18790
0
            proto = JS_DupValue(ctx, realm->class_proto[class_id]);
18791
0
        }
18792
0
    }
18793
78
    obj = JS_NewObjectProtoClass(ctx, proto, class_id);
18794
78
    JS_FreeValue(ctx, proto);
18795
78
    return obj;
18796
78
}
18797
18798
/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
18799
static JSValue JS_CallConstructorInternal(JSContext *ctx,
18800
                                          JSValueConst func_obj,
18801
                                          JSValueConst new_target,
18802
                                          int argc, JSValue *argv, int flags)
18803
0
{
18804
0
    JSObject *p;
18805
0
    JSFunctionBytecode *b;
18806
18807
0
    if (js_poll_interrupts(ctx))
18808
0
        return JS_EXCEPTION;
18809
0
    flags |= JS_CALL_FLAG_CONSTRUCTOR;
18810
0
    if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT))
18811
0
        goto not_a_function;
18812
0
    p = JS_VALUE_GET_OBJ(func_obj);
18813
0
    if (unlikely(!p->is_constructor))
18814
0
        return JS_ThrowTypeError(ctx, "not a constructor");
18815
0
    if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
18816
0
        JSClassCall *call_func;
18817
0
        call_func = ctx->rt->class_array[p->class_id].call;
18818
0
        if (!call_func) {
18819
0
        not_a_function:
18820
0
            return JS_ThrowTypeError(ctx, "not a function");
18821
0
        }
18822
0
        return call_func(ctx, func_obj, new_target, argc,
18823
0
                         (JSValueConst *)argv, flags);
18824
0
    }
18825
18826
0
    b = p->u.func.function_bytecode;
18827
0
    if (b->is_derived_class_constructor) {
18828
0
        return JS_CallInternal(ctx, func_obj, JS_UNDEFINED, new_target, argc, argv, flags);
18829
0
    } else {
18830
0
        JSValue obj, ret;
18831
        /* legacy constructor behavior */
18832
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
18833
0
        if (JS_IsException(obj))
18834
0
            return JS_EXCEPTION;
18835
0
        ret = JS_CallInternal(ctx, func_obj, obj, new_target, argc, argv, flags);
18836
0
        if (JS_VALUE_GET_TAG(ret) == JS_TAG_OBJECT ||
18837
0
            JS_IsException(ret)) {
18838
0
            JS_FreeValue(ctx, obj);
18839
0
            return ret;
18840
0
        } else {
18841
0
            JS_FreeValue(ctx, ret);
18842
0
            return obj;
18843
0
        }
18844
0
    }
18845
0
}
18846
18847
JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,
18848
                            JSValueConst new_target,
18849
                            int argc, JSValueConst *argv)
18850
0
{
18851
0
    return JS_CallConstructorInternal(ctx, func_obj, new_target,
18852
0
                                      argc, (JSValue *)argv,
18853
0
                                      JS_CALL_FLAG_COPY_ARGV);
18854
0
}
18855
18856
JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,
18857
                           int argc, JSValueConst *argv)
18858
0
{
18859
0
    return JS_CallConstructorInternal(ctx, func_obj, func_obj,
18860
0
                                      argc, (JSValue *)argv,
18861
0
                                      JS_CALL_FLAG_COPY_ARGV);
18862
0
}
18863
18864
JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom,
18865
                  int argc, JSValueConst *argv)
18866
0
{
18867
0
    JSValue func_obj;
18868
0
    func_obj = JS_GetProperty(ctx, this_val, atom);
18869
0
    if (JS_IsException(func_obj))
18870
0
        return func_obj;
18871
0
    return JS_CallFree(ctx, func_obj, this_val, argc, argv);
18872
0
}
18873
18874
static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
18875
                             int argc, JSValueConst *argv)
18876
0
{
18877
0
    JSValue res = JS_Invoke(ctx, this_val, atom, argc, argv);
18878
0
    JS_FreeValue(ctx, this_val);
18879
0
    return res;
18880
0
}
18881
18882
/* JSAsyncFunctionState (used by generator and async functions) */
18883
static JSAsyncFunctionState *async_func_init(JSContext *ctx,
18884
                                             JSValueConst func_obj, JSValueConst this_obj,
18885
                                             int argc, JSValueConst *argv)
18886
39
{
18887
39
    JSAsyncFunctionState *s;
18888
39
    JSObject *p;
18889
39
    JSFunctionBytecode *b;
18890
39
    JSStackFrame *sf;
18891
39
    int local_count, i, arg_buf_len, n;
18892
18893
39
    s = js_mallocz(ctx, sizeof(*s));
18894
39
    if (!s)
18895
0
        return NULL;
18896
39
    s->header.ref_count = 1;
18897
39
    add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
18898
18899
39
    sf = &s->frame;
18900
39
    init_list_head(&sf->var_ref_list);
18901
39
    p = JS_VALUE_GET_OBJ(func_obj);
18902
39
    b = p->u.func.function_bytecode;
18903
39
    sf->js_mode = b->js_mode | JS_MODE_ASYNC;
18904
39
    sf->cur_pc = b->byte_code_buf;
18905
39
    arg_buf_len = max_int(b->arg_count, argc);
18906
39
    local_count = arg_buf_len + b->var_count + b->stack_size;
18907
39
    sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1));
18908
39
    if (!sf->arg_buf) {
18909
0
        js_free(ctx, s);
18910
0
        return NULL;
18911
0
    }
18912
39
    sf->cur_func = JS_DupValue(ctx, func_obj);
18913
39
    s->this_val = JS_DupValue(ctx, this_obj);
18914
39
    s->argc = argc;
18915
39
    sf->arg_count = arg_buf_len;
18916
39
    sf->var_buf = sf->arg_buf + arg_buf_len;
18917
39
    sf->cur_sp = sf->var_buf + b->var_count;
18918
39
    for(i = 0; i < argc; i++)
18919
0
        sf->arg_buf[i] = JS_DupValue(ctx, argv[i]);
18920
39
    n = arg_buf_len + b->var_count;
18921
39
    for(i = argc; i < n; i++)
18922
39
        sf->arg_buf[i] = JS_UNDEFINED;
18923
39
    s->resolving_funcs[0] = JS_UNDEFINED;
18924
39
    s->resolving_funcs[1] = JS_UNDEFINED;
18925
39
    s->is_completed = FALSE;
18926
39
    return s;
18927
39
}
18928
18929
static void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s)
18930
39
{
18931
39
    JSStackFrame *sf = &s->frame;
18932
39
    JSValue *sp;
18933
18934
39
    if (sf->arg_buf) {
18935
        /* cannot free the function if it is running */
18936
39
        assert(sf->cur_sp != NULL);
18937
78
        for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) {
18938
39
            JS_FreeValueRT(rt, *sp);
18939
39
        }
18940
39
        js_free_rt(rt, sf->arg_buf);
18941
39
        sf->arg_buf = NULL;
18942
39
    }
18943
39
    JS_FreeValueRT(rt, sf->cur_func);
18944
39
    JS_FreeValueRT(rt, s->this_val);
18945
39
}
18946
18947
static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)
18948
39
{
18949
39
    JSRuntime *rt = ctx->rt;
18950
39
    JSStackFrame *sf = &s->frame;
18951
39
    JSValue func_obj, ret;
18952
18953
39
    assert(!s->is_completed);
18954
39
    if (js_check_stack_overflow(ctx->rt, 0)) {
18955
0
        ret = JS_ThrowStackOverflow(ctx);
18956
39
    } else {
18957
        /* the tag does not matter provided it is not an object */
18958
39
        func_obj = JS_MKPTR(JS_TAG_INT, s);
18959
39
        ret = JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,
18960
39
                              s->argc, sf->arg_buf, JS_CALL_FLAG_GENERATOR);
18961
39
    }
18962
39
    if (JS_IsException(ret) || JS_IsUndefined(ret)) {
18963
39
        if (JS_IsUndefined(ret)) {
18964
39
            ret = sf->cur_sp[-1];
18965
39
            sf->cur_sp[-1] = JS_UNDEFINED;
18966
39
        }
18967
        /* end of execution */
18968
39
        s->is_completed = TRUE;
18969
18970
        /* close the closure variables. */
18971
39
        close_var_refs(rt, sf);
18972
18973
39
        async_func_free_frame(rt, s);
18974
39
    }
18975
39
    return ret;
18976
39
}
18977
18978
static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
18979
39
{
18980
    /* cannot close the closure variables here because it would
18981
       potentially modify the object graph */
18982
39
    if (!s->is_completed) {
18983
0
        async_func_free_frame(rt, s);
18984
0
    }
18985
18986
39
    JS_FreeValueRT(rt, s->resolving_funcs[0]);
18987
39
    JS_FreeValueRT(rt, s->resolving_funcs[1]);
18988
18989
39
    remove_gc_object(&s->header);
18990
39
    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && s->header.ref_count != 0) {
18991
0
        list_add_tail(&s->header.link, &rt->gc_zero_ref_count_list);
18992
39
    } else {
18993
39
        js_free_rt(rt, s);
18994
39
    }
18995
39
}
18996
18997
static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
18998
39
{
18999
39
    if (--s->header.ref_count == 0) {
19000
39
        if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
19001
39
            list_del(&s->header.link);
19002
39
            list_add(&s->header.link, &rt->gc_zero_ref_count_list);
19003
39
            if (rt->gc_phase == JS_GC_PHASE_NONE) {
19004
39
                free_zero_refcount(rt);
19005
39
            }
19006
39
        }
19007
39
    }
19008
39
}
19009
19010
/* Generators */
19011
19012
typedef enum JSGeneratorStateEnum {
19013
    JS_GENERATOR_STATE_SUSPENDED_START,
19014
    JS_GENERATOR_STATE_SUSPENDED_YIELD,
19015
    JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
19016
    JS_GENERATOR_STATE_EXECUTING,
19017
    JS_GENERATOR_STATE_COMPLETED,
19018
} JSGeneratorStateEnum;
19019
19020
typedef struct JSGeneratorData {
19021
    JSGeneratorStateEnum state;
19022
    JSAsyncFunctionState *func_state;
19023
} JSGeneratorData;
19024
19025
static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s)
19026
0
{
19027
0
    if (s->state == JS_GENERATOR_STATE_COMPLETED)
19028
0
        return;
19029
0
    if (s->func_state) {
19030
0
        async_func_free(rt, s->func_state);
19031
0
        s->func_state = NULL;
19032
0
    }
19033
0
    s->state = JS_GENERATOR_STATE_COMPLETED;
19034
0
}
19035
19036
static void js_generator_finalizer(JSRuntime *rt, JSValue obj)
19037
0
{
19038
0
    JSGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_GENERATOR);
19039
19040
0
    if (s) {
19041
0
        free_generator_stack_rt(rt, s);
19042
0
        js_free_rt(rt, s);
19043
0
    }
19044
0
}
19045
19046
static void free_generator_stack(JSContext *ctx, JSGeneratorData *s)
19047
0
{
19048
0
    free_generator_stack_rt(ctx->rt, s);
19049
0
}
19050
19051
static void js_generator_mark(JSRuntime *rt, JSValueConst val,
19052
                              JS_MarkFunc *mark_func)
19053
0
{
19054
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
19055
0
    JSGeneratorData *s = p->u.generator_data;
19056
19057
0
    if (!s || !s->func_state)
19058
0
        return;
19059
0
    mark_func(rt, &s->func_state->header);
19060
0
}
19061
19062
/* XXX: use enum */
19063
0
#define GEN_MAGIC_NEXT   0
19064
0
#define GEN_MAGIC_RETURN 1
19065
0
#define GEN_MAGIC_THROW  2
19066
19067
static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
19068
                                 int argc, JSValueConst *argv,
19069
                                 BOOL *pdone, int magic)
19070
0
{
19071
0
    JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR);
19072
0
    JSStackFrame *sf;
19073
0
    JSValue ret, func_ret;
19074
19075
0
    *pdone = TRUE;
19076
0
    if (!s)
19077
0
        return JS_ThrowTypeError(ctx, "not a generator");
19078
0
    switch(s->state) {
19079
0
    default:
19080
0
    case JS_GENERATOR_STATE_SUSPENDED_START:
19081
0
        sf = &s->func_state->frame;
19082
0
        if (magic == GEN_MAGIC_NEXT) {
19083
0
            goto exec_no_arg;
19084
0
        } else {
19085
0
            free_generator_stack(ctx, s);
19086
0
            goto done;
19087
0
        }
19088
0
        break;
19089
0
    case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
19090
0
    case JS_GENERATOR_STATE_SUSPENDED_YIELD:
19091
0
        sf = &s->func_state->frame;
19092
        /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
19093
0
        ret = JS_DupValue(ctx, argv[0]);
19094
0
        if (magic == GEN_MAGIC_THROW &&
19095
0
            s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {
19096
0
            JS_Throw(ctx, ret);
19097
0
            s->func_state->throw_flag = TRUE;
19098
0
        } else {
19099
0
            sf->cur_sp[-1] = ret;
19100
0
            sf->cur_sp[0] = JS_NewInt32(ctx, magic);
19101
0
            sf->cur_sp++;
19102
0
        exec_no_arg:
19103
0
            s->func_state->throw_flag = FALSE;
19104
0
        }
19105
0
        s->state = JS_GENERATOR_STATE_EXECUTING;
19106
0
        func_ret = async_func_resume(ctx, s->func_state);
19107
0
        s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD;
19108
0
        if (s->func_state->is_completed) {
19109
            /* finalize the execution in case of exception or normal return */
19110
0
            free_generator_stack(ctx, s);
19111
0
            return func_ret;
19112
0
        } else {
19113
0
            assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT);
19114
            /* get the returned yield value at the top of the stack */
19115
0
            ret = sf->cur_sp[-1];
19116
0
            sf->cur_sp[-1] = JS_UNDEFINED;
19117
0
            if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) {
19118
0
                s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
19119
                /* return (value, done) object */
19120
0
                *pdone = 2;
19121
0
            } else {
19122
0
                *pdone = FALSE;
19123
0
            }
19124
0
        }
19125
0
        break;
19126
0
    case JS_GENERATOR_STATE_COMPLETED:
19127
0
    done:
19128
        /* execution is finished */
19129
0
        switch(magic) {
19130
0
        default:
19131
0
        case GEN_MAGIC_NEXT:
19132
0
            ret = JS_UNDEFINED;
19133
0
            break;
19134
0
        case GEN_MAGIC_RETURN:
19135
0
            ret = JS_DupValue(ctx, argv[0]);
19136
0
            break;
19137
0
        case GEN_MAGIC_THROW:
19138
0
            ret = JS_Throw(ctx, JS_DupValue(ctx, argv[0]));
19139
0
            break;
19140
0
        }
19141
0
        break;
19142
0
    case JS_GENERATOR_STATE_EXECUTING:
19143
0
        ret = JS_ThrowTypeError(ctx, "cannot invoke a running generator");
19144
0
        break;
19145
0
    }
19146
0
    return ret;
19147
0
}
19148
19149
static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
19150
                                          JSValueConst this_obj,
19151
                                          int argc, JSValueConst *argv,
19152
                                          int flags)
19153
0
{
19154
0
    JSValue obj, func_ret;
19155
0
    JSGeneratorData *s;
19156
19157
0
    s = js_mallocz(ctx, sizeof(*s));
19158
0
    if (!s)
19159
0
        return JS_EXCEPTION;
19160
0
    s->state = JS_GENERATOR_STATE_SUSPENDED_START;
19161
0
    s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv);
19162
0
    if (!s->func_state) {
19163
0
        s->state = JS_GENERATOR_STATE_COMPLETED;
19164
0
        goto fail;
19165
0
    }
19166
19167
    /* execute the function up to 'OP_initial_yield' */
19168
0
    func_ret = async_func_resume(ctx, s->func_state);
19169
0
    if (JS_IsException(func_ret))
19170
0
        goto fail;
19171
0
    JS_FreeValue(ctx, func_ret);
19172
19173
0
    obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR);
19174
0
    if (JS_IsException(obj))
19175
0
        goto fail;
19176
0
    JS_SetOpaque(obj, s);
19177
0
    return obj;
19178
0
 fail:
19179
0
    free_generator_stack_rt(ctx->rt, s);
19180
0
    js_free(ctx, s);
19181
0
    return JS_EXCEPTION;
19182
0
}
19183
19184
/* AsyncFunction */
19185
19186
static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val)
19187
0
{
19188
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
19189
0
    JSAsyncFunctionState *s = p->u.async_function_data;
19190
0
    if (s) {
19191
0
        async_func_free(rt, s);
19192
0
    }
19193
0
}
19194
19195
static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
19196
                                           JS_MarkFunc *mark_func)
19197
0
{
19198
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
19199
0
    JSAsyncFunctionState *s = p->u.async_function_data;
19200
0
    if (s) {
19201
0
        mark_func(rt, &s->header);
19202
0
    }
19203
0
}
19204
19205
static int js_async_function_resolve_create(JSContext *ctx,
19206
                                            JSAsyncFunctionState *s,
19207
                                            JSValue *resolving_funcs)
19208
0
{
19209
0
    int i;
19210
0
    JSObject *p;
19211
19212
0
    for(i = 0; i < 2; i++) {
19213
0
        resolving_funcs[i] =
19214
0
            JS_NewObjectProtoClass(ctx, ctx->function_proto,
19215
0
                                   JS_CLASS_ASYNC_FUNCTION_RESOLVE + i);
19216
0
        if (JS_IsException(resolving_funcs[i])) {
19217
0
            if (i == 1)
19218
0
                JS_FreeValue(ctx, resolving_funcs[0]);
19219
0
            return -1;
19220
0
        }
19221
0
        p = JS_VALUE_GET_OBJ(resolving_funcs[i]);
19222
0
        s->header.ref_count++;
19223
0
        p->u.async_function_data = s;
19224
0
    }
19225
0
    return 0;
19226
0
}
19227
19228
static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionState *s)
19229
39
{
19230
39
    JSValue func_ret, ret2;
19231
19232
39
    func_ret = async_func_resume(ctx, s);
19233
39
    if (s->is_completed) {
19234
39
        if (JS_IsException(func_ret)) {
19235
0
            JSValue error;
19236
0
        fail:
19237
0
            error = JS_GetException(ctx);
19238
0
            ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED,
19239
0
                           1, (JSValueConst *)&error);
19240
0
            JS_FreeValue(ctx, error);
19241
0
            JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
19242
39
        } else {
19243
            /* normal return */
19244
39
            ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,
19245
39
                           1, (JSValueConst *)&func_ret);
19246
39
            JS_FreeValue(ctx, func_ret);
19247
39
            JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
19248
39
        }
19249
39
    } else {
19250
0
        JSValue value, promise, resolving_funcs[2], resolving_funcs1[2];
19251
0
        int i, res;
19252
19253
0
        value = s->frame.cur_sp[-1];
19254
0
        s->frame.cur_sp[-1] = JS_UNDEFINED;
19255
19256
        /* await */
19257
0
        JS_FreeValue(ctx, func_ret); /* not used */
19258
0
        promise = js_promise_resolve(ctx, ctx->promise_ctor,
19259
0
                                     1, (JSValueConst *)&value, 0);
19260
0
        JS_FreeValue(ctx, value);
19261
0
        if (JS_IsException(promise))
19262
0
            goto fail;
19263
0
        if (js_async_function_resolve_create(ctx, s, resolving_funcs)) {
19264
0
            JS_FreeValue(ctx, promise);
19265
0
            goto fail;
19266
0
        }
19267
19268
        /* Note: no need to create 'thrownawayCapability' as in
19269
           the spec */
19270
0
        for(i = 0; i < 2; i++)
19271
0
            resolving_funcs1[i] = JS_UNDEFINED;
19272
0
        res = perform_promise_then(ctx, promise,
19273
0
                                   (JSValueConst *)resolving_funcs,
19274
0
                                   (JSValueConst *)resolving_funcs1);
19275
0
        JS_FreeValue(ctx, promise);
19276
0
        for(i = 0; i < 2; i++)
19277
0
            JS_FreeValue(ctx, resolving_funcs[i]);
19278
0
        if (res)
19279
0
            goto fail;
19280
0
    }
19281
39
}
19282
19283
static JSValue js_async_function_resolve_call(JSContext *ctx,
19284
                                              JSValueConst func_obj,
19285
                                              JSValueConst this_obj,
19286
                                              int argc, JSValueConst *argv,
19287
                                              int flags)
19288
0
{
19289
0
    JSObject *p = JS_VALUE_GET_OBJ(func_obj);
19290
0
    JSAsyncFunctionState *s = p->u.async_function_data;
19291
0
    BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE;
19292
0
    JSValueConst arg;
19293
19294
0
    if (argc > 0)
19295
0
        arg = argv[0];
19296
0
    else
19297
0
        arg = JS_UNDEFINED;
19298
0
    s->throw_flag = is_reject;
19299
0
    if (is_reject) {
19300
0
        JS_Throw(ctx, JS_DupValue(ctx, arg));
19301
0
    } else {
19302
        /* return value of await */
19303
0
        s->frame.cur_sp[-1] = JS_DupValue(ctx, arg);
19304
0
    }
19305
0
    js_async_function_resume(ctx, s);
19306
0
    return JS_UNDEFINED;
19307
0
}
19308
19309
static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj,
19310
                                      JSValueConst this_obj,
19311
                                      int argc, JSValueConst *argv, int flags)
19312
39
{
19313
39
    JSValue promise;
19314
39
    JSAsyncFunctionState *s;
19315
19316
39
    s = async_func_init(ctx, func_obj, this_obj, argc, argv);
19317
39
    if (!s)
19318
0
        return JS_EXCEPTION;
19319
19320
39
    promise = JS_NewPromiseCapability(ctx, s->resolving_funcs);
19321
39
    if (JS_IsException(promise)) {
19322
0
        async_func_free(ctx->rt, s);
19323
0
        return JS_EXCEPTION;
19324
0
    }
19325
19326
39
    js_async_function_resume(ctx, s);
19327
19328
39
    async_func_free(ctx->rt, s);
19329
19330
39
    return promise;
19331
39
}
19332
19333
/* AsyncGenerator */
19334
19335
typedef enum JSAsyncGeneratorStateEnum {
19336
    JS_ASYNC_GENERATOR_STATE_SUSPENDED_START,
19337
    JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD,
19338
    JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
19339
    JS_ASYNC_GENERATOR_STATE_EXECUTING,
19340
    JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN,
19341
    JS_ASYNC_GENERATOR_STATE_COMPLETED,
19342
} JSAsyncGeneratorStateEnum;
19343
19344
typedef struct JSAsyncGeneratorRequest {
19345
    struct list_head link;
19346
    /* completion */
19347
    int completion_type; /* GEN_MAGIC_x */
19348
    JSValue result;
19349
    /* promise capability */
19350
    JSValue promise;
19351
    JSValue resolving_funcs[2];
19352
} JSAsyncGeneratorRequest;
19353
19354
typedef struct JSAsyncGeneratorData {
19355
    JSObject *generator; /* back pointer to the object (const) */
19356
    JSAsyncGeneratorStateEnum state;
19357
    /* func_state is NULL is state AWAITING_RETURN and COMPLETED */
19358
    JSAsyncFunctionState *func_state;
19359
    struct list_head queue; /* list of JSAsyncGeneratorRequest.link */
19360
} JSAsyncGeneratorData;
19361
19362
static void js_async_generator_free(JSRuntime *rt,
19363
                                    JSAsyncGeneratorData *s)
19364
0
{
19365
0
    struct list_head *el, *el1;
19366
0
    JSAsyncGeneratorRequest *req;
19367
19368
0
    list_for_each_safe(el, el1, &s->queue) {
19369
0
        req = list_entry(el, JSAsyncGeneratorRequest, link);
19370
0
        JS_FreeValueRT(rt, req->result);
19371
0
        JS_FreeValueRT(rt, req->promise);
19372
0
        JS_FreeValueRT(rt, req->resolving_funcs[0]);
19373
0
        JS_FreeValueRT(rt, req->resolving_funcs[1]);
19374
0
        js_free_rt(rt, req);
19375
0
    }
19376
0
    if (s->func_state)
19377
0
        async_func_free(rt, s->func_state);
19378
0
    js_free_rt(rt, s);
19379
0
}
19380
19381
static void js_async_generator_finalizer(JSRuntime *rt, JSValue obj)
19382
0
{
19383
0
    JSAsyncGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_ASYNC_GENERATOR);
19384
19385
0
    if (s) {
19386
0
        js_async_generator_free(rt, s);
19387
0
    }
19388
0
}
19389
19390
static void js_async_generator_mark(JSRuntime *rt, JSValueConst val,
19391
                                    JS_MarkFunc *mark_func)
19392
0
{
19393
0
    JSAsyncGeneratorData *s = JS_GetOpaque(val, JS_CLASS_ASYNC_GENERATOR);
19394
0
    struct list_head *el;
19395
0
    JSAsyncGeneratorRequest *req;
19396
0
    if (s) {
19397
0
        list_for_each(el, &s->queue) {
19398
0
            req = list_entry(el, JSAsyncGeneratorRequest, link);
19399
0
            JS_MarkValue(rt, req->result, mark_func);
19400
0
            JS_MarkValue(rt, req->promise, mark_func);
19401
0
            JS_MarkValue(rt, req->resolving_funcs[0], mark_func);
19402
0
            JS_MarkValue(rt, req->resolving_funcs[1], mark_func);
19403
0
        }
19404
0
        if (s->func_state) {
19405
0
            mark_func(rt, &s->func_state->header);
19406
0
        }
19407
0
    }
19408
0
}
19409
19410
static JSValue js_async_generator_resolve_function(JSContext *ctx,
19411
                                          JSValueConst this_obj,
19412
                                          int argc, JSValueConst *argv,
19413
                                          int magic, JSValue *func_data);
19414
19415
static int js_async_generator_resolve_function_create(JSContext *ctx,
19416
                                                      JSValueConst generator,
19417
                                                      JSValue *resolving_funcs,
19418
                                                      BOOL is_resume_next)
19419
0
{
19420
0
    int i;
19421
0
    JSValue func;
19422
19423
0
    for(i = 0; i < 2; i++) {
19424
0
        func = JS_NewCFunctionData(ctx, js_async_generator_resolve_function, 1,
19425
0
                                   i + is_resume_next * 2, 1, &generator);
19426
0
        if (JS_IsException(func)) {
19427
0
            if (i == 1)
19428
0
                JS_FreeValue(ctx, resolving_funcs[0]);
19429
0
            return -1;
19430
0
        }
19431
0
        resolving_funcs[i] = func;
19432
0
    }
19433
0
    return 0;
19434
0
}
19435
19436
static int js_async_generator_await(JSContext *ctx,
19437
                                    JSAsyncGeneratorData *s,
19438
                                    JSValueConst value)
19439
0
{
19440
0
    JSValue promise, resolving_funcs[2], resolving_funcs1[2];
19441
0
    int i, res;
19442
19443
0
    promise = js_promise_resolve(ctx, ctx->promise_ctor,
19444
0
                                 1, &value, 0);
19445
0
    if (JS_IsException(promise))
19446
0
        goto fail;
19447
19448
0
    if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator),
19449
0
                                                   resolving_funcs, FALSE)) {
19450
0
        JS_FreeValue(ctx, promise);
19451
0
        goto fail;
19452
0
    }
19453
19454
    /* Note: no need to create 'thrownawayCapability' as in
19455
       the spec */
19456
0
    for(i = 0; i < 2; i++)
19457
0
        resolving_funcs1[i] = JS_UNDEFINED;
19458
0
    res = perform_promise_then(ctx, promise,
19459
0
                               (JSValueConst *)resolving_funcs,
19460
0
                               (JSValueConst *)resolving_funcs1);
19461
0
    JS_FreeValue(ctx, promise);
19462
0
    for(i = 0; i < 2; i++)
19463
0
        JS_FreeValue(ctx, resolving_funcs[i]);
19464
0
    if (res)
19465
0
        goto fail;
19466
0
    return 0;
19467
0
 fail:
19468
0
    return -1;
19469
0
}
19470
19471
static void js_async_generator_resolve_or_reject(JSContext *ctx,
19472
                                                 JSAsyncGeneratorData *s,
19473
                                                 JSValueConst result,
19474
                                                 int is_reject)
19475
0
{
19476
0
    JSAsyncGeneratorRequest *next;
19477
0
    JSValue ret;
19478
19479
0
    next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
19480
0
    list_del(&next->link);
19481
0
    ret = JS_Call(ctx, next->resolving_funcs[is_reject], JS_UNDEFINED, 1,
19482
0
                  &result);
19483
0
    JS_FreeValue(ctx, ret);
19484
0
    JS_FreeValue(ctx, next->result);
19485
0
    JS_FreeValue(ctx, next->promise);
19486
0
    JS_FreeValue(ctx, next->resolving_funcs[0]);
19487
0
    JS_FreeValue(ctx, next->resolving_funcs[1]);
19488
0
    js_free(ctx, next);
19489
0
}
19490
19491
static void js_async_generator_resolve(JSContext *ctx,
19492
                                       JSAsyncGeneratorData *s,
19493
                                       JSValueConst value,
19494
                                       BOOL done)
19495
0
{
19496
0
    JSValue result;
19497
0
    result = js_create_iterator_result(ctx, JS_DupValue(ctx, value), done);
19498
    /* XXX: better exception handling ? */
19499
0
    js_async_generator_resolve_or_reject(ctx, s, result, 0);
19500
0
    JS_FreeValue(ctx, result);
19501
0
 }
19502
19503
static void js_async_generator_reject(JSContext *ctx,
19504
                                       JSAsyncGeneratorData *s,
19505
                                       JSValueConst exception)
19506
0
{
19507
0
    js_async_generator_resolve_or_reject(ctx, s, exception, 1);
19508
0
}
19509
19510
static void js_async_generator_complete(JSContext *ctx,
19511
                                        JSAsyncGeneratorData *s)
19512
0
{
19513
0
    if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) {
19514
0
        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
19515
0
        async_func_free(ctx->rt, s->func_state);
19516
0
        s->func_state = NULL;
19517
0
    }
19518
0
}
19519
19520
static int js_async_generator_completed_return(JSContext *ctx,
19521
                                               JSAsyncGeneratorData *s,
19522
                                               JSValueConst value)
19523
0
{
19524
0
    JSValue promise, resolving_funcs[2], resolving_funcs1[2];
19525
0
    int res;
19526
19527
    // Can fail looking up JS_ATOM_constructor when is_reject==0.
19528
0
    promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, &value,
19529
0
                                 /*is_reject*/0);
19530
    // A poisoned .constructor property is observable and the resulting
19531
    // exception should be delivered to the catch handler.
19532
0
    if (JS_IsException(promise)) {
19533
0
        JSValue err = JS_GetException(ctx);
19534
0
        promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, (JSValueConst *)&err,
19535
0
                                     /*is_reject*/1);
19536
0
        JS_FreeValue(ctx, err);
19537
0
        if (JS_IsException(promise))
19538
0
            return -1;
19539
0
    }
19540
0
    if (js_async_generator_resolve_function_create(ctx,
19541
0
                                                   JS_MKPTR(JS_TAG_OBJECT, s->generator),
19542
0
                                                   resolving_funcs1,
19543
0
                                                   TRUE)) {
19544
0
        JS_FreeValue(ctx, promise);
19545
0
        return -1;
19546
0
    }
19547
0
    resolving_funcs[0] = JS_UNDEFINED;
19548
0
    resolving_funcs[1] = JS_UNDEFINED;
19549
0
    res = perform_promise_then(ctx, promise,
19550
0
                               (JSValueConst *)resolving_funcs1,
19551
0
                               (JSValueConst *)resolving_funcs);
19552
0
    JS_FreeValue(ctx, resolving_funcs1[0]);
19553
0
    JS_FreeValue(ctx, resolving_funcs1[1]);
19554
0
    JS_FreeValue(ctx, promise);
19555
0
    return res;
19556
0
}
19557
19558
static void js_async_generator_resume_next(JSContext *ctx,
19559
                                           JSAsyncGeneratorData *s)
19560
0
{
19561
0
    JSAsyncGeneratorRequest *next;
19562
0
    JSValue func_ret, value;
19563
19564
0
    for(;;) {
19565
0
        if (list_empty(&s->queue))
19566
0
            break;
19567
0
        next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
19568
0
        switch(s->state) {
19569
0
        case JS_ASYNC_GENERATOR_STATE_EXECUTING:
19570
            /* only happens when restarting execution after await() */
19571
0
            goto resume_exec;
19572
0
        case JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN:
19573
0
            goto done;
19574
0
        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_START:
19575
0
            if (next->completion_type == GEN_MAGIC_NEXT) {
19576
0
                goto exec_no_arg;
19577
0
            } else {
19578
0
                js_async_generator_complete(ctx, s);
19579
0
            }
19580
0
            break;
19581
0
        case JS_ASYNC_GENERATOR_STATE_COMPLETED:
19582
0
            if (next->completion_type == GEN_MAGIC_NEXT) {
19583
0
                js_async_generator_resolve(ctx, s, JS_UNDEFINED, TRUE);
19584
0
            } else if (next->completion_type == GEN_MAGIC_RETURN) {
19585
0
                s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN;
19586
0
                js_async_generator_completed_return(ctx, s, next->result);
19587
0
            } else {
19588
0
                js_async_generator_reject(ctx, s, next->result);
19589
0
            }
19590
0
            goto done;
19591
0
        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD:
19592
0
        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
19593
0
            value = JS_DupValue(ctx, next->result);
19594
0
            if (next->completion_type == GEN_MAGIC_THROW &&
19595
0
                s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) {
19596
0
                JS_Throw(ctx, value);
19597
0
                s->func_state->throw_flag = TRUE;
19598
0
            } else {
19599
                /* 'yield' returns a value. 'yield *' also returns a value
19600
                   in case the 'throw' method is called */
19601
0
                s->func_state->frame.cur_sp[-1] = value;
19602
0
                s->func_state->frame.cur_sp[0] =
19603
0
                    JS_NewInt32(ctx, next->completion_type);
19604
0
                s->func_state->frame.cur_sp++;
19605
0
            exec_no_arg:
19606
0
                s->func_state->throw_flag = FALSE;
19607
0
            }
19608
0
            s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING;
19609
0
        resume_exec:
19610
0
            func_ret = async_func_resume(ctx, s->func_state);
19611
0
            if (s->func_state->is_completed) {
19612
0
                if (JS_IsException(func_ret)) {
19613
0
                    value = JS_GetException(ctx);
19614
0
                    js_async_generator_complete(ctx, s);
19615
0
                    js_async_generator_reject(ctx, s, value);
19616
0
                    JS_FreeValue(ctx, value);
19617
0
                } else {
19618
                    /* end of function */
19619
0
                    js_async_generator_complete(ctx, s);
19620
0
                    js_async_generator_resolve(ctx, s, func_ret, TRUE);
19621
0
                    JS_FreeValue(ctx, func_ret);
19622
0
                }
19623
0
            } else {
19624
0
                int func_ret_code, ret;
19625
0
                assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT);
19626
0
                func_ret_code = JS_VALUE_GET_INT(func_ret);
19627
0
                value = s->func_state->frame.cur_sp[-1];
19628
0
                s->func_state->frame.cur_sp[-1] = JS_UNDEFINED;
19629
0
                switch(func_ret_code) {
19630
0
                case FUNC_RET_YIELD:
19631
0
                case FUNC_RET_YIELD_STAR:
19632
0
                    if (func_ret_code == FUNC_RET_YIELD_STAR)
19633
0
                        s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
19634
0
                    else
19635
0
                        s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD;
19636
0
                    js_async_generator_resolve(ctx, s, value, FALSE);
19637
0
                    JS_FreeValue(ctx, value);
19638
0
                    break;
19639
0
                case FUNC_RET_AWAIT:
19640
0
                    ret = js_async_generator_await(ctx, s, value);
19641
0
                    JS_FreeValue(ctx, value);
19642
0
                    if (ret < 0) {
19643
                        /* exception: throw it */
19644
0
                        s->func_state->throw_flag = TRUE;
19645
0
                        goto resume_exec;
19646
0
                    }
19647
0
                    goto done;
19648
0
                default:
19649
0
                    abort();
19650
0
                }
19651
0
            }
19652
0
            break;
19653
0
        default:
19654
0
            abort();
19655
0
        }
19656
0
    }
19657
0
 done: ;
19658
0
}
19659
19660
static JSValue js_async_generator_resolve_function(JSContext *ctx,
19661
                                                   JSValueConst this_obj,
19662
                                                   int argc, JSValueConst *argv,
19663
                                                   int magic, JSValue *func_data)
19664
0
{
19665
0
    BOOL is_reject = magic & 1;
19666
0
    JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR);
19667
0
    JSValueConst arg = argv[0];
19668
19669
    /* XXX: what if s == NULL */
19670
19671
0
    if (magic >= 2) {
19672
        /* resume next case in AWAITING_RETURN state */
19673
0
        assert(s->state == JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN ||
19674
0
               s->state == JS_ASYNC_GENERATOR_STATE_COMPLETED);
19675
0
        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
19676
0
        if (is_reject) {
19677
0
            js_async_generator_reject(ctx, s, arg);
19678
0
        } else {
19679
0
            js_async_generator_resolve(ctx, s, arg, TRUE);
19680
0
        }
19681
0
    } else {
19682
        /* restart function execution after await() */
19683
0
        assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING);
19684
0
        s->func_state->throw_flag = is_reject;
19685
0
        if (is_reject) {
19686
0
            JS_Throw(ctx, JS_DupValue(ctx, arg));
19687
0
        } else {
19688
            /* return value of await */
19689
0
            s->func_state->frame.cur_sp[-1] = JS_DupValue(ctx, arg);
19690
0
        }
19691
0
        js_async_generator_resume_next(ctx, s);
19692
0
    }
19693
0
    return JS_UNDEFINED;
19694
0
}
19695
19696
/* magic = GEN_MAGIC_x */
19697
static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val,
19698
                                       int argc, JSValueConst *argv,
19699
                                       int magic)
19700
0
{
19701
0
    JSAsyncGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_GENERATOR);
19702
0
    JSValue promise, resolving_funcs[2];
19703
0
    JSAsyncGeneratorRequest *req;
19704
19705
0
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
19706
0
    if (JS_IsException(promise))
19707
0
        return JS_EXCEPTION;
19708
0
    if (!s) {
19709
0
        JSValue err, res2;
19710
0
        JS_ThrowTypeError(ctx, "not an AsyncGenerator object");
19711
0
        err = JS_GetException(ctx);
19712
0
        res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
19713
0
                       1, (JSValueConst *)&err);
19714
0
        JS_FreeValue(ctx, err);
19715
0
        JS_FreeValue(ctx, res2);
19716
0
        JS_FreeValue(ctx, resolving_funcs[0]);
19717
0
        JS_FreeValue(ctx, resolving_funcs[1]);
19718
0
        return promise;
19719
0
    }
19720
0
    req = js_mallocz(ctx, sizeof(*req));
19721
0
    if (!req)
19722
0
        goto fail;
19723
0
    req->completion_type = magic;
19724
0
    req->result = JS_DupValue(ctx, argv[0]);
19725
0
    req->promise = JS_DupValue(ctx, promise);
19726
0
    req->resolving_funcs[0] = resolving_funcs[0];
19727
0
    req->resolving_funcs[1] = resolving_funcs[1];
19728
0
    list_add_tail(&req->link, &s->queue);
19729
0
    if (s->state != JS_ASYNC_GENERATOR_STATE_EXECUTING) {
19730
0
        js_async_generator_resume_next(ctx, s);
19731
0
    }
19732
0
    return promise;
19733
0
 fail:
19734
0
    JS_FreeValue(ctx, resolving_funcs[0]);
19735
0
    JS_FreeValue(ctx, resolving_funcs[1]);
19736
0
    JS_FreeValue(ctx, promise);
19737
0
    return JS_EXCEPTION;
19738
0
}
19739
19740
static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst func_obj,
19741
                                                JSValueConst this_obj,
19742
                                                int argc, JSValueConst *argv,
19743
                                                int flags)
19744
0
{
19745
0
    JSValue obj, func_ret;
19746
0
    JSAsyncGeneratorData *s;
19747
19748
0
    s = js_mallocz(ctx, sizeof(*s));
19749
0
    if (!s)
19750
0
        return JS_EXCEPTION;
19751
0
    s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START;
19752
0
    init_list_head(&s->queue);
19753
0
    s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv);
19754
0
    if (!s->func_state)
19755
0
        goto fail;
19756
    /* execute the function up to 'OP_initial_yield' (no yield nor
19757
       await are possible) */
19758
0
    func_ret = async_func_resume(ctx, s->func_state);
19759
0
    if (JS_IsException(func_ret))
19760
0
        goto fail;
19761
0
    JS_FreeValue(ctx, func_ret);
19762
19763
0
    obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_ASYNC_GENERATOR);
19764
0
    if (JS_IsException(obj))
19765
0
        goto fail;
19766
0
    s->generator = JS_VALUE_GET_OBJ(obj);
19767
0
    JS_SetOpaque(obj, s);
19768
0
    return obj;
19769
0
 fail:
19770
0
    js_async_generator_free(ctx->rt, s);
19771
0
    return JS_EXCEPTION;
19772
0
}
19773
19774
/* JS parser */
19775
19776
enum {
19777
    TOK_NUMBER = -128,
19778
    TOK_STRING,
19779
    TOK_TEMPLATE,
19780
    TOK_IDENT,
19781
    TOK_REGEXP,
19782
    /* warning: order matters (see js_parse_assign_expr) */
19783
    TOK_MUL_ASSIGN,
19784
    TOK_DIV_ASSIGN,
19785
    TOK_MOD_ASSIGN,
19786
    TOK_PLUS_ASSIGN,
19787
    TOK_MINUS_ASSIGN,
19788
    TOK_SHL_ASSIGN,
19789
    TOK_SAR_ASSIGN,
19790
    TOK_SHR_ASSIGN,
19791
    TOK_AND_ASSIGN,
19792
    TOK_XOR_ASSIGN,
19793
    TOK_OR_ASSIGN,
19794
#ifdef CONFIG_BIGNUM
19795
    TOK_MATH_POW_ASSIGN,
19796
#endif
19797
    TOK_POW_ASSIGN,
19798
    TOK_LAND_ASSIGN,
19799
    TOK_LOR_ASSIGN,
19800
    TOK_DOUBLE_QUESTION_MARK_ASSIGN,
19801
    TOK_DEC,
19802
    TOK_INC,
19803
    TOK_SHL,
19804
    TOK_SAR,
19805
    TOK_SHR,
19806
    TOK_LT,
19807
    TOK_LTE,
19808
    TOK_GT,
19809
    TOK_GTE,
19810
    TOK_EQ,
19811
    TOK_STRICT_EQ,
19812
    TOK_NEQ,
19813
    TOK_STRICT_NEQ,
19814
    TOK_LAND,
19815
    TOK_LOR,
19816
#ifdef CONFIG_BIGNUM
19817
    TOK_MATH_POW,
19818
#endif
19819
    TOK_POW,
19820
    TOK_ARROW,
19821
    TOK_ELLIPSIS,
19822
    TOK_DOUBLE_QUESTION_MARK,
19823
    TOK_QUESTION_MARK_DOT,
19824
    TOK_ERROR,
19825
    TOK_PRIVATE_NAME,
19826
    TOK_EOF,
19827
    /* keywords: WARNING: same order as atoms */
19828
    TOK_NULL, /* must be first */
19829
    TOK_FALSE,
19830
    TOK_TRUE,
19831
    TOK_IF,
19832
    TOK_ELSE,
19833
    TOK_RETURN,
19834
    TOK_VAR,
19835
    TOK_THIS,
19836
    TOK_DELETE,
19837
    TOK_VOID,
19838
    TOK_TYPEOF,
19839
    TOK_NEW,
19840
    TOK_IN,
19841
    TOK_INSTANCEOF,
19842
    TOK_DO,
19843
    TOK_WHILE,
19844
    TOK_FOR,
19845
    TOK_BREAK,
19846
    TOK_CONTINUE,
19847
    TOK_SWITCH,
19848
    TOK_CASE,
19849
    TOK_DEFAULT,
19850
    TOK_THROW,
19851
    TOK_TRY,
19852
    TOK_CATCH,
19853
    TOK_FINALLY,
19854
    TOK_FUNCTION,
19855
    TOK_DEBUGGER,
19856
    TOK_WITH,
19857
    /* FutureReservedWord */
19858
    TOK_CLASS,
19859
    TOK_CONST,
19860
    TOK_ENUM,
19861
    TOK_EXPORT,
19862
    TOK_EXTENDS,
19863
    TOK_IMPORT,
19864
    TOK_SUPER,
19865
    /* FutureReservedWords when parsing strict mode code */
19866
    TOK_IMPLEMENTS,
19867
    TOK_INTERFACE,
19868
    TOK_LET,
19869
    TOK_PACKAGE,
19870
    TOK_PRIVATE,
19871
    TOK_PROTECTED,
19872
    TOK_PUBLIC,
19873
    TOK_STATIC,
19874
    TOK_YIELD,
19875
    TOK_AWAIT, /* must be last */
19876
    TOK_OF,     /* only used for js_parse_skip_parens_token() */
19877
};
19878
19879
22.3M
#define TOK_FIRST_KEYWORD   TOK_NULL
19880
11.1M
#define TOK_LAST_KEYWORD    TOK_AWAIT
19881
19882
/* unicode code points */
19883
#define CP_NBSP 0x00a0
19884
#define CP_BOM  0xfeff
19885
19886
0
#define CP_LS   0x2028
19887
0
#define CP_PS   0x2029
19888
19889
typedef struct BlockEnv {
19890
    struct BlockEnv *prev;
19891
    JSAtom label_name; /* JS_ATOM_NULL if none */
19892
    int label_break; /* -1 if none */
19893
    int label_cont; /* -1 if none */
19894
    int drop_count; /* number of stack elements to drop */
19895
    int label_finally; /* -1 if none */
19896
    int scope_level;
19897
    int has_iterator;
19898
} BlockEnv;
19899
19900
typedef struct JSGlobalVar {
19901
    int cpool_idx; /* if >= 0, index in the constant pool for hoisted
19902
                      function defintion*/
19903
    uint8_t force_init : 1; /* force initialization to undefined */
19904
    uint8_t is_lexical : 1; /* global let/const definition */
19905
    uint8_t is_const   : 1; /* const definition */
19906
    int scope_level;    /* scope of definition */
19907
    JSAtom var_name;  /* variable name */
19908
} JSGlobalVar;
19909
19910
typedef struct RelocEntry {
19911
    struct RelocEntry *next;
19912
    uint32_t addr; /* address to patch */
19913
    int size;   /* address size: 1, 2 or 4 bytes */
19914
} RelocEntry;
19915
19916
typedef struct JumpSlot {
19917
    int op;
19918
    int size;
19919
    int pos;
19920
    int label;
19921
} JumpSlot;
19922
19923
typedef struct LabelSlot {
19924
    int ref_count;
19925
    int pos;    /* phase 1 address, -1 means not resolved yet */
19926
    int pos2;   /* phase 2 address, -1 means not resolved yet */
19927
    int addr;   /* phase 3 address, -1 means not resolved yet */
19928
    RelocEntry *first_reloc;
19929
} LabelSlot;
19930
19931
typedef struct LineNumberSlot {
19932
    uint32_t pc;
19933
    int line_num;
19934
} LineNumberSlot;
19935
19936
typedef enum JSParseFunctionEnum {
19937
    JS_PARSE_FUNC_STATEMENT,
19938
    JS_PARSE_FUNC_VAR,
19939
    JS_PARSE_FUNC_EXPR,
19940
    JS_PARSE_FUNC_ARROW,
19941
    JS_PARSE_FUNC_GETTER,
19942
    JS_PARSE_FUNC_SETTER,
19943
    JS_PARSE_FUNC_METHOD,
19944
    JS_PARSE_FUNC_CLASS_STATIC_INIT,
19945
    JS_PARSE_FUNC_CLASS_CONSTRUCTOR,
19946
    JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR,
19947
} JSParseFunctionEnum;
19948
19949
typedef enum JSParseExportEnum {
19950
    JS_PARSE_EXPORT_NONE,
19951
    JS_PARSE_EXPORT_NAMED,
19952
    JS_PARSE_EXPORT_DEFAULT,
19953
} JSParseExportEnum;
19954
19955
typedef struct JSFunctionDef {
19956
    JSContext *ctx;
19957
    struct JSFunctionDef *parent;
19958
    int parent_cpool_idx; /* index in the constant pool of the parent
19959
                             or -1 if none */
19960
    int parent_scope_level; /* scope level in parent at point of definition */
19961
    struct list_head child_list; /* list of JSFunctionDef.link */
19962
    struct list_head link;
19963
19964
    BOOL is_eval; /* TRUE if eval code */
19965
    int eval_type; /* only valid if is_eval = TRUE */
19966
    BOOL is_global_var; /* TRUE if variables are not defined locally:
19967
                           eval global, eval module or non strict eval */
19968
    BOOL is_func_expr; /* TRUE if function expression */
19969
    BOOL has_home_object; /* TRUE if the home object is available */
19970
    BOOL has_prototype; /* true if a prototype field is necessary */
19971
    BOOL has_simple_parameter_list;
19972
    BOOL has_parameter_expressions; /* if true, an argument scope is created */
19973
    BOOL has_use_strict; /* to reject directive in special cases */
19974
    BOOL has_eval_call; /* true if the function contains a call to eval() */
19975
    BOOL has_arguments_binding; /* true if the 'arguments' binding is
19976
                                   available in the function */
19977
    BOOL has_this_binding; /* true if the 'this' and new.target binding are
19978
                              available in the function */
19979
    BOOL new_target_allowed; /* true if the 'new.target' does not
19980
                                throw a syntax error */
19981
    BOOL super_call_allowed; /* true if super() is allowed */
19982
    BOOL super_allowed; /* true if super. or super[] is allowed */
19983
    BOOL arguments_allowed; /* true if the 'arguments' identifier is allowed */
19984
    BOOL is_derived_class_constructor;
19985
    BOOL in_function_body;
19986
    BOOL backtrace_barrier;
19987
    JSFunctionKindEnum func_kind : 8;
19988
    JSParseFunctionEnum func_type : 8;
19989
    uint8_t js_mode; /* bitmap of JS_MODE_x */
19990
    JSAtom func_name; /* JS_ATOM_NULL if no name */
19991
19992
    JSVarDef *vars;
19993
    int var_size; /* allocated size for vars[] */
19994
    int var_count;
19995
    JSVarDef *args;
19996
    int arg_size; /* allocated size for args[] */
19997
    int arg_count; /* number of arguments */
19998
    int defined_arg_count;
19999
    int var_object_idx; /* -1 if none */
20000
    int arg_var_object_idx; /* -1 if none (var object for the argument scope) */
20001
    int arguments_var_idx; /* -1 if none */
20002
    int arguments_arg_idx; /* argument variable definition in argument scope,
20003
                              -1 if none */
20004
    int func_var_idx; /* variable containing the current function (-1
20005
                         if none, only used if is_func_expr is true) */
20006
    int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */
20007
    int this_var_idx; /* variable containg the 'this' value, -1 if none */
20008
    int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */
20009
    int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */
20010
    int home_object_var_idx;
20011
    BOOL need_home_object;
20012
20013
    int scope_level;    /* index into fd->scopes if the current lexical scope */
20014
    int scope_first;    /* index into vd->vars of first lexically scoped variable */
20015
    int scope_size;     /* allocated size of fd->scopes array */
20016
    int scope_count;    /* number of entries used in the fd->scopes array */
20017
    JSVarScope *scopes;
20018
    JSVarScope def_scope_array[4];
20019
    int body_scope; /* scope of the body of the function or eval */
20020
20021
    int global_var_count;
20022
    int global_var_size;
20023
    JSGlobalVar *global_vars;
20024
20025
    DynBuf byte_code;
20026
    int last_opcode_pos; /* -1 if no last opcode */
20027
    int last_opcode_line_num;
20028
    BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */
20029
20030
    LabelSlot *label_slots;
20031
    int label_size; /* allocated size for label_slots[] */
20032
    int label_count;
20033
    BlockEnv *top_break; /* break/continue label stack */
20034
20035
    /* constant pool (strings, functions, numbers) */
20036
    JSValue *cpool;
20037
    int cpool_count;
20038
    int cpool_size;
20039
20040
    /* list of variables in the closure */
20041
    int closure_var_count;
20042
    int closure_var_size;
20043
    JSClosureVar *closure_var;
20044
20045
    JumpSlot *jump_slots;
20046
    int jump_size;
20047
    int jump_count;
20048
20049
    LineNumberSlot *line_number_slots;
20050
    int line_number_size;
20051
    int line_number_count;
20052
    int line_number_last;
20053
    int line_number_last_pc;
20054
20055
    /* pc2line table */
20056
    JSAtom filename;
20057
    int line_num;
20058
    DynBuf pc2line;
20059
20060
    char *source;  /* raw source, utf-8 encoded */
20061
    int source_len;
20062
20063
    JSModuleDef *module; /* != NULL when parsing a module */
20064
    BOOL has_await; /* TRUE if await is used (used in module eval) */
20065
} JSFunctionDef;
20066
20067
typedef struct JSToken {
20068
    int val;
20069
    int line_num;   /* line number of token start */
20070
    const uint8_t *ptr;
20071
    union {
20072
        struct {
20073
            JSValue str;
20074
            int sep;
20075
        } str;
20076
        struct {
20077
            JSValue val;
20078
#ifdef CONFIG_BIGNUM
20079
            slimb_t exponent; /* may be != 0 only if val is a float */
20080
#endif
20081
        } num;
20082
        struct {
20083
            JSAtom atom;
20084
            BOOL has_escape;
20085
            BOOL is_reserved;
20086
        } ident;
20087
        struct {
20088
            JSValue body;
20089
            JSValue flags;
20090
        } regexp;
20091
    } u;
20092
} JSToken;
20093
20094
typedef struct JSParseState {
20095
    JSContext *ctx;
20096
    int last_line_num;  /* line number of last token */
20097
    int line_num;       /* line number of current offset */
20098
    const char *filename;
20099
    JSToken token;
20100
    BOOL got_lf; /* true if got line feed before the current token */
20101
    const uint8_t *last_ptr;
20102
    const uint8_t *buf_ptr;
20103
    const uint8_t *buf_end;
20104
20105
    /* current function code */
20106
    JSFunctionDef *cur_func;
20107
    BOOL is_module; /* parsing a module */
20108
    BOOL allow_html_comments;
20109
    BOOL ext_json; /* true if accepting JSON superset */
20110
} JSParseState;
20111
20112
typedef struct JSOpCode {
20113
#ifdef DUMP_BYTECODE
20114
    const char *name;
20115
#endif
20116
    uint8_t size; /* in bytes */
20117
    /* the opcodes remove n_pop items from the top of the stack, then
20118
       pushes n_push items */
20119
    uint8_t n_pop;
20120
    uint8_t n_push;
20121
    uint8_t fmt;
20122
} JSOpCode;
20123
20124
static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = {
20125
#define FMT(f)
20126
#ifdef DUMP_BYTECODE
20127
#define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f },
20128
#else
20129
#define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f },
20130
#endif
20131
#include "quickjs-opcode.h"
20132
#undef DEF
20133
#undef FMT
20134
};
20135
20136
#if SHORT_OPCODES
20137
/* After the final compilation pass, short opcodes are used. Their
20138
   opcodes overlap with the temporary opcodes which cannot appear in
20139
   the final bytecode. Their description is after the temporary
20140
   opcodes in opcode_info[]. */
20141
#define short_opcode_info(op)           \
20142
14.1M
    opcode_info[(op) >= OP_TEMP_START ? \
20143
14.1M
                (op) + (OP_TEMP_END - OP_TEMP_START) : (op)]
20144
#else
20145
#define short_opcode_info(op) opcode_info[op]
20146
#endif
20147
20148
static __exception int next_token(JSParseState *s);
20149
20150
static void free_token(JSParseState *s, JSToken *token)
20151
22.3M
{
20152
22.3M
    switch(token->val) {
20153
11.1M
    case TOK_NUMBER:
20154
11.1M
        JS_FreeValue(s->ctx, token->u.num.val);
20155
11.1M
        break;
20156
116
    case TOK_STRING:
20157
116
    case TOK_TEMPLATE:
20158
116
        JS_FreeValue(s->ctx, token->u.str.str);
20159
116
        break;
20160
0
    case TOK_REGEXP:
20161
0
        JS_FreeValue(s->ctx, token->u.regexp.body);
20162
0
        JS_FreeValue(s->ctx, token->u.regexp.flags);
20163
0
        break;
20164
485
    case TOK_IDENT:
20165
485
    case TOK_PRIVATE_NAME:
20166
485
        JS_FreeAtom(s->ctx, token->u.ident.atom);
20167
485
        break;
20168
11.1M
    default:
20169
11.1M
        if (token->val >= TOK_FIRST_KEYWORD &&
20170
11.1M
            token->val <= TOK_LAST_KEYWORD) {
20171
78
            JS_FreeAtom(s->ctx, token->u.ident.atom);
20172
78
        }
20173
11.1M
        break;
20174
22.3M
    }
20175
22.3M
}
20176
20177
static void __attribute((unused)) dump_token(JSParseState *s,
20178
                                             const JSToken *token)
20179
0
{
20180
0
    switch(token->val) {
20181
0
    case TOK_NUMBER:
20182
0
        {
20183
0
            double d;
20184
0
            JS_ToFloat64(s->ctx, &d, token->u.num.val);  /* no exception possible */
20185
0
            printf("number: %.14g\n", d);
20186
0
        }
20187
0
        break;
20188
0
    case TOK_IDENT:
20189
0
    dump_atom:
20190
0
        {
20191
0
            char buf[ATOM_GET_STR_BUF_SIZE];
20192
0
            printf("ident: '%s'\n",
20193
0
                   JS_AtomGetStr(s->ctx, buf, sizeof(buf), token->u.ident.atom));
20194
0
        }
20195
0
        break;
20196
0
    case TOK_STRING:
20197
0
        {
20198
0
            const char *str;
20199
0
            /* XXX: quote the string */
20200
0
            str = JS_ToCString(s->ctx, token->u.str.str);
20201
0
            printf("string: '%s'\n", str);
20202
0
            JS_FreeCString(s->ctx, str);
20203
0
        }
20204
0
        break;
20205
0
    case TOK_TEMPLATE:
20206
0
        {
20207
0
            const char *str;
20208
0
            str = JS_ToCString(s->ctx, token->u.str.str);
20209
0
            printf("template: `%s`\n", str);
20210
0
            JS_FreeCString(s->ctx, str);
20211
0
        }
20212
0
        break;
20213
0
    case TOK_REGEXP:
20214
0
        {
20215
0
            const char *str, *str2;
20216
0
            str = JS_ToCString(s->ctx, token->u.regexp.body);
20217
0
            str2 = JS_ToCString(s->ctx, token->u.regexp.flags);
20218
0
            printf("regexp: '%s' '%s'\n", str, str2);
20219
0
            JS_FreeCString(s->ctx, str);
20220
0
            JS_FreeCString(s->ctx, str2);
20221
0
        }
20222
0
        break;
20223
0
    case TOK_EOF:
20224
0
        printf("eof\n");
20225
0
        break;
20226
0
    default:
20227
0
        if (s->token.val >= TOK_NULL && s->token.val <= TOK_LAST_KEYWORD) {
20228
0
            goto dump_atom;
20229
0
        } else if (s->token.val >= 256) {
20230
0
            printf("token: %d\n", token->val);
20231
0
        } else {
20232
0
            printf("token: '%c'\n", token->val);
20233
0
        }
20234
0
        break;
20235
0
    }
20236
0
}
20237
20238
int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const char *fmt, ...)
20239
17
{
20240
17
    JSContext *ctx = s->ctx;
20241
17
    va_list ap;
20242
17
    int backtrace_flags;
20243
20244
17
    va_start(ap, fmt);
20245
17
    JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE);
20246
17
    va_end(ap);
20247
17
    backtrace_flags = 0;
20248
17
    if (s->cur_func && s->cur_func->backtrace_barrier)
20249
0
        backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
20250
17
    build_backtrace(ctx, ctx->rt->current_exception, s->filename, s->line_num,
20251
17
                    backtrace_flags);
20252
17
    return -1;
20253
17
}
20254
20255
static int js_parse_expect(JSParseState *s, int tok)
20256
65.5k
{
20257
65.5k
    if (s->token.val != tok) {
20258
        /* XXX: dump token correctly in all cases */
20259
0
        return js_parse_error(s, "expecting '%c'", tok);
20260
0
    }
20261
65.5k
    return next_token(s);
20262
65.5k
}
20263
20264
static int js_parse_expect_semi(JSParseState *s)
20265
186
{
20266
186
    if (s->token.val != ';') {
20267
        /* automatic insertion of ';' */
20268
30
        if (s->token.val == TOK_EOF || s->token.val == '}' || s->got_lf) {
20269
26
            return 0;
20270
26
        }
20271
4
        return js_parse_error(s, "expecting '%c'", ';');
20272
30
    }
20273
156
    return next_token(s);
20274
186
}
20275
20276
static int js_parse_error_reserved_identifier(JSParseState *s)
20277
0
{
20278
0
    char buf1[ATOM_GET_STR_BUF_SIZE];
20279
0
    return js_parse_error(s, "'%s' is a reserved identifier",
20280
0
                          JS_AtomGetStr(s->ctx, buf1, sizeof(buf1),
20281
0
                                        s->token.u.ident.atom));
20282
0
}
20283
20284
static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
20285
0
{
20286
0
    uint32_t c;
20287
0
    StringBuffer b_s, *b = &b_s;
20288
20289
    /* p points to the first byte of the template part */
20290
0
    if (string_buffer_init(s->ctx, b, 32))
20291
0
        goto fail;
20292
0
    for(;;) {
20293
0
        if (p >= s->buf_end)
20294
0
            goto unexpected_eof;
20295
0
        c = *p++;
20296
0
        if (c == '`') {
20297
            /* template end part */
20298
0
            break;
20299
0
        }
20300
0
        if (c == '$' && *p == '{') {
20301
            /* template start or middle part */
20302
0
            p++;
20303
0
            break;
20304
0
        }
20305
0
        if (c == '\\') {
20306
0
            if (string_buffer_putc8(b, c))
20307
0
                goto fail;
20308
0
            if (p >= s->buf_end)
20309
0
                goto unexpected_eof;
20310
0
            c = *p++;
20311
0
        }
20312
        /* newline sequences are normalized as single '\n' bytes */
20313
0
        if (c == '\r') {
20314
0
            if (*p == '\n')
20315
0
                p++;
20316
0
            c = '\n';
20317
0
        }
20318
0
        if (c == '\n') {
20319
0
            s->line_num++;
20320
0
        } else if (c >= 0x80) {
20321
0
            const uint8_t *p_next;
20322
0
            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
20323
0
            if (c > 0x10FFFF) {
20324
0
                js_parse_error(s, "invalid UTF-8 sequence");
20325
0
                goto fail;
20326
0
            }
20327
0
            p = p_next;
20328
0
        }
20329
0
        if (string_buffer_putc(b, c))
20330
0
            goto fail;
20331
0
    }
20332
0
    s->token.val = TOK_TEMPLATE;
20333
0
    s->token.u.str.sep = c;
20334
0
    s->token.u.str.str = string_buffer_end(b);
20335
0
    s->buf_ptr = p;
20336
0
    return 0;
20337
20338
0
 unexpected_eof:
20339
0
    js_parse_error(s, "unexpected end of string");
20340
0
 fail:
20341
0
    string_buffer_free(b);
20342
0
    return -1;
20343
0
}
20344
20345
static __exception int js_parse_string(JSParseState *s, int sep,
20346
                                       BOOL do_throw, const uint8_t *p,
20347
                                       JSToken *token, const uint8_t **pp)
20348
117
{
20349
117
    int ret;
20350
117
    uint32_t c;
20351
117
    StringBuffer b_s, *b = &b_s;
20352
20353
    /* string */
20354
117
    if (string_buffer_init(s->ctx, b, 32))
20355
0
        goto fail;
20356
24.0M
    for(;;) {
20357
24.0M
        if (p >= s->buf_end)
20358
1
            goto invalid_char;
20359
24.0M
        c = *p;
20360
24.0M
        if (c < 0x20) {
20361
156
            if (!s->cur_func) {
20362
0
                if (do_throw)
20363
0
                    js_parse_error(s, "invalid character in a JSON string");
20364
0
                goto fail;
20365
0
            }
20366
156
            if (sep == '`') {
20367
0
                if (c == '\r') {
20368
0
                    if (p[1] == '\n')
20369
0
                        p++;
20370
0
                    c = '\n';
20371
0
                }
20372
                /* do not update s->line_num */
20373
156
            } else if (c == '\n' || c == '\r')
20374
0
                goto invalid_char;
20375
156
        }
20376
24.0M
        p++;
20377
24.0M
        if (c == sep)
20378
116
            break;
20379
24.0M
        if (c == '$' && *p == '{' && sep == '`') {
20380
            /* template start or middle part */
20381
0
            p++;
20382
0
            break;
20383
0
        }
20384
24.0M
        if (c == '\\') {
20385
36
            c = *p;
20386
            /* XXX: need a specific JSON case to avoid
20387
               accepting invalid escapes */
20388
36
            switch(c) {
20389
0
            case '\0':
20390
0
                if (p >= s->buf_end)
20391
0
                    goto invalid_char;
20392
0
                p++;
20393
0
                break;
20394
0
            case '\'':
20395
0
            case '\"':
20396
14
            case '\\':
20397
14
                p++;
20398
14
                break;
20399
0
            case '\r':  /* accept DOS and MAC newline sequences */
20400
0
                if (p[1] == '\n') {
20401
0
                    p++;
20402
0
                }
20403
                /* fall thru */
20404
0
            case '\n':
20405
                /* ignore escaped newline sequence */
20406
0
                p++;
20407
0
                if (sep != '`')
20408
0
                    s->line_num++;
20409
0
                continue;
20410
22
            default:
20411
22
                if (c >= '0' && c <= '9') {
20412
0
                    if (!s->cur_func)
20413
0
                        goto invalid_escape; /* JSON case */
20414
0
                    if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`')
20415
0
                        goto parse_escape;
20416
0
                    if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) {
20417
0
                        p++;
20418
0
                        c = '\0';
20419
0
                    } else {
20420
0
                        if (c >= '8' || sep == '`') {
20421
                            /* Note: according to ES2021, \8 and \9 are not
20422
                               accepted in strict mode or in templates. */
20423
0
                            goto invalid_escape;
20424
0
                        } else {
20425
0
                            if (do_throw)
20426
0
                                js_parse_error(s, "octal escape sequences are not allowed in strict mode");
20427
0
                        }
20428
0
                        goto fail;
20429
0
                    }
20430
22
                } else if (c >= 0x80) {
20431
0
                    const uint8_t *p_next;
20432
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
20433
0
                    if (c > 0x10FFFF) {
20434
0
                        goto invalid_utf8;
20435
0
                    }
20436
0
                    p = p_next;
20437
                    /* LS or PS are skipped */
20438
0
                    if (c == CP_LS || c == CP_PS)
20439
0
                        continue;
20440
22
                } else {
20441
22
                parse_escape:
20442
22
                    ret = lre_parse_escape(&p, TRUE);
20443
22
                    if (ret == -1) {
20444
0
                    invalid_escape:
20445
0
                        if (do_throw)
20446
0
                            js_parse_error(s, "malformed escape sequence in string literal");
20447
0
                        goto fail;
20448
22
                    } else if (ret < 0) {
20449
                        /* ignore the '\' (could output a warning) */
20450
0
                        p++;
20451
22
                    } else {
20452
22
                        c = ret;
20453
22
                    }
20454
22
                }
20455
22
                break;
20456
36
            }
20457
24.0M
        } else if (c >= 0x80) {
20458
43.0k
            const uint8_t *p_next;
20459
43.0k
            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
20460
43.0k
            if (c > 0x10FFFF)
20461
0
                goto invalid_utf8;
20462
43.0k
            p = p_next;
20463
43.0k
        }
20464
24.0M
        if (string_buffer_putc(b, c))
20465
0
            goto fail;
20466
24.0M
    }
20467
116
    token->val = TOK_STRING;
20468
116
    token->u.str.sep = c;
20469
116
    token->u.str.str = string_buffer_end(b);
20470
116
    *pp = p;
20471
116
    return 0;
20472
20473
0
 invalid_utf8:
20474
0
    if (do_throw)
20475
0
        js_parse_error(s, "invalid UTF-8 sequence");
20476
0
    goto fail;
20477
1
 invalid_char:
20478
1
    if (do_throw)
20479
1
        js_parse_error(s, "unexpected end of string");
20480
1
 fail:
20481
1
    string_buffer_free(b);
20482
1
    return -1;
20483
1
}
20484
20485
5.52M
static inline BOOL token_is_pseudo_keyword(JSParseState *s, JSAtom atom) {
20486
5.52M
    return s->token.val == TOK_IDENT && s->token.u.ident.atom == atom &&
20487
5.52M
        !s->token.u.ident.has_escape;
20488
5.52M
}
20489
20490
static __exception int js_parse_regexp(JSParseState *s)
20491
0
{
20492
0
    const uint8_t *p;
20493
0
    BOOL in_class;
20494
0
    StringBuffer b_s, *b = &b_s;
20495
0
    StringBuffer b2_s, *b2 = &b2_s;
20496
0
    uint32_t c;
20497
20498
0
    p = s->buf_ptr;
20499
0
    p++;
20500
0
    in_class = FALSE;
20501
0
    if (string_buffer_init(s->ctx, b, 32))
20502
0
        return -1;
20503
0
    if (string_buffer_init(s->ctx, b2, 1))
20504
0
        goto fail;
20505
0
    for(;;) {
20506
0
        if (p >= s->buf_end) {
20507
0
        eof_error:
20508
0
            js_parse_error(s, "unexpected end of regexp");
20509
0
            goto fail;
20510
0
        }
20511
0
        c = *p++;
20512
0
        if (c == '\n' || c == '\r') {
20513
0
            goto eol_error;
20514
0
        } else if (c == '/') {
20515
0
            if (!in_class)
20516
0
                break;
20517
0
        } else if (c == '[') {
20518
0
            in_class = TRUE;
20519
0
        } else if (c == ']') {
20520
            /* XXX: incorrect as the first character in a class */
20521
0
            in_class = FALSE;
20522
0
        } else if (c == '\\') {
20523
0
            if (string_buffer_putc8(b, c))
20524
0
                goto fail;
20525
0
            c = *p++;
20526
0
            if (c == '\n' || c == '\r')
20527
0
                goto eol_error;
20528
0
            else if (c == '\0' && p >= s->buf_end)
20529
0
                goto eof_error;
20530
0
            else if (c >= 0x80) {
20531
0
                const uint8_t *p_next;
20532
0
                c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
20533
0
                if (c > 0x10FFFF) {
20534
0
                    goto invalid_utf8;
20535
0
                }
20536
0
                p = p_next;
20537
0
                if (c == CP_LS || c == CP_PS)
20538
0
                    goto eol_error;
20539
0
            }
20540
0
        } else if (c >= 0x80) {
20541
0
            const uint8_t *p_next;
20542
0
            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
20543
0
            if (c > 0x10FFFF) {
20544
0
            invalid_utf8:
20545
0
                js_parse_error(s, "invalid UTF-8 sequence");
20546
0
                goto fail;
20547
0
            }
20548
0
            p = p_next;
20549
            /* LS or PS are considered as line terminator */
20550
0
            if (c == CP_LS || c == CP_PS) {
20551
0
            eol_error:
20552
0
                js_parse_error(s, "unexpected line terminator in regexp");
20553
0
                goto fail;
20554
0
            }
20555
0
        }
20556
0
        if (string_buffer_putc(b, c))
20557
0
            goto fail;
20558
0
    }
20559
20560
    /* flags */
20561
0
    for(;;) {
20562
0
        const uint8_t *p_next = p;
20563
0
        c = *p_next++;
20564
0
        if (c >= 0x80) {
20565
0
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
20566
0
            if (c > 0x10FFFF) {
20567
0
                goto invalid_utf8;
20568
0
            }
20569
0
        }
20570
0
        if (!lre_js_is_ident_next(c))
20571
0
            break;
20572
0
        if (string_buffer_putc(b2, c))
20573
0
            goto fail;
20574
0
        p = p_next;
20575
0
    }
20576
20577
0
    s->token.val = TOK_REGEXP;
20578
0
    s->token.u.regexp.body = string_buffer_end(b);
20579
0
    s->token.u.regexp.flags = string_buffer_end(b2);
20580
0
    s->buf_ptr = p;
20581
0
    return 0;
20582
0
 fail:
20583
0
    string_buffer_free(b);
20584
0
    string_buffer_free(b2);
20585
0
    return -1;
20586
0
}
20587
20588
static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
20589
                                     char *static_buf)
20590
46
{
20591
46
    char *buf, *new_buf;
20592
46
    size_t size, new_size;
20593
20594
46
    buf = *pbuf;
20595
46
    size = *psize;
20596
46
    if (size >= (SIZE_MAX / 3) * 2)
20597
0
        new_size = SIZE_MAX;
20598
46
    else
20599
46
        new_size = size + (size >> 1);
20600
46
    if (buf == static_buf) {
20601
2
        new_buf = js_malloc(ctx, new_size);
20602
2
        if (!new_buf)
20603
0
            return -1;
20604
2
        memcpy(new_buf, buf, size);
20605
44
    } else {
20606
44
        new_buf = js_realloc(ctx, buf, new_size);
20607
44
        if (!new_buf)
20608
0
            return -1;
20609
44
    }
20610
46
    *pbuf = new_buf;
20611
46
    *psize = new_size;
20612
46
    return 0;
20613
46
}
20614
20615
/* convert a TOK_IDENT to a keyword when needed */
20616
static void update_token_ident(JSParseState *s)
20617
563
{
20618
563
    if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
20619
563
        (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&
20620
485
         (s->cur_func->js_mode & JS_MODE_STRICT)) ||
20621
563
        (s->token.u.ident.atom == JS_ATOM_yield &&
20622
485
         ((s->cur_func->func_kind & JS_FUNC_GENERATOR) ||
20623
0
          (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
20624
0
           !s->cur_func->in_function_body && s->cur_func->parent &&
20625
0
           (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||
20626
563
        (s->token.u.ident.atom == JS_ATOM_await &&
20627
485
         (s->is_module ||
20628
0
          (s->cur_func->func_kind & JS_FUNC_ASYNC) ||
20629
0
          s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT ||
20630
0
          (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
20631
0
           !s->cur_func->in_function_body && s->cur_func->parent &&
20632
0
           ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) ||
20633
78
            s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) {
20634
78
        if (s->token.u.ident.has_escape) {
20635
0
            s->token.u.ident.is_reserved = TRUE;
20636
0
            s->token.val = TOK_IDENT;
20637
78
        } else {
20638
            /* The keywords atoms are pre allocated */
20639
78
            s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD;
20640
78
        }
20641
78
    }
20642
563
}
20643
20644
/* if the current token is an identifier or keyword, reparse it
20645
   according to the current function type */
20646
static void reparse_ident_token(JSParseState *s)
20647
0
{
20648
0
    if (s->token.val == TOK_IDENT ||
20649
0
        (s->token.val >= TOK_FIRST_KEYWORD &&
20650
0
         s->token.val <= TOK_LAST_KEYWORD)) {
20651
0
        s->token.val = TOK_IDENT;
20652
0
        s->token.u.ident.is_reserved = FALSE;
20653
0
        update_token_ident(s);
20654
0
    }
20655
0
}
20656
20657
/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
20658
static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
20659
                          BOOL *pident_has_escape, int c, BOOL is_private)
20660
563
{
20661
563
    const uint8_t *p, *p1;
20662
563
    char ident_buf[128], *buf;
20663
563
    size_t ident_size, ident_pos;
20664
563
    JSAtom atom;
20665
20666
563
    p = *pp;
20667
563
    buf = ident_buf;
20668
563
    ident_size = sizeof(ident_buf);
20669
563
    ident_pos = 0;
20670
563
    if (is_private)
20671
0
        buf[ident_pos++] = '#';
20672
2.09M
    for(;;) {
20673
2.09M
        p1 = p;
20674
20675
2.09M
        if (c < 128) {
20676
2.09M
            buf[ident_pos++] = c;
20677
2.09M
        } else {
20678
0
            ident_pos += unicode_to_utf8((uint8_t*)buf + ident_pos, c);
20679
0
        }
20680
2.09M
        c = *p1++;
20681
2.09M
        if (c == '\\' && *p1 == 'u') {
20682
0
            c = lre_parse_escape(&p1, TRUE);
20683
0
            *pident_has_escape = TRUE;
20684
2.09M
        } else if (c >= 128) {
20685
0
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
20686
0
        }
20687
2.09M
        if (!lre_js_is_ident_next(c))
20688
563
            break;
20689
2.09M
        p = p1;
20690
2.09M
        if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
20691
46
            if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
20692
0
                atom = JS_ATOM_NULL;
20693
0
                goto done;
20694
0
            }
20695
46
        }
20696
2.09M
    }
20697
563
    atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
20698
563
 done:
20699
563
    if (unlikely(buf != ident_buf))
20700
2
        js_free(s->ctx, buf);
20701
563
    *pp = p;
20702
563
    return atom;
20703
563
}
20704
20705
20706
static __exception int next_token(JSParseState *s)
20707
22.3M
{
20708
22.3M
    const uint8_t *p;
20709
22.3M
    int c;
20710
22.3M
    BOOL ident_has_escape;
20711
22.3M
    JSAtom atom;
20712
20713
22.3M
    if (js_check_stack_overflow(s->ctx->rt, 0)) {
20714
0
        return js_parse_error(s, "stack overflow");
20715
0
    }
20716
20717
22.3M
    free_token(s, &s->token);
20718
20719
22.3M
    p = s->last_ptr = s->buf_ptr;
20720
22.3M
    s->got_lf = FALSE;
20721
22.3M
    s->last_line_num = s->token.line_num;
20722
27.5M
 redo:
20723
27.5M
    s->token.line_num = s->line_num;
20724
27.5M
    s->token.ptr = p;
20725
27.5M
    c = *p;
20726
27.5M
    switch(c) {
20727
89
    case 0:
20728
89
        if (p >= s->buf_end) {
20729
87
            s->token.val = TOK_EOF;
20730
87
        } else {
20731
2
            goto def_token;
20732
2
        }
20733
87
        break;
20734
87
    case '`':
20735
0
        if (js_parse_template_part(s, p + 1))
20736
0
            goto fail;
20737
0
        p = s->buf_ptr;
20738
0
        break;
20739
80
    case '\'':
20740
117
    case '\"':
20741
117
        if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
20742
1
            goto fail;
20743
116
        break;
20744
116
    case '\r':  /* accept DOS and MAC newline sequences */
20745
0
        if (p[1] == '\n') {
20746
0
            p++;
20747
0
        }
20748
        /* fall thru */
20749
5.24M
    case '\n':
20750
5.24M
        p++;
20751
5.24M
    line_terminator:
20752
5.24M
        s->got_lf = TRUE;
20753
5.24M
        s->line_num++;
20754
5.24M
        goto redo;
20755
0
    case '\f':
20756
1
    case '\v':
20757
628
    case ' ':
20758
630
    case '\t':
20759
630
        p++;
20760
630
        goto redo;
20761
0
    case '/':
20762
0
        if (p[1] == '*') {
20763
            /* comment */
20764
0
            p += 2;
20765
0
            for(;;) {
20766
0
                if (*p == '\0' && p >= s->buf_end) {
20767
0
                    js_parse_error(s, "unexpected end of comment");
20768
0
                    goto fail;
20769
0
                }
20770
0
                if (p[0] == '*' && p[1] == '/') {
20771
0
                    p += 2;
20772
0
                    break;
20773
0
                }
20774
0
                if (*p == '\n') {
20775
0
                    s->line_num++;
20776
0
                    s->got_lf = TRUE; /* considered as LF for ASI */
20777
0
                    p++;
20778
0
                } else if (*p == '\r') {
20779
0
                    s->got_lf = TRUE; /* considered as LF for ASI */
20780
0
                    p++;
20781
0
                } else if (*p >= 0x80) {
20782
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
20783
0
                    if (c == CP_LS || c == CP_PS) {
20784
0
                        s->got_lf = TRUE; /* considered as LF for ASI */
20785
0
                    } else if (c == -1) {
20786
0
                        p++; /* skip invalid UTF-8 */
20787
0
                    }
20788
0
                } else {
20789
0
                    p++;
20790
0
                }
20791
0
            }
20792
0
            goto redo;
20793
0
        } else if (p[1] == '/') {
20794
            /* line comment */
20795
0
            p += 2;
20796
0
        skip_line_comment:
20797
0
            for(;;) {
20798
0
                if (*p == '\0' && p >= s->buf_end)
20799
0
                    break;
20800
0
                if (*p == '\r' || *p == '\n')
20801
0
                    break;
20802
0
                if (*p >= 0x80) {
20803
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
20804
                    /* LS or PS are considered as line terminator */
20805
0
                    if (c == CP_LS || c == CP_PS) {
20806
0
                        break;
20807
0
                    } else if (c == -1) {
20808
0
                        p++; /* skip invalid UTF-8 */
20809
0
                    }
20810
0
                } else {
20811
0
                    p++;
20812
0
                }
20813
0
            }
20814
0
            goto redo;
20815
0
        } else if (p[1] == '=') {
20816
0
            p += 2;
20817
0
            s->token.val = TOK_DIV_ASSIGN;
20818
0
        } else {
20819
0
            p++;
20820
0
            s->token.val = c;
20821
0
        }
20822
0
        break;
20823
0
    case '\\':
20824
0
        if (p[1] == 'u') {
20825
0
            const uint8_t *p1 = p + 1;
20826
0
            int c1 = lre_parse_escape(&p1, TRUE);
20827
0
            if (c1 >= 0 && lre_js_is_ident_first(c1)) {
20828
0
                c = c1;
20829
0
                p = p1;
20830
0
                ident_has_escape = TRUE;
20831
0
                goto has_ident;
20832
0
            } else {
20833
                /* XXX: syntax error? */
20834
0
            }
20835
0
        }
20836
0
        goto def_token;
20837
79
    case 'a': case 'b': case 'c': case 'd':
20838
235
    case 'e': case 'f': case 'g': case 'h':
20839
313
    case 'i': case 'j': case 'k': case 'l':
20840
430
    case 'm': case 'n': case 'o': case 'p':
20841
553
    case 'q': case 'r': case 's': case 't':
20842
553
    case 'u': case 'v': case 'w': case 'x':
20843
553
    case 'y': case 'z':
20844
553
    case 'A': case 'B': case 'C': case 'D':
20845
555
    case 'E': case 'F': case 'G': case 'H':
20846
555
    case 'I': case 'J': case 'K': case 'L':
20847
561
    case 'M': case 'N': case 'O': case 'P':
20848
561
    case 'Q': case 'R': case 'S': case 'T':
20849
561
    case 'U': case 'V': case 'W': case 'X':
20850
561
    case 'Y': case 'Z':
20851
563
    case '_':
20852
563
    case '$':
20853
        /* identifier */
20854
563
        p++;
20855
563
        ident_has_escape = FALSE;
20856
563
    has_ident:
20857
563
        atom = parse_ident(s, &p, &ident_has_escape, c, FALSE);
20858
563
        if (atom == JS_ATOM_NULL)
20859
0
            goto fail;
20860
563
        s->token.u.ident.atom = atom;
20861
563
        s->token.u.ident.has_escape = ident_has_escape;
20862
563
        s->token.u.ident.is_reserved = FALSE;
20863
563
        s->token.val = TOK_IDENT;
20864
563
        update_token_ident(s);
20865
563
        break;
20866
0
    case '#':
20867
        /* private name */
20868
0
        {
20869
0
            const uint8_t *p1;
20870
0
            p++;
20871
0
            p1 = p;
20872
0
            c = *p1++;
20873
0
            if (c == '\\' && *p1 == 'u') {
20874
0
                c = lre_parse_escape(&p1, TRUE);
20875
0
            } else if (c >= 128) {
20876
0
                c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
20877
0
            }
20878
0
            if (!lre_js_is_ident_first(c)) {
20879
0
                js_parse_error(s, "invalid first character of private name");
20880
0
                goto fail;
20881
0
            }
20882
0
            p = p1;
20883
0
            ident_has_escape = FALSE; /* not used */
20884
0
            atom = parse_ident(s, &p, &ident_has_escape, c, TRUE);
20885
0
            if (atom == JS_ATOM_NULL)
20886
0
                goto fail;
20887
0
            s->token.u.ident.atom = atom;
20888
0
            s->token.val = TOK_PRIVATE_NAME;
20889
0
        }
20890
0
        break;
20891
79
    case '.':
20892
79
        if (p[1] == '.' && p[2] == '.') {
20893
0
            p += 3;
20894
0
            s->token.val = TOK_ELLIPSIS;
20895
0
            break;
20896
0
        }
20897
79
        if (p[1] >= '0' && p[1] <= '9') {
20898
1
            goto parse_number;
20899
78
        } else {
20900
78
            goto def_token;
20901
78
        }
20902
0
        break;
20903
9.94M
    case '0':
20904
        /* in strict mode, octal literals are not accepted */
20905
9.94M
        if (is_digit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) {
20906
2
            js_parse_error(s, "octal literals are deprecated in strict mode");
20907
2
            goto fail;
20908
2
        }
20909
9.94M
        goto parse_number;
20910
9.94M
    case '1': case '2': case '3': case '4':
20911
1.21M
    case '5': case '6': case '7': case '8':
20912
1.21M
    case '9':
20913
        /* number */
20914
11.1M
    parse_number:
20915
11.1M
        {
20916
11.1M
            JSValue ret;
20917
11.1M
            const uint8_t *p1;
20918
11.1M
            int flags, radix;
20919
11.1M
            flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |
20920
11.1M
                ATOD_ACCEPT_UNDERSCORES;
20921
11.1M
            flags |= ATOD_ACCEPT_SUFFIX;
20922
11.1M
#ifdef CONFIG_BIGNUM
20923
11.1M
            if (s->cur_func->js_mode & JS_MODE_MATH) {
20924
0
                flags |= ATOD_MODE_BIGINT;
20925
0
                if (s->cur_func->js_mode & JS_MODE_MATH)
20926
0
                    flags |= ATOD_TYPE_BIG_FLOAT;
20927
0
            }
20928
11.1M
#endif
20929
11.1M
            radix = 0;
20930
11.1M
#ifdef CONFIG_BIGNUM
20931
11.1M
            s->token.u.num.exponent = 0;
20932
11.1M
            ret = js_atof2(s->ctx, (const char *)p, (const char **)&p, radix,
20933
11.1M
                           flags, &s->token.u.num.exponent);
20934
#else
20935
            ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
20936
                          flags);
20937
#endif
20938
11.1M
            if (JS_IsException(ret))
20939
0
                goto fail;
20940
            /* reject `10instanceof Number` */
20941
11.1M
            if (JS_VALUE_IS_NAN(ret) ||
20942
11.1M
                lre_js_is_ident_next(unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1))) {
20943
3
                JS_FreeValue(s->ctx, ret);
20944
3
                js_parse_error(s, "invalid number literal");
20945
3
                goto fail;
20946
3
            }
20947
11.1M
            s->token.val = TOK_NUMBER;
20948
11.1M
            s->token.u.num.val = ret;
20949
11.1M
        }
20950
0
        break;
20951
78
    case '*':
20952
78
        if (p[1] == '=') {
20953
0
            p += 2;
20954
0
            s->token.val = TOK_MUL_ASSIGN;
20955
78
        } else if (p[1] == '*') {
20956
0
            if (p[2] == '=') {
20957
0
                p += 3;
20958
0
                s->token.val = TOK_POW_ASSIGN;
20959
0
            } else {
20960
0
                p += 2;
20961
0
                s->token.val = TOK_POW;
20962
0
            }
20963
78
        } else {
20964
78
            goto def_token;
20965
78
        }
20966
0
        break;
20967
0
    case '%':
20968
0
        if (p[1] == '=') {
20969
0
            p += 2;
20970
0
            s->token.val = TOK_MOD_ASSIGN;
20971
0
        } else {
20972
0
            goto def_token;
20973
0
        }
20974
0
        break;
20975
2
    case '+':
20976
2
        if (p[1] == '=') {
20977
0
            p += 2;
20978
0
            s->token.val = TOK_PLUS_ASSIGN;
20979
2
        } else if (p[1] == '+') {
20980
0
            p += 2;
20981
0
            s->token.val = TOK_INC;
20982
2
        } else {
20983
2
            goto def_token;
20984
2
        }
20985
0
        break;
20986
13
    case '-':
20987
13
        if (p[1] == '=') {
20988
0
            p += 2;
20989
0
            s->token.val = TOK_MINUS_ASSIGN;
20990
13
        } else if (p[1] == '-') {
20991
0
            if (s->allow_html_comments &&
20992
0
                p[2] == '>' && s->last_line_num != s->line_num) {
20993
                /* Annex B: `-->` at beginning of line is an html comment end.
20994
                   It extends to the end of the line.
20995
                 */
20996
0
                goto skip_line_comment;
20997
0
            }
20998
0
            p += 2;
20999
0
            s->token.val = TOK_DEC;
21000
13
        } else {
21001
13
            goto def_token;
21002
13
        }
21003
0
        break;
21004
0
    case '<':
21005
0
        if (p[1] == '=') {
21006
0
            p += 2;
21007
0
            s->token.val = TOK_LTE;
21008
0
        } else if (p[1] == '<') {
21009
0
            if (p[2] == '=') {
21010
0
                p += 3;
21011
0
                s->token.val = TOK_SHL_ASSIGN;
21012
0
            } else {
21013
0
                p += 2;
21014
0
                s->token.val = TOK_SHL;
21015
0
            }
21016
0
        } else if (s->allow_html_comments &&
21017
0
                   p[1] == '!' && p[2] == '-' && p[3] == '-') {
21018
            /* Annex B: handle `<!--` single line html comments */
21019
0
            goto skip_line_comment;
21020
0
        } else {
21021
0
            goto def_token;
21022
0
        }
21023
0
        break;
21024
0
    case '>':
21025
0
        if (p[1] == '=') {
21026
0
            p += 2;
21027
0
            s->token.val = TOK_GTE;
21028
0
        } else if (p[1] == '>') {
21029
0
            if (p[2] == '>') {
21030
0
                if (p[3] == '=') {
21031
0
                    p += 4;
21032
0
                    s->token.val = TOK_SHR_ASSIGN;
21033
0
                } else {
21034
0
                    p += 3;
21035
0
                    s->token.val = TOK_SHR;
21036
0
                }
21037
0
            } else if (p[2] == '=') {
21038
0
                p += 3;
21039
0
                s->token.val = TOK_SAR_ASSIGN;
21040
0
            } else {
21041
0
                p += 2;
21042
0
                s->token.val = TOK_SAR;
21043
0
            }
21044
0
        } else {
21045
0
            goto def_token;
21046
0
        }
21047
0
        break;
21048
79
    case '=':
21049
79
        if (p[1] == '=') {
21050
0
            if (p[2] == '=') {
21051
0
                p += 3;
21052
0
                s->token.val = TOK_STRICT_EQ;
21053
0
            } else {
21054
0
                p += 2;
21055
0
                s->token.val = TOK_EQ;
21056
0
            }
21057
79
        } else if (p[1] == '>') {
21058
0
            p += 2;
21059
0
            s->token.val = TOK_ARROW;
21060
79
        } else {
21061
79
            goto def_token;
21062
79
        }
21063
0
        break;
21064
0
    case '!':
21065
0
        if (p[1] == '=') {
21066
0
            if (p[2] == '=') {
21067
0
                p += 3;
21068
0
                s->token.val = TOK_STRICT_NEQ;
21069
0
            } else {
21070
0
                p += 2;
21071
0
                s->token.val = TOK_NEQ;
21072
0
            }
21073
0
        } else {
21074
0
            goto def_token;
21075
0
        }
21076
0
        break;
21077
0
    case '&':
21078
0
        if (p[1] == '=') {
21079
0
            p += 2;
21080
0
            s->token.val = TOK_AND_ASSIGN;
21081
0
        } else if (p[1] == '&') {
21082
0
            if (p[2] == '=') {
21083
0
                p += 3;
21084
0
                s->token.val = TOK_LAND_ASSIGN;
21085
0
            } else {
21086
0
                p += 2;
21087
0
                s->token.val = TOK_LAND;
21088
0
            }
21089
0
        } else {
21090
0
            goto def_token;
21091
0
        }
21092
0
        break;
21093
0
#ifdef CONFIG_BIGNUM
21094
        /* in math mode, '^' is the power operator. '^^' is always the
21095
           xor operator and '**' is always the power operator */
21096
0
    case '^':
21097
0
        if (p[1] == '=') {
21098
0
            p += 2;
21099
0
            if (s->cur_func->js_mode & JS_MODE_MATH)
21100
0
                s->token.val = TOK_MATH_POW_ASSIGN;
21101
0
            else
21102
0
                s->token.val = TOK_XOR_ASSIGN;
21103
0
        } else if (p[1] == '^') {
21104
0
            if (p[2] == '=') {
21105
0
                p += 3;
21106
0
                s->token.val = TOK_XOR_ASSIGN;
21107
0
            } else {
21108
0
                p += 2;
21109
0
                s->token.val = '^';
21110
0
            }
21111
0
        } else {
21112
0
            p++;
21113
0
            if (s->cur_func->js_mode & JS_MODE_MATH)
21114
0
                s->token.val = TOK_MATH_POW;
21115
0
            else
21116
0
                s->token.val = '^';
21117
0
        }
21118
0
        break;
21119
#else
21120
    case '^':
21121
        if (p[1] == '=') {
21122
            p += 2;
21123
            s->token.val = TOK_XOR_ASSIGN;
21124
        } else {
21125
            goto def_token;
21126
        }
21127
        break;
21128
#endif
21129
0
    case '|':
21130
0
        if (p[1] == '=') {
21131
0
            p += 2;
21132
0
            s->token.val = TOK_OR_ASSIGN;
21133
0
        } else if (p[1] == '|') {
21134
0
            if (p[2] == '=') {
21135
0
                p += 3;
21136
0
                s->token.val = TOK_LOR_ASSIGN;
21137
0
            } else {
21138
0
                p += 2;
21139
0
                s->token.val = TOK_LOR;
21140
0
            }
21141
0
        } else {
21142
0
            goto def_token;
21143
0
        }
21144
0
        break;
21145
0
    case '?':
21146
0
        if (p[1] == '?') {
21147
0
            if (p[2] == '=') {
21148
0
                p += 3;
21149
0
                s->token.val = TOK_DOUBLE_QUESTION_MARK_ASSIGN;
21150
0
            } else {
21151
0
                p += 2;
21152
0
                s->token.val = TOK_DOUBLE_QUESTION_MARK;
21153
0
            }
21154
0
        } else if (p[1] == '.' && !(p[2] >= '0' && p[2] <= '9')) {
21155
0
            p += 2;
21156
0
            s->token.val = TOK_QUESTION_MARK_DOT;
21157
0
        } else {
21158
0
            goto def_token;
21159
0
        }
21160
0
        break;
21161
11.1M
    default:
21162
11.1M
        if (c >= 128) {
21163
            /* unicode value */
21164
1
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21165
1
            switch(c) {
21166
0
            case CP_PS:
21167
0
            case CP_LS:
21168
                /* XXX: should avoid incrementing line_number, but
21169
                   needed to handle HTML comments */
21170
0
                goto line_terminator;
21171
1
            default:
21172
1
                if (lre_is_space(c)) {
21173
0
                    goto redo;
21174
1
                } else if (lre_js_is_ident_first(c)) {
21175
0
                    ident_has_escape = FALSE;
21176
0
                    goto has_ident;
21177
1
                } else {
21178
1
                    js_parse_error(s, "unexpected character");
21179
1
                    goto fail;
21180
1
                }
21181
1
            }
21182
1
        }
21183
11.1M
    def_token:
21184
11.1M
        s->token.val = c;
21185
11.1M
        p++;
21186
11.1M
        break;
21187
27.5M
    }
21188
22.3M
    s->buf_ptr = p;
21189
21190
    //    dump_token(s, &s->token);
21191
22.3M
    return 0;
21192
21193
7
 fail:
21194
7
    s->token.val = TOK_ERROR;
21195
7
    return -1;
21196
27.5M
}
21197
21198
/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
21199
static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
21200
0
{
21201
0
    const uint8_t *p;
21202
0
    char ident_buf[128], *buf;
21203
0
    size_t ident_size, ident_pos;
21204
0
    JSAtom atom;
21205
21206
0
    p = *pp;
21207
0
    buf = ident_buf;
21208
0
    ident_size = sizeof(ident_buf);
21209
0
    ident_pos = 0;
21210
0
    for(;;) {
21211
0
        buf[ident_pos++] = c;
21212
0
        c = *p;
21213
0
        if (c >= 128 || !lre_is_id_continue_byte(c))
21214
0
            break;
21215
0
        p++;
21216
0
        if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
21217
0
            if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
21218
0
                atom = JS_ATOM_NULL;
21219
0
                goto done;
21220
0
            }
21221
0
        }
21222
0
    }
21223
0
    atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
21224
0
 done:
21225
0
    if (unlikely(buf != ident_buf))
21226
0
        js_free(s->ctx, buf);
21227
0
    *pp = p;
21228
0
    return atom;
21229
0
}
21230
21231
static __exception int json_next_token(JSParseState *s)
21232
0
{
21233
0
    const uint8_t *p;
21234
0
    int c;
21235
0
    JSAtom atom;
21236
21237
0
    if (js_check_stack_overflow(s->ctx->rt, 0)) {
21238
0
        return js_parse_error(s, "stack overflow");
21239
0
    }
21240
21241
0
    free_token(s, &s->token);
21242
21243
0
    p = s->last_ptr = s->buf_ptr;
21244
0
    s->last_line_num = s->token.line_num;
21245
0
 redo:
21246
0
    s->token.line_num = s->line_num;
21247
0
    s->token.ptr = p;
21248
0
    c = *p;
21249
0
    switch(c) {
21250
0
    case 0:
21251
0
        if (p >= s->buf_end) {
21252
0
            s->token.val = TOK_EOF;
21253
0
        } else {
21254
0
            goto def_token;
21255
0
        }
21256
0
        break;
21257
0
    case '\'':
21258
0
        if (!s->ext_json) {
21259
            /* JSON does not accept single quoted strings */
21260
0
            goto def_token;
21261
0
        }
21262
        /* fall through */
21263
0
    case '\"':
21264
0
        if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
21265
0
            goto fail;
21266
0
        break;
21267
0
    case '\r':  /* accept DOS and MAC newline sequences */
21268
0
        if (p[1] == '\n') {
21269
0
            p++;
21270
0
        }
21271
        /* fall thru */
21272
0
    case '\n':
21273
0
        p++;
21274
0
        s->line_num++;
21275
0
        goto redo;
21276
0
    case '\f':
21277
0
    case '\v':
21278
0
        if (!s->ext_json) {
21279
            /* JSONWhitespace does not match <VT>, nor <FF> */
21280
0
            goto def_token;
21281
0
        }
21282
        /* fall through */
21283
0
    case ' ':
21284
0
    case '\t':
21285
0
        p++;
21286
0
        goto redo;
21287
0
    case '/':
21288
0
        if (!s->ext_json) {
21289
            /* JSON does not accept comments */
21290
0
            goto def_token;
21291
0
        }
21292
0
        if (p[1] == '*') {
21293
            /* comment */
21294
0
            p += 2;
21295
0
            for(;;) {
21296
0
                if (*p == '\0' && p >= s->buf_end) {
21297
0
                    js_parse_error(s, "unexpected end of comment");
21298
0
                    goto fail;
21299
0
                }
21300
0
                if (p[0] == '*' && p[1] == '/') {
21301
0
                    p += 2;
21302
0
                    break;
21303
0
                }
21304
0
                if (*p == '\n') {
21305
0
                    s->line_num++;
21306
0
                    p++;
21307
0
                } else if (*p == '\r') {
21308
0
                    p++;
21309
0
                } else if (*p >= 0x80) {
21310
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21311
0
                    if (c == -1) {
21312
0
                        p++; /* skip invalid UTF-8 */
21313
0
                    }
21314
0
                } else {
21315
0
                    p++;
21316
0
                }
21317
0
            }
21318
0
            goto redo;
21319
0
        } else if (p[1] == '/') {
21320
            /* line comment */
21321
0
            p += 2;
21322
0
            for(;;) {
21323
0
                if (*p == '\0' && p >= s->buf_end)
21324
0
                    break;
21325
0
                if (*p == '\r' || *p == '\n')
21326
0
                    break;
21327
0
                if (*p >= 0x80) {
21328
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21329
                    /* LS or PS are considered as line terminator */
21330
0
                    if (c == CP_LS || c == CP_PS) {
21331
0
                        break;
21332
0
                    } else if (c == -1) {
21333
0
                        p++; /* skip invalid UTF-8 */
21334
0
                    }
21335
0
                } else {
21336
0
                    p++;
21337
0
                }
21338
0
            }
21339
0
            goto redo;
21340
0
        } else {
21341
0
            goto def_token;
21342
0
        }
21343
0
        break;
21344
0
    case 'a': case 'b': case 'c': case 'd':
21345
0
    case 'e': case 'f': case 'g': case 'h':
21346
0
    case 'i': case 'j': case 'k': case 'l':
21347
0
    case 'm': case 'n': case 'o': case 'p':
21348
0
    case 'q': case 'r': case 's': case 't':
21349
0
    case 'u': case 'v': case 'w': case 'x':
21350
0
    case 'y': case 'z':
21351
0
    case 'A': case 'B': case 'C': case 'D':
21352
0
    case 'E': case 'F': case 'G': case 'H':
21353
0
    case 'I': case 'J': case 'K': case 'L':
21354
0
    case 'M': case 'N': case 'O': case 'P':
21355
0
    case 'Q': case 'R': case 'S': case 'T':
21356
0
    case 'U': case 'V': case 'W': case 'X':
21357
0
    case 'Y': case 'Z':
21358
0
    case '_':
21359
0
    case '$':
21360
        /* identifier : only pure ascii characters are accepted */
21361
0
        p++;
21362
0
        atom = json_parse_ident(s, &p, c);
21363
0
        if (atom == JS_ATOM_NULL)
21364
0
            goto fail;
21365
0
        s->token.u.ident.atom = atom;
21366
0
        s->token.u.ident.has_escape = FALSE;
21367
0
        s->token.u.ident.is_reserved = FALSE;
21368
0
        s->token.val = TOK_IDENT;
21369
0
        break;
21370
0
    case '+':
21371
0
        if (!s->ext_json || !is_digit(p[1]))
21372
0
            goto def_token;
21373
0
        goto parse_number;
21374
0
    case '0':
21375
0
        if (is_digit(p[1]))
21376
0
            goto def_token;
21377
0
        goto parse_number;
21378
0
    case '-':
21379
0
        if (!is_digit(p[1]))
21380
0
            goto def_token;
21381
0
        goto parse_number;
21382
0
    case '1': case '2': case '3': case '4':
21383
0
    case '5': case '6': case '7': case '8':
21384
0
    case '9':
21385
        /* number */
21386
0
    parse_number:
21387
0
        {
21388
0
            JSValue ret;
21389
0
            int flags, radix;
21390
0
            if (!s->ext_json) {
21391
0
                flags = 0;
21392
0
                radix = 10;
21393
0
            } else {
21394
0
                flags = ATOD_ACCEPT_BIN_OCT;
21395
0
                radix = 0;
21396
0
            }
21397
0
            ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
21398
0
                          flags);
21399
0
            if (JS_IsException(ret))
21400
0
                goto fail;
21401
0
            s->token.val = TOK_NUMBER;
21402
0
            s->token.u.num.val = ret;
21403
0
        }
21404
0
        break;
21405
0
    default:
21406
0
        if (c >= 128) {
21407
0
            js_parse_error(s, "unexpected character");
21408
0
            goto fail;
21409
0
        }
21410
0
    def_token:
21411
0
        s->token.val = c;
21412
0
        p++;
21413
0
        break;
21414
0
    }
21415
0
    s->buf_ptr = p;
21416
21417
    //    dump_token(s, &s->token);
21418
0
    return 0;
21419
21420
0
 fail:
21421
0
    s->token.val = TOK_ERROR;
21422
0
    return -1;
21423
0
}
21424
21425
0
static int match_identifier(const uint8_t *p, const char *s) {
21426
0
    uint32_t c;
21427
0
    while (*s) {
21428
0
        if ((uint8_t)*s++ != *p++)
21429
0
            return 0;
21430
0
    }
21431
0
    c = *p;
21432
0
    if (c >= 128)
21433
0
        c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21434
0
    return !lre_js_is_ident_next(c);
21435
0
}
21436
21437
/* simple_next_token() is used to check for the next token in simple cases.
21438
   It is only used for ':' and '=>', 'let' or 'function' look-ahead.
21439
   (*pp) is only set if TOK_IMPORT is returned for JS_DetectModule()
21440
   Whitespace and comments are skipped correctly.
21441
   Then the next token is analyzed, only for specific words.
21442
   Return values:
21443
   - '\n' if !no_line_terminator
21444
   - TOK_ARROW, TOK_IN, TOK_IMPORT, TOK_OF, TOK_EXPORT, TOK_FUNCTION
21445
   - TOK_IDENT is returned for other identifiers and keywords
21446
   - otherwise the next character or unicode codepoint is returned.
21447
 */
21448
static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator)
21449
333
{
21450
333
    const uint8_t *p;
21451
333
    uint32_t c;
21452
21453
    /* skip spaces and comments */
21454
333
    p = *pp;
21455
394k
    for (;;) {
21456
394k
        switch(c = *p++) {
21457
0
        case '\r':
21458
393k
        case '\n':
21459
393k
            if (no_line_terminator)
21460
1
                return '\n';
21461
393k
            continue;
21462
393k
        case ' ':
21463
78
        case '\t':
21464
78
        case '\v':
21465
78
        case '\f':
21466
78
            continue;
21467
0
        case '/':
21468
0
            if (*p == '/') {
21469
0
                if (no_line_terminator)
21470
0
                    return '\n';
21471
0
                while (*p && *p != '\r' && *p != '\n')
21472
0
                    p++;
21473
0
                continue;
21474
0
            }
21475
0
            if (*p == '*') {
21476
0
                while (*++p) {
21477
0
                    if ((*p == '\r' || *p == '\n') && no_line_terminator)
21478
0
                        return '\n';
21479
0
                    if (*p == '*' && p[1] == '/') {
21480
0
                        p += 2;
21481
0
                        break;
21482
0
                    }
21483
0
                }
21484
0
                continue;
21485
0
            }
21486
0
            break;
21487
2
        case '=':
21488
2
            if (*p == '>')
21489
0
                return TOK_ARROW;
21490
2
            break;
21491
2
        case 'i':
21492
0
            if (match_identifier(p, "n"))
21493
0
                return TOK_IN;
21494
0
            if (match_identifier(p, "mport")) {
21495
0
                *pp = p + 5;
21496
0
                return TOK_IMPORT;
21497
0
            }
21498
0
            return TOK_IDENT;
21499
0
        case 'o':
21500
0
            if (match_identifier(p, "f"))
21501
0
                return TOK_OF;
21502
0
            return TOK_IDENT;
21503
0
        case 'e':
21504
0
            if (match_identifier(p, "xport"))
21505
0
                return TOK_EXPORT;
21506
0
            return TOK_IDENT;
21507
0
        case 'f':
21508
0
            if (match_identifier(p, "unction"))
21509
0
                return TOK_FUNCTION;
21510
0
            return TOK_IDENT;
21511
0
        case '\\':
21512
0
            if (*p == 'u') {
21513
0
                if (lre_js_is_ident_first(lre_parse_escape(&p, TRUE)))
21514
0
                    return TOK_IDENT;
21515
0
            }
21516
0
            break;
21517
330
        default:
21518
330
            if (c >= 128) {
21519
0
                c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p);
21520
0
                if (no_line_terminator && (c == CP_PS || c == CP_LS))
21521
0
                    return '\n';
21522
0
            }
21523
330
            if (lre_is_space(c))
21524
0
                continue;
21525
330
            if (lre_js_is_ident_first(c))
21526
0
                return TOK_IDENT;
21527
330
            break;
21528
394k
        }
21529
332
        return c;
21530
394k
    }
21531
333
}
21532
21533
static int peek_token(JSParseState *s, BOOL no_line_terminator)
21534
333
{
21535
333
    const uint8_t *p = s->buf_ptr;
21536
333
    return simple_next_token(&p, no_line_terminator);
21537
333
}
21538
21539
static void skip_shebang(const uint8_t **pp, const uint8_t *buf_end)
21540
78
{
21541
78
    const uint8_t *p = *pp;
21542
78
    int c;
21543
21544
78
    if (p[0] == '#' && p[1] == '!') {
21545
0
        p += 2;
21546
0
        while (p < buf_end) {
21547
0
            if (*p == '\n' || *p == '\r') {
21548
0
                break;
21549
0
            } else if (*p >= 0x80) {
21550
0
                c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21551
0
                if (c == CP_LS || c == CP_PS) {
21552
0
                    break;
21553
0
                } else if (c == -1) {
21554
0
                    p++; /* skip invalid UTF-8 */
21555
0
                }
21556
0
            } else {
21557
0
                p++;
21558
0
            }
21559
0
        }
21560
0
        *pp = p;
21561
0
    }
21562
78
}
21563
21564
/* return true if 'input' contains the source of a module
21565
   (heuristic). 'input' must be a zero terminated.
21566
21567
   Heuristic: skip comments and expect 'import' keyword not followed
21568
   by '(' or '.' or export keyword.
21569
*/
21570
BOOL JS_DetectModule(const char *input, size_t input_len)
21571
0
{
21572
0
    const uint8_t *p = (const uint8_t *)input;
21573
0
    int tok;
21574
21575
0
    skip_shebang(&p, p + input_len);
21576
0
    switch(simple_next_token(&p, FALSE)) {
21577
0
    case TOK_IMPORT:
21578
0
        tok = simple_next_token(&p, FALSE);
21579
0
        return (tok != '.' && tok != '(');
21580
0
    case TOK_EXPORT:
21581
0
        return TRUE;
21582
0
    default:
21583
0
        return FALSE;
21584
0
    }
21585
0
}
21586
21587
159
static inline int get_prev_opcode(JSFunctionDef *fd) {
21588
159
    if (fd->last_opcode_pos < 0)
21589
0
        return OP_invalid;
21590
159
    else
21591
159
        return fd->byte_code.buf[fd->last_opcode_pos];
21592
159
}
21593
21594
0
static BOOL js_is_live_code(JSParseState *s) {
21595
0
    switch (get_prev_opcode(s->cur_func)) {
21596
0
    case OP_tail_call:
21597
0
    case OP_tail_call_method:
21598
0
    case OP_return:
21599
0
    case OP_return_undef:
21600
0
    case OP_return_async:
21601
0
    case OP_throw:
21602
0
    case OP_throw_error:
21603
0
    case OP_goto:
21604
0
#if SHORT_OPCODES
21605
0
    case OP_goto8:
21606
0
    case OP_goto16:
21607
0
#endif
21608
0
    case OP_ret:
21609
0
        return FALSE;
21610
0
    default:
21611
0
        return TRUE;
21612
0
    }
21613
0
}
21614
21615
static void emit_u8(JSParseState *s, uint8_t val)
21616
0
{
21617
0
    dbuf_putc(&s->cur_func->byte_code, val);
21618
0
}
21619
21620
static void emit_u16(JSParseState *s, uint16_t val)
21621
323
{
21622
323
    dbuf_put_u16(&s->cur_func->byte_code, val);
21623
323
}
21624
21625
static void emit_u32(JSParseState *s, uint32_t val)
21626
10.9M
{
21627
10.9M
    dbuf_put_u32(&s->cur_func->byte_code, val);
21628
10.9M
}
21629
21630
static void emit_op(JSParseState *s, uint8_t val)
21631
10.9M
{
21632
10.9M
    JSFunctionDef *fd = s->cur_func;
21633
10.9M
    DynBuf *bc = &fd->byte_code;
21634
21635
    /* Use the line number of the last token used, not the next token,
21636
       nor the current offset in the source file.
21637
     */
21638
10.9M
    if (unlikely(fd->last_opcode_line_num != s->last_line_num)) {
21639
194
        dbuf_putc(bc, OP_line_num);
21640
194
        dbuf_put_u32(bc, s->last_line_num);
21641
194
        fd->last_opcode_line_num = s->last_line_num;
21642
194
    }
21643
10.9M
    fd->last_opcode_pos = bc->size;
21644
10.9M
    dbuf_putc(bc, val);
21645
10.9M
}
21646
21647
static void emit_atom(JSParseState *s, JSAtom name)
21648
79
{
21649
79
    emit_u32(s, JS_DupAtom(s->ctx, name));
21650
79
}
21651
21652
static int update_label(JSFunctionDef *s, int label, int delta)
21653
157
{
21654
157
    LabelSlot *ls;
21655
21656
157
    assert(label >= 0 && label < s->label_count);
21657
157
    ls = &s->label_slots[label];
21658
157
    ls->ref_count += delta;
21659
157
    assert(ls->ref_count >= 0);
21660
157
    return ls->ref_count;
21661
157
}
21662
21663
static int new_label_fd(JSFunctionDef *fd, int label)
21664
40
{
21665
40
    LabelSlot *ls;
21666
21667
40
    if (label < 0) {
21668
40
        if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
21669
40
                            sizeof(fd->label_slots[0]),
21670
40
                            &fd->label_size, fd->label_count + 1))
21671
0
            return -1;
21672
40
        label = fd->label_count++;
21673
40
        ls = &fd->label_slots[label];
21674
40
        ls->ref_count = 0;
21675
40
        ls->pos = -1;
21676
40
        ls->pos2 = -1;
21677
40
        ls->addr = -1;
21678
40
        ls->first_reloc = NULL;
21679
40
    }
21680
40
    return label;
21681
40
}
21682
21683
static int new_label(JSParseState *s)
21684
1
{
21685
1
    return new_label_fd(s->cur_func, -1);
21686
1
}
21687
21688
/* don't update the last opcode and don't emit line number info */
21689
static void emit_label_raw(JSParseState *s, int label)
21690
0
{
21691
0
    emit_u8(s, OP_label);
21692
0
    emit_u32(s, label);
21693
0
    s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
21694
0
}
21695
21696
/* return the label ID offset */
21697
static int emit_label(JSParseState *s, int label)
21698
1
{
21699
1
    if (label >= 0) {
21700
1
        emit_op(s, OP_label);
21701
1
        emit_u32(s, label);
21702
1
        s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
21703
1
        return s->cur_func->byte_code.size - 4;
21704
1
    } else {
21705
0
        return -1;
21706
0
    }
21707
1
}
21708
21709
/* return label or -1 if dead code */
21710
static int emit_goto(JSParseState *s, int opcode, int label)
21711
0
{
21712
0
    if (js_is_live_code(s)) {
21713
0
        if (label < 0)
21714
0
            label = new_label(s);
21715
0
        emit_op(s, opcode);
21716
0
        emit_u32(s, label);
21717
0
        s->cur_func->label_slots[label].ref_count++;
21718
0
        return label;
21719
0
    }
21720
0
    return -1;
21721
0
}
21722
21723
/* return the constant pool index. 'val' is not duplicated. */
21724
static int cpool_add(JSParseState *s, JSValue val)
21725
7
{
21726
7
    JSFunctionDef *fd = s->cur_func;
21727
21728
7
    if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]),
21729
7
                        &fd->cpool_size, fd->cpool_count + 1))
21730
0
        return -1;
21731
7
    fd->cpool[fd->cpool_count++] = val;
21732
7
    return fd->cpool_count - 1;
21733
7
}
21734
21735
static __exception int emit_push_const(JSParseState *s, JSValueConst val,
21736
                                       BOOL as_atom)
21737
27
{
21738
27
    int idx;
21739
21740
27
    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING && as_atom) {
21741
20
        JSAtom atom;
21742
        /* warning: JS_NewAtomStr frees the string value */
21743
20
        JS_DupValue(s->ctx, val);
21744
20
        atom = JS_NewAtomStr(s->ctx, JS_VALUE_GET_STRING(val));
21745
20
        if (atom != JS_ATOM_NULL && !__JS_AtomIsTaggedInt(atom)) {
21746
20
            emit_op(s, OP_push_atom_value);
21747
20
            emit_u32(s, atom);
21748
20
            return 0;
21749
20
        }
21750
20
    }
21751
21752
7
    idx = cpool_add(s, JS_DupValue(s->ctx, val));
21753
7
    if (idx < 0)
21754
0
        return -1;
21755
7
    emit_op(s, OP_push_const);
21756
7
    emit_u32(s, idx);
21757
7
    return 0;
21758
7
}
21759
21760
/* return the variable index or -1 if not found,
21761
   add ARGUMENT_VAR_OFFSET for argument variables */
21762
static int find_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21763
167
{
21764
167
    int i;
21765
167
    for(i = fd->arg_count; i-- > 0;) {
21766
0
        if (fd->args[i].var_name == name)
21767
0
            return i | ARGUMENT_VAR_OFFSET;
21768
0
    }
21769
167
    return -1;
21770
167
}
21771
21772
static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21773
167
{
21774
167
    int i;
21775
178
    for(i = fd->var_count; i-- > 0;) {
21776
11
        if (fd->vars[i].var_name == name && fd->vars[i].scope_level == 0)
21777
0
            return i;
21778
11
    }
21779
167
    return find_arg(ctx, fd, name);
21780
167
}
21781
21782
/* find a variable declaration in a given scope */
21783
static int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd,
21784
                             JSAtom name, int scope_level)
21785
0
{
21786
0
    int scope_idx;
21787
0
    for(scope_idx = fd->scopes[scope_level].first; scope_idx >= 0;
21788
0
        scope_idx = fd->vars[scope_idx].scope_next) {
21789
0
        if (fd->vars[scope_idx].scope_level != scope_level)
21790
0
            break;
21791
0
        if (fd->vars[scope_idx].var_name == name)
21792
0
            return scope_idx;
21793
0
    }
21794
0
    return -1;
21795
0
}
21796
21797
/* return true if scope == parent_scope or if scope is a child of
21798
   parent_scope */
21799
static BOOL is_child_scope(JSContext *ctx, JSFunctionDef *fd,
21800
                           int scope, int parent_scope)
21801
0
{
21802
0
    while (scope >= 0) {
21803
0
        if (scope == parent_scope)
21804
0
            return TRUE;
21805
0
        scope = fd->scopes[scope].parent;
21806
0
    }
21807
0
    return FALSE;
21808
0
}
21809
21810
/* find a 'var' declaration in the same scope or a child scope */
21811
static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd,
21812
                                   JSAtom name, int scope_level)
21813
0
{
21814
0
    int i;
21815
0
    for(i = 0; i < fd->var_count; i++) {
21816
0
        JSVarDef *vd = &fd->vars[i];
21817
0
        if (vd->var_name == name && vd->scope_level == 0) {
21818
0
            if (is_child_scope(ctx, fd, vd->scope_next,
21819
0
                               scope_level))
21820
0
                return i;
21821
0
        }
21822
0
    }
21823
0
    return -1;
21824
0
}
21825
21826
21827
static JSGlobalVar *find_global_var(JSFunctionDef *fd, JSAtom name)
21828
0
{
21829
0
    int i;
21830
0
    for(i = 0; i < fd->global_var_count; i++) {
21831
0
        JSGlobalVar *hf = &fd->global_vars[i];
21832
0
        if (hf->var_name == name)
21833
0
            return hf;
21834
0
    }
21835
0
    return NULL;
21836
21837
0
}
21838
21839
static JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name)
21840
0
{
21841
0
    JSGlobalVar *hf = find_global_var(fd, name);
21842
0
    if (hf && hf->is_lexical)
21843
0
        return hf;
21844
0
    else
21845
0
        return NULL;
21846
0
}
21847
21848
static int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
21849
                             int scope_idx, BOOL check_catch_var)
21850
0
{
21851
0
    while (scope_idx >= 0) {
21852
0
        JSVarDef *vd = &fd->vars[scope_idx];
21853
0
        if (vd->var_name == name &&
21854
0
            (vd->is_lexical || (vd->var_kind == JS_VAR_CATCH &&
21855
0
                                check_catch_var)))
21856
0
            return scope_idx;
21857
0
        scope_idx = vd->scope_next;
21858
0
    }
21859
21860
0
    if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_GLOBAL) {
21861
0
        if (find_lexical_global_var(fd, name))
21862
0
            return GLOBAL_VAR_OFFSET;
21863
0
    }
21864
0
    return -1;
21865
0
}
21866
21867
78
static int push_scope(JSParseState *s) {
21868
78
    if (s->cur_func) {
21869
78
        JSFunctionDef *fd = s->cur_func;
21870
78
        int scope = fd->scope_count;
21871
        /* XXX: should check for scope overflow */
21872
78
        if ((fd->scope_count + 1) > fd->scope_size) {
21873
0
            int new_size;
21874
0
            size_t slack;
21875
0
            JSVarScope *new_buf;
21876
            /* XXX: potential arithmetic overflow */
21877
0
            new_size = max_int(fd->scope_count + 1, fd->scope_size * 3 / 2);
21878
0
            if (fd->scopes == fd->def_scope_array) {
21879
0
                new_buf = js_realloc2(s->ctx, NULL, new_size * sizeof(*fd->scopes), &slack);
21880
0
                if (!new_buf)
21881
0
                    return -1;
21882
0
                memcpy(new_buf, fd->scopes, fd->scope_count * sizeof(*fd->scopes));
21883
0
            } else {
21884
0
                new_buf = js_realloc2(s->ctx, fd->scopes, new_size * sizeof(*fd->scopes), &slack);
21885
0
                if (!new_buf)
21886
0
                    return -1;
21887
0
            }
21888
0
            new_size += slack / sizeof(*new_buf);
21889
0
            fd->scopes = new_buf;
21890
0
            fd->scope_size = new_size;
21891
0
        }
21892
78
        fd->scope_count++;
21893
78
        fd->scopes[scope].parent = fd->scope_level;
21894
78
        fd->scopes[scope].first = fd->scope_first;
21895
78
        emit_op(s, OP_enter_scope);
21896
78
        emit_u16(s, scope);
21897
78
        return fd->scope_level = scope;
21898
78
    }
21899
0
    return 0;
21900
78
}
21901
21902
static int get_first_lexical_var(JSFunctionDef *fd, int scope)
21903
0
{
21904
0
    while (scope >= 0) {
21905
0
        int scope_idx = fd->scopes[scope].first;
21906
0
        if (scope_idx >= 0)
21907
0
            return scope_idx;
21908
0
        scope = fd->scopes[scope].parent;
21909
0
    }
21910
0
    return -1;
21911
0
}
21912
21913
0
static void pop_scope(JSParseState *s) {
21914
0
    if (s->cur_func) {
21915
        /* disable scoped variables */
21916
0
        JSFunctionDef *fd = s->cur_func;
21917
0
        int scope = fd->scope_level;
21918
0
        emit_op(s, OP_leave_scope);
21919
0
        emit_u16(s, scope);
21920
0
        fd->scope_level = fd->scopes[scope].parent;
21921
0
        fd->scope_first = get_first_lexical_var(fd, fd->scope_level);
21922
0
    }
21923
0
}
21924
21925
static void close_scopes(JSParseState *s, int scope, int scope_stop)
21926
0
{
21927
0
    while (scope > scope_stop) {
21928
0
        emit_op(s, OP_leave_scope);
21929
0
        emit_u16(s, scope);
21930
0
        scope = s->cur_func->scopes[scope].parent;
21931
0
    }
21932
0
}
21933
21934
/* return the variable index or -1 if error */
21935
static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21936
36
{
21937
36
    JSVarDef *vd;
21938
21939
    /* the local variable indexes are currently stored on 16 bits */
21940
36
    if (fd->var_count >= JS_MAX_LOCAL_VARS) {
21941
0
        JS_ThrowInternalError(ctx, "too many local variables");
21942
0
        return -1;
21943
0
    }
21944
36
    if (js_resize_array(ctx, (void **)&fd->vars, sizeof(fd->vars[0]),
21945
36
                        &fd->var_size, fd->var_count + 1))
21946
0
        return -1;
21947
36
    vd = &fd->vars[fd->var_count++];
21948
36
    memset(vd, 0, sizeof(*vd));
21949
36
    vd->var_name = JS_DupAtom(ctx, name);
21950
36
    vd->func_pool_idx = -1;
21951
36
    return fd->var_count - 1;
21952
36
}
21953
21954
static int add_scope_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
21955
                         JSVarKindEnum var_kind)
21956
0
{
21957
0
    int idx = add_var(ctx, fd, name);
21958
0
    if (idx >= 0) {
21959
0
        JSVarDef *vd = &fd->vars[idx];
21960
0
        vd->var_kind = var_kind;
21961
0
        vd->scope_level = fd->scope_level;
21962
0
        vd->scope_next = fd->scope_first;
21963
0
        fd->scopes[fd->scope_level].first = idx;
21964
0
        fd->scope_first = idx;
21965
0
    }
21966
0
    return idx;
21967
0
}
21968
21969
static int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21970
0
{
21971
0
    int idx = fd->func_var_idx;
21972
0
    if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) {
21973
0
        fd->func_var_idx = idx;
21974
0
        fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME;
21975
0
        if (fd->js_mode & JS_MODE_STRICT)
21976
0
            fd->vars[idx].is_const = TRUE;
21977
0
    }
21978
0
    return idx;
21979
0
}
21980
21981
static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd)
21982
0
{
21983
0
    int idx = fd->arguments_var_idx;
21984
0
    if (idx < 0 && (idx = add_var(ctx, fd, JS_ATOM_arguments)) >= 0) {
21985
0
        fd->arguments_var_idx = idx;
21986
0
    }
21987
0
    return idx;
21988
0
}
21989
21990
/* add an argument definition in the argument scope. Only needed when
21991
   "eval()" may be called in the argument scope. Return 0 if OK. */
21992
static int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd)
21993
0
{
21994
0
    int idx;
21995
0
    if (fd->arguments_arg_idx < 0) {
21996
0
        idx = find_var_in_scope(ctx, fd, JS_ATOM_arguments, ARG_SCOPE_INDEX);
21997
0
        if (idx < 0) {
21998
            /* XXX: the scope links are not fully updated. May be an
21999
               issue if there are child scopes of the argument
22000
               scope */
22001
0
            idx = add_var(ctx, fd, JS_ATOM_arguments);
22002
0
            if (idx < 0)
22003
0
                return -1;
22004
0
            fd->vars[idx].scope_next = fd->scopes[ARG_SCOPE_INDEX].first;
22005
0
            fd->scopes[ARG_SCOPE_INDEX].first = idx;
22006
0
            fd->vars[idx].scope_level = ARG_SCOPE_INDEX;
22007
0
            fd->vars[idx].is_lexical = TRUE;
22008
22009
0
            fd->arguments_arg_idx = idx;
22010
0
        }
22011
0
    }
22012
0
    return 0;
22013
0
}
22014
22015
static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
22016
0
{
22017
0
    JSVarDef *vd;
22018
22019
    /* the local variable indexes are currently stored on 16 bits */
22020
0
    if (fd->arg_count >= JS_MAX_LOCAL_VARS) {
22021
0
        JS_ThrowInternalError(ctx, "too many arguments");
22022
0
        return -1;
22023
0
    }
22024
0
    if (js_resize_array(ctx, (void **)&fd->args, sizeof(fd->args[0]),
22025
0
                        &fd->arg_size, fd->arg_count + 1))
22026
0
        return -1;
22027
0
    vd = &fd->args[fd->arg_count++];
22028
0
    memset(vd, 0, sizeof(*vd));
22029
0
    vd->var_name = JS_DupAtom(ctx, name);
22030
0
    vd->func_pool_idx = -1;
22031
0
    return fd->arg_count - 1;
22032
0
}
22033
22034
/* add a global variable definition */
22035
static JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s,
22036
                                     JSAtom name)
22037
0
{
22038
0
    JSGlobalVar *hf;
22039
22040
0
    if (js_resize_array(ctx, (void **)&s->global_vars,
22041
0
                        sizeof(s->global_vars[0]),
22042
0
                        &s->global_var_size, s->global_var_count + 1))
22043
0
        return NULL;
22044
0
    hf = &s->global_vars[s->global_var_count++];
22045
0
    hf->cpool_idx = -1;
22046
0
    hf->force_init = FALSE;
22047
0
    hf->is_lexical = FALSE;
22048
0
    hf->is_const = FALSE;
22049
0
    hf->scope_level = s->scope_level;
22050
0
    hf->var_name = JS_DupAtom(ctx, name);
22051
0
    return hf;
22052
0
}
22053
22054
typedef enum {
22055
    JS_VAR_DEF_WITH,
22056
    JS_VAR_DEF_LET,
22057
    JS_VAR_DEF_CONST,
22058
    JS_VAR_DEF_FUNCTION_DECL, /* function declaration */
22059
    JS_VAR_DEF_NEW_FUNCTION_DECL, /* async/generator function declaration */
22060
    JS_VAR_DEF_CATCH,
22061
    JS_VAR_DEF_VAR,
22062
} JSVarDefEnum;
22063
22064
static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
22065
                      JSVarDefEnum var_def_type)
22066
0
{
22067
0
    JSContext *ctx = s->ctx;
22068
0
    JSVarDef *vd;
22069
0
    int idx;
22070
22071
0
    switch (var_def_type) {
22072
0
    case JS_VAR_DEF_WITH:
22073
0
        idx = add_scope_var(ctx, fd, name, JS_VAR_NORMAL);
22074
0
        break;
22075
22076
0
    case JS_VAR_DEF_LET:
22077
0
    case JS_VAR_DEF_CONST:
22078
0
    case JS_VAR_DEF_FUNCTION_DECL:
22079
0
    case JS_VAR_DEF_NEW_FUNCTION_DECL:
22080
0
        idx = find_lexical_decl(ctx, fd, name, fd->scope_first, TRUE);
22081
0
        if (idx >= 0) {
22082
0
            if (idx < GLOBAL_VAR_OFFSET) {
22083
0
                if (fd->vars[idx].scope_level == fd->scope_level) {
22084
                    /* same scope: in non strict mode, functions
22085
                       can be redefined (annex B.3.3.4). */
22086
0
                    if (!(!(fd->js_mode & JS_MODE_STRICT) &&
22087
0
                          var_def_type == JS_VAR_DEF_FUNCTION_DECL &&
22088
0
                          fd->vars[idx].var_kind == JS_VAR_FUNCTION_DECL)) {
22089
0
                        goto redef_lex_error;
22090
0
                    }
22091
0
                } else if (fd->vars[idx].var_kind == JS_VAR_CATCH && (fd->vars[idx].scope_level + 2) == fd->scope_level) {
22092
0
                    goto redef_lex_error;
22093
0
                }
22094
0
            } else {
22095
0
                if (fd->scope_level == fd->body_scope) {
22096
0
                redef_lex_error:
22097
                    /* redefining a scoped var in the same scope: error */
22098
0
                    return js_parse_error(s, "invalid redefinition of lexical identifier");
22099
0
                }
22100
0
            }
22101
0
        }
22102
0
        if (var_def_type != JS_VAR_DEF_FUNCTION_DECL &&
22103
0
            var_def_type != JS_VAR_DEF_NEW_FUNCTION_DECL &&
22104
0
            fd->scope_level == fd->body_scope &&
22105
0
            find_arg(ctx, fd, name) >= 0) {
22106
            /* lexical variable redefines a parameter name */
22107
0
            return js_parse_error(s, "invalid redefinition of parameter name");
22108
0
        }
22109
22110
0
        if (find_var_in_child_scope(ctx, fd, name, fd->scope_level) >= 0) {
22111
0
            return js_parse_error(s, "invalid redefinition of a variable");
22112
0
        }
22113
22114
0
        if (fd->is_global_var) {
22115
0
            JSGlobalVar *hf;
22116
0
            hf = find_global_var(fd, name);
22117
0
            if (hf && is_child_scope(ctx, fd, hf->scope_level,
22118
0
                                     fd->scope_level)) {
22119
0
                return js_parse_error(s, "invalid redefinition of global identifier");
22120
0
            }
22121
0
        }
22122
22123
0
        if (fd->is_eval &&
22124
0
            (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
22125
0
             fd->eval_type == JS_EVAL_TYPE_MODULE) &&
22126
0
            fd->scope_level == fd->body_scope) {
22127
0
            JSGlobalVar *hf;
22128
0
            hf = add_global_var(s->ctx, fd, name);
22129
0
            if (!hf)
22130
0
                return -1;
22131
0
            hf->is_lexical = TRUE;
22132
0
            hf->is_const = (var_def_type == JS_VAR_DEF_CONST);
22133
0
            idx = GLOBAL_VAR_OFFSET;
22134
0
        } else {
22135
0
            JSVarKindEnum var_kind;
22136
0
            if (var_def_type == JS_VAR_DEF_FUNCTION_DECL)
22137
0
                var_kind = JS_VAR_FUNCTION_DECL;
22138
0
            else if (var_def_type == JS_VAR_DEF_NEW_FUNCTION_DECL)
22139
0
                var_kind = JS_VAR_NEW_FUNCTION_DECL;
22140
0
            else
22141
0
                var_kind = JS_VAR_NORMAL;
22142
0
            idx = add_scope_var(ctx, fd, name, var_kind);
22143
0
            if (idx >= 0) {
22144
0
                vd = &fd->vars[idx];
22145
0
                vd->is_lexical = 1;
22146
0
                vd->is_const = (var_def_type == JS_VAR_DEF_CONST);
22147
0
            }
22148
0
        }
22149
0
        break;
22150
22151
0
    case JS_VAR_DEF_CATCH:
22152
0
        idx = add_scope_var(ctx, fd, name, JS_VAR_CATCH);
22153
0
        break;
22154
22155
0
    case JS_VAR_DEF_VAR:
22156
0
        if (find_lexical_decl(ctx, fd, name, fd->scope_first,
22157
0
                              FALSE) >= 0) {
22158
0
       invalid_lexical_redefinition:
22159
            /* error to redefine a var that inside a lexical scope */
22160
0
            return js_parse_error(s, "invalid redefinition of lexical identifier");
22161
0
        }
22162
0
        if (fd->is_global_var) {
22163
0
            JSGlobalVar *hf;
22164
0
            hf = find_global_var(fd, name);
22165
0
            if (hf && hf->is_lexical && hf->scope_level == fd->scope_level &&
22166
0
                fd->eval_type == JS_EVAL_TYPE_MODULE) {
22167
0
                goto invalid_lexical_redefinition;
22168
0
            }
22169
0
            hf = add_global_var(s->ctx, fd, name);
22170
0
            if (!hf)
22171
0
                return -1;
22172
0
            idx = GLOBAL_VAR_OFFSET;
22173
0
        } else {
22174
            /* if the variable already exists, don't add it again  */
22175
0
            idx = find_var(ctx, fd, name);
22176
0
            if (idx >= 0)
22177
0
                break;
22178
0
            idx = add_var(ctx, fd, name);
22179
0
            if (idx >= 0) {
22180
0
                if (name == JS_ATOM_arguments && fd->has_arguments_binding)
22181
0
                    fd->arguments_var_idx = idx;
22182
0
                fd->vars[idx].scope_next = fd->scope_level;
22183
0
            }
22184
0
        }
22185
0
        break;
22186
0
    default:
22187
0
        abort();
22188
0
    }
22189
0
    return idx;
22190
0
}
22191
22192
/* add a private field variable in the current scope */
22193
static int add_private_class_field(JSParseState *s, JSFunctionDef *fd,
22194
                                   JSAtom name, JSVarKindEnum var_kind, BOOL is_static)
22195
0
{
22196
0
    JSContext *ctx = s->ctx;
22197
0
    JSVarDef *vd;
22198
0
    int idx;
22199
22200
0
    idx = add_scope_var(ctx, fd, name, var_kind);
22201
0
    if (idx < 0)
22202
0
        return idx;
22203
0
    vd = &fd->vars[idx];
22204
0
    vd->is_lexical = 1;
22205
0
    vd->is_const = 1;
22206
0
    vd->is_static_private = is_static;
22207
0
    return idx;
22208
0
}
22209
22210
static __exception int js_parse_expr(JSParseState *s);
22211
static __exception int js_parse_function_decl(JSParseState *s,
22212
                                              JSParseFunctionEnum func_type,
22213
                                              JSFunctionKindEnum func_kind,
22214
                                              JSAtom func_name, const uint8_t *ptr,
22215
                                              int start_line);
22216
static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s);
22217
static __exception int js_parse_function_decl2(JSParseState *s,
22218
                                               JSParseFunctionEnum func_type,
22219
                                               JSFunctionKindEnum func_kind,
22220
                                               JSAtom func_name,
22221
                                               const uint8_t *ptr,
22222
                                               int function_line_num,
22223
                                               JSParseExportEnum export_flag,
22224
                                               JSFunctionDef **pfd);
22225
static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);
22226
static __exception int js_parse_assign_expr(JSParseState *s);
22227
static __exception int js_parse_unary(JSParseState *s, int parse_flags);
22228
static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
22229
                             JSAtom label_name,
22230
                             int label_break, int label_cont,
22231
                             int drop_count);
22232
static void pop_break_entry(JSFunctionDef *fd);
22233
static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
22234
                                       JSAtom local_name, JSAtom export_name,
22235
                                       JSExportTypeEnum export_type);
22236
22237
/* Note: all the fields are already sealed except length */
22238
static int seal_template_obj(JSContext *ctx, JSValueConst obj)
22239
0
{
22240
0
    JSObject *p;
22241
0
    JSShapeProperty *prs;
22242
22243
0
    p = JS_VALUE_GET_OBJ(obj);
22244
0
    prs = find_own_property1(p, JS_ATOM_length);
22245
0
    if (prs) {
22246
0
        if (js_update_property_flags(ctx, p, &prs,
22247
0
                                     prs->flags & ~(JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)))
22248
0
            return -1;
22249
0
    }
22250
0
    p->extensible = FALSE;
22251
0
    return 0;
22252
0
}
22253
22254
static __exception int js_parse_template(JSParseState *s, int call, int *argc)
22255
0
{
22256
0
    JSContext *ctx = s->ctx;
22257
0
    JSValue raw_array, template_object;
22258
0
    JSToken cooked;
22259
0
    int depth, ret;
22260
22261
0
    raw_array = JS_UNDEFINED; /* avoid warning */
22262
0
    template_object = JS_UNDEFINED; /* avoid warning */
22263
0
    if (call) {
22264
        /* Create a template object: an array of cooked strings */
22265
        /* Create an array of raw strings and store it to the raw property */
22266
0
        template_object = JS_NewArray(ctx);
22267
0
        if (JS_IsException(template_object))
22268
0
            return -1;
22269
        //        pool_idx = s->cur_func->cpool_count;
22270
0
        ret = emit_push_const(s, template_object, 0);
22271
0
        JS_FreeValue(ctx, template_object);
22272
0
        if (ret)
22273
0
            return -1;
22274
0
        raw_array = JS_NewArray(ctx);
22275
0
        if (JS_IsException(raw_array))
22276
0
            return -1;
22277
0
        if (JS_DefinePropertyValue(ctx, template_object, JS_ATOM_raw,
22278
0
                                   raw_array, JS_PROP_THROW) < 0) {
22279
0
            return -1;
22280
0
        }
22281
0
    }
22282
22283
0
    depth = 0;
22284
0
    while (s->token.val == TOK_TEMPLATE) {
22285
0
        const uint8_t *p = s->token.ptr + 1;
22286
0
        cooked = s->token;
22287
0
        if (call) {
22288
0
            if (JS_DefinePropertyValueUint32(ctx, raw_array, depth,
22289
0
                                             JS_DupValue(ctx, s->token.u.str.str),
22290
0
                                             JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
22291
0
                return -1;
22292
0
            }
22293
            /* re-parse the string with escape sequences but do not throw a
22294
               syntax error if it contains invalid sequences
22295
             */
22296
0
            if (js_parse_string(s, '`', FALSE, p, &cooked, &p)) {
22297
0
                cooked.u.str.str = JS_UNDEFINED;
22298
0
            }
22299
0
            if (JS_DefinePropertyValueUint32(ctx, template_object, depth,
22300
0
                                             cooked.u.str.str,
22301
0
                                             JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
22302
0
                return -1;
22303
0
            }
22304
0
        } else {
22305
0
            JSString *str;
22306
            /* re-parse the string with escape sequences and throw a
22307
               syntax error if it contains invalid sequences
22308
             */
22309
0
            JS_FreeValue(ctx, s->token.u.str.str);
22310
0
            s->token.u.str.str = JS_UNDEFINED;
22311
0
            if (js_parse_string(s, '`', TRUE, p, &cooked, &p))
22312
0
                return -1;
22313
0
            str = JS_VALUE_GET_STRING(cooked.u.str.str);
22314
0
            if (str->len != 0 || depth == 0) {
22315
0
                ret = emit_push_const(s, cooked.u.str.str, 1);
22316
0
                JS_FreeValue(s->ctx, cooked.u.str.str);
22317
0
                if (ret)
22318
0
                    return -1;
22319
0
                if (depth == 0) {
22320
0
                    if (s->token.u.str.sep == '`')
22321
0
                        goto done1;
22322
0
                    emit_op(s, OP_get_field2);
22323
0
                    emit_atom(s, JS_ATOM_concat);
22324
0
                }
22325
0
                depth++;
22326
0
            } else {
22327
0
                JS_FreeValue(s->ctx, cooked.u.str.str);
22328
0
            }
22329
0
        }
22330
0
        if (s->token.u.str.sep == '`')
22331
0
            goto done;
22332
0
        if (next_token(s))
22333
0
            return -1;
22334
0
        if (js_parse_expr(s))
22335
0
            return -1;
22336
0
        depth++;
22337
0
        if (s->token.val != '}') {
22338
0
            return js_parse_error(s, "expected '}' after template expression");
22339
0
        }
22340
        /* XXX: should convert to string at this stage? */
22341
0
        free_token(s, &s->token);
22342
        /* Resume TOK_TEMPLATE parsing (s->token.line_num and
22343
         * s->token.ptr are OK) */
22344
0
        s->got_lf = FALSE;
22345
0
        s->last_line_num = s->token.line_num;
22346
0
        if (js_parse_template_part(s, s->buf_ptr))
22347
0
            return -1;
22348
0
    }
22349
0
    return js_parse_expect(s, TOK_TEMPLATE);
22350
22351
0
 done:
22352
0
    if (call) {
22353
        /* Seal the objects */
22354
0
        seal_template_obj(ctx, raw_array);
22355
0
        seal_template_obj(ctx, template_object);
22356
0
        *argc = depth + 1;
22357
0
    } else {
22358
0
        emit_op(s, OP_call_method);
22359
0
        emit_u16(s, depth - 1);
22360
0
    }
22361
0
 done1:
22362
0
    return next_token(s);
22363
0
}
22364
22365
22366
0
#define PROP_TYPE_IDENT 0
22367
0
#define PROP_TYPE_VAR   1
22368
0
#define PROP_TYPE_GET   2
22369
0
#define PROP_TYPE_SET   3
22370
0
#define PROP_TYPE_STAR  4
22371
0
#define PROP_TYPE_ASYNC 5
22372
0
#define PROP_TYPE_ASYNC_STAR 6
22373
22374
0
#define PROP_TYPE_PRIVATE (1 << 4)
22375
22376
static BOOL token_is_ident(int tok)
22377
156
{
22378
    /* Accept keywords and reserved words as property names */
22379
156
    return (tok == TOK_IDENT ||
22380
156
            (tok >= TOK_FIRST_KEYWORD &&
22381
0
             tok <= TOK_LAST_KEYWORD));
22382
156
}
22383
22384
/* if the property is an expression, name = JS_ATOM_NULL */
22385
static int __exception js_parse_property_name(JSParseState *s,
22386
                                              JSAtom *pname,
22387
                                              BOOL allow_method, BOOL allow_var,
22388
                                              BOOL allow_private)
22389
0
{
22390
0
    int is_private = 0;
22391
0
    BOOL is_non_reserved_ident;
22392
0
    JSAtom name;
22393
0
    int prop_type;
22394
22395
0
    prop_type = PROP_TYPE_IDENT;
22396
0
    if (allow_method) {
22397
0
        if (token_is_pseudo_keyword(s, JS_ATOM_get)
22398
0
        ||  token_is_pseudo_keyword(s, JS_ATOM_set)) {
22399
            /* get x(), set x() */
22400
0
            name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
22401
0
            if (next_token(s))
22402
0
                goto fail1;
22403
0
            if (s->token.val == ':' || s->token.val == ',' ||
22404
0
                s->token.val == '}' || s->token.val == '(' ||
22405
0
                s->token.val == '=') {
22406
0
                is_non_reserved_ident = TRUE;
22407
0
                goto ident_found;
22408
0
            }
22409
0
            prop_type = PROP_TYPE_GET + (name == JS_ATOM_set);
22410
0
            JS_FreeAtom(s->ctx, name);
22411
0
        } else if (s->token.val == '*') {
22412
0
            if (next_token(s))
22413
0
                goto fail;
22414
0
            prop_type = PROP_TYPE_STAR;
22415
0
        } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
22416
0
                   peek_token(s, TRUE) != '\n') {
22417
0
            name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
22418
0
            if (next_token(s))
22419
0
                goto fail1;
22420
0
            if (s->token.val == ':' || s->token.val == ',' ||
22421
0
                s->token.val == '}' || s->token.val == '(' ||
22422
0
                s->token.val == '=') {
22423
0
                is_non_reserved_ident = TRUE;
22424
0
                goto ident_found;
22425
0
            }
22426
0
            JS_FreeAtom(s->ctx, name);
22427
0
            if (s->token.val == '*') {
22428
0
                if (next_token(s))
22429
0
                    goto fail;
22430
0
                prop_type = PROP_TYPE_ASYNC_STAR;
22431
0
            } else {
22432
0
                prop_type = PROP_TYPE_ASYNC;
22433
0
            }
22434
0
        }
22435
0
    }
22436
22437
0
    if (token_is_ident(s->token.val)) {
22438
        /* variable can only be a non-reserved identifier */
22439
0
        is_non_reserved_ident =
22440
0
            (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved);
22441
        /* keywords and reserved words have a valid atom */
22442
0
        name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
22443
0
        if (next_token(s))
22444
0
            goto fail1;
22445
0
    ident_found:
22446
0
        if (is_non_reserved_ident &&
22447
0
            prop_type == PROP_TYPE_IDENT && allow_var) {
22448
0
            if (!(s->token.val == ':' ||
22449
0
                  (s->token.val == '(' && allow_method))) {
22450
0
                prop_type = PROP_TYPE_VAR;
22451
0
            }
22452
0
        }
22453
0
    } else if (s->token.val == TOK_STRING) {
22454
0
        name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
22455
0
        if (name == JS_ATOM_NULL)
22456
0
            goto fail;
22457
0
        if (next_token(s))
22458
0
            goto fail1;
22459
0
    } else if (s->token.val == TOK_NUMBER) {
22460
0
        JSValue val;
22461
0
        val = s->token.u.num.val;
22462
0
#ifdef CONFIG_BIGNUM
22463
0
        if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
22464
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
22465
0
            val = s->ctx->rt->bigfloat_ops.
22466
0
                mul_pow10_to_float64(s->ctx, &p->num,
22467
0
                                     s->token.u.num.exponent);
22468
0
            if (JS_IsException(val))
22469
0
                goto fail;
22470
0
            name = JS_ValueToAtom(s->ctx, val);
22471
0
            JS_FreeValue(s->ctx, val);
22472
0
        } else
22473
0
#endif
22474
0
        {
22475
0
            name = JS_ValueToAtom(s->ctx, val);
22476
0
        }
22477
0
        if (name == JS_ATOM_NULL)
22478
0
            goto fail;
22479
0
        if (next_token(s))
22480
0
            goto fail1;
22481
0
    } else if (s->token.val == '[') {
22482
0
        if (next_token(s))
22483
0
            goto fail;
22484
0
        if (js_parse_expr(s))
22485
0
            goto fail;
22486
0
        if (js_parse_expect(s, ']'))
22487
0
            goto fail;
22488
0
        name = JS_ATOM_NULL;
22489
0
    } else if (s->token.val == TOK_PRIVATE_NAME && allow_private) {
22490
0
        name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
22491
0
        if (next_token(s))
22492
0
            goto fail1;
22493
0
        is_private = PROP_TYPE_PRIVATE;
22494
0
    } else {
22495
0
        goto invalid_prop;
22496
0
    }
22497
0
    if (prop_type != PROP_TYPE_IDENT && prop_type != PROP_TYPE_VAR &&
22498
0
        s->token.val != '(') {
22499
0
        JS_FreeAtom(s->ctx, name);
22500
0
    invalid_prop:
22501
0
        js_parse_error(s, "invalid property name");
22502
0
        goto fail;
22503
0
    }
22504
0
    *pname = name;
22505
0
    return prop_type | is_private;
22506
0
 fail1:
22507
0
    JS_FreeAtom(s->ctx, name);
22508
0
 fail:
22509
0
    *pname = JS_ATOM_NULL;
22510
0
    return -1;
22511
0
}
22512
22513
typedef struct JSParsePos {
22514
    int last_line_num;
22515
    int line_num;
22516
    BOOL got_lf;
22517
    const uint8_t *ptr;
22518
} JSParsePos;
22519
22520
static int js_parse_get_pos(JSParseState *s, JSParsePos *sp)
22521
32
{
22522
32
    sp->last_line_num = s->last_line_num;
22523
32
    sp->line_num = s->token.line_num;
22524
32
    sp->ptr = s->token.ptr;
22525
32
    sp->got_lf = s->got_lf;
22526
32
    return 0;
22527
32
}
22528
22529
static __exception int js_parse_seek_token(JSParseState *s, const JSParsePos *sp)
22530
32
{
22531
32
    s->token.line_num = sp->last_line_num;
22532
32
    s->line_num = sp->line_num;
22533
32
    s->buf_ptr = sp->ptr;
22534
32
    s->got_lf = sp->got_lf;
22535
32
    return next_token(s);
22536
32
}
22537
22538
/* return TRUE if a regexp literal is allowed after this token */
22539
static BOOL is_regexp_allowed(int tok)
22540
0
{
22541
0
    switch (tok) {
22542
0
    case TOK_NUMBER:
22543
0
    case TOK_STRING:
22544
0
    case TOK_REGEXP:
22545
0
    case TOK_DEC:
22546
0
    case TOK_INC:
22547
0
    case TOK_NULL:
22548
0
    case TOK_FALSE:
22549
0
    case TOK_TRUE:
22550
0
    case TOK_THIS:
22551
0
    case ')':
22552
0
    case ']':
22553
0
    case '}': /* XXX: regexp may occur after */
22554
0
    case TOK_IDENT:
22555
0
        return FALSE;
22556
0
    default:
22557
0
        return TRUE;
22558
0
    }
22559
0
}
22560
22561
0
#define SKIP_HAS_SEMI       (1 << 0)
22562
0
#define SKIP_HAS_ELLIPSIS   (1 << 1)
22563
0
#define SKIP_HAS_ASSIGNMENT (1 << 2)
22564
22565
/* XXX: improve speed with early bailout */
22566
/* XXX: no longer works if regexps are present. Could use previous
22567
   regexp parsing heuristics to handle most cases */
22568
static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_terminator)
22569
21
{
22570
21
    char state[256];
22571
21
    size_t level = 0;
22572
21
    JSParsePos pos;
22573
21
    int last_tok, tok = TOK_EOF;
22574
21
    int c, tok_len, bits = 0;
22575
22576
    /* protect from underflow */
22577
21
    state[level++] = 0;
22578
22579
21
    js_parse_get_pos(s, &pos);
22580
21
    last_tok = 0;
22581
11.2M
    for (;;) {
22582
11.2M
        switch(s->token.val) {
22583
1
        case '(':
22584
31
        case '[':
22585
31
        case '{':
22586
31
            if (level >= sizeof(state))
22587
0
                goto done;
22588
31
            state[level++] = s->token.val;
22589
31
            break;
22590
0
        case ')':
22591
0
            if (state[--level] != '(')
22592
0
                goto done;
22593
0
            break;
22594
25
        case ']':
22595
25
            if (state[--level] != '[')
22596
0
                goto done;
22597
25
            break;
22598
25
        case '}':
22599
0
            c = state[--level];
22600
0
            if (c == '`') {
22601
                /* continue the parsing of the template */
22602
0
                free_token(s, &s->token);
22603
                /* Resume TOK_TEMPLATE parsing (s->token.line_num and
22604
                 * s->token.ptr are OK) */
22605
0
                s->got_lf = FALSE;
22606
0
                s->last_line_num = s->token.line_num;
22607
0
                if (js_parse_template_part(s, s->buf_ptr))
22608
0
                    goto done;
22609
0
                goto handle_template;
22610
0
            } else if (c != '{') {
22611
0
                goto done;
22612
0
            }
22613
0
            break;
22614
0
        case TOK_TEMPLATE:
22615
0
        handle_template:
22616
0
            if (s->token.u.str.sep != '`') {
22617
                /* '${' inside the template : closing '}' and continue
22618
                   parsing the template */
22619
0
                if (level >= sizeof(state))
22620
0
                    goto done;
22621
0
                state[level++] = '`';
22622
0
            }
22623
0
            break;
22624
3
        case TOK_EOF:
22625
3
            goto done;
22626
0
        case ';':
22627
0
            if (level == 2) {
22628
0
                bits |= SKIP_HAS_SEMI;
22629
0
            }
22630
0
            break;
22631
0
        case TOK_ELLIPSIS:
22632
0
            if (level == 2) {
22633
0
                bits |= SKIP_HAS_ELLIPSIS;
22634
0
            }
22635
0
            break;
22636
0
        case '=':
22637
0
            bits |= SKIP_HAS_ASSIGNMENT;
22638
0
            break;
22639
22640
0
        case TOK_DIV_ASSIGN:
22641
0
            tok_len = 2;
22642
0
            goto parse_regexp;
22643
0
        case '/':
22644
0
            tok_len = 1;
22645
0
        parse_regexp:
22646
0
            if (is_regexp_allowed(last_tok)) {
22647
0
                s->buf_ptr -= tok_len;
22648
0
                if (js_parse_regexp(s)) {
22649
                    /* XXX: should clear the exception */
22650
0
                    goto done;
22651
0
                }
22652
0
            }
22653
0
            break;
22654
11.2M
        }
22655
        /* last_tok is only used to recognize regexps */
22656
11.2M
        if (s->token.val == TOK_IDENT &&
22657
11.2M
            (token_is_pseudo_keyword(s, JS_ATOM_of) ||
22658
4
             token_is_pseudo_keyword(s, JS_ATOM_yield))) {
22659
0
            last_tok = TOK_OF;
22660
11.2M
        } else {
22661
11.2M
            last_tok = s->token.val;
22662
11.2M
        }
22663
11.2M
        if (next_token(s)) {
22664
            /* XXX: should clear the exception generated by next_token() */
22665
2
            break;
22666
2
        }
22667
11.2M
        if (level <= 1) {
22668
16
            tok = s->token.val;
22669
16
            if (token_is_pseudo_keyword(s, JS_ATOM_of))
22670
0
                tok = TOK_OF;
22671
16
            if (no_line_terminator && s->last_line_num != s->token.line_num)
22672
0
                tok = '\n';
22673
16
            break;
22674
16
        }
22675
11.2M
    }
22676
21
 done:
22677
21
    if (pbits) {
22678
21
        *pbits = bits;
22679
21
    }
22680
21
    if (js_parse_seek_token(s, &pos))
22681
0
        return -1;
22682
21
    return tok;
22683
21
}
22684
22685
static void set_object_name(JSParseState *s, JSAtom name)
22686
1
{
22687
1
    JSFunctionDef *fd = s->cur_func;
22688
1
    int opcode;
22689
22690
1
    opcode = get_prev_opcode(fd);
22691
1
    if (opcode == OP_set_name) {
22692
        /* XXX: should free atom after OP_set_name? */
22693
0
        fd->byte_code.size = fd->last_opcode_pos;
22694
0
        fd->last_opcode_pos = -1;
22695
0
        emit_op(s, OP_set_name);
22696
0
        emit_atom(s, name);
22697
1
    } else if (opcode == OP_set_class_name) {
22698
0
        int define_class_pos;
22699
0
        JSAtom atom;
22700
0
        define_class_pos = fd->last_opcode_pos + 1 -
22701
0
            get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
22702
0
        assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
22703
        /* for consistency we free the previous atom which is
22704
           JS_ATOM_empty_string */
22705
0
        atom = get_u32(fd->byte_code.buf + define_class_pos + 1);
22706
0
        JS_FreeAtom(s->ctx, atom);
22707
0
        put_u32(fd->byte_code.buf + define_class_pos + 1,
22708
0
                JS_DupAtom(s->ctx, name));
22709
0
        fd->last_opcode_pos = -1;
22710
0
    }
22711
1
}
22712
22713
static void set_object_name_computed(JSParseState *s)
22714
0
{
22715
0
    JSFunctionDef *fd = s->cur_func;
22716
0
    int opcode;
22717
22718
0
    opcode = get_prev_opcode(fd);
22719
0
    if (opcode == OP_set_name) {
22720
        /* XXX: should free atom after OP_set_name? */
22721
0
        fd->byte_code.size = fd->last_opcode_pos;
22722
0
        fd->last_opcode_pos = -1;
22723
0
        emit_op(s, OP_set_name_computed);
22724
0
    } else if (opcode == OP_set_class_name) {
22725
0
        int define_class_pos;
22726
0
        define_class_pos = fd->last_opcode_pos + 1 -
22727
0
            get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
22728
0
        assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
22729
0
        fd->byte_code.buf[define_class_pos] = OP_define_class_computed;
22730
0
        fd->last_opcode_pos = -1;
22731
0
    }
22732
0
}
22733
22734
static __exception int js_parse_object_literal(JSParseState *s)
22735
0
{
22736
0
    JSAtom name = JS_ATOM_NULL;
22737
0
    const uint8_t *start_ptr;
22738
0
    int start_line, prop_type;
22739
0
    BOOL has_proto;
22740
22741
0
    if (next_token(s))
22742
0
        goto fail;
22743
    /* XXX: add an initial length that will be patched back */
22744
0
    emit_op(s, OP_object);
22745
0
    has_proto = FALSE;
22746
0
    while (s->token.val != '}') {
22747
        /* specific case for getter/setter */
22748
0
        start_ptr = s->token.ptr;
22749
0
        start_line = s->token.line_num;
22750
22751
0
        if (s->token.val == TOK_ELLIPSIS) {
22752
0
            if (next_token(s))
22753
0
                return -1;
22754
0
            if (js_parse_assign_expr(s))
22755
0
                return -1;
22756
0
            emit_op(s, OP_null);  /* dummy excludeList */
22757
0
            emit_op(s, OP_copy_data_properties);
22758
0
            emit_u8(s, 2 | (1 << 2) | (0 << 5));
22759
0
            emit_op(s, OP_drop); /* pop excludeList */
22760
0
            emit_op(s, OP_drop); /* pop src object */
22761
0
            goto next;
22762
0
        }
22763
22764
0
        prop_type = js_parse_property_name(s, &name, TRUE, TRUE, FALSE);
22765
0
        if (prop_type < 0)
22766
0
            goto fail;
22767
22768
0
        if (prop_type == PROP_TYPE_VAR) {
22769
            /* shortcut for x: x */
22770
0
            emit_op(s, OP_scope_get_var);
22771
0
            emit_atom(s, name);
22772
0
            emit_u16(s, s->cur_func->scope_level);
22773
0
            emit_op(s, OP_define_field);
22774
0
            emit_atom(s, name);
22775
0
        } else if (s->token.val == '(') {
22776
0
            BOOL is_getset = (prop_type == PROP_TYPE_GET ||
22777
0
                              prop_type == PROP_TYPE_SET);
22778
0
            JSParseFunctionEnum func_type;
22779
0
            JSFunctionKindEnum func_kind;
22780
0
            int op_flags;
22781
22782
0
            func_kind = JS_FUNC_NORMAL;
22783
0
            if (is_getset) {
22784
0
                func_type = JS_PARSE_FUNC_GETTER + prop_type - PROP_TYPE_GET;
22785
0
            } else {
22786
0
                func_type = JS_PARSE_FUNC_METHOD;
22787
0
                if (prop_type == PROP_TYPE_STAR)
22788
0
                    func_kind = JS_FUNC_GENERATOR;
22789
0
                else if (prop_type == PROP_TYPE_ASYNC)
22790
0
                    func_kind = JS_FUNC_ASYNC;
22791
0
                else if (prop_type == PROP_TYPE_ASYNC_STAR)
22792
0
                    func_kind = JS_FUNC_ASYNC_GENERATOR;
22793
0
            }
22794
0
            if (js_parse_function_decl(s, func_type, func_kind, JS_ATOM_NULL,
22795
0
                                       start_ptr, start_line))
22796
0
                goto fail;
22797
0
            if (name == JS_ATOM_NULL) {
22798
0
                emit_op(s, OP_define_method_computed);
22799
0
            } else {
22800
0
                emit_op(s, OP_define_method);
22801
0
                emit_atom(s, name);
22802
0
            }
22803
0
            if (is_getset) {
22804
0
                op_flags = OP_DEFINE_METHOD_GETTER +
22805
0
                    prop_type - PROP_TYPE_GET;
22806
0
            } else {
22807
0
                op_flags = OP_DEFINE_METHOD_METHOD;
22808
0
            }
22809
0
            emit_u8(s, op_flags | OP_DEFINE_METHOD_ENUMERABLE);
22810
0
        } else {
22811
0
            if (js_parse_expect(s, ':'))
22812
0
                goto fail;
22813
0
            if (js_parse_assign_expr(s))
22814
0
                goto fail;
22815
0
            if (name == JS_ATOM_NULL) {
22816
0
                set_object_name_computed(s);
22817
0
                emit_op(s, OP_define_array_el);
22818
0
                emit_op(s, OP_drop);
22819
0
            } else if (name == JS_ATOM___proto__) {
22820
0
                if (has_proto) {
22821
0
                    js_parse_error(s, "duplicate __proto__ property name");
22822
0
                    goto fail;
22823
0
                }
22824
0
                emit_op(s, OP_set_proto);
22825
0
                has_proto = TRUE;
22826
0
            } else {
22827
0
                set_object_name(s, name);
22828
0
                emit_op(s, OP_define_field);
22829
0
                emit_atom(s, name);
22830
0
            }
22831
0
        }
22832
0
        JS_FreeAtom(s->ctx, name);
22833
0
    next:
22834
0
        name = JS_ATOM_NULL;
22835
0
        if (s->token.val != ',')
22836
0
            break;
22837
0
        if (next_token(s))
22838
0
            goto fail;
22839
0
    }
22840
0
    if (js_parse_expect(s, '}'))
22841
0
        goto fail;
22842
0
    return 0;
22843
0
 fail:
22844
0
    JS_FreeAtom(s->ctx, name);
22845
0
    return -1;
22846
0
}
22847
22848
/* allow the 'in' binary operator */
22849
5.52M
#define PF_IN_ACCEPTED  (1 << 0)
22850
/* allow function calls parsing in js_parse_postfix_expr() */
22851
11.0M
#define PF_POSTFIX_CALL (1 << 1)
22852
/* allow the exponentiation operator in js_parse_unary() */
22853
11.0M
#define PF_POW_ALLOWED  (1 << 2)
22854
/* forbid the exponentiation operator in js_parse_unary() */
22855
5.52M
#define PF_POW_FORBIDDEN (1 << 3)
22856
22857
static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
22858
22859
static __exception int js_parse_left_hand_side_expr(JSParseState *s)
22860
0
{
22861
0
    return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
22862
0
}
22863
22864
/* XXX: could generate specific bytecode */
22865
static __exception int js_parse_class_default_ctor(JSParseState *s,
22866
                                                   BOOL has_super,
22867
                                                   JSFunctionDef **pfd)
22868
0
{
22869
0
    JSParsePos pos;
22870
0
    const char *str;
22871
0
    int ret, line_num;
22872
0
    JSParseFunctionEnum func_type;
22873
0
    const uint8_t *saved_buf_end;
22874
22875
0
    js_parse_get_pos(s, &pos);
22876
0
    if (has_super) {
22877
        /* spec change: no argument evaluation */
22878
0
        str = "(){super(...arguments);}";
22879
0
        func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
22880
0
    } else {
22881
0
        str = "(){}";
22882
0
        func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
22883
0
    }
22884
0
    line_num = s->token.line_num;
22885
0
    saved_buf_end = s->buf_end;
22886
0
    s->buf_ptr = (uint8_t *)str;
22887
0
    s->buf_end = (uint8_t *)(str + strlen(str));
22888
0
    ret = next_token(s);
22889
0
    if (!ret) {
22890
0
        ret = js_parse_function_decl2(s, func_type, JS_FUNC_NORMAL,
22891
0
                                      JS_ATOM_NULL, (uint8_t *)str,
22892
0
                                      line_num, JS_PARSE_EXPORT_NONE, pfd);
22893
0
    }
22894
0
    s->buf_end = saved_buf_end;
22895
0
    ret |= js_parse_seek_token(s, &pos);
22896
0
    return ret;
22897
0
}
22898
22899
/* find field in the current scope */
22900
static int find_private_class_field(JSContext *ctx, JSFunctionDef *fd,
22901
                                    JSAtom name, int scope_level)
22902
0
{
22903
0
    int idx;
22904
0
    idx = fd->scopes[scope_level].first;
22905
0
    while (idx != -1) {
22906
0
        if (fd->vars[idx].scope_level != scope_level)
22907
0
            break;
22908
0
        if (fd->vars[idx].var_name == name)
22909
0
            return idx;
22910
0
        idx = fd->vars[idx].scope_next;
22911
0
    }
22912
0
    return -1;
22913
0
}
22914
22915
/* initialize the class fields, called by the constructor. Note:
22916
   super() can be called in an arrow function, so <this> and
22917
   <class_fields_init> can be variable references */
22918
static void emit_class_field_init(JSParseState *s)
22919
0
{
22920
0
    int label_next;
22921
22922
0
    emit_op(s, OP_scope_get_var);
22923
0
    emit_atom(s, JS_ATOM_class_fields_init);
22924
0
    emit_u16(s, s->cur_func->scope_level);
22925
22926
    /* no need to call the class field initializer if not defined */
22927
0
    emit_op(s, OP_dup);
22928
0
    label_next = emit_goto(s, OP_if_false, -1);
22929
22930
0
    emit_op(s, OP_scope_get_var);
22931
0
    emit_atom(s, JS_ATOM_this);
22932
0
    emit_u16(s, 0);
22933
22934
0
    emit_op(s, OP_swap);
22935
22936
0
    emit_op(s, OP_call_method);
22937
0
    emit_u16(s, 0);
22938
22939
0
    emit_label(s, label_next);
22940
0
    emit_op(s, OP_drop);
22941
0
}
22942
22943
/* build a private setter function name from the private getter name */
22944
static JSAtom get_private_setter_name(JSContext *ctx, JSAtom name)
22945
0
{
22946
0
    return js_atom_concat_str(ctx, name, "<set>");
22947
0
}
22948
22949
typedef struct {
22950
    JSFunctionDef *fields_init_fd;
22951
    int computed_fields_count;
22952
    BOOL need_brand;
22953
    int brand_push_pos;
22954
    BOOL is_static;
22955
} ClassFieldsDef;
22956
22957
static __exception int emit_class_init_start(JSParseState *s,
22958
                                             ClassFieldsDef *cf)
22959
0
{
22960
0
    int label_add_brand;
22961
22962
0
    cf->fields_init_fd = js_parse_function_class_fields_init(s);
22963
0
    if (!cf->fields_init_fd)
22964
0
        return -1;
22965
22966
0
    s->cur_func = cf->fields_init_fd;
22967
22968
0
    if (!cf->is_static) {
22969
        /* add the brand to the newly created instance */
22970
        /* XXX: would be better to add the code only if needed, maybe in a
22971
           later pass */
22972
0
        emit_op(s, OP_push_false); /* will be patched later */
22973
0
        cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos;
22974
0
        label_add_brand = emit_goto(s, OP_if_false, -1);
22975
22976
0
        emit_op(s, OP_scope_get_var);
22977
0
        emit_atom(s, JS_ATOM_this);
22978
0
        emit_u16(s, 0);
22979
22980
0
        emit_op(s, OP_scope_get_var);
22981
0
        emit_atom(s, JS_ATOM_home_object);
22982
0
        emit_u16(s, 0);
22983
22984
0
        emit_op(s, OP_add_brand);
22985
22986
0
        emit_label(s, label_add_brand);
22987
0
    }
22988
0
    s->cur_func = s->cur_func->parent;
22989
0
    return 0;
22990
0
}
22991
22992
static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf)
22993
0
{
22994
0
    int cpool_idx;
22995
22996
0
    s->cur_func = cf->fields_init_fd;
22997
0
    emit_op(s, OP_return_undef);
22998
0
    s->cur_func = s->cur_func->parent;
22999
23000
0
    cpool_idx = cpool_add(s, JS_NULL);
23001
0
    cf->fields_init_fd->parent_cpool_idx = cpool_idx;
23002
0
    emit_op(s, OP_fclosure);
23003
0
    emit_u32(s, cpool_idx);
23004
0
    emit_op(s, OP_set_home_object);
23005
0
}
23006
23007
23008
static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
23009
                                      JSParseExportEnum export_flag)
23010
0
{
23011
0
    JSContext *ctx = s->ctx;
23012
0
    JSFunctionDef *fd = s->cur_func;
23013
0
    JSAtom name = JS_ATOM_NULL, class_name = JS_ATOM_NULL, class_name1;
23014
0
    JSAtom class_var_name = JS_ATOM_NULL;
23015
0
    JSFunctionDef *method_fd, *ctor_fd;
23016
0
    int saved_js_mode, class_name_var_idx, prop_type, ctor_cpool_offset;
23017
0
    int class_flags = 0, i, define_class_offset;
23018
0
    BOOL is_static, is_private;
23019
0
    const uint8_t *class_start_ptr = s->token.ptr;
23020
0
    const uint8_t *start_ptr;
23021
0
    ClassFieldsDef class_fields[2];
23022
23023
    /* classes are parsed and executed in strict mode */
23024
0
    saved_js_mode = fd->js_mode;
23025
0
    fd->js_mode |= JS_MODE_STRICT;
23026
0
    if (next_token(s))
23027
0
        goto fail;
23028
0
    if (s->token.val == TOK_IDENT) {
23029
0
        if (s->token.u.ident.is_reserved) {
23030
0
            js_parse_error_reserved_identifier(s);
23031
0
            goto fail;
23032
0
        }
23033
0
        class_name = JS_DupAtom(ctx, s->token.u.ident.atom);
23034
0
        if (next_token(s))
23035
0
            goto fail;
23036
0
    } else if (!is_class_expr && export_flag != JS_PARSE_EXPORT_DEFAULT) {
23037
0
        js_parse_error(s, "class statement requires a name");
23038
0
        goto fail;
23039
0
    }
23040
0
    if (!is_class_expr) {
23041
0
        if (class_name == JS_ATOM_NULL)
23042
0
            class_var_name = JS_ATOM__default_; /* export default */
23043
0
        else
23044
0
            class_var_name = class_name;
23045
0
        class_var_name = JS_DupAtom(ctx, class_var_name);
23046
0
    }
23047
23048
0
    push_scope(s);
23049
23050
0
    if (s->token.val == TOK_EXTENDS) {
23051
0
        class_flags = JS_DEFINE_CLASS_HAS_HERITAGE;
23052
0
        if (next_token(s))
23053
0
            goto fail;
23054
0
        if (js_parse_left_hand_side_expr(s))
23055
0
            goto fail;
23056
0
    } else {
23057
0
        emit_op(s, OP_undefined);
23058
0
    }
23059
23060
    /* add a 'const' definition for the class name */
23061
0
    if (class_name != JS_ATOM_NULL) {
23062
0
        class_name_var_idx = define_var(s, fd, class_name, JS_VAR_DEF_CONST);
23063
0
        if (class_name_var_idx < 0)
23064
0
            goto fail;
23065
0
    }
23066
23067
0
    if (js_parse_expect(s, '{'))
23068
0
        goto fail;
23069
23070
    /* this scope contains the private fields */
23071
0
    push_scope(s);
23072
23073
0
    emit_op(s, OP_push_const);
23074
0
    ctor_cpool_offset = fd->byte_code.size;
23075
0
    emit_u32(s, 0); /* will be patched at the end of the class parsing */
23076
23077
0
    if (class_name == JS_ATOM_NULL) {
23078
0
        if (class_var_name != JS_ATOM_NULL)
23079
0
            class_name1 = JS_ATOM_default;
23080
0
        else
23081
0
            class_name1 = JS_ATOM_empty_string;
23082
0
    } else {
23083
0
        class_name1 = class_name;
23084
0
    }
23085
23086
0
    emit_op(s, OP_define_class);
23087
0
    emit_atom(s, class_name1);
23088
0
    emit_u8(s, class_flags);
23089
0
    define_class_offset = fd->last_opcode_pos;
23090
23091
0
    for(i = 0; i < 2; i++) {
23092
0
        ClassFieldsDef *cf = &class_fields[i];
23093
0
        cf->fields_init_fd = NULL;
23094
0
        cf->computed_fields_count = 0;
23095
0
        cf->need_brand = FALSE;
23096
0
        cf->is_static = i;
23097
0
    }
23098
23099
0
    ctor_fd = NULL;
23100
0
    while (s->token.val != '}') {
23101
0
        if (s->token.val == ';') {
23102
0
            if (next_token(s))
23103
0
                goto fail;
23104
0
            continue;
23105
0
        }
23106
0
        is_static = FALSE;
23107
0
        if (s->token.val == TOK_STATIC) {
23108
0
            int next = peek_token(s, TRUE);
23109
0
            if (!(next == ';' || next == '}' || next == '(' || next == '='))
23110
0
                is_static = TRUE;
23111
0
        }
23112
0
        prop_type = -1;
23113
0
        if (is_static) {
23114
0
            if (next_token(s))
23115
0
                goto fail;
23116
0
            if (s->token.val == '{') {
23117
0
                ClassFieldsDef *cf = &class_fields[is_static];
23118
0
                JSFunctionDef *init;
23119
0
                if (!cf->fields_init_fd) {
23120
0
                    if (emit_class_init_start(s, cf))
23121
0
                        goto fail;
23122
0
                }
23123
0
                s->cur_func = cf->fields_init_fd;
23124
                /* XXX: could try to avoid creating a new function and
23125
                   reuse 'fields_init_fd' with a specific 'var'
23126
                   scope */
23127
                // stack is now: <empty>
23128
0
                if (js_parse_function_decl2(s, JS_PARSE_FUNC_CLASS_STATIC_INIT,
23129
0
                                            JS_FUNC_NORMAL, JS_ATOM_NULL,
23130
0
                                            s->token.ptr, s->token.line_num,
23131
0
                                            JS_PARSE_EXPORT_NONE, &init) < 0) {
23132
0
                    goto fail;
23133
0
                }
23134
                // stack is now: fclosure
23135
0
                push_scope(s);
23136
0
                emit_op(s, OP_scope_get_var);
23137
0
                emit_atom(s, JS_ATOM_this);
23138
0
                emit_u16(s, 0);
23139
                // stack is now: fclosure this
23140
0
                emit_op(s, OP_swap);
23141
                // stack is now: this fclosure
23142
0
                emit_op(s, OP_call_method);
23143
0
                emit_u16(s, 0);
23144
                // stack is now: returnvalue
23145
0
                emit_op(s, OP_drop);
23146
                // stack is now: <empty>
23147
0
                pop_scope(s);
23148
0
                s->cur_func = s->cur_func->parent;
23149
0
                continue;
23150
0
            }
23151
            /* allow "static" field name */
23152
0
            if (s->token.val == ';' || s->token.val == '=') {
23153
0
                is_static = FALSE;
23154
0
                name = JS_DupAtom(ctx, JS_ATOM_static);
23155
0
                prop_type = PROP_TYPE_IDENT;
23156
0
            }
23157
0
        }
23158
0
        if (is_static)
23159
0
            emit_op(s, OP_swap);
23160
0
        start_ptr = s->token.ptr;
23161
0
        if (prop_type < 0) {
23162
0
            prop_type = js_parse_property_name(s, &name, TRUE, FALSE, TRUE);
23163
0
            if (prop_type < 0)
23164
0
                goto fail;
23165
0
        }
23166
0
        is_private = prop_type & PROP_TYPE_PRIVATE;
23167
0
        prop_type &= ~PROP_TYPE_PRIVATE;
23168
23169
0
        if ((name == JS_ATOM_constructor && !is_static &&
23170
0
             prop_type != PROP_TYPE_IDENT) ||
23171
0
            (name == JS_ATOM_prototype && is_static) ||
23172
0
            name == JS_ATOM_hash_constructor) {
23173
0
            js_parse_error(s, "invalid method name");
23174
0
            goto fail;
23175
0
        }
23176
0
        if (prop_type == PROP_TYPE_GET || prop_type == PROP_TYPE_SET) {
23177
0
            BOOL is_set = prop_type - PROP_TYPE_GET;
23178
0
            JSFunctionDef *method_fd;
23179
23180
0
            if (is_private) {
23181
0
                int idx, var_kind, is_static1;
23182
0
                idx = find_private_class_field(ctx, fd, name, fd->scope_level);
23183
0
                if (idx >= 0) {
23184
0
                    var_kind = fd->vars[idx].var_kind;
23185
0
                    is_static1 = fd->vars[idx].is_static_private;
23186
0
                    if (var_kind == JS_VAR_PRIVATE_FIELD ||
23187
0
                        var_kind == JS_VAR_PRIVATE_METHOD ||
23188
0
                        var_kind == JS_VAR_PRIVATE_GETTER_SETTER ||
23189
0
                        var_kind == (JS_VAR_PRIVATE_GETTER + is_set) ||
23190
0
                        (var_kind == (JS_VAR_PRIVATE_GETTER + 1 - is_set) &&
23191
0
                         is_static != is_static1)) {
23192
0
                        goto private_field_already_defined;
23193
0
                    }
23194
0
                    fd->vars[idx].var_kind = JS_VAR_PRIVATE_GETTER_SETTER;
23195
0
                } else {
23196
0
                    if (add_private_class_field(s, fd, name,
23197
0
                                                JS_VAR_PRIVATE_GETTER + is_set, is_static) < 0)
23198
0
                        goto fail;
23199
0
                }
23200
0
                class_fields[is_static].need_brand = TRUE;
23201
0
            }
23202
23203
0
            if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set,
23204
0
                                        JS_FUNC_NORMAL, JS_ATOM_NULL,
23205
0
                                        start_ptr, s->token.line_num,
23206
0
                                        JS_PARSE_EXPORT_NONE, &method_fd))
23207
0
                goto fail;
23208
0
            if (is_private) {
23209
0
                method_fd->need_home_object = TRUE; /* needed for brand check */
23210
0
                emit_op(s, OP_set_home_object);
23211
                /* XXX: missing function name */
23212
0
                emit_op(s, OP_scope_put_var_init);
23213
0
                if (is_set) {
23214
0
                    JSAtom setter_name;
23215
0
                    int ret;
23216
23217
0
                    setter_name = get_private_setter_name(ctx, name);
23218
0
                    if (setter_name == JS_ATOM_NULL)
23219
0
                        goto fail;
23220
0
                    emit_atom(s, setter_name);
23221
0
                    ret = add_private_class_field(s, fd, setter_name,
23222
0
                                                  JS_VAR_PRIVATE_SETTER, is_static);
23223
0
                    JS_FreeAtom(ctx, setter_name);
23224
0
                    if (ret < 0)
23225
0
                        goto fail;
23226
0
                } else {
23227
0
                    emit_atom(s, name);
23228
0
                }
23229
0
                emit_u16(s, s->cur_func->scope_level);
23230
0
            } else {
23231
0
                if (name == JS_ATOM_NULL) {
23232
0
                    emit_op(s, OP_define_method_computed);
23233
0
                } else {
23234
0
                    emit_op(s, OP_define_method);
23235
0
                    emit_atom(s, name);
23236
0
                }
23237
0
                emit_u8(s, OP_DEFINE_METHOD_GETTER + is_set);
23238
0
            }
23239
0
        } else if (prop_type == PROP_TYPE_IDENT && s->token.val != '(') {
23240
0
            ClassFieldsDef *cf = &class_fields[is_static];
23241
0
            JSAtom field_var_name = JS_ATOM_NULL;
23242
23243
            /* class field */
23244
23245
            /* XXX: spec: not consistent with method name checks */
23246
0
            if (name == JS_ATOM_constructor || name == JS_ATOM_prototype) {
23247
0
                js_parse_error(s, "invalid field name");
23248
0
                goto fail;
23249
0
            }
23250
23251
0
            if (is_private) {
23252
0
                if (find_private_class_field(ctx, fd, name,
23253
0
                                             fd->scope_level) >= 0) {
23254
0
                    goto private_field_already_defined;
23255
0
                }
23256
0
                if (add_private_class_field(s, fd, name,
23257
0
                                            JS_VAR_PRIVATE_FIELD, is_static) < 0)
23258
0
                    goto fail;
23259
0
                emit_op(s, OP_private_symbol);
23260
0
                emit_atom(s, name);
23261
0
                emit_op(s, OP_scope_put_var_init);
23262
0
                emit_atom(s, name);
23263
0
                emit_u16(s, s->cur_func->scope_level);
23264
0
            }
23265
23266
0
            if (!cf->fields_init_fd) {
23267
0
                if (emit_class_init_start(s, cf))
23268
0
                    goto fail;
23269
0
            }
23270
0
            if (name == JS_ATOM_NULL ) {
23271
                /* save the computed field name into a variable */
23272
0
                field_var_name = js_atom_concat_num(ctx, JS_ATOM_computed_field + is_static, cf->computed_fields_count);
23273
0
                if (field_var_name == JS_ATOM_NULL)
23274
0
                    goto fail;
23275
0
                if (define_var(s, fd, field_var_name, JS_VAR_DEF_CONST) < 0) {
23276
0
                    JS_FreeAtom(ctx, field_var_name);
23277
0
                    goto fail;
23278
0
                }
23279
0
                emit_op(s, OP_to_propkey);
23280
0
                emit_op(s, OP_scope_put_var_init);
23281
0
                emit_atom(s, field_var_name);
23282
0
                emit_u16(s, s->cur_func->scope_level);
23283
0
            }
23284
0
            s->cur_func = cf->fields_init_fd;
23285
0
            emit_op(s, OP_scope_get_var);
23286
0
            emit_atom(s, JS_ATOM_this);
23287
0
            emit_u16(s, 0);
23288
23289
0
            if (name == JS_ATOM_NULL) {
23290
0
                emit_op(s, OP_scope_get_var);
23291
0
                emit_atom(s, field_var_name);
23292
0
                emit_u16(s, s->cur_func->scope_level);
23293
0
                cf->computed_fields_count++;
23294
0
                JS_FreeAtom(ctx, field_var_name);
23295
0
            } else if (is_private) {
23296
0
                emit_op(s, OP_scope_get_var);
23297
0
                emit_atom(s, name);
23298
0
                emit_u16(s, s->cur_func->scope_level);
23299
0
            }
23300
23301
0
            if (s->token.val == '=') {
23302
0
                if (next_token(s))
23303
0
                    goto fail;
23304
0
                if (js_parse_assign_expr(s))
23305
0
                    goto fail;
23306
0
            } else {
23307
0
                emit_op(s, OP_undefined);
23308
0
            }
23309
0
            if (is_private) {
23310
0
                set_object_name_computed(s);
23311
0
                emit_op(s, OP_define_private_field);
23312
0
            } else if (name == JS_ATOM_NULL) {
23313
0
                set_object_name_computed(s);
23314
0
                emit_op(s, OP_define_array_el);
23315
0
                emit_op(s, OP_drop);
23316
0
            } else {
23317
0
                set_object_name(s, name);
23318
0
                emit_op(s, OP_define_field);
23319
0
                emit_atom(s, name);
23320
0
            }
23321
0
            s->cur_func = s->cur_func->parent;
23322
0
            if (js_parse_expect_semi(s))
23323
0
                goto fail;
23324
0
        } else {
23325
0
            JSParseFunctionEnum func_type;
23326
0
            JSFunctionKindEnum func_kind;
23327
23328
0
            func_type = JS_PARSE_FUNC_METHOD;
23329
0
            func_kind = JS_FUNC_NORMAL;
23330
0
            if (prop_type == PROP_TYPE_STAR) {
23331
0
                func_kind = JS_FUNC_GENERATOR;
23332
0
            } else if (prop_type == PROP_TYPE_ASYNC) {
23333
0
                func_kind = JS_FUNC_ASYNC;
23334
0
            } else if (prop_type == PROP_TYPE_ASYNC_STAR) {
23335
0
                func_kind = JS_FUNC_ASYNC_GENERATOR;
23336
0
            } else if (name == JS_ATOM_constructor && !is_static) {
23337
0
                if (ctor_fd) {
23338
0
                    js_parse_error(s, "property constructor appears more than once");
23339
0
                    goto fail;
23340
0
                }
23341
0
                if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE)
23342
0
                    func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
23343
0
                else
23344
0
                    func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
23345
0
            }
23346
0
            if (is_private) {
23347
0
                class_fields[is_static].need_brand = TRUE;
23348
0
            }
23349
0
            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))
23350
0
                goto fail;
23351
0
            if (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR ||
23352
0
                func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
23353
0
                ctor_fd = method_fd;
23354
0
            } else if (is_private) {
23355
0
                method_fd->need_home_object = TRUE; /* needed for brand check */
23356
0
                if (find_private_class_field(ctx, fd, name,
23357
0
                                             fd->scope_level) >= 0) {
23358
0
                private_field_already_defined:
23359
0
                    js_parse_error(s, "private class field is already defined");
23360
0
                    goto fail;
23361
0
                }
23362
0
                if (add_private_class_field(s, fd, name,
23363
0
                                            JS_VAR_PRIVATE_METHOD, is_static) < 0)
23364
0
                    goto fail;
23365
0
                emit_op(s, OP_set_home_object);
23366
0
                emit_op(s, OP_set_name);
23367
0
                emit_atom(s, name);
23368
0
                emit_op(s, OP_scope_put_var_init);
23369
0
                emit_atom(s, name);
23370
0
                emit_u16(s, s->cur_func->scope_level);
23371
0
            } else {
23372
0
                if (name == JS_ATOM_NULL) {
23373
0
                    emit_op(s, OP_define_method_computed);
23374
0
                } else {
23375
0
                    emit_op(s, OP_define_method);
23376
0
                    emit_atom(s, name);
23377
0
                }
23378
0
                emit_u8(s, OP_DEFINE_METHOD_METHOD);
23379
0
            }
23380
0
        }
23381
0
        if (is_static)
23382
0
            emit_op(s, OP_swap);
23383
0
        JS_FreeAtom(ctx, name);
23384
0
        name = JS_ATOM_NULL;
23385
0
    }
23386
23387
0
    if (s->token.val != '}') {
23388
0
        js_parse_error(s, "expecting '%c'", '}');
23389
0
        goto fail;
23390
0
    }
23391
23392
0
    if (!ctor_fd) {
23393
0
        if (js_parse_class_default_ctor(s, class_flags & JS_DEFINE_CLASS_HAS_HERITAGE, &ctor_fd))
23394
0
            goto fail;
23395
0
    }
23396
    /* patch the constant pool index for the constructor */
23397
0
    put_u32(fd->byte_code.buf + ctor_cpool_offset, ctor_fd->parent_cpool_idx);
23398
23399
    /* store the class source code in the constructor. */
23400
0
    if (!(fd->js_mode & JS_MODE_STRIP)) {
23401
0
        js_free(ctx, ctor_fd->source);
23402
0
        ctor_fd->source_len = s->buf_ptr - class_start_ptr;
23403
0
        ctor_fd->source = js_strndup(ctx, (const char *)class_start_ptr,
23404
0
                                     ctor_fd->source_len);
23405
0
        if (!ctor_fd->source)
23406
0
            goto fail;
23407
0
    }
23408
23409
    /* consume the '}' */
23410
0
    if (next_token(s))
23411
0
        goto fail;
23412
23413
0
    {
23414
0
        ClassFieldsDef *cf = &class_fields[0];
23415
0
        int var_idx;
23416
23417
0
        if (cf->need_brand) {
23418
            /* add a private brand to the prototype */
23419
0
            emit_op(s, OP_dup);
23420
0
            emit_op(s, OP_null);
23421
0
            emit_op(s, OP_swap);
23422
0
            emit_op(s, OP_add_brand);
23423
23424
            /* define the brand field in 'this' of the initializer */
23425
0
            if (!cf->fields_init_fd) {
23426
0
                if (emit_class_init_start(s, cf))
23427
0
                    goto fail;
23428
0
            }
23429
            /* patch the start of the function to enable the
23430
               OP_add_brand_instance code */
23431
0
            cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true;
23432
0
        }
23433
23434
        /* store the function to initialize the fields to that it can be
23435
           referenced by the constructor */
23436
0
        var_idx = define_var(s, fd, JS_ATOM_class_fields_init,
23437
0
                             JS_VAR_DEF_CONST);
23438
0
        if (var_idx < 0)
23439
0
            goto fail;
23440
0
        if (cf->fields_init_fd) {
23441
0
            emit_class_init_end(s, cf);
23442
0
        } else {
23443
0
            emit_op(s, OP_undefined);
23444
0
        }
23445
0
        emit_op(s, OP_scope_put_var_init);
23446
0
        emit_atom(s, JS_ATOM_class_fields_init);
23447
0
        emit_u16(s, s->cur_func->scope_level);
23448
0
    }
23449
23450
    /* drop the prototype */
23451
0
    emit_op(s, OP_drop);
23452
23453
0
    if (class_fields[1].need_brand) {
23454
        /* add a private brand to the class */
23455
0
        emit_op(s, OP_dup);
23456
0
        emit_op(s, OP_dup);
23457
0
        emit_op(s, OP_add_brand);
23458
0
    }
23459
23460
0
    if (class_name != JS_ATOM_NULL) {
23461
        /* store the class name in the scoped class name variable (it
23462
           is independent from the class statement variable
23463
           definition) */
23464
0
        emit_op(s, OP_dup);
23465
0
        emit_op(s, OP_scope_put_var_init);
23466
0
        emit_atom(s, class_name);
23467
0
        emit_u16(s, fd->scope_level);
23468
0
    }
23469
23470
    /* initialize the static fields */
23471
0
    if (class_fields[1].fields_init_fd != NULL) {
23472
0
        ClassFieldsDef *cf = &class_fields[1];
23473
0
        emit_op(s, OP_dup);
23474
0
        emit_class_init_end(s, cf);
23475
0
        emit_op(s, OP_call_method);
23476
0
        emit_u16(s, 0);
23477
0
        emit_op(s, OP_drop);
23478
0
    }
23479
23480
0
    pop_scope(s);
23481
0
    pop_scope(s);
23482
23483
    /* the class statements have a block level scope */
23484
0
    if (class_var_name != JS_ATOM_NULL) {
23485
0
        if (define_var(s, fd, class_var_name, JS_VAR_DEF_LET) < 0)
23486
0
            goto fail;
23487
0
        emit_op(s, OP_scope_put_var_init);
23488
0
        emit_atom(s, class_var_name);
23489
0
        emit_u16(s, fd->scope_level);
23490
0
    } else {
23491
0
        if (class_name == JS_ATOM_NULL) {
23492
            /* cannot use OP_set_name because the name of the class
23493
               must be defined before the static initializers are
23494
               executed */
23495
0
            emit_op(s, OP_set_class_name);
23496
0
            emit_u32(s, fd->last_opcode_pos + 1 - define_class_offset);
23497
0
        }
23498
0
    }
23499
23500
0
    if (export_flag != JS_PARSE_EXPORT_NONE) {
23501
0
        if (!add_export_entry(s, fd->module,
23502
0
                              class_var_name,
23503
0
                              export_flag == JS_PARSE_EXPORT_NAMED ? class_var_name : JS_ATOM_default,
23504
0
                              JS_EXPORT_TYPE_LOCAL))
23505
0
            goto fail;
23506
0
    }
23507
23508
0
    JS_FreeAtom(ctx, class_name);
23509
0
    JS_FreeAtom(ctx, class_var_name);
23510
0
    fd->js_mode = saved_js_mode;
23511
0
    return 0;
23512
0
 fail:
23513
0
    JS_FreeAtom(ctx, name);
23514
0
    JS_FreeAtom(ctx, class_name);
23515
0
    JS_FreeAtom(ctx, class_var_name);
23516
0
    fd->js_mode = saved_js_mode;
23517
0
    return -1;
23518
0
}
23519
23520
static __exception int js_parse_array_literal(JSParseState *s)
23521
21
{
23522
21
    uint32_t idx;
23523
21
    BOOL need_length;
23524
23525
21
    if (next_token(s))
23526
0
        return -1;
23527
    /* small regular arrays are created on the stack */
23528
21
    idx = 0;
23529
405
    while (s->token.val != ']' && idx < 32) {
23530
384
        if (s->token.val == ',' || s->token.val == TOK_ELLIPSIS)
23531
0
            break;
23532
384
        if (js_parse_assign_expr(s))
23533
0
            return -1;
23534
384
        idx++;
23535
        /* accept trailing comma */
23536
384
        if (s->token.val == ',') {
23537
384
            if (next_token(s))
23538
0
                return -1;
23539
384
        } else
23540
0
        if (s->token.val != ']')
23541
0
            goto done;
23542
384
    }
23543
21
    emit_op(s, OP_array_from);
23544
21
    emit_u16(s, idx);
23545
23546
    /* larger arrays and holes are handled with explicit indices */
23547
21
    need_length = FALSE;
23548
5.45M
    while (s->token.val != ']' && idx < 0x7fffffff) {
23549
5.45M
        if (s->token.val == TOK_ELLIPSIS)
23550
0
            break;
23551
5.45M
        need_length = TRUE;
23552
5.45M
        if (s->token.val != ',') {
23553
5.45M
            if (js_parse_assign_expr(s))
23554
4
                return -1;
23555
5.45M
            emit_op(s, OP_define_field);
23556
5.45M
            emit_u32(s, __JS_AtomFromUInt32(idx));
23557
5.45M
            need_length = FALSE;
23558
5.45M
        }
23559
5.45M
        idx++;
23560
        /* accept trailing comma */
23561
5.45M
        if (s->token.val == ',') {
23562
5.45M
            if (next_token(s))
23563
1
                return -1;
23564
5.45M
        }
23565
5.45M
    }
23566
16
    if (s->token.val == ']') {
23567
16
        if (need_length) {
23568
            /* Set the length: Cannot use OP_define_field because
23569
               length is not configurable */
23570
0
            emit_op(s, OP_dup);
23571
0
            emit_op(s, OP_push_i32);
23572
0
            emit_u32(s, idx);
23573
0
            emit_op(s, OP_put_field);
23574
0
            emit_atom(s, JS_ATOM_length);
23575
0
        }
23576
16
        goto done;
23577
16
    }
23578
23579
    /* huge arrays and spread elements require a dynamic index on the stack */
23580
0
    emit_op(s, OP_push_i32);
23581
0
    emit_u32(s, idx);
23582
23583
    /* stack has array, index */
23584
0
    while (s->token.val != ']') {
23585
0
        if (s->token.val == TOK_ELLIPSIS) {
23586
0
            if (next_token(s))
23587
0
                return -1;
23588
0
            if (js_parse_assign_expr(s))
23589
0
                return -1;
23590
0
#if 1
23591
0
            emit_op(s, OP_append);
23592
#else
23593
            int label_next, label_done;
23594
            label_next = new_label(s);
23595
            label_done = new_label(s);
23596
            /* enumerate object */
23597
            emit_op(s, OP_for_of_start);
23598
            emit_op(s, OP_rot5l);
23599
            emit_op(s, OP_rot5l);
23600
            emit_label(s, label_next);
23601
            /* on stack: enum_rec array idx */
23602
            emit_op(s, OP_for_of_next);
23603
            emit_u8(s, 2);
23604
            emit_goto(s, OP_if_true, label_done);
23605
            /* append element */
23606
            /* enum_rec array idx val -> enum_rec array new_idx */
23607
            emit_op(s, OP_define_array_el);
23608
            emit_op(s, OP_inc);
23609
            emit_goto(s, OP_goto, label_next);
23610
            emit_label(s, label_done);
23611
            /* close enumeration */
23612
            emit_op(s, OP_drop); /* drop undef val */
23613
            emit_op(s, OP_nip1); /* drop enum_rec */
23614
            emit_op(s, OP_nip1);
23615
            emit_op(s, OP_nip1);
23616
#endif
23617
0
        } else {
23618
0
            need_length = TRUE;
23619
0
            if (s->token.val != ',') {
23620
0
                if (js_parse_assign_expr(s))
23621
0
                    return -1;
23622
                /* a idx val */
23623
0
                emit_op(s, OP_define_array_el);
23624
0
                need_length = FALSE;
23625
0
            }
23626
0
            emit_op(s, OP_inc);
23627
0
        }
23628
0
        if (s->token.val != ',')
23629
0
            break;
23630
0
        if (next_token(s))
23631
0
            return -1;
23632
0
    }
23633
0
    if (need_length) {
23634
        /* Set the length: cannot use OP_define_field because
23635
           length is not configurable */
23636
0
        emit_op(s, OP_dup1);    /* array length - array array length */
23637
0
        emit_op(s, OP_put_field);
23638
0
        emit_atom(s, JS_ATOM_length);
23639
0
    } else {
23640
0
        emit_op(s, OP_drop);    /* array length - array */
23641
0
    }
23642
16
done:
23643
16
    return js_parse_expect(s, ']');
23644
0
}
23645
23646
/* XXX: remove */
23647
static BOOL has_with_scope(JSFunctionDef *s, int scope_level)
23648
0
{
23649
    /* check if scope chain contains a with statement */
23650
0
    while (s) {
23651
0
        int scope_idx = s->scopes[scope_level].first;
23652
0
        while (scope_idx >= 0) {
23653
0
            JSVarDef *vd = &s->vars[scope_idx];
23654
23655
0
            if (vd->var_name == JS_ATOM__with_)
23656
0
                return TRUE;
23657
0
            scope_idx = vd->scope_next;
23658
0
        }
23659
        /* check parent scopes */
23660
0
        scope_level = s->parent_scope_level;
23661
0
        s = s->parent;
23662
0
    }
23663
0
    return FALSE;
23664
0
}
23665
23666
static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
23667
                                  JSAtom *pname, int *plabel, int *pdepth, BOOL keep,
23668
                                  int tok)
23669
79
{
23670
79
    JSFunctionDef *fd;
23671
79
    int opcode, scope, label, depth;
23672
79
    JSAtom name;
23673
23674
    /* we check the last opcode to get the lvalue type */
23675
79
    fd = s->cur_func;
23676
79
    scope = 0;
23677
79
    name = JS_ATOM_NULL;
23678
79
    label = -1;
23679
79
    depth = 0;
23680
79
    switch(opcode = get_prev_opcode(fd)) {
23681
1
    case OP_scope_get_var:
23682
1
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
23683
1
        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
23684
1
        if ((name == JS_ATOM_arguments || name == JS_ATOM_eval) &&
23685
1
            (fd->js_mode & JS_MODE_STRICT)) {
23686
0
            return js_parse_error(s, "invalid lvalue in strict mode");
23687
0
        }
23688
1
        if (name == JS_ATOM_this || name == JS_ATOM_new_target)
23689
0
            goto invalid_lvalue;
23690
1
        depth = 2;  /* will generate OP_get_ref_value */
23691
1
        break;
23692
78
    case OP_get_field:
23693
78
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
23694
78
        depth = 1;
23695
78
        break;
23696
0
    case OP_scope_get_private_field:
23697
0
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
23698
0
        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
23699
0
        depth = 1;
23700
0
        break;
23701
0
    case OP_get_array_el:
23702
0
        depth = 2;
23703
0
        break;
23704
0
    case OP_get_super_value:
23705
0
        depth = 3;
23706
0
        break;
23707
0
    default:
23708
0
    invalid_lvalue:
23709
0
        if (tok == TOK_FOR) {
23710
0
            return js_parse_error(s, "invalid for in/of left hand-side");
23711
0
        } else if (tok == TOK_INC || tok == TOK_DEC) {
23712
0
            return js_parse_error(s, "invalid increment/decrement operand");
23713
0
        } else if (tok == '[' || tok == '{') {
23714
0
            return js_parse_error(s, "invalid destructuring target");
23715
0
        } else {
23716
0
            return js_parse_error(s, "invalid assignment left-hand side");
23717
0
        }
23718
79
    }
23719
    /* remove the last opcode */
23720
79
    fd->byte_code.size = fd->last_opcode_pos;
23721
79
    fd->last_opcode_pos = -1;
23722
23723
79
    if (keep) {
23724
        /* get the value but keep the object/fields on the stack */
23725
0
        switch(opcode) {
23726
0
        case OP_scope_get_var:
23727
0
            label = new_label(s);
23728
0
            emit_op(s, OP_scope_make_ref);
23729
0
            emit_atom(s, name);
23730
0
            emit_u32(s, label);
23731
0
            emit_u16(s, scope);
23732
0
            update_label(fd, label, 1);
23733
0
            emit_op(s, OP_get_ref_value);
23734
0
            opcode = OP_get_ref_value;
23735
0
            break;
23736
0
        case OP_get_field:
23737
0
            emit_op(s, OP_get_field2);
23738
0
            emit_atom(s, name);
23739
0
            break;
23740
0
        case OP_scope_get_private_field:
23741
0
            emit_op(s, OP_scope_get_private_field2);
23742
0
            emit_atom(s, name);
23743
0
            emit_u16(s, scope);
23744
0
            break;
23745
0
        case OP_get_array_el:
23746
            /* XXX: replace by a single opcode ? */
23747
0
            emit_op(s, OP_to_propkey2);
23748
0
            emit_op(s, OP_dup2);
23749
0
            emit_op(s, OP_get_array_el);
23750
0
            break;
23751
0
        case OP_get_super_value:
23752
0
            emit_op(s, OP_to_propkey);
23753
0
            emit_op(s, OP_dup3);
23754
0
            emit_op(s, OP_get_super_value);
23755
0
            break;
23756
0
        default:
23757
0
            abort();
23758
0
        }
23759
79
    } else {
23760
79
        switch(opcode) {
23761
1
        case OP_scope_get_var:
23762
1
            label = new_label(s);
23763
1
            emit_op(s, OP_scope_make_ref);
23764
1
            emit_atom(s, name);
23765
1
            emit_u32(s, label);
23766
1
            emit_u16(s, scope);
23767
1
            update_label(fd, label, 1);
23768
1
            opcode = OP_get_ref_value;
23769
1
            break;
23770
0
        case OP_get_array_el:
23771
0
            emit_op(s, OP_to_propkey2);
23772
0
            break;
23773
0
        case OP_get_super_value:
23774
0
            emit_op(s, OP_to_propkey);
23775
0
            break;
23776
79
        }
23777
79
    }
23778
23779
79
    *popcode = opcode;
23780
79
    *pscope = scope;
23781
    /* name has refcount for OP_get_field and OP_get_ref_value,
23782
       and JS_ATOM_NULL for other opcodes */
23783
79
    *pname = name;
23784
79
    *plabel = label;
23785
79
    if (pdepth)
23786
0
        *pdepth = depth;
23787
79
    return 0;
23788
79
}
23789
23790
typedef enum {
23791
    PUT_LVALUE_NOKEEP, /* [depth] v -> */
23792
    PUT_LVALUE_NOKEEP_DEPTH, /* [depth] v -> , keep depth (currently
23793
                                just disable optimizations) */
23794
    PUT_LVALUE_KEEP_TOP,  /* [depth] v -> v */
23795
    PUT_LVALUE_KEEP_SECOND, /* [depth] v0 v -> v0 */
23796
    PUT_LVALUE_NOKEEP_BOTTOM, /* v [depth] -> */
23797
} PutLValueEnum;
23798
23799
/* name has a live reference. 'is_let' is only used with opcode =
23800
   OP_scope_get_var which is never generated by get_lvalue(). */
23801
static void put_lvalue(JSParseState *s, int opcode, int scope,
23802
                       JSAtom name, int label, PutLValueEnum special,
23803
                       BOOL is_let)
23804
79
{
23805
79
    switch(opcode) {
23806
78
    case OP_get_field:
23807
78
    case OP_scope_get_private_field:
23808
        /* depth = 1 */
23809
78
        switch(special) {
23810
0
        case PUT_LVALUE_NOKEEP:
23811
0
        case PUT_LVALUE_NOKEEP_DEPTH:
23812
0
            break;
23813
78
        case PUT_LVALUE_KEEP_TOP:
23814
78
            emit_op(s, OP_insert2); /* obj v -> v obj v */
23815
78
            break;
23816
0
        case PUT_LVALUE_KEEP_SECOND:
23817
0
            emit_op(s, OP_perm3); /* obj v0 v -> v0 obj v */
23818
0
            break;
23819
0
        case PUT_LVALUE_NOKEEP_BOTTOM:
23820
0
            emit_op(s, OP_swap);
23821
0
            break;
23822
0
        default:
23823
0
            abort();
23824
78
        }
23825
78
        break;
23826
78
    case OP_get_array_el:
23827
1
    case OP_get_ref_value:
23828
        /* depth = 2 */
23829
1
        if (opcode == OP_get_ref_value) {
23830
1
            JS_FreeAtom(s->ctx, name);
23831
1
            emit_label(s, label);
23832
1
        }
23833
1
        switch(special) {
23834
0
        case PUT_LVALUE_NOKEEP:
23835
0
            emit_op(s, OP_nop); /* will trigger optimization */
23836
0
            break;
23837
0
        case PUT_LVALUE_NOKEEP_DEPTH:
23838
0
            break;
23839
1
        case PUT_LVALUE_KEEP_TOP:
23840
1
            emit_op(s, OP_insert3); /* obj prop v -> v obj prop v */
23841
1
            break;
23842
0
        case PUT_LVALUE_KEEP_SECOND:
23843
0
            emit_op(s, OP_perm4); /* obj prop v0 v -> v0 obj prop v */
23844
0
            break;
23845
0
        case PUT_LVALUE_NOKEEP_BOTTOM:
23846
0
            emit_op(s, OP_rot3l);
23847
0
            break;
23848
0
        default:
23849
0
            abort();
23850
1
        }
23851
1
        break;
23852
1
    case OP_get_super_value:
23853
        /* depth = 3 */
23854
0
        switch(special) {
23855
0
        case PUT_LVALUE_NOKEEP:
23856
0
        case PUT_LVALUE_NOKEEP_DEPTH:
23857
0
            break;
23858
0
        case PUT_LVALUE_KEEP_TOP:
23859
0
            emit_op(s, OP_insert4); /* this obj prop v -> v this obj prop v */
23860
0
            break;
23861
0
        case PUT_LVALUE_KEEP_SECOND:
23862
0
            emit_op(s, OP_perm5); /* this obj prop v0 v -> v0 this obj prop v */
23863
0
            break;
23864
0
        case PUT_LVALUE_NOKEEP_BOTTOM:
23865
0
            emit_op(s, OP_rot4l);
23866
0
            break;
23867
0
        default:
23868
0
            abort();
23869
0
        }
23870
0
        break;
23871
0
    default:
23872
0
        break;
23873
79
    }
23874
23875
79
    switch(opcode) {
23876
0
    case OP_scope_get_var:  /* val -- */
23877
0
        assert(special == PUT_LVALUE_NOKEEP ||
23878
0
               special == PUT_LVALUE_NOKEEP_DEPTH);
23879
0
        emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var);
23880
0
        emit_u32(s, name);  /* has refcount */
23881
0
        emit_u16(s, scope);
23882
0
        break;
23883
78
    case OP_get_field:
23884
78
        emit_op(s, OP_put_field);
23885
78
        emit_u32(s, name);  /* name has refcount */
23886
78
        break;
23887
0
    case OP_scope_get_private_field:
23888
0
        emit_op(s, OP_scope_put_private_field);
23889
0
        emit_u32(s, name);  /* name has refcount */
23890
0
        emit_u16(s, scope);
23891
0
        break;
23892
0
    case OP_get_array_el:
23893
0
        emit_op(s, OP_put_array_el);
23894
0
        break;
23895
1
    case OP_get_ref_value:
23896
1
        emit_op(s, OP_put_ref_value);
23897
1
        break;
23898
0
    case OP_get_super_value:
23899
0
        emit_op(s, OP_put_super_value);
23900
0
        break;
23901
0
    default:
23902
0
        abort();
23903
79
    }
23904
79
}
23905
23906
static __exception int js_parse_expr_paren(JSParseState *s)
23907
0
{
23908
0
    if (js_parse_expect(s, '('))
23909
0
        return -1;
23910
0
    if (js_parse_expr(s))
23911
0
        return -1;
23912
0
    if (js_parse_expect(s, ')'))
23913
0
        return -1;
23914
0
    return 0;
23915
0
}
23916
23917
static int js_unsupported_keyword(JSParseState *s, JSAtom atom)
23918
0
{
23919
0
    char buf[ATOM_GET_STR_BUF_SIZE];
23920
0
    return js_parse_error(s, "unsupported keyword: %s",
23921
0
                          JS_AtomGetStr(s->ctx, buf, sizeof(buf), atom));
23922
0
}
23923
23924
static __exception int js_define_var(JSParseState *s, JSAtom name, int tok)
23925
0
{
23926
0
    JSFunctionDef *fd = s->cur_func;
23927
0
    JSVarDefEnum var_def_type;
23928
23929
0
    if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
23930
0
        return js_parse_error(s, "yield is a reserved identifier");
23931
0
    }
23932
0
    if ((name == JS_ATOM_arguments || name == JS_ATOM_eval)
23933
0
    &&  (fd->js_mode & JS_MODE_STRICT)) {
23934
0
        return js_parse_error(s, "invalid variable name in strict mode");
23935
0
    }
23936
0
    if ((name == JS_ATOM_let || name == JS_ATOM_undefined)
23937
0
    &&  (tok == TOK_LET || tok == TOK_CONST)) {
23938
0
        return js_parse_error(s, "invalid lexical variable name");
23939
0
    }
23940
0
    switch(tok) {
23941
0
    case TOK_LET:
23942
0
        var_def_type = JS_VAR_DEF_LET;
23943
0
        break;
23944
0
    case TOK_CONST:
23945
0
        var_def_type = JS_VAR_DEF_CONST;
23946
0
        break;
23947
0
    case TOK_VAR:
23948
0
        var_def_type = JS_VAR_DEF_VAR;
23949
0
        break;
23950
0
    case TOK_CATCH:
23951
0
        var_def_type = JS_VAR_DEF_CATCH;
23952
0
        break;
23953
0
    default:
23954
0
        abort();
23955
0
    }
23956
0
    if (define_var(s, fd, name, var_def_type) < 0)
23957
0
        return -1;
23958
0
    return 0;
23959
0
}
23960
23961
static void js_emit_spread_code(JSParseState *s, int depth)
23962
0
{
23963
0
    int label_rest_next, label_rest_done;
23964
23965
    /* XXX: could check if enum object is an actual array and optimize
23966
       slice extraction. enumeration record and target array are in a
23967
       different order from OP_append case. */
23968
    /* enum_rec xxx -- enum_rec xxx array 0 */
23969
0
    emit_op(s, OP_array_from);
23970
0
    emit_u16(s, 0);
23971
0
    emit_op(s, OP_push_i32);
23972
0
    emit_u32(s, 0);
23973
0
    emit_label(s, label_rest_next = new_label(s));
23974
0
    emit_op(s, OP_for_of_next);
23975
0
    emit_u8(s, 2 + depth);
23976
0
    label_rest_done = emit_goto(s, OP_if_true, -1);
23977
    /* array idx val -- array idx */
23978
0
    emit_op(s, OP_define_array_el);
23979
0
    emit_op(s, OP_inc);
23980
0
    emit_goto(s, OP_goto, label_rest_next);
23981
0
    emit_label(s, label_rest_done);
23982
    /* enum_rec xxx array idx undef -- enum_rec xxx array */
23983
0
    emit_op(s, OP_drop);
23984
0
    emit_op(s, OP_drop);
23985
0
}
23986
23987
static int js_parse_check_duplicate_parameter(JSParseState *s, JSAtom name)
23988
0
{
23989
    /* Check for duplicate parameter names */
23990
0
    JSFunctionDef *fd = s->cur_func;
23991
0
    int i;
23992
0
    for (i = 0; i < fd->arg_count; i++) {
23993
0
        if (fd->args[i].var_name == name)
23994
0
            goto duplicate;
23995
0
    }
23996
0
    for (i = 0; i < fd->var_count; i++) {
23997
0
        if (fd->vars[i].var_name == name)
23998
0
            goto duplicate;
23999
0
    }
24000
0
    return 0;
24001
24002
0
duplicate:
24003
0
    return js_parse_error(s, "duplicate parameter names not allowed in this context");
24004
0
}
24005
24006
static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg)
24007
0
{
24008
0
    JSAtom name;
24009
24010
0
    if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
24011
0
    ||  ((s->cur_func->js_mode & JS_MODE_STRICT) &&
24012
0
         (s->token.u.ident.atom == JS_ATOM_eval || s->token.u.ident.atom == JS_ATOM_arguments))) {
24013
0
        js_parse_error(s, "invalid destructuring target");
24014
0
        return JS_ATOM_NULL;
24015
0
    }
24016
0
    name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
24017
0
    if (is_arg && js_parse_check_duplicate_parameter(s, name))
24018
0
        goto fail;
24019
0
    if (next_token(s))
24020
0
        goto fail;
24021
24022
0
    return name;
24023
0
fail:
24024
0
    JS_FreeAtom(s->ctx, name);
24025
0
    return JS_ATOM_NULL;
24026
0
}
24027
24028
/* Return -1 if error, 0 if no initializer, 1 if an initializer is
24029
   present at the top level. */
24030
static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
24031
                                        int hasval, int has_ellipsis,
24032
                                        BOOL allow_initializer)
24033
0
{
24034
0
    int label_parse, label_assign, label_done, label_lvalue, depth_lvalue;
24035
0
    int start_addr, assign_addr;
24036
0
    JSAtom prop_name, var_name;
24037
0
    int opcode, scope, tok1, skip_bits;
24038
0
    BOOL has_initializer;
24039
24040
0
    if (has_ellipsis < 0) {
24041
        /* pre-parse destructuration target for spread detection */
24042
0
        js_parse_skip_parens_token(s, &skip_bits, FALSE);
24043
0
        has_ellipsis = skip_bits & SKIP_HAS_ELLIPSIS;
24044
0
    }
24045
24046
0
    label_parse = new_label(s);
24047
0
    label_assign = new_label(s);
24048
24049
0
    start_addr = s->cur_func->byte_code.size;
24050
0
    if (hasval) {
24051
        /* consume value from the stack */
24052
0
        emit_op(s, OP_dup);
24053
0
        emit_op(s, OP_undefined);
24054
0
        emit_op(s, OP_strict_eq);
24055
0
        emit_goto(s, OP_if_true, label_parse);
24056
0
        emit_label(s, label_assign);
24057
0
    } else {
24058
0
        emit_goto(s, OP_goto, label_parse);
24059
0
        emit_label(s, label_assign);
24060
        /* leave value on the stack */
24061
0
        emit_op(s, OP_dup);
24062
0
    }
24063
0
    assign_addr = s->cur_func->byte_code.size;
24064
0
    if (s->token.val == '{') {
24065
0
        if (next_token(s))
24066
0
            return -1;
24067
        /* throw an exception if the value cannot be converted to an object */
24068
0
        emit_op(s, OP_to_object);
24069
0
        if (has_ellipsis) {
24070
            /* add excludeList on stack just below src object */
24071
0
            emit_op(s, OP_object);
24072
0
            emit_op(s, OP_swap);
24073
0
        }
24074
0
        while (s->token.val != '}') {
24075
0
            int prop_type;
24076
0
            if (s->token.val == TOK_ELLIPSIS) {
24077
0
                if (!has_ellipsis) {
24078
0
                    JS_ThrowInternalError(s->ctx, "unexpected ellipsis token");
24079
0
                    return -1;
24080
0
                }
24081
0
                if (next_token(s))
24082
0
                    return -1;
24083
0
                if (tok) {
24084
0
                    var_name = js_parse_destructuring_var(s, tok, is_arg);
24085
0
                    if (var_name == JS_ATOM_NULL)
24086
0
                        return -1;
24087
0
                    opcode = OP_scope_get_var;
24088
0
                    scope = s->cur_func->scope_level;
24089
0
                    label_lvalue = -1;
24090
0
                    depth_lvalue = 0;
24091
0
                } else {
24092
0
                    if (js_parse_left_hand_side_expr(s))
24093
0
                        return -1;
24094
24095
0
                    if (get_lvalue(s, &opcode, &scope, &var_name,
24096
0
                                   &label_lvalue, &depth_lvalue, FALSE, '{'))
24097
0
                        return -1;
24098
0
                }
24099
0
                if (s->token.val != '}') {
24100
0
                    js_parse_error(s, "assignment rest property must be last");
24101
0
                    goto var_error;
24102
0
                }
24103
0
                emit_op(s, OP_object);  /* target */
24104
0
                emit_op(s, OP_copy_data_properties);
24105
0
                emit_u8(s, 0 | ((depth_lvalue + 1) << 2) | ((depth_lvalue + 2) << 5));
24106
0
                goto set_val;
24107
0
            }
24108
0
            prop_type = js_parse_property_name(s, &prop_name, FALSE, TRUE, FALSE);
24109
0
            if (prop_type < 0)
24110
0
                return -1;
24111
0
            var_name = JS_ATOM_NULL;
24112
0
            opcode = OP_scope_get_var;
24113
0
            scope = s->cur_func->scope_level;
24114
0
            label_lvalue = -1;
24115
0
            depth_lvalue = 0;
24116
0
            if (prop_type == PROP_TYPE_IDENT) {
24117
0
                if (next_token(s))
24118
0
                    goto prop_error;
24119
0
                if ((s->token.val == '[' || s->token.val == '{')
24120
0
                    &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
24121
0
                         tok1 == '=' || tok1 == '}')) {
24122
0
                    if (prop_name == JS_ATOM_NULL) {
24123
                        /* computed property name on stack */
24124
0
                        if (has_ellipsis) {
24125
                            /* define the property in excludeList */
24126
0
                            emit_op(s, OP_to_propkey); /* avoid calling ToString twice */
24127
0
                            emit_op(s, OP_perm3); /* TOS: src excludeList prop */
24128
0
                            emit_op(s, OP_null); /* TOS: src excludeList prop null */
24129
0
                            emit_op(s, OP_define_array_el); /* TOS: src excludeList prop */
24130
0
                            emit_op(s, OP_perm3); /* TOS: excludeList src prop */
24131
0
                        }
24132
                        /* get the computed property from the source object */
24133
0
                        emit_op(s, OP_get_array_el2);
24134
0
                    } else {
24135
                        /* named property */
24136
0
                        if (has_ellipsis) {
24137
                            /* define the property in excludeList */
24138
0
                            emit_op(s, OP_swap); /* TOS: src excludeList */
24139
0
                            emit_op(s, OP_null); /* TOS: src excludeList null */
24140
0
                            emit_op(s, OP_define_field); /* TOS: src excludeList */
24141
0
                            emit_atom(s, prop_name);
24142
0
                            emit_op(s, OP_swap); /* TOS: excludeList src */
24143
0
                        }
24144
                        /* get the named property from the source object */
24145
0
                        emit_op(s, OP_get_field2);
24146
0
                        emit_u32(s, prop_name);
24147
0
                    }
24148
0
                    if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE) < 0)
24149
0
                        return -1;
24150
0
                    if (s->token.val == '}')
24151
0
                        break;
24152
                    /* accept a trailing comma before the '}' */
24153
0
                    if (js_parse_expect(s, ','))
24154
0
                        return -1;
24155
0
                    continue;
24156
0
                }
24157
0
                if (prop_name == JS_ATOM_NULL) {
24158
0
                    emit_op(s, OP_to_propkey2);
24159
0
                    if (has_ellipsis) {
24160
                        /* define the property in excludeList */
24161
0
                        emit_op(s, OP_perm3);
24162
0
                        emit_op(s, OP_null);
24163
0
                        emit_op(s, OP_define_array_el);
24164
0
                        emit_op(s, OP_perm3);
24165
0
                    }
24166
                    /* source prop -- source source prop */
24167
0
                    emit_op(s, OP_dup1);
24168
0
                } else {
24169
0
                    if (has_ellipsis) {
24170
                        /* define the property in excludeList */
24171
0
                        emit_op(s, OP_swap);
24172
0
                        emit_op(s, OP_null);
24173
0
                        emit_op(s, OP_define_field);
24174
0
                        emit_atom(s, prop_name);
24175
0
                        emit_op(s, OP_swap);
24176
0
                    }
24177
                    /* source -- source source */
24178
0
                    emit_op(s, OP_dup);
24179
0
                }
24180
0
                if (tok) {
24181
0
                    var_name = js_parse_destructuring_var(s, tok, is_arg);
24182
0
                    if (var_name == JS_ATOM_NULL)
24183
0
                        goto prop_error;
24184
0
                } else {
24185
0
                    if (js_parse_left_hand_side_expr(s))
24186
0
                        goto prop_error;
24187
0
                lvalue:
24188
0
                    if (get_lvalue(s, &opcode, &scope, &var_name,
24189
0
                                   &label_lvalue, &depth_lvalue, FALSE, '{'))
24190
0
                        goto prop_error;
24191
                    /* swap ref and lvalue object if any */
24192
0
                    if (prop_name == JS_ATOM_NULL) {
24193
0
                        switch(depth_lvalue) {
24194
0
                        case 1:
24195
                            /* source prop x -> x source prop */
24196
0
                            emit_op(s, OP_rot3r);
24197
0
                            break;
24198
0
                        case 2:
24199
                            /* source prop x y -> x y source prop */
24200
0
                            emit_op(s, OP_swap2);   /* t p2 s p1 */
24201
0
                            break;
24202
0
                        case 3:
24203
                            /* source prop x y z -> x y z source prop */
24204
0
                            emit_op(s, OP_rot5l);
24205
0
                            emit_op(s, OP_rot5l);
24206
0
                            break;
24207
0
                        }
24208
0
                    } else {
24209
0
                        switch(depth_lvalue) {
24210
0
                        case 1:
24211
                            /* source x -> x source */
24212
0
                            emit_op(s, OP_swap);
24213
0
                            break;
24214
0
                        case 2:
24215
                            /* source x y -> x y source */
24216
0
                            emit_op(s, OP_rot3l);
24217
0
                            break;
24218
0
                        case 3:
24219
                            /* source x y z -> x y z source */
24220
0
                            emit_op(s, OP_rot4l);
24221
0
                            break;
24222
0
                        }
24223
0
                    }
24224
0
                }
24225
0
                if (prop_name == JS_ATOM_NULL) {
24226
                    /* computed property name on stack */
24227
                    /* XXX: should have OP_get_array_el2x with depth */
24228
                    /* source prop -- val */
24229
0
                    emit_op(s, OP_get_array_el);
24230
0
                } else {
24231
                    /* named property */
24232
                    /* XXX: should have OP_get_field2x with depth */
24233
                    /* source -- val */
24234
0
                    emit_op(s, OP_get_field);
24235
0
                    emit_u32(s, prop_name);
24236
0
                }
24237
0
            } else {
24238
                /* prop_type = PROP_TYPE_VAR, cannot be a computed property */
24239
0
                if (is_arg && js_parse_check_duplicate_parameter(s, prop_name))
24240
0
                    goto prop_error;
24241
0
                if ((s->cur_func->js_mode & JS_MODE_STRICT) &&
24242
0
                    (prop_name == JS_ATOM_eval || prop_name == JS_ATOM_arguments)) {
24243
0
                    js_parse_error(s, "invalid destructuring target");
24244
0
                    goto prop_error;
24245
0
                }
24246
0
                if (has_ellipsis) {
24247
                    /* define the property in excludeList */
24248
0
                    emit_op(s, OP_swap);
24249
0
                    emit_op(s, OP_null);
24250
0
                    emit_op(s, OP_define_field);
24251
0
                    emit_atom(s, prop_name);
24252
0
                    emit_op(s, OP_swap);
24253
0
                }
24254
0
                if (!tok || tok == TOK_VAR) {
24255
                    /* generate reference */
24256
                    /* source -- source source */
24257
0
                    emit_op(s, OP_dup);
24258
0
                    emit_op(s, OP_scope_get_var);
24259
0
                    emit_atom(s, prop_name);
24260
0
                    emit_u16(s, s->cur_func->scope_level);
24261
0
                    goto lvalue;
24262
0
                }
24263
0
                var_name = JS_DupAtom(s->ctx, prop_name);
24264
                /* source -- source val */
24265
0
                emit_op(s, OP_get_field2);
24266
0
                emit_u32(s, prop_name);
24267
0
            }
24268
0
        set_val:
24269
0
            if (tok) {
24270
0
                if (js_define_var(s, var_name, tok))
24271
0
                    goto var_error;
24272
0
                scope = s->cur_func->scope_level;
24273
0
            }
24274
0
            if (s->token.val == '=') {  /* handle optional default value */
24275
0
                int label_hasval;
24276
0
                emit_op(s, OP_dup);
24277
0
                emit_op(s, OP_undefined);
24278
0
                emit_op(s, OP_strict_eq);
24279
0
                label_hasval = emit_goto(s, OP_if_false, -1);
24280
0
                if (next_token(s))
24281
0
                    goto var_error;
24282
0
                emit_op(s, OP_drop);
24283
0
                if (js_parse_assign_expr(s))
24284
0
                    goto var_error;
24285
0
                if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
24286
0
                    set_object_name(s, var_name);
24287
0
                emit_label(s, label_hasval);
24288
0
            }
24289
            /* store value into lvalue object */
24290
0
            put_lvalue(s, opcode, scope, var_name, label_lvalue,
24291
0
                       PUT_LVALUE_NOKEEP_DEPTH,
24292
0
                       (tok == TOK_CONST || tok == TOK_LET));
24293
0
            if (s->token.val == '}')
24294
0
                break;
24295
            /* accept a trailing comma before the '}' */
24296
0
            if (js_parse_expect(s, ','))
24297
0
                return -1;
24298
0
        }
24299
        /* drop the source object */
24300
0
        emit_op(s, OP_drop);
24301
0
        if (has_ellipsis) {
24302
0
            emit_op(s, OP_drop); /* pop excludeList */
24303
0
        }
24304
0
        if (next_token(s))
24305
0
            return -1;
24306
0
    } else if (s->token.val == '[') {
24307
0
        BOOL has_spread;
24308
0
        int enum_depth;
24309
0
        BlockEnv block_env;
24310
24311
0
        if (next_token(s))
24312
0
            return -1;
24313
        /* the block environment is only needed in generators in case
24314
           'yield' triggers a 'return' */
24315
0
        push_break_entry(s->cur_func, &block_env,
24316
0
                         JS_ATOM_NULL, -1, -1, 2);
24317
0
        block_env.has_iterator = TRUE;
24318
0
        emit_op(s, OP_for_of_start);
24319
0
        has_spread = FALSE;
24320
0
        while (s->token.val != ']') {
24321
            /* get the next value */
24322
0
            if (s->token.val == TOK_ELLIPSIS) {
24323
0
                if (next_token(s))
24324
0
                    return -1;
24325
0
                if (s->token.val == ',' || s->token.val == ']')
24326
0
                    return js_parse_error(s, "missing binding pattern...");
24327
0
                has_spread = TRUE;
24328
0
            }
24329
0
            if (s->token.val == ',') {
24330
                /* do nothing, skip the value, has_spread is false */
24331
0
                emit_op(s, OP_for_of_next);
24332
0
                emit_u8(s, 0);
24333
0
                emit_op(s, OP_drop);
24334
0
                emit_op(s, OP_drop);
24335
0
            } else if ((s->token.val == '[' || s->token.val == '{')
24336
0
                   &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
24337
0
                        tok1 == '=' || tok1 == ']')) {
24338
0
                if (has_spread) {
24339
0
                    if (tok1 == '=')
24340
0
                        return js_parse_error(s, "rest element cannot have a default value");
24341
0
                    js_emit_spread_code(s, 0);
24342
0
                } else {
24343
0
                    emit_op(s, OP_for_of_next);
24344
0
                    emit_u8(s, 0);
24345
0
                    emit_op(s, OP_drop);
24346
0
                }
24347
0
                if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
24348
0
                    return -1;
24349
0
            } else {
24350
0
                var_name = JS_ATOM_NULL;
24351
0
                enum_depth = 0;
24352
0
                if (tok) {
24353
0
                    var_name = js_parse_destructuring_var(s, tok, is_arg);
24354
0
                    if (var_name == JS_ATOM_NULL)
24355
0
                        goto var_error;
24356
0
                    if (js_define_var(s, var_name, tok))
24357
0
                        goto var_error;
24358
0
                    opcode = OP_scope_get_var;
24359
0
                    scope = s->cur_func->scope_level;
24360
0
                } else {
24361
0
                    if (js_parse_left_hand_side_expr(s))
24362
0
                        return -1;
24363
0
                    if (get_lvalue(s, &opcode, &scope, &var_name,
24364
0
                                   &label_lvalue, &enum_depth, FALSE, '[')) {
24365
0
                        return -1;
24366
0
                    }
24367
0
                }
24368
0
                if (has_spread) {
24369
0
                    js_emit_spread_code(s, enum_depth);
24370
0
                } else {
24371
0
                    emit_op(s, OP_for_of_next);
24372
0
                    emit_u8(s, enum_depth);
24373
0
                    emit_op(s, OP_drop);
24374
0
                }
24375
0
                if (s->token.val == '=' && !has_spread) {
24376
                    /* handle optional default value */
24377
0
                    int label_hasval;
24378
0
                    emit_op(s, OP_dup);
24379
0
                    emit_op(s, OP_undefined);
24380
0
                    emit_op(s, OP_strict_eq);
24381
0
                    label_hasval = emit_goto(s, OP_if_false, -1);
24382
0
                    if (next_token(s))
24383
0
                        goto var_error;
24384
0
                    emit_op(s, OP_drop);
24385
0
                    if (js_parse_assign_expr(s))
24386
0
                        goto var_error;
24387
0
                    if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
24388
0
                        set_object_name(s, var_name);
24389
0
                    emit_label(s, label_hasval);
24390
0
                }
24391
                /* store value into lvalue object */
24392
0
                put_lvalue(s, opcode, scope, var_name,
24393
0
                           label_lvalue, PUT_LVALUE_NOKEEP_DEPTH,
24394
0
                           (tok == TOK_CONST || tok == TOK_LET));
24395
0
            }
24396
0
            if (s->token.val == ']')
24397
0
                break;
24398
0
            if (has_spread)
24399
0
                return js_parse_error(s, "rest element must be the last one");
24400
            /* accept a trailing comma before the ']' */
24401
0
            if (js_parse_expect(s, ','))
24402
0
                return -1;
24403
0
        }
24404
        /* close iterator object:
24405
           if completed, enum_obj has been replaced by undefined */
24406
0
        emit_op(s, OP_iterator_close);
24407
0
        pop_break_entry(s->cur_func);
24408
0
        if (next_token(s))
24409
0
            return -1;
24410
0
    } else {
24411
0
        return js_parse_error(s, "invalid assignment syntax");
24412
0
    }
24413
0
    if (s->token.val == '=' && allow_initializer) {
24414
0
        label_done = emit_goto(s, OP_goto, -1);
24415
0
        if (next_token(s))
24416
0
            return -1;
24417
0
        emit_label(s, label_parse);
24418
0
        if (hasval)
24419
0
            emit_op(s, OP_drop);
24420
0
        if (js_parse_assign_expr(s))
24421
0
            return -1;
24422
0
        emit_goto(s, OP_goto, label_assign);
24423
0
        emit_label(s, label_done);
24424
0
        has_initializer = TRUE;
24425
0
    } else {
24426
        /* normally hasval is true except if
24427
           js_parse_skip_parens_token() was wrong in the parsing */
24428
        //        assert(hasval);
24429
0
        if (!hasval) {
24430
0
            js_parse_error(s, "too complicated destructuring expression");
24431
0
            return -1;
24432
0
        }
24433
        /* remove test and decrement label ref count */
24434
0
        memset(s->cur_func->byte_code.buf + start_addr, OP_nop,
24435
0
               assign_addr - start_addr);
24436
0
        s->cur_func->label_slots[label_parse].ref_count--;
24437
0
        has_initializer = FALSE;
24438
0
    }
24439
0
    return has_initializer;
24440
24441
0
 prop_error:
24442
0
    JS_FreeAtom(s->ctx, prop_name);
24443
0
 var_error:
24444
0
    JS_FreeAtom(s->ctx, var_name);
24445
0
    return -1;
24446
0
}
24447
24448
typedef enum FuncCallType {
24449
    FUNC_CALL_NORMAL,
24450
    FUNC_CALL_NEW,
24451
    FUNC_CALL_SUPER_CTOR,
24452
    FUNC_CALL_TEMPLATE,
24453
} FuncCallType;
24454
24455
static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
24456
                                int drop_count)
24457
0
{
24458
0
    int label_next, i;
24459
0
    if (*poptional_chaining_label < 0)
24460
0
        *poptional_chaining_label = new_label(s);
24461
   /* XXX: could be more efficient with a specific opcode */
24462
0
    emit_op(s, OP_dup);
24463
0
    emit_op(s, OP_is_undefined_or_null);
24464
0
    label_next = emit_goto(s, OP_if_false, -1);
24465
0
    for(i = 0; i < drop_count; i++)
24466
0
        emit_op(s, OP_drop);
24467
0
    emit_op(s, OP_undefined);
24468
0
    emit_goto(s, OP_goto, *poptional_chaining_label);
24469
0
    emit_label(s, label_next);
24470
0
}
24471
24472
/* allowed parse_flags: PF_POSTFIX_CALL */
24473
static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
24474
5.52M
{
24475
5.52M
    FuncCallType call_type;
24476
5.52M
    int optional_chaining_label;
24477
5.52M
    BOOL accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0;
24478
24479
5.52M
    call_type = FUNC_CALL_NORMAL;
24480
5.52M
    switch(s->token.val) {
24481
5.52M
    case TOK_NUMBER:
24482
5.52M
        {
24483
5.52M
            JSValue val;
24484
5.52M
            val = s->token.u.num.val;
24485
24486
5.52M
            if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
24487
5.52M
                emit_op(s, OP_push_i32);
24488
5.52M
                emit_u32(s, JS_VALUE_GET_INT(val));
24489
5.52M
            } else
24490
7
#ifdef CONFIG_BIGNUM
24491
7
            if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
24492
0
                slimb_t e;
24493
0
                int ret;
24494
24495
                /* need a runtime conversion */
24496
                /* XXX: could add a cache and/or do it once at
24497
                   the start of the function */
24498
0
                if (emit_push_const(s, val, 0) < 0)
24499
0
                    return -1;
24500
0
                e = s->token.u.num.exponent;
24501
0
                if (e == (int32_t)e) {
24502
0
                    emit_op(s, OP_push_i32);
24503
0
                    emit_u32(s, e);
24504
0
                } else {
24505
0
                    val = JS_NewBigInt64_1(s->ctx, e);
24506
0
                    if (JS_IsException(val))
24507
0
                        return -1;
24508
0
                    ret = emit_push_const(s, val, 0);
24509
0
                    JS_FreeValue(s->ctx, val);
24510
0
                    if (ret < 0)
24511
0
                        return -1;
24512
0
                }
24513
0
                emit_op(s, OP_mul_pow10);
24514
0
            } else
24515
7
#endif
24516
7
            {
24517
7
                if (emit_push_const(s, val, 0) < 0)
24518
0
                    return -1;
24519
7
            }
24520
5.52M
        }
24521
5.52M
        if (next_token(s))
24522
1
            return -1;
24523
5.52M
        break;
24524
5.52M
    case TOK_TEMPLATE:
24525
0
        if (js_parse_template(s, 0, NULL))
24526
0
            return -1;
24527
0
        break;
24528
20
    case TOK_STRING:
24529
20
        if (emit_push_const(s, s->token.u.str.str, 1))
24530
0
            return -1;
24531
20
        if (next_token(s))
24532
0
            return -1;
24533
20
        break;
24534
24535
20
    case TOK_DIV_ASSIGN:
24536
0
        s->buf_ptr -= 2;
24537
0
        goto parse_regexp;
24538
0
    case '/':
24539
0
        s->buf_ptr--;
24540
0
    parse_regexp:
24541
0
        {
24542
0
            JSValue str;
24543
0
            int ret, backtrace_flags;
24544
0
            if (!s->ctx->compile_regexp)
24545
0
                return js_parse_error(s, "RegExp are not supported");
24546
            /* the previous token is '/' or '/=', so no need to free */
24547
0
            if (js_parse_regexp(s))
24548
0
                return -1;
24549
0
            ret = emit_push_const(s, s->token.u.regexp.body, 0);
24550
0
            str = s->ctx->compile_regexp(s->ctx, s->token.u.regexp.body,
24551
0
                                         s->token.u.regexp.flags);
24552
0
            if (JS_IsException(str)) {
24553
                /* add the line number info */
24554
0
                backtrace_flags = 0;
24555
0
                if (s->cur_func && s->cur_func->backtrace_barrier)
24556
0
                    backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
24557
0
                build_backtrace(s->ctx, s->ctx->rt->current_exception,
24558
0
                                s->filename, s->token.line_num,
24559
0
                                backtrace_flags);
24560
0
                return -1;
24561
0
            }
24562
0
            ret = emit_push_const(s, str, 0);
24563
0
            JS_FreeValue(s->ctx, str);
24564
0
            if (ret)
24565
0
                return -1;
24566
            /* we use a specific opcode to be sure the correct
24567
               function is called (otherwise the bytecode would have
24568
               to be verified by the RegExp constructor) */
24569
0
            emit_op(s, OP_regexp);
24570
0
            if (next_token(s))
24571
0
                return -1;
24572
0
        }
24573
0
        break;
24574
0
    case '(':
24575
0
        if (js_parse_expr_paren(s))
24576
0
            return -1;
24577
0
        break;
24578
0
    case TOK_FUNCTION:
24579
0
        if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
24580
0
                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
24581
0
                                   s->token.ptr, s->token.line_num))
24582
0
            return -1;
24583
0
        break;
24584
0
    case TOK_CLASS:
24585
0
        if (js_parse_class(s, TRUE, JS_PARSE_EXPORT_NONE))
24586
0
            return -1;
24587
0
        break;
24588
0
    case TOK_NULL:
24589
0
        if (next_token(s))
24590
0
            return -1;
24591
0
        emit_op(s, OP_null);
24592
0
        break;
24593
0
    case TOK_THIS:
24594
0
        if (next_token(s))
24595
0
            return -1;
24596
0
        emit_op(s, OP_scope_get_var);
24597
0
        emit_atom(s, JS_ATOM_this);
24598
0
        emit_u16(s, 0);
24599
0
        break;
24600
0
    case TOK_FALSE:
24601
0
        if (next_token(s))
24602
0
            return -1;
24603
0
        emit_op(s, OP_push_false);
24604
0
        break;
24605
0
    case TOK_TRUE:
24606
0
        if (next_token(s))
24607
0
            return -1;
24608
0
        emit_op(s, OP_push_true);
24609
0
        break;
24610
169
    case TOK_IDENT:
24611
169
        {
24612
169
            JSAtom name;
24613
169
            if (s->token.u.ident.is_reserved) {
24614
0
                return js_parse_error_reserved_identifier(s);
24615
0
            }
24616
169
            if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
24617
169
                peek_token(s, TRUE) != '\n') {
24618
0
                const uint8_t *source_ptr;
24619
0
                int source_line_num;
24620
24621
0
                source_ptr = s->token.ptr;
24622
0
                source_line_num = s->token.line_num;
24623
0
                if (next_token(s))
24624
0
                    return -1;
24625
0
                if (s->token.val == TOK_FUNCTION) {
24626
0
                    if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
24627
0
                                               JS_FUNC_ASYNC, JS_ATOM_NULL,
24628
0
                                               source_ptr, source_line_num))
24629
0
                        return -1;
24630
0
                } else {
24631
0
                    name = JS_DupAtom(s->ctx, JS_ATOM_async);
24632
0
                    goto do_get_var;
24633
0
                }
24634
169
            } else {
24635
169
                if (s->token.u.ident.atom == JS_ATOM_arguments &&
24636
169
                    !s->cur_func->arguments_allowed) {
24637
0
                    js_parse_error(s, "'arguments' identifier is not allowed in class field initializer");
24638
0
                    return -1;
24639
0
                }
24640
169
                name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
24641
169
                if (next_token(s)) {  /* update line number before emitting code */
24642
0
                    JS_FreeAtom(s->ctx, name);
24643
0
                    return -1;
24644
0
                }
24645
169
            do_get_var:
24646
169
                emit_op(s, OP_scope_get_var);
24647
169
                emit_u32(s, name);
24648
169
                emit_u16(s, s->cur_func->scope_level);
24649
169
            }
24650
169
        }
24651
169
        break;
24652
169
    case '{':
24653
21
    case '[':
24654
21
        {
24655
21
            int skip_bits;
24656
21
            if (js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
24657
0
                if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
24658
0
                    return -1;
24659
21
            } else {
24660
21
                if (s->token.val == '{') {
24661
0
                    if (js_parse_object_literal(s))
24662
0
                        return -1;
24663
21
                } else {
24664
21
                    if (js_parse_array_literal(s))
24665
5
                        return -1;
24666
21
                }
24667
21
            }
24668
21
        }
24669
16
        break;
24670
16
    case TOK_NEW:
24671
0
        if (next_token(s))
24672
0
            return -1;
24673
0
        if (s->token.val == '.') {
24674
0
            if (next_token(s))
24675
0
                return -1;
24676
0
            if (!token_is_pseudo_keyword(s, JS_ATOM_target))
24677
0
                return js_parse_error(s, "expecting target");
24678
0
            if (!s->cur_func->new_target_allowed)
24679
0
                return js_parse_error(s, "new.target only allowed within functions");
24680
0
            if (next_token(s))
24681
0
                return -1;
24682
0
            emit_op(s, OP_scope_get_var);
24683
0
            emit_atom(s, JS_ATOM_new_target);
24684
0
            emit_u16(s, 0);
24685
0
        } else {
24686
0
            if (js_parse_postfix_expr(s, 0))
24687
0
                return -1;
24688
0
            accept_lparen = TRUE;
24689
0
            if (s->token.val != '(') {
24690
                /* new operator on an object */
24691
0
                emit_op(s, OP_dup);
24692
0
                emit_op(s, OP_call_constructor);
24693
0
                emit_u16(s, 0);
24694
0
            } else {
24695
0
                call_type = FUNC_CALL_NEW;
24696
0
            }
24697
0
        }
24698
0
        break;
24699
0
    case TOK_SUPER:
24700
0
        if (next_token(s))
24701
0
            return -1;
24702
0
        if (s->token.val == '(') {
24703
0
            if (!s->cur_func->super_call_allowed)
24704
0
                return js_parse_error(s, "super() is only valid in a derived class constructor");
24705
0
            call_type = FUNC_CALL_SUPER_CTOR;
24706
0
        } else if (s->token.val == '.' || s->token.val == '[') {
24707
0
            if (!s->cur_func->super_allowed)
24708
0
                return js_parse_error(s, "'super' is only valid in a method");
24709
0
            emit_op(s, OP_scope_get_var);
24710
0
            emit_atom(s, JS_ATOM_this);
24711
0
            emit_u16(s, 0);
24712
0
            emit_op(s, OP_scope_get_var);
24713
0
            emit_atom(s, JS_ATOM_home_object);
24714
0
            emit_u16(s, 0);
24715
0
            emit_op(s, OP_get_super);
24716
0
        } else {
24717
0
            return js_parse_error(s, "invalid use of 'super'");
24718
0
        }
24719
0
        break;
24720
0
    case TOK_IMPORT:
24721
0
        if (next_token(s))
24722
0
            return -1;
24723
0
        if (s->token.val == '.') {
24724
0
            if (next_token(s))
24725
0
                return -1;
24726
0
            if (!token_is_pseudo_keyword(s, JS_ATOM_meta))
24727
0
                return js_parse_error(s, "meta expected");
24728
0
            if (!s->is_module)
24729
0
                return js_parse_error(s, "import.meta only valid in module code");
24730
0
            if (next_token(s))
24731
0
                return -1;
24732
0
            emit_op(s, OP_special_object);
24733
0
            emit_u8(s, OP_SPECIAL_OBJECT_IMPORT_META);
24734
0
        } else {
24735
0
            if (js_parse_expect(s, '('))
24736
0
                return -1;
24737
0
            if (!accept_lparen)
24738
0
                return js_parse_error(s, "invalid use of 'import()'");
24739
0
            if (js_parse_assign_expr(s))
24740
0
                return -1;
24741
0
            if (js_parse_expect(s, ')'))
24742
0
                return -1;
24743
0
            emit_op(s, OP_import);
24744
0
        }
24745
0
        break;
24746
5
    default:
24747
5
        return js_parse_error(s, "unexpected token in expression: '%.*s'",
24748
5
                              (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
24749
5.52M
    }
24750
24751
5.52M
    optional_chaining_label = -1;
24752
5.52M
    for(;;) {
24753
5.52M
        JSFunctionDef *fd = s->cur_func;
24754
5.52M
        BOOL has_optional_chain = FALSE;
24755
24756
5.52M
        if (s->token.val == TOK_QUESTION_MARK_DOT) {
24757
            /* optional chaining */
24758
0
            if (next_token(s))
24759
0
                return -1;
24760
0
            has_optional_chain = TRUE;
24761
0
            if (s->token.val == '(' && accept_lparen) {
24762
0
                goto parse_func_call;
24763
0
            } else if (s->token.val == '[') {
24764
0
                goto parse_array_access;
24765
0
            } else {
24766
0
                goto parse_property;
24767
0
            }
24768
5.52M
        } else if (s->token.val == TOK_TEMPLATE &&
24769
5.52M
                   call_type == FUNC_CALL_NORMAL) {
24770
0
            if (optional_chaining_label >= 0) {
24771
0
                return js_parse_error(s, "template literal cannot appear in an optional chain");
24772
0
            }
24773
0
            call_type = FUNC_CALL_TEMPLATE;
24774
0
            goto parse_func_call2;
24775
5.52M
        } else if (s->token.val == '(' && accept_lparen) {
24776
2
            int opcode, arg_count, drop_count;
24777
24778
            /* function call */
24779
2
        parse_func_call:
24780
2
            if (next_token(s))
24781
1
                return -1;
24782
24783
1
            if (call_type == FUNC_CALL_NORMAL) {
24784
1
            parse_func_call2:
24785
1
                switch(opcode = get_prev_opcode(fd)) {
24786
0
                case OP_get_field:
24787
                    /* keep the object on the stack */
24788
0
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
24789
0
                    drop_count = 2;
24790
0
                    break;
24791
0
                case OP_get_field_opt_chain:
24792
0
                    {
24793
0
                        int opt_chain_label, next_label;
24794
0
                        opt_chain_label = get_u32(fd->byte_code.buf +
24795
0
                                                  fd->last_opcode_pos + 1 + 4 + 1);
24796
                        /* keep the object on the stack */
24797
0
                        fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
24798
0
                        fd->byte_code.size = fd->last_opcode_pos + 1 + 4;
24799
0
                        next_label = emit_goto(s, OP_goto, -1);
24800
0
                        emit_label(s, opt_chain_label);
24801
                        /* need an additional undefined value for the
24802
                           case where the optional field does not
24803
                           exists */
24804
0
                        emit_op(s, OP_undefined);
24805
0
                        emit_label(s, next_label);
24806
0
                        drop_count = 2;
24807
0
                        opcode = OP_get_field;
24808
0
                    }
24809
0
                    break;
24810
0
                case OP_scope_get_private_field:
24811
                    /* keep the object on the stack */
24812
0
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2;
24813
0
                    drop_count = 2;
24814
0
                    break;
24815
0
                case OP_get_array_el:
24816
                    /* keep the object on the stack */
24817
0
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
24818
0
                    drop_count = 2;
24819
0
                    break;
24820
0
                case OP_get_array_el_opt_chain:
24821
0
                    {
24822
0
                        int opt_chain_label, next_label;
24823
0
                        opt_chain_label = get_u32(fd->byte_code.buf +
24824
0
                                                  fd->last_opcode_pos + 1 + 1);
24825
                        /* keep the object on the stack */
24826
0
                        fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
24827
0
                        fd->byte_code.size = fd->last_opcode_pos + 1;
24828
0
                        next_label = emit_goto(s, OP_goto, -1);
24829
0
                        emit_label(s, opt_chain_label);
24830
                        /* need an additional undefined value for the
24831
                           case where the optional field does not
24832
                           exists */
24833
0
                        emit_op(s, OP_undefined);
24834
0
                        emit_label(s, next_label);
24835
0
                        drop_count = 2;
24836
0
                        opcode = OP_get_array_el;
24837
0
                    }
24838
0
                    break;
24839
0
                case OP_scope_get_var:
24840
0
                    {
24841
0
                        JSAtom name;
24842
0
                        int scope;
24843
0
                        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
24844
0
                        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
24845
0
                        if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL && !has_optional_chain) {
24846
                            /* direct 'eval' */
24847
0
                            opcode = OP_eval;
24848
0
                        } else {
24849
                            /* verify if function name resolves to a simple
24850
                               get_loc/get_arg: a function call inside a `with`
24851
                               statement can resolve to a method call of the
24852
                               `with` context object
24853
                             */
24854
                            /* XXX: always generate the OP_scope_get_ref
24855
                               and remove it in variable resolution
24856
                               pass ? */
24857
0
                            if (has_with_scope(fd, scope)) {
24858
0
                                opcode = OP_scope_get_ref;
24859
0
                                fd->byte_code.buf[fd->last_opcode_pos] = opcode;
24860
0
                            }
24861
0
                        }
24862
0
                        drop_count = 1;
24863
0
                    }
24864
0
                    break;
24865
0
                case OP_get_super_value:
24866
0
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el;
24867
                    /* on stack: this func_obj */
24868
0
                    opcode = OP_get_array_el;
24869
0
                    drop_count = 2;
24870
0
                    break;
24871
1
                default:
24872
1
                    opcode = OP_invalid;
24873
1
                    drop_count = 1;
24874
1
                    break;
24875
1
                }
24876
1
                if (has_optional_chain) {
24877
0
                    optional_chain_test(s, &optional_chaining_label,
24878
0
                                        drop_count);
24879
0
                }
24880
1
            } else {
24881
0
                opcode = OP_invalid;
24882
0
            }
24883
24884
1
            if (call_type == FUNC_CALL_TEMPLATE) {
24885
0
                if (js_parse_template(s, 1, &arg_count))
24886
0
                    return -1;
24887
0
                goto emit_func_call;
24888
1
            } else if (call_type == FUNC_CALL_SUPER_CTOR) {
24889
0
                emit_op(s, OP_scope_get_var);
24890
0
                emit_atom(s, JS_ATOM_this_active_func);
24891
0
                emit_u16(s, 0);
24892
24893
0
                emit_op(s, OP_get_super);
24894
24895
0
                emit_op(s, OP_scope_get_var);
24896
0
                emit_atom(s, JS_ATOM_new_target);
24897
0
                emit_u16(s, 0);
24898
1
            } else if (call_type == FUNC_CALL_NEW) {
24899
0
                emit_op(s, OP_dup); /* new.target = function */
24900
0
            }
24901
24902
            /* parse arguments */
24903
1
            arg_count = 0;
24904
65.5k
            while (s->token.val != ')') {
24905
65.5k
                if (arg_count >= 65535) {
24906
1
                    return js_parse_error(s, "Too many call arguments");
24907
1
                }
24908
65.5k
                if (s->token.val == TOK_ELLIPSIS)
24909
0
                    break;
24910
65.5k
                if (js_parse_assign_expr(s))
24911
0
                    return -1;
24912
65.5k
                arg_count++;
24913
65.5k
                if (s->token.val == ')')
24914
0
                    break;
24915
                /* accept a trailing comma before the ')' */
24916
65.5k
                if (js_parse_expect(s, ','))
24917
0
                    return -1;
24918
65.5k
            }
24919
0
            if (s->token.val == TOK_ELLIPSIS) {
24920
0
                emit_op(s, OP_array_from);
24921
0
                emit_u16(s, arg_count);
24922
0
                emit_op(s, OP_push_i32);
24923
0
                emit_u32(s, arg_count);
24924
24925
                /* on stack: array idx */
24926
0
                while (s->token.val != ')') {
24927
0
                    if (s->token.val == TOK_ELLIPSIS) {
24928
0
                        if (next_token(s))
24929
0
                            return -1;
24930
0
                        if (js_parse_assign_expr(s))
24931
0
                            return -1;
24932
0
#if 1
24933
                        /* XXX: could pass is_last indicator? */
24934
0
                        emit_op(s, OP_append);
24935
#else
24936
                        int label_next, label_done;
24937
                        label_next = new_label(s);
24938
                        label_done = new_label(s);
24939
                        /* push enumerate object below array/idx pair */
24940
                        emit_op(s, OP_for_of_start);
24941
                        emit_op(s, OP_rot5l);
24942
                        emit_op(s, OP_rot5l);
24943
                        emit_label(s, label_next);
24944
                        /* on stack: enum_rec array idx */
24945
                        emit_op(s, OP_for_of_next);
24946
                        emit_u8(s, 2);
24947
                        emit_goto(s, OP_if_true, label_done);
24948
                        /* append element */
24949
                        /* enum_rec array idx val -> enum_rec array new_idx */
24950
                        emit_op(s, OP_define_array_el);
24951
                        emit_op(s, OP_inc);
24952
                        emit_goto(s, OP_goto, label_next);
24953
                        emit_label(s, label_done);
24954
                        /* close enumeration, drop enum_rec and idx */
24955
                        emit_op(s, OP_drop); /* drop undef */
24956
                        emit_op(s, OP_nip1); /* drop enum_rec */
24957
                        emit_op(s, OP_nip1);
24958
                        emit_op(s, OP_nip1);
24959
#endif
24960
0
                    } else {
24961
0
                        if (js_parse_assign_expr(s))
24962
0
                            return -1;
24963
                        /* array idx val */
24964
0
                        emit_op(s, OP_define_array_el);
24965
0
                        emit_op(s, OP_inc);
24966
0
                    }
24967
0
                    if (s->token.val == ')')
24968
0
                        break;
24969
                    /* accept a trailing comma before the ')' */
24970
0
                    if (js_parse_expect(s, ','))
24971
0
                        return -1;
24972
0
                }
24973
0
                if (next_token(s))
24974
0
                    return -1;
24975
                /* drop the index */
24976
0
                emit_op(s, OP_drop);
24977
24978
                /* apply function call */
24979
0
                switch(opcode) {
24980
0
                case OP_get_field:
24981
0
                case OP_scope_get_private_field:
24982
0
                case OP_get_array_el:
24983
0
                case OP_scope_get_ref:
24984
                    /* obj func array -> func obj array */
24985
0
                    emit_op(s, OP_perm3);
24986
0
                    emit_op(s, OP_apply);
24987
0
                    emit_u16(s, call_type == FUNC_CALL_NEW);
24988
0
                    break;
24989
0
                case OP_eval:
24990
0
                    emit_op(s, OP_apply_eval);
24991
0
                    emit_u16(s, fd->scope_level);
24992
0
                    fd->has_eval_call = TRUE;
24993
0
                    break;
24994
0
                default:
24995
0
                    if (call_type == FUNC_CALL_SUPER_CTOR) {
24996
0
                        emit_op(s, OP_apply);
24997
0
                        emit_u16(s, 1);
24998
                        /* set the 'this' value */
24999
0
                        emit_op(s, OP_dup);
25000
0
                        emit_op(s, OP_scope_put_var_init);
25001
0
                        emit_atom(s, JS_ATOM_this);
25002
0
                        emit_u16(s, 0);
25003
25004
0
                        emit_class_field_init(s);
25005
0
                    } else if (call_type == FUNC_CALL_NEW) {
25006
                        /* obj func array -> func obj array */
25007
0
                        emit_op(s, OP_perm3);
25008
0
                        emit_op(s, OP_apply);
25009
0
                        emit_u16(s, 1);
25010
0
                    } else {
25011
                        /* func array -> func undef array */
25012
0
                        emit_op(s, OP_undefined);
25013
0
                        emit_op(s, OP_swap);
25014
0
                        emit_op(s, OP_apply);
25015
0
                        emit_u16(s, 0);
25016
0
                    }
25017
0
                    break;
25018
0
                }
25019
0
            } else {
25020
0
                if (next_token(s))
25021
0
                    return -1;
25022
0
            emit_func_call:
25023
0
                switch(opcode) {
25024
0
                case OP_get_field:
25025
0
                case OP_scope_get_private_field:
25026
0
                case OP_get_array_el:
25027
0
                case OP_scope_get_ref:
25028
0
                    emit_op(s, OP_call_method);
25029
0
                    emit_u16(s, arg_count);
25030
0
                    break;
25031
0
                case OP_eval:
25032
0
                    emit_op(s, OP_eval);
25033
0
                    emit_u16(s, arg_count);
25034
0
                    emit_u16(s, fd->scope_level);
25035
0
                    fd->has_eval_call = TRUE;
25036
0
                    break;
25037
0
                default:
25038
0
                    if (call_type == FUNC_CALL_SUPER_CTOR) {
25039
0
                        emit_op(s, OP_call_constructor);
25040
0
                        emit_u16(s, arg_count);
25041
25042
                        /* set the 'this' value */
25043
0
                        emit_op(s, OP_dup);
25044
0
                        emit_op(s, OP_scope_put_var_init);
25045
0
                        emit_atom(s, JS_ATOM_this);
25046
0
                        emit_u16(s, 0);
25047
25048
0
                        emit_class_field_init(s);
25049
0
                    } else if (call_type == FUNC_CALL_NEW) {
25050
0
                        emit_op(s, OP_call_constructor);
25051
0
                        emit_u16(s, arg_count);
25052
0
                    } else {
25053
0
                        emit_op(s, OP_call);
25054
0
                        emit_u16(s, arg_count);
25055
0
                    }
25056
0
                    break;
25057
0
                }
25058
0
            }
25059
0
            call_type = FUNC_CALL_NORMAL;
25060
5.52M
        } else if (s->token.val == '.') {
25061
78
            if (next_token(s))
25062
0
                return -1;
25063
78
        parse_property:
25064
78
            if (s->token.val == TOK_PRIVATE_NAME) {
25065
                /* private class field */
25066
0
                if (get_prev_opcode(fd) == OP_get_super) {
25067
0
                    return js_parse_error(s, "private class field forbidden after super");
25068
0
                }
25069
0
                if (has_optional_chain) {
25070
0
                    optional_chain_test(s, &optional_chaining_label, 1);
25071
0
                }
25072
0
                emit_op(s, OP_scope_get_private_field);
25073
0
                emit_atom(s, s->token.u.ident.atom);
25074
0
                emit_u16(s, s->cur_func->scope_level);
25075
78
            } else {
25076
78
                if (!token_is_ident(s->token.val)) {
25077
0
                    return js_parse_error(s, "expecting field name");
25078
0
                }
25079
78
                if (get_prev_opcode(fd) == OP_get_super) {
25080
0
                    JSValue val;
25081
0
                    int ret;
25082
0
                    val = JS_AtomToValue(s->ctx, s->token.u.ident.atom);
25083
0
                    ret = emit_push_const(s, val, 1);
25084
0
                    JS_FreeValue(s->ctx, val);
25085
0
                    if (ret)
25086
0
                        return -1;
25087
0
                    emit_op(s, OP_get_super_value);
25088
78
                } else {
25089
78
                    if (has_optional_chain) {
25090
0
                        optional_chain_test(s, &optional_chaining_label, 1);
25091
0
                    }
25092
78
                    emit_op(s, OP_get_field);
25093
78
                    emit_atom(s, s->token.u.ident.atom);
25094
78
                }
25095
78
            }
25096
78
            if (next_token(s))
25097
0
                return -1;
25098
5.52M
        } else if (s->token.val == '[') {
25099
0
            int prev_op;
25100
25101
0
        parse_array_access:
25102
0
            prev_op = get_prev_opcode(fd);
25103
0
            if (has_optional_chain) {
25104
0
                optional_chain_test(s, &optional_chaining_label, 1);
25105
0
            }
25106
0
            if (next_token(s))
25107
0
                return -1;
25108
0
            if (js_parse_expr(s))
25109
0
                return -1;
25110
0
            if (js_parse_expect(s, ']'))
25111
0
                return -1;
25112
0
            if (prev_op == OP_get_super) {
25113
0
                emit_op(s, OP_get_super_value);
25114
0
            } else {
25115
0
                emit_op(s, OP_get_array_el);
25116
0
            }
25117
5.52M
        } else {
25118
5.52M
            break;
25119
5.52M
        }
25120
5.52M
    }
25121
5.52M
    if (optional_chaining_label >= 0) {
25122
0
        JSFunctionDef *fd = s->cur_func;
25123
0
        int opcode;
25124
0
        emit_label_raw(s, optional_chaining_label);
25125
        /* modify the last opcode so that it is an indicator of an
25126
           optional chain */
25127
0
        opcode = get_prev_opcode(fd);
25128
0
        if (opcode == OP_get_field || opcode == OP_get_array_el) {
25129
0
            if (opcode == OP_get_field)
25130
0
                opcode = OP_get_field_opt_chain;
25131
0
            else
25132
0
                opcode = OP_get_array_el_opt_chain;
25133
0
            fd->byte_code.buf[fd->last_opcode_pos] = opcode;
25134
0
        } else {
25135
0
            fd->last_opcode_pos = -1;
25136
0
        }
25137
0
    }
25138
5.52M
    return 0;
25139
5.52M
}
25140
25141
static __exception int js_parse_delete(JSParseState *s)
25142
0
{
25143
0
    JSFunctionDef *fd = s->cur_func;
25144
0
    JSAtom name;
25145
0
    int opcode;
25146
25147
0
    if (next_token(s))
25148
0
        return -1;
25149
0
    if (js_parse_unary(s, PF_POW_FORBIDDEN))
25150
0
        return -1;
25151
0
    switch(opcode = get_prev_opcode(fd)) {
25152
0
    case OP_get_field:
25153
0
    case OP_get_field_opt_chain:
25154
0
        {
25155
0
            JSValue val;
25156
0
            int ret, opt_chain_label, next_label;
25157
0
            if (opcode == OP_get_field_opt_chain) {
25158
0
                opt_chain_label = get_u32(fd->byte_code.buf +
25159
0
                                          fd->last_opcode_pos + 1 + 4 + 1);
25160
0
            } else {
25161
0
                opt_chain_label = -1;
25162
0
            }
25163
0
            name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
25164
0
            fd->byte_code.size = fd->last_opcode_pos;
25165
0
            val = JS_AtomToValue(s->ctx, name);
25166
0
            ret = emit_push_const(s, val, 1);
25167
0
            JS_FreeValue(s->ctx, val);
25168
0
            JS_FreeAtom(s->ctx, name);
25169
0
            if (ret)
25170
0
                return ret;
25171
0
            emit_op(s, OP_delete);
25172
0
            if (opt_chain_label >= 0) {
25173
0
                next_label = emit_goto(s, OP_goto, -1);
25174
0
                emit_label(s, opt_chain_label);
25175
                /* if the optional chain is not taken, return 'true' */
25176
0
                emit_op(s, OP_drop);
25177
0
                emit_op(s, OP_push_true);
25178
0
                emit_label(s, next_label);
25179
0
            }
25180
0
            fd->last_opcode_pos = -1;
25181
0
        }
25182
0
        break;
25183
0
    case OP_get_array_el:
25184
0
        fd->byte_code.size = fd->last_opcode_pos;
25185
0
        fd->last_opcode_pos = -1;
25186
0
        emit_op(s, OP_delete);
25187
0
        break;
25188
0
    case OP_get_array_el_opt_chain:
25189
0
        {
25190
0
            int opt_chain_label, next_label;
25191
0
            opt_chain_label = get_u32(fd->byte_code.buf +
25192
0
                                      fd->last_opcode_pos + 1 + 1);
25193
0
            fd->byte_code.size = fd->last_opcode_pos;
25194
0
            emit_op(s, OP_delete);
25195
0
            next_label = emit_goto(s, OP_goto, -1);
25196
0
            emit_label(s, opt_chain_label);
25197
            /* if the optional chain is not taken, return 'true' */
25198
0
            emit_op(s, OP_drop);
25199
0
            emit_op(s, OP_push_true);
25200
0
            emit_label(s, next_label);
25201
0
            fd->last_opcode_pos = -1;
25202
0
        }
25203
0
        break;
25204
0
    case OP_scope_get_var:
25205
        /* 'delete this': this is not a reference */
25206
0
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
25207
0
        if (name == JS_ATOM_this || name == JS_ATOM_new_target)
25208
0
            goto ret_true;
25209
0
        if (fd->js_mode & JS_MODE_STRICT) {
25210
0
            return js_parse_error(s, "cannot delete a direct reference in strict mode");
25211
0
        } else {
25212
0
            fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_delete_var;
25213
0
        }
25214
0
        break;
25215
0
    case OP_scope_get_private_field:
25216
0
        return js_parse_error(s, "cannot delete a private class field");
25217
0
    case OP_get_super_value:
25218
0
        fd->byte_code.size = fd->last_opcode_pos;
25219
0
        fd->last_opcode_pos = -1;
25220
0
        emit_op(s, OP_throw_error);
25221
0
        emit_atom(s, JS_ATOM_NULL);
25222
0
        emit_u8(s, JS_THROW_ERROR_DELETE_SUPER);
25223
0
        break;
25224
0
    default:
25225
0
    ret_true:
25226
0
        emit_op(s, OP_drop);
25227
0
        emit_op(s, OP_push_true);
25228
0
        break;
25229
0
    }
25230
0
    return 0;
25231
0
}
25232
25233
/* allowed parse_flags: PF_POW_ALLOWED, PF_POW_FORBIDDEN */
25234
static __exception int js_parse_unary(JSParseState *s, int parse_flags)
25235
5.52M
{
25236
5.52M
    int op;
25237
25238
5.52M
    switch(s->token.val) {
25239
0
    case '+':
25240
8
    case '-':
25241
8
    case '!':
25242
8
    case '~':
25243
8
    case TOK_VOID:
25244
8
        op = s->token.val;
25245
8
        if (next_token(s))
25246
1
            return -1;
25247
7
        if (js_parse_unary(s, PF_POW_FORBIDDEN))
25248
2
            return -1;
25249
5
        switch(op) {
25250
5
        case '-':
25251
5
            emit_op(s, OP_neg);
25252
5
            break;
25253
0
        case '+':
25254
0
            emit_op(s, OP_plus);
25255
0
            break;
25256
0
        case '!':
25257
0
            emit_op(s, OP_lnot);
25258
0
            break;
25259
0
        case '~':
25260
0
            emit_op(s, OP_not);
25261
0
            break;
25262
0
        case TOK_VOID:
25263
0
            emit_op(s, OP_drop);
25264
0
            emit_op(s, OP_undefined);
25265
0
            break;
25266
0
        default:
25267
0
            abort();
25268
5
        }
25269
5
        parse_flags = 0;
25270
5
        break;
25271
0
    case TOK_DEC:
25272
0
    case TOK_INC:
25273
0
        {
25274
0
            int opcode, op, scope, label;
25275
0
            JSAtom name;
25276
0
            op = s->token.val;
25277
0
            if (next_token(s))
25278
0
                return -1;
25279
0
            if (js_parse_unary(s, 0))
25280
0
                return -1;
25281
0
            if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
25282
0
                return -1;
25283
0
            emit_op(s, OP_dec + op - TOK_DEC);
25284
0
            put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP,
25285
0
                       FALSE);
25286
0
        }
25287
0
        break;
25288
0
    case TOK_TYPEOF:
25289
0
        {
25290
0
            JSFunctionDef *fd;
25291
0
            if (next_token(s))
25292
0
                return -1;
25293
0
            if (js_parse_unary(s, PF_POW_FORBIDDEN))
25294
0
                return -1;
25295
            /* reference access should not return an exception, so we
25296
               patch the get_var */
25297
0
            fd = s->cur_func;
25298
0
            if (get_prev_opcode(fd) == OP_scope_get_var) {
25299
0
                fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef;
25300
0
            }
25301
0
            emit_op(s, OP_typeof);
25302
0
            parse_flags = 0;
25303
0
        }
25304
0
        break;
25305
0
    case TOK_DELETE:
25306
0
        if (js_parse_delete(s))
25307
0
            return -1;
25308
0
        parse_flags = 0;
25309
0
        break;
25310
0
    case TOK_AWAIT:
25311
0
        if (!(s->cur_func->func_kind & JS_FUNC_ASYNC))
25312
0
            return js_parse_error(s, "unexpected 'await' keyword");
25313
0
        if (!s->cur_func->in_function_body)
25314
0
            return js_parse_error(s, "await in default expression");
25315
0
        if (next_token(s))
25316
0
            return -1;
25317
0
        if (js_parse_unary(s, PF_POW_FORBIDDEN))
25318
0
            return -1;
25319
0
        s->cur_func->has_await = TRUE;
25320
0
        emit_op(s, OP_await);
25321
0
        parse_flags = 0;
25322
0
        break;
25323
5.52M
    default:
25324
5.52M
        if (js_parse_postfix_expr(s, PF_POSTFIX_CALL))
25325
13
            return -1;
25326
5.52M
        if (!s->got_lf &&
25327
5.52M
            (s->token.val == TOK_DEC || s->token.val == TOK_INC)) {
25328
0
            int opcode, op, scope, label;
25329
0
            JSAtom name;
25330
0
            op = s->token.val;
25331
0
            if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
25332
0
                return -1;
25333
0
            emit_op(s, OP_post_dec + op - TOK_DEC);
25334
0
            put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND,
25335
0
                       FALSE);
25336
0
            if (next_token(s))
25337
0
                return -1;
25338
0
        }
25339
5.52M
        break;
25340
5.52M
    }
25341
5.52M
    if (parse_flags & (PF_POW_ALLOWED | PF_POW_FORBIDDEN)) {
25342
5.52M
#ifdef CONFIG_BIGNUM
25343
5.52M
        if (s->token.val == TOK_POW || s->token.val == TOK_MATH_POW) {
25344
            /* Extended exponentiation syntax rules: we extend the ES7
25345
               grammar in order to have more intuitive semantics:
25346
               -2**2 evaluates to -4. */
25347
0
            if (!(s->cur_func->js_mode & JS_MODE_MATH)) {
25348
0
                if (parse_flags & PF_POW_FORBIDDEN) {
25349
0
                    JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
25350
0
                    return -1;
25351
0
                }
25352
0
            }
25353
0
            if (next_token(s))
25354
0
                return -1;
25355
0
            if (js_parse_unary(s, PF_POW_ALLOWED))
25356
0
                return -1;
25357
0
            emit_op(s, OP_pow);
25358
0
        }
25359
#else
25360
        if (s->token.val == TOK_POW) {
25361
            /* Strict ES7 exponentiation syntax rules: To solve
25362
               conficting semantics between different implementations
25363
               regarding the precedence of prefix operators and the
25364
               postifx exponential, ES7 specifies that -2**2 is a
25365
               syntax error. */
25366
            if (parse_flags & PF_POW_FORBIDDEN) {
25367
                JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
25368
                return -1;
25369
            }
25370
            if (next_token(s))
25371
                return -1;
25372
            if (js_parse_unary(s, PF_POW_ALLOWED))
25373
                return -1;
25374
            emit_op(s, OP_pow);
25375
        }
25376
#endif
25377
5.52M
    }
25378
5.52M
    return 0;
25379
5.52M
}
25380
25381
/* allowed parse_flags: PF_IN_ACCEPTED */
25382
static __exception int js_parse_expr_binary(JSParseState *s, int level,
25383
                                            int parse_flags)
25384
49.7M
{
25385
49.7M
    int op, opcode;
25386
25387
49.7M
    if (level == 0) {
25388
5.52M
        return js_parse_unary(s, PF_POW_ALLOWED);
25389
44.2M
    } else if (s->token.val == TOK_PRIVATE_NAME &&
25390
44.2M
               (parse_flags & PF_IN_ACCEPTED) && level == 4 &&
25391
44.2M
               peek_token(s, FALSE) == TOK_IN) {
25392
0
        JSAtom atom;
25393
25394
0
        atom = JS_DupAtom(s->ctx, s->token.u.ident.atom);
25395
0
        if (next_token(s))
25396
0
            goto fail_private_in;
25397
0
        if (s->token.val != TOK_IN)
25398
0
            goto fail_private_in;
25399
0
        if (next_token(s))
25400
0
            goto fail_private_in;
25401
0
        if (js_parse_expr_binary(s, level - 1, parse_flags)) {
25402
0
        fail_private_in:
25403
0
            JS_FreeAtom(s->ctx, atom);
25404
0
            return -1;
25405
0
        }
25406
0
        emit_op(s, OP_scope_in_private_field);
25407
0
        emit_atom(s, atom);
25408
0
        emit_u16(s, s->cur_func->scope_level);
25409
0
        JS_FreeAtom(s->ctx, atom);
25410
0
        return 0;
25411
44.2M
    } else {
25412
44.2M
        if (js_parse_expr_binary(s, level - 1, parse_flags))
25413
112
            return -1;
25414
44.2M
    }
25415
44.2M
    for(;;) {
25416
44.2M
        op = s->token.val;
25417
44.2M
        switch(level) {
25418
5.52M
        case 1:
25419
5.52M
            switch(op) {
25420
0
            case '*':
25421
0
                opcode = OP_mul;
25422
0
                break;
25423
0
            case '/':
25424
0
                opcode = OP_div;
25425
0
                break;
25426
0
            case '%':
25427
0
#ifdef CONFIG_BIGNUM
25428
0
                if (s->cur_func->js_mode & JS_MODE_MATH)
25429
0
                    opcode = OP_math_mod;
25430
0
                else
25431
0
#endif
25432
0
                    opcode = OP_mod;
25433
0
                break;
25434
5.52M
            default:
25435
5.52M
                return 0;
25436
5.52M
            }
25437
0
            break;
25438
5.52M
        case 2:
25439
5.52M
            switch(op) {
25440
2
            case '+':
25441
2
                opcode = OP_add;
25442
2
                break;
25443
2
            case '-':
25444
2
                opcode = OP_sub;
25445
2
                break;
25446
5.52M
            default:
25447
5.52M
                return 0;
25448
5.52M
            }
25449
4
            break;
25450
5.52M
        case 3:
25451
5.52M
            switch(op) {
25452
0
            case TOK_SHL:
25453
0
                opcode = OP_shl;
25454
0
                break;
25455
0
            case TOK_SAR:
25456
0
                opcode = OP_sar;
25457
0
                break;
25458
0
            case TOK_SHR:
25459
0
                opcode = OP_shr;
25460
0
                break;
25461
5.52M
            default:
25462
5.52M
                return 0;
25463
5.52M
            }
25464
0
            break;
25465
5.52M
        case 4:
25466
5.52M
            switch(op) {
25467
0
            case '<':
25468
0
                opcode = OP_lt;
25469
0
                break;
25470
0
            case '>':
25471
0
                opcode = OP_gt;
25472
0
                break;
25473
0
            case TOK_LTE:
25474
0
                opcode = OP_lte;
25475
0
                break;
25476
0
            case TOK_GTE:
25477
0
                opcode = OP_gte;
25478
0
                break;
25479
0
            case TOK_INSTANCEOF:
25480
0
                opcode = OP_instanceof;
25481
0
                break;
25482
0
            case TOK_IN:
25483
0
                if (parse_flags & PF_IN_ACCEPTED) {
25484
0
                    opcode = OP_in;
25485
0
                } else {
25486
0
                    return 0;
25487
0
                }
25488
0
                break;
25489
5.52M
            default:
25490
5.52M
                return 0;
25491
5.52M
            }
25492
0
            break;
25493
5.52M
        case 5:
25494
5.52M
            switch(op) {
25495
0
            case TOK_EQ:
25496
0
                opcode = OP_eq;
25497
0
                break;
25498
0
            case TOK_NEQ:
25499
0
                opcode = OP_neq;
25500
0
                break;
25501
0
            case TOK_STRICT_EQ:
25502
0
                opcode = OP_strict_eq;
25503
0
                break;
25504
0
            case TOK_STRICT_NEQ:
25505
0
                opcode = OP_strict_neq;
25506
0
                break;
25507
5.52M
            default:
25508
5.52M
                return 0;
25509
5.52M
            }
25510
0
            break;
25511
5.52M
        case 6:
25512
5.52M
            switch(op) {
25513
0
            case '&':
25514
0
                opcode = OP_and;
25515
0
                break;
25516
5.52M
            default:
25517
5.52M
                return 0;
25518
5.52M
            }
25519
0
            break;
25520
5.52M
        case 7:
25521
5.52M
            switch(op) {
25522
0
            case '^':
25523
0
                opcode = OP_xor;
25524
0
                break;
25525
5.52M
            default:
25526
5.52M
                return 0;
25527
5.52M
            }
25528
0
            break;
25529
5.52M
        case 8:
25530
5.52M
            switch(op) {
25531
0
            case '|':
25532
0
                opcode = OP_or;
25533
0
                break;
25534
5.52M
            default:
25535
5.52M
                return 0;
25536
5.52M
            }
25537
0
            break;
25538
0
        default:
25539
0
            abort();
25540
44.2M
        }
25541
4
        if (next_token(s))
25542
0
            return -1;
25543
4
        if (js_parse_expr_binary(s, level - 1, parse_flags))
25544
0
            return -1;
25545
4
        emit_op(s, opcode);
25546
4
    }
25547
0
    return 0;
25548
44.2M
}
25549
25550
/* allowed parse_flags: PF_IN_ACCEPTED */
25551
static __exception int js_parse_logical_and_or(JSParseState *s, int op,
25552
                                               int parse_flags)
25553
11.0M
{
25554
11.0M
    int label1;
25555
25556
11.0M
    if (op == TOK_LAND) {
25557
5.52M
        if (js_parse_expr_binary(s, 8, parse_flags))
25558
14
            return -1;
25559
5.52M
    } else {
25560
5.52M
        if (js_parse_logical_and_or(s, TOK_LAND, parse_flags))
25561
14
            return -1;
25562
5.52M
    }
25563
11.0M
    if (s->token.val == op) {
25564
0
        label1 = new_label(s);
25565
25566
0
        for(;;) {
25567
0
            if (next_token(s))
25568
0
                return -1;
25569
0
            emit_op(s, OP_dup);
25570
0
            emit_goto(s, op == TOK_LAND ? OP_if_false : OP_if_true, label1);
25571
0
            emit_op(s, OP_drop);
25572
25573
0
            if (op == TOK_LAND) {
25574
0
                if (js_parse_expr_binary(s, 8, parse_flags))
25575
0
                    return -1;
25576
0
            } else {
25577
0
                if (js_parse_logical_and_or(s, TOK_LAND,
25578
0
                                            parse_flags))
25579
0
                    return -1;
25580
0
            }
25581
0
            if (s->token.val != op) {
25582
0
                if (s->token.val == TOK_DOUBLE_QUESTION_MARK)
25583
0
                    return js_parse_error(s, "cannot mix ?? with && or ||");
25584
0
                break;
25585
0
            }
25586
0
        }
25587
25588
0
        emit_label(s, label1);
25589
0
    }
25590
11.0M
    return 0;
25591
11.0M
}
25592
25593
static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
25594
5.52M
{
25595
5.52M
    int label1;
25596
25597
5.52M
    if (js_parse_logical_and_or(s, TOK_LOR, parse_flags))
25598
14
        return -1;
25599
5.52M
    if (s->token.val == TOK_DOUBLE_QUESTION_MARK) {
25600
0
        label1 = new_label(s);
25601
0
        for(;;) {
25602
0
            if (next_token(s))
25603
0
                return -1;
25604
25605
0
            emit_op(s, OP_dup);
25606
0
            emit_op(s, OP_is_undefined_or_null);
25607
0
            emit_goto(s, OP_if_false, label1);
25608
0
            emit_op(s, OP_drop);
25609
25610
0
            if (js_parse_expr_binary(s, 8, parse_flags))
25611
0
                return -1;
25612
0
            if (s->token.val != TOK_DOUBLE_QUESTION_MARK)
25613
0
                break;
25614
0
        }
25615
0
        emit_label(s, label1);
25616
0
    }
25617
5.52M
    return 0;
25618
5.52M
}
25619
25620
/* allowed parse_flags: PF_IN_ACCEPTED */
25621
static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
25622
5.52M
{
25623
5.52M
    int label1, label2;
25624
25625
5.52M
    if (js_parse_coalesce_expr(s, parse_flags))
25626
14
        return -1;
25627
5.52M
    if (s->token.val == '?') {
25628
0
        if (next_token(s))
25629
0
            return -1;
25630
0
        label1 = emit_goto(s, OP_if_false, -1);
25631
25632
0
        if (js_parse_assign_expr(s))
25633
0
            return -1;
25634
0
        if (js_parse_expect(s, ':'))
25635
0
            return -1;
25636
25637
0
        label2 = emit_goto(s, OP_goto, -1);
25638
25639
0
        emit_label(s, label1);
25640
25641
0
        if (js_parse_assign_expr2(s, parse_flags & PF_IN_ACCEPTED))
25642
0
            return -1;
25643
25644
0
        emit_label(s, label2);
25645
0
    }
25646
5.52M
    return 0;
25647
5.52M
}
25648
25649
static void emit_return(JSParseState *s, BOOL hasval);
25650
25651
/* allowed parse_flags: PF_IN_ACCEPTED */
25652
static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
25653
5.52M
{
25654
5.52M
    int opcode, op, scope;
25655
5.52M
    JSAtom name0 = JS_ATOM_NULL;
25656
5.52M
    JSAtom name;
25657
25658
5.52M
    if (s->token.val == TOK_YIELD) {
25659
0
        BOOL is_star = FALSE, is_async;
25660
25661
0
        if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR))
25662
0
            return js_parse_error(s, "unexpected 'yield' keyword");
25663
0
        if (!s->cur_func->in_function_body)
25664
0
            return js_parse_error(s, "yield in default expression");
25665
0
        if (next_token(s))
25666
0
            return -1;
25667
        /* XXX: is there a better method to detect 'yield' without
25668
           parameters ? */
25669
0
        if (s->token.val != ';' && s->token.val != ')' &&
25670
0
            s->token.val != ']' && s->token.val != '}' &&
25671
0
            s->token.val != ',' && s->token.val != ':' && !s->got_lf) {
25672
0
            if (s->token.val == '*') {
25673
0
                is_star = TRUE;
25674
0
                if (next_token(s))
25675
0
                    return -1;
25676
0
            }
25677
0
            if (js_parse_assign_expr2(s, parse_flags))
25678
0
                return -1;
25679
0
        } else {
25680
0
            emit_op(s, OP_undefined);
25681
0
        }
25682
0
        is_async = (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR);
25683
25684
0
        if (is_star) {
25685
0
            int label_loop, label_return, label_next;
25686
0
            int label_return1, label_yield, label_throw, label_throw1;
25687
0
            int label_throw2;
25688
25689
0
            label_loop = new_label(s);
25690
0
            label_yield = new_label(s);
25691
25692
0
            emit_op(s, is_async ? OP_for_await_of_start : OP_for_of_start);
25693
25694
            /* remove the catch offset (XXX: could avoid pushing back
25695
               undefined) */
25696
0
            emit_op(s, OP_drop);
25697
0
            emit_op(s, OP_undefined);
25698
25699
0
            emit_op(s, OP_undefined); /* initial value */
25700
25701
0
            emit_label(s, label_loop);
25702
0
            emit_op(s, OP_iterator_next);
25703
0
            if (is_async)
25704
0
                emit_op(s, OP_await);
25705
0
            emit_op(s, OP_iterator_check_object);
25706
0
            emit_op(s, OP_get_field2);
25707
0
            emit_atom(s, JS_ATOM_done);
25708
0
            label_next = emit_goto(s, OP_if_true, -1); /* end of loop */
25709
0
            emit_label(s, label_yield);
25710
0
            if (is_async) {
25711
                /* OP_async_yield_star takes the value as parameter */
25712
0
                emit_op(s, OP_get_field);
25713
0
                emit_atom(s, JS_ATOM_value);
25714
0
                emit_op(s, OP_async_yield_star);
25715
0
            } else {
25716
                /* OP_yield_star takes (value, done) as parameter */
25717
0
                emit_op(s, OP_yield_star);
25718
0
            }
25719
0
            emit_op(s, OP_dup);
25720
0
            label_return = emit_goto(s, OP_if_true, -1);
25721
0
            emit_op(s, OP_drop);
25722
0
            emit_goto(s, OP_goto, label_loop);
25723
25724
0
            emit_label(s, label_return);
25725
0
            emit_op(s, OP_push_i32);
25726
0
            emit_u32(s, 2);
25727
0
            emit_op(s, OP_strict_eq);
25728
0
            label_throw = emit_goto(s, OP_if_true, -1);
25729
25730
            /* return handling */
25731
0
            if (is_async)
25732
0
                emit_op(s, OP_await);
25733
0
            emit_op(s, OP_iterator_call);
25734
0
            emit_u8(s, 0);
25735
0
            label_return1 = emit_goto(s, OP_if_true, -1);
25736
0
            if (is_async)
25737
0
                emit_op(s, OP_await);
25738
0
            emit_op(s, OP_iterator_check_object);
25739
0
            emit_op(s, OP_get_field2);
25740
0
            emit_atom(s, JS_ATOM_done);
25741
0
            emit_goto(s, OP_if_false, label_yield);
25742
25743
0
            emit_op(s, OP_get_field);
25744
0
            emit_atom(s, JS_ATOM_value);
25745
25746
0
            emit_label(s, label_return1);
25747
0
            emit_op(s, OP_nip);
25748
0
            emit_op(s, OP_nip);
25749
0
            emit_op(s, OP_nip);
25750
0
            emit_return(s, TRUE);
25751
25752
            /* throw handling */
25753
0
            emit_label(s, label_throw);
25754
0
            emit_op(s, OP_iterator_call);
25755
0
            emit_u8(s, 1);
25756
0
            label_throw1 = emit_goto(s, OP_if_true, -1);
25757
0
            if (is_async)
25758
0
                emit_op(s, OP_await);
25759
0
            emit_op(s, OP_iterator_check_object);
25760
0
            emit_op(s, OP_get_field2);
25761
0
            emit_atom(s, JS_ATOM_done);
25762
0
            emit_goto(s, OP_if_false, label_yield);
25763
0
            emit_goto(s, OP_goto, label_next);
25764
            /* close the iterator and throw a type error exception */
25765
0
            emit_label(s, label_throw1);
25766
0
            emit_op(s, OP_iterator_call);
25767
0
            emit_u8(s, 2);
25768
0
            label_throw2 = emit_goto(s, OP_if_true, -1);
25769
0
            if (is_async)
25770
0
                emit_op(s, OP_await);
25771
0
            emit_label(s, label_throw2);
25772
25773
0
            emit_op(s, OP_throw_error);
25774
0
            emit_atom(s, JS_ATOM_NULL);
25775
0
            emit_u8(s, JS_THROW_ERROR_ITERATOR_THROW);
25776
25777
0
            emit_label(s, label_next);
25778
0
            emit_op(s, OP_get_field);
25779
0
            emit_atom(s, JS_ATOM_value);
25780
0
            emit_op(s, OP_nip); /* keep the value associated with
25781
                                   done = true */
25782
0
            emit_op(s, OP_nip);
25783
0
            emit_op(s, OP_nip);
25784
0
        } else {
25785
0
            int label_next;
25786
25787
0
            if (is_async)
25788
0
                emit_op(s, OP_await);
25789
0
            emit_op(s, OP_yield);
25790
0
            label_next = emit_goto(s, OP_if_false, -1);
25791
0
            emit_return(s, TRUE);
25792
0
            emit_label(s, label_next);
25793
0
        }
25794
0
        return 0;
25795
5.52M
    } else if (s->token.val == '(' &&
25796
5.52M
               js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
25797
0
        return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
25798
0
                                      JS_FUNC_NORMAL, JS_ATOM_NULL,
25799
0
                                      s->token.ptr, s->token.line_num);
25800
5.52M
    } else if (token_is_pseudo_keyword(s, JS_ATOM_async)) {
25801
0
        const uint8_t *source_ptr;
25802
0
        int source_line_num, tok;
25803
0
        JSParsePos pos;
25804
25805
        /* fast test */
25806
0
        tok = peek_token(s, TRUE);
25807
0
        if (tok == TOK_FUNCTION || tok == '\n')
25808
0
            goto next;
25809
25810
0
        source_ptr = s->token.ptr;
25811
0
        source_line_num = s->token.line_num;
25812
0
        js_parse_get_pos(s, &pos);
25813
0
        if (next_token(s))
25814
0
            return -1;
25815
0
        if ((s->token.val == '(' &&
25816
0
             js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||
25817
0
            (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
25818
0
             peek_token(s, TRUE) == TOK_ARROW)) {
25819
0
            return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
25820
0
                                          JS_FUNC_ASYNC, JS_ATOM_NULL,
25821
0
                                          source_ptr, source_line_num);
25822
0
        } else {
25823
            /* undo the token parsing */
25824
0
            if (js_parse_seek_token(s, &pos))
25825
0
                return -1;
25826
0
        }
25827
5.52M
    } else if (s->token.val == TOK_IDENT &&
25828
5.52M
               peek_token(s, TRUE) == TOK_ARROW) {
25829
0
        return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
25830
0
                                      JS_FUNC_NORMAL, JS_ATOM_NULL,
25831
0
                                      s->token.ptr, s->token.line_num);
25832
0
    }
25833
5.52M
 next:
25834
5.52M
    if (s->token.val == TOK_IDENT) {
25835
        /* name0 is used to check for OP_set_name pattern, not duplicated */
25836
169
        name0 = s->token.u.ident.atom;
25837
169
    }
25838
5.52M
    if (js_parse_cond_expr(s, parse_flags))
25839
14
        return -1;
25840
25841
5.52M
    op = s->token.val;
25842
5.52M
    if (op == '=' || (op >= TOK_MUL_ASSIGN && op <= TOK_POW_ASSIGN)) {
25843
79
        int label;
25844
79
        if (next_token(s))
25845
0
            return -1;
25846
79
        if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
25847
0
            return -1;
25848
25849
79
        if (js_parse_assign_expr2(s, parse_flags)) {
25850
0
            JS_FreeAtom(s->ctx, name);
25851
0
            return -1;
25852
0
        }
25853
25854
79
        if (op == '=') {
25855
79
            if (opcode == OP_get_ref_value && name == name0) {
25856
1
                set_object_name(s, name);
25857
1
            }
25858
79
        } else {
25859
0
            static const uint8_t assign_opcodes[] = {
25860
0
                OP_mul, OP_div, OP_mod, OP_add, OP_sub,
25861
0
                OP_shl, OP_sar, OP_shr, OP_and, OP_xor, OP_or,
25862
0
#ifdef CONFIG_BIGNUM
25863
0
                OP_pow,
25864
0
#endif
25865
0
                OP_pow,
25866
0
            };
25867
0
            op = assign_opcodes[op - TOK_MUL_ASSIGN];
25868
0
#ifdef CONFIG_BIGNUM
25869
0
            if (s->cur_func->js_mode & JS_MODE_MATH) {
25870
0
                if (op == OP_mod)
25871
0
                    op = OP_math_mod;
25872
0
            }
25873
0
#endif
25874
0
            emit_op(s, op);
25875
0
        }
25876
79
        put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE);
25877
5.52M
    } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) {
25878
0
        int label, label1, depth_lvalue, label2;
25879
25880
0
        if (next_token(s))
25881
0
            return -1;
25882
0
        if (get_lvalue(s, &opcode, &scope, &name, &label,
25883
0
                       &depth_lvalue, TRUE, op) < 0)
25884
0
            return -1;
25885
25886
0
        emit_op(s, OP_dup);
25887
0
        if (op == TOK_DOUBLE_QUESTION_MARK_ASSIGN)
25888
0
            emit_op(s, OP_is_undefined_or_null);
25889
0
        label1 = emit_goto(s, op == TOK_LOR_ASSIGN ? OP_if_true : OP_if_false,
25890
0
                           -1);
25891
0
        emit_op(s, OP_drop);
25892
25893
0
        if (js_parse_assign_expr2(s, parse_flags)) {
25894
0
            JS_FreeAtom(s->ctx, name);
25895
0
            return -1;
25896
0
        }
25897
25898
0
        if (opcode == OP_get_ref_value && name == name0) {
25899
0
            set_object_name(s, name);
25900
0
        }
25901
25902
0
        switch(depth_lvalue) {
25903
0
        case 1:
25904
0
            emit_op(s, OP_insert2);
25905
0
            break;
25906
0
        case 2:
25907
0
            emit_op(s, OP_insert3);
25908
0
            break;
25909
0
        case 3:
25910
0
            emit_op(s, OP_insert4);
25911
0
            break;
25912
0
        default:
25913
0
            abort();
25914
0
        }
25915
25916
        /* XXX: we disable the OP_put_ref_value optimization by not
25917
           using put_lvalue() otherwise depth_lvalue is not correct */
25918
0
        put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH,
25919
0
                   FALSE);
25920
0
        label2 = emit_goto(s, OP_goto, -1);
25921
25922
0
        emit_label(s, label1);
25923
25924
        /* remove the lvalue stack entries */
25925
0
        while (depth_lvalue != 0) {
25926
0
            emit_op(s, OP_nip);
25927
0
            depth_lvalue--;
25928
0
        }
25929
25930
0
        emit_label(s, label2);
25931
0
    }
25932
5.52M
    return 0;
25933
5.52M
}
25934
25935
static __exception int js_parse_assign_expr(JSParseState *s)
25936
5.52M
{
25937
5.52M
    return js_parse_assign_expr2(s, PF_IN_ACCEPTED);
25938
5.52M
}
25939
25940
/* allowed parse_flags: PF_IN_ACCEPTED */
25941
static __exception int js_parse_expr2(JSParseState *s, int parse_flags)
25942
118
{
25943
118
    BOOL comma = FALSE;
25944
118
    for(;;) {
25945
118
        if (js_parse_assign_expr2(s, parse_flags))
25946
10
            return -1;
25947
108
        if (comma) {
25948
            /* prevent get_lvalue from using the last expression
25949
               as an lvalue. This also prevents the conversion of
25950
               of get_var to get_ref for method lookup in function
25951
               call inside `with` statement.
25952
             */
25953
0
            s->cur_func->last_opcode_pos = -1;
25954
0
        }
25955
108
        if (s->token.val != ',')
25956
108
            break;
25957
0
        comma = TRUE;
25958
0
        if (next_token(s))
25959
0
            return -1;
25960
0
        emit_op(s, OP_drop);
25961
0
    }
25962
108
    return 0;
25963
118
}
25964
25965
static __exception int js_parse_expr(JSParseState *s)
25966
118
{
25967
118
    return js_parse_expr2(s, PF_IN_ACCEPTED);
25968
118
}
25969
25970
static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
25971
                             JSAtom label_name,
25972
                             int label_break, int label_cont,
25973
                             int drop_count)
25974
0
{
25975
0
    be->prev = fd->top_break;
25976
0
    fd->top_break = be;
25977
0
    be->label_name = label_name;
25978
0
    be->label_break = label_break;
25979
0
    be->label_cont = label_cont;
25980
0
    be->drop_count = drop_count;
25981
0
    be->label_finally = -1;
25982
0
    be->scope_level = fd->scope_level;
25983
0
    be->has_iterator = FALSE;
25984
0
}
25985
25986
static void pop_break_entry(JSFunctionDef *fd)
25987
0
{
25988
0
    BlockEnv *be;
25989
0
    be = fd->top_break;
25990
0
    fd->top_break = be->prev;
25991
0
}
25992
25993
static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
25994
0
{
25995
0
    BlockEnv *top;
25996
0
    int i, scope_level;
25997
25998
0
    scope_level = s->cur_func->scope_level;
25999
0
    top = s->cur_func->top_break;
26000
0
    while (top != NULL) {
26001
0
        close_scopes(s, scope_level, top->scope_level);
26002
0
        scope_level = top->scope_level;
26003
0
        if (is_cont &&
26004
0
            top->label_cont != -1 &&
26005
0
            (name == JS_ATOM_NULL || top->label_name == name)) {
26006
            /* continue stays inside the same block */
26007
0
            emit_goto(s, OP_goto, top->label_cont);
26008
0
            return 0;
26009
0
        }
26010
0
        if (!is_cont &&
26011
0
            top->label_break != -1 &&
26012
0
            (name == JS_ATOM_NULL || top->label_name == name)) {
26013
0
            emit_goto(s, OP_goto, top->label_break);
26014
0
            return 0;
26015
0
        }
26016
0
        i = 0;
26017
0
        if (top->has_iterator) {
26018
0
            emit_op(s, OP_iterator_close);
26019
0
            i += 3;
26020
0
        }
26021
0
        for(; i < top->drop_count; i++)
26022
0
            emit_op(s, OP_drop);
26023
0
        if (top->label_finally != -1) {
26024
            /* must push dummy value to keep same stack depth */
26025
0
            emit_op(s, OP_undefined);
26026
0
            emit_goto(s, OP_gosub, top->label_finally);
26027
0
            emit_op(s, OP_drop);
26028
0
        }
26029
0
        top = top->prev;
26030
0
    }
26031
0
    if (name == JS_ATOM_NULL) {
26032
0
        if (is_cont)
26033
0
            return js_parse_error(s, "continue must be inside loop");
26034
0
        else
26035
0
            return js_parse_error(s, "break must be inside loop or switch");
26036
0
    } else {
26037
0
        return js_parse_error(s, "break/continue label not found");
26038
0
    }
26039
0
}
26040
26041
/* execute the finally blocks before return */
26042
static void emit_return(JSParseState *s, BOOL hasval)
26043
63
{
26044
63
    BlockEnv *top;
26045
26046
63
    if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
26047
39
        if (!hasval) {
26048
            /* no value: direct return in case of async generator */
26049
39
            emit_op(s, OP_undefined);
26050
39
            hasval = TRUE;
26051
39
        } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
26052
            /* the await must be done before handling the "finally" in
26053
               case it raises an exception */
26054
0
            emit_op(s, OP_await);
26055
0
        }
26056
39
    }
26057
26058
63
    top = s->cur_func->top_break;
26059
63
    while (top != NULL) {
26060
0
        if (top->has_iterator || top->label_finally != -1) {
26061
0
            if (!hasval) {
26062
0
                emit_op(s, OP_undefined);
26063
0
                hasval = TRUE;
26064
0
            }
26065
            /* Remove the stack elements up to and including the catch
26066
               offset. When 'yield' is used in an expression we have
26067
               no easy way to count them, so we use this specific
26068
               instruction instead. */
26069
0
            emit_op(s, OP_nip_catch);
26070
            /* stack: iter_obj next ret_val */
26071
0
            if (top->has_iterator) {
26072
0
                if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
26073
0
                    int label_next, label_next2;
26074
0
                    emit_op(s, OP_nip); /* next */
26075
0
                    emit_op(s, OP_swap);
26076
0
                    emit_op(s, OP_get_field2);
26077
0
                    emit_atom(s, JS_ATOM_return);
26078
                    /* stack: iter_obj return_func */
26079
0
                    emit_op(s, OP_dup);
26080
0
                    emit_op(s, OP_is_undefined_or_null);
26081
0
                    label_next = emit_goto(s, OP_if_true, -1);
26082
0
                    emit_op(s, OP_call_method);
26083
0
                    emit_u16(s, 0);
26084
0
                    emit_op(s, OP_iterator_check_object);
26085
0
                    emit_op(s, OP_await);
26086
0
                    label_next2 = emit_goto(s, OP_goto, -1);
26087
0
                    emit_label(s, label_next);
26088
0
                    emit_op(s, OP_drop);
26089
0
                    emit_label(s, label_next2);
26090
0
                    emit_op(s, OP_drop);
26091
0
                } else {
26092
0
                    emit_op(s, OP_rot3r);
26093
0
                    emit_op(s, OP_undefined); /* dummy catch offset */
26094
0
                    emit_op(s, OP_iterator_close);
26095
0
                }
26096
0
            } else {
26097
                /* execute the "finally" block */
26098
0
                emit_goto(s, OP_gosub, top->label_finally);
26099
0
            }
26100
0
        }
26101
0
        top = top->prev;
26102
0
    }
26103
63
    if (s->cur_func->is_derived_class_constructor) {
26104
0
        int label_return;
26105
26106
        /* 'this' can be uninitialized, so it may be accessed only if
26107
           the derived class constructor does not return an object */
26108
0
        if (hasval) {
26109
0
            emit_op(s, OP_check_ctor_return);
26110
0
            label_return = emit_goto(s, OP_if_false, -1);
26111
0
            emit_op(s, OP_drop);
26112
0
        } else {
26113
0
            label_return = -1;
26114
0
        }
26115
26116
        /* The error should be raised in the caller context, so we use
26117
           a specific opcode */
26118
0
        emit_op(s, OP_scope_get_var_checkthis);
26119
0
        emit_atom(s, JS_ATOM_this);
26120
0
        emit_u16(s, 0);
26121
26122
0
        emit_label(s, label_return);
26123
0
        emit_op(s, OP_return);
26124
63
    } else if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
26125
39
        emit_op(s, OP_return_async);
26126
39
    } else {
26127
24
        emit_op(s, hasval ? OP_return : OP_return_undef);
26128
24
    }
26129
63
}
26130
26131
118
#define DECL_MASK_FUNC  (1 << 0) /* allow normal function declaration */
26132
/* ored with DECL_MASK_FUNC if function declarations are allowed with a label */
26133
118
#define DECL_MASK_FUNC_WITH_LABEL (1 << 1)
26134
118
#define DECL_MASK_OTHER (1 << 2) /* all other declarations */
26135
118
#define DECL_MASK_ALL   (DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL | DECL_MASK_OTHER)
26136
26137
static __exception int js_parse_statement_or_decl(JSParseState *s,
26138
                                                  int decl_mask);
26139
26140
static __exception int js_parse_statement(JSParseState *s)
26141
0
{
26142
0
    return js_parse_statement_or_decl(s, 0);
26143
0
}
26144
26145
static __exception int js_parse_block(JSParseState *s)
26146
0
{
26147
0
    if (js_parse_expect(s, '{'))
26148
0
        return -1;
26149
0
    if (s->token.val != '}') {
26150
0
        push_scope(s);
26151
0
        for(;;) {
26152
0
            if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
26153
0
                return -1;
26154
0
            if (s->token.val == '}')
26155
0
                break;
26156
0
        }
26157
0
        pop_scope(s);
26158
0
    }
26159
0
    if (next_token(s))
26160
0
        return -1;
26161
0
    return 0;
26162
0
}
26163
26164
/* allowed parse_flags: PF_IN_ACCEPTED */
26165
static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
26166
                                    BOOL export_flag)
26167
0
{
26168
0
    JSContext *ctx = s->ctx;
26169
0
    JSFunctionDef *fd = s->cur_func;
26170
0
    JSAtom name = JS_ATOM_NULL;
26171
26172
0
    for (;;) {
26173
0
        if (s->token.val == TOK_IDENT) {
26174
0
            if (s->token.u.ident.is_reserved) {
26175
0
                return js_parse_error_reserved_identifier(s);
26176
0
            }
26177
0
            name = JS_DupAtom(ctx, s->token.u.ident.atom);
26178
0
            if (name == JS_ATOM_let && (tok == TOK_LET || tok == TOK_CONST)) {
26179
0
                js_parse_error(s, "'let' is not a valid lexical identifier");
26180
0
                goto var_error;
26181
0
            }
26182
0
            if (next_token(s))
26183
0
                goto var_error;
26184
0
            if (js_define_var(s, name, tok))
26185
0
                goto var_error;
26186
0
            if (export_flag) {
26187
0
                if (!add_export_entry(s, s->cur_func->module, name, name,
26188
0
                                      JS_EXPORT_TYPE_LOCAL))
26189
0
                    goto var_error;
26190
0
            }
26191
26192
0
            if (s->token.val == '=') {
26193
0
                if (next_token(s))
26194
0
                    goto var_error;
26195
0
                if (tok == TOK_VAR) {
26196
                    /* Must make a reference for proper `with` semantics */
26197
0
                    int opcode, scope, label;
26198
0
                    JSAtom name1;
26199
26200
0
                    emit_op(s, OP_scope_get_var);
26201
0
                    emit_atom(s, name);
26202
0
                    emit_u16(s, fd->scope_level);
26203
0
                    if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0)
26204
0
                        goto var_error;
26205
0
                    if (js_parse_assign_expr2(s, parse_flags)) {
26206
0
                        JS_FreeAtom(ctx, name1);
26207
0
                        goto var_error;
26208
0
                    }
26209
0
                    set_object_name(s, name);
26210
0
                    put_lvalue(s, opcode, scope, name1, label,
26211
0
                               PUT_LVALUE_NOKEEP, FALSE);
26212
0
                } else {
26213
0
                    if (js_parse_assign_expr2(s, parse_flags))
26214
0
                        goto var_error;
26215
0
                    set_object_name(s, name);
26216
0
                    emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
26217
0
                        OP_scope_put_var_init : OP_scope_put_var);
26218
0
                    emit_atom(s, name);
26219
0
                    emit_u16(s, fd->scope_level);
26220
0
                }
26221
0
            } else {
26222
0
                if (tok == TOK_CONST) {
26223
0
                    js_parse_error(s, "missing initializer for const variable");
26224
0
                    goto var_error;
26225
0
                }
26226
0
                if (tok == TOK_LET) {
26227
                    /* initialize lexical variable upon entering its scope */
26228
0
                    emit_op(s, OP_undefined);
26229
0
                    emit_op(s, OP_scope_put_var_init);
26230
0
                    emit_atom(s, name);
26231
0
                    emit_u16(s, fd->scope_level);
26232
0
                }
26233
0
            }
26234
0
            JS_FreeAtom(ctx, name);
26235
0
        } else {
26236
0
            int skip_bits;
26237
0
            if ((s->token.val == '[' || s->token.val == '{')
26238
0
            &&  js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
26239
0
                emit_op(s, OP_undefined);
26240
0
                if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
26241
0
                    return -1;
26242
0
            } else {
26243
0
                return js_parse_error(s, "variable name expected");
26244
0
            }
26245
0
        }
26246
0
        if (s->token.val != ',')
26247
0
            break;
26248
0
        if (next_token(s))
26249
0
            return -1;
26250
0
    }
26251
0
    return 0;
26252
26253
0
 var_error:
26254
0
    JS_FreeAtom(ctx, name);
26255
0
    return -1;
26256
0
}
26257
26258
/* test if the current token is a label. Use simplistic look-ahead scanner */
26259
static BOOL is_label(JSParseState *s)
26260
118
{
26261
118
    return (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
26262
118
            peek_token(s, FALSE) == ':');
26263
118
}
26264
26265
/* test if the current token is a let keyword. Use simplistic look-ahead scanner */
26266
static int is_let(JSParseState *s, int decl_mask)
26267
86
{
26268
86
    int res = FALSE;
26269
26270
86
    if (token_is_pseudo_keyword(s, JS_ATOM_let)) {
26271
0
        JSParsePos pos;
26272
0
        js_parse_get_pos(s, &pos);
26273
0
        for (;;) {
26274
0
            if (next_token(s)) {
26275
0
                res = -1;
26276
0
                break;
26277
0
            }
26278
0
            if (s->token.val == '[') {
26279
                /* let [ is a syntax restriction:
26280
                   it never introduces an ExpressionStatement */
26281
0
                res = TRUE;
26282
0
                break;
26283
0
            }
26284
0
            if (s->token.val == '{' ||
26285
0
                (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) ||
26286
0
                s->token.val == TOK_LET ||
26287
0
                s->token.val == TOK_YIELD ||
26288
0
                s->token.val == TOK_AWAIT) {
26289
                /* Check for possible ASI if not scanning for Declaration */
26290
                /* XXX: should also check that `{` introduces a BindingPattern,
26291
                   but Firefox does not and rejects eval("let=1;let\n{if(1)2;}") */
26292
0
                if (s->last_line_num == s->token.line_num || (decl_mask & DECL_MASK_OTHER)) {
26293
0
                    res = TRUE;
26294
0
                    break;
26295
0
                }
26296
0
                break;
26297
0
            }
26298
0
            break;
26299
0
        }
26300
0
        if (js_parse_seek_token(s, &pos)) {
26301
0
            res = -1;
26302
0
        }
26303
0
    }
26304
86
    return res;
26305
86
}
26306
26307
/* XXX: handle IteratorClose when exiting the loop before the
26308
   enumeration is done */
26309
static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
26310
                                          BOOL is_async)
26311
0
{
26312
0
    JSContext *ctx = s->ctx;
26313
0
    JSFunctionDef *fd = s->cur_func;
26314
0
    JSAtom var_name;
26315
0
    BOOL has_initializer, is_for_of, has_destructuring;
26316
0
    int tok, tok1, opcode, scope, block_scope_level;
26317
0
    int label_next, label_expr, label_cont, label_body, label_break;
26318
0
    int pos_next, pos_expr;
26319
0
    BlockEnv break_entry;
26320
26321
0
    has_initializer = FALSE;
26322
0
    has_destructuring = FALSE;
26323
0
    is_for_of = FALSE;
26324
0
    block_scope_level = fd->scope_level;
26325
0
    label_cont = new_label(s);
26326
0
    label_body = new_label(s);
26327
0
    label_break = new_label(s);
26328
0
    label_next = new_label(s);
26329
26330
    /* create scope for the lexical variables declared in the enumeration
26331
       expressions. XXX: Not completely correct because of weird capturing
26332
       semantics in `for (i of o) a.push(function(){return i})` */
26333
0
    push_scope(s);
26334
26335
    /* local for_in scope starts here so individual elements
26336
       can be closed in statement. */
26337
0
    push_break_entry(s->cur_func, &break_entry,
26338
0
                     label_name, label_break, label_cont, 1);
26339
0
    break_entry.scope_level = block_scope_level;
26340
26341
0
    label_expr = emit_goto(s, OP_goto, -1);
26342
26343
0
    pos_next = s->cur_func->byte_code.size;
26344
0
    emit_label(s, label_next);
26345
26346
0
    tok = s->token.val;
26347
0
    switch (is_let(s, DECL_MASK_OTHER)) {
26348
0
    case TRUE:
26349
0
        tok = TOK_LET;
26350
0
        break;
26351
0
    case FALSE:
26352
0
        break;
26353
0
    default:
26354
0
        return -1;
26355
0
    }
26356
0
    if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
26357
0
        if (next_token(s))
26358
0
            return -1;
26359
26360
0
        if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
26361
0
            if (s->token.val == '[' || s->token.val == '{') {
26362
0
                if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE) < 0)
26363
0
                    return -1;
26364
0
                has_destructuring = TRUE;
26365
0
            } else {
26366
0
                return js_parse_error(s, "variable name expected");
26367
0
            }
26368
0
            var_name = JS_ATOM_NULL;
26369
0
        } else {
26370
0
            var_name = JS_DupAtom(ctx, s->token.u.ident.atom);
26371
0
            if (next_token(s)) {
26372
0
                JS_FreeAtom(s->ctx, var_name);
26373
0
                return -1;
26374
0
            }
26375
0
            if (js_define_var(s, var_name, tok)) {
26376
0
                JS_FreeAtom(s->ctx, var_name);
26377
0
                return -1;
26378
0
            }
26379
0
            emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
26380
0
                    OP_scope_put_var_init : OP_scope_put_var);
26381
0
            emit_atom(s, var_name);
26382
0
            emit_u16(s, fd->scope_level);
26383
0
        }
26384
0
    } else if (!is_async && token_is_pseudo_keyword(s, JS_ATOM_async) &&
26385
0
               peek_token(s, FALSE) == TOK_OF) {
26386
0
        return js_parse_error(s, "'for of' expression cannot start with 'async'");
26387
0
    } else {
26388
0
        int skip_bits;
26389
0
        if ((s->token.val == '[' || s->token.val == '{')
26390
0
        &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) {
26391
0
            if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
26392
0
                return -1;
26393
0
        } else {
26394
0
            int lvalue_label;
26395
0
            if (js_parse_left_hand_side_expr(s))
26396
0
                return -1;
26397
0
            if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label,
26398
0
                           NULL, FALSE, TOK_FOR))
26399
0
                return -1;
26400
0
            put_lvalue(s, opcode, scope, var_name, lvalue_label,
26401
0
                       PUT_LVALUE_NOKEEP_BOTTOM, FALSE);
26402
0
        }
26403
0
        var_name = JS_ATOM_NULL;
26404
0
    }
26405
0
    emit_goto(s, OP_goto, label_body);
26406
26407
0
    pos_expr = s->cur_func->byte_code.size;
26408
0
    emit_label(s, label_expr);
26409
0
    if (s->token.val == '=') {
26410
        /* XXX: potential scoping issue if inside `with` statement */
26411
0
        has_initializer = TRUE;
26412
        /* parse and evaluate initializer prior to evaluating the
26413
           object (only used with "for in" with a non lexical variable
26414
           in non strict mode */
26415
0
        if (next_token(s) || js_parse_assign_expr2(s, 0)) {
26416
0
            JS_FreeAtom(ctx, var_name);
26417
0
            return -1;
26418
0
        }
26419
0
        if (var_name != JS_ATOM_NULL) {
26420
0
            emit_op(s, OP_scope_put_var);
26421
0
            emit_atom(s, var_name);
26422
0
            emit_u16(s, fd->scope_level);
26423
0
        }
26424
0
    }
26425
0
    JS_FreeAtom(ctx, var_name);
26426
26427
0
    if (token_is_pseudo_keyword(s, JS_ATOM_of)) {
26428
0
        break_entry.has_iterator = is_for_of = TRUE;
26429
0
        break_entry.drop_count += 2;
26430
0
        if (has_initializer)
26431
0
            goto initializer_error;
26432
0
    } else if (s->token.val == TOK_IN) {
26433
0
        if (is_async)
26434
0
            return js_parse_error(s, "'for await' loop should be used with 'of'");
26435
0
        if (has_initializer &&
26436
0
            (tok != TOK_VAR || (fd->js_mode & JS_MODE_STRICT) ||
26437
0
             has_destructuring)) {
26438
0
        initializer_error:
26439
0
            return js_parse_error(s, "a declaration in the head of a for-%s loop can't have an initializer",
26440
0
                                  is_for_of ? "of" : "in");
26441
0
        }
26442
0
    } else {
26443
0
        return js_parse_error(s, "expected 'of' or 'in' in for control expression");
26444
0
    }
26445
0
    if (next_token(s))
26446
0
        return -1;
26447
0
    if (is_for_of) {
26448
0
        if (js_parse_assign_expr(s))
26449
0
            return -1;
26450
0
    } else {
26451
0
        if (js_parse_expr(s))
26452
0
            return -1;
26453
0
    }
26454
    /* close the scope after having evaluated the expression so that
26455
       the TDZ values are in the closures */
26456
0
    close_scopes(s, s->cur_func->scope_level, block_scope_level);
26457
0
    if (is_for_of) {
26458
0
        if (is_async)
26459
0
            emit_op(s, OP_for_await_of_start);
26460
0
        else
26461
0
            emit_op(s, OP_for_of_start);
26462
        /* on stack: enum_rec */
26463
0
    } else {
26464
0
        emit_op(s, OP_for_in_start);
26465
        /* on stack: enum_obj */
26466
0
    }
26467
0
    emit_goto(s, OP_goto, label_cont);
26468
26469
0
    if (js_parse_expect(s, ')'))
26470
0
        return -1;
26471
26472
0
    if (OPTIMIZE) {
26473
        /* move the `next` code here */
26474
0
        DynBuf *bc = &s->cur_func->byte_code;
26475
0
        int chunk_size = pos_expr - pos_next;
26476
0
        int offset = bc->size - pos_next;
26477
0
        int i;
26478
0
        dbuf_realloc(bc, bc->size + chunk_size);
26479
0
        dbuf_put(bc, bc->buf + pos_next, chunk_size);
26480
0
        memset(bc->buf + pos_next, OP_nop, chunk_size);
26481
        /* `next` part ends with a goto */
26482
0
        s->cur_func->last_opcode_pos = bc->size - 5;
26483
        /* relocate labels */
26484
0
        for (i = label_cont; i < s->cur_func->label_count; i++) {
26485
0
            LabelSlot *ls = &s->cur_func->label_slots[i];
26486
0
            if (ls->pos >= pos_next && ls->pos < pos_expr)
26487
0
                ls->pos += offset;
26488
0
        }
26489
0
    }
26490
26491
0
    emit_label(s, label_body);
26492
0
    if (js_parse_statement(s))
26493
0
        return -1;
26494
26495
0
    close_scopes(s, s->cur_func->scope_level, block_scope_level);
26496
26497
0
    emit_label(s, label_cont);
26498
0
    if (is_for_of) {
26499
0
        if (is_async) {
26500
            /* call the next method */
26501
            /* stack: iter_obj next catch_offset */
26502
0
            emit_op(s, OP_dup3);
26503
0
            emit_op(s, OP_drop);
26504
0
            emit_op(s, OP_call_method);
26505
0
            emit_u16(s, 0);
26506
            /* get the result of the promise */
26507
0
            emit_op(s, OP_await);
26508
            /* unwrap the value and done values */
26509
0
            emit_op(s, OP_iterator_get_value_done);
26510
0
        } else {
26511
0
            emit_op(s, OP_for_of_next);
26512
0
            emit_u8(s, 0);
26513
0
        }
26514
0
    } else {
26515
0
        emit_op(s, OP_for_in_next);
26516
0
    }
26517
    /* on stack: enum_rec / enum_obj value bool */
26518
0
    emit_goto(s, OP_if_false, label_next);
26519
    /* drop the undefined value from for_xx_next */
26520
0
    emit_op(s, OP_drop);
26521
26522
0
    emit_label(s, label_break);
26523
0
    if (is_for_of) {
26524
        /* close and drop enum_rec */
26525
0
        emit_op(s, OP_iterator_close);
26526
0
    } else {
26527
0
        emit_op(s, OP_drop);
26528
0
    }
26529
0
    pop_break_entry(s->cur_func);
26530
0
    pop_scope(s);
26531
0
    return 0;
26532
0
}
26533
26534
static void set_eval_ret_undefined(JSParseState *s)
26535
0
{
26536
0
    if (s->cur_func->eval_ret_idx >= 0) {
26537
0
        emit_op(s, OP_undefined);
26538
0
        emit_op(s, OP_put_loc);
26539
0
        emit_u16(s, s->cur_func->eval_ret_idx);
26540
0
    }
26541
0
}
26542
26543
static __exception int js_parse_statement_or_decl(JSParseState *s,
26544
                                                  int decl_mask)
26545
118
{
26546
118
    JSContext *ctx = s->ctx;
26547
118
    JSAtom label_name;
26548
118
    int tok;
26549
26550
    /* specific label handling */
26551
    /* XXX: support multiple labels on loop statements */
26552
118
    label_name = JS_ATOM_NULL;
26553
118
    if (is_label(s)) {
26554
0
        BlockEnv *be;
26555
26556
0
        label_name = JS_DupAtom(ctx, s->token.u.ident.atom);
26557
26558
0
        for (be = s->cur_func->top_break; be; be = be->prev) {
26559
0
            if (be->label_name == label_name) {
26560
0
                js_parse_error(s, "duplicate label name");
26561
0
                goto fail;
26562
0
            }
26563
0
        }
26564
26565
0
        if (next_token(s))
26566
0
            goto fail;
26567
0
        if (js_parse_expect(s, ':'))
26568
0
            goto fail;
26569
0
        if (s->token.val != TOK_FOR
26570
0
        &&  s->token.val != TOK_DO
26571
0
        &&  s->token.val != TOK_WHILE) {
26572
            /* labelled regular statement */
26573
0
            int label_break, mask;
26574
0
            BlockEnv break_entry;
26575
26576
0
            label_break = new_label(s);
26577
0
            push_break_entry(s->cur_func, &break_entry,
26578
0
                             label_name, label_break, -1, 0);
26579
0
            if (!(s->cur_func->js_mode & JS_MODE_STRICT) &&
26580
0
                (decl_mask & DECL_MASK_FUNC_WITH_LABEL)) {
26581
0
                mask = DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL;
26582
0
            } else {
26583
0
                mask = 0;
26584
0
            }
26585
0
            if (js_parse_statement_or_decl(s, mask))
26586
0
                goto fail;
26587
0
            emit_label(s, label_break);
26588
0
            pop_break_entry(s->cur_func);
26589
0
            goto done;
26590
0
        }
26591
0
    }
26592
26593
118
    switch(tok = s->token.val) {
26594
0
    case '{':
26595
0
        if (js_parse_block(s))
26596
0
            goto fail;
26597
0
        break;
26598
0
    case TOK_RETURN:
26599
0
        if (s->cur_func->is_eval) {
26600
0
            js_parse_error(s, "return not in a function");
26601
0
            goto fail;
26602
0
        }
26603
0
        if (s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
26604
0
            js_parse_error(s, "return in a static initializer block");
26605
0
            goto fail;
26606
0
        }
26607
0
        if (next_token(s))
26608
0
            goto fail;
26609
0
        if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) {
26610
0
            if (js_parse_expr(s))
26611
0
                goto fail;
26612
0
            emit_return(s, TRUE);
26613
0
        } else {
26614
0
            emit_return(s, FALSE);
26615
0
        }
26616
0
        if (js_parse_expect_semi(s))
26617
0
            goto fail;
26618
0
        break;
26619
0
    case TOK_THROW:
26620
0
        if (next_token(s))
26621
0
            goto fail;
26622
0
        if (s->got_lf) {
26623
0
            js_parse_error(s, "line terminator not allowed after throw");
26624
0
            goto fail;
26625
0
        }
26626
0
        if (js_parse_expr(s))
26627
0
            goto fail;
26628
0
        emit_op(s, OP_throw);
26629
0
        if (js_parse_expect_semi(s))
26630
0
            goto fail;
26631
0
        break;
26632
0
    case TOK_LET:
26633
0
    case TOK_CONST:
26634
0
    haslet:
26635
0
        if (!(decl_mask & DECL_MASK_OTHER)) {
26636
0
            js_parse_error(s, "lexical declarations can't appear in single-statement context");
26637
0
            goto fail;
26638
0
        }
26639
        /* fall thru */
26640
0
    case TOK_VAR:
26641
0
        if (next_token(s))
26642
0
            goto fail;
26643
0
        if (js_parse_var(s, TRUE, tok, FALSE))
26644
0
            goto fail;
26645
0
        if (js_parse_expect_semi(s))
26646
0
            goto fail;
26647
0
        break;
26648
0
    case TOK_IF:
26649
0
        {
26650
0
            int label1, label2, mask;
26651
0
            if (next_token(s))
26652
0
                goto fail;
26653
            /* create a new scope for `let f;if(1) function f(){}` */
26654
0
            push_scope(s);
26655
0
            set_eval_ret_undefined(s);
26656
0
            if (js_parse_expr_paren(s))
26657
0
                goto fail;
26658
0
            label1 = emit_goto(s, OP_if_false, -1);
26659
0
            if (s->cur_func->js_mode & JS_MODE_STRICT)
26660
0
                mask = 0;
26661
0
            else
26662
0
                mask = DECL_MASK_FUNC; /* Annex B.3.4 */
26663
26664
0
            if (js_parse_statement_or_decl(s, mask))
26665
0
                goto fail;
26666
26667
0
            if (s->token.val == TOK_ELSE) {
26668
0
                label2 = emit_goto(s, OP_goto, -1);
26669
0
                if (next_token(s))
26670
0
                    goto fail;
26671
26672
0
                emit_label(s, label1);
26673
0
                if (js_parse_statement_or_decl(s, mask))
26674
0
                    goto fail;
26675
26676
0
                label1 = label2;
26677
0
            }
26678
0
            emit_label(s, label1);
26679
0
            pop_scope(s);
26680
0
        }
26681
0
        break;
26682
0
    case TOK_WHILE:
26683
0
        {
26684
0
            int label_cont, label_break;
26685
0
            BlockEnv break_entry;
26686
26687
0
            label_cont = new_label(s);
26688
0
            label_break = new_label(s);
26689
26690
0
            push_break_entry(s->cur_func, &break_entry,
26691
0
                             label_name, label_break, label_cont, 0);
26692
26693
0
            if (next_token(s))
26694
0
                goto fail;
26695
26696
0
            set_eval_ret_undefined(s);
26697
26698
0
            emit_label(s, label_cont);
26699
0
            if (js_parse_expr_paren(s))
26700
0
                goto fail;
26701
0
            emit_goto(s, OP_if_false, label_break);
26702
26703
0
            if (js_parse_statement(s))
26704
0
                goto fail;
26705
0
            emit_goto(s, OP_goto, label_cont);
26706
26707
0
            emit_label(s, label_break);
26708
26709
0
            pop_break_entry(s->cur_func);
26710
0
        }
26711
0
        break;
26712
0
    case TOK_DO:
26713
0
        {
26714
0
            int label_cont, label_break, label1;
26715
0
            BlockEnv break_entry;
26716
26717
0
            label_cont = new_label(s);
26718
0
            label_break = new_label(s);
26719
0
            label1 = new_label(s);
26720
26721
0
            push_break_entry(s->cur_func, &break_entry,
26722
0
                             label_name, label_break, label_cont, 0);
26723
26724
0
            if (next_token(s))
26725
0
                goto fail;
26726
26727
0
            emit_label(s, label1);
26728
26729
0
            set_eval_ret_undefined(s);
26730
26731
0
            if (js_parse_statement(s))
26732
0
                goto fail;
26733
26734
0
            emit_label(s, label_cont);
26735
0
            if (js_parse_expect(s, TOK_WHILE))
26736
0
                goto fail;
26737
0
            if (js_parse_expr_paren(s))
26738
0
                goto fail;
26739
            /* Insert semicolon if missing */
26740
0
            if (s->token.val == ';') {
26741
0
                if (next_token(s))
26742
0
                    goto fail;
26743
0
            }
26744
0
            emit_goto(s, OP_if_true, label1);
26745
26746
0
            emit_label(s, label_break);
26747
26748
0
            pop_break_entry(s->cur_func);
26749
0
        }
26750
0
        break;
26751
0
    case TOK_FOR:
26752
0
        {
26753
0
            int label_cont, label_break, label_body, label_test;
26754
0
            int pos_cont, pos_body, block_scope_level;
26755
0
            BlockEnv break_entry;
26756
0
            int tok, bits;
26757
0
            BOOL is_async;
26758
26759
0
            if (next_token(s))
26760
0
                goto fail;
26761
26762
0
            set_eval_ret_undefined(s);
26763
0
            bits = 0;
26764
0
            is_async = FALSE;
26765
0
            if (s->token.val == '(') {
26766
0
                js_parse_skip_parens_token(s, &bits, FALSE);
26767
0
            } else if (s->token.val == TOK_AWAIT) {
26768
0
                if (!(s->cur_func->func_kind & JS_FUNC_ASYNC)) {
26769
0
                    js_parse_error(s, "for await is only valid in asynchronous functions");
26770
0
                    goto fail;
26771
0
                }
26772
0
                is_async = TRUE;
26773
0
                if (next_token(s))
26774
0
                    goto fail;
26775
0
                s->cur_func->has_await = TRUE;
26776
0
            }
26777
0
            if (js_parse_expect(s, '('))
26778
0
                goto fail;
26779
26780
0
            if (!(bits & SKIP_HAS_SEMI)) {
26781
                /* parse for/in or for/of */
26782
0
                if (js_parse_for_in_of(s, label_name, is_async))
26783
0
                    goto fail;
26784
0
                break;
26785
0
            }
26786
0
            block_scope_level = s->cur_func->scope_level;
26787
26788
            /* create scope for the lexical variables declared in the initial,
26789
               test and increment expressions */
26790
0
            push_scope(s);
26791
            /* initial expression */
26792
0
            tok = s->token.val;
26793
0
            if (tok != ';') {
26794
0
                switch (is_let(s, DECL_MASK_OTHER)) {
26795
0
                case TRUE:
26796
0
                    tok = TOK_LET;
26797
0
                    break;
26798
0
                case FALSE:
26799
0
                    break;
26800
0
                default:
26801
0
                    goto fail;
26802
0
                }
26803
0
                if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
26804
0
                    if (next_token(s))
26805
0
                        goto fail;
26806
0
                    if (js_parse_var(s, FALSE, tok, FALSE))
26807
0
                        goto fail;
26808
0
                } else {
26809
0
                    if (js_parse_expr2(s, FALSE))
26810
0
                        goto fail;
26811
0
                    emit_op(s, OP_drop);
26812
0
                }
26813
26814
                /* close the closures before the first iteration */
26815
0
                close_scopes(s, s->cur_func->scope_level, block_scope_level);
26816
0
            }
26817
0
            if (js_parse_expect(s, ';'))
26818
0
                goto fail;
26819
26820
0
            label_test = new_label(s);
26821
0
            label_cont = new_label(s);
26822
0
            label_body = new_label(s);
26823
0
            label_break = new_label(s);
26824
26825
0
            push_break_entry(s->cur_func, &break_entry,
26826
0
                             label_name, label_break, label_cont, 0);
26827
26828
            /* test expression */
26829
0
            if (s->token.val == ';') {
26830
                /* no test expression */
26831
0
                label_test = label_body;
26832
0
            } else {
26833
0
                emit_label(s, label_test);
26834
0
                if (js_parse_expr(s))
26835
0
                    goto fail;
26836
0
                emit_goto(s, OP_if_false, label_break);
26837
0
            }
26838
0
            if (js_parse_expect(s, ';'))
26839
0
                goto fail;
26840
26841
0
            if (s->token.val == ')') {
26842
                /* no end expression */
26843
0
                break_entry.label_cont = label_cont = label_test;
26844
0
                pos_cont = 0; /* avoid warning */
26845
0
            } else {
26846
                /* skip the end expression */
26847
0
                emit_goto(s, OP_goto, label_body);
26848
26849
0
                pos_cont = s->cur_func->byte_code.size;
26850
0
                emit_label(s, label_cont);
26851
0
                if (js_parse_expr(s))
26852
0
                    goto fail;
26853
0
                emit_op(s, OP_drop);
26854
0
                if (label_test != label_body)
26855
0
                    emit_goto(s, OP_goto, label_test);
26856
0
            }
26857
0
            if (js_parse_expect(s, ')'))
26858
0
                goto fail;
26859
26860
0
            pos_body = s->cur_func->byte_code.size;
26861
0
            emit_label(s, label_body);
26862
0
            if (js_parse_statement(s))
26863
0
                goto fail;
26864
26865
            /* close the closures before the next iteration */
26866
            /* XXX: check continue case */
26867
0
            close_scopes(s, s->cur_func->scope_level, block_scope_level);
26868
26869
0
            if (OPTIMIZE && label_test != label_body && label_cont != label_test) {
26870
                /* move the increment code here */
26871
0
                DynBuf *bc = &s->cur_func->byte_code;
26872
0
                int chunk_size = pos_body - pos_cont;
26873
0
                int offset = bc->size - pos_cont;
26874
0
                int i;
26875
0
                dbuf_realloc(bc, bc->size + chunk_size);
26876
0
                dbuf_put(bc, bc->buf + pos_cont, chunk_size);
26877
0
                memset(bc->buf + pos_cont, OP_nop, chunk_size);
26878
                /* increment part ends with a goto */
26879
0
                s->cur_func->last_opcode_pos = bc->size - 5;
26880
                /* relocate labels */
26881
0
                for (i = label_cont; i < s->cur_func->label_count; i++) {
26882
0
                    LabelSlot *ls = &s->cur_func->label_slots[i];
26883
0
                    if (ls->pos >= pos_cont && ls->pos < pos_body)
26884
0
                        ls->pos += offset;
26885
0
                }
26886
0
            } else {
26887
0
                emit_goto(s, OP_goto, label_cont);
26888
0
            }
26889
26890
0
            emit_label(s, label_break);
26891
26892
0
            pop_break_entry(s->cur_func);
26893
0
            pop_scope(s);
26894
0
        }
26895
0
        break;
26896
0
    case TOK_BREAK:
26897
0
    case TOK_CONTINUE:
26898
0
        {
26899
0
            int is_cont = s->token.val - TOK_BREAK;
26900
0
            int label;
26901
26902
0
            if (next_token(s))
26903
0
                goto fail;
26904
0
            if (!s->got_lf && s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
26905
0
                label = s->token.u.ident.atom;
26906
0
            else
26907
0
                label = JS_ATOM_NULL;
26908
0
            if (emit_break(s, label, is_cont))
26909
0
                goto fail;
26910
0
            if (label != JS_ATOM_NULL) {
26911
0
                if (next_token(s))
26912
0
                    goto fail;
26913
0
            }
26914
0
            if (js_parse_expect_semi(s))
26915
0
                goto fail;
26916
0
        }
26917
0
        break;
26918
0
    case TOK_SWITCH:
26919
0
        {
26920
0
            int label_case, label_break, label1;
26921
0
            int default_label_pos;
26922
0
            BlockEnv break_entry;
26923
26924
0
            if (next_token(s))
26925
0
                goto fail;
26926
26927
0
            set_eval_ret_undefined(s);
26928
0
            if (js_parse_expr_paren(s))
26929
0
                goto fail;
26930
26931
0
            push_scope(s);
26932
0
            label_break = new_label(s);
26933
0
            push_break_entry(s->cur_func, &break_entry,
26934
0
                             label_name, label_break, -1, 1);
26935
26936
0
            if (js_parse_expect(s, '{'))
26937
0
                goto fail;
26938
26939
0
            default_label_pos = -1;
26940
0
            label_case = -1;
26941
0
            while (s->token.val != '}') {
26942
0
                if (s->token.val == TOK_CASE) {
26943
0
                    label1 = -1;
26944
0
                    if (label_case >= 0) {
26945
                        /* skip the case if needed */
26946
0
                        label1 = emit_goto(s, OP_goto, -1);
26947
0
                    }
26948
0
                    emit_label(s, label_case);
26949
0
                    label_case = -1;
26950
0
                    for (;;) {
26951
                        /* parse a sequence of case clauses */
26952
0
                        if (next_token(s))
26953
0
                            goto fail;
26954
0
                        emit_op(s, OP_dup);
26955
0
                        if (js_parse_expr(s))
26956
0
                            goto fail;
26957
0
                        if (js_parse_expect(s, ':'))
26958
0
                            goto fail;
26959
0
                        emit_op(s, OP_strict_eq);
26960
0
                        if (s->token.val == TOK_CASE) {
26961
0
                            label1 = emit_goto(s, OP_if_true, label1);
26962
0
                        } else {
26963
0
                            label_case = emit_goto(s, OP_if_false, -1);
26964
0
                            emit_label(s, label1);
26965
0
                            break;
26966
0
                        }
26967
0
                    }
26968
0
                } else if (s->token.val == TOK_DEFAULT) {
26969
0
                    if (next_token(s))
26970
0
                        goto fail;
26971
0
                    if (js_parse_expect(s, ':'))
26972
0
                        goto fail;
26973
0
                    if (default_label_pos >= 0) {
26974
0
                        js_parse_error(s, "duplicate default");
26975
0
                        goto fail;
26976
0
                    }
26977
0
                    if (label_case < 0) {
26978
                        /* falling thru direct from switch expression */
26979
0
                        label_case = emit_goto(s, OP_goto, -1);
26980
0
                    }
26981
                    /* Emit a dummy label opcode. Label will be patched after
26982
                       the end of the switch body. Do not use emit_label(s, 0)
26983
                       because it would clobber label 0 address, preventing
26984
                       proper optimizer operation.
26985
                     */
26986
0
                    emit_op(s, OP_label);
26987
0
                    emit_u32(s, 0);
26988
0
                    default_label_pos = s->cur_func->byte_code.size - 4;
26989
0
                } else {
26990
0
                    if (label_case < 0) {
26991
                        /* falling thru direct from switch expression */
26992
0
                        js_parse_error(s, "invalid switch statement");
26993
0
                        goto fail;
26994
0
                    }
26995
0
                    if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
26996
0
                        goto fail;
26997
0
                }
26998
0
            }
26999
0
            if (js_parse_expect(s, '}'))
27000
0
                goto fail;
27001
0
            if (default_label_pos >= 0) {
27002
                /* Ugly patch for the the `default` label, shameful and risky */
27003
0
                put_u32(s->cur_func->byte_code.buf + default_label_pos,
27004
0
                        label_case);
27005
0
                s->cur_func->label_slots[label_case].pos = default_label_pos + 4;
27006
0
            } else {
27007
0
                emit_label(s, label_case);
27008
0
            }
27009
0
            emit_label(s, label_break);
27010
0
            emit_op(s, OP_drop); /* drop the switch expression */
27011
27012
0
            pop_break_entry(s->cur_func);
27013
0
            pop_scope(s);
27014
0
        }
27015
0
        break;
27016
0
    case TOK_TRY:
27017
0
        {
27018
0
            int label_catch, label_catch2, label_finally, label_end;
27019
0
            JSAtom name;
27020
0
            BlockEnv block_env;
27021
27022
0
            set_eval_ret_undefined(s);
27023
0
            if (next_token(s))
27024
0
                goto fail;
27025
0
            label_catch = new_label(s);
27026
0
            label_catch2 = new_label(s);
27027
0
            label_finally = new_label(s);
27028
0
            label_end = new_label(s);
27029
27030
0
            emit_goto(s, OP_catch, label_catch);
27031
27032
0
            push_break_entry(s->cur_func, &block_env,
27033
0
                             JS_ATOM_NULL, -1, -1, 1);
27034
0
            block_env.label_finally = label_finally;
27035
27036
0
            if (js_parse_block(s))
27037
0
                goto fail;
27038
27039
0
            pop_break_entry(s->cur_func);
27040
27041
0
            if (js_is_live_code(s)) {
27042
                /* drop the catch offset */
27043
0
                emit_op(s, OP_drop);
27044
                /* must push dummy value to keep same stack size */
27045
0
                emit_op(s, OP_undefined);
27046
0
                emit_goto(s, OP_gosub, label_finally);
27047
0
                emit_op(s, OP_drop);
27048
27049
0
                emit_goto(s, OP_goto, label_end);
27050
0
            }
27051
27052
0
            if (s->token.val == TOK_CATCH) {
27053
0
                if (next_token(s))
27054
0
                    goto fail;
27055
27056
0
                push_scope(s);  /* catch variable */
27057
0
                emit_label(s, label_catch);
27058
27059
0
                if (s->token.val == '{') {
27060
                    /* support optional-catch-binding feature */
27061
0
                    emit_op(s, OP_drop);    /* pop the exception object */
27062
0
                } else {
27063
0
                    if (js_parse_expect(s, '('))
27064
0
                        goto fail;
27065
0
                    if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
27066
0
                        if (s->token.val == '[' || s->token.val == '{') {
27067
                            /* XXX: TOK_LET is not completely correct */
27068
0
                            if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE) < 0)
27069
0
                                goto fail;
27070
0
                        } else {
27071
0
                            js_parse_error(s, "identifier expected");
27072
0
                            goto fail;
27073
0
                        }
27074
0
                    } else {
27075
0
                        name = JS_DupAtom(ctx, s->token.u.ident.atom);
27076
0
                        if (next_token(s)
27077
0
                        ||  js_define_var(s, name, TOK_CATCH) < 0) {
27078
0
                            JS_FreeAtom(ctx, name);
27079
0
                            goto fail;
27080
0
                        }
27081
                        /* store the exception value in the catch variable */
27082
0
                        emit_op(s, OP_scope_put_var);
27083
0
                        emit_u32(s, name);
27084
0
                        emit_u16(s, s->cur_func->scope_level);
27085
0
                    }
27086
0
                    if (js_parse_expect(s, ')'))
27087
0
                        goto fail;
27088
0
                }
27089
                /* XXX: should keep the address to nop it out if there is no finally block */
27090
0
                emit_goto(s, OP_catch, label_catch2);
27091
27092
0
                push_scope(s);  /* catch block */
27093
0
                push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
27094
0
                                 -1, -1, 1);
27095
0
                block_env.label_finally = label_finally;
27096
27097
0
                if (js_parse_block(s))
27098
0
                    goto fail;
27099
27100
0
                pop_break_entry(s->cur_func);
27101
0
                pop_scope(s);  /* catch block */
27102
0
                pop_scope(s);  /* catch variable */
27103
27104
0
                if (js_is_live_code(s)) {
27105
                    /* drop the catch2 offset */
27106
0
                    emit_op(s, OP_drop);
27107
                    /* XXX: should keep the address to nop it out if there is no finally block */
27108
                    /* must push dummy value to keep same stack size */
27109
0
                    emit_op(s, OP_undefined);
27110
0
                    emit_goto(s, OP_gosub, label_finally);
27111
0
                    emit_op(s, OP_drop);
27112
0
                    emit_goto(s, OP_goto, label_end);
27113
0
                }
27114
                /* catch exceptions thrown in the catch block to execute the
27115
                 * finally clause and rethrow the exception */
27116
0
                emit_label(s, label_catch2);
27117
                /* catch value is at TOS, no need to push undefined */
27118
0
                emit_goto(s, OP_gosub, label_finally);
27119
0
                emit_op(s, OP_throw);
27120
27121
0
            } else if (s->token.val == TOK_FINALLY) {
27122
                /* finally without catch : execute the finally clause
27123
                 * and rethrow the exception */
27124
0
                emit_label(s, label_catch);
27125
                /* catch value is at TOS, no need to push undefined */
27126
0
                emit_goto(s, OP_gosub, label_finally);
27127
0
                emit_op(s, OP_throw);
27128
0
            } else {
27129
0
                js_parse_error(s, "expecting catch or finally");
27130
0
                goto fail;
27131
0
            }
27132
0
            emit_label(s, label_finally);
27133
0
            if (s->token.val == TOK_FINALLY) {
27134
0
                int saved_eval_ret_idx = 0; /* avoid warning */
27135
27136
0
                if (next_token(s))
27137
0
                    goto fail;
27138
                /* on the stack: ret_value gosub_ret_value */
27139
0
                push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
27140
0
                                 -1, -1, 2);
27141
27142
0
                if (s->cur_func->eval_ret_idx >= 0) {
27143
                    /* 'finally' updates eval_ret only if not a normal
27144
                       termination */
27145
0
                    saved_eval_ret_idx =
27146
0
                        add_var(s->ctx, s->cur_func, JS_ATOM__ret_);
27147
0
                    if (saved_eval_ret_idx < 0)
27148
0
                        goto fail;
27149
0
                    emit_op(s, OP_get_loc);
27150
0
                    emit_u16(s, s->cur_func->eval_ret_idx);
27151
0
                    emit_op(s, OP_put_loc);
27152
0
                    emit_u16(s, saved_eval_ret_idx);
27153
0
                    set_eval_ret_undefined(s);
27154
0
                }
27155
27156
0
                if (js_parse_block(s))
27157
0
                    goto fail;
27158
27159
0
                if (s->cur_func->eval_ret_idx >= 0) {
27160
0
                    emit_op(s, OP_get_loc);
27161
0
                    emit_u16(s, saved_eval_ret_idx);
27162
0
                    emit_op(s, OP_put_loc);
27163
0
                    emit_u16(s, s->cur_func->eval_ret_idx);
27164
0
                }
27165
0
                pop_break_entry(s->cur_func);
27166
0
            }
27167
0
            emit_op(s, OP_ret);
27168
0
            emit_label(s, label_end);
27169
0
        }
27170
0
        break;
27171
0
    case ';':
27172
        /* empty statement */
27173
0
        if (next_token(s))
27174
0
            goto fail;
27175
0
        break;
27176
0
    case TOK_WITH:
27177
0
        if (s->cur_func->js_mode & JS_MODE_STRICT) {
27178
0
            js_parse_error(s, "invalid keyword: with");
27179
0
            goto fail;
27180
0
        } else {
27181
0
            int with_idx;
27182
27183
0
            if (next_token(s))
27184
0
                goto fail;
27185
27186
0
            if (js_parse_expr_paren(s))
27187
0
                goto fail;
27188
27189
0
            push_scope(s);
27190
0
            with_idx = define_var(s, s->cur_func, JS_ATOM__with_,
27191
0
                                  JS_VAR_DEF_WITH);
27192
0
            if (with_idx < 0)
27193
0
                goto fail;
27194
0
            emit_op(s, OP_to_object);
27195
0
            emit_op(s, OP_put_loc);
27196
0
            emit_u16(s, with_idx);
27197
27198
0
            set_eval_ret_undefined(s);
27199
0
            if (js_parse_statement(s))
27200
0
                goto fail;
27201
27202
            /* Popping scope drops lexical context for the with object variable */
27203
0
            pop_scope(s);
27204
0
        }
27205
0
        break;
27206
0
    case TOK_FUNCTION:
27207
        /* ES6 Annex B.3.2 and B.3.3 semantics */
27208
0
        if (!(decl_mask & DECL_MASK_FUNC))
27209
0
            goto func_decl_error;
27210
0
        if (!(decl_mask & DECL_MASK_OTHER) && peek_token(s, FALSE) == '*')
27211
0
            goto func_decl_error;
27212
0
        goto parse_func_var;
27213
86
    case TOK_IDENT:
27214
86
        if (s->token.u.ident.is_reserved) {
27215
0
            js_parse_error_reserved_identifier(s);
27216
0
            goto fail;
27217
0
        }
27218
        /* Determine if `let` introduces a Declaration or an ExpressionStatement */
27219
86
        switch (is_let(s, decl_mask)) {
27220
0
        case TRUE:
27221
0
            tok = TOK_LET;
27222
0
            goto haslet;
27223
86
        case FALSE:
27224
86
            break;
27225
0
        default:
27226
0
            goto fail;
27227
86
        }
27228
86
        if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
27229
86
            peek_token(s, TRUE) == TOK_FUNCTION) {
27230
0
            if (!(decl_mask & DECL_MASK_OTHER)) {
27231
0
            func_decl_error:
27232
0
                js_parse_error(s, "function declarations can't appear in single-statement context");
27233
0
                goto fail;
27234
0
            }
27235
0
        parse_func_var:
27236
0
            if (js_parse_function_decl(s, JS_PARSE_FUNC_VAR,
27237
0
                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
27238
0
                                       s->token.ptr, s->token.line_num))
27239
0
                goto fail;
27240
0
            break;
27241
0
        }
27242
86
        goto hasexpr;
27243
27244
86
    case TOK_CLASS:
27245
0
        if (!(decl_mask & DECL_MASK_OTHER)) {
27246
0
            js_parse_error(s, "class declarations can't appear in single-statement context");
27247
0
            goto fail;
27248
0
        }
27249
0
        if (js_parse_class(s, FALSE, JS_PARSE_EXPORT_NONE))
27250
0
            return -1;
27251
0
        break;
27252
27253
0
    case TOK_DEBUGGER:
27254
        /* currently no debugger, so just skip the keyword */
27255
0
        if (next_token(s))
27256
0
            goto fail;
27257
0
        if (js_parse_expect_semi(s))
27258
0
            goto fail;
27259
0
        break;
27260
27261
0
    case TOK_ENUM:
27262
0
    case TOK_EXPORT:
27263
0
    case TOK_EXTENDS:
27264
0
        js_unsupported_keyword(s, s->token.u.ident.atom);
27265
0
        goto fail;
27266
27267
32
    default:
27268
118
    hasexpr:
27269
118
        if (js_parse_expr(s))
27270
10
            goto fail;
27271
108
        if (s->cur_func->eval_ret_idx >= 0) {
27272
            /* store the expression value so that it can be returned
27273
               by eval() */
27274
30
            emit_op(s, OP_put_loc);
27275
30
            emit_u16(s, s->cur_func->eval_ret_idx);
27276
78
        } else {
27277
78
            emit_op(s, OP_drop); /* drop the result */
27278
78
        }
27279
108
        if (js_parse_expect_semi(s))
27280
4
            goto fail;
27281
104
        break;
27282
118
    }
27283
104
done:
27284
104
    JS_FreeAtom(ctx, label_name);
27285
104
    return 0;
27286
14
fail:
27287
14
    JS_FreeAtom(ctx, label_name);
27288
14
    return -1;
27289
118
}
27290
27291
/* 'name' is freed */
27292
static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
27293
119
{
27294
119
    JSModuleDef *m;
27295
119
    m = js_mallocz(ctx, sizeof(*m));
27296
119
    if (!m) {
27297
0
        JS_FreeAtom(ctx, name);
27298
0
        return NULL;
27299
0
    }
27300
119
    m->header.ref_count = 1;
27301
119
    m->module_name = name;
27302
119
    m->module_ns = JS_UNDEFINED;
27303
119
    m->func_obj = JS_UNDEFINED;
27304
119
    m->eval_exception = JS_UNDEFINED;
27305
119
    m->meta_obj = JS_UNDEFINED;
27306
119
    m->promise = JS_UNDEFINED;
27307
119
    m->resolving_funcs[0] = JS_UNDEFINED;
27308
119
    m->resolving_funcs[1] = JS_UNDEFINED;
27309
119
    list_add_tail(&m->link, &ctx->loaded_modules);
27310
119
    return m;
27311
119
}
27312
27313
static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
27314
                               JS_MarkFunc *mark_func)
27315
442
{
27316
442
    int i;
27317
27318
14.7k
    for(i = 0; i < m->export_entries_count; i++) {
27319
14.3k
        JSExportEntry *me = &m->export_entries[i];
27320
14.3k
        if (me->export_type == JS_EXPORT_TYPE_LOCAL &&
27321
14.3k
            me->u.local.var_ref) {
27322
14.3k
            mark_func(rt, &me->u.local.var_ref->header);
27323
14.3k
        }
27324
14.3k
    }
27325
27326
442
    JS_MarkValue(rt, m->module_ns, mark_func);
27327
442
    JS_MarkValue(rt, m->func_obj, mark_func);
27328
442
    JS_MarkValue(rt, m->eval_exception, mark_func);
27329
442
    JS_MarkValue(rt, m->meta_obj, mark_func);
27330
442
    JS_MarkValue(rt, m->promise, mark_func);
27331
442
    JS_MarkValue(rt, m->resolving_funcs[0], mark_func);
27332
442
    JS_MarkValue(rt, m->resolving_funcs[1], mark_func);
27333
442
}
27334
27335
static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
27336
119
{
27337
119
    int i;
27338
27339
119
    JS_FreeAtom(ctx, m->module_name);
27340
27341
197
    for(i = 0; i < m->req_module_entries_count; i++) {
27342
78
        JSReqModuleEntry *rme = &m->req_module_entries[i];
27343
78
        JS_FreeAtom(ctx, rme->module_name);
27344
78
    }
27345
119
    js_free(ctx, m->req_module_entries);
27346
27347
3.94k
    for(i = 0; i < m->export_entries_count; i++) {
27348
3.82k
        JSExportEntry *me = &m->export_entries[i];
27349
3.82k
        if (me->export_type == JS_EXPORT_TYPE_LOCAL)
27350
3.82k
            free_var_ref(ctx->rt, me->u.local.var_ref);
27351
3.82k
        JS_FreeAtom(ctx, me->export_name);
27352
3.82k
        JS_FreeAtom(ctx, me->local_name);
27353
3.82k
    }
27354
119
    js_free(ctx, m->export_entries);
27355
27356
119
    js_free(ctx, m->star_export_entries);
27357
27358
197
    for(i = 0; i < m->import_entries_count; i++) {
27359
78
        JSImportEntry *mi = &m->import_entries[i];
27360
78
        JS_FreeAtom(ctx, mi->import_name);
27361
78
    }
27362
119
    js_free(ctx, m->import_entries);
27363
119
    js_free(ctx, m->async_parent_modules);
27364
27365
119
    JS_FreeValue(ctx, m->module_ns);
27366
119
    JS_FreeValue(ctx, m->func_obj);
27367
119
    JS_FreeValue(ctx, m->eval_exception);
27368
119
    JS_FreeValue(ctx, m->meta_obj);
27369
119
    JS_FreeValue(ctx, m->promise);
27370
119
    JS_FreeValue(ctx, m->resolving_funcs[0]);
27371
119
    JS_FreeValue(ctx, m->resolving_funcs[1]);
27372
119
    list_del(&m->link);
27373
119
    js_free(ctx, m);
27374
119
}
27375
27376
static int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
27377
                                JSAtom module_name)
27378
78
{
27379
78
    JSReqModuleEntry *rme;
27380
78
    int i;
27381
27382
    /* no need to add the module request if it is already present */
27383
117
    for(i = 0; i < m->req_module_entries_count; i++) {
27384
39
        rme = &m->req_module_entries[i];
27385
39
        if (rme->module_name == module_name)
27386
0
            return i;
27387
39
    }
27388
27389
78
    if (js_resize_array(ctx, (void **)&m->req_module_entries,
27390
78
                        sizeof(JSReqModuleEntry),
27391
78
                        &m->req_module_entries_size,
27392
78
                        m->req_module_entries_count + 1))
27393
0
        return -1;
27394
78
    rme = &m->req_module_entries[m->req_module_entries_count++];
27395
78
    rme->module_name = JS_DupAtom(ctx, module_name);
27396
78
    rme->module = NULL;
27397
78
    return i;
27398
78
}
27399
27400
static JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m,
27401
                                        JSAtom export_name)
27402
7.64k
{
27403
7.64k
    JSExportEntry *me;
27404
7.64k
    int i;
27405
232k
    for(i = 0; i < m->export_entries_count; i++) {
27406
228k
        me = &m->export_entries[i];
27407
228k
        if (me->export_name == export_name)
27408
3.82k
            return me;
27409
228k
    }
27410
3.82k
    return NULL;
27411
7.64k
}
27412
27413
static JSExportEntry *add_export_entry2(JSContext *ctx,
27414
                                        JSParseState *s, JSModuleDef *m,
27415
                                       JSAtom local_name, JSAtom export_name,
27416
                                       JSExportTypeEnum export_type)
27417
3.82k
{
27418
3.82k
    JSExportEntry *me;
27419
27420
3.82k
    if (find_export_entry(ctx, m, export_name)) {
27421
0
        char buf1[ATOM_GET_STR_BUF_SIZE];
27422
0
        if (s) {
27423
0
            js_parse_error(s, "duplicate exported name '%s'",
27424
0
                           JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name));
27425
0
        } else {
27426
0
            JS_ThrowSyntaxErrorAtom(ctx, "duplicate exported name '%s'", export_name);
27427
0
        }
27428
0
        return NULL;
27429
0
    }
27430
27431
3.82k
    if (js_resize_array(ctx, (void **)&m->export_entries,
27432
3.82k
                        sizeof(JSExportEntry),
27433
3.82k
                        &m->export_entries_size,
27434
3.82k
                        m->export_entries_count + 1))
27435
0
        return NULL;
27436
3.82k
    me = &m->export_entries[m->export_entries_count++];
27437
3.82k
    memset(me, 0, sizeof(*me));
27438
3.82k
    me->local_name = JS_DupAtom(ctx, local_name);
27439
3.82k
    me->export_name = JS_DupAtom(ctx, export_name);
27440
3.82k
    me->export_type = export_type;
27441
3.82k
    return me;
27442
3.82k
}
27443
27444
static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
27445
                                       JSAtom local_name, JSAtom export_name,
27446
                                       JSExportTypeEnum export_type)
27447
0
{
27448
0
    return add_export_entry2(s->ctx, s, m, local_name, export_name,
27449
0
                             export_type);
27450
0
}
27451
27452
static int add_star_export_entry(JSContext *ctx, JSModuleDef *m,
27453
                                 int req_module_idx)
27454
0
{
27455
0
    JSStarExportEntry *se;
27456
27457
0
    if (js_resize_array(ctx, (void **)&m->star_export_entries,
27458
0
                        sizeof(JSStarExportEntry),
27459
0
                        &m->star_export_entries_size,
27460
0
                        m->star_export_entries_count + 1))
27461
0
        return -1;
27462
0
    se = &m->star_export_entries[m->star_export_entries_count++];
27463
0
    se->req_module_idx = req_module_idx;
27464
0
    return 0;
27465
0
}
27466
27467
/* create a C module */
27468
JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
27469
                           JSModuleInitFunc *func)
27470
78
{
27471
78
    JSModuleDef *m;
27472
78
    JSAtom name;
27473
78
    name = JS_NewAtom(ctx, name_str);
27474
78
    if (name == JS_ATOM_NULL)
27475
0
        return NULL;
27476
78
    m = js_new_module_def(ctx, name);
27477
78
    m->init_func = func;
27478
78
    return m;
27479
78
}
27480
27481
int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name)
27482
3.82k
{
27483
3.82k
    JSExportEntry *me;
27484
3.82k
    JSAtom name;
27485
3.82k
    name = JS_NewAtom(ctx, export_name);
27486
3.82k
    if (name == JS_ATOM_NULL)
27487
0
        return -1;
27488
3.82k
    me = add_export_entry2(ctx, NULL, m, JS_ATOM_NULL, name,
27489
3.82k
                           JS_EXPORT_TYPE_LOCAL);
27490
3.82k
    JS_FreeAtom(ctx, name);
27491
3.82k
    if (!me)
27492
0
        return -1;
27493
3.82k
    else
27494
3.82k
        return 0;
27495
3.82k
}
27496
27497
int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
27498
                       JSValue val)
27499
3.82k
{
27500
3.82k
    JSExportEntry *me;
27501
3.82k
    JSAtom name;
27502
3.82k
    name = JS_NewAtom(ctx, export_name);
27503
3.82k
    if (name == JS_ATOM_NULL)
27504
0
        goto fail;
27505
3.82k
    me = find_export_entry(ctx, m, name);
27506
3.82k
    JS_FreeAtom(ctx, name);
27507
3.82k
    if (!me)
27508
0
        goto fail;
27509
3.82k
    set_value(ctx, me->u.local.var_ref->pvalue, val);
27510
3.82k
    return 0;
27511
0
 fail:
27512
0
    JS_FreeValue(ctx, val);
27513
0
    return -1;
27514
3.82k
}
27515
27516
void JS_SetModuleLoaderFunc(JSRuntime *rt,
27517
                            JSModuleNormalizeFunc *module_normalize,
27518
                            JSModuleLoaderFunc *module_loader, void *opaque)
27519
39
{
27520
39
    rt->module_normalize_func = module_normalize;
27521
39
    rt->module_loader_func = module_loader;
27522
39
    rt->module_loader_opaque = opaque;
27523
39
}
27524
27525
/* default module filename normalizer */
27526
static char *js_default_module_normalize_name(JSContext *ctx,
27527
                                              const char *base_name,
27528
                                              const char *name)
27529
78
{
27530
78
    char *filename, *p;
27531
78
    const char *r;
27532
78
    int cap;
27533
78
    int len;
27534
27535
78
    if (name[0] != '.') {
27536
        /* if no initial dot, the module name is not modified */
27537
78
        return js_strdup(ctx, name);
27538
78
    }
27539
27540
0
    p = strrchr(base_name, '/');
27541
0
    if (p)
27542
0
        len = p - base_name;
27543
0
    else
27544
0
        len = 0;
27545
27546
0
    cap = len + strlen(name) + 1 + 1;
27547
0
    filename = js_malloc(ctx, cap);
27548
0
    if (!filename)
27549
0
        return NULL;
27550
0
    memcpy(filename, base_name, len);
27551
0
    filename[len] = '\0';
27552
27553
    /* we only normalize the leading '..' or '.' */
27554
0
    r = name;
27555
0
    for(;;) {
27556
0
        if (r[0] == '.' && r[1] == '/') {
27557
0
            r += 2;
27558
0
        } else if (r[0] == '.' && r[1] == '.' && r[2] == '/') {
27559
            /* remove the last path element of filename, except if "."
27560
               or ".." */
27561
0
            if (filename[0] == '\0')
27562
0
                break;
27563
0
            p = strrchr(filename, '/');
27564
0
            if (!p)
27565
0
                p = filename;
27566
0
            else
27567
0
                p++;
27568
0
            if (!strcmp(p, ".") || !strcmp(p, ".."))
27569
0
                break;
27570
0
            if (p > filename)
27571
0
                p--;
27572
0
            *p = '\0';
27573
0
            r += 3;
27574
0
        } else {
27575
0
            break;
27576
0
        }
27577
0
    }
27578
0
    if (filename[0] != '\0')
27579
0
        pstrcat(filename, cap, "/");
27580
0
    pstrcat(filename, cap, r);
27581
    //    printf("normalize: %s %s -> %s\n", base_name, name, filename);
27582
0
    return filename;
27583
0
}
27584
27585
static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name)
27586
78
{
27587
78
    struct list_head *el;
27588
78
    JSModuleDef *m;
27589
27590
    /* first look at the loaded modules */
27591
117
    list_for_each(el, &ctx->loaded_modules) {
27592
117
        m = list_entry(el, JSModuleDef, link);
27593
117
        if (m->module_name == name)
27594
78
            return m;
27595
117
    }
27596
0
    return NULL;
27597
78
}
27598
27599
/* return NULL in case of exception (e.g. module could not be loaded) */
27600
static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx,
27601
                                                    const char *base_cname,
27602
                                                    const char *cname1)
27603
78
{
27604
78
    JSRuntime *rt = ctx->rt;
27605
78
    JSModuleDef *m;
27606
78
    char *cname;
27607
78
    JSAtom module_name;
27608
27609
78
    if (!rt->module_normalize_func) {
27610
78
        cname = js_default_module_normalize_name(ctx, base_cname, cname1);
27611
78
    } else {
27612
0
        cname = rt->module_normalize_func(ctx, base_cname, cname1,
27613
0
                                          rt->module_loader_opaque);
27614
0
    }
27615
78
    if (!cname)
27616
0
        return NULL;
27617
27618
78
    module_name = JS_NewAtom(ctx, cname);
27619
78
    if (module_name == JS_ATOM_NULL) {
27620
0
        js_free(ctx, cname);
27621
0
        return NULL;
27622
0
    }
27623
27624
    /* first look at the loaded modules */
27625
78
    m = js_find_loaded_module(ctx, module_name);
27626
78
    if (m) {
27627
78
        js_free(ctx, cname);
27628
78
        JS_FreeAtom(ctx, module_name);
27629
78
        return m;
27630
78
    }
27631
27632
0
    JS_FreeAtom(ctx, module_name);
27633
27634
    /* load the module */
27635
0
    if (!rt->module_loader_func) {
27636
        /* XXX: use a syntax error ? */
27637
0
        JS_ThrowReferenceError(ctx, "could not load module '%s'",
27638
0
                               cname);
27639
0
        js_free(ctx, cname);
27640
0
        return NULL;
27641
0
    }
27642
27643
0
    m = rt->module_loader_func(ctx, cname, rt->module_loader_opaque);
27644
0
    js_free(ctx, cname);
27645
0
    return m;
27646
0
}
27647
27648
static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx,
27649
                                                    JSAtom base_module_name,
27650
                                                    JSAtom module_name1)
27651
78
{
27652
78
    const char *base_cname, *cname;
27653
78
    JSModuleDef *m;
27654
27655
78
    base_cname = JS_AtomToCString(ctx, base_module_name);
27656
78
    if (!base_cname)
27657
0
        return NULL;
27658
78
    cname = JS_AtomToCString(ctx, module_name1);
27659
78
    if (!cname) {
27660
0
        JS_FreeCString(ctx, base_cname);
27661
0
        return NULL;
27662
0
    }
27663
78
    m = js_host_resolve_imported_module(ctx, base_cname, cname);
27664
78
    JS_FreeCString(ctx, base_cname);
27665
78
    JS_FreeCString(ctx, cname);
27666
78
    return m;
27667
78
}
27668
27669
typedef struct JSResolveEntry {
27670
    JSModuleDef *module;
27671
    JSAtom name;
27672
} JSResolveEntry;
27673
27674
typedef struct JSResolveState {
27675
    JSResolveEntry *array;
27676
    int size;
27677
    int count;
27678
} JSResolveState;
27679
27680
static int find_resolve_entry(JSResolveState *s,
27681
                              JSModuleDef *m, JSAtom name)
27682
0
{
27683
0
    int i;
27684
0
    for(i = 0; i < s->count; i++) {
27685
0
        JSResolveEntry *re = &s->array[i];
27686
0
        if (re->module == m && re->name == name)
27687
0
            return i;
27688
0
    }
27689
0
    return -1;
27690
0
}
27691
27692
static int add_resolve_entry(JSContext *ctx, JSResolveState *s,
27693
                             JSModuleDef *m, JSAtom name)
27694
0
{
27695
0
    JSResolveEntry *re;
27696
27697
0
    if (js_resize_array(ctx, (void **)&s->array,
27698
0
                        sizeof(JSResolveEntry),
27699
0
                        &s->size, s->count + 1))
27700
0
        return -1;
27701
0
    re = &s->array[s->count++];
27702
0
    re->module = m;
27703
0
    re->name = JS_DupAtom(ctx, name);
27704
0
    return 0;
27705
0
}
27706
27707
typedef enum JSResolveResultEnum {
27708
    JS_RESOLVE_RES_EXCEPTION = -1, /* memory alloc error */
27709
    JS_RESOLVE_RES_FOUND = 0,
27710
    JS_RESOLVE_RES_NOT_FOUND,
27711
    JS_RESOLVE_RES_CIRCULAR,
27712
    JS_RESOLVE_RES_AMBIGUOUS,
27713
} JSResolveResultEnum;
27714
27715
static JSResolveResultEnum js_resolve_export1(JSContext *ctx,
27716
                                              JSModuleDef **pmodule,
27717
                                              JSExportEntry **pme,
27718
                                              JSModuleDef *m,
27719
                                              JSAtom export_name,
27720
                                              JSResolveState *s)
27721
0
{
27722
0
    JSExportEntry *me;
27723
27724
0
    *pmodule = NULL;
27725
0
    *pme = NULL;
27726
0
    if (find_resolve_entry(s, m, export_name) >= 0)
27727
0
        return JS_RESOLVE_RES_CIRCULAR;
27728
0
    if (add_resolve_entry(ctx, s, m, export_name) < 0)
27729
0
        return JS_RESOLVE_RES_EXCEPTION;
27730
0
    me = find_export_entry(ctx, m, export_name);
27731
0
    if (me) {
27732
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
27733
            /* local export */
27734
0
            *pmodule = m;
27735
0
            *pme = me;
27736
0
            return JS_RESOLVE_RES_FOUND;
27737
0
        } else {
27738
            /* indirect export */
27739
0
            JSModuleDef *m1;
27740
0
            m1 = m->req_module_entries[me->u.req_module_idx].module;
27741
0
            if (me->local_name == JS_ATOM__star_) {
27742
                /* export ns from */
27743
0
                *pmodule = m;
27744
0
                *pme = me;
27745
0
                return JS_RESOLVE_RES_FOUND;
27746
0
            } else {
27747
0
                return js_resolve_export1(ctx, pmodule, pme, m1,
27748
0
                                          me->local_name, s);
27749
0
            }
27750
0
        }
27751
0
    } else {
27752
0
        if (export_name != JS_ATOM_default) {
27753
            /* not found in direct or indirect exports: try star exports */
27754
0
            int i;
27755
27756
0
            for(i = 0; i < m->star_export_entries_count; i++) {
27757
0
                JSStarExportEntry *se = &m->star_export_entries[i];
27758
0
                JSModuleDef *m1, *res_m;
27759
0
                JSExportEntry *res_me;
27760
0
                JSResolveResultEnum ret;
27761
27762
0
                m1 = m->req_module_entries[se->req_module_idx].module;
27763
0
                ret = js_resolve_export1(ctx, &res_m, &res_me, m1,
27764
0
                                         export_name, s);
27765
0
                if (ret == JS_RESOLVE_RES_AMBIGUOUS ||
27766
0
                    ret == JS_RESOLVE_RES_EXCEPTION) {
27767
0
                    return ret;
27768
0
                } else if (ret == JS_RESOLVE_RES_FOUND) {
27769
0
                    if (*pme != NULL) {
27770
0
                        if (*pmodule != res_m ||
27771
0
                            res_me->local_name != (*pme)->local_name) {
27772
0
                            *pmodule = NULL;
27773
0
                            *pme = NULL;
27774
0
                            return JS_RESOLVE_RES_AMBIGUOUS;
27775
0
                        }
27776
0
                    } else {
27777
0
                        *pmodule = res_m;
27778
0
                        *pme = res_me;
27779
0
                    }
27780
0
                }
27781
0
            }
27782
0
            if (*pme != NULL)
27783
0
                return JS_RESOLVE_RES_FOUND;
27784
0
        }
27785
0
        return JS_RESOLVE_RES_NOT_FOUND;
27786
0
    }
27787
0
}
27788
27789
/* If the return value is JS_RESOLVE_RES_FOUND, return the module
27790
  (*pmodule) and the corresponding local export entry
27791
  (*pme). Otherwise return (NULL, NULL) */
27792
static JSResolveResultEnum js_resolve_export(JSContext *ctx,
27793
                                             JSModuleDef **pmodule,
27794
                                             JSExportEntry **pme,
27795
                                             JSModuleDef *m,
27796
                                             JSAtom export_name)
27797
0
{
27798
0
    JSResolveState ss, *s = &ss;
27799
0
    int i;
27800
0
    JSResolveResultEnum ret;
27801
27802
0
    s->array = NULL;
27803
0
    s->size = 0;
27804
0
    s->count = 0;
27805
27806
0
    ret = js_resolve_export1(ctx, pmodule, pme, m, export_name, s);
27807
27808
0
    for(i = 0; i < s->count; i++)
27809
0
        JS_FreeAtom(ctx, s->array[i].name);
27810
0
    js_free(ctx, s->array);
27811
27812
0
    return ret;
27813
0
}
27814
27815
static void js_resolve_export_throw_error(JSContext *ctx,
27816
                                          JSResolveResultEnum res,
27817
                                          JSModuleDef *m, JSAtom export_name)
27818
0
{
27819
0
    char buf1[ATOM_GET_STR_BUF_SIZE];
27820
0
    char buf2[ATOM_GET_STR_BUF_SIZE];
27821
0
    switch(res) {
27822
0
    case JS_RESOLVE_RES_EXCEPTION:
27823
0
        break;
27824
0
    default:
27825
0
    case JS_RESOLVE_RES_NOT_FOUND:
27826
0
        JS_ThrowSyntaxError(ctx, "Could not find export '%s' in module '%s'",
27827
0
                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
27828
0
                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
27829
0
        break;
27830
0
    case JS_RESOLVE_RES_CIRCULAR:
27831
0
        JS_ThrowSyntaxError(ctx, "circular reference when looking for export '%s' in module '%s'",
27832
0
                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
27833
0
                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
27834
0
        break;
27835
0
    case JS_RESOLVE_RES_AMBIGUOUS:
27836
0
        JS_ThrowSyntaxError(ctx, "export '%s' in module '%s' is ambiguous",
27837
0
                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
27838
0
                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
27839
0
        break;
27840
0
    }
27841
0
}
27842
27843
27844
typedef enum {
27845
    EXPORTED_NAME_AMBIGUOUS,
27846
    EXPORTED_NAME_NORMAL,
27847
    EXPORTED_NAME_NS,
27848
} ExportedNameEntryEnum;
27849
27850
typedef struct ExportedNameEntry {
27851
    JSAtom export_name;
27852
    ExportedNameEntryEnum export_type;
27853
    union {
27854
        JSExportEntry *me; /* using when the list is built */
27855
        JSVarRef *var_ref; /* EXPORTED_NAME_NORMAL */
27856
        JSModuleDef *module; /* for EXPORTED_NAME_NS */
27857
    } u;
27858
} ExportedNameEntry;
27859
27860
typedef struct GetExportNamesState {
27861
    JSModuleDef **modules;
27862
    int modules_size;
27863
    int modules_count;
27864
27865
    ExportedNameEntry *exported_names;
27866
    int exported_names_size;
27867
    int exported_names_count;
27868
} GetExportNamesState;
27869
27870
static int find_exported_name(GetExportNamesState *s, JSAtom name)
27871
3.82k
{
27872
3.82k
    int i;
27873
116k
    for(i = 0; i < s->exported_names_count; i++) {
27874
112k
        if (s->exported_names[i].export_name == name)
27875
0
            return i;
27876
112k
    }
27877
3.82k
    return -1;
27878
3.82k
}
27879
27880
static __exception int get_exported_names(JSContext *ctx,
27881
                                          GetExportNamesState *s,
27882
                                          JSModuleDef *m, BOOL from_star)
27883
78
{
27884
78
    ExportedNameEntry *en;
27885
78
    int i, j;
27886
27887
    /* check circular reference */
27888
78
    for(i = 0; i < s->modules_count; i++) {
27889
0
        if (s->modules[i] == m)
27890
0
            return 0;
27891
0
    }
27892
78
    if (js_resize_array(ctx, (void **)&s->modules, sizeof(s->modules[0]),
27893
78
                        &s->modules_size, s->modules_count + 1))
27894
0
        return -1;
27895
78
    s->modules[s->modules_count++] = m;
27896
27897
3.90k
    for(i = 0; i < m->export_entries_count; i++) {
27898
3.82k
        JSExportEntry *me = &m->export_entries[i];
27899
3.82k
        if (from_star && me->export_name == JS_ATOM_default)
27900
0
            continue;
27901
3.82k
        j = find_exported_name(s, me->export_name);
27902
3.82k
        if (j < 0) {
27903
3.82k
            if (js_resize_array(ctx, (void **)&s->exported_names, sizeof(s->exported_names[0]),
27904
3.82k
                                &s->exported_names_size,
27905
3.82k
                                s->exported_names_count + 1))
27906
0
                return -1;
27907
3.82k
            en = &s->exported_names[s->exported_names_count++];
27908
3.82k
            en->export_name = me->export_name;
27909
            /* avoid a second lookup for simple module exports */
27910
3.82k
            if (from_star || me->export_type != JS_EXPORT_TYPE_LOCAL)
27911
0
                en->u.me = NULL;
27912
3.82k
            else
27913
3.82k
                en->u.me = me;
27914
3.82k
        } else {
27915
0
            en = &s->exported_names[j];
27916
0
            en->u.me = NULL;
27917
0
        }
27918
3.82k
    }
27919
78
    for(i = 0; i < m->star_export_entries_count; i++) {
27920
0
        JSStarExportEntry *se = &m->star_export_entries[i];
27921
0
        JSModuleDef *m1;
27922
0
        m1 = m->req_module_entries[se->req_module_idx].module;
27923
0
        if (get_exported_names(ctx, s, m1, TRUE))
27924
0
            return -1;
27925
0
    }
27926
78
    return 0;
27927
78
}
27928
27929
/* Unfortunately, the spec gives a different behavior from GetOwnProperty ! */
27930
static int js_module_ns_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
27931
0
{
27932
0
    return (find_own_property1(JS_VALUE_GET_OBJ(obj), atom) != NULL);
27933
0
}
27934
27935
static const JSClassExoticMethods js_module_ns_exotic_methods = {
27936
    .has_property = js_module_ns_has,
27937
};
27938
27939
static int exported_names_cmp(const void *p1, const void *p2, void *opaque)
27940
19.2k
{
27941
19.2k
    JSContext *ctx = opaque;
27942
19.2k
    const ExportedNameEntry *me1 = p1;
27943
19.2k
    const ExportedNameEntry *me2 = p2;
27944
19.2k
    JSValue str1, str2;
27945
19.2k
    int ret;
27946
27947
    /* XXX: should avoid allocation memory in atom comparison */
27948
19.2k
    str1 = JS_AtomToString(ctx, me1->export_name);
27949
19.2k
    str2 = JS_AtomToString(ctx, me2->export_name);
27950
19.2k
    if (JS_IsException(str1) || JS_IsException(str2)) {
27951
        /* XXX: raise an error ? */
27952
0
        ret = 0;
27953
19.2k
    } else {
27954
19.2k
        ret = js_string_compare(ctx, JS_VALUE_GET_STRING(str1),
27955
19.2k
                                JS_VALUE_GET_STRING(str2));
27956
19.2k
    }
27957
19.2k
    JS_FreeValue(ctx, str1);
27958
19.2k
    JS_FreeValue(ctx, str2);
27959
19.2k
    return ret;
27960
19.2k
}
27961
27962
static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
27963
                                     void *opaque)
27964
0
{
27965
0
    JSModuleDef *m = opaque;
27966
0
    return JS_GetModuleNamespace(ctx, m);
27967
0
}
27968
27969
static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
27970
78
{
27971
78
    JSValue obj;
27972
78
    JSObject *p;
27973
78
    GetExportNamesState s_s, *s = &s_s;
27974
78
    int i, ret;
27975
78
    JSProperty *pr;
27976
27977
78
    obj = JS_NewObjectClass(ctx, JS_CLASS_MODULE_NS);
27978
78
    if (JS_IsException(obj))
27979
0
        return obj;
27980
78
    p = JS_VALUE_GET_OBJ(obj);
27981
27982
78
    memset(s, 0, sizeof(*s));
27983
78
    ret = get_exported_names(ctx, s, m, FALSE);
27984
78
    js_free(ctx, s->modules);
27985
78
    if (ret)
27986
0
        goto fail;
27987
27988
    /* Resolve the exported names. The ambiguous exports are removed */
27989
3.90k
    for(i = 0; i < s->exported_names_count; i++) {
27990
3.82k
        ExportedNameEntry *en = &s->exported_names[i];
27991
3.82k
        JSResolveResultEnum res;
27992
3.82k
        JSExportEntry *res_me;
27993
3.82k
        JSModuleDef *res_m;
27994
27995
3.82k
        if (en->u.me) {
27996
3.82k
            res_me = en->u.me; /* fast case: no resolution needed */
27997
3.82k
            res_m = m;
27998
3.82k
            res = JS_RESOLVE_RES_FOUND;
27999
3.82k
        } else {
28000
0
            res = js_resolve_export(ctx, &res_m, &res_me, m,
28001
0
                                    en->export_name);
28002
0
        }
28003
3.82k
        if (res != JS_RESOLVE_RES_FOUND) {
28004
0
            if (res != JS_RESOLVE_RES_AMBIGUOUS) {
28005
0
                js_resolve_export_throw_error(ctx, res, m, en->export_name);
28006
0
                goto fail;
28007
0
            }
28008
0
            en->export_type = EXPORTED_NAME_AMBIGUOUS;
28009
3.82k
        } else {
28010
3.82k
            if (res_me->local_name == JS_ATOM__star_) {
28011
0
                en->export_type = EXPORTED_NAME_NS;
28012
0
                en->u.module = res_m->req_module_entries[res_me->u.req_module_idx].module;
28013
3.82k
            } else {
28014
3.82k
                en->export_type = EXPORTED_NAME_NORMAL;
28015
3.82k
                if (res_me->u.local.var_ref) {
28016
3.82k
                    en->u.var_ref = res_me->u.local.var_ref;
28017
3.82k
                } else {
28018
0
                    JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
28019
0
                    p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
28020
0
                    en->u.var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
28021
0
                }
28022
3.82k
            }
28023
3.82k
        }
28024
3.82k
    }
28025
28026
    /* sort the exported names */
28027
78
    rqsort(s->exported_names, s->exported_names_count,
28028
78
           sizeof(s->exported_names[0]), exported_names_cmp, ctx);
28029
28030
3.90k
    for(i = 0; i < s->exported_names_count; i++) {
28031
3.82k
        ExportedNameEntry *en = &s->exported_names[i];
28032
3.82k
        switch(en->export_type) {
28033
3.82k
        case EXPORTED_NAME_NORMAL:
28034
3.82k
            {
28035
3.82k
                JSVarRef *var_ref = en->u.var_ref;
28036
3.82k
                pr = add_property(ctx, p, en->export_name,
28037
3.82k
                                  JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
28038
3.82k
                                  JS_PROP_VARREF);
28039
3.82k
                if (!pr)
28040
0
                    goto fail;
28041
3.82k
                var_ref->header.ref_count++;
28042
3.82k
                pr->u.var_ref = var_ref;
28043
3.82k
            }
28044
0
            break;
28045
0
        case EXPORTED_NAME_NS:
28046
            /* the exported namespace must be created on demand */
28047
0
            if (JS_DefineAutoInitProperty(ctx, obj,
28048
0
                                          en->export_name,
28049
0
                                          JS_AUTOINIT_ID_MODULE_NS,
28050
0
                                          en->u.module, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
28051
0
                goto fail;
28052
0
            break;
28053
0
        default:
28054
0
            break;
28055
3.82k
        }
28056
3.82k
    }
28057
28058
78
    js_free(ctx, s->exported_names);
28059
28060
78
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_toStringTag,
28061
78
                           JS_AtomToString(ctx, JS_ATOM_Module),
28062
78
                           0);
28063
28064
78
    p->extensible = FALSE;
28065
78
    return obj;
28066
0
 fail:
28067
0
    js_free(ctx, s->exported_names);
28068
0
    JS_FreeValue(ctx, obj);
28069
0
    return JS_EXCEPTION;
28070
78
}
28071
28072
JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m)
28073
78
{
28074
78
    if (JS_IsUndefined(m->module_ns)) {
28075
78
        JSValue val;
28076
78
        val = js_build_module_ns(ctx, m);
28077
78
        if (JS_IsException(val))
28078
0
            return JS_EXCEPTION;
28079
78
        m->module_ns = val;
28080
78
    }
28081
78
    return JS_DupValue(ctx, m->module_ns);
28082
78
}
28083
28084
/* Load all the required modules for module 'm' */
28085
static int js_resolve_module(JSContext *ctx, JSModuleDef *m)
28086
117
{
28087
117
    int i;
28088
117
    JSModuleDef *m1;
28089
28090
117
    if (m->resolved)
28091
0
        return 0;
28092
#ifdef DUMP_MODULE_RESOLVE
28093
    {
28094
        char buf1[ATOM_GET_STR_BUF_SIZE];
28095
        printf("resolving module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
28096
    }
28097
#endif
28098
117
    m->resolved = TRUE;
28099
    /* resolve each requested module */
28100
195
    for(i = 0; i < m->req_module_entries_count; i++) {
28101
78
        JSReqModuleEntry *rme = &m->req_module_entries[i];
28102
78
        m1 = js_host_resolve_imported_module_atom(ctx, m->module_name,
28103
78
                                                  rme->module_name);
28104
78
        if (!m1)
28105
0
            return -1;
28106
78
        rme->module = m1;
28107
        /* already done in js_host_resolve_imported_module() except if
28108
           the module was loaded with JS_EvalBinary() */
28109
78
        if (js_resolve_module(ctx, m1) < 0)
28110
0
            return -1;
28111
78
    }
28112
117
    return 0;
28113
117
}
28114
28115
static JSVarRef *js_create_module_var(JSContext *ctx, BOOL is_lexical)
28116
3.90k
{
28117
3.90k
    JSVarRef *var_ref;
28118
3.90k
    var_ref = js_malloc(ctx, sizeof(JSVarRef));
28119
3.90k
    if (!var_ref)
28120
0
        return NULL;
28121
3.90k
    var_ref->header.ref_count = 1;
28122
3.90k
    if (is_lexical)
28123
78
        var_ref->value = JS_UNINITIALIZED;
28124
3.82k
    else
28125
3.82k
        var_ref->value = JS_UNDEFINED;
28126
3.90k
    var_ref->pvalue = &var_ref->value;
28127
3.90k
    var_ref->is_detached = TRUE;
28128
3.90k
    add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
28129
3.90k
    return var_ref;
28130
3.90k
}
28131
28132
/* Create the <eval> function associated with the module */
28133
static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
28134
39
{
28135
39
    JSFunctionBytecode *b;
28136
39
    int i;
28137
39
    JSVarRef **var_refs;
28138
39
    JSValue func_obj, bfunc;
28139
39
    JSObject *p;
28140
28141
39
    bfunc = m->func_obj;
28142
39
    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
28143
39
                                      JS_CLASS_BYTECODE_FUNCTION);
28144
28145
39
    if (JS_IsException(func_obj))
28146
0
        return -1;
28147
39
    b = JS_VALUE_GET_PTR(bfunc);
28148
28149
39
    p = JS_VALUE_GET_OBJ(func_obj);
28150
39
    p->u.func.function_bytecode = b;
28151
39
    b->header.ref_count++;
28152
39
    p->u.func.home_object = NULL;
28153
39
    p->u.func.var_refs = NULL;
28154
39
    if (b->closure_var_count) {
28155
39
        var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
28156
39
        if (!var_refs)
28157
0
            goto fail;
28158
39
        p->u.func.var_refs = var_refs;
28159
28160
        /* create the global variables. The other variables are
28161
           imported from other modules */
28162
117
        for(i = 0; i < b->closure_var_count; i++) {
28163
78
            JSClosureVar *cv = &b->closure_var[i];
28164
78
            JSVarRef *var_ref;
28165
78
            if (cv->is_local) {
28166
78
                var_ref = js_create_module_var(ctx, cv->is_lexical);
28167
78
                if (!var_ref)
28168
0
                    goto fail;
28169
#ifdef DUMP_MODULE_RESOLVE
28170
                printf("local %d: %p\n", i, var_ref);
28171
#endif
28172
78
                var_refs[i] = var_ref;
28173
78
            }
28174
78
        }
28175
39
    }
28176
39
    m->func_obj = func_obj;
28177
39
    JS_FreeValue(ctx, bfunc);
28178
39
    return 0;
28179
0
 fail:
28180
0
    JS_FreeValue(ctx, func_obj);
28181
0
    return -1;
28182
39
}
28183
28184
/* must be done before js_link_module() because of cyclic references */
28185
static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
28186
117
{
28187
117
    BOOL is_c_module;
28188
117
    int i;
28189
117
    JSVarRef *var_ref;
28190
28191
117
    if (m->func_created)
28192
0
        return 0;
28193
28194
117
    is_c_module = (m->init_func != NULL);
28195
28196
117
    if (is_c_module) {
28197
        /* initialize the exported variables */
28198
3.90k
        for(i = 0; i < m->export_entries_count; i++) {
28199
3.82k
            JSExportEntry *me = &m->export_entries[i];
28200
3.82k
            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
28201
3.82k
                var_ref = js_create_module_var(ctx, FALSE);
28202
3.82k
                if (!var_ref)
28203
0
                    return -1;
28204
3.82k
                me->u.local.var_ref = var_ref;
28205
3.82k
            }
28206
3.82k
        }
28207
78
    } else {
28208
39
        if (js_create_module_bytecode_function(ctx, m))
28209
0
            return -1;
28210
39
    }
28211
117
    m->func_created = TRUE;
28212
28213
    /* do it on the dependencies */
28214
28215
195
    for(i = 0; i < m->req_module_entries_count; i++) {
28216
78
        JSReqModuleEntry *rme = &m->req_module_entries[i];
28217
78
        if (js_create_module_function(ctx, rme->module) < 0)
28218
0
            return -1;
28219
78
    }
28220
28221
117
    return 0;
28222
117
}
28223
28224
28225
/* Prepare a module to be executed by resolving all the imported
28226
   variables. */
28227
static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m,
28228
                                   JSModuleDef **pstack_top, int index)
28229
117
{
28230
117
    int i;
28231
117
    JSImportEntry *mi;
28232
117
    JSModuleDef *m1;
28233
117
    JSVarRef **var_refs, *var_ref;
28234
117
    JSObject *p;
28235
117
    BOOL is_c_module;
28236
117
    JSValue ret_val;
28237
28238
117
    if (js_check_stack_overflow(ctx->rt, 0)) {
28239
0
        JS_ThrowStackOverflow(ctx);
28240
0
        return -1;
28241
0
    }
28242
28243
#ifdef DUMP_MODULE_RESOLVE
28244
    {
28245
        char buf1[ATOM_GET_STR_BUF_SIZE];
28246
        printf("js_inner_module_linking '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
28247
    }
28248
#endif
28249
28250
117
    if (m->status == JS_MODULE_STATUS_LINKING ||
28251
117
        m->status == JS_MODULE_STATUS_LINKED ||
28252
117
        m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
28253
117
        m->status == JS_MODULE_STATUS_EVALUATED)
28254
0
        return index;
28255
28256
117
    assert(m->status == JS_MODULE_STATUS_UNLINKED);
28257
117
    m->status = JS_MODULE_STATUS_LINKING;
28258
117
    m->dfs_index = index;
28259
117
    m->dfs_ancestor_index = index;
28260
117
    index++;
28261
    /* push 'm' on stack */
28262
117
    m->stack_prev = *pstack_top;
28263
117
    *pstack_top = m;
28264
28265
195
    for(i = 0; i < m->req_module_entries_count; i++) {
28266
78
        JSReqModuleEntry *rme = &m->req_module_entries[i];
28267
78
        m1 = rme->module;
28268
78
        index = js_inner_module_linking(ctx, m1, pstack_top, index);
28269
78
        if (index < 0)
28270
0
            goto fail;
28271
78
        assert(m1->status == JS_MODULE_STATUS_LINKING ||
28272
78
               m1->status == JS_MODULE_STATUS_LINKED ||
28273
78
               m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
28274
78
               m1->status == JS_MODULE_STATUS_EVALUATED);
28275
78
        if (m1->status == JS_MODULE_STATUS_LINKING) {
28276
0
            m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,
28277
0
                                            m1->dfs_ancestor_index);
28278
0
        }
28279
78
    }
28280
28281
#ifdef DUMP_MODULE_RESOLVE
28282
    {
28283
        char buf1[ATOM_GET_STR_BUF_SIZE];
28284
        printf("instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
28285
    }
28286
#endif
28287
    /* check the indirect exports */
28288
3.93k
    for(i = 0; i < m->export_entries_count; i++) {
28289
3.82k
        JSExportEntry *me = &m->export_entries[i];
28290
3.82k
        if (me->export_type == JS_EXPORT_TYPE_INDIRECT &&
28291
3.82k
            me->local_name != JS_ATOM__star_) {
28292
0
            JSResolveResultEnum ret;
28293
0
            JSExportEntry *res_me;
28294
0
            JSModuleDef *res_m, *m1;
28295
0
            m1 = m->req_module_entries[me->u.req_module_idx].module;
28296
0
            ret = js_resolve_export(ctx, &res_m, &res_me, m1, me->local_name);
28297
0
            if (ret != JS_RESOLVE_RES_FOUND) {
28298
0
                js_resolve_export_throw_error(ctx, ret, m, me->export_name);
28299
0
                goto fail;
28300
0
            }
28301
0
        }
28302
3.82k
    }
28303
28304
#ifdef DUMP_MODULE_RESOLVE
28305
    {
28306
        printf("exported bindings:\n");
28307
        for(i = 0; i < m->export_entries_count; i++) {
28308
            JSExportEntry *me = &m->export_entries[i];
28309
            printf(" name="); print_atom(ctx, me->export_name);
28310
            printf(" local="); print_atom(ctx, me->local_name);
28311
            printf(" type=%d idx=%d\n", me->export_type, me->u.local.var_idx);
28312
        }
28313
    }
28314
#endif
28315
28316
117
    is_c_module = (m->init_func != NULL);
28317
28318
117
    if (!is_c_module) {
28319
39
        p = JS_VALUE_GET_OBJ(m->func_obj);
28320
39
        var_refs = p->u.func.var_refs;
28321
28322
117
        for(i = 0; i < m->import_entries_count; i++) {
28323
78
            mi = &m->import_entries[i];
28324
#ifdef DUMP_MODULE_RESOLVE
28325
            printf("import var_idx=%d name=", mi->var_idx);
28326
            print_atom(ctx, mi->import_name);
28327
            printf(": ");
28328
#endif
28329
78
            m1 = m->req_module_entries[mi->req_module_idx].module;
28330
78
            if (mi->import_name == JS_ATOM__star_) {
28331
78
                JSValue val;
28332
                /* name space import */
28333
78
                val = JS_GetModuleNamespace(ctx, m1);
28334
78
                if (JS_IsException(val))
28335
0
                    goto fail;
28336
78
                set_value(ctx, &var_refs[mi->var_idx]->value, val);
28337
#ifdef DUMP_MODULE_RESOLVE
28338
                printf("namespace\n");
28339
#endif
28340
78
            } else {
28341
0
                JSResolveResultEnum ret;
28342
0
                JSExportEntry *res_me;
28343
0
                JSModuleDef *res_m;
28344
0
                JSObject *p1;
28345
28346
0
                ret = js_resolve_export(ctx, &res_m,
28347
0
                                        &res_me, m1, mi->import_name);
28348
0
                if (ret != JS_RESOLVE_RES_FOUND) {
28349
0
                    js_resolve_export_throw_error(ctx, ret, m1, mi->import_name);
28350
0
                    goto fail;
28351
0
                }
28352
0
                if (res_me->local_name == JS_ATOM__star_) {
28353
0
                    JSValue val;
28354
0
                    JSModuleDef *m2;
28355
                    /* name space import from */
28356
0
                    m2 = res_m->req_module_entries[res_me->u.req_module_idx].module;
28357
0
                    val = JS_GetModuleNamespace(ctx, m2);
28358
0
                    if (JS_IsException(val))
28359
0
                        goto fail;
28360
0
                    var_ref = js_create_module_var(ctx, TRUE);
28361
0
                    if (!var_ref) {
28362
0
                        JS_FreeValue(ctx, val);
28363
0
                        goto fail;
28364
0
                    }
28365
0
                    set_value(ctx, &var_ref->value, val);
28366
0
                    var_refs[mi->var_idx] = var_ref;
28367
#ifdef DUMP_MODULE_RESOLVE
28368
                    printf("namespace from\n");
28369
#endif
28370
0
                } else {
28371
0
                    var_ref = res_me->u.local.var_ref;
28372
0
                    if (!var_ref) {
28373
0
                        p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
28374
0
                        var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
28375
0
                    }
28376
0
                    var_ref->header.ref_count++;
28377
0
                    var_refs[mi->var_idx] = var_ref;
28378
#ifdef DUMP_MODULE_RESOLVE
28379
                    printf("local export (var_ref=%p)\n", var_ref);
28380
#endif
28381
0
                }
28382
0
            }
28383
78
        }
28384
28385
        /* keep the exported variables in the module export entries (they
28386
           are used when the eval function is deleted and cannot be
28387
           initialized before in case imports are exported) */
28388
39
        for(i = 0; i < m->export_entries_count; i++) {
28389
0
            JSExportEntry *me = &m->export_entries[i];
28390
0
            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
28391
0
                var_ref = var_refs[me->u.local.var_idx];
28392
0
                var_ref->header.ref_count++;
28393
0
                me->u.local.var_ref = var_ref;
28394
0
            }
28395
0
        }
28396
28397
        /* initialize the global variables */
28398
39
        ret_val = JS_Call(ctx, m->func_obj, JS_TRUE, 0, NULL);
28399
39
        if (JS_IsException(ret_val))
28400
0
            goto fail;
28401
39
        JS_FreeValue(ctx, ret_val);
28402
39
    }
28403
28404
117
    assert(m->dfs_ancestor_index <= m->dfs_index);
28405
117
    if (m->dfs_index == m->dfs_ancestor_index) {
28406
117
        for(;;) {
28407
            /* pop m1 from stack */
28408
117
            m1 = *pstack_top;
28409
117
            *pstack_top = m1->stack_prev;
28410
117
            m1->status = JS_MODULE_STATUS_LINKED;
28411
117
            if (m1 == m)
28412
117
                break;
28413
117
        }
28414
117
    }
28415
28416
#ifdef DUMP_MODULE_RESOLVE
28417
    printf("js_inner_module_linking done\n");
28418
#endif
28419
117
    return index;
28420
0
 fail:
28421
0
    return -1;
28422
117
}
28423
28424
/* Prepare a module to be executed by resolving all the imported
28425
   variables. */
28426
static int js_link_module(JSContext *ctx, JSModuleDef *m)
28427
39
{
28428
39
    JSModuleDef *stack_top, *m1;
28429
28430
#ifdef DUMP_MODULE_RESOLVE
28431
    {
28432
        char buf1[ATOM_GET_STR_BUF_SIZE];
28433
        printf("js_link_module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
28434
    }
28435
#endif
28436
39
    assert(m->status == JS_MODULE_STATUS_UNLINKED ||
28437
39
           m->status == JS_MODULE_STATUS_LINKED ||
28438
39
           m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
28439
39
           m->status == JS_MODULE_STATUS_EVALUATED);
28440
39
    stack_top = NULL;
28441
39
    if (js_inner_module_linking(ctx, m, &stack_top, 0) < 0) {
28442
0
        while (stack_top != NULL) {
28443
0
            m1 = stack_top;
28444
0
            assert(m1->status == JS_MODULE_STATUS_LINKING);
28445
0
            m1->status = JS_MODULE_STATUS_UNLINKED;
28446
0
            stack_top = m1->stack_prev;
28447
0
        }
28448
0
        return -1;
28449
0
    }
28450
39
    assert(stack_top == NULL);
28451
39
    assert(m->status == JS_MODULE_STATUS_LINKED ||
28452
39
           m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
28453
39
           m->status == JS_MODULE_STATUS_EVALUATED);
28454
39
    return 0;
28455
39
}
28456
28457
/* return JS_ATOM_NULL if the name cannot be found. Only works with
28458
   not striped bytecode functions. */
28459
JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
28460
0
{
28461
0
    JSStackFrame *sf;
28462
0
    JSFunctionBytecode *b;
28463
0
    JSObject *p;
28464
    /* XXX: currently we just use the filename of the englobing
28465
       function from the debug info. May need to add a ScriptOrModule
28466
       info in JSFunctionBytecode. */
28467
0
    sf = ctx->rt->current_stack_frame;
28468
0
    if (!sf)
28469
0
        return JS_ATOM_NULL;
28470
0
    while (n_stack_levels-- > 0) {
28471
0
        sf = sf->prev_frame;
28472
0
        if (!sf)
28473
0
            return JS_ATOM_NULL;
28474
0
    }
28475
0
    for(;;) {
28476
0
        if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT)
28477
0
            return JS_ATOM_NULL;
28478
0
        p = JS_VALUE_GET_OBJ(sf->cur_func);
28479
0
        if (!js_class_has_bytecode(p->class_id))
28480
0
            return JS_ATOM_NULL;
28481
0
        b = p->u.func.function_bytecode;
28482
0
        if (!b->is_direct_or_indirect_eval) {
28483
0
            if (!b->has_debug)
28484
0
                return JS_ATOM_NULL;
28485
0
            return JS_DupAtom(ctx, b->debug.filename);
28486
0
        } else {
28487
0
            sf = sf->prev_frame;
28488
0
            if (!sf)
28489
0
                return JS_ATOM_NULL;
28490
0
        }
28491
0
    }
28492
0
}
28493
28494
JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m)
28495
39
{
28496
39
    return JS_DupAtom(ctx, m->module_name);
28497
39
}
28498
28499
JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m)
28500
0
{
28501
0
    JSValue obj;
28502
    /* allocate meta_obj only if requested to save memory */
28503
0
    obj = m->meta_obj;
28504
0
    if (JS_IsUndefined(obj)) {
28505
0
        obj = JS_NewObjectProto(ctx, JS_NULL);
28506
0
        if (JS_IsException(obj))
28507
0
            return JS_EXCEPTION;
28508
0
        m->meta_obj = obj;
28509
0
    }
28510
0
    return JS_DupValue(ctx, obj);
28511
0
}
28512
28513
static JSValue js_import_meta(JSContext *ctx)
28514
0
{
28515
0
    JSAtom filename;
28516
0
    JSModuleDef *m;
28517
28518
0
    filename = JS_GetScriptOrModuleName(ctx, 0);
28519
0
    if (filename == JS_ATOM_NULL)
28520
0
        goto fail;
28521
28522
    /* XXX: inefficient, need to add a module or script pointer in
28523
       JSFunctionBytecode */
28524
0
    m = js_find_loaded_module(ctx, filename);
28525
0
    JS_FreeAtom(ctx, filename);
28526
0
    if (!m) {
28527
0
    fail:
28528
0
        JS_ThrowTypeError(ctx, "import.meta not supported in this context");
28529
0
        return JS_EXCEPTION;
28530
0
    }
28531
0
    return JS_GetImportMeta(ctx, m);
28532
0
}
28533
28534
static JSValue JS_NewModuleValue(JSContext *ctx, JSModuleDef *m)
28535
39
{
28536
39
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
28537
39
}
28538
28539
static JSValue js_load_module_rejected(JSContext *ctx, JSValueConst this_val,
28540
                                       int argc, JSValueConst *argv, int magic, JSValue *func_data)
28541
0
{
28542
0
    JSValueConst *resolving_funcs = (JSValueConst *)func_data;
28543
0
    JSValueConst error;
28544
0
    JSValue ret;
28545
28546
    /* XXX: check if the test is necessary */
28547
0
    if (argc >= 1)
28548
0
        error = argv[0];
28549
0
    else
28550
0
        error = JS_UNDEFINED;
28551
0
    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
28552
0
                  1, &error);
28553
0
    JS_FreeValue(ctx, ret);
28554
0
    return JS_UNDEFINED;
28555
0
}
28556
28557
static JSValue js_load_module_fulfilled(JSContext *ctx, JSValueConst this_val,
28558
                                        int argc, JSValueConst *argv, int magic, JSValue *func_data)
28559
0
{
28560
0
    JSValueConst *resolving_funcs = (JSValueConst *)func_data;
28561
0
    JSModuleDef *m = JS_VALUE_GET_PTR(func_data[2]);
28562
0
    JSValue ret, ns;
28563
28564
    /* return the module namespace */
28565
0
    ns = JS_GetModuleNamespace(ctx, m);
28566
0
    if (JS_IsException(ns)) {
28567
0
        JSValue err = JS_GetException(ctx);
28568
0
        js_load_module_rejected(ctx, JS_UNDEFINED, 1, (JSValueConst *)&err, 0, func_data);
28569
0
        return JS_UNDEFINED;
28570
0
    }
28571
0
    ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
28572
0
                   1, (JSValueConst *)&ns);
28573
0
    JS_FreeValue(ctx, ret);
28574
0
    JS_FreeValue(ctx, ns);
28575
0
    return JS_UNDEFINED;
28576
0
}
28577
28578
static void JS_LoadModuleInternal(JSContext *ctx, const char *basename,
28579
                                  const char *filename,
28580
                                  JSValueConst *resolving_funcs)
28581
0
{
28582
0
    JSValue evaluate_promise;
28583
0
    JSModuleDef *m;
28584
0
    JSValue ret, err, func_obj, evaluate_resolving_funcs[2];
28585
0
    JSValueConst func_data[3];
28586
28587
0
    m = js_host_resolve_imported_module(ctx, basename, filename);
28588
0
    if (!m)
28589
0
        goto fail;
28590
28591
0
    if (js_resolve_module(ctx, m) < 0) {
28592
0
        js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
28593
0
        goto fail;
28594
0
    }
28595
28596
    /* Evaluate the module code */
28597
0
    func_obj = JS_NewModuleValue(ctx, m);
28598
0
    evaluate_promise = JS_EvalFunction(ctx, func_obj);
28599
0
    if (JS_IsException(evaluate_promise)) {
28600
0
    fail:
28601
0
        err = JS_GetException(ctx);
28602
0
        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
28603
0
                      1, (JSValueConst *)&err);
28604
0
        JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
28605
0
        JS_FreeValue(ctx, err);
28606
0
        return;
28607
0
    }
28608
28609
0
    func_obj = JS_NewModuleValue(ctx, m);
28610
0
    func_data[0] = resolving_funcs[0];
28611
0
    func_data[1] = resolving_funcs[1];
28612
0
    func_data[2] = func_obj;
28613
0
    evaluate_resolving_funcs[0] = JS_NewCFunctionData(ctx, js_load_module_fulfilled, 0, 0, 3, func_data);
28614
0
    evaluate_resolving_funcs[1] = JS_NewCFunctionData(ctx, js_load_module_rejected, 0, 0, 3, func_data);
28615
0
    JS_FreeValue(ctx, func_obj);
28616
0
    ret = js_promise_then(ctx, evaluate_promise, 2, (JSValueConst *)evaluate_resolving_funcs);
28617
0
    JS_FreeValue(ctx, ret);
28618
0
    JS_FreeValue(ctx, evaluate_resolving_funcs[0]);
28619
0
    JS_FreeValue(ctx, evaluate_resolving_funcs[1]);
28620
0
    JS_FreeValue(ctx, evaluate_promise);
28621
0
}
28622
28623
/* Return a promise or an exception in case of memory error. Used by
28624
   os.Worker() */
28625
JSValue JS_LoadModule(JSContext *ctx, const char *basename,
28626
                      const char *filename)
28627
0
{
28628
0
    JSValue promise, resolving_funcs[2];
28629
28630
0
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
28631
0
    if (JS_IsException(promise))
28632
0
        return JS_EXCEPTION;
28633
0
    JS_LoadModuleInternal(ctx, basename, filename,
28634
0
                          (JSValueConst *)resolving_funcs);
28635
0
    JS_FreeValue(ctx, resolving_funcs[0]);
28636
0
    JS_FreeValue(ctx, resolving_funcs[1]);
28637
0
    return promise;
28638
0
}
28639
28640
static JSValue js_dynamic_import_job(JSContext *ctx,
28641
                                     int argc, JSValueConst *argv)
28642
0
{
28643
0
    JSValueConst *resolving_funcs = argv;
28644
0
    JSValueConst basename_val = argv[2];
28645
0
    JSValueConst specifier = argv[3];
28646
0
    const char *basename = NULL, *filename;
28647
0
    JSValue ret, err;
28648
28649
0
    if (!JS_IsString(basename_val)) {
28650
0
        JS_ThrowTypeError(ctx, "no function filename for import()");
28651
0
        goto exception;
28652
0
    }
28653
0
    basename = JS_ToCString(ctx, basename_val);
28654
0
    if (!basename)
28655
0
        goto exception;
28656
28657
0
    filename = JS_ToCString(ctx, specifier);
28658
0
    if (!filename)
28659
0
        goto exception;
28660
28661
0
    JS_LoadModuleInternal(ctx, basename, filename,
28662
0
                          resolving_funcs);
28663
0
    JS_FreeCString(ctx, filename);
28664
0
    JS_FreeCString(ctx, basename);
28665
0
    return JS_UNDEFINED;
28666
0
 exception:
28667
0
    err = JS_GetException(ctx);
28668
0
    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
28669
0
                   1, (JSValueConst *)&err);
28670
0
    JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
28671
0
    JS_FreeValue(ctx, err);
28672
0
    JS_FreeCString(ctx, basename);
28673
0
    return JS_UNDEFINED;
28674
0
}
28675
28676
static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
28677
0
{
28678
0
    JSAtom basename;
28679
0
    JSValue promise, resolving_funcs[2], basename_val;
28680
0
    JSValueConst args[4];
28681
28682
0
    basename = JS_GetScriptOrModuleName(ctx, 0);
28683
0
    if (basename == JS_ATOM_NULL)
28684
0
        basename_val = JS_NULL;
28685
0
    else
28686
0
        basename_val = JS_AtomToValue(ctx, basename);
28687
0
    JS_FreeAtom(ctx, basename);
28688
0
    if (JS_IsException(basename_val))
28689
0
        return basename_val;
28690
28691
0
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
28692
0
    if (JS_IsException(promise)) {
28693
0
        JS_FreeValue(ctx, basename_val);
28694
0
        return promise;
28695
0
    }
28696
28697
0
    args[0] = resolving_funcs[0];
28698
0
    args[1] = resolving_funcs[1];
28699
0
    args[2] = basename_val;
28700
0
    args[3] = specifier;
28701
28702
    /* cannot run JS_LoadModuleInternal synchronously because it would
28703
       cause an unexpected recursion in js_evaluate_module() */
28704
0
    JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args);
28705
28706
0
    JS_FreeValue(ctx, basename_val);
28707
0
    JS_FreeValue(ctx, resolving_funcs[0]);
28708
0
    JS_FreeValue(ctx, resolving_funcs[1]);
28709
0
    return promise;
28710
0
}
28711
28712
static void js_set_module_evaluated(JSContext *ctx, JSModuleDef *m)
28713
0
{
28714
0
    m->status = JS_MODULE_STATUS_EVALUATED;
28715
0
    if (!JS_IsUndefined(m->promise)) {
28716
0
        JSValue value, ret_val;
28717
0
        assert(m->cycle_root == m);
28718
0
        value = JS_UNDEFINED;
28719
0
        ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED,
28720
0
                          1, (JSValueConst *)&value);
28721
0
        JS_FreeValue(ctx, ret_val);
28722
0
    }
28723
0
}
28724
28725
typedef struct {
28726
    JSModuleDef **tab;
28727
    int count;
28728
    int size;
28729
} ExecModuleList;
28730
28731
/* XXX: slow. Could use a linked list instead of ExecModuleList */
28732
static BOOL find_in_exec_module_list(ExecModuleList *exec_list, JSModuleDef *m)
28733
0
{
28734
0
    int i;
28735
0
    for(i = 0; i < exec_list->count; i++) {
28736
0
        if (exec_list->tab[i] == m)
28737
0
            return TRUE;
28738
0
    }
28739
0
    return FALSE;
28740
0
}
28741
28742
static int gather_available_ancestors(JSContext *ctx, JSModuleDef *module,
28743
                                      ExecModuleList *exec_list)
28744
0
{
28745
0
    int i;
28746
28747
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
28748
0
        JS_ThrowStackOverflow(ctx);
28749
0
        return -1;
28750
0
    }
28751
0
    for(i = 0; i < module->async_parent_modules_count; i++) {
28752
0
        JSModuleDef *m = module->async_parent_modules[i];
28753
0
        if (!find_in_exec_module_list(exec_list, m) &&
28754
0
            !m->cycle_root->eval_has_exception) {
28755
0
            assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
28756
0
            assert(!m->eval_has_exception);
28757
0
            assert(m->async_evaluation);
28758
0
            assert(m->pending_async_dependencies > 0);
28759
0
            m->pending_async_dependencies--;
28760
0
            if (m->pending_async_dependencies == 0) {
28761
0
                if (js_resize_array(ctx, (void **)&exec_list->tab, sizeof(exec_list->tab[0]), &exec_list->size, exec_list->count + 1)) {
28762
0
                    return -1;
28763
0
                }
28764
0
                exec_list->tab[exec_list->count++] = m;
28765
0
                if (!m->has_tla) {
28766
0
                    if (gather_available_ancestors(ctx, m, exec_list))
28767
0
                        return -1;
28768
0
                }
28769
0
            }
28770
0
        }
28771
0
    }
28772
0
    return 0;
28773
0
}
28774
28775
static int exec_module_list_cmp(const void *p1, const void *p2, void *opaque)
28776
0
{
28777
0
    JSModuleDef *m1 = *(JSModuleDef **)p1;
28778
0
    JSModuleDef *m2 = *(JSModuleDef **)p2;
28779
0
    return (m1->async_evaluation_timestamp > m2->async_evaluation_timestamp) -
28780
0
        (m1->async_evaluation_timestamp < m2->async_evaluation_timestamp);
28781
0
}
28782
28783
static int js_execute_async_module(JSContext *ctx, JSModuleDef *m);
28784
static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,
28785
                                  JSValue *pvalue);
28786
28787
static JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst this_val,
28788
                                                  int argc, JSValueConst *argv, int magic, JSValue *func_data)
28789
0
{
28790
0
    JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);
28791
0
    JSValueConst error = argv[0];
28792
0
    int i;
28793
28794
0
    if (js_check_stack_overflow(ctx->rt, 0))
28795
0
        return JS_ThrowStackOverflow(ctx);
28796
28797
0
    if (module->status == JS_MODULE_STATUS_EVALUATED) {
28798
0
        assert(module->eval_has_exception);
28799
0
        return JS_UNDEFINED;
28800
0
    }
28801
28802
0
    assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
28803
0
    assert(!module->eval_has_exception);
28804
0
    assert(module->async_evaluation);
28805
28806
0
    module->eval_has_exception = TRUE;
28807
0
    module->eval_exception = JS_DupValue(ctx, error);
28808
0
    module->status = JS_MODULE_STATUS_EVALUATED;
28809
28810
0
    for(i = 0; i < module->async_parent_modules_count; i++) {
28811
0
        JSModuleDef *m = module->async_parent_modules[i];
28812
0
        JSValue m_obj = JS_NewModuleValue(ctx, m);
28813
0
        js_async_module_execution_rejected(ctx, JS_UNDEFINED, 1, &error, 0,
28814
0
                                           &m_obj);
28815
0
        JS_FreeValue(ctx, m_obj);
28816
0
    }
28817
28818
0
    if (!JS_IsUndefined(module->promise)) {
28819
0
        JSValue ret_val;
28820
0
        assert(module->cycle_root == module);
28821
0
        ret_val = JS_Call(ctx, module->resolving_funcs[1], JS_UNDEFINED,
28822
0
                          1, &error);
28823
0
        JS_FreeValue(ctx, ret_val);
28824
0
    }
28825
0
    return JS_UNDEFINED;
28826
0
}
28827
28828
static JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst this_val,
28829
                                                   int argc, JSValueConst *argv, int magic, JSValue *func_data)
28830
0
{
28831
0
    JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);
28832
0
    ExecModuleList exec_list_s, *exec_list = &exec_list_s;
28833
0
    int i;
28834
28835
0
    if (module->status == JS_MODULE_STATUS_EVALUATED) {
28836
0
        assert(module->eval_has_exception);
28837
0
        return JS_UNDEFINED;
28838
0
    }
28839
0
    assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
28840
0
    assert(!module->eval_has_exception);
28841
0
    assert(module->async_evaluation);
28842
0
    module->async_evaluation = FALSE;
28843
0
    js_set_module_evaluated(ctx, module);
28844
28845
0
    exec_list->tab = NULL;
28846
0
    exec_list->count = 0;
28847
0
    exec_list->size = 0;
28848
28849
0
    if (gather_available_ancestors(ctx, module, exec_list) < 0) {
28850
0
        js_free(ctx, exec_list->tab);
28851
0
        return JS_EXCEPTION;
28852
0
    }
28853
28854
    /* sort by increasing async_evaluation timestamp */
28855
0
    rqsort(exec_list->tab, exec_list->count, sizeof(exec_list->tab[0]),
28856
0
           exec_module_list_cmp, NULL);
28857
28858
0
    for(i = 0; i < exec_list->count; i++) {
28859
0
        JSModuleDef *m = exec_list->tab[i];
28860
0
        if (m->status == JS_MODULE_STATUS_EVALUATED) {
28861
0
            assert(m->eval_has_exception);
28862
0
        } else if (m->has_tla) {
28863
0
            js_execute_async_module(ctx, m);
28864
0
        } else {
28865
0
            JSValue error;
28866
0
            if (js_execute_sync_module(ctx, m, &error) < 0) {
28867
0
                JSValue m_obj = JS_NewModuleValue(ctx, m);
28868
0
                js_async_module_execution_rejected(ctx, JS_UNDEFINED,
28869
0
                                                   1, (JSValueConst *)&error, 0,
28870
0
                                                   &m_obj);
28871
0
                JS_FreeValue(ctx, m_obj);
28872
0
                JS_FreeValue(ctx, error);
28873
0
            } else {
28874
0
                js_set_module_evaluated(ctx, m);
28875
0
            }
28876
0
        }
28877
0
    }
28878
0
    js_free(ctx, exec_list->tab);
28879
0
    return JS_UNDEFINED;
28880
0
}
28881
28882
static int js_execute_async_module(JSContext *ctx, JSModuleDef *m)
28883
0
{
28884
0
    JSValue promise, m_obj;
28885
0
    JSValue resolve_funcs[2], ret_val;
28886
0
    promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);
28887
0
    if (JS_IsException(promise))
28888
0
        return -1;
28889
0
    m_obj = JS_NewModuleValue(ctx, m);
28890
0
    resolve_funcs[0] = JS_NewCFunctionData(ctx, js_async_module_execution_fulfilled, 0, 0, 1, (JSValueConst *)&m_obj);
28891
0
    resolve_funcs[1] = JS_NewCFunctionData(ctx, js_async_module_execution_rejected, 0, 0, 1, (JSValueConst *)&m_obj);
28892
0
    ret_val = js_promise_then(ctx, promise, 2, (JSValueConst *)resolve_funcs);
28893
0
    JS_FreeValue(ctx, ret_val);
28894
0
    JS_FreeValue(ctx, m_obj);
28895
0
    JS_FreeValue(ctx, resolve_funcs[0]);
28896
0
    JS_FreeValue(ctx, resolve_funcs[1]);
28897
0
    JS_FreeValue(ctx, promise);
28898
0
    return 0;
28899
0
}
28900
28901
/* return < 0 in case of exception. *pvalue contains the exception. */
28902
static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,
28903
                                  JSValue *pvalue)
28904
117
{
28905
117
    if (m->init_func) {
28906
        /* C module init : no asynchronous execution */
28907
78
        if (m->init_func(ctx, m) < 0)
28908
0
            goto fail;
28909
78
    } else {
28910
39
        JSValue promise;
28911
39
        JSPromiseStateEnum state;
28912
28913
39
        promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);
28914
39
        if (JS_IsException(promise))
28915
0
            goto fail;
28916
39
        state = JS_PromiseState(ctx, promise);
28917
39
        if (state == JS_PROMISE_FULFILLED) {
28918
39
            JS_FreeValue(ctx, promise);
28919
39
        } else if (state == JS_PROMISE_REJECTED) {
28920
0
            *pvalue = JS_PromiseResult(ctx, promise);
28921
0
            JS_FreeValue(ctx, promise);
28922
0
            return -1;
28923
0
        } else {
28924
0
            JS_FreeValue(ctx, promise);
28925
0
            JS_ThrowTypeError(ctx, "promise is pending");
28926
0
        fail:
28927
0
            *pvalue = JS_GetException(ctx);
28928
0
            return -1;
28929
0
        }
28930
39
    }
28931
117
    *pvalue = JS_UNDEFINED;
28932
117
    return 0;
28933
117
}
28934
28935
/* spec: InnerModuleEvaluation. Return (index, JS_UNDEFINED) or (-1,
28936
   exception) */
28937
static int js_inner_module_evaluation(JSContext *ctx, JSModuleDef *m,
28938
                                      int index, JSModuleDef **pstack_top,
28939
                                      JSValue *pvalue)
28940
117
{
28941
117
    JSModuleDef *m1;
28942
117
    int i;
28943
28944
117
    if (js_check_stack_overflow(ctx->rt, 0)) {
28945
0
        JS_ThrowStackOverflow(ctx);
28946
0
        *pvalue = JS_GetException(ctx);
28947
0
        return -1;
28948
0
    }
28949
28950
#ifdef DUMP_MODULE_RESOLVE
28951
    {
28952
        char buf1[ATOM_GET_STR_BUF_SIZE];
28953
        printf("js_inner_module_evaluation '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
28954
    }
28955
#endif
28956
28957
117
    if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
28958
117
        m->status == JS_MODULE_STATUS_EVALUATED) {
28959
0
        if (m->eval_has_exception) {
28960
0
            *pvalue = JS_DupValue(ctx, m->eval_exception);
28961
0
            return -1;
28962
0
        } else {
28963
0
            *pvalue = JS_UNDEFINED;
28964
0
            return index;
28965
0
        }
28966
0
    }
28967
117
    if (m->status == JS_MODULE_STATUS_EVALUATING) {
28968
0
        *pvalue = JS_UNDEFINED;
28969
0
        return index;
28970
0
    }
28971
117
    assert(m->status == JS_MODULE_STATUS_LINKED);
28972
28973
117
    m->status = JS_MODULE_STATUS_EVALUATING;
28974
117
    m->dfs_index = index;
28975
117
    m->dfs_ancestor_index = index;
28976
117
    m->pending_async_dependencies = 0;
28977
117
    index++;
28978
    /* push 'm' on stack */
28979
117
    m->stack_prev = *pstack_top;
28980
117
    *pstack_top = m;
28981
28982
195
    for(i = 0; i < m->req_module_entries_count; i++) {
28983
78
        JSReqModuleEntry *rme = &m->req_module_entries[i];
28984
78
        m1 = rme->module;
28985
78
        index = js_inner_module_evaluation(ctx, m1, index, pstack_top, pvalue);
28986
78
        if (index < 0)
28987
0
            return -1;
28988
78
        assert(m1->status == JS_MODULE_STATUS_EVALUATING ||
28989
78
               m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
28990
78
               m1->status == JS_MODULE_STATUS_EVALUATED);
28991
78
        if (m1->status == JS_MODULE_STATUS_EVALUATING) {
28992
0
            m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,
28993
0
                                            m1->dfs_ancestor_index);
28994
78
        } else {
28995
78
            m1 = m1->cycle_root;
28996
78
            assert(m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
28997
78
                   m1->status == JS_MODULE_STATUS_EVALUATED);
28998
78
            if (m1->eval_has_exception) {
28999
0
                *pvalue = JS_DupValue(ctx, m1->eval_exception);
29000
0
                return -1;
29001
0
            }
29002
78
        }
29003
78
        if (m1->async_evaluation) {
29004
0
            m->pending_async_dependencies++;
29005
0
            if (js_resize_array(ctx, (void **)&m1->async_parent_modules, sizeof(m1->async_parent_modules[0]), &m1->async_parent_modules_size, m1->async_parent_modules_count + 1)) {
29006
0
                *pvalue = JS_GetException(ctx);
29007
0
                return -1;
29008
0
            }
29009
0
            m1->async_parent_modules[m1->async_parent_modules_count++] = m;
29010
0
        }
29011
78
    }
29012
29013
117
    if (m->pending_async_dependencies > 0) {
29014
0
        assert(!m->async_evaluation);
29015
0
        m->async_evaluation = TRUE;
29016
0
        m->async_evaluation_timestamp =
29017
0
            ctx->rt->module_async_evaluation_next_timestamp++;
29018
117
    } else if (m->has_tla) {
29019
0
        assert(!m->async_evaluation);
29020
0
        m->async_evaluation = TRUE;
29021
0
        m->async_evaluation_timestamp =
29022
0
            ctx->rt->module_async_evaluation_next_timestamp++;
29023
0
        js_execute_async_module(ctx, m);
29024
117
    } else {
29025
117
        if (js_execute_sync_module(ctx, m, pvalue) < 0)
29026
0
            return -1;
29027
117
    }
29028
29029
117
    assert(m->dfs_ancestor_index <= m->dfs_index);
29030
117
    if (m->dfs_index == m->dfs_ancestor_index) {
29031
117
        for(;;) {
29032
            /* pop m1 from stack */
29033
117
            m1 = *pstack_top;
29034
117
            *pstack_top = m1->stack_prev;
29035
117
            if (!m1->async_evaluation) {
29036
117
                m1->status = JS_MODULE_STATUS_EVALUATED;
29037
117
            } else {
29038
0
                m1->status = JS_MODULE_STATUS_EVALUATING_ASYNC;
29039
0
            }
29040
            /* spec bug: cycle_root must be assigned before the test */
29041
117
            m1->cycle_root = m;
29042
117
            if (m1 == m)
29043
117
                break;
29044
117
        }
29045
117
    }
29046
117
    *pvalue = JS_UNDEFINED;
29047
117
    return index;
29048
117
}
29049
29050
/* Run the <eval> function of the module and of all its requested
29051
   modules. Return a promise or an exception. */
29052
static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
29053
39
{
29054
39
    JSModuleDef *m1, *stack_top;
29055
39
    JSValue ret_val, result;
29056
29057
39
    assert(m->status == JS_MODULE_STATUS_LINKED ||
29058
39
           m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
29059
39
           m->status == JS_MODULE_STATUS_EVALUATED);
29060
39
    if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
29061
39
        m->status == JS_MODULE_STATUS_EVALUATED) {
29062
0
        m = m->cycle_root;
29063
0
    }
29064
    /* a promise may be created only on the cycle_root of a cycle */
29065
39
    if (!JS_IsUndefined(m->promise))
29066
0
        return JS_DupValue(ctx, m->promise);
29067
39
    m->promise = JS_NewPromiseCapability(ctx, m->resolving_funcs);
29068
39
    if (JS_IsException(m->promise))
29069
0
        return JS_EXCEPTION;
29070
29071
39
    stack_top = NULL;
29072
39
    if (js_inner_module_evaluation(ctx, m, 0, &stack_top, &result) < 0) {
29073
0
        while (stack_top != NULL) {
29074
0
            m1 = stack_top;
29075
0
            assert(m1->status == JS_MODULE_STATUS_EVALUATING);
29076
0
            m1->status = JS_MODULE_STATUS_EVALUATED;
29077
0
            m1->eval_has_exception = TRUE;
29078
0
            m1->eval_exception = JS_DupValue(ctx, result);
29079
0
            m1->cycle_root = m; /* spec bug: should be present */
29080
0
            stack_top = m1->stack_prev;
29081
0
        }
29082
0
        JS_FreeValue(ctx, result);
29083
0
        assert(m->status == JS_MODULE_STATUS_EVALUATED);
29084
0
        assert(m->eval_has_exception);
29085
0
        ret_val = JS_Call(ctx, m->resolving_funcs[1], JS_UNDEFINED,
29086
0
                          1, (JSValueConst *)&m->eval_exception);
29087
0
        JS_FreeValue(ctx, ret_val);
29088
39
    } else {
29089
39
        assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
29090
39
               m->status == JS_MODULE_STATUS_EVALUATED);
29091
39
        assert(!m->eval_has_exception);
29092
39
        if (!m->async_evaluation) {
29093
39
            JSValue value;
29094
39
            assert(m->status == JS_MODULE_STATUS_EVALUATED);
29095
39
            value = JS_UNDEFINED;
29096
39
            ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED,
29097
39
                              1, (JSValueConst *)&value);
29098
39
            JS_FreeValue(ctx, ret_val);
29099
39
        }
29100
39
        assert(stack_top == NULL);
29101
39
    }
29102
39
    return JS_DupValue(ctx, m->promise);
29103
39
}
29104
29105
static __exception JSAtom js_parse_from_clause(JSParseState *s)
29106
78
{
29107
78
    JSAtom module_name;
29108
78
    if (!token_is_pseudo_keyword(s, JS_ATOM_from)) {
29109
0
        js_parse_error(s, "from clause expected");
29110
0
        return JS_ATOM_NULL;
29111
0
    }
29112
78
    if (next_token(s))
29113
0
        return JS_ATOM_NULL;
29114
78
    if (s->token.val != TOK_STRING) {
29115
0
        js_parse_error(s, "string expected");
29116
0
        return JS_ATOM_NULL;
29117
0
    }
29118
78
    module_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
29119
78
    if (module_name == JS_ATOM_NULL)
29120
0
        return JS_ATOM_NULL;
29121
78
    if (next_token(s)) {
29122
0
        JS_FreeAtom(s->ctx, module_name);
29123
0
        return JS_ATOM_NULL;
29124
0
    }
29125
78
    return module_name;
29126
78
}
29127
29128
static __exception int js_parse_export(JSParseState *s)
29129
0
{
29130
0
    JSContext *ctx = s->ctx;
29131
0
    JSModuleDef *m = s->cur_func->module;
29132
0
    JSAtom local_name, export_name;
29133
0
    int first_export, idx, i, tok;
29134
0
    JSAtom module_name;
29135
0
    JSExportEntry *me;
29136
29137
0
    if (next_token(s))
29138
0
        return -1;
29139
29140
0
    tok = s->token.val;
29141
0
    if (tok == TOK_CLASS) {
29142
0
        return js_parse_class(s, FALSE, JS_PARSE_EXPORT_NAMED);
29143
0
    } else if (tok == TOK_FUNCTION ||
29144
0
               (token_is_pseudo_keyword(s, JS_ATOM_async) &&
29145
0
                peek_token(s, TRUE) == TOK_FUNCTION)) {
29146
0
        return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
29147
0
                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
29148
0
                                       s->token.ptr, s->token.line_num,
29149
0
                                       JS_PARSE_EXPORT_NAMED, NULL);
29150
0
    }
29151
29152
0
    if (next_token(s))
29153
0
        return -1;
29154
29155
0
    switch(tok) {
29156
0
    case '{':
29157
0
        first_export = m->export_entries_count;
29158
0
        while (s->token.val != '}') {
29159
0
            if (!token_is_ident(s->token.val)) {
29160
0
                js_parse_error(s, "identifier expected");
29161
0
                return -1;
29162
0
            }
29163
0
            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
29164
0
            export_name = JS_ATOM_NULL;
29165
0
            if (next_token(s))
29166
0
                goto fail;
29167
0
            if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
29168
0
                if (next_token(s))
29169
0
                    goto fail;
29170
0
                if (!token_is_ident(s->token.val)) {
29171
0
                    js_parse_error(s, "identifier expected");
29172
0
                    goto fail;
29173
0
                }
29174
0
                export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
29175
0
                if (next_token(s)) {
29176
0
                fail:
29177
0
                    JS_FreeAtom(ctx, local_name);
29178
0
                fail1:
29179
0
                    JS_FreeAtom(ctx, export_name);
29180
0
                    return -1;
29181
0
                }
29182
0
            } else {
29183
0
                export_name = JS_DupAtom(ctx, local_name);
29184
0
            }
29185
0
            me = add_export_entry(s, m, local_name, export_name,
29186
0
                                  JS_EXPORT_TYPE_LOCAL);
29187
0
            JS_FreeAtom(ctx, local_name);
29188
0
            JS_FreeAtom(ctx, export_name);
29189
0
            if (!me)
29190
0
                return -1;
29191
0
            if (s->token.val != ',')
29192
0
                break;
29193
0
            if (next_token(s))
29194
0
                return -1;
29195
0
        }
29196
0
        if (js_parse_expect(s, '}'))
29197
0
            return -1;
29198
0
        if (token_is_pseudo_keyword(s, JS_ATOM_from)) {
29199
0
            module_name = js_parse_from_clause(s);
29200
0
            if (module_name == JS_ATOM_NULL)
29201
0
                return -1;
29202
0
            idx = add_req_module_entry(ctx, m, module_name);
29203
0
            JS_FreeAtom(ctx, module_name);
29204
0
            if (idx < 0)
29205
0
                return -1;
29206
0
            for(i = first_export; i < m->export_entries_count; i++) {
29207
0
                me = &m->export_entries[i];
29208
0
                me->export_type = JS_EXPORT_TYPE_INDIRECT;
29209
0
                me->u.req_module_idx = idx;
29210
0
            }
29211
0
        }
29212
0
        break;
29213
0
    case '*':
29214
0
        if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
29215
            /* export ns from */
29216
0
            if (next_token(s))
29217
0
                return -1;
29218
0
            if (!token_is_ident(s->token.val)) {
29219
0
                js_parse_error(s, "identifier expected");
29220
0
                return -1;
29221
0
            }
29222
0
            export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
29223
0
            if (next_token(s))
29224
0
                goto fail1;
29225
0
            module_name = js_parse_from_clause(s);
29226
0
            if (module_name == JS_ATOM_NULL)
29227
0
                goto fail1;
29228
0
            idx = add_req_module_entry(ctx, m, module_name);
29229
0
            JS_FreeAtom(ctx, module_name);
29230
0
            if (idx < 0)
29231
0
                goto fail1;
29232
0
            me = add_export_entry(s, m, JS_ATOM__star_, export_name,
29233
0
                                  JS_EXPORT_TYPE_INDIRECT);
29234
0
            JS_FreeAtom(ctx, export_name);
29235
0
            if (!me)
29236
0
                return -1;
29237
0
            me->u.req_module_idx = idx;
29238
0
        } else {
29239
0
            module_name = js_parse_from_clause(s);
29240
0
            if (module_name == JS_ATOM_NULL)
29241
0
                return -1;
29242
0
            idx = add_req_module_entry(ctx, m, module_name);
29243
0
            JS_FreeAtom(ctx, module_name);
29244
0
            if (idx < 0)
29245
0
                return -1;
29246
0
            if (add_star_export_entry(ctx, m, idx) < 0)
29247
0
                return -1;
29248
0
        }
29249
0
        break;
29250
0
    case TOK_DEFAULT:
29251
0
        if (s->token.val == TOK_CLASS) {
29252
0
            return js_parse_class(s, FALSE, JS_PARSE_EXPORT_DEFAULT);
29253
0
        } else if (s->token.val == TOK_FUNCTION ||
29254
0
                   (token_is_pseudo_keyword(s, JS_ATOM_async) &&
29255
0
                    peek_token(s, TRUE) == TOK_FUNCTION)) {
29256
0
            return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
29257
0
                                           JS_FUNC_NORMAL, JS_ATOM_NULL,
29258
0
                                           s->token.ptr, s->token.line_num,
29259
0
                                           JS_PARSE_EXPORT_DEFAULT, NULL);
29260
0
        } else {
29261
0
            if (js_parse_assign_expr(s))
29262
0
                return -1;
29263
0
        }
29264
        /* set the name of anonymous functions */
29265
0
        set_object_name(s, JS_ATOM_default);
29266
29267
        /* store the value in the _default_ global variable and export
29268
           it */
29269
0
        local_name = JS_ATOM__default_;
29270
0
        if (define_var(s, s->cur_func, local_name, JS_VAR_DEF_LET) < 0)
29271
0
            return -1;
29272
0
        emit_op(s, OP_scope_put_var_init);
29273
0
        emit_atom(s, local_name);
29274
0
        emit_u16(s, 0);
29275
29276
0
        if (!add_export_entry(s, m, local_name, JS_ATOM_default,
29277
0
                              JS_EXPORT_TYPE_LOCAL))
29278
0
            return -1;
29279
0
        break;
29280
0
    case TOK_VAR:
29281
0
    case TOK_LET:
29282
0
    case TOK_CONST:
29283
0
        return js_parse_var(s, TRUE, tok, TRUE);
29284
0
    default:
29285
0
        return js_parse_error(s, "invalid export syntax");
29286
0
    }
29287
0
    return js_parse_expect_semi(s);
29288
0
}
29289
29290
static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
29291
                           BOOL is_local, BOOL is_arg,
29292
                           int var_idx, JSAtom var_name,
29293
                           BOOL is_const, BOOL is_lexical,
29294
                           JSVarKindEnum var_kind);
29295
29296
static int add_import(JSParseState *s, JSModuleDef *m,
29297
                      JSAtom local_name, JSAtom import_name)
29298
78
{
29299
78
    JSContext *ctx = s->ctx;
29300
78
    int i, var_idx;
29301
78
    JSImportEntry *mi;
29302
78
    BOOL is_local;
29303
29304
78
    if (local_name == JS_ATOM_arguments || local_name == JS_ATOM_eval)
29305
0
        return js_parse_error(s, "invalid import binding");
29306
29307
78
    if (local_name != JS_ATOM_default) {
29308
117
        for (i = 0; i < s->cur_func->closure_var_count; i++) {
29309
39
            if (s->cur_func->closure_var[i].var_name == local_name)
29310
0
                return js_parse_error(s, "duplicate import binding");
29311
39
        }
29312
78
    }
29313
29314
78
    is_local = (import_name == JS_ATOM__star_);
29315
78
    var_idx = add_closure_var(ctx, s->cur_func, is_local, FALSE,
29316
78
                              m->import_entries_count,
29317
78
                              local_name, TRUE, TRUE, FALSE);
29318
78
    if (var_idx < 0)
29319
0
        return -1;
29320
78
    if (js_resize_array(ctx, (void **)&m->import_entries,
29321
78
                        sizeof(JSImportEntry),
29322
78
                        &m->import_entries_size,
29323
78
                        m->import_entries_count + 1))
29324
0
        return -1;
29325
78
    mi = &m->import_entries[m->import_entries_count++];
29326
78
    mi->import_name = JS_DupAtom(ctx, import_name);
29327
78
    mi->var_idx = var_idx;
29328
78
    return 0;
29329
78
}
29330
29331
static __exception int js_parse_import(JSParseState *s)
29332
78
{
29333
78
    JSContext *ctx = s->ctx;
29334
78
    JSModuleDef *m = s->cur_func->module;
29335
78
    JSAtom local_name, import_name, module_name;
29336
78
    int first_import, i, idx;
29337
29338
78
    if (next_token(s))
29339
0
        return -1;
29340
29341
78
    first_import = m->import_entries_count;
29342
78
    if (s->token.val == TOK_STRING) {
29343
0
        module_name = JS_ValueToAtom(ctx, s->token.u.str.str);
29344
0
        if (module_name == JS_ATOM_NULL)
29345
0
            return -1;
29346
0
        if (next_token(s)) {
29347
0
            JS_FreeAtom(ctx, module_name);
29348
0
            return -1;
29349
0
        }
29350
78
    } else {
29351
78
        if (s->token.val == TOK_IDENT) {
29352
0
            if (s->token.u.ident.is_reserved) {
29353
0
                return js_parse_error_reserved_identifier(s);
29354
0
            }
29355
            /* "default" import */
29356
0
            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
29357
0
            import_name = JS_ATOM_default;
29358
0
            if (next_token(s))
29359
0
                goto fail;
29360
0
            if (add_import(s, m, local_name, import_name))
29361
0
                goto fail;
29362
0
            JS_FreeAtom(ctx, local_name);
29363
29364
0
            if (s->token.val != ',')
29365
0
                goto end_import_clause;
29366
0
            if (next_token(s))
29367
0
                return -1;
29368
0
        }
29369
29370
78
        if (s->token.val == '*') {
29371
            /* name space import */
29372
78
            if (next_token(s))
29373
0
                return -1;
29374
78
            if (!token_is_pseudo_keyword(s, JS_ATOM_as))
29375
0
                return js_parse_error(s, "expecting 'as'");
29376
78
            if (next_token(s))
29377
0
                return -1;
29378
78
            if (!token_is_ident(s->token.val)) {
29379
0
                js_parse_error(s, "identifier expected");
29380
0
                return -1;
29381
0
            }
29382
78
            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
29383
78
            import_name = JS_ATOM__star_;
29384
78
            if (next_token(s))
29385
0
                goto fail;
29386
78
            if (add_import(s, m, local_name, import_name))
29387
0
                goto fail;
29388
78
            JS_FreeAtom(ctx, local_name);
29389
78
        } else if (s->token.val == '{') {
29390
0
            if (next_token(s))
29391
0
                return -1;
29392
29393
0
            while (s->token.val != '}') {
29394
0
                if (!token_is_ident(s->token.val)) {
29395
0
                    js_parse_error(s, "identifier expected");
29396
0
                    return -1;
29397
0
                }
29398
0
                import_name = JS_DupAtom(ctx, s->token.u.ident.atom);
29399
0
                local_name = JS_ATOM_NULL;
29400
0
                if (next_token(s))
29401
0
                    goto fail;
29402
0
                if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
29403
0
                    if (next_token(s))
29404
0
                        goto fail;
29405
0
                    if (!token_is_ident(s->token.val)) {
29406
0
                        js_parse_error(s, "identifier expected");
29407
0
                        goto fail;
29408
0
                    }
29409
0
                    local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
29410
0
                    if (next_token(s)) {
29411
0
                    fail:
29412
0
                        JS_FreeAtom(ctx, local_name);
29413
0
                        JS_FreeAtom(ctx, import_name);
29414
0
                        return -1;
29415
0
                    }
29416
0
                } else {
29417
0
                    local_name = JS_DupAtom(ctx, import_name);
29418
0
                }
29419
0
                if (add_import(s, m, local_name, import_name))
29420
0
                    goto fail;
29421
0
                JS_FreeAtom(ctx, local_name);
29422
0
                JS_FreeAtom(ctx, import_name);
29423
0
                if (s->token.val != ',')
29424
0
                    break;
29425
0
                if (next_token(s))
29426
0
                    return -1;
29427
0
            }
29428
0
            if (js_parse_expect(s, '}'))
29429
0
                return -1;
29430
0
        }
29431
78
    end_import_clause:
29432
78
        module_name = js_parse_from_clause(s);
29433
78
        if (module_name == JS_ATOM_NULL)
29434
0
            return -1;
29435
78
    }
29436
78
    idx = add_req_module_entry(ctx, m, module_name);
29437
78
    JS_FreeAtom(ctx, module_name);
29438
78
    if (idx < 0)
29439
0
        return -1;
29440
156
    for(i = first_import; i < m->import_entries_count; i++)
29441
78
        m->import_entries[i].req_module_idx = idx;
29442
29443
78
    return js_parse_expect_semi(s);
29444
78
}
29445
29446
static __exception int js_parse_source_element(JSParseState *s)
29447
196
{
29448
196
    JSFunctionDef *fd = s->cur_func;
29449
196
    int tok;
29450
29451
196
    if (s->token.val == TOK_FUNCTION ||
29452
196
        (token_is_pseudo_keyword(s, JS_ATOM_async) &&
29453
196
         peek_token(s, TRUE) == TOK_FUNCTION)) {
29454
0
        if (js_parse_function_decl(s, JS_PARSE_FUNC_STATEMENT,
29455
0
                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
29456
0
                                   s->token.ptr, s->token.line_num))
29457
0
            return -1;
29458
196
    } else if (s->token.val == TOK_EXPORT && fd->module) {
29459
0
        if (js_parse_export(s))
29460
0
            return -1;
29461
196
    } else if (s->token.val == TOK_IMPORT && fd->module &&
29462
196
               ((tok = peek_token(s, FALSE)) != '(' && tok != '.'))  {
29463
        /* the peek_token is needed to avoid confusion with ImportCall
29464
           (dynamic import) or import.meta */
29465
78
        if (js_parse_import(s))
29466
0
            return -1;
29467
118
    } else {
29468
118
        if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
29469
14
            return -1;
29470
118
    }
29471
182
    return 0;
29472
196
}
29473
29474
static JSFunctionDef *js_new_function_def(JSContext *ctx,
29475
                                          JSFunctionDef *parent,
29476
                                          BOOL is_eval,
29477
                                          BOOL is_func_expr,
29478
                                          const char *filename, int line_num)
29479
78
{
29480
78
    JSFunctionDef *fd;
29481
29482
78
    fd = js_mallocz(ctx, sizeof(*fd));
29483
78
    if (!fd)
29484
0
        return NULL;
29485
29486
78
    fd->ctx = ctx;
29487
78
    init_list_head(&fd->child_list);
29488
29489
    /* insert in parent list */
29490
78
    fd->parent = parent;
29491
78
    fd->parent_cpool_idx = -1;
29492
78
    if (parent) {
29493
0
        list_add_tail(&fd->link, &parent->child_list);
29494
0
        fd->js_mode = parent->js_mode;
29495
0
        fd->parent_scope_level = parent->scope_level;
29496
0
    }
29497
29498
78
    fd->is_eval = is_eval;
29499
78
    fd->is_func_expr = is_func_expr;
29500
78
    js_dbuf_init(ctx, &fd->byte_code);
29501
78
    fd->last_opcode_pos = -1;
29502
78
    fd->func_name = JS_ATOM_NULL;
29503
78
    fd->var_object_idx = -1;
29504
78
    fd->arg_var_object_idx = -1;
29505
78
    fd->arguments_var_idx = -1;
29506
78
    fd->arguments_arg_idx = -1;
29507
78
    fd->func_var_idx = -1;
29508
78
    fd->eval_ret_idx = -1;
29509
78
    fd->this_var_idx = -1;
29510
78
    fd->new_target_var_idx = -1;
29511
78
    fd->this_active_func_var_idx = -1;
29512
78
    fd->home_object_var_idx = -1;
29513
29514
    /* XXX: should distinguish arg, var and var object and body scopes */
29515
78
    fd->scopes = fd->def_scope_array;
29516
78
    fd->scope_size = countof(fd->def_scope_array);
29517
78
    fd->scope_count = 1;
29518
78
    fd->scopes[0].first = -1;
29519
78
    fd->scopes[0].parent = -1;
29520
78
    fd->scope_level = 0;  /* 0: var/arg scope */
29521
78
    fd->scope_first = -1;
29522
78
    fd->body_scope = -1;
29523
29524
78
    fd->filename = JS_NewAtom(ctx, filename);
29525
78
    fd->line_num = line_num;
29526
29527
78
    js_dbuf_init(ctx, &fd->pc2line);
29528
    //fd->pc2line_last_line_num = line_num;
29529
    //fd->pc2line_last_pc = 0;
29530
78
    fd->last_opcode_line_num = line_num;
29531
29532
78
    return fd;
29533
78
}
29534
29535
static void free_bytecode_atoms(JSRuntime *rt,
29536
                                const uint8_t *bc_buf, int bc_len,
29537
                                BOOL use_short_opcodes)
29538
78
{
29539
78
    int pos, len, op;
29540
78
    JSAtom atom;
29541
78
    const JSOpCode *oi;
29542
29543
78
    pos = 0;
29544
10.9M
    while (pos < bc_len) {
29545
10.9M
        op = bc_buf[pos];
29546
10.9M
        if (use_short_opcodes)
29547
7.08M
            oi = &short_opcode_info(op);
29548
3.89M
        else
29549
3.89M
            oi = &opcode_info[op];
29550
29551
10.9M
        len = oi->size;
29552
10.9M
        switch(oi->fmt) {
29553
5.45M
        case OP_FMT_atom:
29554
5.45M
        case OP_FMT_atom_u8:
29555
5.45M
        case OP_FMT_atom_u16:
29556
5.45M
        case OP_FMT_atom_label_u8:
29557
5.45M
        case OP_FMT_atom_label_u16:
29558
5.45M
            atom = get_u32(bc_buf + pos + 1);
29559
5.45M
            JS_FreeAtomRT(rt, atom);
29560
5.45M
            break;
29561
5.52M
        default:
29562
5.52M
            break;
29563
10.9M
        }
29564
10.9M
        pos += len;
29565
10.9M
    }
29566
78
}
29567
29568
static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd)
29569
15
{
29570
15
    int i;
29571
15
    struct list_head *el, *el1;
29572
29573
    /* free the child functions */
29574
15
    list_for_each_safe(el, el1, &fd->child_list) {
29575
0
        JSFunctionDef *fd1;
29576
0
        fd1 = list_entry(el, JSFunctionDef, link);
29577
0
        js_free_function_def(ctx, fd1);
29578
0
    }
29579
29580
15
    free_bytecode_atoms(ctx->rt, fd->byte_code.buf, fd->byte_code.size,
29581
15
                        fd->use_short_opcodes);
29582
15
    dbuf_free(&fd->byte_code);
29583
15
    js_free(ctx, fd->jump_slots);
29584
15
    js_free(ctx, fd->label_slots);
29585
15
    js_free(ctx, fd->line_number_slots);
29586
29587
22
    for(i = 0; i < fd->cpool_count; i++) {
29588
7
        JS_FreeValue(ctx, fd->cpool[i]);
29589
7
    }
29590
15
    js_free(ctx, fd->cpool);
29591
29592
15
    JS_FreeAtom(ctx, fd->func_name);
29593
29594
27
    for(i = 0; i < fd->var_count; i++) {
29595
12
        JS_FreeAtom(ctx, fd->vars[i].var_name);
29596
12
    }
29597
15
    js_free(ctx, fd->vars);
29598
15
    for(i = 0; i < fd->arg_count; i++) {
29599
0
        JS_FreeAtom(ctx, fd->args[i].var_name);
29600
0
    }
29601
15
    js_free(ctx, fd->args);
29602
29603
15
    for(i = 0; i < fd->global_var_count; i++) {
29604
0
        JS_FreeAtom(ctx, fd->global_vars[i].var_name);
29605
0
    }
29606
15
    js_free(ctx, fd->global_vars);
29607
29608
15
    for(i = 0; i < fd->closure_var_count; i++) {
29609
0
        JSClosureVar *cv = &fd->closure_var[i];
29610
0
        JS_FreeAtom(ctx, cv->var_name);
29611
0
    }
29612
15
    js_free(ctx, fd->closure_var);
29613
29614
15
    if (fd->scopes != fd->def_scope_array)
29615
0
        js_free(ctx, fd->scopes);
29616
29617
15
    JS_FreeAtom(ctx, fd->filename);
29618
15
    dbuf_free(&fd->pc2line);
29619
29620
15
    js_free(ctx, fd->source);
29621
29622
15
    if (fd->parent) {
29623
        /* remove in parent list */
29624
0
        list_del(&fd->link);
29625
0
    }
29626
15
    js_free(ctx, fd);
29627
15
}
29628
29629
#ifdef DUMP_BYTECODE
29630
static const char *skip_lines(const char *p, int n) {
29631
    while (n-- > 0 && *p) {
29632
        while (*p && *p++ != '\n')
29633
            continue;
29634
    }
29635
    return p;
29636
}
29637
29638
static void print_lines(const char *source, int line, int line1) {
29639
    const char *s = source;
29640
    const char *p = skip_lines(s, line);
29641
    if (*p) {
29642
        while (line++ < line1) {
29643
            p = skip_lines(s = p, 1);
29644
            printf(";; %.*s", (int)(p - s), s);
29645
            if (!*p) {
29646
                if (p[-1] != '\n')
29647
                    printf("\n");
29648
                break;
29649
            }
29650
        }
29651
    }
29652
}
29653
29654
static void dump_byte_code(JSContext *ctx, int pass,
29655
                           const uint8_t *tab, int len,
29656
                           const JSVarDef *args, int arg_count,
29657
                           const JSVarDef *vars, int var_count,
29658
                           const JSClosureVar *closure_var, int closure_var_count,
29659
                           const JSValue *cpool, uint32_t cpool_count,
29660
                           const char *source, int line_num,
29661
                           const LabelSlot *label_slots, JSFunctionBytecode *b)
29662
{
29663
    const JSOpCode *oi;
29664
    int pos, pos_next, op, size, idx, addr, line, line1, in_source;
29665
    uint8_t *bits = js_mallocz(ctx, len * sizeof(*bits));
29666
    BOOL use_short_opcodes = (b != NULL);
29667
29668
    /* scan for jump targets */
29669
    for (pos = 0; pos < len; pos = pos_next) {
29670
        op = tab[pos];
29671
        if (use_short_opcodes)
29672
            oi = &short_opcode_info(op);
29673
        else
29674
            oi = &opcode_info[op];
29675
        pos_next = pos + oi->size;
29676
        if (op < OP_COUNT) {
29677
            switch (oi->fmt) {
29678
#if SHORT_OPCODES
29679
            case OP_FMT_label8:
29680
                pos++;
29681
                addr = (int8_t)tab[pos];
29682
                goto has_addr;
29683
            case OP_FMT_label16:
29684
                pos++;
29685
                addr = (int16_t)get_u16(tab + pos);
29686
                goto has_addr;
29687
#endif
29688
            case OP_FMT_atom_label_u8:
29689
            case OP_FMT_atom_label_u16:
29690
                pos += 4;
29691
                /* fall thru */
29692
            case OP_FMT_label:
29693
            case OP_FMT_label_u16:
29694
                pos++;
29695
                addr = get_u32(tab + pos);
29696
                goto has_addr;
29697
            has_addr:
29698
                if (pass == 1)
29699
                    addr = label_slots[addr].pos;
29700
                if (pass == 2)
29701
                    addr = label_slots[addr].pos2;
29702
                if (pass == 3)
29703
                    addr += pos;
29704
                if (addr >= 0 && addr < len)
29705
                    bits[addr] |= 1;
29706
                break;
29707
            }
29708
        }
29709
    }
29710
    in_source = 0;
29711
    if (source) {
29712
        /* Always print first line: needed if single line */
29713
        print_lines(source, 0, 1);
29714
        in_source = 1;
29715
    }
29716
    line1 = line = 1;
29717
    pos = 0;
29718
    while (pos < len) {
29719
        op = tab[pos];
29720
        if (source) {
29721
            if (b) {
29722
                line1 = find_line_num(ctx, b, pos) - line_num + 1;
29723
            } else if (op == OP_line_num) {
29724
                line1 = get_u32(tab + pos + 1) - line_num + 1;
29725
            }
29726
            if (line1 > line) {
29727
                if (!in_source)
29728
                    printf("\n");
29729
                in_source = 1;
29730
                print_lines(source, line, line1);
29731
                line = line1;
29732
                //bits[pos] |= 2;
29733
            }
29734
        }
29735
        if (in_source)
29736
            printf("\n");
29737
        in_source = 0;
29738
        if (op >= OP_COUNT) {
29739
            printf("invalid opcode (0x%02x)\n", op);
29740
            pos++;
29741
            continue;
29742
        }
29743
        if (use_short_opcodes)
29744
            oi = &short_opcode_info(op);
29745
        else
29746
            oi = &opcode_info[op];
29747
        size = oi->size;
29748
        if (pos + size > len) {
29749
            printf("truncated opcode (0x%02x)\n", op);
29750
            break;
29751
        }
29752
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 16)
29753
        {
29754
            int i, x, x0;
29755
            x = x0 = printf("%5d ", pos);
29756
            for (i = 0; i < size; i++) {
29757
                if (i == 6) {
29758
                    printf("\n%*s", x = x0, "");
29759
                }
29760
                x += printf(" %02X", tab[pos + i]);
29761
            }
29762
            printf("%*s", x0 + 20 - x, "");
29763
        }
29764
#endif
29765
        if (bits[pos]) {
29766
            printf("%5d:  ", pos);
29767
        } else {
29768
            printf("        ");
29769
        }
29770
        printf("%s", oi->name);
29771
        pos++;
29772
        switch(oi->fmt) {
29773
        case OP_FMT_none_int:
29774
            printf(" %d", op - OP_push_0);
29775
            break;
29776
        case OP_FMT_npopx:
29777
            printf(" %d", op - OP_call0);
29778
            break;
29779
        case OP_FMT_u8:
29780
            printf(" %u", get_u8(tab + pos));
29781
            break;
29782
        case OP_FMT_i8:
29783
            printf(" %d", get_i8(tab + pos));
29784
            break;
29785
        case OP_FMT_u16:
29786
        case OP_FMT_npop:
29787
            printf(" %u", get_u16(tab + pos));
29788
            break;
29789
        case OP_FMT_npop_u16:
29790
            printf(" %u,%u", get_u16(tab + pos), get_u16(tab + pos + 2));
29791
            break;
29792
        case OP_FMT_i16:
29793
            printf(" %d", get_i16(tab + pos));
29794
            break;
29795
        case OP_FMT_i32:
29796
            printf(" %d", get_i32(tab + pos));
29797
            break;
29798
        case OP_FMT_u32:
29799
            printf(" %u", get_u32(tab + pos));
29800
            break;
29801
#if SHORT_OPCODES
29802
        case OP_FMT_label8:
29803
            addr = get_i8(tab + pos);
29804
            goto has_addr1;
29805
        case OP_FMT_label16:
29806
            addr = get_i16(tab + pos);
29807
            goto has_addr1;
29808
#endif
29809
        case OP_FMT_label:
29810
            addr = get_u32(tab + pos);
29811
            goto has_addr1;
29812
        has_addr1:
29813
            if (pass == 1)
29814
                printf(" %u:%u", addr, label_slots[addr].pos);
29815
            if (pass == 2)
29816
                printf(" %u:%u", addr, label_slots[addr].pos2);
29817
            if (pass == 3)
29818
                printf(" %u", addr + pos);
29819
            break;
29820
        case OP_FMT_label_u16:
29821
            addr = get_u32(tab + pos);
29822
            if (pass == 1)
29823
                printf(" %u:%u", addr, label_slots[addr].pos);
29824
            if (pass == 2)
29825
                printf(" %u:%u", addr, label_slots[addr].pos2);
29826
            if (pass == 3)
29827
                printf(" %u", addr + pos);
29828
            printf(",%u", get_u16(tab + pos + 4));
29829
            break;
29830
#if SHORT_OPCODES
29831
        case OP_FMT_const8:
29832
            idx = get_u8(tab + pos);
29833
            goto has_pool_idx;
29834
#endif
29835
        case OP_FMT_const:
29836
            idx = get_u32(tab + pos);
29837
            goto has_pool_idx;
29838
        has_pool_idx:
29839
            printf(" %u: ", idx);
29840
            if (idx < cpool_count) {
29841
                JS_DumpValue(ctx, cpool[idx]);
29842
            }
29843
            break;
29844
        case OP_FMT_atom:
29845
            printf(" ");
29846
            print_atom(ctx, get_u32(tab + pos));
29847
            break;
29848
        case OP_FMT_atom_u8:
29849
            printf(" ");
29850
            print_atom(ctx, get_u32(tab + pos));
29851
            printf(",%d", get_u8(tab + pos + 4));
29852
            break;
29853
        case OP_FMT_atom_u16:
29854
            printf(" ");
29855
            print_atom(ctx, get_u32(tab + pos));
29856
            printf(",%d", get_u16(tab + pos + 4));
29857
            break;
29858
        case OP_FMT_atom_label_u8:
29859
        case OP_FMT_atom_label_u16:
29860
            printf(" ");
29861
            print_atom(ctx, get_u32(tab + pos));
29862
            addr = get_u32(tab + pos + 4);
29863
            if (pass == 1)
29864
                printf(",%u:%u", addr, label_slots[addr].pos);
29865
            if (pass == 2)
29866
                printf(",%u:%u", addr, label_slots[addr].pos2);
29867
            if (pass == 3)
29868
                printf(",%u", addr + pos + 4);
29869
            if (oi->fmt == OP_FMT_atom_label_u8)
29870
                printf(",%u", get_u8(tab + pos + 8));
29871
            else
29872
                printf(",%u", get_u16(tab + pos + 8));
29873
            break;
29874
        case OP_FMT_none_loc:
29875
            idx = (op - OP_get_loc0) % 4;
29876
            goto has_loc;
29877
        case OP_FMT_loc8:
29878
            idx = get_u8(tab + pos);
29879
            goto has_loc;
29880
        case OP_FMT_loc:
29881
            idx = get_u16(tab + pos);
29882
        has_loc:
29883
            printf(" %d: ", idx);
29884
            if (idx < var_count) {
29885
                print_atom(ctx, vars[idx].var_name);
29886
            }
29887
            break;
29888
        case OP_FMT_none_arg:
29889
            idx = (op - OP_get_arg0) % 4;
29890
            goto has_arg;
29891
        case OP_FMT_arg:
29892
            idx = get_u16(tab + pos);
29893
        has_arg:
29894
            printf(" %d: ", idx);
29895
            if (idx < arg_count) {
29896
                print_atom(ctx, args[idx].var_name);
29897
            }
29898
            break;
29899
        case OP_FMT_none_var_ref:
29900
            idx = (op - OP_get_var_ref0) % 4;
29901
            goto has_var_ref;
29902
        case OP_FMT_var_ref:
29903
            idx = get_u16(tab + pos);
29904
        has_var_ref:
29905
            printf(" %d: ", idx);
29906
            if (idx < closure_var_count) {
29907
                print_atom(ctx, closure_var[idx].var_name);
29908
            }
29909
            break;
29910
        default:
29911
            break;
29912
        }
29913
        printf("\n");
29914
        pos += oi->size - 1;
29915
    }
29916
    if (source) {
29917
        if (!in_source)
29918
            printf("\n");
29919
        print_lines(source, line, INT32_MAX);
29920
    }
29921
    js_free(ctx, bits);
29922
}
29923
29924
static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int len,
29925
                                                 int line_num)
29926
{
29927
    const uint8_t *p_end, *p_next, *p;
29928
    int pc, v;
29929
    unsigned int op;
29930
29931
    if (len <= 0)
29932
        return;
29933
29934
    printf("%5s %5s\n", "PC", "LINE");
29935
29936
    p = buf;
29937
    p_end = buf + len;
29938
    pc = 0;
29939
    while (p < p_end) {
29940
        op = *p++;
29941
        if (op == 0) {
29942
            v = unicode_from_utf8(p, p_end - p, &p_next);
29943
            if (v < 0)
29944
                goto fail;
29945
            pc += v;
29946
            p = p_next;
29947
            v = unicode_from_utf8(p, p_end - p, &p_next);
29948
            if (v < 0) {
29949
            fail:
29950
                printf("invalid pc2line encode pos=%d\n", (int)(p - buf));
29951
                return;
29952
            }
29953
            if (!(v & 1)) {
29954
                v = v >> 1;
29955
            } else {
29956
                v = -(v >> 1) - 1;
29957
            }
29958
            line_num += v;
29959
            p = p_next;
29960
        } else {
29961
            op -= PC2LINE_OP_FIRST;
29962
            pc += (op / PC2LINE_RANGE);
29963
            line_num += (op % PC2LINE_RANGE) + PC2LINE_BASE;
29964
        }
29965
        printf("%5d %5d\n", pc, line_num);
29966
    }
29967
}
29968
29969
static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionBytecode *b)
29970
{
29971
    int i;
29972
    char atom_buf[ATOM_GET_STR_BUF_SIZE];
29973
    const char *str;
29974
29975
    if (b->has_debug && b->debug.filename != JS_ATOM_NULL) {
29976
        str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->debug.filename);
29977
        printf("%s:%d: ", str, b->debug.line_num);
29978
    }
29979
29980
    str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name);
29981
    printf("function: %s%s\n", &"*"[b->func_kind != JS_FUNC_GENERATOR], str);
29982
    if (b->js_mode) {
29983
        printf("  mode:");
29984
        if (b->js_mode & JS_MODE_STRICT)
29985
            printf(" strict");
29986
#ifdef CONFIG_BIGNUM
29987
        if (b->js_mode & JS_MODE_MATH)
29988
            printf(" math");
29989
#endif
29990
        printf("\n");
29991
    }
29992
    if (b->arg_count && b->vardefs) {
29993
        printf("  args:");
29994
        for(i = 0; i < b->arg_count; i++) {
29995
            printf(" %s", JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf),
29996
                                        b->vardefs[i].var_name));
29997
        }
29998
        printf("\n");
29999
    }
30000
    if (b->var_count && b->vardefs) {
30001
        printf("  locals:\n");
30002
        for(i = 0; i < b->var_count; i++) {
30003
            JSVarDef *vd = &b->vardefs[b->arg_count + i];
30004
            printf("%5d: %s %s", i,
30005
                   vd->var_kind == JS_VAR_CATCH ? "catch" :
30006
                   (vd->var_kind == JS_VAR_FUNCTION_DECL ||
30007
                    vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) ? "function" :
30008
                   vd->is_const ? "const" :
30009
                   vd->is_lexical ? "let" : "var",
30010
                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), vd->var_name));
30011
            if (vd->scope_level)
30012
                printf(" [level:%d next:%d]", vd->scope_level, vd->scope_next);
30013
            printf("\n");
30014
        }
30015
    }
30016
    if (b->closure_var_count) {
30017
        printf("  closure vars:\n");
30018
        for(i = 0; i < b->closure_var_count; i++) {
30019
            JSClosureVar *cv = &b->closure_var[i];
30020
            printf("%5d: %s %s:%s%d %s\n", i,
30021
                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), cv->var_name),
30022
                   cv->is_local ? "local" : "parent",
30023
                   cv->is_arg ? "arg" : "loc", cv->var_idx,
30024
                   cv->is_const ? "const" :
30025
                   cv->is_lexical ? "let" : "var");
30026
        }
30027
    }
30028
    printf("  stack_size: %d\n", b->stack_size);
30029
    printf("  opcodes:\n");
30030
    dump_byte_code(ctx, 3, b->byte_code_buf, b->byte_code_len,
30031
                   b->vardefs, b->arg_count,
30032
                   b->vardefs ? b->vardefs + b->arg_count : NULL, b->var_count,
30033
                   b->closure_var, b->closure_var_count,
30034
                   b->cpool, b->cpool_count,
30035
                   b->has_debug ? b->debug.source : NULL,
30036
                   b->has_debug ? b->debug.line_num : -1, NULL, b);
30037
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32)
30038
    if (b->has_debug)
30039
        dump_pc2line(ctx, b->debug.pc2line_buf, b->debug.pc2line_len, b->debug.line_num);
30040
#endif
30041
    printf("\n");
30042
}
30043
#endif
30044
30045
static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
30046
                           BOOL is_local, BOOL is_arg,
30047
                           int var_idx, JSAtom var_name,
30048
                           BOOL is_const, BOOL is_lexical,
30049
                           JSVarKindEnum var_kind)
30050
78
{
30051
78
    JSClosureVar *cv;
30052
30053
    /* the closure variable indexes are currently stored on 16 bits */
30054
78
    if (s->closure_var_count >= JS_MAX_LOCAL_VARS) {
30055
0
        JS_ThrowInternalError(ctx, "too many closure variables");
30056
0
        return -1;
30057
0
    }
30058
30059
78
    if (js_resize_array(ctx, (void **)&s->closure_var,
30060
78
                        sizeof(s->closure_var[0]),
30061
78
                        &s->closure_var_size, s->closure_var_count + 1))
30062
0
        return -1;
30063
78
    cv = &s->closure_var[s->closure_var_count++];
30064
78
    cv->is_local = is_local;
30065
78
    cv->is_arg = is_arg;
30066
78
    cv->is_const = is_const;
30067
78
    cv->is_lexical = is_lexical;
30068
78
    cv->var_kind = var_kind;
30069
78
    cv->var_idx = var_idx;
30070
78
    cv->var_name = JS_DupAtom(ctx, var_name);
30071
78
    return s->closure_var_count - 1;
30072
78
}
30073
30074
static int find_closure_var(JSContext *ctx, JSFunctionDef *s,
30075
                            JSAtom var_name)
30076
0
{
30077
0
    int i;
30078
0
    for(i = 0; i < s->closure_var_count; i++) {
30079
0
        JSClosureVar *cv = &s->closure_var[i];
30080
0
        if (cv->var_name == var_name)
30081
0
            return i;
30082
0
    }
30083
0
    return -1;
30084
0
}
30085
30086
/* 'fd' must be a parent of 's'. Create in 's' a closure referencing a
30087
   local variable (is_local = TRUE) or a closure (is_local = FALSE) in
30088
   'fd' */
30089
static int get_closure_var2(JSContext *ctx, JSFunctionDef *s,
30090
                            JSFunctionDef *fd, BOOL is_local,
30091
                            BOOL is_arg, int var_idx, JSAtom var_name,
30092
                            BOOL is_const, BOOL is_lexical,
30093
                            JSVarKindEnum var_kind)
30094
0
{
30095
0
    int i;
30096
30097
0
    if (fd != s->parent) {
30098
0
        var_idx = get_closure_var2(ctx, s->parent, fd, is_local,
30099
0
                                   is_arg, var_idx, var_name,
30100
0
                                   is_const, is_lexical, var_kind);
30101
0
        if (var_idx < 0)
30102
0
            return -1;
30103
0
        is_local = FALSE;
30104
0
    }
30105
0
    for(i = 0; i < s->closure_var_count; i++) {
30106
0
        JSClosureVar *cv = &s->closure_var[i];
30107
0
        if (cv->var_idx == var_idx && cv->is_arg == is_arg &&
30108
0
            cv->is_local == is_local)
30109
0
            return i;
30110
0
    }
30111
0
    return add_closure_var(ctx, s, is_local, is_arg, var_idx, var_name,
30112
0
                           is_const, is_lexical, var_kind);
30113
0
}
30114
30115
static int get_closure_var(JSContext *ctx, JSFunctionDef *s,
30116
                           JSFunctionDef *fd, BOOL is_arg,
30117
                           int var_idx, JSAtom var_name,
30118
                           BOOL is_const, BOOL is_lexical,
30119
                           JSVarKindEnum var_kind)
30120
0
{
30121
0
    return get_closure_var2(ctx, s, fd, TRUE, is_arg,
30122
0
                            var_idx, var_name, is_const, is_lexical,
30123
0
                            var_kind);
30124
0
}
30125
30126
static int get_with_scope_opcode(int op)
30127
0
{
30128
0
    if (op == OP_scope_get_var_undef)
30129
0
        return OP_with_get_var;
30130
0
    else
30131
0
        return OP_with_get_var + (op - OP_scope_get_var);
30132
0
}
30133
30134
static BOOL can_opt_put_ref_value(const uint8_t *bc_buf, int pos)
30135
0
{
30136
0
    int opcode = bc_buf[pos];
30137
0
    return (bc_buf[pos + 1] == OP_put_ref_value &&
30138
0
            (opcode == OP_insert3 ||
30139
0
             opcode == OP_perm4 ||
30140
0
             opcode == OP_nop ||
30141
0
             opcode == OP_rot3l));
30142
0
}
30143
30144
static BOOL can_opt_put_global_ref_value(const uint8_t *bc_buf, int pos)
30145
0
{
30146
0
    int opcode = bc_buf[pos];
30147
0
    return (bc_buf[pos + 1] == OP_put_ref_value &&
30148
0
            (opcode == OP_insert3 ||
30149
0
             opcode == OP_perm4 ||
30150
0
             opcode == OP_nop ||
30151
0
             opcode == OP_rot3l));
30152
0
}
30153
30154
static int optimize_scope_make_ref(JSContext *ctx, JSFunctionDef *s,
30155
                                   DynBuf *bc, uint8_t *bc_buf,
30156
                                   LabelSlot *ls, int pos_next,
30157
                                   int get_op, int var_idx)
30158
0
{
30159
0
    int label_pos, end_pos, pos;
30160
30161
    /* XXX: should optimize `loc(a) += expr` as `expr add_loc(a)`
30162
       but only if expr does not modify `a`.
30163
       should scan the code between pos_next and label_pos
30164
       for operations that can potentially change `a`:
30165
       OP_scope_make_ref(a), function calls, jumps and gosub.
30166
     */
30167
    /* replace the reference get/put with normal variable
30168
       accesses */
30169
0
    if (bc_buf[pos_next] == OP_get_ref_value) {
30170
0
        dbuf_putc(bc, get_op);
30171
0
        dbuf_put_u16(bc, var_idx);
30172
0
        pos_next++;
30173
0
    }
30174
    /* remove the OP_label to make room for replacement */
30175
    /* label should have a refcount of 0 anyway */
30176
    /* XXX: should avoid this patch by inserting nops in phase 1 */
30177
0
    label_pos = ls->pos;
30178
0
    pos = label_pos - 5;
30179
0
    assert(bc_buf[pos] == OP_label);
30180
    /* label points to an instruction pair:
30181
       - insert3 / put_ref_value
30182
       - perm4 / put_ref_value
30183
       - rot3l / put_ref_value
30184
       - nop / put_ref_value
30185
     */
30186
0
    end_pos = label_pos + 2;
30187
0
    if (bc_buf[label_pos] == OP_insert3)
30188
0
        bc_buf[pos++] = OP_dup;
30189
0
    bc_buf[pos] = get_op + 1;
30190
0
    put_u16(bc_buf + pos + 1, var_idx);
30191
0
    pos += 3;
30192
    /* pad with OP_nop */
30193
0
    while (pos < end_pos)
30194
0
        bc_buf[pos++] = OP_nop;
30195
0
    return pos_next;
30196
0
}
30197
30198
static int optimize_scope_make_global_ref(JSContext *ctx, JSFunctionDef *s,
30199
                                          DynBuf *bc, uint8_t *bc_buf,
30200
                                          LabelSlot *ls, int pos_next,
30201
                                          JSAtom var_name)
30202
0
{
30203
0
    int label_pos, end_pos, pos, op;
30204
0
    BOOL is_strict;
30205
0
    is_strict = ((s->js_mode & JS_MODE_STRICT) != 0);
30206
30207
    /* replace the reference get/put with normal variable
30208
       accesses */
30209
0
    if (is_strict) {
30210
        /* need to check if the variable exists before evaluating the right
30211
           expression */
30212
        /* XXX: need an extra OP_true if destructuring an array */
30213
0
        dbuf_putc(bc, OP_check_var);
30214
0
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30215
0
    } else {
30216
        /* XXX: need 2 extra OP_true if destructuring an array */
30217
0
    }
30218
0
    if (bc_buf[pos_next] == OP_get_ref_value) {
30219
0
        dbuf_putc(bc, OP_get_var);
30220
0
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30221
0
        pos_next++;
30222
0
    }
30223
    /* remove the OP_label to make room for replacement */
30224
    /* label should have a refcount of 0 anyway */
30225
    /* XXX: should have emitted several OP_nop to avoid this kludge */
30226
0
    label_pos = ls->pos;
30227
0
    pos = label_pos - 5;
30228
0
    assert(bc_buf[pos] == OP_label);
30229
0
    end_pos = label_pos + 2;
30230
0
    op = bc_buf[label_pos];
30231
0
    if (is_strict) {
30232
0
        if (op != OP_nop) {
30233
0
            switch(op) {
30234
0
            case OP_insert3:
30235
0
                op = OP_insert2;
30236
0
                break;
30237
0
            case OP_perm4:
30238
0
                op = OP_perm3;
30239
0
                break;
30240
0
            case OP_rot3l:
30241
0
                op = OP_swap;
30242
0
                break;
30243
0
            default:
30244
0
                abort();
30245
0
            }
30246
0
            bc_buf[pos++] = op;
30247
0
        }
30248
0
    } else {
30249
0
        if (op == OP_insert3)
30250
0
            bc_buf[pos++] = OP_dup;
30251
0
    }
30252
0
    if (is_strict) {
30253
0
        bc_buf[pos] = OP_put_var_strict;
30254
        /* XXX: need 1 extra OP_drop if destructuring an array */
30255
0
    } else {
30256
0
        bc_buf[pos] = OP_put_var;
30257
        /* XXX: need 2 extra OP_drop if destructuring an array */
30258
0
    }
30259
0
    put_u32(bc_buf + pos + 1, JS_DupAtom(ctx, var_name));
30260
0
    pos += 5;
30261
    /* pad with OP_nop */
30262
0
    while (pos < end_pos)
30263
0
        bc_buf[pos++] = OP_nop;
30264
0
    return pos_next;
30265
0
}
30266
30267
static int add_var_this(JSContext *ctx, JSFunctionDef *fd)
30268
0
{
30269
0
    int idx;
30270
0
    idx = add_var(ctx, fd, JS_ATOM_this);
30271
0
    if (idx >= 0 && fd->is_derived_class_constructor) {
30272
0
        JSVarDef *vd = &fd->vars[idx];
30273
        /* XXX: should have is_this flag or var type */
30274
0
        vd->is_lexical = 1; /* used to trigger 'uninitialized' checks
30275
                               in a derived class constructor */
30276
0
    }
30277
0
    return idx;
30278
0
}
30279
30280
static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s,
30281
                               JSAtom var_name)
30282
0
{
30283
0
    int var_idx;
30284
30285
0
    if (!s->has_this_binding)
30286
0
        return -1;
30287
0
    switch(var_name) {
30288
0
    case JS_ATOM_home_object:
30289
        /* 'home_object' pseudo variable */
30290
0
        if (s->home_object_var_idx < 0)
30291
0
            s->home_object_var_idx = add_var(ctx, s, var_name);
30292
0
        var_idx = s->home_object_var_idx;
30293
0
        break;
30294
0
    case JS_ATOM_this_active_func:
30295
        /* 'this.active_func' pseudo variable */
30296
0
        if (s->this_active_func_var_idx < 0)
30297
0
            s->this_active_func_var_idx = add_var(ctx, s, var_name);
30298
0
        var_idx = s->this_active_func_var_idx;
30299
0
        break;
30300
0
    case JS_ATOM_new_target:
30301
        /* 'new.target' pseudo variable */
30302
0
        if (s->new_target_var_idx < 0)
30303
0
            s->new_target_var_idx = add_var(ctx, s, var_name);
30304
0
        var_idx = s->new_target_var_idx;
30305
0
        break;
30306
0
    case JS_ATOM_this:
30307
        /* 'this' pseudo variable */
30308
0
        if (s->this_var_idx < 0)
30309
0
            s->this_var_idx = add_var_this(ctx, s);
30310
0
        var_idx = s->this_var_idx;
30311
0
        break;
30312
0
    default:
30313
0
        var_idx = -1;
30314
0
        break;
30315
0
    }
30316
0
    return var_idx;
30317
0
}
30318
30319
/* test if 'var_name' is in the variable object on the stack. If is it
30320
   the case, handle it and jump to 'label_done' */
30321
static void var_object_test(JSContext *ctx, JSFunctionDef *s,
30322
                            JSAtom var_name, int op, DynBuf *bc,
30323
                            int *plabel_done, BOOL is_with)
30324
0
{
30325
0
    dbuf_putc(bc, get_with_scope_opcode(op));
30326
0
    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30327
0
    *plabel_done = new_label_fd(s, *plabel_done);
30328
0
    dbuf_put_u32(bc, *plabel_done);
30329
0
    dbuf_putc(bc, is_with);
30330
0
    update_label(s, *plabel_done, 1);
30331
0
    s->jump_size++;
30332
0
}
30333
30334
/* return the position of the next opcode */
30335
static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
30336
                             JSAtom var_name, int scope_level, int op,
30337
                             DynBuf *bc, uint8_t *bc_buf,
30338
                             LabelSlot *ls, int pos_next)
30339
167
{
30340
167
    int idx, var_idx, is_put;
30341
167
    int label_done;
30342
167
    JSFunctionDef *fd;
30343
167
    JSVarDef *vd;
30344
167
    BOOL is_pseudo_var, is_arg_scope;
30345
30346
167
    label_done = -1;
30347
30348
    /* XXX: could be simpler to use a specific function to
30349
       resolve the pseudo variables */
30350
167
    is_pseudo_var = (var_name == JS_ATOM_home_object ||
30351
167
                     var_name == JS_ATOM_this_active_func ||
30352
167
                     var_name == JS_ATOM_new_target ||
30353
167
                     var_name == JS_ATOM_this);
30354
30355
    /* resolve local scoped variables */
30356
167
    var_idx = -1;
30357
167
    for (idx = s->scopes[scope_level].first; idx >= 0;) {
30358
0
        vd = &s->vars[idx];
30359
0
        if (vd->var_name == var_name) {
30360
0
            if (op == OP_scope_put_var || op == OP_scope_make_ref) {
30361
0
                if (vd->is_const) {
30362
0
                    dbuf_putc(bc, OP_throw_error);
30363
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30364
0
                    dbuf_putc(bc, JS_THROW_VAR_RO);
30365
0
                    goto done;
30366
0
                }
30367
0
            }
30368
0
            var_idx = idx;
30369
0
            break;
30370
0
        } else
30371
0
        if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
30372
0
            dbuf_putc(bc, OP_get_loc);
30373
0
            dbuf_put_u16(bc, idx);
30374
0
            var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
30375
0
        }
30376
0
        idx = vd->scope_next;
30377
0
    }
30378
167
    is_arg_scope = (idx == ARG_SCOPE_END);
30379
167
    if (var_idx < 0) {
30380
        /* argument scope: variables are not visible but pseudo
30381
           variables are visible */
30382
167
        if (!is_arg_scope) {
30383
167
            var_idx = find_var(ctx, s, var_name);
30384
167
        }
30385
30386
167
        if (var_idx < 0 && is_pseudo_var)
30387
0
            var_idx = resolve_pseudo_var(ctx, s, var_name);
30388
30389
167
        if (var_idx < 0 && var_name == JS_ATOM_arguments &&
30390
167
            s->has_arguments_binding) {
30391
            /* 'arguments' pseudo variable */
30392
0
            var_idx = add_arguments_var(ctx, s);
30393
0
        }
30394
167
        if (var_idx < 0 && s->is_func_expr && var_name == s->func_name) {
30395
            /* add a new variable with the function name */
30396
0
            var_idx = add_func_var(ctx, s, var_name);
30397
0
        }
30398
167
    }
30399
167
    if (var_idx >= 0) {
30400
0
        if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
30401
0
            !(var_idx & ARGUMENT_VAR_OFFSET) &&
30402
0
            s->vars[var_idx].is_const) {
30403
            /* only happens when assigning a function expression name
30404
               in strict mode */
30405
0
            dbuf_putc(bc, OP_throw_error);
30406
0
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30407
0
            dbuf_putc(bc, JS_THROW_VAR_RO);
30408
0
            goto done;
30409
0
        }
30410
        /* OP_scope_put_var_init is only used to initialize a
30411
           lexical variable, so it is never used in a with or var object. It
30412
           can be used with a closure (module global variable case). */
30413
0
        switch (op) {
30414
0
        case OP_scope_make_ref:
30415
0
            if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
30416
0
                s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
30417
                /* Create a dummy object reference for the func_var */
30418
0
                dbuf_putc(bc, OP_object);
30419
0
                dbuf_putc(bc, OP_get_loc);
30420
0
                dbuf_put_u16(bc, var_idx);
30421
0
                dbuf_putc(bc, OP_define_field);
30422
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30423
0
                dbuf_putc(bc, OP_push_atom_value);
30424
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30425
0
            } else
30426
0
            if (label_done == -1 && can_opt_put_ref_value(bc_buf, ls->pos)) {
30427
0
                int get_op;
30428
0
                if (var_idx & ARGUMENT_VAR_OFFSET) {
30429
0
                    get_op = OP_get_arg;
30430
0
                    var_idx -= ARGUMENT_VAR_OFFSET;
30431
0
                } else {
30432
0
                    if (s->vars[var_idx].is_lexical)
30433
0
                        get_op = OP_get_loc_check;
30434
0
                    else
30435
0
                        get_op = OP_get_loc;
30436
0
                }
30437
0
                pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
30438
0
                                                   pos_next, get_op, var_idx);
30439
0
            } else {
30440
                /* Create a dummy object with a named slot that is
30441
                   a reference to the local variable */
30442
0
                if (var_idx & ARGUMENT_VAR_OFFSET) {
30443
0
                    dbuf_putc(bc, OP_make_arg_ref);
30444
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30445
0
                    dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
30446
0
                } else {
30447
0
                    dbuf_putc(bc, OP_make_loc_ref);
30448
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30449
0
                    dbuf_put_u16(bc, var_idx);
30450
0
                }
30451
0
            }
30452
0
            break;
30453
0
        case OP_scope_get_ref:
30454
0
            dbuf_putc(bc, OP_undefined);
30455
            /* fall thru */
30456
0
        case OP_scope_get_var_checkthis:
30457
0
        case OP_scope_get_var_undef:
30458
0
        case OP_scope_get_var:
30459
0
        case OP_scope_put_var:
30460
0
        case OP_scope_put_var_init:
30461
0
            is_put = (op == OP_scope_put_var || op == OP_scope_put_var_init);
30462
0
            if (var_idx & ARGUMENT_VAR_OFFSET) {
30463
0
                dbuf_putc(bc, OP_get_arg + is_put);
30464
0
                dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
30465
0
            } else {
30466
0
                if (is_put) {
30467
0
                    if (s->vars[var_idx].is_lexical) {
30468
0
                        if (op == OP_scope_put_var_init) {
30469
                            /* 'this' can only be initialized once */
30470
0
                            if (var_name == JS_ATOM_this)
30471
0
                                dbuf_putc(bc, OP_put_loc_check_init);
30472
0
                            else
30473
0
                                dbuf_putc(bc, OP_put_loc);
30474
0
                        } else {
30475
0
                            dbuf_putc(bc, OP_put_loc_check);
30476
0
                        }
30477
0
                    } else {
30478
0
                        dbuf_putc(bc, OP_put_loc);
30479
0
                    }
30480
0
                } else {
30481
0
                    if (s->vars[var_idx].is_lexical) {
30482
0
                        if (op == OP_scope_get_var_checkthis) {
30483
                            /* only used for 'this' return in derived class constructors */
30484
0
                            dbuf_putc(bc, OP_get_loc_checkthis);
30485
0
                        } else {
30486
0
                            dbuf_putc(bc, OP_get_loc_check);
30487
0
                        }
30488
0
                    } else {
30489
0
                        dbuf_putc(bc, OP_get_loc);
30490
0
                    }
30491
0
                }
30492
0
                dbuf_put_u16(bc, var_idx);
30493
0
            }
30494
0
            break;
30495
0
        case OP_scope_delete_var:
30496
0
            dbuf_putc(bc, OP_push_false);
30497
0
            break;
30498
0
        }
30499
0
        goto done;
30500
0
    }
30501
    /* check eval object */
30502
167
    if (!is_arg_scope && s->var_object_idx >= 0 && !is_pseudo_var) {
30503
0
        dbuf_putc(bc, OP_get_loc);
30504
0
        dbuf_put_u16(bc, s->var_object_idx);
30505
0
        var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
30506
0
    }
30507
    /* check eval object in argument scope */
30508
167
    if (s->arg_var_object_idx >= 0 && !is_pseudo_var) {
30509
0
        dbuf_putc(bc, OP_get_loc);
30510
0
        dbuf_put_u16(bc, s->arg_var_object_idx);
30511
0
        var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
30512
0
    }
30513
30514
    /* check parent scopes */
30515
167
    for (fd = s; fd->parent;) {
30516
0
        scope_level = fd->parent_scope_level;
30517
0
        fd = fd->parent;
30518
0
        for (idx = fd->scopes[scope_level].first; idx >= 0;) {
30519
0
            vd = &fd->vars[idx];
30520
0
            if (vd->var_name == var_name) {
30521
0
                if (op == OP_scope_put_var || op == OP_scope_make_ref) {
30522
0
                    if (vd->is_const) {
30523
0
                        dbuf_putc(bc, OP_throw_error);
30524
0
                        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30525
0
                        dbuf_putc(bc, JS_THROW_VAR_RO);
30526
0
                        goto done;
30527
0
                    }
30528
0
                }
30529
0
                var_idx = idx;
30530
0
                break;
30531
0
            } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
30532
0
                vd->is_captured = 1;
30533
0
                idx = get_closure_var(ctx, s, fd, FALSE, idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
30534
0
                if (idx >= 0) {
30535
0
                    dbuf_putc(bc, OP_get_var_ref);
30536
0
                    dbuf_put_u16(bc, idx);
30537
0
                    var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
30538
0
                }
30539
0
            }
30540
0
            idx = vd->scope_next;
30541
0
        }
30542
0
        is_arg_scope = (idx == ARG_SCOPE_END);
30543
0
        if (var_idx >= 0)
30544
0
            break;
30545
30546
0
        if (!is_arg_scope) {
30547
0
            var_idx = find_var(ctx, fd, var_name);
30548
0
            if (var_idx >= 0)
30549
0
                break;
30550
0
        }
30551
0
        if (is_pseudo_var) {
30552
0
            var_idx = resolve_pseudo_var(ctx, fd, var_name);
30553
0
            if (var_idx >= 0)
30554
0
                break;
30555
0
        }
30556
0
        if (var_name == JS_ATOM_arguments && fd->has_arguments_binding) {
30557
0
            var_idx = add_arguments_var(ctx, fd);
30558
0
            break;
30559
0
        }
30560
0
        if (fd->is_func_expr && fd->func_name == var_name) {
30561
            /* add a new variable with the function name */
30562
0
            var_idx = add_func_var(ctx, fd, var_name);
30563
0
            break;
30564
0
        }
30565
30566
        /* check eval object */
30567
0
        if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
30568
0
            vd = &fd->vars[fd->var_object_idx];
30569
0
            vd->is_captured = 1;
30570
0
            idx = get_closure_var(ctx, s, fd, FALSE,
30571
0
                                  fd->var_object_idx, vd->var_name,
30572
0
                                  FALSE, FALSE, JS_VAR_NORMAL);
30573
0
            dbuf_putc(bc, OP_get_var_ref);
30574
0
            dbuf_put_u16(bc, idx);
30575
0
            var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
30576
0
        }
30577
30578
        /* check eval object in argument scope */
30579
0
        if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
30580
0
            vd = &fd->vars[fd->arg_var_object_idx];
30581
0
            vd->is_captured = 1;
30582
0
            idx = get_closure_var(ctx, s, fd, FALSE,
30583
0
                                  fd->arg_var_object_idx, vd->var_name,
30584
0
                                  FALSE, FALSE, JS_VAR_NORMAL);
30585
0
            dbuf_putc(bc, OP_get_var_ref);
30586
0
            dbuf_put_u16(bc, idx);
30587
0
            var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
30588
0
        }
30589
30590
0
        if (fd->is_eval)
30591
0
            break; /* it it necessarily the top level function */
30592
0
    }
30593
30594
    /* check direct eval scope (in the closure of the eval function
30595
       which is necessarily at the top level) */
30596
167
    if (!fd)
30597
0
        fd = s;
30598
167
    if (var_idx < 0 && fd->is_eval) {
30599
167
        int idx1;
30600
362
        for (idx1 = 0; idx1 < fd->closure_var_count; idx1++) {
30601
273
            JSClosureVar *cv = &fd->closure_var[idx1];
30602
273
            if (var_name == cv->var_name) {
30603
78
                if (fd != s) {
30604
0
                    idx = get_closure_var2(ctx, s, fd,
30605
0
                                           FALSE,
30606
0
                                           cv->is_arg, idx1,
30607
0
                                           cv->var_name, cv->is_const,
30608
0
                                           cv->is_lexical, cv->var_kind);
30609
78
                } else {
30610
78
                    idx = idx1;
30611
78
                }
30612
78
                goto has_idx;
30613
195
            } else if ((cv->var_name == JS_ATOM__var_ ||
30614
195
                        cv->var_name == JS_ATOM__arg_var_ ||
30615
195
                        cv->var_name == JS_ATOM__with_) && !is_pseudo_var) {
30616
0
                int is_with = (cv->var_name == JS_ATOM__with_);
30617
0
                if (fd != s) {
30618
0
                    idx = get_closure_var2(ctx, s, fd,
30619
0
                                           FALSE,
30620
0
                                           cv->is_arg, idx1,
30621
0
                                           cv->var_name, FALSE, FALSE,
30622
0
                                           JS_VAR_NORMAL);
30623
0
                } else {
30624
0
                    idx = idx1;
30625
0
                }
30626
0
                dbuf_putc(bc, OP_get_var_ref);
30627
0
                dbuf_put_u16(bc, idx);
30628
0
                var_object_test(ctx, s, var_name, op, bc, &label_done, is_with);
30629
0
            }
30630
273
        }
30631
167
    }
30632
30633
89
    if (var_idx >= 0) {
30634
        /* find the corresponding closure variable */
30635
0
        if (var_idx & ARGUMENT_VAR_OFFSET) {
30636
0
            fd->args[var_idx - ARGUMENT_VAR_OFFSET].is_captured = 1;
30637
0
            idx = get_closure_var(ctx, s, fd,
30638
0
                                  TRUE, var_idx - ARGUMENT_VAR_OFFSET,
30639
0
                                  var_name, FALSE, FALSE, JS_VAR_NORMAL);
30640
0
        } else {
30641
0
            fd->vars[var_idx].is_captured = 1;
30642
0
            idx = get_closure_var(ctx, s, fd,
30643
0
                                  FALSE, var_idx,
30644
0
                                  var_name,
30645
0
                                  fd->vars[var_idx].is_const,
30646
0
                                  fd->vars[var_idx].is_lexical,
30647
0
                                  fd->vars[var_idx].var_kind);
30648
0
        }
30649
0
        if (idx >= 0) {
30650
78
        has_idx:
30651
78
            if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
30652
78
                s->closure_var[idx].is_const) {
30653
0
                dbuf_putc(bc, OP_throw_error);
30654
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30655
0
                dbuf_putc(bc, JS_THROW_VAR_RO);
30656
0
                goto done;
30657
0
            }
30658
78
            switch (op) {
30659
0
            case OP_scope_make_ref:
30660
0
                if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
30661
                    /* Create a dummy object reference for the func_var */
30662
0
                    dbuf_putc(bc, OP_object);
30663
0
                    dbuf_putc(bc, OP_get_var_ref);
30664
0
                    dbuf_put_u16(bc, idx);
30665
0
                    dbuf_putc(bc, OP_define_field);
30666
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30667
0
                    dbuf_putc(bc, OP_push_atom_value);
30668
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30669
0
                } else
30670
0
                if (label_done == -1 &&
30671
0
                    can_opt_put_ref_value(bc_buf, ls->pos)) {
30672
0
                    int get_op;
30673
0
                    if (s->closure_var[idx].is_lexical)
30674
0
                        get_op = OP_get_var_ref_check;
30675
0
                    else
30676
0
                        get_op = OP_get_var_ref;
30677
0
                    pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
30678
0
                                                       pos_next,
30679
0
                                                       get_op, idx);
30680
0
                } else {
30681
                    /* Create a dummy object with a named slot that is
30682
                       a reference to the closure variable */
30683
0
                    dbuf_putc(bc, OP_make_var_ref_ref);
30684
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30685
0
                    dbuf_put_u16(bc, idx);
30686
0
                }
30687
0
                break;
30688
0
            case OP_scope_get_ref:
30689
                /* XXX: should create a dummy object with a named slot that is
30690
                   a reference to the closure variable */
30691
0
                dbuf_putc(bc, OP_undefined);
30692
                /* fall thru */
30693
0
            case OP_scope_get_var_undef:
30694
78
            case OP_scope_get_var:
30695
78
            case OP_scope_put_var:
30696
78
            case OP_scope_put_var_init:
30697
78
                is_put = (op == OP_scope_put_var ||
30698
78
                          op == OP_scope_put_var_init);
30699
78
                if (is_put) {
30700
0
                    if (s->closure_var[idx].is_lexical) {
30701
0
                        if (op == OP_scope_put_var_init) {
30702
                            /* 'this' can only be initialized once */
30703
0
                            if (var_name == JS_ATOM_this)
30704
0
                                dbuf_putc(bc, OP_put_var_ref_check_init);
30705
0
                            else
30706
0
                                dbuf_putc(bc, OP_put_var_ref);
30707
0
                        } else {
30708
0
                            dbuf_putc(bc, OP_put_var_ref_check);
30709
0
                        }
30710
0
                    } else {
30711
0
                        dbuf_putc(bc, OP_put_var_ref);
30712
0
                    }
30713
78
                } else {
30714
78
                    if (s->closure_var[idx].is_lexical) {
30715
78
                        dbuf_putc(bc, OP_get_var_ref_check);
30716
78
                    } else {
30717
0
                        dbuf_putc(bc, OP_get_var_ref);
30718
0
                    }
30719
78
                }
30720
78
                dbuf_put_u16(bc, idx);
30721
78
                break;
30722
0
            case OP_scope_delete_var:
30723
0
                dbuf_putc(bc, OP_push_false);
30724
0
                break;
30725
78
            }
30726
78
            goto done;
30727
78
        }
30728
0
    }
30729
30730
    /* global variable access */
30731
30732
89
    switch (op) {
30733
0
    case OP_scope_make_ref:
30734
0
        if (label_done == -1 && can_opt_put_global_ref_value(bc_buf, ls->pos)) {
30735
0
            pos_next = optimize_scope_make_global_ref(ctx, s, bc, bc_buf, ls,
30736
0
                                                      pos_next, var_name);
30737
0
        } else {
30738
0
            dbuf_putc(bc, OP_make_var_ref);
30739
0
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30740
0
        }
30741
0
        break;
30742
0
    case OP_scope_get_ref:
30743
        /* XXX: should create a dummy object with a named slot that is
30744
           a reference to the global variable */
30745
0
        dbuf_putc(bc, OP_undefined);
30746
0
        dbuf_putc(bc, OP_get_var);
30747
0
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30748
0
        break;
30749
0
    case OP_scope_get_var_undef:
30750
89
    case OP_scope_get_var:
30751
89
    case OP_scope_put_var:
30752
89
        dbuf_putc(bc, OP_get_var_undef + (op - OP_scope_get_var_undef));
30753
89
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30754
89
        break;
30755
0
    case OP_scope_put_var_init:
30756
0
        dbuf_putc(bc, OP_put_var_init);
30757
0
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30758
0
        break;
30759
0
    case OP_scope_delete_var:
30760
0
        dbuf_putc(bc, OP_delete_var);
30761
0
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30762
0
        break;
30763
89
    }
30764
167
done:
30765
167
    if (label_done >= 0) {
30766
0
        dbuf_putc(bc, OP_label);
30767
0
        dbuf_put_u32(bc, label_done);
30768
0
        s->label_slots[label_done].pos2 = bc->size;
30769
0
    }
30770
167
    return pos_next;
30771
89
}
30772
30773
/* search in all scopes */
30774
static int find_private_class_field_all(JSContext *ctx, JSFunctionDef *fd,
30775
                                        JSAtom name, int scope_level)
30776
0
{
30777
0
    int idx;
30778
30779
0
    idx = fd->scopes[scope_level].first;
30780
0
    while (idx >= 0) {
30781
0
        if (fd->vars[idx].var_name == name)
30782
0
            return idx;
30783
0
        idx = fd->vars[idx].scope_next;
30784
0
    }
30785
0
    return -1;
30786
0
}
30787
30788
static void get_loc_or_ref(DynBuf *bc, BOOL is_ref, int idx)
30789
0
{
30790
    /* if the field is not initialized, the error is catched when
30791
       accessing it */
30792
0
    if (is_ref)
30793
0
        dbuf_putc(bc, OP_get_var_ref);
30794
0
    else
30795
0
        dbuf_putc(bc, OP_get_loc);
30796
0
    dbuf_put_u16(bc, idx);
30797
0
}
30798
30799
static int resolve_scope_private_field1(JSContext *ctx,
30800
                                        BOOL *pis_ref, int *pvar_kind,
30801
                                        JSFunctionDef *s,
30802
                                        JSAtom var_name, int scope_level)
30803
0
{
30804
0
    int idx, var_kind;
30805
0
    JSFunctionDef *fd;
30806
0
    BOOL is_ref;
30807
30808
0
    fd = s;
30809
0
    is_ref = FALSE;
30810
0
    for(;;) {
30811
0
        idx = find_private_class_field_all(ctx, fd, var_name, scope_level);
30812
0
        if (idx >= 0) {
30813
0
            var_kind = fd->vars[idx].var_kind;
30814
0
            if (is_ref) {
30815
0
                idx = get_closure_var(ctx, s, fd, FALSE, idx, var_name,
30816
0
                                      TRUE, TRUE, JS_VAR_NORMAL);
30817
0
                if (idx < 0)
30818
0
                    return -1;
30819
0
            }
30820
0
            break;
30821
0
        }
30822
0
        scope_level = fd->parent_scope_level;
30823
0
        if (!fd->parent) {
30824
0
            if (fd->is_eval) {
30825
                /* closure of the eval function (top level) */
30826
0
                for (idx = 0; idx < fd->closure_var_count; idx++) {
30827
0
                    JSClosureVar *cv = &fd->closure_var[idx];
30828
0
                    if (cv->var_name == var_name) {
30829
0
                        var_kind = cv->var_kind;
30830
0
                        is_ref = TRUE;
30831
0
                        if (fd != s) {
30832
0
                            idx = get_closure_var2(ctx, s, fd,
30833
0
                                                   FALSE,
30834
0
                                                   cv->is_arg, idx,
30835
0
                                                   cv->var_name, cv->is_const,
30836
0
                                                   cv->is_lexical,
30837
0
                                                   cv->var_kind);
30838
0
                            if (idx < 0)
30839
0
                                return -1;
30840
0
                        }
30841
0
                        goto done;
30842
0
                    }
30843
0
                }
30844
0
            }
30845
            /* XXX: no line number info */
30846
0
            JS_ThrowSyntaxErrorAtom(ctx, "undefined private field '%s'",
30847
0
                                    var_name);
30848
0
            return -1;
30849
0
        } else {
30850
0
            fd = fd->parent;
30851
0
        }
30852
0
        is_ref = TRUE;
30853
0
    }
30854
0
 done:
30855
0
    *pis_ref = is_ref;
30856
0
    *pvar_kind = var_kind;
30857
0
    return idx;
30858
0
}
30859
30860
/* return 0 if OK or -1 if the private field could not be resolved */
30861
static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
30862
                                       JSAtom var_name, int scope_level, int op,
30863
                                       DynBuf *bc)
30864
0
{
30865
0
    int idx, var_kind;
30866
0
    BOOL is_ref;
30867
30868
0
    idx = resolve_scope_private_field1(ctx, &is_ref, &var_kind, s,
30869
0
                                       var_name, scope_level);
30870
0
    if (idx < 0)
30871
0
        return -1;
30872
0
    assert(var_kind != JS_VAR_NORMAL);
30873
0
    switch (op) {
30874
0
    case OP_scope_get_private_field:
30875
0
    case OP_scope_get_private_field2:
30876
0
        switch(var_kind) {
30877
0
        case JS_VAR_PRIVATE_FIELD:
30878
0
            if (op == OP_scope_get_private_field2)
30879
0
                dbuf_putc(bc, OP_dup);
30880
0
            get_loc_or_ref(bc, is_ref, idx);
30881
0
            dbuf_putc(bc, OP_get_private_field);
30882
0
            break;
30883
0
        case JS_VAR_PRIVATE_METHOD:
30884
0
            get_loc_or_ref(bc, is_ref, idx);
30885
0
            dbuf_putc(bc, OP_check_brand);
30886
0
            if (op != OP_scope_get_private_field2)
30887
0
                dbuf_putc(bc, OP_nip);
30888
0
            break;
30889
0
        case JS_VAR_PRIVATE_GETTER:
30890
0
        case JS_VAR_PRIVATE_GETTER_SETTER:
30891
0
            if (op == OP_scope_get_private_field2)
30892
0
                dbuf_putc(bc, OP_dup);
30893
0
            get_loc_or_ref(bc, is_ref, idx);
30894
0
            dbuf_putc(bc, OP_check_brand);
30895
0
            dbuf_putc(bc, OP_call_method);
30896
0
            dbuf_put_u16(bc, 0);
30897
0
            break;
30898
0
        case JS_VAR_PRIVATE_SETTER:
30899
            /* XXX: add clearer error message */
30900
0
            dbuf_putc(bc, OP_throw_error);
30901
0
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30902
0
            dbuf_putc(bc, JS_THROW_VAR_RO);
30903
0
            break;
30904
0
        default:
30905
0
            abort();
30906
0
        }
30907
0
        break;
30908
0
    case OP_scope_put_private_field:
30909
0
        switch(var_kind) {
30910
0
        case JS_VAR_PRIVATE_FIELD:
30911
0
            get_loc_or_ref(bc, is_ref, idx);
30912
0
            dbuf_putc(bc, OP_put_private_field);
30913
0
            break;
30914
0
        case JS_VAR_PRIVATE_METHOD:
30915
0
        case JS_VAR_PRIVATE_GETTER:
30916
            /* XXX: add clearer error message */
30917
0
            dbuf_putc(bc, OP_throw_error);
30918
0
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30919
0
            dbuf_putc(bc, JS_THROW_VAR_RO);
30920
0
            break;
30921
0
        case JS_VAR_PRIVATE_SETTER:
30922
0
        case JS_VAR_PRIVATE_GETTER_SETTER:
30923
0
            {
30924
0
                JSAtom setter_name = get_private_setter_name(ctx, var_name);
30925
0
                if (setter_name == JS_ATOM_NULL)
30926
0
                    return -1;
30927
0
                idx = resolve_scope_private_field1(ctx, &is_ref,
30928
0
                                                   &var_kind, s,
30929
0
                                                   setter_name, scope_level);
30930
0
                JS_FreeAtom(ctx, setter_name);
30931
0
                if (idx < 0)
30932
0
                    return -1;
30933
0
                assert(var_kind == JS_VAR_PRIVATE_SETTER);
30934
0
                get_loc_or_ref(bc, is_ref, idx);
30935
0
                dbuf_putc(bc, OP_swap);
30936
                /* obj func value */
30937
0
                dbuf_putc(bc, OP_rot3r);
30938
                /* value obj func */
30939
0
                dbuf_putc(bc, OP_check_brand);
30940
0
                dbuf_putc(bc, OP_rot3l);
30941
                /* obj func value */
30942
0
                dbuf_putc(bc, OP_call_method);
30943
0
                dbuf_put_u16(bc, 1);
30944
0
                dbuf_putc(bc, OP_drop);
30945
0
            }
30946
0
            break;
30947
0
        default:
30948
0
            abort();
30949
0
        }
30950
0
        break;
30951
0
    case OP_scope_in_private_field:
30952
0
        get_loc_or_ref(bc, is_ref, idx);
30953
0
        dbuf_putc(bc, OP_private_in);
30954
0
        break;
30955
0
    default:
30956
0
        abort();
30957
0
    }
30958
0
    return 0;
30959
0
}
30960
30961
static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,
30962
                                         int scope_level)
30963
0
{
30964
0
    int idx;
30965
0
    JSVarDef *vd;
30966
30967
0
    for (idx = s->scopes[scope_level].first; idx >= 0;) {
30968
0
        vd = &s->vars[idx];
30969
0
        vd->is_captured = 1;
30970
0
        idx = vd->scope_next;
30971
0
    }
30972
0
}
30973
30974
/* XXX: should handle the argument scope generically */
30975
static BOOL is_var_in_arg_scope(const JSVarDef *vd)
30976
0
{
30977
0
    return (vd->var_name == JS_ATOM_home_object ||
30978
0
            vd->var_name == JS_ATOM_this_active_func ||
30979
0
            vd->var_name == JS_ATOM_new_target ||
30980
0
            vd->var_name == JS_ATOM_this ||
30981
0
            vd->var_name == JS_ATOM__arg_var_ ||
30982
0
            vd->var_kind == JS_VAR_FUNCTION_NAME);
30983
0
}
30984
30985
static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
30986
0
{
30987
0
    JSFunctionDef *fd;
30988
0
    JSVarDef *vd;
30989
0
    int i, scope_level, scope_idx;
30990
0
    BOOL has_arguments_binding, has_this_binding, is_arg_scope;
30991
30992
    /* in non strict mode, variables are created in the caller's
30993
       environment object */
30994
0
    if (!s->is_eval && !(s->js_mode & JS_MODE_STRICT)) {
30995
0
        s->var_object_idx = add_var(ctx, s, JS_ATOM__var_);
30996
0
        if (s->has_parameter_expressions) {
30997
            /* an additional variable object is needed for the
30998
               argument scope */
30999
0
            s->arg_var_object_idx = add_var(ctx, s, JS_ATOM__arg_var_);
31000
0
        }
31001
0
    }
31002
31003
    /* eval can potentially use 'arguments' so we must define it */
31004
0
    has_this_binding = s->has_this_binding;
31005
0
    if (has_this_binding) {
31006
0
        if (s->this_var_idx < 0)
31007
0
            s->this_var_idx = add_var_this(ctx, s);
31008
0
        if (s->new_target_var_idx < 0)
31009
0
            s->new_target_var_idx = add_var(ctx, s, JS_ATOM_new_target);
31010
0
        if (s->is_derived_class_constructor && s->this_active_func_var_idx < 0)
31011
0
            s->this_active_func_var_idx = add_var(ctx, s, JS_ATOM_this_active_func);
31012
0
        if (s->has_home_object && s->home_object_var_idx < 0)
31013
0
            s->home_object_var_idx = add_var(ctx, s, JS_ATOM_home_object);
31014
0
    }
31015
0
    has_arguments_binding = s->has_arguments_binding;
31016
0
    if (has_arguments_binding) {
31017
0
        add_arguments_var(ctx, s);
31018
        /* also add an arguments binding in the argument scope to
31019
           raise an error if a direct eval in the argument scope tries
31020
           to redefine it */
31021
0
        if (s->has_parameter_expressions && !(s->js_mode & JS_MODE_STRICT))
31022
0
            add_arguments_arg(ctx, s);
31023
0
    }
31024
0
    if (s->is_func_expr && s->func_name != JS_ATOM_NULL)
31025
0
        add_func_var(ctx, s, s->func_name);
31026
31027
    /* eval can use all the variables of the enclosing functions, so
31028
       they must be all put in the closure. The closure variables are
31029
       ordered by scope. It works only because no closure are created
31030
       before. */
31031
0
    assert(s->is_eval || s->closure_var_count == 0);
31032
31033
    /* XXX: inefficient, but eval performance is less critical */
31034
0
    fd = s;
31035
0
    for(;;) {
31036
0
        scope_level = fd->parent_scope_level;
31037
0
        fd = fd->parent;
31038
0
        if (!fd)
31039
0
            break;
31040
        /* add 'this' if it was not previously added */
31041
0
        if (!has_this_binding && fd->has_this_binding) {
31042
0
            if (fd->this_var_idx < 0)
31043
0
                fd->this_var_idx = add_var_this(ctx, fd);
31044
0
            if (fd->new_target_var_idx < 0)
31045
0
                fd->new_target_var_idx = add_var(ctx, fd, JS_ATOM_new_target);
31046
0
            if (fd->is_derived_class_constructor && fd->this_active_func_var_idx < 0)
31047
0
                fd->this_active_func_var_idx = add_var(ctx, fd, JS_ATOM_this_active_func);
31048
0
            if (fd->has_home_object && fd->home_object_var_idx < 0)
31049
0
                fd->home_object_var_idx = add_var(ctx, fd, JS_ATOM_home_object);
31050
0
            has_this_binding = TRUE;
31051
0
        }
31052
        /* add 'arguments' if it was not previously added */
31053
0
        if (!has_arguments_binding && fd->has_arguments_binding) {
31054
0
            add_arguments_var(ctx, fd);
31055
0
            has_arguments_binding = TRUE;
31056
0
        }
31057
        /* add function name */
31058
0
        if (fd->is_func_expr && fd->func_name != JS_ATOM_NULL)
31059
0
            add_func_var(ctx, fd, fd->func_name);
31060
31061
        /* add lexical variables */
31062
0
        scope_idx = fd->scopes[scope_level].first;
31063
0
        while (scope_idx >= 0) {
31064
0
            vd = &fd->vars[scope_idx];
31065
0
            vd->is_captured = 1;
31066
0
            get_closure_var(ctx, s, fd, FALSE, scope_idx,
31067
0
                            vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);
31068
0
            scope_idx = vd->scope_next;
31069
0
        }
31070
0
        is_arg_scope = (scope_idx == ARG_SCOPE_END);
31071
0
        if (!is_arg_scope) {
31072
            /* add unscoped variables */
31073
            /* XXX: propagate is_const and var_kind too ? */
31074
0
            for(i = 0; i < fd->arg_count; i++) {
31075
0
                vd = &fd->args[i];
31076
0
                if (vd->var_name != JS_ATOM_NULL) {
31077
0
                    get_closure_var(ctx, s, fd,
31078
0
                                    TRUE, i, vd->var_name, FALSE,
31079
0
                                    vd->is_lexical, JS_VAR_NORMAL);
31080
0
                }
31081
0
            }
31082
0
            for(i = 0; i < fd->var_count; i++) {
31083
0
                vd = &fd->vars[i];
31084
                /* do not close top level last result */
31085
0
                if (vd->scope_level == 0 &&
31086
0
                    vd->var_name != JS_ATOM__ret_ &&
31087
0
                    vd->var_name != JS_ATOM_NULL) {
31088
0
                    get_closure_var(ctx, s, fd,
31089
0
                                    FALSE, i, vd->var_name, FALSE,
31090
0
                                    vd->is_lexical, JS_VAR_NORMAL);
31091
0
                }
31092
0
            }
31093
0
        } else {
31094
0
            for(i = 0; i < fd->var_count; i++) {
31095
0
                vd = &fd->vars[i];
31096
                /* do not close top level last result */
31097
0
                if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
31098
0
                    get_closure_var(ctx, s, fd,
31099
0
                                    FALSE, i, vd->var_name, FALSE,
31100
0
                                    vd->is_lexical, JS_VAR_NORMAL);
31101
0
                }
31102
0
            }
31103
0
        }
31104
0
        if (fd->is_eval) {
31105
0
            int idx;
31106
            /* add direct eval variables (we are necessarily at the
31107
               top level) */
31108
0
            for (idx = 0; idx < fd->closure_var_count; idx++) {
31109
0
                JSClosureVar *cv = &fd->closure_var[idx];
31110
0
                get_closure_var2(ctx, s, fd,
31111
0
                                 FALSE, cv->is_arg,
31112
0
                                 idx, cv->var_name, cv->is_const,
31113
0
                                 cv->is_lexical, cv->var_kind);
31114
0
            }
31115
0
        }
31116
0
    }
31117
0
}
31118
31119
static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
31120
                                 JSVarDef *vd, int var_idx)
31121
0
{
31122
0
    cv->is_local = TRUE;
31123
0
    cv->is_arg = FALSE;
31124
0
    cv->is_const = vd->is_const;
31125
0
    cv->is_lexical = vd->is_lexical;
31126
0
    cv->var_kind = vd->var_kind;
31127
0
    cv->var_idx = var_idx;
31128
0
    cv->var_name = JS_DupAtom(ctx, vd->var_name);
31129
0
}
31130
31131
/* for direct eval compilation: add references to the variables of the
31132
   calling function */
31133
static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
31134
                                             JSFunctionBytecode *b, int scope_idx)
31135
0
{
31136
0
    int i, count;
31137
0
    JSVarDef *vd;
31138
0
    BOOL is_arg_scope;
31139
31140
0
    count = b->arg_count + b->var_count + b->closure_var_count;
31141
0
    s->closure_var = NULL;
31142
0
    s->closure_var_count = 0;
31143
0
    s->closure_var_size = count;
31144
0
    if (count == 0)
31145
0
        return 0;
31146
0
    s->closure_var = js_malloc(ctx, sizeof(s->closure_var[0]) * count);
31147
0
    if (!s->closure_var)
31148
0
        return -1;
31149
    /* Add lexical variables in scope at the point of evaluation */
31150
0
    for (i = scope_idx; i >= 0;) {
31151
0
        vd = &b->vardefs[b->arg_count + i];
31152
0
        if (vd->scope_level > 0) {
31153
0
            JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
31154
0
            set_closure_from_var(ctx, cv, vd, i);
31155
0
        }
31156
0
        i = vd->scope_next;
31157
0
    }
31158
0
    is_arg_scope = (i == ARG_SCOPE_END);
31159
0
    if (!is_arg_scope) {
31160
        /* Add argument variables */
31161
0
        for(i = 0; i < b->arg_count; i++) {
31162
0
            JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
31163
0
            vd = &b->vardefs[i];
31164
0
            cv->is_local = TRUE;
31165
0
            cv->is_arg = TRUE;
31166
0
            cv->is_const = FALSE;
31167
0
            cv->is_lexical = FALSE;
31168
0
            cv->var_kind = JS_VAR_NORMAL;
31169
0
            cv->var_idx = i;
31170
0
            cv->var_name = JS_DupAtom(ctx, vd->var_name);
31171
0
        }
31172
        /* Add local non lexical variables */
31173
0
        for(i = 0; i < b->var_count; i++) {
31174
0
            vd = &b->vardefs[b->arg_count + i];
31175
0
            if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) {
31176
0
                JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
31177
0
                set_closure_from_var(ctx, cv, vd, i);
31178
0
            }
31179
0
        }
31180
0
    } else {
31181
        /* only add pseudo variables */
31182
0
        for(i = 0; i < b->var_count; i++) {
31183
0
            vd = &b->vardefs[b->arg_count + i];
31184
0
            if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
31185
0
                JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
31186
0
                set_closure_from_var(ctx, cv, vd, i);
31187
0
            }
31188
0
        }
31189
0
    }
31190
0
    for(i = 0; i < b->closure_var_count; i++) {
31191
0
        JSClosureVar *cv0 = &b->closure_var[i];
31192
0
        JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
31193
0
        cv->is_local = FALSE;
31194
0
        cv->is_arg = cv0->is_arg;
31195
0
        cv->is_const = cv0->is_const;
31196
0
        cv->is_lexical = cv0->is_lexical;
31197
0
        cv->var_kind = cv0->var_kind;
31198
0
        cv->var_idx = i;
31199
0
        cv->var_name = JS_DupAtom(ctx, cv0->var_name);
31200
0
    }
31201
0
    return 0;
31202
0
}
31203
31204
typedef struct CodeContext {
31205
    const uint8_t *bc_buf; /* code buffer */
31206
    int bc_len;   /* length of the code buffer */
31207
    int pos;      /* position past the matched code pattern */
31208
    int line_num; /* last visited OP_line_num parameter or -1 */
31209
    int op;
31210
    int idx;
31211
    int label;
31212
    int val;
31213
    JSAtom atom;
31214
} CodeContext;
31215
31216
3.54M
#define M2(op1, op2)            ((op1) | ((op2) << 8))
31217
0
#define M3(op1, op2, op3)       ((op1) | ((op2) << 8) | ((op3) << 16))
31218
0
#define M4(op1, op2, op3, op4)  ((op1) | ((op2) << 8) | ((op3) << 16) | ((op4) << 24))
31219
31220
static BOOL code_match(CodeContext *s, int pos, ...)
31221
7.47M
{
31222
7.47M
    const uint8_t *tab = s->bc_buf;
31223
7.47M
    int op, len, op1, line_num, pos_next;
31224
7.47M
    va_list ap;
31225
7.47M
    BOOL ret = FALSE;
31226
31227
7.47M
    line_num = -1;
31228
7.47M
    va_start(ap, pos);
31229
31230
7.47M
    for(;;) {
31231
7.47M
        op1 = va_arg(ap, int);
31232
7.47M
        if (op1 == -1) {
31233
103
            s->pos = pos;
31234
103
            s->line_num = line_num;
31235
103
            ret = TRUE;
31236
103
            break;
31237
103
        }
31238
7.47M
        for (;;) {
31239
7.47M
            if (pos >= s->bc_len)
31240
0
                goto done;
31241
7.47M
            op = tab[pos];
31242
7.47M
            len = opcode_info[op].size;
31243
7.47M
            pos_next = pos + len;
31244
7.47M
            if (pos_next > s->bc_len)
31245
0
                goto done;
31246
7.47M
            if (op == OP_line_num) {
31247
2
                line_num = get_u32(tab + pos + 1);
31248
2
                pos = pos_next;
31249
7.47M
            } else {
31250
7.47M
                break;
31251
7.47M
            }
31252
7.47M
        }
31253
7.47M
        if (op != op1) {
31254
7.47M
            if (op1 == (uint8_t)op1 || !op)
31255
3.93M
                break;
31256
3.54M
            if (op != (uint8_t)op1
31257
3.54M
            &&  op != (uint8_t)(op1 >> 8)
31258
3.54M
            &&  op != (uint8_t)(op1 >> 16)
31259
3.54M
            &&  op != (uint8_t)(op1 >> 24)) {
31260
3.54M
                break;
31261
3.54M
            }
31262
78
            s->op = op;
31263
78
        }
31264
31265
181
        pos++;
31266
181
        switch(opcode_info[op].fmt) {
31267
0
        case OP_FMT_loc8:
31268
0
        case OP_FMT_u8:
31269
0
            {
31270
0
                int idx = tab[pos];
31271
0
                int arg = va_arg(ap, int);
31272
0
                if (arg == -1) {
31273
0
                    s->idx = idx;
31274
0
                } else {
31275
0
                    if (arg != idx)
31276
0
                        goto done;
31277
0
                }
31278
0
                break;
31279
0
            }
31280
0
        case OP_FMT_u16:
31281
0
        case OP_FMT_npop:
31282
24
        case OP_FMT_loc:
31283
24
        case OP_FMT_arg:
31284
24
        case OP_FMT_var_ref:
31285
24
            {
31286
24
                int idx = get_u16(tab + pos);
31287
24
                int arg = va_arg(ap, int);
31288
24
                if (arg == -1) {
31289
0
                    s->idx = idx;
31290
24
                } else {
31291
24
                    if (arg != idx)
31292
0
                        goto done;
31293
24
                }
31294
24
                break;
31295
24
            }
31296
24
        case OP_FMT_i32:
31297
0
        case OP_FMT_u32:
31298
0
        case OP_FMT_label:
31299
0
        case OP_FMT_const:
31300
0
            {
31301
0
                s->label = get_u32(tab + pos);
31302
0
                break;
31303
0
            }
31304
0
        case OP_FMT_label_u16:
31305
0
            {
31306
0
                s->label = get_u32(tab + pos);
31307
0
                s->val = get_u16(tab + pos + 4);
31308
0
                break;
31309
0
            }
31310
78
        case OP_FMT_atom:
31311
78
            {
31312
78
                s->atom = get_u32(tab + pos);
31313
78
                break;
31314
0
            }
31315
0
        case OP_FMT_atom_u8:
31316
0
            {
31317
0
                s->atom = get_u32(tab + pos);
31318
0
                s->val = get_u8(tab + pos + 4);
31319
0
                break;
31320
0
            }
31321
0
        case OP_FMT_atom_u16:
31322
0
            {
31323
0
                s->atom = get_u32(tab + pos);
31324
0
                s->val = get_u16(tab + pos + 4);
31325
0
                break;
31326
0
            }
31327
0
        case OP_FMT_atom_label_u8:
31328
0
            {
31329
0
                s->atom = get_u32(tab + pos);
31330
0
                s->label = get_u32(tab + pos + 4);
31331
0
                s->val = get_u8(tab + pos + 8);
31332
0
                break;
31333
0
            }
31334
79
        default:
31335
79
            break;
31336
181
        }
31337
181
        pos = pos_next;
31338
181
    }
31339
7.47M
 done:
31340
7.47M
    va_end(ap);
31341
7.47M
    return ret;
31342
7.47M
}
31343
31344
static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, DynBuf *bc)
31345
63
{
31346
63
    int i, idx, label_next = -1;
31347
31348
    /* add the hoisted functions in arguments and local variables */
31349
63
    for(i = 0; i < s->arg_count; i++) {
31350
0
        JSVarDef *vd = &s->args[i];
31351
0
        if (vd->func_pool_idx >= 0) {
31352
0
            dbuf_putc(bc, OP_fclosure);
31353
0
            dbuf_put_u32(bc, vd->func_pool_idx);
31354
0
            dbuf_putc(bc, OP_put_arg);
31355
0
            dbuf_put_u16(bc, i);
31356
0
        }
31357
0
    }
31358
87
    for(i = 0; i < s->var_count; i++) {
31359
24
        JSVarDef *vd = &s->vars[i];
31360
24
        if (vd->scope_level == 0 && vd->func_pool_idx >= 0) {
31361
0
            dbuf_putc(bc, OP_fclosure);
31362
0
            dbuf_put_u32(bc, vd->func_pool_idx);
31363
0
            dbuf_putc(bc, OP_put_loc);
31364
0
            dbuf_put_u16(bc, i);
31365
0
        }
31366
24
    }
31367
31368
    /* the module global variables must be initialized before
31369
       evaluating the module so that the exported functions are
31370
       visible if there are cyclic module references */
31371
63
    if (s->module) {
31372
39
        label_next = new_label_fd(s, -1);
31373
31374
        /* if 'this' is true, initialize the global variables and return */
31375
39
        dbuf_putc(bc, OP_push_this);
31376
39
        dbuf_putc(bc, OP_if_false);
31377
39
        dbuf_put_u32(bc, label_next);
31378
39
        update_label(s, label_next, 1);
31379
39
        s->jump_size++;
31380
39
    }
31381
31382
    /* add the global variables (only happens if s->is_global_var is
31383
       true) */
31384
63
    for(i = 0; i < s->global_var_count; i++) {
31385
0
        JSGlobalVar *hf = &s->global_vars[i];
31386
0
        int has_closure = 0;
31387
0
        BOOL force_init = hf->force_init;
31388
        /* we are in an eval, so the closure contains all the
31389
           enclosing variables */
31390
        /* If the outer function has a variable environment,
31391
           create a property for the variable there */
31392
0
        for(idx = 0; idx < s->closure_var_count; idx++) {
31393
0
            JSClosureVar *cv = &s->closure_var[idx];
31394
0
            if (cv->var_name == hf->var_name) {
31395
0
                has_closure = 2;
31396
0
                force_init = FALSE;
31397
0
                break;
31398
0
            }
31399
0
            if (cv->var_name == JS_ATOM__var_ ||
31400
0
                cv->var_name == JS_ATOM__arg_var_) {
31401
0
                dbuf_putc(bc, OP_get_var_ref);
31402
0
                dbuf_put_u16(bc, idx);
31403
0
                has_closure = 1;
31404
0
                force_init = TRUE;
31405
0
                break;
31406
0
            }
31407
0
        }
31408
0
        if (!has_closure) {
31409
0
            int flags;
31410
31411
0
            flags = 0;
31412
0
            if (s->eval_type != JS_EVAL_TYPE_GLOBAL)
31413
0
                flags |= JS_PROP_CONFIGURABLE;
31414
0
            if (hf->cpool_idx >= 0 && !hf->is_lexical) {
31415
                /* global function definitions need a specific handling */
31416
0
                dbuf_putc(bc, OP_fclosure);
31417
0
                dbuf_put_u32(bc, hf->cpool_idx);
31418
31419
0
                dbuf_putc(bc, OP_define_func);
31420
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
31421
0
                dbuf_putc(bc, flags);
31422
31423
0
                goto done_global_var;
31424
0
            } else {
31425
0
                if (hf->is_lexical) {
31426
0
                    flags |= DEFINE_GLOBAL_LEX_VAR;
31427
0
                    if (!hf->is_const)
31428
0
                        flags |= JS_PROP_WRITABLE;
31429
0
                }
31430
0
                dbuf_putc(bc, OP_define_var);
31431
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
31432
0
                dbuf_putc(bc, flags);
31433
0
            }
31434
0
        }
31435
0
        if (hf->cpool_idx >= 0 || force_init) {
31436
0
            if (hf->cpool_idx >= 0) {
31437
0
                dbuf_putc(bc, OP_fclosure);
31438
0
                dbuf_put_u32(bc, hf->cpool_idx);
31439
0
                if (hf->var_name == JS_ATOM__default_) {
31440
                    /* set default export function name */
31441
0
                    dbuf_putc(bc, OP_set_name);
31442
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, JS_ATOM_default));
31443
0
                }
31444
0
            } else {
31445
0
                dbuf_putc(bc, OP_undefined);
31446
0
            }
31447
0
            if (has_closure == 2) {
31448
0
                dbuf_putc(bc, OP_put_var_ref);
31449
0
                dbuf_put_u16(bc, idx);
31450
0
            } else if (has_closure == 1) {
31451
0
                dbuf_putc(bc, OP_define_field);
31452
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
31453
0
                dbuf_putc(bc, OP_drop);
31454
0
            } else {
31455
                /* XXX: Check if variable is writable and enumerable */
31456
0
                dbuf_putc(bc, OP_put_var);
31457
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
31458
0
            }
31459
0
        }
31460
0
    done_global_var:
31461
0
        JS_FreeAtom(ctx, hf->var_name);
31462
0
    }
31463
31464
63
    if (s->module) {
31465
39
        dbuf_putc(bc, OP_return_undef);
31466
31467
39
        dbuf_putc(bc, OP_label);
31468
39
        dbuf_put_u32(bc, label_next);
31469
39
        s->label_slots[label_next].pos2 = bc->size;
31470
39
    }
31471
31472
63
    js_free(ctx, s->global_vars);
31473
63
    s->global_vars = NULL;
31474
63
    s->global_var_count = 0;
31475
63
    s->global_var_size = 0;
31476
63
}
31477
31478
static int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len,
31479
                          int pos, int *linep)
31480
126
{
31481
126
    int op, len, label;
31482
31483
126
    for (; pos < bc_len; pos += len) {
31484
39
        op = bc_buf[pos];
31485
39
        len = opcode_info[op].size;
31486
39
        if (op == OP_line_num) {
31487
0
            *linep = get_u32(bc_buf + pos + 1);
31488
0
        } else
31489
39
        if (op == OP_label) {
31490
39
            label = get_u32(bc_buf + pos + 1);
31491
39
            if (update_label(s, label, 0) > 0)
31492
39
                break;
31493
#if 0
31494
            if (s->label_slots[label].first_reloc) {
31495
                printf("line %d: unreferenced label %d:%d has relocations\n",
31496
                       *linep, label, s->label_slots[label].pos2);
31497
            }
31498
#endif
31499
0
            assert(s->label_slots[label].first_reloc == NULL);
31500
0
        } else {
31501
            /* XXX: output a warning for unreachable code? */
31502
0
            JSAtom atom;
31503
0
            switch(opcode_info[op].fmt) {
31504
0
            case OP_FMT_label:
31505
0
            case OP_FMT_label_u16:
31506
0
                label = get_u32(bc_buf + pos + 1);
31507
0
                update_label(s, label, -1);
31508
0
                break;
31509
0
            case OP_FMT_atom_label_u8:
31510
0
            case OP_FMT_atom_label_u16:
31511
0
                label = get_u32(bc_buf + pos + 5);
31512
0
                update_label(s, label, -1);
31513
                /* fall thru */
31514
0
            case OP_FMT_atom:
31515
0
            case OP_FMT_atom_u8:
31516
0
            case OP_FMT_atom_u16:
31517
0
                atom = get_u32(bc_buf + pos + 1);
31518
0
                JS_FreeAtom(s->ctx, atom);
31519
0
                break;
31520
0
            default:
31521
0
                break;
31522
0
            }
31523
0
        }
31524
39
    }
31525
126
    return pos;
31526
126
}
31527
31528
static int get_label_pos(JSFunctionDef *s, int label)
31529
0
{
31530
0
    int i, pos;
31531
0
    for (i = 0; i < 20; i++) {
31532
0
        pos = s->label_slots[label].pos;
31533
0
        for (;;) {
31534
0
            switch (s->byte_code.buf[pos]) {
31535
0
            case OP_line_num:
31536
0
            case OP_label:
31537
0
                pos += 5;
31538
0
                continue;
31539
0
            case OP_goto:
31540
0
                label = get_u32(s->byte_code.buf + pos + 1);
31541
0
                break;
31542
0
            default:
31543
0
                return pos;
31544
0
            }
31545
0
            break;
31546
0
        }
31547
0
    }
31548
0
    return pos;
31549
0
}
31550
31551
/* convert global variable accesses to local variables or closure
31552
   variables when necessary */
31553
static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
31554
63
{
31555
63
    int pos, pos_next, bc_len, op, len, i, idx, line_num;
31556
63
    uint8_t *bc_buf;
31557
63
    JSAtom var_name;
31558
63
    DynBuf bc_out;
31559
63
    CodeContext cc;
31560
63
    int scope;
31561
31562
63
    cc.bc_buf = bc_buf = s->byte_code.buf;
31563
63
    cc.bc_len = bc_len = s->byte_code.size;
31564
63
    js_dbuf_init(ctx, &bc_out);
31565
31566
    /* first pass for runtime checks (must be done before the
31567
       variables are created) */
31568
63
    for(i = 0; i < s->global_var_count; i++) {
31569
0
        JSGlobalVar *hf = &s->global_vars[i];
31570
0
        int flags;
31571
31572
        /* check if global variable (XXX: simplify) */
31573
0
        for(idx = 0; idx < s->closure_var_count; idx++) {
31574
0
            JSClosureVar *cv = &s->closure_var[idx];
31575
0
            if (cv->var_name == hf->var_name) {
31576
0
                if (s->eval_type == JS_EVAL_TYPE_DIRECT &&
31577
0
                    cv->is_lexical) {
31578
                    /* Check if a lexical variable is
31579
                       redefined as 'var'. XXX: Could abort
31580
                       compilation here, but for consistency
31581
                       with the other checks, we delay the
31582
                       error generation. */
31583
0
                    dbuf_putc(&bc_out, OP_throw_error);
31584
0
                    dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
31585
0
                    dbuf_putc(&bc_out, JS_THROW_VAR_REDECL);
31586
0
                }
31587
0
                goto next;
31588
0
            }
31589
0
            if (cv->var_name == JS_ATOM__var_ ||
31590
0
                cv->var_name == JS_ATOM__arg_var_)
31591
0
                goto next;
31592
0
        }
31593
31594
0
        dbuf_putc(&bc_out, OP_check_define_var);
31595
0
        dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
31596
0
        flags = 0;
31597
0
        if (hf->is_lexical)
31598
0
            flags |= DEFINE_GLOBAL_LEX_VAR;
31599
0
        if (hf->cpool_idx >= 0)
31600
0
            flags |= DEFINE_GLOBAL_FUNC_VAR;
31601
0
        dbuf_putc(&bc_out, flags);
31602
0
    next: ;
31603
0
    }
31604
31605
63
    line_num = 0; /* avoid warning */
31606
7.08M
    for (pos = 0; pos < bc_len; pos = pos_next) {
31607
7.08M
        op = bc_buf[pos];
31608
7.08M
        len = opcode_info[op].size;
31609
7.08M
        pos_next = pos + len;
31610
7.08M
        switch(op) {
31611
168
        case OP_line_num:
31612
168
            line_num = get_u32(bc_buf + pos + 1);
31613
168
            s->line_number_size++;
31614
168
            goto no_change;
31615
31616
0
        case OP_eval: /* convert scope index to adjusted variable index */
31617
0
            {
31618
0
                int call_argc = get_u16(bc_buf + pos + 1);
31619
0
                scope = get_u16(bc_buf + pos + 1 + 2);
31620
0
                mark_eval_captured_variables(ctx, s, scope);
31621
0
                dbuf_putc(&bc_out, op);
31622
0
                dbuf_put_u16(&bc_out, call_argc);
31623
0
                dbuf_put_u16(&bc_out, s->scopes[scope].first + 1);
31624
0
            }
31625
0
            break;
31626
0
        case OP_apply_eval: /* convert scope index to adjusted variable index */
31627
0
            scope = get_u16(bc_buf + pos + 1);
31628
0
            mark_eval_captured_variables(ctx, s, scope);
31629
0
            dbuf_putc(&bc_out, op);
31630
0
            dbuf_put_u16(&bc_out, s->scopes[scope].first + 1);
31631
0
            break;
31632
0
        case OP_scope_get_var_checkthis:
31633
0
        case OP_scope_get_var_undef:
31634
167
        case OP_scope_get_var:
31635
167
        case OP_scope_put_var:
31636
167
        case OP_scope_delete_var:
31637
167
        case OP_scope_get_ref:
31638
167
        case OP_scope_put_var_init:
31639
167
            var_name = get_u32(bc_buf + pos + 1);
31640
167
            scope = get_u16(bc_buf + pos + 5);
31641
167
            pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
31642
167
                                         NULL, NULL, pos_next);
31643
167
            JS_FreeAtom(ctx, var_name);
31644
167
            break;
31645
0
        case OP_scope_make_ref:
31646
0
            {
31647
0
                int label;
31648
0
                LabelSlot *ls;
31649
0
                var_name = get_u32(bc_buf + pos + 1);
31650
0
                label = get_u32(bc_buf + pos + 5);
31651
0
                scope = get_u16(bc_buf + pos + 9);
31652
0
                ls = &s->label_slots[label];
31653
0
                ls->ref_count--;  /* always remove label reference */
31654
0
                pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
31655
0
                                             bc_buf, ls, pos_next);
31656
0
                JS_FreeAtom(ctx, var_name);
31657
0
            }
31658
0
            break;
31659
0
        case OP_scope_get_private_field:
31660
0
        case OP_scope_get_private_field2:
31661
0
        case OP_scope_put_private_field:
31662
0
        case OP_scope_in_private_field:
31663
0
            {
31664
0
                int ret;
31665
0
                var_name = get_u32(bc_buf + pos + 1);
31666
0
                scope = get_u16(bc_buf + pos + 5);
31667
0
                ret = resolve_scope_private_field(ctx, s, var_name, scope, op, &bc_out);
31668
0
                if (ret < 0)
31669
0
                    goto fail;
31670
0
                JS_FreeAtom(ctx, var_name);
31671
0
            }
31672
0
            break;
31673
0
        case OP_gosub:
31674
0
            s->jump_size++;
31675
0
            if (OPTIMIZE) {
31676
                /* remove calls to empty finalizers  */
31677
0
                int label;
31678
0
                LabelSlot *ls;
31679
31680
0
                label = get_u32(bc_buf + pos + 1);
31681
0
                assert(label >= 0 && label < s->label_count);
31682
0
                ls = &s->label_slots[label];
31683
0
                if (code_match(&cc, ls->pos, OP_ret, -1)) {
31684
0
                    ls->ref_count--;
31685
0
                    break;
31686
0
                }
31687
0
            }
31688
0
            goto no_change;
31689
78
        case OP_drop:
31690
78
            if (0) {
31691
                /* remove drops before return_undef */
31692
                /* do not perform this optimization in pass2 because
31693
                   it breaks patterns recognised in resolve_labels */
31694
0
                int pos1 = pos_next;
31695
0
                int line1 = line_num;
31696
0
                while (code_match(&cc, pos1, OP_drop, -1)) {
31697
0
                    if (cc.line_num >= 0) line1 = cc.line_num;
31698
0
                    pos1 = cc.pos;
31699
0
                }
31700
0
                if (code_match(&cc, pos1, OP_return_undef, -1)) {
31701
0
                    pos_next = pos1;
31702
0
                    if (line1 != -1 && line1 != line_num) {
31703
0
                        line_num = line1;
31704
0
                        s->line_number_size++;
31705
0
                        dbuf_putc(&bc_out, OP_line_num);
31706
0
                        dbuf_put_u32(&bc_out, line_num);
31707
0
                    }
31708
0
                    break;
31709
0
                }
31710
0
            }
31711
78
            goto no_change;
31712
78
        case OP_insert3:
31713
0
            if (OPTIMIZE) {
31714
                /* Transformation: insert3 put_array_el|put_ref_value drop -> put_array_el|put_ref_value */
31715
0
                if (code_match(&cc, pos_next, M2(OP_put_array_el, OP_put_ref_value), OP_drop, -1)) {
31716
0
                    dbuf_putc(&bc_out, cc.op);
31717
0
                    pos_next = cc.pos;
31718
0
                    if (cc.line_num != -1 && cc.line_num != line_num) {
31719
0
                        line_num = cc.line_num;
31720
0
                        s->line_number_size++;
31721
0
                        dbuf_putc(&bc_out, OP_line_num);
31722
0
                        dbuf_put_u32(&bc_out, line_num);
31723
0
                    }
31724
0
                    break;
31725
0
                }
31726
0
            }
31727
0
            goto no_change;
31728
31729
0
        case OP_goto:
31730
0
            s->jump_size++;
31731
            /* fall thru */
31732
0
        case OP_tail_call:
31733
0
        case OP_tail_call_method:
31734
24
        case OP_return:
31735
24
        case OP_return_undef:
31736
24
        case OP_throw:
31737
24
        case OP_throw_error:
31738
24
        case OP_ret:
31739
24
            if (OPTIMIZE) {
31740
                /* remove dead code */
31741
24
                int line = -1;
31742
24
                dbuf_put(&bc_out, bc_buf + pos, len);
31743
24
                pos = skip_dead_code(s, bc_buf, bc_len, pos + len, &line);
31744
24
                pos_next = pos;
31745
24
                if (pos < bc_len && line >= 0 && line_num != line) {
31746
0
                    line_num = line;
31747
0
                    s->line_number_size++;
31748
0
                    dbuf_putc(&bc_out, OP_line_num);
31749
0
                    dbuf_put_u32(&bc_out, line_num);
31750
0
                }
31751
24
                break;
31752
24
            }
31753
0
            goto no_change;
31754
31755
0
        case OP_label:
31756
0
            {
31757
0
                int label;
31758
0
                LabelSlot *ls;
31759
31760
0
                label = get_u32(bc_buf + pos + 1);
31761
0
                assert(label >= 0 && label < s->label_count);
31762
0
                ls = &s->label_slots[label];
31763
0
                ls->pos2 = bc_out.size + opcode_info[op].size;
31764
0
            }
31765
0
            goto no_change;
31766
31767
63
        case OP_enter_scope:
31768
63
            {
31769
63
                int scope_idx, scope = get_u16(bc_buf + pos + 1);
31770
31771
63
                if (scope == s->body_scope) {
31772
63
                    instantiate_hoisted_definitions(ctx, s, &bc_out);
31773
63
                }
31774
31775
63
                for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
31776
0
                    JSVarDef *vd = &s->vars[scope_idx];
31777
0
                    if (vd->scope_level == scope) {
31778
0
                        if (scope_idx != s->arguments_arg_idx) {
31779
0
                            if (vd->var_kind == JS_VAR_FUNCTION_DECL ||
31780
0
                                vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) {
31781
                                /* Initialize lexical variable upon entering scope */
31782
0
                                dbuf_putc(&bc_out, OP_fclosure);
31783
0
                                dbuf_put_u32(&bc_out, vd->func_pool_idx);
31784
0
                                dbuf_putc(&bc_out, OP_put_loc);
31785
0
                                dbuf_put_u16(&bc_out, scope_idx);
31786
0
                            } else {
31787
                                /* XXX: should check if variable can be used
31788
                                   before initialization */
31789
0
                                dbuf_putc(&bc_out, OP_set_loc_uninitialized);
31790
0
                                dbuf_put_u16(&bc_out, scope_idx);
31791
0
                            }
31792
0
                        }
31793
0
                        scope_idx = vd->scope_next;
31794
0
                    } else {
31795
0
                        break;
31796
0
                    }
31797
0
                }
31798
63
            }
31799
63
            break;
31800
31801
0
        case OP_leave_scope:
31802
0
            {
31803
0
                int scope_idx, scope = get_u16(bc_buf + pos + 1);
31804
31805
0
                for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
31806
0
                    JSVarDef *vd = &s->vars[scope_idx];
31807
0
                    if (vd->scope_level == scope) {
31808
0
                        if (vd->is_captured) {
31809
0
                            dbuf_putc(&bc_out, OP_close_loc);
31810
0
                            dbuf_put_u16(&bc_out, scope_idx);
31811
0
                        }
31812
0
                        scope_idx = vd->scope_next;
31813
0
                    } else {
31814
0
                        break;
31815
0
                    }
31816
0
                }
31817
0
            }
31818
0
            break;
31819
31820
0
        case OP_set_name:
31821
0
            {
31822
                /* remove dummy set_name opcodes */
31823
0
                JSAtom name = get_u32(bc_buf + pos + 1);
31824
0
                if (name == JS_ATOM_NULL)
31825
0
                    break;
31826
0
            }
31827
0
            goto no_change;
31828
31829
0
        case OP_if_false:
31830
0
        case OP_if_true:
31831
0
        case OP_catch:
31832
0
            s->jump_size++;
31833
0
            goto no_change;
31834
31835
0
        case OP_dup:
31836
0
            if (OPTIMIZE) {
31837
                /* Transformation: dup if_false(l1) drop, l1: if_false(l2) -> if_false(l2) */
31838
                /* Transformation: dup if_true(l1) drop, l1: if_true(l2) -> if_true(l2) */
31839
0
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), OP_drop, -1)) {
31840
0
                    int lab0, lab1, op1, pos1, line1, pos2;
31841
0
                    lab0 = lab1 = cc.label;
31842
0
                    assert(lab1 >= 0 && lab1 < s->label_count);
31843
0
                    op1 = cc.op;
31844
0
                    pos1 = cc.pos;
31845
0
                    line1 = cc.line_num;
31846
0
                    while (code_match(&cc, (pos2 = get_label_pos(s, lab1)), OP_dup, op1, OP_drop, -1)) {
31847
0
                        lab1 = cc.label;
31848
0
                    }
31849
0
                    if (code_match(&cc, pos2, op1, -1)) {
31850
0
                        s->jump_size++;
31851
0
                        update_label(s, lab0, -1);
31852
0
                        update_label(s, cc.label, +1);
31853
0
                        dbuf_putc(&bc_out, op1);
31854
0
                        dbuf_put_u32(&bc_out, cc.label);
31855
0
                        pos_next = pos1;
31856
0
                        if (line1 != -1 && line1 != line_num) {
31857
0
                            line_num = line1;
31858
0
                            s->line_number_size++;
31859
0
                            dbuf_putc(&bc_out, OP_line_num);
31860
0
                            dbuf_put_u32(&bc_out, line_num);
31861
0
                        }
31862
0
                        break;
31863
0
                    }
31864
0
                }
31865
0
            }
31866
0
            goto no_change;
31867
31868
0
        case OP_nop:
31869
            /* remove erased code */
31870
0
            break;
31871
0
        case OP_set_class_name:
31872
            /* only used during parsing */
31873
0
            break;
31874
31875
0
        case OP_get_field_opt_chain: /* equivalent to OP_get_field */
31876
0
            {
31877
0
                JSAtom name = get_u32(bc_buf + pos + 1);
31878
0
                dbuf_putc(&bc_out, OP_get_field);
31879
0
                dbuf_put_u32(&bc_out, name);
31880
0
            }
31881
0
            break;
31882
0
        case OP_get_array_el_opt_chain: /* equivalent to OP_get_array_el */
31883
0
            dbuf_putc(&bc_out, OP_get_array_el);
31884
0
            break;
31885
31886
7.08M
        default:
31887
7.08M
        no_change:
31888
7.08M
            dbuf_put(&bc_out, bc_buf + pos, len);
31889
7.08M
            break;
31890
7.08M
        }
31891
7.08M
    }
31892
31893
    /* set the new byte code */
31894
63
    dbuf_free(&s->byte_code);
31895
63
    s->byte_code = bc_out;
31896
63
    if (dbuf_error(&s->byte_code)) {
31897
0
        JS_ThrowOutOfMemory(ctx);
31898
0
        return -1;
31899
0
    }
31900
63
    return 0;
31901
0
 fail:
31902
    /* continue the copy to keep the atom refcounts consistent */
31903
    /* XXX: find a better solution ? */
31904
0
    for (; pos < bc_len; pos = pos_next) {
31905
0
        op = bc_buf[pos];
31906
0
        len = opcode_info[op].size;
31907
0
        pos_next = pos + len;
31908
0
        dbuf_put(&bc_out, bc_buf + pos, len);
31909
0
    }
31910
0
    dbuf_free(&s->byte_code);
31911
0
    s->byte_code = bc_out;
31912
0
    return -1;
31913
63
}
31914
31915
/* the pc2line table gives a line number for each PC value */
31916
static void add_pc2line_info(JSFunctionDef *s, uint32_t pc, int line_num)
31917
7.08M
{
31918
7.08M
    if (s->line_number_slots != NULL
31919
7.08M
    &&  s->line_number_count < s->line_number_size
31920
7.08M
    &&  pc >= s->line_number_last_pc
31921
7.08M
    &&  line_num != s->line_number_last) {
31922
125
        s->line_number_slots[s->line_number_count].pc = pc;
31923
125
        s->line_number_slots[s->line_number_count].line_num = line_num;
31924
125
        s->line_number_count++;
31925
125
        s->line_number_last_pc = pc;
31926
125
        s->line_number_last = line_num;
31927
125
    }
31928
7.08M
}
31929
31930
static void compute_pc2line_info(JSFunctionDef *s)
31931
63
{
31932
63
    if (!(s->js_mode & JS_MODE_STRIP) && s->line_number_slots) {
31933
63
        int last_line_num = s->line_num;
31934
63
        uint32_t last_pc = 0;
31935
63
        int i;
31936
31937
63
        js_dbuf_init(s->ctx, &s->pc2line);
31938
188
        for (i = 0; i < s->line_number_count; i++) {
31939
125
            uint32_t pc = s->line_number_slots[i].pc;
31940
125
            int line_num = s->line_number_slots[i].line_num;
31941
125
            int diff_pc, diff_line;
31942
31943
125
            if (line_num < 0)
31944
0
                continue;
31945
31946
125
            diff_pc = pc - last_pc;
31947
125
            diff_line = line_num - last_line_num;
31948
125
            if (diff_line == 0 || diff_pc < 0)
31949
0
                continue;
31950
31951
125
            if (diff_line >= PC2LINE_BASE &&
31952
125
                diff_line < PC2LINE_BASE + PC2LINE_RANGE &&
31953
125
                diff_pc <= PC2LINE_DIFF_PC_MAX) {
31954
117
                dbuf_putc(&s->pc2line, (diff_line - PC2LINE_BASE) +
31955
117
                          diff_pc * PC2LINE_RANGE + PC2LINE_OP_FIRST);
31956
117
            } else {
31957
                /* longer encoding */
31958
8
                dbuf_putc(&s->pc2line, 0);
31959
8
                dbuf_put_leb128(&s->pc2line, diff_pc);
31960
8
                dbuf_put_sleb128(&s->pc2line, diff_line);
31961
8
            }
31962
125
            last_pc = pc;
31963
125
            last_line_num = line_num;
31964
125
        }
31965
63
    }
31966
63
}
31967
31968
static RelocEntry *add_reloc(JSContext *ctx, LabelSlot *ls, uint32_t addr, int size)
31969
39
{
31970
39
    RelocEntry *re;
31971
39
    re = js_malloc(ctx, sizeof(*re));
31972
39
    if (!re)
31973
0
        return NULL;
31974
39
    re->addr = addr;
31975
39
    re->size = size;
31976
39
    re->next = ls->first_reloc;
31977
39
    ls->first_reloc = re;
31978
39
    return re;
31979
39
}
31980
31981
static BOOL code_has_label(CodeContext *s, int pos, int label)
31982
39
{
31983
39
    while (pos < s->bc_len) {
31984
39
        int op = s->bc_buf[pos];
31985
39
        if (op == OP_line_num) {
31986
0
            pos += 5;
31987
0
            continue;
31988
0
        }
31989
39
        if (op == OP_label) {
31990
0
            int lab = get_u32(s->bc_buf + pos + 1);
31991
0
            if (lab == label)
31992
0
                return TRUE;
31993
0
            pos += 5;
31994
0
            continue;
31995
0
        }
31996
39
        if (op == OP_goto) {
31997
0
            int lab = get_u32(s->bc_buf + pos + 1);
31998
0
            if (lab == label)
31999
0
                return TRUE;
32000
0
        }
32001
39
        break;
32002
39
    }
32003
39
    return FALSE;
32004
39
}
32005
32006
/* return the target label, following the OP_goto jumps
32007
   the first opcode at destination is stored in *pop
32008
 */
32009
static int find_jump_target(JSFunctionDef *s, int label, int *pop, int *pline)
32010
39
{
32011
39
    int i, pos, op;
32012
32013
39
    update_label(s, label, -1);
32014
39
    for (i = 0; i < 10; i++) {
32015
39
        assert(label >= 0 && label < s->label_count);
32016
39
        pos = s->label_slots[label].pos2;
32017
78
        for (;;) {
32018
78
            switch(op = s->byte_code.buf[pos]) {
32019
39
            case OP_line_num:
32020
39
                if (pline)
32021
0
                    *pline = get_u32(s->byte_code.buf + pos + 1);
32022
                /* fall thru */
32023
39
            case OP_label:
32024
39
                pos += opcode_info[op].size;
32025
39
                continue;
32026
0
            case OP_goto:
32027
0
                label = get_u32(s->byte_code.buf + pos + 1);
32028
0
                break;
32029
0
            case OP_drop:
32030
                /* ignore drop opcodes if followed by OP_return_undef */
32031
0
                while (s->byte_code.buf[++pos] == OP_drop)
32032
0
                    continue;
32033
0
                if (s->byte_code.buf[pos] == OP_return_undef)
32034
0
                    op = OP_return_undef;
32035
                /* fall thru */
32036
39
            default:
32037
39
                goto done;
32038
78
            }
32039
0
            break;
32040
78
        }
32041
39
    }
32042
    /* cycle detected, could issue a warning */
32043
39
 done:
32044
39
    *pop = op;
32045
39
    update_label(s, label, +1);
32046
39
    return label;
32047
39
}
32048
32049
static void push_short_int(DynBuf *bc_out, int val)
32050
3.54M
{
32051
3.54M
#if SHORT_OPCODES
32052
3.54M
    if (val >= -1 && val <= 7) {
32053
3.54M
        dbuf_putc(bc_out, OP_push_0 + val);
32054
3.54M
        return;
32055
3.54M
    }
32056
1.85k
    if (val == (int8_t)val) {
32057
1.85k
        dbuf_putc(bc_out, OP_push_i8);
32058
1.85k
        dbuf_putc(bc_out, val);
32059
1.85k
        return;
32060
1.85k
    }
32061
0
    if (val == (int16_t)val) {
32062
0
        dbuf_putc(bc_out, OP_push_i16);
32063
0
        dbuf_put_u16(bc_out, val);
32064
0
        return;
32065
0
    }
32066
0
#endif
32067
0
    dbuf_putc(bc_out, OP_push_i32);
32068
0
    dbuf_put_u32(bc_out, val);
32069
0
}
32070
32071
static void put_short_code(DynBuf *bc_out, int op, int idx)
32072
26
{
32073
26
#if SHORT_OPCODES
32074
26
    if (idx < 4) {
32075
26
        switch (op) {
32076
0
        case OP_get_loc:
32077
0
            dbuf_putc(bc_out, OP_get_loc0 + idx);
32078
0
            return;
32079
2
        case OP_put_loc:
32080
2
            dbuf_putc(bc_out, OP_put_loc0 + idx);
32081
2
            return;
32082
24
        case OP_set_loc:
32083
24
            dbuf_putc(bc_out, OP_set_loc0 + idx);
32084
24
            return;
32085
0
        case OP_get_arg:
32086
0
            dbuf_putc(bc_out, OP_get_arg0 + idx);
32087
0
            return;
32088
0
        case OP_put_arg:
32089
0
            dbuf_putc(bc_out, OP_put_arg0 + idx);
32090
0
            return;
32091
0
        case OP_set_arg:
32092
0
            dbuf_putc(bc_out, OP_set_arg0 + idx);
32093
0
            return;
32094
0
        case OP_get_var_ref:
32095
0
            dbuf_putc(bc_out, OP_get_var_ref0 + idx);
32096
0
            return;
32097
0
        case OP_put_var_ref:
32098
0
            dbuf_putc(bc_out, OP_put_var_ref0 + idx);
32099
0
            return;
32100
0
        case OP_set_var_ref:
32101
0
            dbuf_putc(bc_out, OP_set_var_ref0 + idx);
32102
0
            return;
32103
0
        case OP_call:
32104
0
            dbuf_putc(bc_out, OP_call0 + idx);
32105
0
            return;
32106
26
        }
32107
26
    }
32108
0
    if (idx < 256) {
32109
0
        switch (op) {
32110
0
        case OP_get_loc:
32111
0
            dbuf_putc(bc_out, OP_get_loc8);
32112
0
            dbuf_putc(bc_out, idx);
32113
0
            return;
32114
0
        case OP_put_loc:
32115
0
            dbuf_putc(bc_out, OP_put_loc8);
32116
0
            dbuf_putc(bc_out, idx);
32117
0
            return;
32118
0
        case OP_set_loc:
32119
0
            dbuf_putc(bc_out, OP_set_loc8);
32120
0
            dbuf_putc(bc_out, idx);
32121
0
            return;
32122
0
        }
32123
0
    }
32124
0
#endif
32125
0
    dbuf_putc(bc_out, op);
32126
0
    dbuf_put_u16(bc_out, idx);
32127
0
}
32128
32129
/* peephole optimizations and resolve goto/labels */
32130
static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
32131
63
{
32132
63
    int pos, pos_next, bc_len, op, op1, len, i, line_num;
32133
63
    const uint8_t *bc_buf;
32134
63
    DynBuf bc_out;
32135
63
    LabelSlot *label_slots, *ls;
32136
63
    RelocEntry *re, *re_next;
32137
63
    CodeContext cc;
32138
63
    int label;
32139
63
#if SHORT_OPCODES
32140
63
    JumpSlot *jp;
32141
63
#endif
32142
32143
63
    label_slots = s->label_slots;
32144
32145
63
    line_num = s->line_num;
32146
32147
63
    cc.bc_buf = bc_buf = s->byte_code.buf;
32148
63
    cc.bc_len = bc_len = s->byte_code.size;
32149
63
    js_dbuf_init(ctx, &bc_out);
32150
32151
63
#if SHORT_OPCODES
32152
63
    if (s->jump_size) {
32153
39
        s->jump_slots = js_mallocz(s->ctx, sizeof(*s->jump_slots) * s->jump_size);
32154
39
        if (s->jump_slots == NULL)
32155
0
            return -1;
32156
39
    }
32157
63
#endif
32158
    /* XXX: Should skip this phase if not generating SHORT_OPCODES */
32159
63
    if (s->line_number_size && !(s->js_mode & JS_MODE_STRIP)) {
32160
63
        s->line_number_slots = js_mallocz(s->ctx, sizeof(*s->line_number_slots) * s->line_number_size);
32161
63
        if (s->line_number_slots == NULL)
32162
0
            return -1;
32163
63
        s->line_number_last = s->line_num;
32164
63
        s->line_number_last_pc = 0;
32165
63
    }
32166
32167
    /* initialize the 'home_object' variable if needed */
32168
63
    if (s->home_object_var_idx >= 0) {
32169
0
        dbuf_putc(&bc_out, OP_special_object);
32170
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_HOME_OBJECT);
32171
0
        put_short_code(&bc_out, OP_put_loc, s->home_object_var_idx);
32172
0
    }
32173
    /* initialize the 'this.active_func' variable if needed */
32174
63
    if (s->this_active_func_var_idx >= 0) {
32175
0
        dbuf_putc(&bc_out, OP_special_object);
32176
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
32177
0
        put_short_code(&bc_out, OP_put_loc, s->this_active_func_var_idx);
32178
0
    }
32179
    /* initialize the 'new.target' variable if needed */
32180
63
    if (s->new_target_var_idx >= 0) {
32181
0
        dbuf_putc(&bc_out, OP_special_object);
32182
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_NEW_TARGET);
32183
0
        put_short_code(&bc_out, OP_put_loc, s->new_target_var_idx);
32184
0
    }
32185
    /* initialize the 'this' variable if needed. In a derived class
32186
       constructor, this is initially uninitialized. */
32187
63
    if (s->this_var_idx >= 0) {
32188
0
        if (s->is_derived_class_constructor) {
32189
0
            dbuf_putc(&bc_out, OP_set_loc_uninitialized);
32190
0
            dbuf_put_u16(&bc_out, s->this_var_idx);
32191
0
        } else {
32192
0
            dbuf_putc(&bc_out, OP_push_this);
32193
0
            put_short_code(&bc_out, OP_put_loc, s->this_var_idx);
32194
0
        }
32195
0
    }
32196
    /* initialize the 'arguments' variable if needed */
32197
63
    if (s->arguments_var_idx >= 0) {
32198
0
        if ((s->js_mode & JS_MODE_STRICT) || !s->has_simple_parameter_list) {
32199
0
            dbuf_putc(&bc_out, OP_special_object);
32200
0
            dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_ARGUMENTS);
32201
0
        } else {
32202
0
            dbuf_putc(&bc_out, OP_special_object);
32203
0
            dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS);
32204
0
        }
32205
0
        if (s->arguments_arg_idx >= 0)
32206
0
            put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);
32207
0
        put_short_code(&bc_out, OP_put_loc, s->arguments_var_idx);
32208
0
    }
32209
    /* initialize a reference to the current function if needed */
32210
63
    if (s->func_var_idx >= 0) {
32211
0
        dbuf_putc(&bc_out, OP_special_object);
32212
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
32213
0
        put_short_code(&bc_out, OP_put_loc, s->func_var_idx);
32214
0
    }
32215
    /* initialize the variable environment object if needed */
32216
63
    if (s->var_object_idx >= 0) {
32217
0
        dbuf_putc(&bc_out, OP_special_object);
32218
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
32219
0
        put_short_code(&bc_out, OP_put_loc, s->var_object_idx);
32220
0
    }
32221
63
    if (s->arg_var_object_idx >= 0) {
32222
0
        dbuf_putc(&bc_out, OP_special_object);
32223
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
32224
0
        put_short_code(&bc_out, OP_put_loc, s->arg_var_object_idx);
32225
0
    }
32226
32227
7.08M
    for (pos = 0; pos < bc_len; pos = pos_next) {
32228
7.08M
        int val;
32229
7.08M
        op = bc_buf[pos];
32230
7.08M
        len = opcode_info[op].size;
32231
7.08M
        pos_next = pos + len;
32232
7.08M
        switch(op) {
32233
168
        case OP_line_num:
32234
            /* line number info (for debug). We put it in a separate
32235
               compressed table to reduce memory usage and get better
32236
               performance */
32237
168
            line_num = get_u32(bc_buf + pos + 1);
32238
168
            break;
32239
32240
39
        case OP_label:
32241
39
            {
32242
39
                label = get_u32(bc_buf + pos + 1);
32243
39
                assert(label >= 0 && label < s->label_count);
32244
39
                ls = &label_slots[label];
32245
39
                assert(ls->addr == -1);
32246
39
                ls->addr = bc_out.size;
32247
                /* resolve the relocation entries */
32248
78
                for(re = ls->first_reloc; re != NULL; re = re_next) {
32249
39
                    int diff = ls->addr - re->addr;
32250
39
                    re_next = re->next;
32251
39
                    switch (re->size) {
32252
0
                    case 4:
32253
0
                        put_u32(bc_out.buf + re->addr, diff);
32254
0
                        break;
32255
0
                    case 2:
32256
0
                        assert(diff == (int16_t)diff);
32257
0
                        put_u16(bc_out.buf + re->addr, diff);
32258
0
                        break;
32259
39
                    case 1:
32260
39
                        assert(diff == (int8_t)diff);
32261
39
                        put_u8(bc_out.buf + re->addr, diff);
32262
39
                        break;
32263
39
                    }
32264
39
                    js_free(ctx, re);
32265
39
                }
32266
39
                ls->first_reloc = NULL;
32267
39
            }
32268
0
            break;
32269
32270
0
        case OP_call:
32271
0
        case OP_call_method:
32272
0
            {
32273
                /* detect and transform tail calls */
32274
0
                int argc;
32275
0
                argc = get_u16(bc_buf + pos + 1);
32276
0
                if (code_match(&cc, pos_next, OP_return, -1)) {
32277
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32278
0
                    add_pc2line_info(s, bc_out.size, line_num);
32279
0
                    put_short_code(&bc_out, op + 1, argc);
32280
0
                    pos_next = skip_dead_code(s, bc_buf, bc_len, cc.pos, &line_num);
32281
0
                    break;
32282
0
                }
32283
0
                add_pc2line_info(s, bc_out.size, line_num);
32284
0
                put_short_code(&bc_out, op, argc);
32285
0
                break;
32286
0
            }
32287
0
            goto no_change;
32288
32289
24
        case OP_return:
32290
63
        case OP_return_undef:
32291
102
        case OP_return_async:
32292
102
        case OP_throw:
32293
102
        case OP_throw_error:
32294
102
            pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
32295
102
            goto no_change;
32296
32297
0
        case OP_goto:
32298
0
            label = get_u32(bc_buf + pos + 1);
32299
0
        has_goto:
32300
0
            if (OPTIMIZE) {
32301
0
                int line1 = -1;
32302
                /* Use custom matcher because multiple labels can follow */
32303
0
                label = find_jump_target(s, label, &op1, &line1);
32304
0
                if (code_has_label(&cc, pos_next, label)) {
32305
                    /* jump to next instruction: remove jump */
32306
0
                    update_label(s, label, -1);
32307
0
                    break;
32308
0
                }
32309
0
                if (op1 == OP_return || op1 == OP_return_undef || op1 == OP_throw) {
32310
                    /* jump to return/throw: remove jump, append return/throw */
32311
                    /* updating the line number obfuscates assembly listing */
32312
                    //if (line1 >= 0) line_num = line1;
32313
0
                    update_label(s, label, -1);
32314
0
                    add_pc2line_info(s, bc_out.size, line_num);
32315
0
                    dbuf_putc(&bc_out, op1);
32316
0
                    pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
32317
0
                    break;
32318
0
                }
32319
                /* XXX: should duplicate single instructions followed by goto or return */
32320
                /* For example, can match one of these followed by return:
32321
                   push_i32 / push_const / push_atom_value / get_var /
32322
                   undefined / null / push_false / push_true / get_ref_value /
32323
                   get_loc / get_arg / get_var_ref
32324
                 */
32325
0
            }
32326
0
            goto has_label;
32327
32328
0
        case OP_gosub:
32329
0
            label = get_u32(bc_buf + pos + 1);
32330
0
            if (0 && OPTIMIZE) {
32331
0
                label = find_jump_target(s, label, &op1, NULL);
32332
0
                if (op1 == OP_ret) {
32333
0
                    update_label(s, label, -1);
32334
                    /* empty finally clause: remove gosub */
32335
0
                    break;
32336
0
                }
32337
0
            }
32338
0
            goto has_label;
32339
32340
0
        case OP_catch:
32341
0
            label = get_u32(bc_buf + pos + 1);
32342
0
            goto has_label;
32343
32344
0
        case OP_if_true:
32345
39
        case OP_if_false:
32346
39
            label = get_u32(bc_buf + pos + 1);
32347
39
            if (OPTIMIZE) {
32348
39
                label = find_jump_target(s, label, &op1, NULL);
32349
                /* transform if_false/if_true(l1) label(l1) -> drop label(l1) */
32350
39
                if (code_has_label(&cc, pos_next, label)) {
32351
0
                    update_label(s, label, -1);
32352
0
                    dbuf_putc(&bc_out, OP_drop);
32353
0
                    break;
32354
0
                }
32355
                /* transform if_false(l1) goto(l2) label(l1) -> if_false(l2) label(l1) */
32356
39
                if (code_match(&cc, pos_next, OP_goto, -1)) {
32357
0
                    int pos1 = cc.pos;
32358
0
                    int line1 = cc.line_num;
32359
0
                    if (code_has_label(&cc, pos1, label)) {
32360
0
                        if (line1 >= 0) line_num = line1;
32361
0
                        pos_next = pos1;
32362
0
                        update_label(s, label, -1);
32363
0
                        label = cc.label;
32364
0
                        op ^= OP_if_true ^ OP_if_false;
32365
0
                    }
32366
0
                }
32367
39
            }
32368
39
        has_label:
32369
39
            add_pc2line_info(s, bc_out.size, line_num);
32370
39
            if (op == OP_goto) {
32371
0
                pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
32372
0
            }
32373
39
            assert(label >= 0 && label < s->label_count);
32374
39
            ls = &label_slots[label];
32375
39
#if SHORT_OPCODES
32376
39
            jp = &s->jump_slots[s->jump_count++];
32377
39
            jp->op = op;
32378
39
            jp->size = 4;
32379
39
            jp->pos = bc_out.size + 1;
32380
39
            jp->label = label;
32381
32382
39
            if (ls->addr == -1) {
32383
39
                int diff = ls->pos2 - pos - 1;
32384
39
                if (diff < 128 && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
32385
39
                    jp->size = 1;
32386
39
                    jp->op = OP_if_false8 + (op - OP_if_false);
32387
39
                    dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
32388
39
                    dbuf_putc(&bc_out, 0);
32389
39
                    if (!add_reloc(ctx, ls, bc_out.size - 1, 1))
32390
0
                        goto fail;
32391
39
                    break;
32392
39
                }
32393
0
                if (diff < 32768 && op == OP_goto) {
32394
0
                    jp->size = 2;
32395
0
                    jp->op = OP_goto16;
32396
0
                    dbuf_putc(&bc_out, OP_goto16);
32397
0
                    dbuf_put_u16(&bc_out, 0);
32398
0
                    if (!add_reloc(ctx, ls, bc_out.size - 2, 2))
32399
0
                        goto fail;
32400
0
                    break;
32401
0
                }
32402
0
            } else {
32403
0
                int diff = ls->addr - bc_out.size - 1;
32404
0
                if (diff == (int8_t)diff && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
32405
0
                    jp->size = 1;
32406
0
                    jp->op = OP_if_false8 + (op - OP_if_false);
32407
0
                    dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
32408
0
                    dbuf_putc(&bc_out, diff);
32409
0
                    break;
32410
0
                }
32411
0
                if (diff == (int16_t)diff && op == OP_goto) {
32412
0
                    jp->size = 2;
32413
0
                    jp->op = OP_goto16;
32414
0
                    dbuf_putc(&bc_out, OP_goto16);
32415
0
                    dbuf_put_u16(&bc_out, diff);
32416
0
                    break;
32417
0
                }
32418
0
            }
32419
0
#endif
32420
0
            dbuf_putc(&bc_out, op);
32421
0
            dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
32422
0
            if (ls->addr == -1) {
32423
                /* unresolved yet: create a new relocation entry */
32424
0
                if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
32425
0
                    goto fail;
32426
0
            }
32427
0
            break;
32428
0
        case OP_with_get_var:
32429
0
        case OP_with_put_var:
32430
0
        case OP_with_delete_var:
32431
0
        case OP_with_make_ref:
32432
0
        case OP_with_get_ref:
32433
0
        case OP_with_get_ref_undef:
32434
0
            {
32435
0
                JSAtom atom;
32436
0
                int is_with;
32437
32438
0
                atom = get_u32(bc_buf + pos + 1);
32439
0
                label = get_u32(bc_buf + pos + 5);
32440
0
                is_with = bc_buf[pos + 9];
32441
0
                if (OPTIMIZE) {
32442
0
                    label = find_jump_target(s, label, &op1, NULL);
32443
0
                }
32444
0
                assert(label >= 0 && label < s->label_count);
32445
0
                ls = &label_slots[label];
32446
0
                add_pc2line_info(s, bc_out.size, line_num);
32447
0
#if SHORT_OPCODES
32448
0
                jp = &s->jump_slots[s->jump_count++];
32449
0
                jp->op = op;
32450
0
                jp->size = 4;
32451
0
                jp->pos = bc_out.size + 5;
32452
0
                jp->label = label;
32453
0
#endif
32454
0
                dbuf_putc(&bc_out, op);
32455
0
                dbuf_put_u32(&bc_out, atom);
32456
0
                dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
32457
0
                if (ls->addr == -1) {
32458
                    /* unresolved yet: create a new relocation entry */
32459
0
                    if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
32460
0
                        goto fail;
32461
0
                }
32462
0
                dbuf_putc(&bc_out, is_with);
32463
0
            }
32464
0
            break;
32465
32466
0
        case OP_drop:
32467
0
            if (OPTIMIZE) {
32468
                /* remove useless drops before return */
32469
0
                if (code_match(&cc, pos_next, OP_return_undef, -1)) {
32470
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32471
0
                    break;
32472
0
                }
32473
0
            }
32474
0
            goto no_change;
32475
32476
0
        case OP_null:
32477
0
#if SHORT_OPCODES
32478
0
            if (OPTIMIZE) {
32479
                /* transform null strict_eq into is_null */
32480
0
                if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
32481
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32482
0
                    add_pc2line_info(s, bc_out.size, line_num);
32483
0
                    dbuf_putc(&bc_out, OP_is_null);
32484
0
                    pos_next = cc.pos;
32485
0
                    break;
32486
0
                }
32487
                /* transform null strict_neq if_false/if_true -> is_null if_true/if_false */
32488
0
                if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
32489
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32490
0
                    add_pc2line_info(s, bc_out.size, line_num);
32491
0
                    dbuf_putc(&bc_out, OP_is_null);
32492
0
                    pos_next = cc.pos;
32493
0
                    label = cc.label;
32494
0
                    op = cc.op ^ OP_if_false ^ OP_if_true;
32495
0
                    goto has_label;
32496
0
                }
32497
0
            }
32498
0
#endif
32499
            /* fall thru */
32500
0
        case OP_push_false:
32501
0
        case OP_push_true:
32502
0
            if (OPTIMIZE) {
32503
0
                val = (op == OP_push_true);
32504
0
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
32505
0
                has_constant_test:
32506
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32507
0
                    if (val == cc.op - OP_if_false) {
32508
                        /* transform null if_false(l1) -> goto l1 */
32509
                        /* transform false if_false(l1) -> goto l1 */
32510
                        /* transform true if_true(l1) -> goto l1 */
32511
0
                        pos_next = cc.pos;
32512
0
                        op = OP_goto;
32513
0
                        label = cc.label;
32514
0
                        goto has_goto;
32515
0
                    } else {
32516
                        /* transform null if_true(l1) -> nop */
32517
                        /* transform false if_true(l1) -> nop */
32518
                        /* transform true if_false(l1) -> nop */
32519
0
                        pos_next = cc.pos;
32520
0
                        update_label(s, cc.label, -1);
32521
0
                        break;
32522
0
                    }
32523
0
                }
32524
0
            }
32525
0
            goto no_change;
32526
32527
3.54M
        case OP_push_i32:
32528
3.54M
            if (OPTIMIZE) {
32529
                /* transform i32(val) neg -> i32(-val) */
32530
3.54M
                val = get_i32(bc_buf + pos + 1);
32531
3.54M
                if ((val != INT32_MIN && val != 0)
32532
3.54M
                &&  code_match(&cc, pos_next, OP_neg, -1)) {
32533
1
                    if (cc.line_num >= 0) line_num = cc.line_num;
32534
1
                    if (code_match(&cc, cc.pos, OP_drop, -1)) {
32535
0
                        if (cc.line_num >= 0) line_num = cc.line_num;
32536
1
                    } else {
32537
1
                        add_pc2line_info(s, bc_out.size, line_num);
32538
1
                        push_short_int(&bc_out, -val);
32539
1
                    }
32540
1
                    pos_next = cc.pos;
32541
1
                    break;
32542
1
                }
32543
                /* remove push/drop pairs generated by the parser */
32544
3.54M
                if (code_match(&cc, pos_next, OP_drop, -1)) {
32545
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32546
0
                    pos_next = cc.pos;
32547
0
                    break;
32548
0
                }
32549
                /* Optimize constant tests: `if (0)`, `if (1)`, `if (!0)`... */
32550
3.54M
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
32551
0
                    val = (val != 0);
32552
0
                    goto has_constant_test;
32553
0
                }
32554
3.54M
                add_pc2line_info(s, bc_out.size, line_num);
32555
3.54M
                push_short_int(&bc_out, val);
32556
3.54M
                break;
32557
3.54M
            }
32558
0
            goto no_change;
32559
32560
0
#if SHORT_OPCODES
32561
0
        case OP_push_const:
32562
0
        case OP_fclosure:
32563
0
            if (OPTIMIZE) {
32564
0
                int idx = get_u32(bc_buf + pos + 1);
32565
0
                if (idx < 256) {
32566
0
                    add_pc2line_info(s, bc_out.size, line_num);
32567
0
                    dbuf_putc(&bc_out, OP_push_const8 + op - OP_push_const);
32568
0
                    dbuf_putc(&bc_out, idx);
32569
0
                    break;
32570
0
                }
32571
0
            }
32572
0
            goto no_change;
32573
32574
0
        case OP_get_field:
32575
0
            if (OPTIMIZE) {
32576
0
                JSAtom atom = get_u32(bc_buf + pos + 1);
32577
0
                if (atom == JS_ATOM_length) {
32578
0
                    JS_FreeAtom(ctx, atom);
32579
0
                    add_pc2line_info(s, bc_out.size, line_num);
32580
0
                    dbuf_putc(&bc_out, OP_get_length);
32581
0
                    break;
32582
0
                }
32583
0
            }
32584
0
            goto no_change;
32585
0
#endif
32586
20
        case OP_push_atom_value:
32587
20
            if (OPTIMIZE) {
32588
20
                JSAtom atom = get_u32(bc_buf + pos + 1);
32589
                /* remove push/drop pairs generated by the parser */
32590
20
                if (code_match(&cc, pos_next, OP_drop, -1)) {
32591
0
                    JS_FreeAtom(ctx, atom);
32592
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32593
0
                    pos_next = cc.pos;
32594
0
                    break;
32595
0
                }
32596
20
#if SHORT_OPCODES
32597
20
                if (atom == JS_ATOM_empty_string) {
32598
2
                    JS_FreeAtom(ctx, atom);
32599
2
                    add_pc2line_info(s, bc_out.size, line_num);
32600
2
                    dbuf_putc(&bc_out, OP_push_empty_string);
32601
2
                    break;
32602
2
                }
32603
20
#endif
32604
20
            }
32605
18
            goto no_change;
32606
32607
18
        case OP_to_propkey:
32608
0
        case OP_to_propkey2:
32609
0
            if (OPTIMIZE) {
32610
                /* remove redundant to_propkey/to_propkey2 opcodes when storing simple data */
32611
0
                if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_put_array_el, -1)
32612
0
                ||  code_match(&cc, pos_next, M3(OP_push_i32, OP_push_const, OP_push_atom_value), OP_put_array_el, -1)
32613
0
                ||  code_match(&cc, pos_next, M4(OP_undefined, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) {
32614
0
                    break;
32615
0
                }
32616
0
            }
32617
0
            goto no_change;
32618
32619
39
        case OP_undefined:
32620
39
            if (OPTIMIZE) {
32621
                /* remove push/drop pairs generated by the parser */
32622
39
                if (code_match(&cc, pos_next, OP_drop, -1)) {
32623
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32624
0
                    pos_next = cc.pos;
32625
0
                    break;
32626
0
                }
32627
                /* transform undefined return -> return_undefined */
32628
39
                if (code_match(&cc, pos_next, OP_return, -1)) {
32629
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32630
0
                    add_pc2line_info(s, bc_out.size, line_num);
32631
0
                    dbuf_putc(&bc_out, OP_return_undef);
32632
0
                    pos_next = cc.pos;
32633
0
                    break;
32634
0
                }
32635
                /* transform undefined if_true(l1)/if_false(l1) -> nop/goto(l1) */
32636
39
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
32637
0
                    val = 0;
32638
0
                    goto has_constant_test;
32639
0
                }
32640
39
#if SHORT_OPCODES
32641
                /* transform undefined strict_eq -> is_undefined */
32642
39
                if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
32643
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32644
0
                    add_pc2line_info(s, bc_out.size, line_num);
32645
0
                    dbuf_putc(&bc_out, OP_is_undefined);
32646
0
                    pos_next = cc.pos;
32647
0
                    break;
32648
0
                }
32649
                /* transform undefined strict_neq if_false/if_true -> is_undefined if_true/if_false */
32650
39
                if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
32651
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32652
0
                    add_pc2line_info(s, bc_out.size, line_num);
32653
0
                    dbuf_putc(&bc_out, OP_is_undefined);
32654
0
                    pos_next = cc.pos;
32655
0
                    label = cc.label;
32656
0
                    op = cc.op ^ OP_if_false ^ OP_if_true;
32657
0
                    goto has_label;
32658
0
                }
32659
39
#endif
32660
39
            }
32661
39
            goto no_change;
32662
32663
78
        case OP_insert2:
32664
78
            if (OPTIMIZE) {
32665
                /* Transformation:
32666
                   insert2 put_field(a) drop -> put_field(a)
32667
                   insert2 put_var_strict(a) drop -> put_var_strict(a)
32668
                */
32669
78
                if (code_match(&cc, pos_next, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
32670
78
                    if (cc.line_num >= 0) line_num = cc.line_num;
32671
78
                    add_pc2line_info(s, bc_out.size, line_num);
32672
78
                    dbuf_putc(&bc_out, cc.op);
32673
78
                    dbuf_put_u32(&bc_out, cc.atom);
32674
78
                    pos_next = cc.pos;
32675
78
                    break;
32676
78
                }
32677
78
            }
32678
0
            goto no_change;
32679
32680
0
        case OP_dup:
32681
0
            if (OPTIMIZE) {
32682
                /* Transformation: dup put_x(n) drop -> put_x(n) */
32683
0
                int op1, line2 = -1;
32684
                /* Transformation: dup put_x(n) -> set_x(n) */
32685
0
                if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, -1)) {
32686
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32687
0
                    op1 = cc.op + 1;  /* put_x -> set_x */
32688
0
                    pos_next = cc.pos;
32689
0
                    if (code_match(&cc, cc.pos, OP_drop, -1)) {
32690
0
                        if (cc.line_num >= 0) line_num = cc.line_num;
32691
0
                        op1 -= 1; /* set_x drop -> put_x */
32692
0
                        pos_next = cc.pos;
32693
0
                        if (code_match(&cc, cc.pos, op1 - 1, cc.idx, -1)) {
32694
0
                            line2 = cc.line_num; /* delay line number update */
32695
0
                            op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
32696
0
                            pos_next = cc.pos;
32697
0
                        }
32698
0
                    }
32699
0
                    add_pc2line_info(s, bc_out.size, line_num);
32700
0
                    put_short_code(&bc_out, op1, cc.idx);
32701
0
                    if (line2 >= 0) line_num = line2;
32702
0
                    break;
32703
0
                }
32704
0
            }
32705
0
            goto no_change;
32706
32707
0
        case OP_get_loc:
32708
0
            if (OPTIMIZE) {
32709
                /* transformation:
32710
                   get_loc(n) post_dec put_loc(n) drop -> dec_loc(n)
32711
                   get_loc(n) post_inc put_loc(n) drop -> inc_loc(n)
32712
                   get_loc(n) dec dup put_loc(n) drop -> dec_loc(n)
32713
                   get_loc(n) inc dup put_loc(n) drop -> inc_loc(n)
32714
                 */
32715
0
                int idx;
32716
0
                idx = get_u16(bc_buf + pos + 1);
32717
0
                if (idx >= 256)
32718
0
                    goto no_change;
32719
0
                if (code_match(&cc, pos_next, M2(OP_post_dec, OP_post_inc), OP_put_loc, idx, OP_drop, -1) ||
32720
0
                    code_match(&cc, pos_next, M2(OP_dec, OP_inc), OP_dup, OP_put_loc, idx, OP_drop, -1)) {
32721
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32722
0
                    add_pc2line_info(s, bc_out.size, line_num);
32723
0
                    dbuf_putc(&bc_out, (cc.op == OP_inc || cc.op == OP_post_inc) ? OP_inc_loc : OP_dec_loc);
32724
0
                    dbuf_putc(&bc_out, idx);
32725
0
                    pos_next = cc.pos;
32726
0
                    break;
32727
0
                }
32728
                /* transformation:
32729
                   get_loc(n) push_atom_value(x) add dup put_loc(n) drop -> push_atom_value(x) add_loc(n)
32730
                 */
32731
0
                if (code_match(&cc, pos_next, OP_push_atom_value, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
32732
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32733
0
                    add_pc2line_info(s, bc_out.size, line_num);
32734
0
#if SHORT_OPCODES
32735
0
                    if (cc.atom == JS_ATOM_empty_string) {
32736
0
                        JS_FreeAtom(ctx, cc.atom);
32737
0
                        dbuf_putc(&bc_out, OP_push_empty_string);
32738
0
                    } else
32739
0
#endif
32740
0
                    {
32741
0
                        dbuf_putc(&bc_out, OP_push_atom_value);
32742
0
                        dbuf_put_u32(&bc_out, cc.atom);
32743
0
                    }
32744
0
                    dbuf_putc(&bc_out, OP_add_loc);
32745
0
                    dbuf_putc(&bc_out, idx);
32746
0
                    pos_next = cc.pos;
32747
0
                    break;
32748
0
                }
32749
                /* transformation:
32750
                   get_loc(n) push_i32(x) add dup put_loc(n) drop -> push_i32(x) add_loc(n)
32751
                 */
32752
0
                if (code_match(&cc, pos_next, OP_push_i32, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
32753
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32754
0
                    add_pc2line_info(s, bc_out.size, line_num);
32755
0
                    push_short_int(&bc_out, cc.label);
32756
0
                    dbuf_putc(&bc_out, OP_add_loc);
32757
0
                    dbuf_putc(&bc_out, idx);
32758
0
                    pos_next = cc.pos;
32759
0
                    break;
32760
0
                }
32761
                /* transformation: XXX: also do these:
32762
                   get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x) add_loc(n)
32763
                   get_loc(n) get_arg(x) add dup put_loc(n) drop -> get_arg(x) add_loc(n)
32764
                   get_loc(n) get_var_ref(x) add dup put_loc(n) drop -> get_var_ref(x) add_loc(n)
32765
                 */
32766
0
                if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
32767
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32768
0
                    add_pc2line_info(s, bc_out.size, line_num);
32769
0
                    put_short_code(&bc_out, cc.op, cc.idx);
32770
0
                    dbuf_putc(&bc_out, OP_add_loc);
32771
0
                    dbuf_putc(&bc_out, idx);
32772
0
                    pos_next = cc.pos;
32773
0
                    break;
32774
0
                }
32775
0
                add_pc2line_info(s, bc_out.size, line_num);
32776
0
                put_short_code(&bc_out, op, idx);
32777
0
                break;
32778
0
            }
32779
0
            goto no_change;
32780
0
#if SHORT_OPCODES
32781
0
        case OP_get_arg:
32782
0
        case OP_get_var_ref:
32783
0
            if (OPTIMIZE) {
32784
0
                int idx;
32785
0
                idx = get_u16(bc_buf + pos + 1);
32786
0
                add_pc2line_info(s, bc_out.size, line_num);
32787
0
                put_short_code(&bc_out, op, idx);
32788
0
                break;
32789
0
            }
32790
0
            goto no_change;
32791
0
#endif
32792
26
        case OP_put_loc:
32793
26
        case OP_put_arg:
32794
26
        case OP_put_var_ref:
32795
26
            if (OPTIMIZE) {
32796
                /* transformation: put_x(n) get_x(n) -> set_x(n) */
32797
26
                int idx;
32798
26
                idx = get_u16(bc_buf + pos + 1);
32799
26
                if (code_match(&cc, pos_next, op - 1, idx, -1)) {
32800
24
                    if (cc.line_num >= 0) line_num = cc.line_num;
32801
24
                    add_pc2line_info(s, bc_out.size, line_num);
32802
24
                    put_short_code(&bc_out, op + 1, idx);
32803
24
                    pos_next = cc.pos;
32804
24
                    break;
32805
24
                }
32806
2
                add_pc2line_info(s, bc_out.size, line_num);
32807
2
                put_short_code(&bc_out, op, idx);
32808
2
                break;
32809
26
            }
32810
0
            goto no_change;
32811
32812
0
        case OP_post_inc:
32813
0
        case OP_post_dec:
32814
0
            if (OPTIMIZE) {
32815
                /* transformation:
32816
                   post_inc put_x drop -> inc put_x
32817
                   post_inc perm3 put_field drop -> inc put_field
32818
                   post_inc perm3 put_var_strict drop -> inc put_var_strict
32819
                   post_inc perm4 put_array_el drop -> inc put_array_el
32820
                 */
32821
0
                int op1, idx;
32822
0
                if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, OP_drop, -1)) {
32823
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32824
0
                    op1 = cc.op;
32825
0
                    idx = cc.idx;
32826
0
                    pos_next = cc.pos;
32827
0
                    if (code_match(&cc, cc.pos, op1 - 1, idx, -1)) {
32828
0
                        if (cc.line_num >= 0) line_num = cc.line_num;
32829
0
                        op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
32830
0
                        pos_next = cc.pos;
32831
0
                    }
32832
0
                    add_pc2line_info(s, bc_out.size, line_num);
32833
0
                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
32834
0
                    put_short_code(&bc_out, op1, idx);
32835
0
                    break;
32836
0
                }
32837
0
                if (code_match(&cc, pos_next, OP_perm3, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
32838
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32839
0
                    add_pc2line_info(s, bc_out.size, line_num);
32840
0
                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
32841
0
                    dbuf_putc(&bc_out, cc.op);
32842
0
                    dbuf_put_u32(&bc_out, cc.atom);
32843
0
                    pos_next = cc.pos;
32844
0
                    break;
32845
0
                }
32846
0
                if (code_match(&cc, pos_next, OP_perm4, OP_put_array_el, OP_drop, -1)) {
32847
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32848
0
                    add_pc2line_info(s, bc_out.size, line_num);
32849
0
                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
32850
0
                    dbuf_putc(&bc_out, OP_put_array_el);
32851
0
                    pos_next = cc.pos;
32852
0
                    break;
32853
0
                }
32854
0
            }
32855
0
            goto no_change;
32856
32857
0
#if SHORT_OPCODES
32858
0
        case OP_typeof:
32859
0
            if (OPTIMIZE) {
32860
                /* simplify typeof tests */
32861
0
                if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) {
32862
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32863
0
                    int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq;
32864
0
                    int op2 = -1;
32865
0
                    switch (cc.atom) {
32866
0
                    case JS_ATOM_undefined:
32867
0
                        op2 = OP_typeof_is_undefined;
32868
0
                        break;
32869
0
                    case JS_ATOM_function:
32870
0
                        op2 = OP_typeof_is_function;
32871
0
                        break;
32872
0
                    }
32873
0
                    if (op2 >= 0) {
32874
                        /* transform typeof(s) == "<type>" into is_<type> */
32875
0
                        if (op1 == OP_strict_eq) {
32876
0
                            add_pc2line_info(s, bc_out.size, line_num);
32877
0
                            dbuf_putc(&bc_out, op2);
32878
0
                            JS_FreeAtom(ctx, cc.atom);
32879
0
                            pos_next = cc.pos;
32880
0
                            break;
32881
0
                        }
32882
0
                        if (op1 == OP_strict_neq && code_match(&cc, cc.pos, OP_if_false, -1)) {
32883
                            /* transform typeof(s) != "<type>" if_false into is_<type> if_true */
32884
0
                            if (cc.line_num >= 0) line_num = cc.line_num;
32885
0
                            add_pc2line_info(s, bc_out.size, line_num);
32886
0
                            dbuf_putc(&bc_out, op2);
32887
0
                            JS_FreeAtom(ctx, cc.atom);
32888
0
                            pos_next = cc.pos;
32889
0
                            label = cc.label;
32890
0
                            op = OP_if_true;
32891
0
                            goto has_label;
32892
0
                        }
32893
0
                    }
32894
0
                }
32895
0
            }
32896
0
            goto no_change;
32897
0
#endif
32898
32899
3.54M
        default:
32900
3.54M
        no_change:
32901
3.54M
            add_pc2line_info(s, bc_out.size, line_num);
32902
3.54M
            dbuf_put(&bc_out, bc_buf + pos, len);
32903
3.54M
            break;
32904
7.08M
        }
32905
7.08M
    }
32906
32907
    /* check that there were no missing labels */
32908
102
    for(i = 0; i < s->label_count; i++) {
32909
39
        assert(label_slots[i].first_reloc == NULL);
32910
39
    }
32911
63
#if SHORT_OPCODES
32912
63
    if (OPTIMIZE) {
32913
        /* more jump optimizations */
32914
63
        int patch_offsets = 0;
32915
102
        for (i = 0, jp = s->jump_slots; i < s->jump_count; i++, jp++) {
32916
39
            LabelSlot *ls;
32917
39
            JumpSlot *jp1;
32918
39
            int j, pos, diff, delta;
32919
32920
39
            delta = 3;
32921
39
            switch (op = jp->op) {
32922
0
            case OP_goto16:
32923
0
                delta = 1;
32924
                /* fall thru */
32925
0
            case OP_if_false:
32926
0
            case OP_if_true:
32927
0
            case OP_goto:
32928
0
                pos = jp->pos;
32929
0
                diff = s->label_slots[jp->label].addr - pos;
32930
0
                if (diff >= -128 && diff <= 127 + delta) {
32931
                    //put_u8(bc_out.buf + pos, diff);
32932
0
                    jp->size = 1;
32933
0
                    if (op == OP_goto16) {
32934
0
                        bc_out.buf[pos - 1] = jp->op = OP_goto8;
32935
0
                    } else {
32936
0
                        bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false);
32937
0
                    }
32938
0
                    goto shrink;
32939
0
                } else
32940
0
                if (diff == (int16_t)diff && op == OP_goto) {
32941
                    //put_u16(bc_out.buf + pos, diff);
32942
0
                    jp->size = 2;
32943
0
                    delta = 2;
32944
0
                    bc_out.buf[pos - 1] = jp->op = OP_goto16;
32945
0
                shrink:
32946
                    /* XXX: should reduce complexity, using 2 finger copy scheme */
32947
0
                    memmove(bc_out.buf + pos + jp->size, bc_out.buf + pos + jp->size + delta,
32948
0
                            bc_out.size - pos - jp->size - delta);
32949
0
                    bc_out.size -= delta;
32950
0
                    patch_offsets++;
32951
0
                    for (j = 0, ls = s->label_slots; j < s->label_count; j++, ls++) {
32952
0
                        if (ls->addr > pos)
32953
0
                            ls->addr -= delta;
32954
0
                    }
32955
0
                    for (j = i + 1, jp1 = jp + 1; j < s->jump_count; j++, jp1++) {
32956
0
                        if (jp1->pos > pos)
32957
0
                            jp1->pos -= delta;
32958
0
                    }
32959
0
                    for (j = 0; j < s->line_number_count; j++) {
32960
0
                        if (s->line_number_slots[j].pc > pos)
32961
0
                            s->line_number_slots[j].pc -= delta;
32962
0
                    }
32963
0
                    continue;
32964
0
                }
32965
0
                break;
32966
39
            }
32967
39
        }
32968
63
        if (patch_offsets) {
32969
0
            JumpSlot *jp1;
32970
0
            int j;
32971
0
            for (j = 0, jp1 = s->jump_slots; j < s->jump_count; j++, jp1++) {
32972
0
                int diff1 = s->label_slots[jp1->label].addr - jp1->pos;
32973
0
                switch (jp1->size) {
32974
0
                case 1:
32975
0
                    put_u8(bc_out.buf + jp1->pos, diff1);
32976
0
                    break;
32977
0
                case 2:
32978
0
                    put_u16(bc_out.buf + jp1->pos, diff1);
32979
0
                    break;
32980
0
                case 4:
32981
0
                    put_u32(bc_out.buf + jp1->pos, diff1);
32982
0
                    break;
32983
0
                }
32984
0
            }
32985
0
        }
32986
63
    }
32987
63
    js_free(ctx, s->jump_slots);
32988
63
    s->jump_slots = NULL;
32989
63
#endif
32990
63
    js_free(ctx, s->label_slots);
32991
63
    s->label_slots = NULL;
32992
    /* XXX: should delay until copying to runtime bytecode function */
32993
63
    compute_pc2line_info(s);
32994
63
    js_free(ctx, s->line_number_slots);
32995
63
    s->line_number_slots = NULL;
32996
    /* set the new byte code */
32997
63
    dbuf_free(&s->byte_code);
32998
63
    s->byte_code = bc_out;
32999
63
    s->use_short_opcodes = TRUE;
33000
63
    if (dbuf_error(&s->byte_code)) {
33001
0
        JS_ThrowOutOfMemory(ctx);
33002
0
        return -1;
33003
0
    }
33004
63
    return 0;
33005
0
 fail:
33006
    /* XXX: not safe */
33007
0
    dbuf_free(&bc_out);
33008
0
    return -1;
33009
63
}
33010
33011
/* compute the maximum stack size needed by the function */
33012
33013
typedef struct StackSizeState {
33014
    int bc_len;
33015
    int stack_len_max;
33016
    uint16_t *stack_level_tab;
33017
    int32_t *catch_pos_tab;
33018
    int *pc_stack;
33019
    int pc_stack_len;
33020
    int pc_stack_size;
33021
} StackSizeState;
33022
33023
/* 'op' is only used for error indication */
33024
static __exception int ss_check(JSContext *ctx, StackSizeState *s,
33025
                                int pos, int op, int stack_len, int catch_pos)
33026
7.08M
{
33027
7.08M
    if ((unsigned)pos >= s->bc_len) {
33028
0
        JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
33029
0
        return -1;
33030
0
    }
33031
7.08M
    if (stack_len > s->stack_len_max) {
33032
0
        s->stack_len_max = stack_len;
33033
0
        if (s->stack_len_max > JS_STACK_SIZE_MAX) {
33034
0
            JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
33035
0
            return -1;
33036
0
        }
33037
0
    }
33038
7.08M
    if (s->stack_level_tab[pos] != 0xffff) {
33039
        /* already explored: check that the stack size is consistent */
33040
0
        if (s->stack_level_tab[pos] != stack_len) {
33041
0
            JS_ThrowInternalError(ctx, "inconsistent stack size: %d %d (pc=%d)",
33042
0
                                  s->stack_level_tab[pos], stack_len, pos);
33043
0
            return -1;
33044
0
        } else if (s->catch_pos_tab[pos] != catch_pos) {
33045
0
            JS_ThrowInternalError(ctx, "inconsistent catch position: %d %d (pc=%d)",
33046
0
                                  s->catch_pos_tab[pos], catch_pos, pos);
33047
0
            return -1;
33048
0
        } else {
33049
0
            return 0;
33050
0
        }
33051
0
    }
33052
33053
    /* mark as explored and store the stack size */
33054
7.08M
    s->stack_level_tab[pos] = stack_len;
33055
7.08M
    s->catch_pos_tab[pos] = catch_pos;
33056
33057
    /* queue the new PC to explore */
33058
7.08M
    if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]),
33059
7.08M
                        &s->pc_stack_size, s->pc_stack_len + 1))
33060
0
        return -1;
33061
7.08M
    s->pc_stack[s->pc_stack_len++] = pos;
33062
7.08M
    return 0;
33063
7.08M
}
33064
33065
static __exception int compute_stack_size(JSContext *ctx,
33066
                                          JSFunctionDef *fd,
33067
                                          int *pstack_size)
33068
63
{
33069
63
    StackSizeState s_s, *s = &s_s;
33070
63
    int i, diff, n_pop, pos_next, stack_len, pos, op, catch_pos, catch_level;
33071
63
    const JSOpCode *oi;
33072
63
    const uint8_t *bc_buf;
33073
33074
63
    bc_buf = fd->byte_code.buf;
33075
63
    s->bc_len = fd->byte_code.size;
33076
    /* bc_len > 0 */
33077
63
    s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) *
33078
63
                                   s->bc_len);
33079
63
    if (!s->stack_level_tab)
33080
0
        return -1;
33081
21.2M
    for(i = 0; i < s->bc_len; i++)
33082
21.2M
        s->stack_level_tab[i] = 0xffff;
33083
63
    s->pc_stack = NULL;
33084
63
    s->catch_pos_tab = js_malloc(ctx, sizeof(s->catch_pos_tab[0]) *
33085
63
                                   s->bc_len);
33086
63
    if (!s->catch_pos_tab)
33087
0
        goto fail;
33088
33089
63
    s->stack_len_max = 0;
33090
63
    s->pc_stack_len = 0;
33091
63
    s->pc_stack_size = 0;
33092
33093
    /* breadth-first graph exploration */
33094
63
    if (ss_check(ctx, s, 0, OP_invalid, 0, -1))
33095
0
        goto fail;
33096
33097
7.08M
    while (s->pc_stack_len > 0) {
33098
7.08M
        pos = s->pc_stack[--s->pc_stack_len];
33099
7.08M
        stack_len = s->stack_level_tab[pos];
33100
7.08M
        catch_pos = s->catch_pos_tab[pos];
33101
7.08M
        op = bc_buf[pos];
33102
7.08M
        if (op == 0 || op >= OP_COUNT) {
33103
0
            JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos);
33104
0
            goto fail;
33105
0
        }
33106
7.08M
        oi = &short_opcode_info(op);
33107
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 64)
33108
        printf("%5d: %10s %5d %5d\n", pos, oi->name, stack_len, catch_pos);
33109
#endif
33110
7.08M
        pos_next = pos + oi->size;
33111
7.08M
        if (pos_next > s->bc_len) {
33112
0
            JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
33113
0
            goto fail;
33114
0
        }
33115
7.08M
        n_pop = oi->n_pop;
33116
        /* call pops a variable number of arguments */
33117
7.08M
        if (oi->fmt == OP_FMT_npop || oi->fmt == OP_FMT_npop_u16) {
33118
14
            n_pop += get_u16(bc_buf + pos + 1);
33119
7.08M
        } else {
33120
7.08M
#if SHORT_OPCODES
33121
7.08M
            if (oi->fmt == OP_FMT_npopx) {
33122
0
                n_pop += op - OP_call0;
33123
0
            }
33124
7.08M
#endif
33125
7.08M
        }
33126
33127
7.08M
        if (stack_len < n_pop) {
33128
0
            JS_ThrowInternalError(ctx, "stack underflow (op=%d, pc=%d)", op, pos);
33129
0
            goto fail;
33130
0
        }
33131
7.08M
        stack_len += oi->n_push - n_pop;
33132
7.08M
        if (stack_len > s->stack_len_max) {
33133
321
            s->stack_len_max = stack_len;
33134
321
            if (s->stack_len_max > JS_STACK_SIZE_MAX) {
33135
0
                JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
33136
0
                goto fail;
33137
0
            }
33138
321
        }
33139
7.08M
        switch(op) {
33140
0
        case OP_tail_call:
33141
0
        case OP_tail_call_method:
33142
24
        case OP_return:
33143
63
        case OP_return_undef:
33144
102
        case OP_return_async:
33145
102
        case OP_throw:
33146
102
        case OP_throw_error:
33147
102
        case OP_ret:
33148
102
            goto done_insn;
33149
0
        case OP_goto:
33150
0
            diff = get_u32(bc_buf + pos + 1);
33151
0
            pos_next = pos + 1 + diff;
33152
0
            break;
33153
0
#if SHORT_OPCODES
33154
0
        case OP_goto16:
33155
0
            diff = (int16_t)get_u16(bc_buf + pos + 1);
33156
0
            pos_next = pos + 1 + diff;
33157
0
            break;
33158
0
        case OP_goto8:
33159
0
            diff = (int8_t)bc_buf[pos + 1];
33160
0
            pos_next = pos + 1 + diff;
33161
0
            break;
33162
0
        case OP_if_true8:
33163
39
        case OP_if_false8:
33164
39
            diff = (int8_t)bc_buf[pos + 1];
33165
39
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
33166
0
                goto fail;
33167
39
            break;
33168
39
#endif
33169
39
        case OP_if_true:
33170
0
        case OP_if_false:
33171
0
            diff = get_u32(bc_buf + pos + 1);
33172
0
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
33173
0
                goto fail;
33174
0
            break;
33175
0
        case OP_gosub:
33176
0
            diff = get_u32(bc_buf + pos + 1);
33177
0
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1, catch_pos))
33178
0
                goto fail;
33179
0
            break;
33180
0
        case OP_with_get_var:
33181
0
        case OP_with_delete_var:
33182
0
            diff = get_u32(bc_buf + pos + 5);
33183
0
            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1, catch_pos))
33184
0
                goto fail;
33185
0
            break;
33186
0
        case OP_with_make_ref:
33187
0
        case OP_with_get_ref:
33188
0
        case OP_with_get_ref_undef:
33189
0
            diff = get_u32(bc_buf + pos + 5);
33190
0
            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2, catch_pos))
33191
0
                goto fail;
33192
0
            break;
33193
0
        case OP_with_put_var:
33194
0
            diff = get_u32(bc_buf + pos + 5);
33195
0
            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1, catch_pos))
33196
0
                goto fail;
33197
0
            break;
33198
0
        case OP_catch:
33199
0
            diff = get_u32(bc_buf + pos + 1);
33200
0
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
33201
0
                goto fail;
33202
0
            catch_pos = pos;
33203
0
            break;
33204
0
        case OP_for_of_start:
33205
0
        case OP_for_await_of_start:
33206
0
            catch_pos = pos;
33207
0
            break;
33208
            /* we assume the catch offset entry is only removed with
33209
               some op codes */
33210
0
        case OP_drop:
33211
0
            catch_level = stack_len;
33212
0
            goto check_catch;
33213
0
        case OP_nip:
33214
0
            catch_level = stack_len - 1;
33215
0
            goto check_catch;
33216
0
        case OP_nip1:
33217
0
            catch_level = stack_len - 1;
33218
0
            goto check_catch;
33219
0
        case OP_iterator_close:
33220
0
            catch_level = stack_len + 2;
33221
0
        check_catch:
33222
            /* Note: for for_of_start/for_await_of_start we consider
33223
               the catch offset is on the first stack entry instead of
33224
               the thirst */
33225
0
            if (catch_pos >= 0) {
33226
0
                int level;
33227
0
                level = s->stack_level_tab[catch_pos];
33228
0
                if (bc_buf[catch_pos] != OP_catch)
33229
0
                    level++; /* for_of_start, for_wait_of_start */
33230
                /* catch_level = stack_level before op_catch is executed ? */
33231
0
                if (catch_level == level) {
33232
0
                    catch_pos = s->catch_pos_tab[catch_pos];
33233
0
                }
33234
0
            }
33235
0
            break;
33236
0
        case OP_nip_catch:
33237
0
            if (catch_pos < 0) {
33238
0
                JS_ThrowInternalError(ctx, "nip_catch: no catch op (pc=%d)", pos);
33239
0
                goto fail;
33240
0
            }
33241
0
            stack_len = s->stack_level_tab[catch_pos];
33242
0
            if (bc_buf[catch_pos] != OP_catch)
33243
0
                stack_len++; /* for_of_start, for_wait_of_start */
33244
0
            stack_len++; /* no stack overflow is possible by construction */
33245
0
            catch_pos = s->catch_pos_tab[catch_pos];
33246
0
            break;
33247
7.08M
        default:
33248
7.08M
            break;
33249
7.08M
        }
33250
7.08M
        if (ss_check(ctx, s, pos_next, op, stack_len, catch_pos))
33251
0
            goto fail;
33252
7.08M
    done_insn: ;
33253
7.08M
    }
33254
63
    js_free(ctx, s->pc_stack);
33255
63
    js_free(ctx, s->catch_pos_tab);
33256
63
    js_free(ctx, s->stack_level_tab);
33257
63
    *pstack_size = s->stack_len_max;
33258
63
    return 0;
33259
0
 fail:
33260
0
    js_free(ctx, s->pc_stack);
33261
0
    js_free(ctx, s->catch_pos_tab);
33262
0
    js_free(ctx, s->stack_level_tab);
33263
0
    *pstack_size = 0;
33264
0
    return -1;
33265
63
}
33266
33267
static int add_module_variables(JSContext *ctx, JSFunctionDef *fd)
33268
39
{
33269
39
    int i, idx;
33270
39
    JSModuleDef *m = fd->module;
33271
39
    JSExportEntry *me;
33272
39
    JSGlobalVar *hf;
33273
33274
    /* The imported global variables were added as closure variables
33275
       in js_parse_import(). We add here the module global
33276
       variables. */
33277
33278
39
    for(i = 0; i < fd->global_var_count; i++) {
33279
0
        hf = &fd->global_vars[i];
33280
0
        if (add_closure_var(ctx, fd, TRUE, FALSE, i, hf->var_name, hf->is_const,
33281
0
                            hf->is_lexical, FALSE) < 0)
33282
0
            return -1;
33283
0
    }
33284
33285
    /* resolve the variable names of the local exports */
33286
39
    for(i = 0; i < m->export_entries_count; i++) {
33287
0
        me = &m->export_entries[i];
33288
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
33289
0
            idx = find_closure_var(ctx, fd, me->local_name);
33290
0
            if (idx < 0) {
33291
0
                JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does not exist",
33292
0
                                        me->local_name);
33293
0
                return -1;
33294
0
            }
33295
0
            me->u.local.var_idx = idx;
33296
0
        }
33297
0
    }
33298
39
    return 0;
33299
39
}
33300
33301
/* create a function object from a function definition. The function
33302
   definition is freed. All the child functions are also created. It
33303
   must be done this way to resolve all the variables. */
33304
static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
33305
63
{
33306
63
    JSValue func_obj;
33307
63
    JSFunctionBytecode *b;
33308
63
    struct list_head *el, *el1;
33309
63
    int stack_size, scope, idx;
33310
63
    int function_size, byte_code_offset, cpool_offset;
33311
63
    int closure_var_offset, vardefs_offset;
33312
33313
    /* recompute scope linkage */
33314
189
    for (scope = 0; scope < fd->scope_count; scope++) {
33315
126
        fd->scopes[scope].first = -1;
33316
126
    }
33317
63
    if (fd->has_parameter_expressions) {
33318
        /* special end of variable list marker for the argument scope */
33319
0
        fd->scopes[ARG_SCOPE_INDEX].first = ARG_SCOPE_END;
33320
0
    }
33321
87
    for (idx = 0; idx < fd->var_count; idx++) {
33322
24
        JSVarDef *vd = &fd->vars[idx];
33323
24
        vd->scope_next = fd->scopes[vd->scope_level].first;
33324
24
        fd->scopes[vd->scope_level].first = idx;
33325
24
    }
33326
63
    for (scope = 2; scope < fd->scope_count; scope++) {
33327
0
        JSVarScope *sd = &fd->scopes[scope];
33328
0
        if (sd->first < 0)
33329
0
            sd->first = fd->scopes[sd->parent].first;
33330
0
    }
33331
87
    for (idx = 0; idx < fd->var_count; idx++) {
33332
24
        JSVarDef *vd = &fd->vars[idx];
33333
24
        if (vd->scope_next < 0 && vd->scope_level > 1) {
33334
0
            scope = fd->scopes[vd->scope_level].parent;
33335
0
            vd->scope_next = fd->scopes[scope].first;
33336
0
        }
33337
24
    }
33338
33339
    /* if the function contains an eval call, the closure variables
33340
       are used to compile the eval and they must be ordered by scope,
33341
       so it is necessary to create the closure variables before any
33342
       other variable lookup is done. */
33343
63
    if (fd->has_eval_call)
33344
0
        add_eval_variables(ctx, fd);
33345
33346
    /* add the module global variables in the closure */
33347
63
    if (fd->module) {
33348
39
        if (add_module_variables(ctx, fd))
33349
0
            goto fail;
33350
39
    }
33351
33352
    /* first create all the child functions */
33353
63
    list_for_each_safe(el, el1, &fd->child_list) {
33354
0
        JSFunctionDef *fd1;
33355
0
        int cpool_idx;
33356
33357
0
        fd1 = list_entry(el, JSFunctionDef, link);
33358
0
        cpool_idx = fd1->parent_cpool_idx;
33359
0
        func_obj = js_create_function(ctx, fd1);
33360
0
        if (JS_IsException(func_obj))
33361
0
            goto fail;
33362
        /* save it in the constant pool */
33363
0
        assert(cpool_idx >= 0);
33364
0
        fd->cpool[cpool_idx] = func_obj;
33365
0
    }
33366
33367
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 4)
33368
    if (!(fd->js_mode & JS_MODE_STRIP)) {
33369
        printf("pass 1\n");
33370
        dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size,
33371
                       fd->args, fd->arg_count, fd->vars, fd->var_count,
33372
                       fd->closure_var, fd->closure_var_count,
33373
                       fd->cpool, fd->cpool_count, fd->source, fd->line_num,
33374
                       fd->label_slots, NULL);
33375
        printf("\n");
33376
    }
33377
#endif
33378
33379
63
    if (resolve_variables(ctx, fd))
33380
0
        goto fail;
33381
33382
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 2)
33383
    if (!(fd->js_mode & JS_MODE_STRIP)) {
33384
        printf("pass 2\n");
33385
        dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size,
33386
                       fd->args, fd->arg_count, fd->vars, fd->var_count,
33387
                       fd->closure_var, fd->closure_var_count,
33388
                       fd->cpool, fd->cpool_count, fd->source, fd->line_num,
33389
                       fd->label_slots, NULL);
33390
        printf("\n");
33391
    }
33392
#endif
33393
33394
63
    if (resolve_labels(ctx, fd))
33395
0
        goto fail;
33396
33397
63
    if (compute_stack_size(ctx, fd, &stack_size) < 0)
33398
0
        goto fail;
33399
33400
63
    if (fd->js_mode & JS_MODE_STRIP) {
33401
0
        function_size = offsetof(JSFunctionBytecode, debug);
33402
63
    } else {
33403
63
        function_size = sizeof(*b);
33404
63
    }
33405
63
    cpool_offset = function_size;
33406
63
    function_size += fd->cpool_count * sizeof(*fd->cpool);
33407
63
    vardefs_offset = function_size;
33408
63
    if (!(fd->js_mode & JS_MODE_STRIP) || fd->has_eval_call) {
33409
63
        function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs);
33410
63
    }
33411
63
    closure_var_offset = function_size;
33412
63
    function_size += fd->closure_var_count * sizeof(*fd->closure_var);
33413
63
    byte_code_offset = function_size;
33414
63
    function_size += fd->byte_code.size;
33415
33416
63
    b = js_mallocz(ctx, function_size);
33417
63
    if (!b)
33418
0
        goto fail;
33419
63
    b->header.ref_count = 1;
33420
33421
63
    b->byte_code_buf = (void *)((uint8_t*)b + byte_code_offset);
33422
63
    b->byte_code_len = fd->byte_code.size;
33423
63
    memcpy(b->byte_code_buf, fd->byte_code.buf, fd->byte_code.size);
33424
63
    js_free(ctx, fd->byte_code.buf);
33425
63
    fd->byte_code.buf = NULL;
33426
33427
63
    b->func_name = fd->func_name;
33428
63
    if (fd->arg_count + fd->var_count > 0) {
33429
24
        if ((fd->js_mode & JS_MODE_STRIP) && !fd->has_eval_call) {
33430
            /* Strip variable definitions not needed at runtime */
33431
0
            int i;
33432
0
            for(i = 0; i < fd->var_count; i++) {
33433
0
                JS_FreeAtom(ctx, fd->vars[i].var_name);
33434
0
            }
33435
0
            for(i = 0; i < fd->arg_count; i++) {
33436
0
                JS_FreeAtom(ctx, fd->args[i].var_name);
33437
0
            }
33438
0
            for(i = 0; i < fd->closure_var_count; i++) {
33439
0
                JS_FreeAtom(ctx, fd->closure_var[i].var_name);
33440
0
                fd->closure_var[i].var_name = JS_ATOM_NULL;
33441
0
            }
33442
24
        } else {
33443
24
            b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
33444
24
            memcpy_no_ub(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
33445
24
            memcpy_no_ub(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
33446
24
        }
33447
24
        b->var_count = fd->var_count;
33448
24
        b->arg_count = fd->arg_count;
33449
24
        b->defined_arg_count = fd->defined_arg_count;
33450
24
        js_free(ctx, fd->args);
33451
24
        js_free(ctx, fd->vars);
33452
24
    }
33453
63
    b->cpool_count = fd->cpool_count;
33454
63
    if (b->cpool_count) {
33455
0
        b->cpool = (void *)((uint8_t*)b + cpool_offset);
33456
0
        memcpy(b->cpool, fd->cpool, b->cpool_count * sizeof(*b->cpool));
33457
0
    }
33458
63
    js_free(ctx, fd->cpool);
33459
63
    fd->cpool = NULL;
33460
33461
63
    b->stack_size = stack_size;
33462
33463
63
    if (fd->js_mode & JS_MODE_STRIP) {
33464
0
        JS_FreeAtom(ctx, fd->filename);
33465
0
        dbuf_free(&fd->pc2line);    // probably useless
33466
63
    } else {
33467
        /* XXX: source and pc2line info should be packed at the end of the
33468
           JSFunctionBytecode structure, avoiding allocation overhead
33469
         */
33470
63
        b->has_debug = 1;
33471
63
        b->debug.filename = fd->filename;
33472
63
        b->debug.line_num = fd->line_num;
33473
33474
        //DynBuf pc2line;
33475
        //compute_pc2line_info(fd, &pc2line);
33476
        //js_free(ctx, fd->line_number_slots)
33477
63
        b->debug.pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size);
33478
63
        if (!b->debug.pc2line_buf)
33479
19
            b->debug.pc2line_buf = fd->pc2line.buf;
33480
63
        b->debug.pc2line_len = fd->pc2line.size;
33481
63
        b->debug.source = fd->source;
33482
63
        b->debug.source_len = fd->source_len;
33483
63
    }
33484
63
    if (fd->scopes != fd->def_scope_array)
33485
0
        js_free(ctx, fd->scopes);
33486
33487
63
    b->closure_var_count = fd->closure_var_count;
33488
63
    if (b->closure_var_count) {
33489
39
        b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
33490
39
        memcpy(b->closure_var, fd->closure_var, b->closure_var_count * sizeof(*b->closure_var));
33491
39
    }
33492
63
    js_free(ctx, fd->closure_var);
33493
63
    fd->closure_var = NULL;
33494
33495
63
    b->has_prototype = fd->has_prototype;
33496
63
    b->has_simple_parameter_list = fd->has_simple_parameter_list;
33497
63
    b->js_mode = fd->js_mode;
33498
63
    b->is_derived_class_constructor = fd->is_derived_class_constructor;
33499
63
    b->func_kind = fd->func_kind;
33500
63
    b->need_home_object = (fd->home_object_var_idx >= 0 ||
33501
63
                           fd->need_home_object);
33502
63
    b->new_target_allowed = fd->new_target_allowed;
33503
63
    b->super_call_allowed = fd->super_call_allowed;
33504
63
    b->super_allowed = fd->super_allowed;
33505
63
    b->arguments_allowed = fd->arguments_allowed;
33506
63
    b->backtrace_barrier = fd->backtrace_barrier;
33507
63
    b->is_direct_or_indirect_eval = (fd->eval_type == JS_EVAL_TYPE_DIRECT ||
33508
63
                                     fd->eval_type == JS_EVAL_TYPE_INDIRECT);
33509
63
    b->realm = JS_DupContext(ctx);
33510
33511
63
    add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
33512
33513
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 1)
33514
    if (!(fd->js_mode & JS_MODE_STRIP)) {
33515
        js_dump_function_bytecode(ctx, b);
33516
    }
33517
#endif
33518
33519
63
    if (fd->parent) {
33520
        /* remove from parent list */
33521
0
        list_del(&fd->link);
33522
0
    }
33523
33524
63
    js_free(ctx, fd);
33525
63
    return JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
33526
0
 fail:
33527
0
    js_free_function_def(ctx, fd);
33528
0
    return JS_EXCEPTION;
33529
63
}
33530
33531
static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)
33532
63
{
33533
63
    int i;
33534
33535
#if 0
33536
    {
33537
        char buf[ATOM_GET_STR_BUF_SIZE];
33538
        printf("freeing %s\n",
33539
               JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
33540
    }
33541
#endif
33542
63
    free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE);
33543
33544
63
    if (b->vardefs) {
33545
48
        for(i = 0; i < b->arg_count + b->var_count; i++) {
33546
24
            JS_FreeAtomRT(rt, b->vardefs[i].var_name);
33547
24
        }
33548
24
    }
33549
63
    for(i = 0; i < b->cpool_count; i++)
33550
0
        JS_FreeValueRT(rt, b->cpool[i]);
33551
33552
141
    for(i = 0; i < b->closure_var_count; i++) {
33553
78
        JSClosureVar *cv = &b->closure_var[i];
33554
78
        JS_FreeAtomRT(rt, cv->var_name);
33555
78
    }
33556
63
    if (b->realm)
33557
63
        JS_FreeContext(b->realm);
33558
33559
63
    JS_FreeAtomRT(rt, b->func_name);
33560
63
    if (b->has_debug) {
33561
63
        JS_FreeAtomRT(rt, b->debug.filename);
33562
63
        js_free_rt(rt, b->debug.pc2line_buf);
33563
63
        js_free_rt(rt, b->debug.source);
33564
63
    }
33565
33566
63
    remove_gc_object(&b->header);
33567
63
    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && b->header.ref_count != 0) {
33568
12
        list_add_tail(&b->header.link, &rt->gc_zero_ref_count_list);
33569
51
    } else {
33570
51
        js_free_rt(rt, b);
33571
51
    }
33572
63
}
33573
33574
static __exception int js_parse_directives(JSParseState *s)
33575
77
{
33576
77
    char str[20];
33577
77
    JSParsePos pos;
33578
77
    BOOL has_semi;
33579
33580
77
    if (s->token.val != TOK_STRING)
33581
66
        return 0;
33582
33583
11
    js_parse_get_pos(s, &pos);
33584
33585
22
    while(s->token.val == TOK_STRING) {
33586
        /* Copy actual source string representation */
33587
11
        snprintf(str, sizeof str, "%.*s",
33588
11
                 (int)(s->buf_ptr - s->token.ptr - 2), s->token.ptr + 1);
33589
33590
11
        if (next_token(s))
33591
0
            return -1;
33592
33593
11
        has_semi = FALSE;
33594
11
        switch (s->token.val) {
33595
0
        case ';':
33596
0
            if (next_token(s))
33597
0
                return -1;
33598
0
            has_semi = TRUE;
33599
0
            break;
33600
0
        case '}':
33601
11
        case TOK_EOF:
33602
11
            has_semi = TRUE;
33603
11
            break;
33604
0
        case TOK_NUMBER:
33605
0
        case TOK_STRING:
33606
0
        case TOK_TEMPLATE:
33607
0
        case TOK_IDENT:
33608
0
        case TOK_REGEXP:
33609
0
        case TOK_DEC:
33610
0
        case TOK_INC:
33611
0
        case TOK_NULL:
33612
0
        case TOK_FALSE:
33613
0
        case TOK_TRUE:
33614
0
        case TOK_IF:
33615
0
        case TOK_RETURN:
33616
0
        case TOK_VAR:
33617
0
        case TOK_THIS:
33618
0
        case TOK_DELETE:
33619
0
        case TOK_TYPEOF:
33620
0
        case TOK_NEW:
33621
0
        case TOK_DO:
33622
0
        case TOK_WHILE:
33623
0
        case TOK_FOR:
33624
0
        case TOK_SWITCH:
33625
0
        case TOK_THROW:
33626
0
        case TOK_TRY:
33627
0
        case TOK_FUNCTION:
33628
0
        case TOK_DEBUGGER:
33629
0
        case TOK_WITH:
33630
0
        case TOK_CLASS:
33631
0
        case TOK_CONST:
33632
0
        case TOK_ENUM:
33633
0
        case TOK_EXPORT:
33634
0
        case TOK_IMPORT:
33635
0
        case TOK_SUPER:
33636
0
        case TOK_INTERFACE:
33637
0
        case TOK_LET:
33638
0
        case TOK_PACKAGE:
33639
0
        case TOK_PRIVATE:
33640
0
        case TOK_PROTECTED:
33641
0
        case TOK_PUBLIC:
33642
0
        case TOK_STATIC:
33643
            /* automatic insertion of ';' */
33644
0
            if (s->got_lf)
33645
0
                has_semi = TRUE;
33646
0
            break;
33647
0
        default:
33648
0
            break;
33649
11
        }
33650
11
        if (!has_semi)
33651
0
            break;
33652
11
        if (!strcmp(str, "use strict")) {
33653
0
            s->cur_func->has_use_strict = TRUE;
33654
0
            s->cur_func->js_mode |= JS_MODE_STRICT;
33655
0
        }
33656
11
#if !defined(DUMP_BYTECODE) || !(DUMP_BYTECODE & 8)
33657
11
        else if (!strcmp(str, "use strip")) {
33658
0
            s->cur_func->js_mode |= JS_MODE_STRIP;
33659
0
        }
33660
11
#endif
33661
11
#ifdef CONFIG_BIGNUM
33662
11
        else if (s->ctx->bignum_ext && !strcmp(str, "use math")) {
33663
0
            s->cur_func->js_mode |= JS_MODE_MATH;
33664
0
        }
33665
11
#endif
33666
11
    }
33667
11
    return js_parse_seek_token(s, &pos);
33668
11
}
33669
33670
static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
33671
                                         JSAtom func_name)
33672
0
{
33673
0
    JSAtom name;
33674
0
    int i, idx;
33675
33676
0
    if (fd->js_mode & JS_MODE_STRICT) {
33677
0
        if (!fd->has_simple_parameter_list && fd->has_use_strict) {
33678
0
            return js_parse_error(s, "\"use strict\" not allowed in function with default or destructuring parameter");
33679
0
        }
33680
0
        if (func_name == JS_ATOM_eval || func_name == JS_ATOM_arguments) {
33681
0
            return js_parse_error(s, "invalid function name in strict code");
33682
0
        }
33683
0
        for (idx = 0; idx < fd->arg_count; idx++) {
33684
0
            name = fd->args[idx].var_name;
33685
33686
0
            if (name == JS_ATOM_eval || name == JS_ATOM_arguments) {
33687
0
                return js_parse_error(s, "invalid argument name in strict code");
33688
0
            }
33689
0
        }
33690
0
    }
33691
    /* check async_generator case */
33692
0
    if ((fd->js_mode & JS_MODE_STRICT)
33693
0
    ||  !fd->has_simple_parameter_list
33694
0
    ||  (fd->func_type == JS_PARSE_FUNC_METHOD && fd->func_kind == JS_FUNC_ASYNC)
33695
0
    ||  fd->func_type == JS_PARSE_FUNC_ARROW
33696
0
    ||  fd->func_type == JS_PARSE_FUNC_METHOD) {
33697
0
        for (idx = 0; idx < fd->arg_count; idx++) {
33698
0
            name = fd->args[idx].var_name;
33699
0
            if (name != JS_ATOM_NULL) {
33700
0
                for (i = 0; i < idx; i++) {
33701
0
                    if (fd->args[i].var_name == name)
33702
0
                        goto duplicate;
33703
0
                }
33704
                /* Check if argument name duplicates a destructuring parameter */
33705
                /* XXX: should have a flag for such variables */
33706
0
                for (i = 0; i < fd->var_count; i++) {
33707
0
                    if (fd->vars[i].var_name == name &&
33708
0
                        fd->vars[i].scope_level == 0)
33709
0
                        goto duplicate;
33710
0
                }
33711
0
            }
33712
0
        }
33713
0
    }
33714
0
    return 0;
33715
33716
0
duplicate:
33717
0
    return js_parse_error(s, "duplicate argument names not allowed in this context");
33718
0
}
33719
33720
/* create a function to initialize class fields */
33721
static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s)
33722
0
{
33723
0
    JSFunctionDef *fd;
33724
33725
0
    fd = js_new_function_def(s->ctx, s->cur_func, FALSE, FALSE,
33726
0
                             s->filename, 0);
33727
0
    if (!fd)
33728
0
        return NULL;
33729
0
    fd->func_name = JS_ATOM_NULL;
33730
0
    fd->has_prototype = FALSE;
33731
0
    fd->has_home_object = TRUE;
33732
33733
0
    fd->has_arguments_binding = FALSE;
33734
0
    fd->has_this_binding = TRUE;
33735
0
    fd->is_derived_class_constructor = FALSE;
33736
0
    fd->new_target_allowed = TRUE;
33737
0
    fd->super_call_allowed = FALSE;
33738
0
    fd->super_allowed = fd->has_home_object;
33739
0
    fd->arguments_allowed = FALSE;
33740
33741
0
    fd->func_kind = JS_FUNC_NORMAL;
33742
0
    fd->func_type = JS_PARSE_FUNC_METHOD;
33743
0
    return fd;
33744
0
}
33745
33746
/* func_name must be JS_ATOM_NULL for JS_PARSE_FUNC_STATEMENT and
33747
   JS_PARSE_FUNC_EXPR, JS_PARSE_FUNC_ARROW and JS_PARSE_FUNC_VAR */
33748
static __exception int js_parse_function_decl2(JSParseState *s,
33749
                                               JSParseFunctionEnum func_type,
33750
                                               JSFunctionKindEnum func_kind,
33751
                                               JSAtom func_name,
33752
                                               const uint8_t *ptr,
33753
                                               int function_line_num,
33754
                                               JSParseExportEnum export_flag,
33755
                                               JSFunctionDef **pfd)
33756
0
{
33757
0
    JSContext *ctx = s->ctx;
33758
0
    JSFunctionDef *fd = s->cur_func;
33759
0
    BOOL is_expr;
33760
0
    int func_idx, lexical_func_idx = -1;
33761
0
    BOOL has_opt_arg;
33762
0
    BOOL create_func_var = FALSE;
33763
33764
0
    is_expr = (func_type != JS_PARSE_FUNC_STATEMENT &&
33765
0
               func_type != JS_PARSE_FUNC_VAR);
33766
33767
0
    if (func_type == JS_PARSE_FUNC_STATEMENT ||
33768
0
        func_type == JS_PARSE_FUNC_VAR ||
33769
0
        func_type == JS_PARSE_FUNC_EXPR) {
33770
0
        if (func_kind == JS_FUNC_NORMAL &&
33771
0
            token_is_pseudo_keyword(s, JS_ATOM_async) &&
33772
0
            peek_token(s, TRUE) != '\n') {
33773
0
            if (next_token(s))
33774
0
                return -1;
33775
0
            func_kind = JS_FUNC_ASYNC;
33776
0
        }
33777
0
        if (next_token(s))
33778
0
            return -1;
33779
0
        if (s->token.val == '*') {
33780
0
            if (next_token(s))
33781
0
                return -1;
33782
0
            func_kind |= JS_FUNC_GENERATOR;
33783
0
        }
33784
33785
0
        if (s->token.val == TOK_IDENT) {
33786
0
            if (s->token.u.ident.is_reserved ||
33787
0
                (s->token.u.ident.atom == JS_ATOM_yield &&
33788
0
                 func_type == JS_PARSE_FUNC_EXPR &&
33789
0
                 (func_kind & JS_FUNC_GENERATOR)) ||
33790
0
                (s->token.u.ident.atom == JS_ATOM_await &&
33791
0
                 ((func_type == JS_PARSE_FUNC_EXPR &&
33792
0
                   (func_kind & JS_FUNC_ASYNC)) ||
33793
0
                  func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))) {
33794
0
                return js_parse_error_reserved_identifier(s);
33795
0
            }
33796
0
        }
33797
0
        if (s->token.val == TOK_IDENT ||
33798
0
            (((s->token.val == TOK_YIELD && !(fd->js_mode & JS_MODE_STRICT)) ||
33799
0
             (s->token.val == TOK_AWAIT && !s->is_module)) &&
33800
0
             func_type == JS_PARSE_FUNC_EXPR)) {
33801
0
            func_name = JS_DupAtom(ctx, s->token.u.ident.atom);
33802
0
            if (next_token(s)) {
33803
0
                JS_FreeAtom(ctx, func_name);
33804
0
                return -1;
33805
0
            }
33806
0
        } else {
33807
0
            if (func_type != JS_PARSE_FUNC_EXPR &&
33808
0
                export_flag != JS_PARSE_EXPORT_DEFAULT) {
33809
0
                return js_parse_error(s, "function name expected");
33810
0
            }
33811
0
        }
33812
0
    } else if (func_type != JS_PARSE_FUNC_ARROW) {
33813
0
        func_name = JS_DupAtom(ctx, func_name);
33814
0
    }
33815
33816
0
    if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_MODULE &&
33817
0
        (func_type == JS_PARSE_FUNC_STATEMENT || func_type == JS_PARSE_FUNC_VAR)) {
33818
0
        JSGlobalVar *hf;
33819
0
        hf = find_global_var(fd, func_name);
33820
        /* XXX: should check scope chain */
33821
0
        if (hf && hf->scope_level == fd->scope_level) {
33822
0
            js_parse_error(s, "invalid redefinition of global identifier in module code");
33823
0
            JS_FreeAtom(ctx, func_name);
33824
0
            return -1;
33825
0
        }
33826
0
    }
33827
33828
0
    if (func_type == JS_PARSE_FUNC_VAR) {
33829
0
        if (!(fd->js_mode & JS_MODE_STRICT)
33830
0
        && func_kind == JS_FUNC_NORMAL
33831
0
        &&  find_lexical_decl(ctx, fd, func_name, fd->scope_first, FALSE) < 0
33832
0
        &&  !((func_idx = find_var(ctx, fd, func_name)) >= 0 && (func_idx & ARGUMENT_VAR_OFFSET))
33833
0
        &&  !(func_name == JS_ATOM_arguments && fd->has_arguments_binding)) {
33834
0
            create_func_var = TRUE;
33835
0
        }
33836
        /* Create the lexical name here so that the function closure
33837
           contains it */
33838
0
        if (fd->is_eval &&
33839
0
            (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
33840
0
             fd->eval_type == JS_EVAL_TYPE_MODULE) &&
33841
0
            fd->scope_level == fd->body_scope) {
33842
            /* avoid creating a lexical variable in the global
33843
               scope. XXX: check annex B */
33844
0
            JSGlobalVar *hf;
33845
0
            hf = find_global_var(fd, func_name);
33846
            /* XXX: should check scope chain */
33847
0
            if (hf && hf->scope_level == fd->scope_level) {
33848
0
                js_parse_error(s, "invalid redefinition of global identifier");
33849
0
                JS_FreeAtom(ctx, func_name);
33850
0
                return -1;
33851
0
            }
33852
0
        } else {
33853
            /* Always create a lexical name, fail if at the same scope as
33854
               existing name */
33855
            /* Lexical variable will be initialized upon entering scope */
33856
0
            lexical_func_idx = define_var(s, fd, func_name,
33857
0
                                          func_kind != JS_FUNC_NORMAL ?
33858
0
                                          JS_VAR_DEF_NEW_FUNCTION_DECL :
33859
0
                                          JS_VAR_DEF_FUNCTION_DECL);
33860
0
            if (lexical_func_idx < 0) {
33861
0
                JS_FreeAtom(ctx, func_name);
33862
0
                return -1;
33863
0
            }
33864
0
        }
33865
0
    }
33866
33867
0
    fd = js_new_function_def(ctx, fd, FALSE, is_expr,
33868
0
                             s->filename, function_line_num);
33869
0
    if (!fd) {
33870
0
        JS_FreeAtom(ctx, func_name);
33871
0
        return -1;
33872
0
    }
33873
0
    if (pfd)
33874
0
        *pfd = fd;
33875
0
    s->cur_func = fd;
33876
0
    fd->func_name = func_name;
33877
    /* XXX: test !fd->is_generator is always false */
33878
0
    fd->has_prototype = (func_type == JS_PARSE_FUNC_STATEMENT ||
33879
0
                         func_type == JS_PARSE_FUNC_VAR ||
33880
0
                         func_type == JS_PARSE_FUNC_EXPR) &&
33881
0
                        func_kind == JS_FUNC_NORMAL;
33882
0
    fd->has_home_object = (func_type == JS_PARSE_FUNC_METHOD ||
33883
0
                           func_type == JS_PARSE_FUNC_GETTER ||
33884
0
                           func_type == JS_PARSE_FUNC_SETTER ||
33885
0
                           func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
33886
0
                           func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
33887
0
    fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW &&
33888
0
                                 func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT);
33889
0
    fd->has_this_binding = fd->has_arguments_binding;
33890
0
    fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
33891
0
    if (func_type == JS_PARSE_FUNC_ARROW) {
33892
0
        fd->new_target_allowed = fd->parent->new_target_allowed;
33893
0
        fd->super_call_allowed = fd->parent->super_call_allowed;
33894
0
        fd->super_allowed = fd->parent->super_allowed;
33895
0
        fd->arguments_allowed = fd->parent->arguments_allowed;
33896
0
    } else if (func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
33897
0
        fd->new_target_allowed = TRUE; // although new.target === undefined
33898
0
        fd->super_call_allowed = FALSE;
33899
0
        fd->super_allowed = TRUE;
33900
0
        fd->arguments_allowed = FALSE;
33901
0
    } else {
33902
0
        fd->new_target_allowed = TRUE;
33903
0
        fd->super_call_allowed = fd->is_derived_class_constructor;
33904
0
        fd->super_allowed = fd->has_home_object;
33905
0
        fd->arguments_allowed = TRUE;
33906
0
    }
33907
33908
    /* fd->in_function_body == FALSE prevents yield/await during the parsing
33909
       of the arguments in generator/async functions. They are parsed as
33910
       regular identifiers for other function kinds. */
33911
0
    fd->func_kind = func_kind;
33912
0
    fd->func_type = func_type;
33913
33914
0
    if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
33915
0
        func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
33916
        /* error if not invoked as a constructor */
33917
0
        emit_op(s, OP_check_ctor);
33918
0
    }
33919
33920
0
    if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
33921
0
        emit_class_field_init(s);
33922
0
    }
33923
33924
    /* parse arguments */
33925
0
    fd->has_simple_parameter_list = TRUE;
33926
0
    fd->has_parameter_expressions = FALSE;
33927
0
    has_opt_arg = FALSE;
33928
0
    if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) {
33929
0
        JSAtom name;
33930
0
        if (s->token.u.ident.is_reserved) {
33931
0
            js_parse_error_reserved_identifier(s);
33932
0
            goto fail;
33933
0
        }
33934
0
        name = s->token.u.ident.atom;
33935
0
        if (add_arg(ctx, fd, name) < 0)
33936
0
            goto fail;
33937
0
        fd->defined_arg_count = 1;
33938
0
    } else if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
33939
0
        if (s->token.val == '(') {
33940
0
            int skip_bits;
33941
            /* if there is an '=' inside the parameter list, we
33942
               consider there is a parameter expression inside */
33943
0
            js_parse_skip_parens_token(s, &skip_bits, FALSE);
33944
0
            if (skip_bits & SKIP_HAS_ASSIGNMENT)
33945
0
                fd->has_parameter_expressions = TRUE;
33946
0
            if (next_token(s))
33947
0
                goto fail;
33948
0
        } else {
33949
0
            if (js_parse_expect(s, '('))
33950
0
                goto fail;
33951
0
        }
33952
33953
0
        if (fd->has_parameter_expressions) {
33954
0
            fd->scope_level = -1; /* force no parent scope */
33955
0
            if (push_scope(s) < 0)
33956
0
                return -1;
33957
0
        }
33958
33959
0
        while (s->token.val != ')') {
33960
0
            JSAtom name;
33961
0
            BOOL rest = FALSE;
33962
0
            int idx, has_initializer;
33963
33964
0
            if (s->token.val == TOK_ELLIPSIS) {
33965
0
                fd->has_simple_parameter_list = FALSE;
33966
0
                rest = TRUE;
33967
0
                if (next_token(s))
33968
0
                    goto fail;
33969
0
            }
33970
0
            if (s->token.val == '[' || s->token.val == '{') {
33971
0
                fd->has_simple_parameter_list = FALSE;
33972
0
                if (rest) {
33973
0
                    emit_op(s, OP_rest);
33974
0
                    emit_u16(s, fd->arg_count);
33975
0
                } else {
33976
                    /* unnamed arg for destructuring */
33977
0
                    idx = add_arg(ctx, fd, JS_ATOM_NULL);
33978
0
                    emit_op(s, OP_get_arg);
33979
0
                    emit_u16(s, idx);
33980
0
                }
33981
0
                has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE);
33982
0
                if (has_initializer < 0)
33983
0
                    goto fail;
33984
0
                if (has_initializer)
33985
0
                    has_opt_arg = TRUE;
33986
0
                if (!has_opt_arg)
33987
0
                    fd->defined_arg_count++;
33988
0
            } else if (s->token.val == TOK_IDENT) {
33989
0
                if (s->token.u.ident.is_reserved) {
33990
0
                    js_parse_error_reserved_identifier(s);
33991
0
                    goto fail;
33992
0
                }
33993
0
                name = s->token.u.ident.atom;
33994
0
                if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
33995
0
                    js_parse_error_reserved_identifier(s);
33996
0
                    goto fail;
33997
0
                }
33998
0
                if (fd->has_parameter_expressions) {
33999
0
                    if (js_parse_check_duplicate_parameter(s, name))
34000
0
                        goto fail;
34001
0
                    if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0)
34002
0
                        goto fail;
34003
0
                }
34004
                /* XXX: could avoid allocating an argument if rest is true */
34005
0
                idx = add_arg(ctx, fd, name);
34006
0
                if (idx < 0)
34007
0
                    goto fail;
34008
0
                if (next_token(s))
34009
0
                    goto fail;
34010
0
                if (rest) {
34011
0
                    emit_op(s, OP_rest);
34012
0
                    emit_u16(s, idx);
34013
0
                    if (fd->has_parameter_expressions) {
34014
0
                        emit_op(s, OP_dup);
34015
0
                        emit_op(s, OP_scope_put_var_init);
34016
0
                        emit_atom(s, name);
34017
0
                        emit_u16(s, fd->scope_level);
34018
0
                    }
34019
0
                    emit_op(s, OP_put_arg);
34020
0
                    emit_u16(s, idx);
34021
0
                    fd->has_simple_parameter_list = FALSE;
34022
0
                    has_opt_arg = TRUE;
34023
0
                } else if (s->token.val == '=') {
34024
0
                    int label;
34025
34026
0
                    fd->has_simple_parameter_list = FALSE;
34027
0
                    has_opt_arg = TRUE;
34028
34029
0
                    if (next_token(s))
34030
0
                        goto fail;
34031
34032
0
                    label = new_label(s);
34033
0
                    emit_op(s, OP_get_arg);
34034
0
                    emit_u16(s, idx);
34035
0
                    emit_op(s, OP_dup);
34036
0
                    emit_op(s, OP_undefined);
34037
0
                    emit_op(s, OP_strict_eq);
34038
0
                    emit_goto(s, OP_if_false, label);
34039
0
                    emit_op(s, OP_drop);
34040
0
                    if (js_parse_assign_expr(s))
34041
0
                        goto fail;
34042
0
                    set_object_name(s, name);
34043
0
                    emit_op(s, OP_dup);
34044
0
                    emit_op(s, OP_put_arg);
34045
0
                    emit_u16(s, idx);
34046
0
                    emit_label(s, label);
34047
0
                    emit_op(s, OP_scope_put_var_init);
34048
0
                    emit_atom(s, name);
34049
0
                    emit_u16(s, fd->scope_level);
34050
0
                } else {
34051
0
                    if (!has_opt_arg) {
34052
0
                        fd->defined_arg_count++;
34053
0
                    }
34054
0
                    if (fd->has_parameter_expressions) {
34055
                        /* copy the argument to the argument scope */
34056
0
                        emit_op(s, OP_get_arg);
34057
0
                        emit_u16(s, idx);
34058
0
                        emit_op(s, OP_scope_put_var_init);
34059
0
                        emit_atom(s, name);
34060
0
                        emit_u16(s, fd->scope_level);
34061
0
                    }
34062
0
                }
34063
0
            } else {
34064
0
                js_parse_error(s, "missing formal parameter");
34065
0
                goto fail;
34066
0
            }
34067
0
            if (rest && s->token.val != ')') {
34068
0
                js_parse_expect(s, ')');
34069
0
                goto fail;
34070
0
            }
34071
0
            if (s->token.val == ')')
34072
0
                break;
34073
0
            if (js_parse_expect(s, ','))
34074
0
                goto fail;
34075
0
        }
34076
0
        if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) ||
34077
0
            (func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) {
34078
0
            js_parse_error(s, "invalid number of arguments for getter or setter");
34079
0
            goto fail;
34080
0
        }
34081
0
    }
34082
34083
0
    if (fd->has_parameter_expressions) {
34084
0
        int idx;
34085
34086
        /* Copy the variables in the argument scope to the variable
34087
           scope (see FunctionDeclarationInstantiation() in spec). The
34088
           normal arguments are already present, so no need to copy
34089
           them. */
34090
0
        idx = fd->scopes[fd->scope_level].first;
34091
0
        while (idx >= 0) {
34092
0
            JSVarDef *vd = &fd->vars[idx];
34093
0
            if (vd->scope_level != fd->scope_level)
34094
0
                break;
34095
0
            if (find_var(ctx, fd, vd->var_name) < 0) {
34096
0
                if (add_var(ctx, fd, vd->var_name) < 0)
34097
0
                    goto fail;
34098
0
                vd = &fd->vars[idx]; /* fd->vars may have been reallocated */
34099
0
                emit_op(s, OP_scope_get_var);
34100
0
                emit_atom(s, vd->var_name);
34101
0
                emit_u16(s, fd->scope_level);
34102
0
                emit_op(s, OP_scope_put_var);
34103
0
                emit_atom(s, vd->var_name);
34104
0
                emit_u16(s, 0);
34105
0
            }
34106
0
            idx = vd->scope_next;
34107
0
        }
34108
34109
        /* the argument scope has no parent, hence we don't use pop_scope(s) */
34110
0
        emit_op(s, OP_leave_scope);
34111
0
        emit_u16(s, fd->scope_level);
34112
34113
        /* set the variable scope as the current scope */
34114
0
        fd->scope_level = 0;
34115
0
        fd->scope_first = fd->scopes[fd->scope_level].first;
34116
0
    }
34117
34118
0
    if (next_token(s))
34119
0
        goto fail;
34120
34121
    /* generator function: yield after the parameters are evaluated */
34122
0
    if (func_kind == JS_FUNC_GENERATOR ||
34123
0
        func_kind == JS_FUNC_ASYNC_GENERATOR)
34124
0
        emit_op(s, OP_initial_yield);
34125
34126
    /* in generators, yield expression is forbidden during the parsing
34127
       of the arguments */
34128
0
    fd->in_function_body = TRUE;
34129
0
    push_scope(s);  /* enter body scope */
34130
0
    fd->body_scope = fd->scope_level;
34131
34132
0
    if (s->token.val == TOK_ARROW) {
34133
0
        if (next_token(s))
34134
0
            goto fail;
34135
34136
0
        if (s->token.val != '{') {
34137
0
            if (js_parse_function_check_names(s, fd, func_name))
34138
0
                goto fail;
34139
34140
0
            if (js_parse_assign_expr(s))
34141
0
                goto fail;
34142
34143
0
            if (func_kind != JS_FUNC_NORMAL)
34144
0
                emit_op(s, OP_return_async);
34145
0
            else
34146
0
                emit_op(s, OP_return);
34147
34148
0
            if (!(fd->js_mode & JS_MODE_STRIP)) {
34149
                /* save the function source code */
34150
                /* the end of the function source code is after the last
34151
                   token of the function source stored into s->last_ptr */
34152
0
                fd->source_len = s->last_ptr - ptr;
34153
0
                fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
34154
0
                if (!fd->source)
34155
0
                    goto fail;
34156
0
            }
34157
0
            goto done;
34158
0
        }
34159
0
    }
34160
34161
0
    if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
34162
0
        if (js_parse_expect(s, '{'))
34163
0
            goto fail;
34164
0
    }
34165
34166
0
    if (js_parse_directives(s))
34167
0
        goto fail;
34168
34169
    /* in strict_mode, check function and argument names */
34170
0
    if (js_parse_function_check_names(s, fd, func_name))
34171
0
        goto fail;
34172
34173
0
    while (s->token.val != '}') {
34174
0
        if (js_parse_source_element(s))
34175
0
            goto fail;
34176
0
    }
34177
0
    if (!(fd->js_mode & JS_MODE_STRIP)) {
34178
        /* save the function source code */
34179
0
        fd->source_len = s->buf_ptr - ptr;
34180
0
        fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
34181
0
        if (!fd->source)
34182
0
            goto fail;
34183
0
    }
34184
34185
0
    if (next_token(s)) {
34186
        /* consume the '}' */
34187
0
        goto fail;
34188
0
    }
34189
34190
    /* in case there is no return, add one */
34191
0
    if (js_is_live_code(s)) {
34192
0
        emit_return(s, FALSE);
34193
0
    }
34194
0
 done:
34195
0
    s->cur_func = fd->parent;
34196
34197
    /* Reparse identifiers after the function is terminated so that
34198
       the token is parsed in the englobing function. It could be done
34199
       by just using next_token() here for normal functions, but it is
34200
       necessary for arrow functions with an expression body. */
34201
0
    reparse_ident_token(s);
34202
34203
    /* create the function object */
34204
0
    {
34205
0
        int idx;
34206
0
        JSAtom func_name = fd->func_name;
34207
34208
        /* the real object will be set at the end of the compilation */
34209
0
        idx = cpool_add(s, JS_NULL);
34210
0
        fd->parent_cpool_idx = idx;
34211
34212
0
        if (is_expr) {
34213
            /* for constructors, no code needs to be generated here */
34214
0
            if (func_type != JS_PARSE_FUNC_CLASS_CONSTRUCTOR &&
34215
0
                func_type != JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
34216
                /* OP_fclosure creates the function object from the bytecode
34217
                   and adds the scope information */
34218
0
                emit_op(s, OP_fclosure);
34219
0
                emit_u32(s, idx);
34220
0
                if (func_name == JS_ATOM_NULL) {
34221
0
                    emit_op(s, OP_set_name);
34222
0
                    emit_u32(s, JS_ATOM_NULL);
34223
0
                }
34224
0
            }
34225
0
        } else if (func_type == JS_PARSE_FUNC_VAR) {
34226
0
            emit_op(s, OP_fclosure);
34227
0
            emit_u32(s, idx);
34228
0
            if (create_func_var) {
34229
0
                if (s->cur_func->is_global_var) {
34230
0
                    JSGlobalVar *hf;
34231
                    /* the global variable must be defined at the start of the
34232
                       function */
34233
0
                    hf = add_global_var(ctx, s->cur_func, func_name);
34234
0
                    if (!hf)
34235
0
                        goto fail;
34236
                    /* it is considered as defined at the top level
34237
                       (needed for annex B.3.3.4 and B.3.3.5
34238
                       checks) */
34239
0
                    hf->scope_level = 0;
34240
0
                    hf->force_init = ((s->cur_func->js_mode & JS_MODE_STRICT) != 0);
34241
                    /* store directly into global var, bypass lexical scope */
34242
0
                    emit_op(s, OP_dup);
34243
0
                    emit_op(s, OP_scope_put_var);
34244
0
                    emit_atom(s, func_name);
34245
0
                    emit_u16(s, 0);
34246
0
                } else {
34247
                    /* do not call define_var to bypass lexical scope check */
34248
0
                    func_idx = find_var(ctx, s->cur_func, func_name);
34249
0
                    if (func_idx < 0) {
34250
0
                        func_idx = add_var(ctx, s->cur_func, func_name);
34251
0
                        if (func_idx < 0)
34252
0
                            goto fail;
34253
0
                    }
34254
                    /* store directly into local var, bypass lexical catch scope */
34255
0
                    emit_op(s, OP_dup);
34256
0
                    emit_op(s, OP_scope_put_var);
34257
0
                    emit_atom(s, func_name);
34258
0
                    emit_u16(s, 0);
34259
0
                }
34260
0
            }
34261
0
            if (lexical_func_idx >= 0) {
34262
                /* lexical variable will be initialized upon entering scope */
34263
0
                s->cur_func->vars[lexical_func_idx].func_pool_idx = idx;
34264
0
                emit_op(s, OP_drop);
34265
0
            } else {
34266
                /* store function object into its lexical name */
34267
                /* XXX: could use OP_put_loc directly */
34268
0
                emit_op(s, OP_scope_put_var_init);
34269
0
                emit_atom(s, func_name);
34270
0
                emit_u16(s, s->cur_func->scope_level);
34271
0
            }
34272
0
        } else {
34273
0
            if (!s->cur_func->is_global_var) {
34274
0
                int var_idx = define_var(s, s->cur_func, func_name, JS_VAR_DEF_VAR);
34275
34276
0
                if (var_idx < 0)
34277
0
                    goto fail;
34278
                /* the variable will be assigned at the top of the function */
34279
0
                if (var_idx & ARGUMENT_VAR_OFFSET) {
34280
0
                    s->cur_func->args[var_idx - ARGUMENT_VAR_OFFSET].func_pool_idx = idx;
34281
0
                } else {
34282
0
                    s->cur_func->vars[var_idx].func_pool_idx = idx;
34283
0
                }
34284
0
            } else {
34285
0
                JSAtom func_var_name;
34286
0
                JSGlobalVar *hf;
34287
0
                if (func_name == JS_ATOM_NULL)
34288
0
                    func_var_name = JS_ATOM__default_; /* export default */
34289
0
                else
34290
0
                    func_var_name = func_name;
34291
                /* the variable will be assigned at the top of the function */
34292
0
                hf = add_global_var(ctx, s->cur_func, func_var_name);
34293
0
                if (!hf)
34294
0
                    goto fail;
34295
0
                hf->cpool_idx = idx;
34296
0
                if (export_flag != JS_PARSE_EXPORT_NONE) {
34297
0
                    if (!add_export_entry(s, s->cur_func->module, func_var_name,
34298
0
                                          export_flag == JS_PARSE_EXPORT_NAMED ? func_var_name : JS_ATOM_default, JS_EXPORT_TYPE_LOCAL))
34299
0
                        goto fail;
34300
0
                }
34301
0
            }
34302
0
        }
34303
0
    }
34304
0
    return 0;
34305
0
 fail:
34306
0
    s->cur_func = fd->parent;
34307
0
    js_free_function_def(ctx, fd);
34308
0
    if (pfd)
34309
0
        *pfd = NULL;
34310
0
    return -1;
34311
0
}
34312
34313
static __exception int js_parse_function_decl(JSParseState *s,
34314
                                              JSParseFunctionEnum func_type,
34315
                                              JSFunctionKindEnum func_kind,
34316
                                              JSAtom func_name,
34317
                                              const uint8_t *ptr,
34318
                                              int function_line_num)
34319
0
{
34320
0
    return js_parse_function_decl2(s, func_type, func_kind, func_name, ptr,
34321
0
                                   function_line_num, JS_PARSE_EXPORT_NONE,
34322
0
                                   NULL);
34323
0
}
34324
34325
static __exception int js_parse_program(JSParseState *s)
34326
78
{
34327
78
    JSFunctionDef *fd = s->cur_func;
34328
78
    int idx;
34329
34330
78
    if (next_token(s))
34331
1
        return -1;
34332
34333
77
    if (js_parse_directives(s))
34334
0
        return -1;
34335
34336
77
    fd->is_global_var = (fd->eval_type == JS_EVAL_TYPE_GLOBAL) ||
34337
77
        (fd->eval_type == JS_EVAL_TYPE_MODULE) ||
34338
77
        !(fd->js_mode & JS_MODE_STRICT);
34339
34340
77
    if (!s->is_module) {
34341
        /* hidden variable for the return value */
34342
36
        fd->eval_ret_idx = idx = add_var(s->ctx, fd, JS_ATOM__ret_);
34343
36
        if (idx < 0)
34344
0
            return -1;
34345
36
    }
34346
34347
259
    while (s->token.val != TOK_EOF) {
34348
196
        if (js_parse_source_element(s))
34349
14
            return -1;
34350
196
    }
34351
34352
63
    if (!s->is_module) {
34353
        /* return the value of the hidden variable eval_ret_idx  */
34354
24
        if (fd->func_kind == JS_FUNC_ASYNC) {
34355
            /* wrap the return value in an object so that promises can
34356
               be safely returned */
34357
0
            emit_op(s, OP_object);
34358
0
            emit_op(s, OP_dup);
34359
34360
0
            emit_op(s, OP_get_loc);
34361
0
            emit_u16(s, fd->eval_ret_idx);
34362
34363
0
            emit_op(s, OP_put_field);
34364
0
            emit_atom(s, JS_ATOM_value);
34365
24
        } else {
34366
24
            emit_op(s, OP_get_loc);
34367
24
            emit_u16(s, fd->eval_ret_idx);
34368
24
        }
34369
24
        emit_return(s, TRUE);
34370
39
    } else {
34371
39
        emit_return(s, FALSE);
34372
39
    }
34373
34374
63
    return 0;
34375
77
}
34376
34377
static void js_parse_init(JSContext *ctx, JSParseState *s,
34378
                          const char *input, size_t input_len,
34379
                          const char *filename)
34380
78
{
34381
78
    memset(s, 0, sizeof(*s));
34382
78
    s->ctx = ctx;
34383
78
    s->filename = filename;
34384
78
    s->line_num = 1;
34385
78
    s->buf_ptr = (const uint8_t *)input;
34386
78
    s->buf_end = s->buf_ptr + input_len;
34387
78
    s->token.val = ' ';
34388
78
    s->token.line_num = 1;
34389
78
}
34390
34391
static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,
34392
                                       JSValueConst this_obj,
34393
                                       JSVarRef **var_refs, JSStackFrame *sf)
34394
63
{
34395
63
    JSValue ret_val;
34396
63
    uint32_t tag;
34397
34398
63
    tag = JS_VALUE_GET_TAG(fun_obj);
34399
63
    if (tag == JS_TAG_FUNCTION_BYTECODE) {
34400
24
        fun_obj = js_closure(ctx, fun_obj, var_refs, sf);
34401
24
        ret_val = JS_CallFree(ctx, fun_obj, this_obj, 0, NULL);
34402
39
    } else if (tag == JS_TAG_MODULE) {
34403
39
        JSModuleDef *m;
34404
39
        m = JS_VALUE_GET_PTR(fun_obj);
34405
        /* the module refcount should be >= 2 */
34406
39
        JS_FreeValue(ctx, fun_obj);
34407
39
        if (js_create_module_function(ctx, m) < 0)
34408
0
            goto fail;
34409
39
        if (js_link_module(ctx, m) < 0)
34410
0
            goto fail;
34411
39
        ret_val = js_evaluate_module(ctx, m);
34412
39
        if (JS_IsException(ret_val)) {
34413
0
        fail:
34414
0
            return JS_EXCEPTION;
34415
0
        }
34416
39
    } else {
34417
0
        JS_FreeValue(ctx, fun_obj);
34418
0
        ret_val = JS_ThrowTypeError(ctx, "bytecode function expected");
34419
0
    }
34420
63
    return ret_val;
34421
63
}
34422
34423
JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj)
34424
39
{
34425
39
    return JS_EvalFunctionInternal(ctx, fun_obj, ctx->global_obj, NULL, NULL);
34426
39
}
34427
34428
/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
34429
static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
34430
                                 const char *input, size_t input_len,
34431
                                 const char *filename, int flags, int scope_idx)
34432
78
{
34433
78
    JSParseState s1, *s = &s1;
34434
78
    int err, js_mode, eval_type;
34435
78
    JSValue fun_obj, ret_val;
34436
78
    JSStackFrame *sf;
34437
78
    JSVarRef **var_refs;
34438
78
    JSFunctionBytecode *b;
34439
78
    JSFunctionDef *fd;
34440
78
    JSModuleDef *m;
34441
34442
78
    js_parse_init(ctx, s, input, input_len, filename);
34443
78
    skip_shebang(&s->buf_ptr, s->buf_end);
34444
34445
78
    eval_type = flags & JS_EVAL_TYPE_MASK;
34446
78
    m = NULL;
34447
78
    if (eval_type == JS_EVAL_TYPE_DIRECT) {
34448
0
        JSObject *p;
34449
0
        sf = ctx->rt->current_stack_frame;
34450
0
        assert(sf != NULL);
34451
0
        assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT);
34452
0
        p = JS_VALUE_GET_OBJ(sf->cur_func);
34453
0
        assert(js_class_has_bytecode(p->class_id));
34454
0
        b = p->u.func.function_bytecode;
34455
0
        var_refs = p->u.func.var_refs;
34456
0
        js_mode = b->js_mode;
34457
78
    } else {
34458
78
        sf = NULL;
34459
78
        b = NULL;
34460
78
        var_refs = NULL;
34461
78
        js_mode = 0;
34462
78
        if (flags & JS_EVAL_FLAG_STRICT)
34463
0
            js_mode |= JS_MODE_STRICT;
34464
78
        if (flags & JS_EVAL_FLAG_STRIP)
34465
0
            js_mode |= JS_MODE_STRIP;
34466
78
        if (eval_type == JS_EVAL_TYPE_MODULE) {
34467
41
            JSAtom module_name = JS_NewAtom(ctx, filename);
34468
41
            if (module_name == JS_ATOM_NULL)
34469
0
                return JS_EXCEPTION;
34470
41
            m = js_new_module_def(ctx, module_name);
34471
41
            if (!m)
34472
0
                return JS_EXCEPTION;
34473
41
            js_mode |= JS_MODE_STRICT;
34474
41
        }
34475
78
    }
34476
78
    fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename, 1);
34477
78
    if (!fd)
34478
0
        goto fail1;
34479
78
    s->cur_func = fd;
34480
78
    fd->eval_type = eval_type;
34481
78
    fd->has_this_binding = (eval_type != JS_EVAL_TYPE_DIRECT);
34482
78
    fd->backtrace_barrier = ((flags & JS_EVAL_FLAG_BACKTRACE_BARRIER) != 0);
34483
78
    if (eval_type == JS_EVAL_TYPE_DIRECT) {
34484
0
        fd->new_target_allowed = b->new_target_allowed;
34485
0
        fd->super_call_allowed = b->super_call_allowed;
34486
0
        fd->super_allowed = b->super_allowed;
34487
0
        fd->arguments_allowed = b->arguments_allowed;
34488
78
    } else {
34489
78
        fd->new_target_allowed = FALSE;
34490
78
        fd->super_call_allowed = FALSE;
34491
78
        fd->super_allowed = FALSE;
34492
78
        fd->arguments_allowed = TRUE;
34493
78
    }
34494
78
    fd->js_mode = js_mode;
34495
78
    fd->func_name = JS_DupAtom(ctx, JS_ATOM__eval_);
34496
78
    if (b) {
34497
0
        if (add_closure_variables(ctx, fd, b, scope_idx))
34498
0
            goto fail;
34499
0
    }
34500
78
    fd->module = m;
34501
78
    if (m != NULL || (flags & JS_EVAL_FLAG_ASYNC)) {
34502
41
        fd->in_function_body = TRUE;
34503
41
        fd->func_kind = JS_FUNC_ASYNC;
34504
41
    }
34505
78
    s->is_module = (m != NULL);
34506
78
    s->allow_html_comments = !s->is_module;
34507
34508
78
    push_scope(s); /* body scope */
34509
78
    fd->body_scope = fd->scope_level;
34510
34511
78
    err = js_parse_program(s);
34512
78
    if (err) {
34513
15
    fail:
34514
15
        free_token(s, &s->token);
34515
15
        js_free_function_def(ctx, fd);
34516
15
        goto fail1;
34517
15
    }
34518
34519
63
    if (m != NULL)
34520
39
        m->has_tla = fd->has_await;
34521
34522
    /* create the function object and all the enclosed functions */
34523
63
    fun_obj = js_create_function(ctx, fd);
34524
63
    if (JS_IsException(fun_obj))
34525
0
        goto fail1;
34526
    /* Could add a flag to avoid resolution if necessary */
34527
63
    if (m) {
34528
39
        m->func_obj = fun_obj;
34529
39
        if (js_resolve_module(ctx, m) < 0)
34530
0
            goto fail1;
34531
39
        fun_obj = JS_NewModuleValue(ctx, m);
34532
39
    }
34533
63
    if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {
34534
39
        ret_val = fun_obj;
34535
39
    } else {
34536
24
        ret_val = JS_EvalFunctionInternal(ctx, fun_obj, this_obj, var_refs, sf);
34537
24
    }
34538
63
    return ret_val;
34539
15
 fail1:
34540
    /* XXX: should free all the unresolved dependencies */
34541
15
    if (m)
34542
2
        js_free_module_def(ctx, m);
34543
15
    return JS_EXCEPTION;
34544
63
}
34545
34546
/* the indirection is needed to make 'eval' optional */
34547
static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
34548
                               const char *input, size_t input_len,
34549
                               const char *filename, int flags, int scope_idx)
34550
78
{
34551
78
    if (unlikely(!ctx->eval_internal)) {
34552
0
        return JS_ThrowTypeError(ctx, "eval is not supported");
34553
0
    }
34554
78
    return ctx->eval_internal(ctx, this_obj, input, input_len, filename,
34555
78
                              flags, scope_idx);
34556
78
}
34557
34558
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
34559
                             JSValueConst val, int flags, int scope_idx)
34560
0
{
34561
0
    JSValue ret;
34562
0
    const char *str;
34563
0
    size_t len;
34564
34565
0
    if (!JS_IsString(val))
34566
0
        return JS_DupValue(ctx, val);
34567
0
    str = JS_ToCStringLen(ctx, &len, val);
34568
0
    if (!str)
34569
0
        return JS_EXCEPTION;
34570
0
    ret = JS_EvalInternal(ctx, this_obj, str, len, "<input>", flags, scope_idx);
34571
0
    JS_FreeCString(ctx, str);
34572
0
    return ret;
34573
34574
0
}
34575
34576
JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
34577
                    const char *input, size_t input_len,
34578
                    const char *filename, int eval_flags)
34579
78
{
34580
78
    int eval_type = eval_flags & JS_EVAL_TYPE_MASK;
34581
78
    JSValue ret;
34582
34583
78
    assert(eval_type == JS_EVAL_TYPE_GLOBAL ||
34584
78
           eval_type == JS_EVAL_TYPE_MODULE);
34585
78
    ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename,
34586
78
                          eval_flags, -1);
34587
78
    return ret;
34588
78
}
34589
34590
JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
34591
                const char *filename, int eval_flags)
34592
78
{
34593
78
    return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename,
34594
78
                       eval_flags);
34595
78
}
34596
34597
int JS_ResolveModule(JSContext *ctx, JSValueConst obj)
34598
0
{
34599
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
34600
0
        JSModuleDef *m = JS_VALUE_GET_PTR(obj);
34601
0
        if (js_resolve_module(ctx, m) < 0) {
34602
0
            js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
34603
0
            return -1;
34604
0
        }
34605
0
    }
34606
0
    return 0;
34607
0
}
34608
34609
/*******************************************************************/
34610
/* object list */
34611
34612
typedef struct {
34613
    JSObject *obj;
34614
    uint32_t hash_next; /* -1 if no next entry */
34615
} JSObjectListEntry;
34616
34617
/* XXX: reuse it to optimize weak references */
34618
typedef struct {
34619
    JSObjectListEntry *object_tab;
34620
    int object_count;
34621
    int object_size;
34622
    uint32_t *hash_table;
34623
    uint32_t hash_size;
34624
} JSObjectList;
34625
34626
static void js_object_list_init(JSObjectList *s)
34627
0
{
34628
0
    memset(s, 0, sizeof(*s));
34629
0
}
34630
34631
static uint32_t js_object_list_get_hash(JSObject *p, uint32_t hash_size)
34632
0
{
34633
0
    return ((uintptr_t)p * 3163) & (hash_size - 1);
34634
0
}
34635
34636
static int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s,
34637
                                 uint32_t new_hash_size)
34638
0
{
34639
0
    JSObjectListEntry *e;
34640
0
    uint32_t i, h, *new_hash_table;
34641
34642
0
    new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size);
34643
0
    if (!new_hash_table)
34644
0
        return -1;
34645
0
    js_free(ctx, s->hash_table);
34646
0
    s->hash_table = new_hash_table;
34647
0
    s->hash_size = new_hash_size;
34648
34649
0
    for(i = 0; i < s->hash_size; i++) {
34650
0
        s->hash_table[i] = -1;
34651
0
    }
34652
0
    for(i = 0; i < s->object_count; i++) {
34653
0
        e = &s->object_tab[i];
34654
0
        h = js_object_list_get_hash(e->obj, s->hash_size);
34655
0
        e->hash_next = s->hash_table[h];
34656
0
        s->hash_table[h] = i;
34657
0
    }
34658
0
    return 0;
34659
0
}
34660
34661
/* the reference count of 'obj' is not modified. Return 0 if OK, -1 if
34662
   memory error */
34663
static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj)
34664
0
{
34665
0
    JSObjectListEntry *e;
34666
0
    uint32_t h, new_hash_size;
34667
34668
0
    if (js_resize_array(ctx, (void *)&s->object_tab,
34669
0
                        sizeof(s->object_tab[0]),
34670
0
                        &s->object_size, s->object_count + 1))
34671
0
        return -1;
34672
0
    if (unlikely((s->object_count + 1) >= s->hash_size)) {
34673
0
        new_hash_size = max_uint32(s->hash_size, 4);
34674
0
        while (new_hash_size <= s->object_count)
34675
0
            new_hash_size *= 2;
34676
0
        if (js_object_list_resize_hash(ctx, s, new_hash_size))
34677
0
            return -1;
34678
0
    }
34679
0
    e = &s->object_tab[s->object_count++];
34680
0
    h = js_object_list_get_hash(obj, s->hash_size);
34681
0
    e->obj = obj;
34682
0
    e->hash_next = s->hash_table[h];
34683
0
    s->hash_table[h] = s->object_count - 1;
34684
0
    return 0;
34685
0
}
34686
34687
/* return -1 if not present or the object index */
34688
static int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj)
34689
0
{
34690
0
    JSObjectListEntry *e;
34691
0
    uint32_t h, p;
34692
34693
    /* must test empty size because there is no hash table */
34694
0
    if (s->object_count == 0)
34695
0
        return -1;
34696
0
    h = js_object_list_get_hash(obj, s->hash_size);
34697
0
    p = s->hash_table[h];
34698
0
    while (p != -1) {
34699
0
        e = &s->object_tab[p];
34700
0
        if (e->obj == obj)
34701
0
            return p;
34702
0
        p = e->hash_next;
34703
0
    }
34704
0
    return -1;
34705
0
}
34706
34707
static void js_object_list_end(JSContext *ctx, JSObjectList *s)
34708
0
{
34709
0
    js_free(ctx, s->object_tab);
34710
0
    js_free(ctx, s->hash_table);
34711
0
}
34712
34713
/*******************************************************************/
34714
/* binary object writer & reader */
34715
34716
typedef enum BCTagEnum {
34717
    BC_TAG_NULL = 1,
34718
    BC_TAG_UNDEFINED,
34719
    BC_TAG_BOOL_FALSE,
34720
    BC_TAG_BOOL_TRUE,
34721
    BC_TAG_INT32,
34722
    BC_TAG_FLOAT64,
34723
    BC_TAG_STRING,
34724
    BC_TAG_OBJECT,
34725
    BC_TAG_ARRAY,
34726
    BC_TAG_BIG_INT,
34727
    BC_TAG_TEMPLATE_OBJECT,
34728
    BC_TAG_FUNCTION_BYTECODE,
34729
    BC_TAG_MODULE,
34730
    BC_TAG_TYPED_ARRAY,
34731
    BC_TAG_ARRAY_BUFFER,
34732
    BC_TAG_SHARED_ARRAY_BUFFER,
34733
    BC_TAG_DATE,
34734
    BC_TAG_OBJECT_VALUE,
34735
    BC_TAG_OBJECT_REFERENCE,
34736
#ifdef CONFIG_BIGNUM
34737
    BC_TAG_BIG_FLOAT,
34738
    BC_TAG_BIG_DECIMAL,
34739
#endif
34740
} BCTagEnum;
34741
34742
#ifdef CONFIG_BIGNUM
34743
0
#define BC_VERSION 0x43
34744
#else
34745
#define BC_VERSION 3
34746
#endif
34747
34748
typedef struct BCWriterState {
34749
    JSContext *ctx;
34750
    DynBuf dbuf;
34751
    BOOL allow_bytecode : 8;
34752
    BOOL allow_sab : 8;
34753
    BOOL allow_reference : 8;
34754
    uint32_t first_atom;
34755
    uint32_t *atom_to_idx;
34756
    int atom_to_idx_size;
34757
    JSAtom *idx_to_atom;
34758
    int idx_to_atom_count;
34759
    int idx_to_atom_size;
34760
    uint8_t **sab_tab;
34761
    int sab_tab_len;
34762
    int sab_tab_size;
34763
    /* list of referenced objects (used if allow_reference = TRUE) */
34764
    JSObjectList object_list;
34765
} BCWriterState;
34766
34767
#ifdef DUMP_READ_OBJECT
34768
static const char * const bc_tag_str[] = {
34769
    "invalid",
34770
    "null",
34771
    "undefined",
34772
    "false",
34773
    "true",
34774
    "int32",
34775
    "float64",
34776
    "string",
34777
    "object",
34778
    "array",
34779
    "bigint",
34780
    "template",
34781
    "function",
34782
    "module",
34783
    "TypedArray",
34784
    "ArrayBuffer",
34785
    "SharedArrayBuffer",
34786
    "Date",
34787
    "ObjectValue",
34788
    "ObjectReference",
34789
#ifdef CONFIG_BIGNUM
34790
    "bigfloat",
34791
    "bigdecimal",
34792
#endif
34793
};
34794
#endif
34795
34796
static inline BOOL is_be(void)
34797
0
{
34798
0
    union {
34799
0
        uint16_t a;
34800
0
        uint8_t  b;
34801
0
    } u = {0x100};
34802
0
    return u.b;
34803
0
}
34804
34805
static void bc_put_u8(BCWriterState *s, uint8_t v)
34806
0
{
34807
0
    dbuf_putc(&s->dbuf, v);
34808
0
}
34809
34810
static void bc_put_u16(BCWriterState *s, uint16_t v)
34811
0
{
34812
0
    if (is_be())
34813
0
        v = bswap16(v);
34814
0
    dbuf_put_u16(&s->dbuf, v);
34815
0
}
34816
34817
static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
34818
0
{
34819
0
    if (is_be())
34820
0
        v = bswap32(v);
34821
0
    dbuf_put_u32(&s->dbuf, v);
34822
0
}
34823
34824
static void bc_put_u64(BCWriterState *s, uint64_t v)
34825
0
{
34826
0
    if (is_be())
34827
0
        v = bswap64(v);
34828
0
    dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v));
34829
0
}
34830
34831
static void bc_put_leb128(BCWriterState *s, uint32_t v)
34832
0
{
34833
0
    dbuf_put_leb128(&s->dbuf, v);
34834
0
}
34835
34836
static void bc_put_sleb128(BCWriterState *s, int32_t v)
34837
0
{
34838
0
    dbuf_put_sleb128(&s->dbuf, v);
34839
0
}
34840
34841
static void bc_set_flags(uint32_t *pflags, int *pidx, uint32_t val, int n)
34842
0
{
34843
0
    *pflags = *pflags | (val << *pidx);
34844
0
    *pidx += n;
34845
0
}
34846
34847
static int bc_atom_to_idx(BCWriterState *s, uint32_t *pres, JSAtom atom)
34848
0
{
34849
0
    uint32_t v;
34850
34851
0
    if (atom < s->first_atom || __JS_AtomIsTaggedInt(atom)) {
34852
0
        *pres = atom;
34853
0
        return 0;
34854
0
    }
34855
0
    atom -= s->first_atom;
34856
0
    if (atom < s->atom_to_idx_size && s->atom_to_idx[atom] != 0) {
34857
0
        *pres = s->atom_to_idx[atom];
34858
0
        return 0;
34859
0
    }
34860
0
    if (atom >= s->atom_to_idx_size) {
34861
0
        int old_size, i;
34862
0
        old_size = s->atom_to_idx_size;
34863
0
        if (js_resize_array(s->ctx, (void **)&s->atom_to_idx,
34864
0
                            sizeof(s->atom_to_idx[0]), &s->atom_to_idx_size,
34865
0
                            atom + 1))
34866
0
            return -1;
34867
        /* XXX: could add a specific js_resize_array() function to do it */
34868
0
        for(i = old_size; i < s->atom_to_idx_size; i++)
34869
0
            s->atom_to_idx[i] = 0;
34870
0
    }
34871
0
    if (js_resize_array(s->ctx, (void **)&s->idx_to_atom,
34872
0
                        sizeof(s->idx_to_atom[0]),
34873
0
                        &s->idx_to_atom_size, s->idx_to_atom_count + 1))
34874
0
        goto fail;
34875
34876
0
    v = s->idx_to_atom_count++;
34877
0
    s->idx_to_atom[v] = atom + s->first_atom;
34878
0
    v += s->first_atom;
34879
0
    s->atom_to_idx[atom] = v;
34880
0
    *pres = v;
34881
0
    return 0;
34882
0
 fail:
34883
0
    *pres = 0;
34884
0
    return -1;
34885
0
}
34886
34887
static int bc_put_atom(BCWriterState *s, JSAtom atom)
34888
0
{
34889
0
    uint32_t v;
34890
34891
0
    if (__JS_AtomIsTaggedInt(atom)) {
34892
0
        v = (__JS_AtomToUInt32(atom) << 1) | 1;
34893
0
    } else {
34894
0
        if (bc_atom_to_idx(s, &v, atom))
34895
0
            return -1;
34896
0
        v <<= 1;
34897
0
    }
34898
0
    bc_put_leb128(s, v);
34899
0
    return 0;
34900
0
}
34901
34902
static void bc_byte_swap(uint8_t *bc_buf, int bc_len)
34903
0
{
34904
0
    int pos, len, op, fmt;
34905
34906
0
    pos = 0;
34907
0
    while (pos < bc_len) {
34908
0
        op = bc_buf[pos];
34909
0
        len = short_opcode_info(op).size;
34910
0
        fmt = short_opcode_info(op).fmt;
34911
0
        switch(fmt) {
34912
0
        case OP_FMT_u16:
34913
0
        case OP_FMT_i16:
34914
0
        case OP_FMT_label16:
34915
0
        case OP_FMT_npop:
34916
0
        case OP_FMT_loc:
34917
0
        case OP_FMT_arg:
34918
0
        case OP_FMT_var_ref:
34919
0
            put_u16(bc_buf + pos + 1,
34920
0
                    bswap16(get_u16(bc_buf + pos + 1)));
34921
0
            break;
34922
0
        case OP_FMT_i32:
34923
0
        case OP_FMT_u32:
34924
0
        case OP_FMT_const:
34925
0
        case OP_FMT_label:
34926
0
        case OP_FMT_atom:
34927
0
        case OP_FMT_atom_u8:
34928
0
            put_u32(bc_buf + pos + 1,
34929
0
                    bswap32(get_u32(bc_buf + pos + 1)));
34930
0
            break;
34931
0
        case OP_FMT_atom_u16:
34932
0
        case OP_FMT_label_u16:
34933
0
            put_u32(bc_buf + pos + 1,
34934
0
                    bswap32(get_u32(bc_buf + pos + 1)));
34935
0
            put_u16(bc_buf + pos + 1 + 4,
34936
0
                    bswap16(get_u16(bc_buf + pos + 1 + 4)));
34937
0
            break;
34938
0
        case OP_FMT_atom_label_u8:
34939
0
        case OP_FMT_atom_label_u16:
34940
0
            put_u32(bc_buf + pos + 1,
34941
0
                    bswap32(get_u32(bc_buf + pos + 1)));
34942
0
            put_u32(bc_buf + pos + 1 + 4,
34943
0
                    bswap32(get_u32(bc_buf + pos + 1 + 4)));
34944
0
            if (fmt == OP_FMT_atom_label_u16) {
34945
0
                put_u16(bc_buf + pos + 1 + 4 + 4,
34946
0
                        bswap16(get_u16(bc_buf + pos + 1 + 4 + 4)));
34947
0
            }
34948
0
            break;
34949
0
        case OP_FMT_npop_u16:
34950
0
            put_u16(bc_buf + pos + 1,
34951
0
                    bswap16(get_u16(bc_buf + pos + 1)));
34952
0
            put_u16(bc_buf + pos + 1 + 2,
34953
0
                    bswap16(get_u16(bc_buf + pos + 1 + 2)));
34954
0
            break;
34955
0
        default:
34956
0
            break;
34957
0
        }
34958
0
        pos += len;
34959
0
    }
34960
0
}
34961
34962
static int JS_WriteFunctionBytecode(BCWriterState *s,
34963
                                    const uint8_t *bc_buf1, int bc_len)
34964
0
{
34965
0
    int pos, len, op;
34966
0
    JSAtom atom;
34967
0
    uint8_t *bc_buf;
34968
0
    uint32_t val;
34969
34970
0
    bc_buf = js_malloc(s->ctx, bc_len);
34971
0
    if (!bc_buf)
34972
0
        return -1;
34973
0
    memcpy(bc_buf, bc_buf1, bc_len);
34974
34975
0
    pos = 0;
34976
0
    while (pos < bc_len) {
34977
0
        op = bc_buf[pos];
34978
0
        len = short_opcode_info(op).size;
34979
0
        switch(short_opcode_info(op).fmt) {
34980
0
        case OP_FMT_atom:
34981
0
        case OP_FMT_atom_u8:
34982
0
        case OP_FMT_atom_u16:
34983
0
        case OP_FMT_atom_label_u8:
34984
0
        case OP_FMT_atom_label_u16:
34985
0
            atom = get_u32(bc_buf + pos + 1);
34986
0
            if (bc_atom_to_idx(s, &val, atom))
34987
0
                goto fail;
34988
0
            put_u32(bc_buf + pos + 1, val);
34989
0
            break;
34990
0
        default:
34991
0
            break;
34992
0
        }
34993
0
        pos += len;
34994
0
    }
34995
34996
0
    if (is_be())
34997
0
        bc_byte_swap(bc_buf, bc_len);
34998
34999
0
    dbuf_put(&s->dbuf, bc_buf, bc_len);
35000
35001
0
    js_free(s->ctx, bc_buf);
35002
0
    return 0;
35003
0
 fail:
35004
0
    js_free(s->ctx, bc_buf);
35005
0
    return -1;
35006
0
}
35007
35008
static void JS_WriteString(BCWriterState *s, JSString *p)
35009
0
{
35010
0
    int i;
35011
0
    bc_put_leb128(s, ((uint32_t)p->len << 1) | p->is_wide_char);
35012
0
    if (p->is_wide_char) {
35013
0
        for(i = 0; i < p->len; i++)
35014
0
            bc_put_u16(s, p->u.str16[i]);
35015
0
    } else {
35016
0
        dbuf_put(&s->dbuf, p->u.str8, p->len);
35017
0
    }
35018
0
}
35019
35020
static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj)
35021
0
{
35022
0
    uint32_t tag, tag1;
35023
0
    int64_t e;
35024
0
    JSBigFloat *bf = JS_VALUE_GET_PTR(obj);
35025
0
    bf_t *a = &bf->num;
35026
0
    size_t len, i, n1, j;
35027
0
    limb_t v;
35028
35029
0
    tag = JS_VALUE_GET_TAG(obj);
35030
0
    switch(tag) {
35031
0
    case JS_TAG_BIG_INT:
35032
0
        tag1 = BC_TAG_BIG_INT;
35033
0
        break;
35034
0
#ifdef CONFIG_BIGNUM
35035
0
    case JS_TAG_BIG_FLOAT:
35036
0
        tag1 = BC_TAG_BIG_FLOAT;
35037
0
        break;
35038
0
    case JS_TAG_BIG_DECIMAL:
35039
0
        tag1 = BC_TAG_BIG_DECIMAL;
35040
0
        break;
35041
0
#endif
35042
0
    default:
35043
0
        abort();
35044
0
    }
35045
0
    bc_put_u8(s, tag1);
35046
35047
    /* sign + exponent */
35048
0
    if (a->expn == BF_EXP_ZERO)
35049
0
        e = 0;
35050
0
    else if (a->expn == BF_EXP_INF)
35051
0
        e = 1;
35052
0
    else if (a->expn == BF_EXP_NAN)
35053
0
        e = 2;
35054
0
    else if (a->expn >= 0)
35055
0
        e = a->expn + 3;
35056
0
    else
35057
0
        e = a->expn;
35058
0
    e = (e * 2) | a->sign;
35059
0
    if (e < INT32_MIN || e > INT32_MAX) {
35060
0
        JS_ThrowInternalError(s->ctx, "bignum exponent is too large");
35061
0
        return -1;
35062
0
    }
35063
0
    bc_put_sleb128(s, e);
35064
35065
    /* mantissa */
35066
0
    if (a->len != 0) {
35067
0
        if (tag != JS_TAG_BIG_DECIMAL) {
35068
0
            i = 0;
35069
0
            while (i < a->len && a->tab[i] == 0)
35070
0
                i++;
35071
0
            assert(i < a->len);
35072
0
            v = a->tab[i];
35073
0
            n1 = sizeof(limb_t);
35074
0
            while ((v & 0xff) == 0) {
35075
0
                n1--;
35076
0
                v >>= 8;
35077
0
            }
35078
0
            i++;
35079
0
            len = (a->len - i) * sizeof(limb_t) + n1;
35080
0
            if (len > INT32_MAX) {
35081
0
                JS_ThrowInternalError(s->ctx, "bignum is too large");
35082
0
                return -1;
35083
0
            }
35084
0
            bc_put_leb128(s, len);
35085
            /* always saved in byte based little endian representation */
35086
0
            for(j = 0; j < n1; j++) {
35087
0
                bc_put_u8(s, v >> (j * 8));
35088
0
            }
35089
0
            for(; i < a->len; i++) {
35090
0
                limb_t v = a->tab[i];
35091
#if LIMB_BITS == 32
35092
                bc_put_u32(s, v);
35093
#else
35094
0
                bc_put_u64(s, v);
35095
0
#endif
35096
0
            }
35097
0
        } else {
35098
0
            int bpos, d;
35099
0
            uint8_t v8;
35100
0
            size_t i0;
35101
35102
            /* little endian BCD */
35103
0
            i = 0;
35104
0
            while (i < a->len && a->tab[i] == 0)
35105
0
                i++;
35106
0
            assert(i < a->len);
35107
0
            len = a->len * LIMB_DIGITS;
35108
0
            v = a->tab[i];
35109
0
            j = 0;
35110
0
            while ((v % 10) == 0) {
35111
0
                j++;
35112
0
                v /= 10;
35113
0
            }
35114
0
            len -= j;
35115
0
            assert(len > 0);
35116
0
            if (len > INT32_MAX) {
35117
0
                JS_ThrowInternalError(s->ctx, "bignum is too large");
35118
0
                return -1;
35119
0
            }
35120
0
            bc_put_leb128(s, len);
35121
35122
0
            bpos = 0;
35123
0
            v8 = 0;
35124
0
            i0 = i;
35125
0
            for(; i < a->len; i++) {
35126
0
                if (i != i0) {
35127
0
                    v = a->tab[i];
35128
0
                    j = 0;
35129
0
                }
35130
0
                for(; j < LIMB_DIGITS; j++) {
35131
0
                    d = v % 10;
35132
0
                    v /= 10;
35133
0
                    if (bpos == 0) {
35134
0
                        v8 = d;
35135
0
                        bpos = 1;
35136
0
                    } else {
35137
0
                        bc_put_u8(s, v8 | (d << 4));
35138
0
                        bpos = 0;
35139
0
                    }
35140
0
                }
35141
0
            }
35142
            /* flush the last digit */
35143
0
            if (bpos) {
35144
0
                bc_put_u8(s, v8);
35145
0
            }
35146
0
        }
35147
0
    }
35148
0
    return 0;
35149
0
}
35150
35151
static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj);
35152
35153
static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
35154
0
{
35155
0
    JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj);
35156
0
    uint32_t flags;
35157
0
    int idx, i;
35158
35159
0
    bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE);
35160
0
    flags = idx = 0;
35161
0
    bc_set_flags(&flags, &idx, b->has_prototype, 1);
35162
0
    bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1);
35163
0
    bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1);
35164
0
    bc_set_flags(&flags, &idx, b->need_home_object, 1);
35165
0
    bc_set_flags(&flags, &idx, b->func_kind, 2);
35166
0
    bc_set_flags(&flags, &idx, b->new_target_allowed, 1);
35167
0
    bc_set_flags(&flags, &idx, b->super_call_allowed, 1);
35168
0
    bc_set_flags(&flags, &idx, b->super_allowed, 1);
35169
0
    bc_set_flags(&flags, &idx, b->arguments_allowed, 1);
35170
0
    bc_set_flags(&flags, &idx, b->has_debug, 1);
35171
0
    bc_set_flags(&flags, &idx, b->backtrace_barrier, 1);
35172
0
    bc_set_flags(&flags, &idx, b->is_direct_or_indirect_eval, 1);
35173
0
    assert(idx <= 16);
35174
0
    bc_put_u16(s, flags);
35175
0
    bc_put_u8(s, b->js_mode);
35176
0
    bc_put_atom(s, b->func_name);
35177
35178
0
    bc_put_leb128(s, b->arg_count);
35179
0
    bc_put_leb128(s, b->var_count);
35180
0
    bc_put_leb128(s, b->defined_arg_count);
35181
0
    bc_put_leb128(s, b->stack_size);
35182
0
    bc_put_leb128(s, b->closure_var_count);
35183
0
    bc_put_leb128(s, b->cpool_count);
35184
0
    bc_put_leb128(s, b->byte_code_len);
35185
0
    if (b->vardefs) {
35186
        /* XXX: this field is redundant */
35187
0
        bc_put_leb128(s, b->arg_count + b->var_count);
35188
0
        for(i = 0; i < b->arg_count + b->var_count; i++) {
35189
0
            JSVarDef *vd = &b->vardefs[i];
35190
0
            bc_put_atom(s, vd->var_name);
35191
0
            bc_put_leb128(s, vd->scope_level);
35192
0
            bc_put_leb128(s, vd->scope_next + 1);
35193
0
            flags = idx = 0;
35194
0
            bc_set_flags(&flags, &idx, vd->var_kind, 4);
35195
0
            bc_set_flags(&flags, &idx, vd->is_const, 1);
35196
0
            bc_set_flags(&flags, &idx, vd->is_lexical, 1);
35197
0
            bc_set_flags(&flags, &idx, vd->is_captured, 1);
35198
0
            assert(idx <= 8);
35199
0
            bc_put_u8(s, flags);
35200
0
        }
35201
0
    } else {
35202
0
        bc_put_leb128(s, 0);
35203
0
    }
35204
35205
0
    for(i = 0; i < b->closure_var_count; i++) {
35206
0
        JSClosureVar *cv = &b->closure_var[i];
35207
0
        bc_put_atom(s, cv->var_name);
35208
0
        bc_put_leb128(s, cv->var_idx);
35209
0
        flags = idx = 0;
35210
0
        bc_set_flags(&flags, &idx, cv->is_local, 1);
35211
0
        bc_set_flags(&flags, &idx, cv->is_arg, 1);
35212
0
        bc_set_flags(&flags, &idx, cv->is_const, 1);
35213
0
        bc_set_flags(&flags, &idx, cv->is_lexical, 1);
35214
0
        bc_set_flags(&flags, &idx, cv->var_kind, 4);
35215
0
        assert(idx <= 8);
35216
0
        bc_put_u8(s, flags);
35217
0
    }
35218
35219
0
    if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len))
35220
0
        goto fail;
35221
35222
0
    if (b->has_debug) {
35223
0
        bc_put_atom(s, b->debug.filename);
35224
0
        bc_put_leb128(s, b->debug.line_num);
35225
0
        bc_put_leb128(s, b->debug.pc2line_len);
35226
0
        dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len);
35227
0
    }
35228
35229
0
    for(i = 0; i < b->cpool_count; i++) {
35230
0
        if (JS_WriteObjectRec(s, b->cpool[i]))
35231
0
            goto fail;
35232
0
    }
35233
0
    return 0;
35234
0
 fail:
35235
0
    return -1;
35236
0
}
35237
35238
static int JS_WriteModule(BCWriterState *s, JSValueConst obj)
35239
0
{
35240
0
    JSModuleDef *m = JS_VALUE_GET_PTR(obj);
35241
0
    int i;
35242
35243
0
    bc_put_u8(s, BC_TAG_MODULE);
35244
0
    bc_put_atom(s, m->module_name);
35245
35246
0
    bc_put_leb128(s, m->req_module_entries_count);
35247
0
    for(i = 0; i < m->req_module_entries_count; i++) {
35248
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
35249
0
        bc_put_atom(s, rme->module_name);
35250
0
    }
35251
35252
0
    bc_put_leb128(s, m->export_entries_count);
35253
0
    for(i = 0; i < m->export_entries_count; i++) {
35254
0
        JSExportEntry *me = &m->export_entries[i];
35255
0
        bc_put_u8(s, me->export_type);
35256
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
35257
0
            bc_put_leb128(s, me->u.local.var_idx);
35258
0
        } else {
35259
0
            bc_put_leb128(s, me->u.req_module_idx);
35260
0
            bc_put_atom(s, me->local_name);
35261
0
        }
35262
0
        bc_put_atom(s, me->export_name);
35263
0
    }
35264
35265
0
    bc_put_leb128(s, m->star_export_entries_count);
35266
0
    for(i = 0; i < m->star_export_entries_count; i++) {
35267
0
        JSStarExportEntry *se = &m->star_export_entries[i];
35268
0
        bc_put_leb128(s, se->req_module_idx);
35269
0
    }
35270
35271
0
    bc_put_leb128(s, m->import_entries_count);
35272
0
    for(i = 0; i < m->import_entries_count; i++) {
35273
0
        JSImportEntry *mi = &m->import_entries[i];
35274
0
        bc_put_leb128(s, mi->var_idx);
35275
0
        bc_put_atom(s, mi->import_name);
35276
0
        bc_put_leb128(s, mi->req_module_idx);
35277
0
    }
35278
35279
0
    bc_put_u8(s, m->has_tla);
35280
35281
0
    if (JS_WriteObjectRec(s, m->func_obj))
35282
0
        goto fail;
35283
0
    return 0;
35284
0
 fail:
35285
0
    return -1;
35286
0
}
35287
35288
static int JS_WriteArray(BCWriterState *s, JSValueConst obj)
35289
0
{
35290
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
35291
0
    uint32_t i, len;
35292
0
    JSValue val;
35293
0
    int ret;
35294
0
    BOOL is_template;
35295
35296
0
    if (s->allow_bytecode && !p->extensible) {
35297
        /* not extensible array: we consider it is a
35298
           template when we are saving bytecode */
35299
0
        bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT);
35300
0
        is_template = TRUE;
35301
0
    } else {
35302
0
        bc_put_u8(s, BC_TAG_ARRAY);
35303
0
        is_template = FALSE;
35304
0
    }
35305
0
    if (js_get_length32(s->ctx, &len, obj))
35306
0
        goto fail1;
35307
0
    bc_put_leb128(s, len);
35308
0
    for(i = 0; i < len; i++) {
35309
0
        val = JS_GetPropertyUint32(s->ctx, obj, i);
35310
0
        if (JS_IsException(val))
35311
0
            goto fail1;
35312
0
        ret = JS_WriteObjectRec(s, val);
35313
0
        JS_FreeValue(s->ctx, val);
35314
0
        if (ret)
35315
0
            goto fail1;
35316
0
    }
35317
0
    if (is_template) {
35318
0
        val = JS_GetProperty(s->ctx, obj, JS_ATOM_raw);
35319
0
        if (JS_IsException(val))
35320
0
            goto fail1;
35321
0
        ret = JS_WriteObjectRec(s, val);
35322
0
        JS_FreeValue(s->ctx, val);
35323
0
        if (ret)
35324
0
            goto fail1;
35325
0
    }
35326
0
    return 0;
35327
0
 fail1:
35328
0
    return -1;
35329
0
}
35330
35331
static int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj)
35332
0
{
35333
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
35334
0
    uint32_t i, prop_count;
35335
0
    JSShape *sh;
35336
0
    JSShapeProperty *pr;
35337
0
    int pass;
35338
0
    JSAtom atom;
35339
35340
0
    bc_put_u8(s, BC_TAG_OBJECT);
35341
0
    prop_count = 0;
35342
0
    sh = p->shape;
35343
0
    for(pass = 0; pass < 2; pass++) {
35344
0
        if (pass == 1)
35345
0
            bc_put_leb128(s, prop_count);
35346
0
        for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
35347
0
            atom = pr->atom;
35348
0
            if (atom != JS_ATOM_NULL &&
35349
0
                JS_AtomIsString(s->ctx, atom) &&
35350
0
                (pr->flags & JS_PROP_ENUMERABLE)) {
35351
0
                if (pr->flags & JS_PROP_TMASK) {
35352
0
                    JS_ThrowTypeError(s->ctx, "only value properties are supported");
35353
0
                    goto fail;
35354
0
                }
35355
0
                if (pass == 0) {
35356
0
                    prop_count++;
35357
0
                } else {
35358
0
                    bc_put_atom(s, atom);
35359
0
                    if (JS_WriteObjectRec(s, p->prop[i].u.value))
35360
0
                        goto fail;
35361
0
                }
35362
0
            }
35363
0
        }
35364
0
    }
35365
0
    return 0;
35366
0
 fail:
35367
0
    return -1;
35368
0
}
35369
35370
static int JS_WriteTypedArray(BCWriterState *s, JSValueConst obj)
35371
0
{
35372
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
35373
0
    JSTypedArray *ta = p->u.typed_array;
35374
35375
0
    bc_put_u8(s, BC_TAG_TYPED_ARRAY);
35376
0
    bc_put_u8(s, p->class_id - JS_CLASS_UINT8C_ARRAY);
35377
0
    bc_put_leb128(s, p->u.array.count);
35378
0
    bc_put_leb128(s, ta->offset);
35379
0
    if (JS_WriteObjectRec(s, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)))
35380
0
        return -1;
35381
0
    return 0;
35382
0
}
35383
35384
static int JS_WriteArrayBuffer(BCWriterState *s, JSValueConst obj)
35385
0
{
35386
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
35387
0
    JSArrayBuffer *abuf = p->u.array_buffer;
35388
0
    if (abuf->detached) {
35389
0
        JS_ThrowTypeErrorDetachedArrayBuffer(s->ctx);
35390
0
        return -1;
35391
0
    }
35392
0
    bc_put_u8(s, BC_TAG_ARRAY_BUFFER);
35393
0
    bc_put_leb128(s, abuf->byte_length);
35394
0
    dbuf_put(&s->dbuf, abuf->data, abuf->byte_length);
35395
0
    return 0;
35396
0
}
35397
35398
static int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValueConst obj)
35399
0
{
35400
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
35401
0
    JSArrayBuffer *abuf = p->u.array_buffer;
35402
0
    assert(!abuf->detached); /* SharedArrayBuffer are never detached */
35403
0
    bc_put_u8(s, BC_TAG_SHARED_ARRAY_BUFFER);
35404
0
    bc_put_leb128(s, abuf->byte_length);
35405
0
    bc_put_u64(s, (uintptr_t)abuf->data);
35406
0
    if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]),
35407
0
                        &s->sab_tab_size, s->sab_tab_len + 1))
35408
0
        return -1;
35409
    /* keep the SAB pointer so that the user can clone it or free it */
35410
0
    s->sab_tab[s->sab_tab_len++] = abuf->data;
35411
0
    return 0;
35412
0
}
35413
35414
static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
35415
0
{
35416
0
    uint32_t tag;
35417
35418
0
    if (js_check_stack_overflow(s->ctx->rt, 0)) {
35419
0
        JS_ThrowStackOverflow(s->ctx);
35420
0
        return -1;
35421
0
    }
35422
35423
0
    tag = JS_VALUE_GET_NORM_TAG(obj);
35424
0
    switch(tag) {
35425
0
    case JS_TAG_NULL:
35426
0
        bc_put_u8(s, BC_TAG_NULL);
35427
0
        break;
35428
0
    case JS_TAG_UNDEFINED:
35429
0
        bc_put_u8(s, BC_TAG_UNDEFINED);
35430
0
        break;
35431
0
    case JS_TAG_BOOL:
35432
0
        bc_put_u8(s, BC_TAG_BOOL_FALSE + JS_VALUE_GET_INT(obj));
35433
0
        break;
35434
0
    case JS_TAG_INT:
35435
0
        bc_put_u8(s, BC_TAG_INT32);
35436
0
        bc_put_sleb128(s, JS_VALUE_GET_INT(obj));
35437
0
        break;
35438
0
    case JS_TAG_FLOAT64:
35439
0
        {
35440
0
            JSFloat64Union u;
35441
0
            bc_put_u8(s, BC_TAG_FLOAT64);
35442
0
            u.d = JS_VALUE_GET_FLOAT64(obj);
35443
0
            bc_put_u64(s, u.u64);
35444
0
        }
35445
0
        break;
35446
0
    case JS_TAG_STRING:
35447
0
        {
35448
0
            JSString *p = JS_VALUE_GET_STRING(obj);
35449
0
            bc_put_u8(s, BC_TAG_STRING);
35450
0
            JS_WriteString(s, p);
35451
0
        }
35452
0
        break;
35453
0
    case JS_TAG_FUNCTION_BYTECODE:
35454
0
        if (!s->allow_bytecode)
35455
0
            goto invalid_tag;
35456
0
        if (JS_WriteFunctionTag(s, obj))
35457
0
            goto fail;
35458
0
        break;
35459
0
    case JS_TAG_MODULE:
35460
0
        if (!s->allow_bytecode)
35461
0
            goto invalid_tag;
35462
0
        if (JS_WriteModule(s, obj))
35463
0
            goto fail;
35464
0
        break;
35465
0
    case JS_TAG_OBJECT:
35466
0
        {
35467
0
            JSObject *p = JS_VALUE_GET_OBJ(obj);
35468
0
            int ret, idx;
35469
35470
0
            if (s->allow_reference) {
35471
0
                idx = js_object_list_find(s->ctx, &s->object_list, p);
35472
0
                if (idx >= 0) {
35473
0
                    bc_put_u8(s, BC_TAG_OBJECT_REFERENCE);
35474
0
                    bc_put_leb128(s, idx);
35475
0
                    break;
35476
0
                } else {
35477
0
                    if (js_object_list_add(s->ctx, &s->object_list, p))
35478
0
                        goto fail;
35479
0
                }
35480
0
            } else {
35481
0
                if (p->tmp_mark) {
35482
0
                    JS_ThrowTypeError(s->ctx, "circular reference");
35483
0
                    goto fail;
35484
0
                }
35485
0
                p->tmp_mark = 1;
35486
0
            }
35487
0
            switch(p->class_id) {
35488
0
            case JS_CLASS_ARRAY:
35489
0
                ret = JS_WriteArray(s, obj);
35490
0
                break;
35491
0
            case JS_CLASS_OBJECT:
35492
0
                ret = JS_WriteObjectTag(s, obj);
35493
0
                break;
35494
0
            case JS_CLASS_ARRAY_BUFFER:
35495
0
                ret = JS_WriteArrayBuffer(s, obj);
35496
0
                break;
35497
0
            case JS_CLASS_SHARED_ARRAY_BUFFER:
35498
0
                if (!s->allow_sab)
35499
0
                    goto invalid_tag;
35500
0
                ret = JS_WriteSharedArrayBuffer(s, obj);
35501
0
                break;
35502
0
            case JS_CLASS_DATE:
35503
0
                bc_put_u8(s, BC_TAG_DATE);
35504
0
                ret = JS_WriteObjectRec(s, p->u.object_data);
35505
0
                break;
35506
0
            case JS_CLASS_NUMBER:
35507
0
            case JS_CLASS_STRING:
35508
0
            case JS_CLASS_BOOLEAN:
35509
0
            case JS_CLASS_BIG_INT:
35510
0
#ifdef CONFIG_BIGNUM
35511
0
            case JS_CLASS_BIG_FLOAT:
35512
0
            case JS_CLASS_BIG_DECIMAL:
35513
0
#endif
35514
0
                bc_put_u8(s, BC_TAG_OBJECT_VALUE);
35515
0
                ret = JS_WriteObjectRec(s, p->u.object_data);
35516
0
                break;
35517
0
            default:
35518
0
                if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
35519
0
                    p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
35520
0
                    ret = JS_WriteTypedArray(s, obj);
35521
0
                } else {
35522
0
                    JS_ThrowTypeError(s->ctx, "unsupported object class");
35523
0
                    ret = -1;
35524
0
                }
35525
0
                break;
35526
0
            }
35527
0
            p->tmp_mark = 0;
35528
0
            if (ret)
35529
0
                goto fail;
35530
0
        }
35531
0
        break;
35532
0
    case JS_TAG_BIG_INT:
35533
0
#ifdef CONFIG_BIGNUM
35534
0
    case JS_TAG_BIG_FLOAT:
35535
0
    case JS_TAG_BIG_DECIMAL:
35536
0
#endif
35537
0
        if (JS_WriteBigNum(s, obj))
35538
0
            goto fail;
35539
0
        break;
35540
0
    default:
35541
0
    invalid_tag:
35542
0
        JS_ThrowInternalError(s->ctx, "unsupported tag (%d)", tag);
35543
0
        goto fail;
35544
0
    }
35545
0
    return 0;
35546
35547
0
 fail:
35548
0
    return -1;
35549
0
}
35550
35551
/* create the atom table */
35552
static int JS_WriteObjectAtoms(BCWriterState *s)
35553
0
{
35554
0
    JSRuntime *rt = s->ctx->rt;
35555
0
    DynBuf dbuf1;
35556
0
    int i, atoms_size;
35557
35558
0
    dbuf1 = s->dbuf;
35559
0
    js_dbuf_init(s->ctx, &s->dbuf);
35560
0
    bc_put_u8(s, BC_VERSION);
35561
35562
0
    bc_put_leb128(s, s->idx_to_atom_count);
35563
0
    for(i = 0; i < s->idx_to_atom_count; i++) {
35564
0
        JSAtomStruct *p = rt->atom_array[s->idx_to_atom[i]];
35565
0
        JS_WriteString(s, p);
35566
0
    }
35567
    /* XXX: should check for OOM in above phase */
35568
35569
    /* move the atoms at the start */
35570
    /* XXX: could just append dbuf1 data, but it uses more memory if
35571
       dbuf1 is larger than dbuf */
35572
0
    atoms_size = s->dbuf.size;
35573
0
    if (dbuf_realloc(&dbuf1, dbuf1.size + atoms_size))
35574
0
        goto fail;
35575
0
    memmove(dbuf1.buf + atoms_size, dbuf1.buf, dbuf1.size);
35576
0
    memcpy(dbuf1.buf, s->dbuf.buf, atoms_size);
35577
0
    dbuf1.size += atoms_size;
35578
0
    dbuf_free(&s->dbuf);
35579
0
    s->dbuf = dbuf1;
35580
0
    return 0;
35581
0
 fail:
35582
0
    dbuf_free(&dbuf1);
35583
0
    return -1;
35584
0
}
35585
35586
uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
35587
                         int flags, uint8_t ***psab_tab, size_t *psab_tab_len)
35588
0
{
35589
0
    BCWriterState ss, *s = &ss;
35590
35591
0
    memset(s, 0, sizeof(*s));
35592
0
    s->ctx = ctx;
35593
0
    s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);
35594
0
    s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
35595
0
    s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0);
35596
    /* XXX: could use a different version when bytecode is included */
35597
0
    if (s->allow_bytecode)
35598
0
        s->first_atom = JS_ATOM_END;
35599
0
    else
35600
0
        s->first_atom = 1;
35601
0
    js_dbuf_init(ctx, &s->dbuf);
35602
0
    js_object_list_init(&s->object_list);
35603
35604
0
    if (JS_WriteObjectRec(s, obj))
35605
0
        goto fail;
35606
0
    if (JS_WriteObjectAtoms(s))
35607
0
        goto fail;
35608
0
    js_object_list_end(ctx, &s->object_list);
35609
0
    js_free(ctx, s->atom_to_idx);
35610
0
    js_free(ctx, s->idx_to_atom);
35611
0
    *psize = s->dbuf.size;
35612
0
    if (psab_tab)
35613
0
        *psab_tab = s->sab_tab;
35614
0
    if (psab_tab_len)
35615
0
        *psab_tab_len = s->sab_tab_len;
35616
0
    return s->dbuf.buf;
35617
0
 fail:
35618
0
    js_object_list_end(ctx, &s->object_list);
35619
0
    js_free(ctx, s->atom_to_idx);
35620
0
    js_free(ctx, s->idx_to_atom);
35621
0
    dbuf_free(&s->dbuf);
35622
0
    *psize = 0;
35623
0
    if (psab_tab)
35624
0
        *psab_tab = NULL;
35625
0
    if (psab_tab_len)
35626
0
        *psab_tab_len = 0;
35627
0
    return NULL;
35628
0
}
35629
35630
uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
35631
                        int flags)
35632
0
{
35633
0
    return JS_WriteObject2(ctx, psize, obj, flags, NULL, NULL);
35634
0
}
35635
35636
typedef struct BCReaderState {
35637
    JSContext *ctx;
35638
    const uint8_t *buf_start, *ptr, *buf_end;
35639
    uint32_t first_atom;
35640
    uint32_t idx_to_atom_count;
35641
    JSAtom *idx_to_atom;
35642
    int error_state;
35643
    BOOL allow_sab : 8;
35644
    BOOL allow_bytecode : 8;
35645
    BOOL is_rom_data : 8;
35646
    BOOL allow_reference : 8;
35647
    /* object references */
35648
    JSObject **objects;
35649
    int objects_count;
35650
    int objects_size;
35651
35652
#ifdef DUMP_READ_OBJECT
35653
    const uint8_t *ptr_last;
35654
    int level;
35655
#endif
35656
} BCReaderState;
35657
35658
#ifdef DUMP_READ_OBJECT
35659
static void __attribute__((format(printf, 2, 3))) bc_read_trace(BCReaderState *s, const char *fmt, ...) {
35660
    va_list ap;
35661
    int i, n, n0;
35662
35663
    if (!s->ptr_last)
35664
        s->ptr_last = s->buf_start;
35665
35666
    n = n0 = 0;
35667
    if (s->ptr > s->ptr_last || s->ptr == s->buf_start) {
35668
        n0 = printf("%04x: ", (int)(s->ptr_last - s->buf_start));
35669
        n += n0;
35670
    }
35671
    for (i = 0; s->ptr_last < s->ptr; i++) {
35672
        if ((i & 7) == 0 && i > 0) {
35673
            printf("\n%*s", n0, "");
35674
            n = n0;
35675
        }
35676
        n += printf(" %02x", *s->ptr_last++);
35677
    }
35678
    if (*fmt == '}')
35679
        s->level--;
35680
    if (n < 32 + s->level * 2) {
35681
        printf("%*s", 32 + s->level * 2 - n, "");
35682
    }
35683
    va_start(ap, fmt);
35684
    vfprintf(stdout, fmt, ap);
35685
    va_end(ap);
35686
    if (strchr(fmt, '{'))
35687
        s->level++;
35688
}
35689
#else
35690
#define bc_read_trace(...)
35691
#endif
35692
35693
static int bc_read_error_end(BCReaderState *s)
35694
0
{
35695
0
    if (!s->error_state) {
35696
0
        JS_ThrowSyntaxError(s->ctx, "read after the end of the buffer");
35697
0
    }
35698
0
    return s->error_state = -1;
35699
0
}
35700
35701
static int bc_get_u8(BCReaderState *s, uint8_t *pval)
35702
0
{
35703
0
    if (unlikely(s->buf_end - s->ptr < 1)) {
35704
0
        *pval = 0; /* avoid warning */
35705
0
        return bc_read_error_end(s);
35706
0
    }
35707
0
    *pval = *s->ptr++;
35708
0
    return 0;
35709
0
}
35710
35711
static int bc_get_u16(BCReaderState *s, uint16_t *pval)
35712
0
{
35713
0
    uint16_t v;
35714
0
    if (unlikely(s->buf_end - s->ptr < 2)) {
35715
0
        *pval = 0; /* avoid warning */
35716
0
        return bc_read_error_end(s);
35717
0
    }
35718
0
    v = get_u16(s->ptr);
35719
0
    if (is_be())
35720
0
        v = bswap16(v);
35721
0
    *pval = v;
35722
0
    s->ptr += 2;
35723
0
    return 0;
35724
0
}
35725
35726
static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
35727
0
{
35728
0
    uint32_t v;
35729
0
    if (unlikely(s->buf_end - s->ptr < 4)) {
35730
0
        *pval = 0; /* avoid warning */
35731
0
        return bc_read_error_end(s);
35732
0
    }
35733
0
    v = get_u32(s->ptr);
35734
0
    if (is_be())
35735
0
        v = bswap32(v);
35736
0
    *pval = v;
35737
0
    s->ptr += 4;
35738
0
    return 0;
35739
0
}
35740
35741
static int bc_get_u64(BCReaderState *s, uint64_t *pval)
35742
0
{
35743
0
    uint64_t v;
35744
0
    if (unlikely(s->buf_end - s->ptr < 8)) {
35745
0
        *pval = 0; /* avoid warning */
35746
0
        return bc_read_error_end(s);
35747
0
    }
35748
0
    v = get_u64(s->ptr);
35749
0
    if (is_be())
35750
0
        v = bswap64(v);
35751
0
    *pval = v;
35752
0
    s->ptr += 8;
35753
0
    return 0;
35754
0
}
35755
35756
static int bc_get_leb128(BCReaderState *s, uint32_t *pval)
35757
0
{
35758
0
    int ret;
35759
0
    ret = get_leb128(pval, s->ptr, s->buf_end);
35760
0
    if (unlikely(ret < 0))
35761
0
        return bc_read_error_end(s);
35762
0
    s->ptr += ret;
35763
0
    return 0;
35764
0
}
35765
35766
static int bc_get_sleb128(BCReaderState *s, int32_t *pval)
35767
0
{
35768
0
    int ret;
35769
0
    ret = get_sleb128(pval, s->ptr, s->buf_end);
35770
0
    if (unlikely(ret < 0))
35771
0
        return bc_read_error_end(s);
35772
0
    s->ptr += ret;
35773
0
    return 0;
35774
0
}
35775
35776
/* XXX: used to read an `int` with a positive value */
35777
static int bc_get_leb128_int(BCReaderState *s, int *pval)
35778
0
{
35779
0
    return bc_get_leb128(s, (uint32_t *)pval);
35780
0
}
35781
35782
static int bc_get_leb128_u16(BCReaderState *s, uint16_t *pval)
35783
0
{
35784
0
    uint32_t val;
35785
0
    if (bc_get_leb128(s, &val)) {
35786
0
        *pval = 0;
35787
0
        return -1;
35788
0
    }
35789
0
    *pval = val;
35790
0
    return 0;
35791
0
}
35792
35793
static int bc_get_buf(BCReaderState *s, uint8_t *buf, uint32_t buf_len)
35794
0
{
35795
0
    if (buf_len != 0) {
35796
0
        if (unlikely(!buf || s->buf_end - s->ptr < buf_len))
35797
0
            return bc_read_error_end(s);
35798
0
        memcpy(buf, s->ptr, buf_len);
35799
0
        s->ptr += buf_len;
35800
0
    }
35801
0
    return 0;
35802
0
}
35803
35804
static int bc_idx_to_atom(BCReaderState *s, JSAtom *patom, uint32_t idx)
35805
0
{
35806
0
    JSAtom atom;
35807
35808
0
    if (__JS_AtomIsTaggedInt(idx)) {
35809
0
        atom = idx;
35810
0
    } else if (idx < s->first_atom) {
35811
0
        atom = JS_DupAtom(s->ctx, idx);
35812
0
    } else {
35813
0
        idx -= s->first_atom;
35814
0
        if (idx >= s->idx_to_atom_count) {
35815
0
            JS_ThrowSyntaxError(s->ctx, "invalid atom index (pos=%u)",
35816
0
                                (unsigned int)(s->ptr - s->buf_start));
35817
0
            *patom = JS_ATOM_NULL;
35818
0
            return s->error_state = -1;
35819
0
        }
35820
0
        atom = JS_DupAtom(s->ctx, s->idx_to_atom[idx]);
35821
0
    }
35822
0
    *patom = atom;
35823
0
    return 0;
35824
0
}
35825
35826
static int bc_get_atom(BCReaderState *s, JSAtom *patom)
35827
0
{
35828
0
    uint32_t v;
35829
0
    if (bc_get_leb128(s, &v))
35830
0
        return -1;
35831
0
    if (v & 1) {
35832
0
        *patom = __JS_AtomFromUInt32(v >> 1);
35833
0
        return 0;
35834
0
    } else {
35835
0
        return bc_idx_to_atom(s, patom, v >> 1);
35836
0
    }
35837
0
}
35838
35839
static JSString *JS_ReadString(BCReaderState *s)
35840
0
{
35841
0
    uint32_t len;
35842
0
    size_t size;
35843
0
    BOOL is_wide_char;
35844
0
    JSString *p;
35845
35846
0
    if (bc_get_leb128(s, &len))
35847
0
        return NULL;
35848
0
    is_wide_char = len & 1;
35849
0
    len >>= 1;
35850
0
    p = js_alloc_string(s->ctx, len, is_wide_char);
35851
0
    if (!p) {
35852
0
        s->error_state = -1;
35853
0
        return NULL;
35854
0
    }
35855
0
    size = (size_t)len << is_wide_char;
35856
0
    if ((s->buf_end - s->ptr) < size) {
35857
0
        bc_read_error_end(s);
35858
0
        js_free_string(s->ctx->rt, p);
35859
0
        return NULL;
35860
0
    }
35861
0
    memcpy(p->u.str8, s->ptr, size);
35862
0
    s->ptr += size;
35863
0
    if (is_wide_char) {
35864
0
        if (is_be()) {
35865
0
            uint32_t i;
35866
0
            for (i = 0; i < len; i++)
35867
0
                p->u.str16[i] = bswap16(p->u.str16[i]);
35868
0
        }
35869
0
    } else {
35870
0
        p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */
35871
0
    }
35872
#ifdef DUMP_READ_OBJECT
35873
    JS_DumpString(s->ctx->rt, p); printf("\n");
35874
#endif
35875
0
    return p;
35876
0
}
35877
35878
static uint32_t bc_get_flags(uint32_t flags, int *pidx, int n)
35879
0
{
35880
0
    uint32_t val;
35881
    /* XXX: this does not work for n == 32 */
35882
0
    val = (flags >> *pidx) & ((1U << n) - 1);
35883
0
    *pidx += n;
35884
0
    return val;
35885
0
}
35886
35887
static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
35888
                                   int byte_code_offset, uint32_t bc_len)
35889
0
{
35890
0
    uint8_t *bc_buf;
35891
0
    int pos, len, op;
35892
0
    JSAtom atom;
35893
0
    uint32_t idx;
35894
35895
0
    if (s->is_rom_data) {
35896
        /* directly use the input buffer */
35897
0
        if (unlikely(s->buf_end - s->ptr < bc_len))
35898
0
            return bc_read_error_end(s);
35899
0
        bc_buf = (uint8_t *)s->ptr;
35900
0
        s->ptr += bc_len;
35901
0
    } else {
35902
0
        bc_buf = (void *)((uint8_t*)b + byte_code_offset);
35903
0
        if (bc_get_buf(s, bc_buf, bc_len))
35904
0
            return -1;
35905
0
    }
35906
0
    b->byte_code_buf = bc_buf;
35907
35908
0
    if (is_be())
35909
0
        bc_byte_swap(bc_buf, bc_len);
35910
35911
0
    pos = 0;
35912
0
    while (pos < bc_len) {
35913
0
        op = bc_buf[pos];
35914
0
        len = short_opcode_info(op).size;
35915
0
        switch(short_opcode_info(op).fmt) {
35916
0
        case OP_FMT_atom:
35917
0
        case OP_FMT_atom_u8:
35918
0
        case OP_FMT_atom_u16:
35919
0
        case OP_FMT_atom_label_u8:
35920
0
        case OP_FMT_atom_label_u16:
35921
0
            idx = get_u32(bc_buf + pos + 1);
35922
0
            if (s->is_rom_data) {
35923
                /* just increment the reference count of the atom */
35924
0
                JS_DupAtom(s->ctx, (JSAtom)idx);
35925
0
            } else {
35926
0
                if (bc_idx_to_atom(s, &atom, idx)) {
35927
                    /* Note: the atoms will be freed up to this position */
35928
0
                    b->byte_code_len = pos;
35929
0
                    return -1;
35930
0
                }
35931
0
                put_u32(bc_buf + pos + 1, atom);
35932
#ifdef DUMP_READ_OBJECT
35933
                bc_read_trace(s, "at %d, fixup atom: ", pos + 1); print_atom(s->ctx, atom); printf("\n");
35934
#endif
35935
0
            }
35936
0
            break;
35937
0
        default:
35938
0
            break;
35939
0
        }
35940
0
        pos += len;
35941
0
    }
35942
0
    return 0;
35943
0
}
35944
35945
static JSValue JS_ReadBigNum(BCReaderState *s, int tag)
35946
0
{
35947
0
    JSValue obj = JS_UNDEFINED;
35948
0
    uint8_t v8;
35949
0
    int32_t e;
35950
0
    uint32_t len;
35951
0
    limb_t l, i, n;
35952
0
    JSBigFloat *p;
35953
0
    limb_t v;
35954
0
    bf_t *a;
35955
35956
0
    p = js_new_bf(s->ctx);
35957
0
    if (!p)
35958
0
        goto fail;
35959
0
    switch(tag) {
35960
0
    case BC_TAG_BIG_INT:
35961
0
        obj = JS_MKPTR(JS_TAG_BIG_INT, p);
35962
0
        break;
35963
0
#ifdef CONFIG_BIGNUM
35964
0
    case BC_TAG_BIG_FLOAT:
35965
0
        obj = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
35966
0
        break;
35967
0
    case BC_TAG_BIG_DECIMAL:
35968
0
        obj = JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
35969
0
        break;
35970
0
#endif
35971
0
    default:
35972
0
        abort();
35973
0
    }
35974
35975
    /* sign + exponent */
35976
0
    if (bc_get_sleb128(s, &e))
35977
0
        goto fail;
35978
35979
0
    a = &p->num;
35980
0
    a->sign = e & 1;
35981
0
    e >>= 1;
35982
0
    if (e == 0)
35983
0
        a->expn = BF_EXP_ZERO;
35984
0
    else if (e == 1)
35985
0
        a->expn = BF_EXP_INF;
35986
0
    else if (e == 2)
35987
0
        a->expn = BF_EXP_NAN;
35988
0
    else if (e >= 3)
35989
0
        a->expn = e - 3;
35990
0
    else
35991
0
        a->expn = e;
35992
35993
    /* mantissa */
35994
0
    if (a->expn != BF_EXP_ZERO &&
35995
0
        a->expn != BF_EXP_INF &&
35996
0
        a->expn != BF_EXP_NAN) {
35997
0
        if (bc_get_leb128(s, &len))
35998
0
            goto fail;
35999
0
        bc_read_trace(s, "len=%" PRId64 "\n", (int64_t)len);
36000
0
        if (len == 0) {
36001
0
            JS_ThrowInternalError(s->ctx, "invalid bignum length");
36002
0
            goto fail;
36003
0
        }
36004
0
#ifdef CONFIG_BIGNUM
36005
0
        if (tag == BC_TAG_BIG_DECIMAL) {
36006
0
            l = (len + LIMB_DIGITS - 1) / LIMB_DIGITS;
36007
0
        } else
36008
0
#endif
36009
0
        {
36010
0
            l = (len + sizeof(limb_t) - 1) / sizeof(limb_t);
36011
0
        }
36012
0
        if (bf_resize(a, l)) {
36013
0
            JS_ThrowOutOfMemory(s->ctx);
36014
0
            goto fail;
36015
0
        }
36016
0
#ifdef CONFIG_BIGNUM
36017
0
        if (tag == BC_TAG_BIG_DECIMAL) {
36018
0
            limb_t j;
36019
0
            int bpos, d;
36020
36021
0
            bpos = 0;
36022
0
            for(i = 0; i < l; i++) {
36023
0
                if (i == 0 && (n = len % LIMB_DIGITS) != 0) {
36024
0
                    j = LIMB_DIGITS - n;
36025
0
                } else {
36026
0
                    j = 0;
36027
0
                }
36028
0
                v = 0;
36029
0
                for(; j < LIMB_DIGITS; j++) {
36030
0
                    if (bpos == 0) {
36031
0
                        if (bc_get_u8(s, &v8))
36032
0
                            goto fail;
36033
0
                        d = v8 & 0xf;
36034
0
                        bpos = 1;
36035
0
                    } else {
36036
0
                        d = v8 >> 4;
36037
0
                        bpos = 0;
36038
0
                    }
36039
0
                    if (d >= 10) {
36040
0
                        JS_ThrowInternalError(s->ctx, "invalid digit");
36041
0
                        goto fail;
36042
0
                    }
36043
0
                    v += mp_pow_dec[j] * d;
36044
0
                }
36045
0
                a->tab[i] = v;
36046
0
            }
36047
0
        } else
36048
0
#endif  /* CONFIG_BIGNUM */
36049
0
        {
36050
0
            n = len & (sizeof(limb_t) - 1);
36051
0
            if (n != 0) {
36052
0
                v = 0;
36053
0
                for(i = 0; i < n; i++) {
36054
0
                    if (bc_get_u8(s, &v8))
36055
0
                        goto fail;
36056
0
                    v |= (limb_t)v8 << ((sizeof(limb_t) - n + i) * 8);
36057
0
                }
36058
0
                a->tab[0] = v;
36059
0
                i = 1;
36060
0
            } else {
36061
0
                i = 0;
36062
0
            }
36063
0
            for(; i < l; i++) {
36064
#if LIMB_BITS == 32
36065
                if (bc_get_u32(s, &v))
36066
                    goto fail;
36067
#else
36068
0
                if (bc_get_u64(s, &v))
36069
0
                    goto fail;
36070
0
#endif
36071
0
                a->tab[i] = v;
36072
0
            }
36073
0
        }
36074
0
    }
36075
0
    bc_read_trace(s, "}\n");
36076
0
    return obj;
36077
0
 fail:
36078
0
    JS_FreeValue(s->ctx, obj);
36079
0
    return JS_EXCEPTION;
36080
0
}
36081
36082
static JSValue JS_ReadObjectRec(BCReaderState *s);
36083
36084
static int BC_add_object_ref1(BCReaderState *s, JSObject *p)
36085
0
{
36086
0
    if (s->allow_reference) {
36087
0
        if (js_resize_array(s->ctx, (void *)&s->objects,
36088
0
                            sizeof(s->objects[0]),
36089
0
                            &s->objects_size, s->objects_count + 1))
36090
0
            return -1;
36091
0
        s->objects[s->objects_count++] = p;
36092
0
    }
36093
0
    return 0;
36094
0
}
36095
36096
static int BC_add_object_ref(BCReaderState *s, JSValueConst obj)
36097
0
{
36098
0
    return BC_add_object_ref1(s, JS_VALUE_GET_OBJ(obj));
36099
0
}
36100
36101
static JSValue JS_ReadFunctionTag(BCReaderState *s)
36102
0
{
36103
0
    JSContext *ctx = s->ctx;
36104
0
    JSFunctionBytecode bc, *b;
36105
0
    JSValue obj = JS_UNDEFINED;
36106
0
    uint16_t v16;
36107
0
    uint8_t v8;
36108
0
    int idx, i, local_count;
36109
0
    int function_size, cpool_offset, byte_code_offset;
36110
0
    int closure_var_offset, vardefs_offset;
36111
36112
0
    memset(&bc, 0, sizeof(bc));
36113
0
    bc.header.ref_count = 1;
36114
    //bc.gc_header.mark = 0;
36115
36116
0
    if (bc_get_u16(s, &v16))
36117
0
        goto fail;
36118
0
    idx = 0;
36119
0
    bc.has_prototype = bc_get_flags(v16, &idx, 1);
36120
0
    bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1);
36121
0
    bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1);
36122
0
    bc.need_home_object = bc_get_flags(v16, &idx, 1);
36123
0
    bc.func_kind = bc_get_flags(v16, &idx, 2);
36124
0
    bc.new_target_allowed = bc_get_flags(v16, &idx, 1);
36125
0
    bc.super_call_allowed = bc_get_flags(v16, &idx, 1);
36126
0
    bc.super_allowed = bc_get_flags(v16, &idx, 1);
36127
0
    bc.arguments_allowed = bc_get_flags(v16, &idx, 1);
36128
0
    bc.has_debug = bc_get_flags(v16, &idx, 1);
36129
0
    bc.backtrace_barrier = bc_get_flags(v16, &idx, 1);
36130
0
    bc.is_direct_or_indirect_eval = bc_get_flags(v16, &idx, 1);
36131
0
    bc.read_only_bytecode = s->is_rom_data;
36132
0
    if (bc_get_u8(s, &v8))
36133
0
        goto fail;
36134
0
    bc.js_mode = v8;
36135
0
    if (bc_get_atom(s, &bc.func_name))  //@ atom leak if failure
36136
0
        goto fail;
36137
0
    if (bc_get_leb128_u16(s, &bc.arg_count))
36138
0
        goto fail;
36139
0
    if (bc_get_leb128_u16(s, &bc.var_count))
36140
0
        goto fail;
36141
0
    if (bc_get_leb128_u16(s, &bc.defined_arg_count))
36142
0
        goto fail;
36143
0
    if (bc_get_leb128_u16(s, &bc.stack_size))
36144
0
        goto fail;
36145
0
    if (bc_get_leb128_int(s, &bc.closure_var_count))
36146
0
        goto fail;
36147
0
    if (bc_get_leb128_int(s, &bc.cpool_count))
36148
0
        goto fail;
36149
0
    if (bc_get_leb128_int(s, &bc.byte_code_len))
36150
0
        goto fail;
36151
0
    if (bc_get_leb128_int(s, &local_count))
36152
0
        goto fail;
36153
36154
0
    if (bc.has_debug) {
36155
0
        function_size = sizeof(*b);
36156
0
    } else {
36157
0
        function_size = offsetof(JSFunctionBytecode, debug);
36158
0
    }
36159
0
    cpool_offset = function_size;
36160
0
    function_size += bc.cpool_count * sizeof(*bc.cpool);
36161
0
    vardefs_offset = function_size;
36162
0
    function_size += local_count * sizeof(*bc.vardefs);
36163
0
    closure_var_offset = function_size;
36164
0
    function_size += bc.closure_var_count * sizeof(*bc.closure_var);
36165
0
    byte_code_offset = function_size;
36166
0
    if (!bc.read_only_bytecode) {
36167
0
        function_size += bc.byte_code_len;
36168
0
    }
36169
36170
0
    b = js_mallocz(ctx, function_size);
36171
0
    if (!b)
36172
0
        return JS_EXCEPTION;
36173
36174
0
    memcpy(b, &bc, offsetof(JSFunctionBytecode, debug));
36175
0
    b->header.ref_count = 1;
36176
0
    if (local_count != 0) {
36177
0
        b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
36178
0
    }
36179
0
    if (b->closure_var_count != 0) {
36180
0
        b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
36181
0
    }
36182
0
    if (b->cpool_count != 0) {
36183
0
        b->cpool = (void *)((uint8_t*)b + cpool_offset);
36184
0
    }
36185
36186
0
    add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
36187
36188
0
    obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
36189
36190
#ifdef DUMP_READ_OBJECT
36191
    bc_read_trace(s, "name: "); print_atom(s->ctx, b->func_name); printf("\n");
36192
#endif
36193
0
    bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n",
36194
0
                  b->arg_count, b->var_count, b->defined_arg_count,
36195
0
                  b->closure_var_count, b->cpool_count);
36196
0
    bc_read_trace(s, "stack=%d bclen=%d locals=%d\n",
36197
0
                  b->stack_size, b->byte_code_len, local_count);
36198
36199
0
    if (local_count != 0) {
36200
0
        bc_read_trace(s, "vars {\n");
36201
0
        for(i = 0; i < local_count; i++) {
36202
0
            JSVarDef *vd = &b->vardefs[i];
36203
0
            if (bc_get_atom(s, &vd->var_name))
36204
0
                goto fail;
36205
0
            if (bc_get_leb128_int(s, &vd->scope_level))
36206
0
                goto fail;
36207
0
            if (bc_get_leb128_int(s, &vd->scope_next))
36208
0
                goto fail;
36209
0
            vd->scope_next--;
36210
0
            if (bc_get_u8(s, &v8))
36211
0
                goto fail;
36212
0
            idx = 0;
36213
0
            vd->var_kind = bc_get_flags(v8, &idx, 4);
36214
0
            vd->is_const = bc_get_flags(v8, &idx, 1);
36215
0
            vd->is_lexical = bc_get_flags(v8, &idx, 1);
36216
0
            vd->is_captured = bc_get_flags(v8, &idx, 1);
36217
#ifdef DUMP_READ_OBJECT
36218
            bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n");
36219
#endif
36220
0
        }
36221
0
        bc_read_trace(s, "}\n");
36222
0
    }
36223
0
    if (b->closure_var_count != 0) {
36224
0
        bc_read_trace(s, "closure vars {\n");
36225
0
        for(i = 0; i < b->closure_var_count; i++) {
36226
0
            JSClosureVar *cv = &b->closure_var[i];
36227
0
            int var_idx;
36228
0
            if (bc_get_atom(s, &cv->var_name))
36229
0
                goto fail;
36230
0
            if (bc_get_leb128_int(s, &var_idx))
36231
0
                goto fail;
36232
0
            cv->var_idx = var_idx;
36233
0
            if (bc_get_u8(s, &v8))
36234
0
                goto fail;
36235
0
            idx = 0;
36236
0
            cv->is_local = bc_get_flags(v8, &idx, 1);
36237
0
            cv->is_arg = bc_get_flags(v8, &idx, 1);
36238
0
            cv->is_const = bc_get_flags(v8, &idx, 1);
36239
0
            cv->is_lexical = bc_get_flags(v8, &idx, 1);
36240
0
            cv->var_kind = bc_get_flags(v8, &idx, 4);
36241
#ifdef DUMP_READ_OBJECT
36242
            bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); printf("\n");
36243
#endif
36244
0
        }
36245
0
        bc_read_trace(s, "}\n");
36246
0
    }
36247
0
    {
36248
0
        bc_read_trace(s, "bytecode {\n");
36249
0
        if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len))
36250
0
            goto fail;
36251
0
        bc_read_trace(s, "}\n");
36252
0
    }
36253
0
    if (b->has_debug) {
36254
        /* read optional debug information */
36255
0
        bc_read_trace(s, "debug {\n");
36256
0
        if (bc_get_atom(s, &b->debug.filename))
36257
0
            goto fail;
36258
0
        if (bc_get_leb128_int(s, &b->debug.line_num))
36259
0
            goto fail;
36260
0
        if (bc_get_leb128_int(s, &b->debug.pc2line_len))
36261
0
            goto fail;
36262
0
        if (b->debug.pc2line_len) {
36263
0
            b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len);
36264
0
            if (!b->debug.pc2line_buf)
36265
0
                goto fail;
36266
0
            if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len))
36267
0
                goto fail;
36268
0
        }
36269
#ifdef DUMP_READ_OBJECT
36270
        bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n");
36271
#endif
36272
0
        bc_read_trace(s, "}\n");
36273
0
    }
36274
0
    if (b->cpool_count != 0) {
36275
0
        bc_read_trace(s, "cpool {\n");
36276
0
        for(i = 0; i < b->cpool_count; i++) {
36277
0
            JSValue val;
36278
0
            val = JS_ReadObjectRec(s);
36279
0
            if (JS_IsException(val))
36280
0
                goto fail;
36281
0
            b->cpool[i] = val;
36282
0
        }
36283
0
        bc_read_trace(s, "}\n");
36284
0
    }
36285
0
    b->realm = JS_DupContext(ctx);
36286
0
    return obj;
36287
0
 fail:
36288
0
    JS_FreeValue(ctx, obj);
36289
0
    return JS_EXCEPTION;
36290
0
}
36291
36292
static JSValue JS_ReadModule(BCReaderState *s)
36293
0
{
36294
0
    JSContext *ctx = s->ctx;
36295
0
    JSValue obj;
36296
0
    JSModuleDef *m = NULL;
36297
0
    JSAtom module_name;
36298
0
    int i;
36299
0
    uint8_t v8;
36300
36301
0
    if (bc_get_atom(s, &module_name))
36302
0
        goto fail;
36303
#ifdef DUMP_READ_OBJECT
36304
    bc_read_trace(s, "name: "); print_atom(s->ctx, module_name); printf("\n");
36305
#endif
36306
0
    m = js_new_module_def(ctx, module_name);
36307
0
    if (!m)
36308
0
        goto fail;
36309
0
    obj = JS_NewModuleValue(ctx, m);
36310
0
    if (bc_get_leb128_int(s, &m->req_module_entries_count))
36311
0
        goto fail;
36312
0
    if (m->req_module_entries_count != 0) {
36313
0
        m->req_module_entries_size = m->req_module_entries_count;
36314
0
        m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size);
36315
0
        if (!m->req_module_entries)
36316
0
            goto fail;
36317
0
        for(i = 0; i < m->req_module_entries_count; i++) {
36318
0
            JSReqModuleEntry *rme = &m->req_module_entries[i];
36319
0
            if (bc_get_atom(s, &rme->module_name))
36320
0
                goto fail;
36321
0
        }
36322
0
    }
36323
36324
0
    if (bc_get_leb128_int(s, &m->export_entries_count))
36325
0
        goto fail;
36326
0
    if (m->export_entries_count != 0) {
36327
0
        m->export_entries_size = m->export_entries_count;
36328
0
        m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size);
36329
0
        if (!m->export_entries)
36330
0
            goto fail;
36331
0
        for(i = 0; i < m->export_entries_count; i++) {
36332
0
            JSExportEntry *me = &m->export_entries[i];
36333
0
            if (bc_get_u8(s, &v8))
36334
0
                goto fail;
36335
0
            me->export_type = v8;
36336
0
            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
36337
0
                if (bc_get_leb128_int(s, &me->u.local.var_idx))
36338
0
                    goto fail;
36339
0
            } else {
36340
0
                if (bc_get_leb128_int(s, &me->u.req_module_idx))
36341
0
                    goto fail;
36342
0
                if (bc_get_atom(s, &me->local_name))
36343
0
                    goto fail;
36344
0
            }
36345
0
            if (bc_get_atom(s, &me->export_name))
36346
0
                goto fail;
36347
0
        }
36348
0
    }
36349
36350
0
    if (bc_get_leb128_int(s, &m->star_export_entries_count))
36351
0
        goto fail;
36352
0
    if (m->star_export_entries_count != 0) {
36353
0
        m->star_export_entries_size = m->star_export_entries_count;
36354
0
        m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size);
36355
0
        if (!m->star_export_entries)
36356
0
            goto fail;
36357
0
        for(i = 0; i < m->star_export_entries_count; i++) {
36358
0
            JSStarExportEntry *se = &m->star_export_entries[i];
36359
0
            if (bc_get_leb128_int(s, &se->req_module_idx))
36360
0
                goto fail;
36361
0
        }
36362
0
    }
36363
36364
0
    if (bc_get_leb128_int(s, &m->import_entries_count))
36365
0
        goto fail;
36366
0
    if (m->import_entries_count != 0) {
36367
0
        m->import_entries_size = m->import_entries_count;
36368
0
        m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size);
36369
0
        if (!m->import_entries)
36370
0
            goto fail;
36371
0
        for(i = 0; i < m->import_entries_count; i++) {
36372
0
            JSImportEntry *mi = &m->import_entries[i];
36373
0
            if (bc_get_leb128_int(s, &mi->var_idx))
36374
0
                goto fail;
36375
0
            if (bc_get_atom(s, &mi->import_name))
36376
0
                goto fail;
36377
0
            if (bc_get_leb128_int(s, &mi->req_module_idx))
36378
0
                goto fail;
36379
0
        }
36380
0
    }
36381
36382
0
    if (bc_get_u8(s, &v8))
36383
0
        goto fail;
36384
0
    m->has_tla = (v8 != 0);
36385
36386
0
    m->func_obj = JS_ReadObjectRec(s);
36387
0
    if (JS_IsException(m->func_obj))
36388
0
        goto fail;
36389
0
    return obj;
36390
0
 fail:
36391
0
    if (m) {
36392
0
        js_free_module_def(ctx, m);
36393
0
    }
36394
0
    return JS_EXCEPTION;
36395
0
}
36396
36397
static JSValue JS_ReadObjectTag(BCReaderState *s)
36398
0
{
36399
0
    JSContext *ctx = s->ctx;
36400
0
    JSValue obj;
36401
0
    uint32_t prop_count, i;
36402
0
    JSAtom atom;
36403
0
    JSValue val;
36404
0
    int ret;
36405
36406
0
    obj = JS_NewObject(ctx);
36407
0
    if (BC_add_object_ref(s, obj))
36408
0
        goto fail;
36409
0
    if (bc_get_leb128(s, &prop_count))
36410
0
        goto fail;
36411
0
    for(i = 0; i < prop_count; i++) {
36412
0
        if (bc_get_atom(s, &atom))
36413
0
            goto fail;
36414
#ifdef DUMP_READ_OBJECT
36415
        bc_read_trace(s, "propname: "); print_atom(s->ctx, atom); printf("\n");
36416
#endif
36417
0
        val = JS_ReadObjectRec(s);
36418
0
        if (JS_IsException(val)) {
36419
0
            JS_FreeAtom(ctx, atom);
36420
0
            goto fail;
36421
0
        }
36422
0
        ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E);
36423
0
        JS_FreeAtom(ctx, atom);
36424
0
        if (ret < 0)
36425
0
            goto fail;
36426
0
    }
36427
0
    return obj;
36428
0
 fail:
36429
0
    JS_FreeValue(ctx, obj);
36430
0
    return JS_EXCEPTION;
36431
0
}
36432
36433
static JSValue JS_ReadArray(BCReaderState *s, int tag)
36434
0
{
36435
0
    JSContext *ctx = s->ctx;
36436
0
    JSValue obj;
36437
0
    uint32_t len, i;
36438
0
    JSValue val;
36439
0
    int ret, prop_flags;
36440
0
    BOOL is_template;
36441
36442
0
    obj = JS_NewArray(ctx);
36443
0
    if (BC_add_object_ref(s, obj))
36444
0
        goto fail;
36445
0
    is_template = (tag == BC_TAG_TEMPLATE_OBJECT);
36446
0
    if (bc_get_leb128(s, &len))
36447
0
        goto fail;
36448
0
    for(i = 0; i < len; i++) {
36449
0
        val = JS_ReadObjectRec(s);
36450
0
        if (JS_IsException(val))
36451
0
            goto fail;
36452
0
        if (is_template)
36453
0
            prop_flags = JS_PROP_ENUMERABLE;
36454
0
        else
36455
0
            prop_flags = JS_PROP_C_W_E;
36456
0
        ret = JS_DefinePropertyValueUint32(ctx, obj, i, val,
36457
0
                                           prop_flags);
36458
0
        if (ret < 0)
36459
0
            goto fail;
36460
0
    }
36461
0
    if (is_template) {
36462
0
        val = JS_ReadObjectRec(s);
36463
0
        if (JS_IsException(val))
36464
0
            goto fail;
36465
0
        if (!JS_IsUndefined(val)) {
36466
0
            ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0);
36467
0
            if (ret < 0)
36468
0
                goto fail;
36469
0
        }
36470
0
        JS_PreventExtensions(ctx, obj);
36471
0
    }
36472
0
    return obj;
36473
0
 fail:
36474
0
    JS_FreeValue(ctx, obj);
36475
0
    return JS_EXCEPTION;
36476
0
}
36477
36478
static JSValue JS_ReadTypedArray(BCReaderState *s)
36479
0
{
36480
0
    JSContext *ctx = s->ctx;
36481
0
    JSValue obj = JS_UNDEFINED, array_buffer = JS_UNDEFINED;
36482
0
    uint8_t array_tag;
36483
0
    JSValueConst args[3];
36484
0
    uint32_t offset, len, idx;
36485
36486
0
    if (bc_get_u8(s, &array_tag))
36487
0
        return JS_EXCEPTION;
36488
0
    if (array_tag >= JS_TYPED_ARRAY_COUNT)
36489
0
        return JS_ThrowTypeError(ctx, "invalid typed array");
36490
0
    if (bc_get_leb128(s, &len))
36491
0
        return JS_EXCEPTION;
36492
0
    if (bc_get_leb128(s, &offset))
36493
0
        return JS_EXCEPTION;
36494
    /* XXX: this hack could be avoided if the typed array could be
36495
       created before the array buffer */
36496
0
    idx = s->objects_count;
36497
0
    if (BC_add_object_ref1(s, NULL))
36498
0
        goto fail;
36499
0
    array_buffer = JS_ReadObjectRec(s);
36500
0
    if (JS_IsException(array_buffer))
36501
0
        return JS_EXCEPTION;
36502
0
    if (!js_get_array_buffer(ctx, array_buffer)) {
36503
0
        JS_FreeValue(ctx, array_buffer);
36504
0
        return JS_EXCEPTION;
36505
0
    }
36506
0
    args[0] = array_buffer;
36507
0
    args[1] = JS_NewInt64(ctx, offset);
36508
0
    args[2] = JS_NewInt64(ctx, len);
36509
0
    obj = js_typed_array_constructor(ctx, JS_UNDEFINED,
36510
0
                                     3, args,
36511
0
                                     JS_CLASS_UINT8C_ARRAY + array_tag);
36512
0
    if (JS_IsException(obj))
36513
0
        goto fail;
36514
0
    if (s->allow_reference) {
36515
0
        s->objects[idx] = JS_VALUE_GET_OBJ(obj);
36516
0
    }
36517
0
    JS_FreeValue(ctx, array_buffer);
36518
0
    return obj;
36519
0
 fail:
36520
0
    JS_FreeValue(ctx, array_buffer);
36521
0
    JS_FreeValue(ctx, obj);
36522
0
    return JS_EXCEPTION;
36523
0
}
36524
36525
static JSValue JS_ReadArrayBuffer(BCReaderState *s)
36526
0
{
36527
0
    JSContext *ctx = s->ctx;
36528
0
    uint32_t byte_length;
36529
0
    JSValue obj;
36530
36531
0
    if (bc_get_leb128(s, &byte_length))
36532
0
        return JS_EXCEPTION;
36533
0
    if (unlikely(s->buf_end - s->ptr < byte_length)) {
36534
0
        bc_read_error_end(s);
36535
0
        return JS_EXCEPTION;
36536
0
    }
36537
0
    obj = JS_NewArrayBufferCopy(ctx, s->ptr, byte_length);
36538
0
    if (JS_IsException(obj))
36539
0
        goto fail;
36540
0
    if (BC_add_object_ref(s, obj))
36541
0
        goto fail;
36542
0
    s->ptr += byte_length;
36543
0
    return obj;
36544
0
 fail:
36545
0
    JS_FreeValue(ctx, obj);
36546
0
    return JS_EXCEPTION;
36547
0
}
36548
36549
static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s)
36550
0
{
36551
0
    JSContext *ctx = s->ctx;
36552
0
    uint32_t byte_length;
36553
0
    uint8_t *data_ptr;
36554
0
    JSValue obj;
36555
0
    uint64_t u64;
36556
36557
0
    if (bc_get_leb128(s, &byte_length))
36558
0
        return JS_EXCEPTION;
36559
0
    if (bc_get_u64(s, &u64))
36560
0
        return JS_EXCEPTION;
36561
0
    data_ptr = (uint8_t *)(uintptr_t)u64;
36562
    /* the SharedArrayBuffer is cloned */
36563
0
    obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED, byte_length,
36564
0
                                       JS_CLASS_SHARED_ARRAY_BUFFER,
36565
0
                                       data_ptr,
36566
0
                                       NULL, NULL, FALSE);
36567
0
    if (JS_IsException(obj))
36568
0
        goto fail;
36569
0
    if (BC_add_object_ref(s, obj))
36570
0
        goto fail;
36571
0
    return obj;
36572
0
 fail:
36573
0
    JS_FreeValue(ctx, obj);
36574
0
    return JS_EXCEPTION;
36575
0
}
36576
36577
static JSValue JS_ReadDate(BCReaderState *s)
36578
0
{
36579
0
    JSContext *ctx = s->ctx;
36580
0
    JSValue val, obj = JS_UNDEFINED;
36581
36582
0
    val = JS_ReadObjectRec(s);
36583
0
    if (JS_IsException(val))
36584
0
        goto fail;
36585
0
    if (!JS_IsNumber(val)) {
36586
0
        JS_ThrowTypeError(ctx, "Number tag expected for date");
36587
0
        goto fail;
36588
0
    }
36589
0
    obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_DATE],
36590
0
                                 JS_CLASS_DATE);
36591
0
    if (JS_IsException(obj))
36592
0
        goto fail;
36593
0
    if (BC_add_object_ref(s, obj))
36594
0
        goto fail;
36595
0
    JS_SetObjectData(ctx, obj, val);
36596
0
    return obj;
36597
0
 fail:
36598
0
    JS_FreeValue(ctx, val);
36599
0
    JS_FreeValue(ctx, obj);
36600
0
    return JS_EXCEPTION;
36601
0
}
36602
36603
static JSValue JS_ReadObjectValue(BCReaderState *s)
36604
0
{
36605
0
    JSContext *ctx = s->ctx;
36606
0
    JSValue val, obj = JS_UNDEFINED;
36607
36608
0
    val = JS_ReadObjectRec(s);
36609
0
    if (JS_IsException(val))
36610
0
        goto fail;
36611
0
    obj = JS_ToObject(ctx, val);
36612
0
    if (JS_IsException(obj))
36613
0
        goto fail;
36614
0
    if (BC_add_object_ref(s, obj))
36615
0
        goto fail;
36616
0
    JS_FreeValue(ctx, val);
36617
0
    return obj;
36618
0
 fail:
36619
0
    JS_FreeValue(ctx, val);
36620
0
    JS_FreeValue(ctx, obj);
36621
0
    return JS_EXCEPTION;
36622
0
}
36623
36624
static JSValue JS_ReadObjectRec(BCReaderState *s)
36625
0
{
36626
0
    JSContext *ctx = s->ctx;
36627
0
    uint8_t tag;
36628
0
    JSValue obj = JS_UNDEFINED;
36629
36630
0
    if (js_check_stack_overflow(ctx->rt, 0))
36631
0
        return JS_ThrowStackOverflow(ctx);
36632
36633
0
    if (bc_get_u8(s, &tag))
36634
0
        return JS_EXCEPTION;
36635
36636
0
    bc_read_trace(s, "%s {\n", bc_tag_str[tag]);
36637
36638
0
    switch(tag) {
36639
0
    case BC_TAG_NULL:
36640
0
        obj = JS_NULL;
36641
0
        break;
36642
0
    case BC_TAG_UNDEFINED:
36643
0
        obj = JS_UNDEFINED;
36644
0
        break;
36645
0
    case BC_TAG_BOOL_FALSE:
36646
0
    case BC_TAG_BOOL_TRUE:
36647
0
        obj = JS_NewBool(ctx, tag - BC_TAG_BOOL_FALSE);
36648
0
        break;
36649
0
    case BC_TAG_INT32:
36650
0
        {
36651
0
            int32_t val;
36652
0
            if (bc_get_sleb128(s, &val))
36653
0
                return JS_EXCEPTION;
36654
0
            bc_read_trace(s, "%d\n", val);
36655
0
            obj = JS_NewInt32(ctx, val);
36656
0
        }
36657
0
        break;
36658
0
    case BC_TAG_FLOAT64:
36659
0
        {
36660
0
            JSFloat64Union u;
36661
0
            if (bc_get_u64(s, &u.u64))
36662
0
                return JS_EXCEPTION;
36663
0
            bc_read_trace(s, "%g\n", u.d);
36664
0
            obj = __JS_NewFloat64(ctx, u.d);
36665
0
        }
36666
0
        break;
36667
0
    case BC_TAG_STRING:
36668
0
        {
36669
0
            JSString *p;
36670
0
            p = JS_ReadString(s);
36671
0
            if (!p)
36672
0
                return JS_EXCEPTION;
36673
0
            obj = JS_MKPTR(JS_TAG_STRING, p);
36674
0
        }
36675
0
        break;
36676
0
    case BC_TAG_FUNCTION_BYTECODE:
36677
0
        if (!s->allow_bytecode)
36678
0
            goto invalid_tag;
36679
0
        obj = JS_ReadFunctionTag(s);
36680
0
        break;
36681
0
    case BC_TAG_MODULE:
36682
0
        if (!s->allow_bytecode)
36683
0
            goto invalid_tag;
36684
0
        obj = JS_ReadModule(s);
36685
0
        break;
36686
0
    case BC_TAG_OBJECT:
36687
0
        obj = JS_ReadObjectTag(s);
36688
0
        break;
36689
0
    case BC_TAG_ARRAY:
36690
0
    case BC_TAG_TEMPLATE_OBJECT:
36691
0
        obj = JS_ReadArray(s, tag);
36692
0
        break;
36693
0
    case BC_TAG_TYPED_ARRAY:
36694
0
        obj = JS_ReadTypedArray(s);
36695
0
        break;
36696
0
    case BC_TAG_ARRAY_BUFFER:
36697
0
        obj = JS_ReadArrayBuffer(s);
36698
0
        break;
36699
0
    case BC_TAG_SHARED_ARRAY_BUFFER:
36700
0
        if (!s->allow_sab || !ctx->rt->sab_funcs.sab_dup)
36701
0
            goto invalid_tag;
36702
0
        obj = JS_ReadSharedArrayBuffer(s);
36703
0
        break;
36704
0
    case BC_TAG_DATE:
36705
0
        obj = JS_ReadDate(s);
36706
0
        break;
36707
0
    case BC_TAG_OBJECT_VALUE:
36708
0
        obj = JS_ReadObjectValue(s);
36709
0
        break;
36710
0
    case BC_TAG_BIG_INT:
36711
0
#ifdef CONFIG_BIGNUM
36712
0
    case BC_TAG_BIG_FLOAT:
36713
0
    case BC_TAG_BIG_DECIMAL:
36714
0
#endif
36715
0
        obj = JS_ReadBigNum(s, tag);
36716
0
        break;
36717
0
    case BC_TAG_OBJECT_REFERENCE:
36718
0
        {
36719
0
            uint32_t val;
36720
0
            if (!s->allow_reference)
36721
0
                return JS_ThrowSyntaxError(ctx, "object references are not allowed");
36722
0
            if (bc_get_leb128(s, &val))
36723
0
                return JS_EXCEPTION;
36724
0
            bc_read_trace(s, "%u\n", val);
36725
0
            if (val >= s->objects_count) {
36726
0
                return JS_ThrowSyntaxError(ctx, "invalid object reference (%u >= %u)",
36727
0
                                           val, s->objects_count);
36728
0
            }
36729
0
            obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, s->objects[val]));
36730
0
        }
36731
0
        break;
36732
0
    default:
36733
0
    invalid_tag:
36734
0
        return JS_ThrowSyntaxError(ctx, "invalid tag (tag=%d pos=%u)",
36735
0
                                   tag, (unsigned int)(s->ptr - s->buf_start));
36736
0
    }
36737
0
    bc_read_trace(s, "}\n");
36738
0
    return obj;
36739
0
}
36740
36741
static int JS_ReadObjectAtoms(BCReaderState *s)
36742
0
{
36743
0
    uint8_t v8;
36744
0
    JSString *p;
36745
0
    int i;
36746
0
    JSAtom atom;
36747
36748
0
    if (bc_get_u8(s, &v8))
36749
0
        return -1;
36750
0
    if (v8 != BC_VERSION) {
36751
0
        JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)",
36752
0
                            v8, BC_VERSION);
36753
0
        return -1;
36754
0
    }
36755
0
    if (bc_get_leb128(s, &s->idx_to_atom_count))
36756
0
        return -1;
36757
36758
0
    bc_read_trace(s, "%d atom indexes {\n", s->idx_to_atom_count);
36759
36760
0
    if (s->idx_to_atom_count != 0) {
36761
0
        s->idx_to_atom = js_mallocz(s->ctx, s->idx_to_atom_count *
36762
0
                                    sizeof(s->idx_to_atom[0]));
36763
0
        if (!s->idx_to_atom)
36764
0
            return s->error_state = -1;
36765
0
    }
36766
0
    for(i = 0; i < s->idx_to_atom_count; i++) {
36767
0
        p = JS_ReadString(s);
36768
0
        if (!p)
36769
0
            return -1;
36770
0
        atom = JS_NewAtomStr(s->ctx, p);
36771
0
        if (atom == JS_ATOM_NULL)
36772
0
            return s->error_state = -1;
36773
0
        s->idx_to_atom[i] = atom;
36774
0
        if (s->is_rom_data && (atom != (i + s->first_atom)))
36775
0
            s->is_rom_data = FALSE; /* atoms must be relocated */
36776
0
    }
36777
0
    bc_read_trace(s, "}\n");
36778
0
    return 0;
36779
0
}
36780
36781
static void bc_reader_free(BCReaderState *s)
36782
0
{
36783
0
    int i;
36784
0
    if (s->idx_to_atom) {
36785
0
        for(i = 0; i < s->idx_to_atom_count; i++) {
36786
0
            JS_FreeAtom(s->ctx, s->idx_to_atom[i]);
36787
0
        }
36788
0
        js_free(s->ctx, s->idx_to_atom);
36789
0
    }
36790
0
    js_free(s->ctx, s->objects);
36791
0
}
36792
36793
JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
36794
                       int flags)
36795
0
{
36796
0
    BCReaderState ss, *s = &ss;
36797
0
    JSValue obj;
36798
36799
0
    ctx->binary_object_count += 1;
36800
0
    ctx->binary_object_size += buf_len;
36801
36802
0
    memset(s, 0, sizeof(*s));
36803
0
    s->ctx = ctx;
36804
0
    s->buf_start = buf;
36805
0
    s->buf_end = buf + buf_len;
36806
0
    s->ptr = buf;
36807
0
    s->allow_bytecode = ((flags & JS_READ_OBJ_BYTECODE) != 0);
36808
0
    s->is_rom_data = ((flags & JS_READ_OBJ_ROM_DATA) != 0);
36809
0
    s->allow_sab = ((flags & JS_READ_OBJ_SAB) != 0);
36810
0
    s->allow_reference = ((flags & JS_READ_OBJ_REFERENCE) != 0);
36811
0
    if (s->allow_bytecode)
36812
0
        s->first_atom = JS_ATOM_END;
36813
0
    else
36814
0
        s->first_atom = 1;
36815
0
    if (JS_ReadObjectAtoms(s)) {
36816
0
        obj = JS_EXCEPTION;
36817
0
    } else {
36818
0
        obj = JS_ReadObjectRec(s);
36819
0
    }
36820
0
    bc_reader_free(s);
36821
0
    return obj;
36822
0
}
36823
36824
/*******************************************************************/
36825
/* runtime functions & objects */
36826
36827
static JSValue js_string_constructor(JSContext *ctx, JSValueConst this_val,
36828
                                     int argc, JSValueConst *argv);
36829
static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst this_val,
36830
                                      int argc, JSValueConst *argv);
36831
static JSValue js_number_constructor(JSContext *ctx, JSValueConst this_val,
36832
                                     int argc, JSValueConst *argv);
36833
36834
static int check_function(JSContext *ctx, JSValueConst obj)
36835
234
{
36836
234
    if (likely(JS_IsFunction(ctx, obj)))
36837
234
        return 0;
36838
0
    JS_ThrowTypeError(ctx, "not a function");
36839
0
    return -1;
36840
234
}
36841
36842
static int check_exception_free(JSContext *ctx, JSValue obj)
36843
0
{
36844
0
    JS_FreeValue(ctx, obj);
36845
0
    return JS_IsException(obj);
36846
0
}
36847
36848
static JSAtom find_atom(JSContext *ctx, const char *name)
36849
21.0k
{
36850
21.0k
    JSAtom atom;
36851
21.0k
    int len;
36852
36853
21.0k
    if (*name == '[') {
36854
1.75k
        name++;
36855
1.75k
        len = strlen(name) - 1;
36856
        /* We assume 8 bit non null strings, which is the case for these
36857
           symbols */
36858
12.7k
        for(atom = JS_ATOM_Symbol_toPrimitive; atom < JS_ATOM_END; atom++) {
36859
12.7k
            JSAtomStruct *p = ctx->rt->atom_array[atom];
36860
12.7k
            JSString *str = p;
36861
12.7k
            if (str->len == len && !memcmp(str->u.str8, name, len))
36862
1.75k
                return JS_DupAtom(ctx, atom);
36863
12.7k
        }
36864
0
        abort();
36865
19.2k
    } else {
36866
19.2k
        atom = JS_NewAtom(ctx, name);
36867
19.2k
    }
36868
19.2k
    return atom;
36869
21.0k
}
36870
36871
static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
36872
                                               JSAtom atom, void *opaque)
36873
390
{
36874
390
    const JSCFunctionListEntry *e = opaque;
36875
390
    JSValue val;
36876
36877
390
    switch(e->def_type) {
36878
390
    case JS_DEF_CFUNC:
36879
390
        val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
36880
390
                               e->name, e->u.func.length, e->u.func.cproto, e->magic);
36881
390
        break;
36882
0
    case JS_DEF_PROP_STRING:
36883
0
        val = JS_NewAtomString(ctx, e->u.str);
36884
0
        break;
36885
0
    case JS_DEF_OBJECT:
36886
0
        val = JS_NewObject(ctx);
36887
0
        JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
36888
0
        break;
36889
0
    default:
36890
0
        abort();
36891
390
    }
36892
390
    return val;
36893
390
}
36894
36895
static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
36896
                                          JSAtom atom,
36897
                                          const JSCFunctionListEntry *e)
36898
20.6k
{
36899
20.6k
    JSValue val;
36900
20.6k
    int prop_flags = e->prop_flags;
36901
36902
20.6k
    switch(e->def_type) {
36903
390
    case JS_DEF_ALIAS: /* using autoinit for aliases is not safe */
36904
390
        {
36905
390
            JSAtom atom1 = find_atom(ctx, e->u.alias.name);
36906
390
            switch (e->u.alias.base) {
36907
312
            case -1:
36908
312
                val = JS_GetProperty(ctx, obj, atom1);
36909
312
                break;
36910
78
            case 0:
36911
78
                val = JS_GetProperty(ctx, ctx->global_obj, atom1);
36912
78
                break;
36913
0
            case 1:
36914
0
                val = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], atom1);
36915
0
                break;
36916
0
            default:
36917
0
                abort();
36918
390
            }
36919
390
            JS_FreeAtom(ctx, atom1);
36920
390
            if (atom == JS_ATOM_Symbol_toPrimitive) {
36921
                /* Symbol.toPrimitive functions are not writable */
36922
0
                prop_flags = JS_PROP_CONFIGURABLE;
36923
390
            } else if (atom == JS_ATOM_Symbol_hasInstance) {
36924
                /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
36925
0
                prop_flags = 0;
36926
0
            }
36927
390
        }
36928
0
        break;
36929
15.9k
    case JS_DEF_CFUNC:
36930
15.9k
        if (atom == JS_ATOM_Symbol_toPrimitive) {
36931
            /* Symbol.toPrimitive functions are not writable */
36932
78
            prop_flags = JS_PROP_CONFIGURABLE;
36933
15.8k
        } else if (atom == JS_ATOM_Symbol_hasInstance) {
36934
            /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
36935
39
            prop_flags = 0;
36936
39
        }
36937
15.9k
        JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
36938
15.9k
                                  (void *)e, prop_flags);
36939
15.9k
        return 0;
36940
741
    case JS_DEF_CGETSET: /* XXX: use autoinit again ? */
36941
1.95k
    case JS_DEF_CGETSET_MAGIC:
36942
1.95k
        {
36943
1.95k
            JSValue getter, setter;
36944
1.95k
            char buf[64];
36945
36946
1.95k
            getter = JS_UNDEFINED;
36947
1.95k
            if (e->u.getset.get.generic) {
36948
1.95k
                snprintf(buf, sizeof(buf), "get %s", e->name);
36949
1.95k
                getter = JS_NewCFunction2(ctx, e->u.getset.get.generic,
36950
1.95k
                                          buf, 0, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_getter_magic : JS_CFUNC_getter,
36951
1.95k
                                          e->magic);
36952
1.95k
            }
36953
1.95k
            setter = JS_UNDEFINED;
36954
1.95k
            if (e->u.getset.set.generic) {
36955
429
                snprintf(buf, sizeof(buf), "set %s", e->name);
36956
429
                setter = JS_NewCFunction2(ctx, e->u.getset.set.generic,
36957
429
                                          buf, 1, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_setter_magic : JS_CFUNC_setter,
36958
429
                                          e->magic);
36959
429
            }
36960
1.95k
            JS_DefinePropertyGetSet(ctx, obj, atom, getter, setter, prop_flags);
36961
1.95k
            return 0;
36962
741
        }
36963
0
        break;
36964
858
    case JS_DEF_PROP_INT32:
36965
858
        val = JS_NewInt32(ctx, e->u.i32);
36966
858
        break;
36967
39
    case JS_DEF_PROP_INT64:
36968
39
        val = JS_NewInt64(ctx, e->u.i64);
36969
39
        break;
36970
390
    case JS_DEF_PROP_DOUBLE:
36971
390
        val = __JS_NewFloat64(ctx, e->u.f64);
36972
390
        break;
36973
39
    case JS_DEF_PROP_UNDEFINED:
36974
39
        val = JS_UNDEFINED;
36975
39
        break;
36976
897
    case JS_DEF_PROP_STRING:
36977
1.05k
    case JS_DEF_OBJECT:
36978
1.05k
        JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
36979
1.05k
                                  (void *)e, prop_flags);
36980
1.05k
        return 0;
36981
0
    default:
36982
0
        abort();
36983
20.6k
    }
36984
1.71k
    JS_DefinePropertyValue(ctx, obj, atom, val, prop_flags);
36985
1.71k
    return 0;
36986
20.6k
}
36987
36988
void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
36989
                                const JSCFunctionListEntry *tab, int len)
36990
2.49k
{
36991
2.49k
    int i;
36992
36993
23.1k
    for (i = 0; i < len; i++) {
36994
20.6k
        const JSCFunctionListEntry *e = &tab[i];
36995
20.6k
        JSAtom atom = find_atom(ctx, e->name);
36996
20.6k
        JS_InstantiateFunctionListItem(ctx, obj, atom, e);
36997
20.6k
        JS_FreeAtom(ctx, atom);
36998
20.6k
    }
36999
2.49k
}
37000
37001
int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,
37002
                           const JSCFunctionListEntry *tab, int len)
37003
78
{
37004
78
    int i;
37005
3.74k
    for(i = 0; i < len; i++) {
37006
3.66k
        if (JS_AddModuleExport(ctx, m, tab[i].name))
37007
0
            return -1;
37008
3.66k
    }
37009
78
    return 0;
37010
78
}
37011
37012
int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
37013
                           const JSCFunctionListEntry *tab, int len)
37014
78
{
37015
78
    int i;
37016
78
    JSValue val;
37017
37018
3.74k
    for(i = 0; i < len; i++) {
37019
3.66k
        const JSCFunctionListEntry *e = &tab[i];
37020
3.66k
        switch(e->def_type) {
37021
2.10k
        case JS_DEF_CFUNC:
37022
2.10k
            val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
37023
2.10k
                                   e->name, e->u.func.length, e->u.func.cproto, e->magic);
37024
2.10k
            break;
37025
39
        case JS_DEF_PROP_STRING:
37026
39
            val = JS_NewString(ctx, e->u.str);
37027
39
            break;
37028
1.48k
        case JS_DEF_PROP_INT32:
37029
1.48k
            val = JS_NewInt32(ctx, e->u.i32);
37030
1.48k
            break;
37031
0
        case JS_DEF_PROP_INT64:
37032
0
            val = JS_NewInt64(ctx, e->u.i64);
37033
0
            break;
37034
0
        case JS_DEF_PROP_DOUBLE:
37035
0
            val = __JS_NewFloat64(ctx, e->u.f64);
37036
0
            break;
37037
39
        case JS_DEF_OBJECT:
37038
39
            val = JS_NewObject(ctx);
37039
39
            JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
37040
39
            break;
37041
0
        default:
37042
0
            abort();
37043
3.66k
        }
37044
3.66k
        if (JS_SetModuleExport(ctx, m, e->name, val))
37045
0
            return -1;
37046
3.66k
    }
37047
78
    return 0;
37048
78
}
37049
37050
/* Note: 'func_obj' is not necessarily a constructor */
37051
static void JS_SetConstructor2(JSContext *ctx,
37052
                               JSValueConst func_obj,
37053
                               JSValueConst proto,
37054
                               int proto_flags, int ctor_flags)
37055
1.87k
{
37056
1.87k
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype,
37057
1.87k
                           JS_DupValue(ctx, proto), proto_flags);
37058
1.87k
    JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
37059
1.87k
                           JS_DupValue(ctx, func_obj),
37060
1.87k
                           ctor_flags);
37061
1.87k
    set_cycle_flag(ctx, func_obj);
37062
1.87k
    set_cycle_flag(ctx, proto);
37063
1.87k
}
37064
37065
void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
37066
                       JSValueConst proto)
37067
1.67k
{
37068
1.67k
    JS_SetConstructor2(ctx, func_obj, proto,
37069
1.67k
                       0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
37070
1.67k
}
37071
37072
static void JS_NewGlobalCConstructor2(JSContext *ctx,
37073
                                      JSValue func_obj,
37074
                                      const char *name,
37075
                                      JSValueConst proto)
37076
1.59k
{
37077
1.59k
    JS_DefinePropertyValueStr(ctx, ctx->global_obj, name,
37078
1.59k
                           JS_DupValue(ctx, func_obj),
37079
1.59k
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
37080
1.59k
    JS_SetConstructor(ctx, func_obj, proto);
37081
1.59k
    JS_FreeValue(ctx, func_obj);
37082
1.59k
}
37083
37084
static JSValueConst JS_NewGlobalCConstructor(JSContext *ctx, const char *name,
37085
                                             JSCFunction *func, int length,
37086
                                             JSValueConst proto)
37087
429
{
37088
429
    JSValue func_obj;
37089
429
    func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor_or_func, 0);
37090
429
    JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
37091
429
    return func_obj;
37092
429
}
37093
37094
static JSValueConst JS_NewGlobalCConstructorOnly(JSContext *ctx, const char *name,
37095
                                                 JSCFunction *func, int length,
37096
                                                 JSValueConst proto)
37097
156
{
37098
156
    JSValue func_obj;
37099
156
    func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor, 0);
37100
156
    JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
37101
156
    return func_obj;
37102
156
}
37103
37104
static JSValue js_global_eval(JSContext *ctx, JSValueConst this_val,
37105
                              int argc, JSValueConst *argv)
37106
0
{
37107
0
    return JS_EvalObject(ctx, ctx->global_obj, argv[0], JS_EVAL_TYPE_INDIRECT, -1);
37108
0
}
37109
37110
static JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val,
37111
                               int argc, JSValueConst *argv)
37112
0
{
37113
0
    double d;
37114
37115
    /* XXX: does this work for bigfloat? */
37116
0
    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
37117
0
        return JS_EXCEPTION;
37118
0
    return JS_NewBool(ctx, isnan(d));
37119
0
}
37120
37121
static JSValue js_global_isFinite(JSContext *ctx, JSValueConst this_val,
37122
                                  int argc, JSValueConst *argv)
37123
0
{
37124
0
    double d;
37125
0
    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
37126
0
        return JS_EXCEPTION;
37127
0
    return JS_NewBool(ctx, isfinite(d));
37128
0
}
37129
37130
/* Object class */
37131
37132
static JSValue JS_ToObject(JSContext *ctx, JSValueConst val)
37133
0
{
37134
0
    int tag = JS_VALUE_GET_NORM_TAG(val);
37135
0
    JSValue obj;
37136
37137
0
    switch(tag) {
37138
0
    default:
37139
0
    case JS_TAG_NULL:
37140
0
    case JS_TAG_UNDEFINED:
37141
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
37142
0
    case JS_TAG_OBJECT:
37143
0
    case JS_TAG_EXCEPTION:
37144
0
        return JS_DupValue(ctx, val);
37145
0
    case JS_TAG_BIG_INT:
37146
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
37147
0
        goto set_value;
37148
0
#ifdef CONFIG_BIGNUM
37149
0
    case JS_TAG_BIG_FLOAT:
37150
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT);
37151
0
        goto set_value;
37152
0
    case JS_TAG_BIG_DECIMAL:
37153
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_DECIMAL);
37154
0
        goto set_value;
37155
0
#endif
37156
0
    case JS_TAG_INT:
37157
0
    case JS_TAG_FLOAT64:
37158
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
37159
0
        goto set_value;
37160
0
    case JS_TAG_STRING:
37161
        /* XXX: should call the string constructor */
37162
0
        {
37163
0
            JSString *p1 = JS_VALUE_GET_STRING(val);
37164
0
            obj = JS_NewObjectClass(ctx, JS_CLASS_STRING);
37165
0
            JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
37166
0
        }
37167
0
        goto set_value;
37168
0
    case JS_TAG_BOOL:
37169
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_BOOLEAN);
37170
0
        goto set_value;
37171
0
    case JS_TAG_SYMBOL:
37172
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_SYMBOL);
37173
0
    set_value:
37174
0
        if (!JS_IsException(obj))
37175
0
            JS_SetObjectData(ctx, obj, JS_DupValue(ctx, val));
37176
0
        return obj;
37177
0
    }
37178
0
}
37179
37180
static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val)
37181
0
{
37182
0
    JSValue obj = JS_ToObject(ctx, val);
37183
0
    JS_FreeValue(ctx, val);
37184
0
    return obj;
37185
0
}
37186
37187
static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
37188
                          JSValueConst desc)
37189
0
{
37190
0
    JSValue val, getter, setter;
37191
0
    int flags;
37192
37193
0
    if (!JS_IsObject(desc)) {
37194
0
        JS_ThrowTypeErrorNotAnObject(ctx);
37195
0
        return -1;
37196
0
    }
37197
0
    flags = 0;
37198
0
    val = JS_UNDEFINED;
37199
0
    getter = JS_UNDEFINED;
37200
0
    setter = JS_UNDEFINED;
37201
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_configurable)) {
37202
0
        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable);
37203
0
        if (JS_IsException(prop))
37204
0
            goto fail;
37205
0
        flags |= JS_PROP_HAS_CONFIGURABLE;
37206
0
        if (JS_ToBoolFree(ctx, prop))
37207
0
            flags |= JS_PROP_CONFIGURABLE;
37208
0
    }
37209
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_writable)) {
37210
0
        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable);
37211
0
        if (JS_IsException(prop))
37212
0
            goto fail;
37213
0
        flags |= JS_PROP_HAS_WRITABLE;
37214
0
        if (JS_ToBoolFree(ctx, prop))
37215
0
            flags |= JS_PROP_WRITABLE;
37216
0
    }
37217
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_enumerable)) {
37218
0
        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable);
37219
0
        if (JS_IsException(prop))
37220
0
            goto fail;
37221
0
        flags |= JS_PROP_HAS_ENUMERABLE;
37222
0
        if (JS_ToBoolFree(ctx, prop))
37223
0
            flags |= JS_PROP_ENUMERABLE;
37224
0
    }
37225
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_value)) {
37226
0
        flags |= JS_PROP_HAS_VALUE;
37227
0
        val = JS_GetProperty(ctx, desc, JS_ATOM_value);
37228
0
        if (JS_IsException(val))
37229
0
            goto fail;
37230
0
    }
37231
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_get)) {
37232
0
        flags |= JS_PROP_HAS_GET;
37233
0
        getter = JS_GetProperty(ctx, desc, JS_ATOM_get);
37234
0
        if (JS_IsException(getter) ||
37235
0
            !(JS_IsUndefined(getter) || JS_IsFunction(ctx, getter))) {
37236
0
            JS_ThrowTypeError(ctx, "invalid getter");
37237
0
            goto fail;
37238
0
        }
37239
0
    }
37240
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_set)) {
37241
0
        flags |= JS_PROP_HAS_SET;
37242
0
        setter = JS_GetProperty(ctx, desc, JS_ATOM_set);
37243
0
        if (JS_IsException(setter) ||
37244
0
            !(JS_IsUndefined(setter) || JS_IsFunction(ctx, setter))) {
37245
0
            JS_ThrowTypeError(ctx, "invalid setter");
37246
0
            goto fail;
37247
0
        }
37248
0
    }
37249
0
    if ((flags & (JS_PROP_HAS_SET | JS_PROP_HAS_GET)) &&
37250
0
        (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE))) {
37251
0
        JS_ThrowTypeError(ctx, "cannot have setter/getter and value or writable");
37252
0
        goto fail;
37253
0
    }
37254
0
    d->flags = flags;
37255
0
    d->value = val;
37256
0
    d->getter = getter;
37257
0
    d->setter = setter;
37258
0
    return 0;
37259
0
 fail:
37260
0
    JS_FreeValue(ctx, val);
37261
0
    JS_FreeValue(ctx, getter);
37262
0
    JS_FreeValue(ctx, setter);
37263
0
    return -1;
37264
0
}
37265
37266
static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
37267
                                             JSAtom prop, JSValueConst desc,
37268
                                             int flags)
37269
0
{
37270
0
    JSPropertyDescriptor d;
37271
0
    int ret;
37272
37273
0
    if (js_obj_to_desc(ctx, &d, desc) < 0)
37274
0
        return -1;
37275
37276
0
    ret = JS_DefineProperty(ctx, obj, prop,
37277
0
                            d.value, d.getter, d.setter, d.flags | flags);
37278
0
    js_free_desc(ctx, &d);
37279
0
    return ret;
37280
0
}
37281
37282
static __exception int JS_ObjectDefineProperties(JSContext *ctx,
37283
                                                 JSValueConst obj,
37284
                                                 JSValueConst properties)
37285
0
{
37286
0
    JSValue props, desc;
37287
0
    JSObject *p;
37288
0
    JSPropertyEnum *atoms;
37289
0
    uint32_t len, i;
37290
0
    int ret = -1;
37291
37292
0
    if (!JS_IsObject(obj)) {
37293
0
        JS_ThrowTypeErrorNotAnObject(ctx);
37294
0
        return -1;
37295
0
    }
37296
0
    desc = JS_UNDEFINED;
37297
0
    props = JS_ToObject(ctx, properties);
37298
0
    if (JS_IsException(props))
37299
0
        return -1;
37300
0
    p = JS_VALUE_GET_OBJ(props);
37301
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) < 0)
37302
0
        goto exception;
37303
0
    for(i = 0; i < len; i++) {
37304
0
        JS_FreeValue(ctx, desc);
37305
0
        desc = JS_GetProperty(ctx, props, atoms[i].atom);
37306
0
        if (JS_IsException(desc))
37307
0
            goto exception;
37308
0
        if (JS_DefinePropertyDesc(ctx, obj, atoms[i].atom, desc, JS_PROP_THROW) < 0)
37309
0
            goto exception;
37310
0
    }
37311
0
    ret = 0;
37312
37313
0
exception:
37314
0
    js_free_prop_enum(ctx, atoms, len);
37315
0
    JS_FreeValue(ctx, props);
37316
0
    JS_FreeValue(ctx, desc);
37317
0
    return ret;
37318
0
}
37319
37320
static JSValue js_object_constructor(JSContext *ctx, JSValueConst new_target,
37321
                                     int argc, JSValueConst *argv)
37322
0
{
37323
0
    JSValue ret;
37324
0
    if (!JS_IsUndefined(new_target) &&
37325
0
        JS_VALUE_GET_OBJ(new_target) !=
37326
0
        JS_VALUE_GET_OBJ(JS_GetActiveFunction(ctx))) {
37327
0
        ret = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
37328
0
    } else {
37329
0
        int tag = JS_VALUE_GET_NORM_TAG(argv[0]);
37330
0
        switch(tag) {
37331
0
        case JS_TAG_NULL:
37332
0
        case JS_TAG_UNDEFINED:
37333
0
            ret = JS_NewObject(ctx);
37334
0
            break;
37335
0
        default:
37336
0
            ret = JS_ToObject(ctx, argv[0]);
37337
0
            break;
37338
0
        }
37339
0
    }
37340
0
    return ret;
37341
0
}
37342
37343
static JSValue js_object_create(JSContext *ctx, JSValueConst this_val,
37344
                                int argc, JSValueConst *argv)
37345
0
{
37346
0
    JSValueConst proto, props;
37347
0
    JSValue obj;
37348
37349
0
    proto = argv[0];
37350
0
    if (!JS_IsObject(proto) && !JS_IsNull(proto))
37351
0
        return JS_ThrowTypeError(ctx, "not a prototype");
37352
0
    obj = JS_NewObjectProto(ctx, proto);
37353
0
    if (JS_IsException(obj))
37354
0
        return JS_EXCEPTION;
37355
0
    props = argv[1];
37356
0
    if (!JS_IsUndefined(props)) {
37357
0
        if (JS_ObjectDefineProperties(ctx, obj, props)) {
37358
0
            JS_FreeValue(ctx, obj);
37359
0
            return JS_EXCEPTION;
37360
0
        }
37361
0
    }
37362
0
    return obj;
37363
0
}
37364
37365
static JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val,
37366
                                        int argc, JSValueConst *argv, int magic)
37367
0
{
37368
0
    JSValueConst val;
37369
37370
0
    val = argv[0];
37371
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) {
37372
        /* ES6 feature non compatible with ES5.1: primitive types are
37373
           accepted */
37374
0
        if (magic || JS_VALUE_GET_TAG(val) == JS_TAG_NULL ||
37375
0
            JS_VALUE_GET_TAG(val) == JS_TAG_UNDEFINED)
37376
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
37377
0
    }
37378
0
    return JS_GetPrototype(ctx, val);
37379
0
}
37380
37381
static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
37382
                                        int argc, JSValueConst *argv)
37383
0
{
37384
0
    JSValueConst obj;
37385
0
    obj = argv[0];
37386
0
    if (JS_SetPrototypeInternal(ctx, obj, argv[1], TRUE) < 0)
37387
0
        return JS_EXCEPTION;
37388
0
    return JS_DupValue(ctx, obj);
37389
0
}
37390
37391
/* magic = 1 if called as Reflect.defineProperty */
37392
static JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val,
37393
                                        int argc, JSValueConst *argv, int magic)
37394
0
{
37395
0
    JSValueConst obj, prop, desc;
37396
0
    int ret, flags;
37397
0
    JSAtom atom;
37398
37399
0
    obj = argv[0];
37400
0
    prop = argv[1];
37401
0
    desc = argv[2];
37402
37403
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
37404
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
37405
0
    atom = JS_ValueToAtom(ctx, prop);
37406
0
    if (unlikely(atom == JS_ATOM_NULL))
37407
0
        return JS_EXCEPTION;
37408
0
    flags = 0;
37409
0
    if (!magic)
37410
0
        flags |= JS_PROP_THROW;
37411
0
    ret = JS_DefinePropertyDesc(ctx, obj, atom, desc, flags);
37412
0
    JS_FreeAtom(ctx, atom);
37413
0
    if (ret < 0) {
37414
0
        return JS_EXCEPTION;
37415
0
    } else if (magic) {
37416
0
        return JS_NewBool(ctx, ret);
37417
0
    } else {
37418
0
        return JS_DupValue(ctx, obj);
37419
0
    }
37420
0
}
37421
37422
static JSValue js_object_defineProperties(JSContext *ctx, JSValueConst this_val,
37423
                                          int argc, JSValueConst *argv)
37424
0
{
37425
    // defineProperties(obj, properties)
37426
0
    JSValueConst obj = argv[0];
37427
37428
0
    if (JS_ObjectDefineProperties(ctx, obj, argv[1]))
37429
0
        return JS_EXCEPTION;
37430
0
    else
37431
0
        return JS_DupValue(ctx, obj);
37432
0
}
37433
37434
/* magic = 1 if called as __defineSetter__ */
37435
static JSValue js_object___defineGetter__(JSContext *ctx, JSValueConst this_val,
37436
                                          int argc, JSValueConst *argv, int magic)
37437
0
{
37438
0
    JSValue obj;
37439
0
    JSValueConst prop, value, get, set;
37440
0
    int ret, flags;
37441
0
    JSAtom atom;
37442
37443
0
    prop = argv[0];
37444
0
    value = argv[1];
37445
37446
0
    obj = JS_ToObject(ctx, this_val);
37447
0
    if (JS_IsException(obj))
37448
0
        return JS_EXCEPTION;
37449
37450
0
    if (check_function(ctx, value)) {
37451
0
        JS_FreeValue(ctx, obj);
37452
0
        return JS_EXCEPTION;
37453
0
    }
37454
0
    atom = JS_ValueToAtom(ctx, prop);
37455
0
    if (unlikely(atom == JS_ATOM_NULL)) {
37456
0
        JS_FreeValue(ctx, obj);
37457
0
        return JS_EXCEPTION;
37458
0
    }
37459
0
    flags = JS_PROP_THROW |
37460
0
        JS_PROP_HAS_ENUMERABLE | JS_PROP_ENUMERABLE |
37461
0
        JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE;
37462
0
    if (magic) {
37463
0
        get = JS_UNDEFINED;
37464
0
        set = value;
37465
0
        flags |= JS_PROP_HAS_SET;
37466
0
    } else {
37467
0
        get = value;
37468
0
        set = JS_UNDEFINED;
37469
0
        flags |= JS_PROP_HAS_GET;
37470
0
    }
37471
0
    ret = JS_DefineProperty(ctx, obj, atom, JS_UNDEFINED, get, set, flags);
37472
0
    JS_FreeValue(ctx, obj);
37473
0
    JS_FreeAtom(ctx, atom);
37474
0
    if (ret < 0) {
37475
0
        return JS_EXCEPTION;
37476
0
    } else {
37477
0
        return JS_UNDEFINED;
37478
0
    }
37479
0
}
37480
37481
static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst this_val,
37482
                                                  int argc, JSValueConst *argv, int magic)
37483
0
{
37484
0
    JSValueConst prop;
37485
0
    JSAtom atom;
37486
0
    JSValue ret, obj;
37487
0
    JSPropertyDescriptor desc;
37488
0
    int res, flags;
37489
37490
0
    if (magic) {
37491
        /* Reflect.getOwnPropertyDescriptor case */
37492
0
        if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
37493
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
37494
0
        obj = JS_DupValue(ctx, argv[0]);
37495
0
    } else {
37496
0
        obj = JS_ToObject(ctx, argv[0]);
37497
0
        if (JS_IsException(obj))
37498
0
            return obj;
37499
0
    }
37500
0
    prop = argv[1];
37501
0
    atom = JS_ValueToAtom(ctx, prop);
37502
0
    if (unlikely(atom == JS_ATOM_NULL))
37503
0
        goto exception;
37504
0
    ret = JS_UNDEFINED;
37505
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
37506
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), atom);
37507
0
        if (res < 0)
37508
0
            goto exception;
37509
0
        if (res) {
37510
0
            ret = JS_NewObject(ctx);
37511
0
            if (JS_IsException(ret))
37512
0
                goto exception1;
37513
0
            flags = JS_PROP_C_W_E | JS_PROP_THROW;
37514
0
            if (desc.flags & JS_PROP_GETSET) {
37515
0
                if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, desc.getter), flags) < 0
37516
0
                ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, desc.setter), flags) < 0)
37517
0
                    goto exception1;
37518
0
            } else {
37519
0
                if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, desc.value), flags) < 0
37520
0
                ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
37521
0
                                           JS_NewBool(ctx, desc.flags & JS_PROP_WRITABLE), flags) < 0)
37522
0
                    goto exception1;
37523
0
            }
37524
0
            if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
37525
0
                                       JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE), flags) < 0
37526
0
            ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
37527
0
                                       JS_NewBool(ctx, desc.flags & JS_PROP_CONFIGURABLE), flags) < 0)
37528
0
                goto exception1;
37529
0
            js_free_desc(ctx, &desc);
37530
0
        }
37531
0
    }
37532
0
    JS_FreeAtom(ctx, atom);
37533
0
    JS_FreeValue(ctx, obj);
37534
0
    return ret;
37535
37536
0
exception1:
37537
0
    js_free_desc(ctx, &desc);
37538
0
    JS_FreeValue(ctx, ret);
37539
0
exception:
37540
0
    JS_FreeAtom(ctx, atom);
37541
0
    JS_FreeValue(ctx, obj);
37542
0
    return JS_EXCEPTION;
37543
0
}
37544
37545
static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst this_val,
37546
                                                   int argc, JSValueConst *argv)
37547
0
{
37548
    //getOwnPropertyDescriptors(obj)
37549
0
    JSValue obj, r;
37550
0
    JSObject *p;
37551
0
    JSPropertyEnum *props;
37552
0
    uint32_t len, i;
37553
37554
0
    r = JS_UNDEFINED;
37555
0
    obj = JS_ToObject(ctx, argv[0]);
37556
0
    if (JS_IsException(obj))
37557
0
        return JS_EXCEPTION;
37558
37559
0
    p = JS_VALUE_GET_OBJ(obj);
37560
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p,
37561
0
                               JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
37562
0
        goto exception;
37563
0
    r = JS_NewObject(ctx);
37564
0
    if (JS_IsException(r))
37565
0
        goto exception;
37566
0
    for(i = 0; i < len; i++) {
37567
0
        JSValue atomValue, desc;
37568
0
        JSValueConst args[2];
37569
37570
0
        atomValue = JS_AtomToValue(ctx, props[i].atom);
37571
0
        if (JS_IsException(atomValue))
37572
0
            goto exception;
37573
0
        args[0] = obj;
37574
0
        args[1] = atomValue;
37575
0
        desc = js_object_getOwnPropertyDescriptor(ctx, JS_UNDEFINED, 2, args, 0);
37576
0
        JS_FreeValue(ctx, atomValue);
37577
0
        if (JS_IsException(desc))
37578
0
            goto exception;
37579
0
        if (!JS_IsUndefined(desc)) {
37580
0
            if (JS_DefinePropertyValue(ctx, r, props[i].atom, desc,
37581
0
                                       JS_PROP_C_W_E | JS_PROP_THROW) < 0)
37582
0
                goto exception;
37583
0
        }
37584
0
    }
37585
0
    js_free_prop_enum(ctx, props, len);
37586
0
    JS_FreeValue(ctx, obj);
37587
0
    return r;
37588
37589
0
exception:
37590
0
    js_free_prop_enum(ctx, props, len);
37591
0
    JS_FreeValue(ctx, obj);
37592
0
    JS_FreeValue(ctx, r);
37593
0
    return JS_EXCEPTION;
37594
0
}
37595
37596
static JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValueConst obj1,
37597
                                       int flags, int kind)
37598
0
{
37599
0
    JSValue obj, r, val, key, value;
37600
0
    JSObject *p;
37601
0
    JSPropertyEnum *atoms;
37602
0
    uint32_t len, i, j;
37603
37604
0
    r = JS_UNDEFINED;
37605
0
    val = JS_UNDEFINED;
37606
0
    obj = JS_ToObject(ctx, obj1);
37607
0
    if (JS_IsException(obj))
37608
0
        return JS_EXCEPTION;
37609
0
    p = JS_VALUE_GET_OBJ(obj);
37610
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, flags & ~JS_GPN_ENUM_ONLY))
37611
0
        goto exception;
37612
0
    r = JS_NewArray(ctx);
37613
0
    if (JS_IsException(r))
37614
0
        goto exception;
37615
0
    for(j = i = 0; i < len; i++) {
37616
0
        JSAtom atom = atoms[i].atom;
37617
0
        if (flags & JS_GPN_ENUM_ONLY) {
37618
0
            JSPropertyDescriptor desc;
37619
0
            int res;
37620
37621
            /* Check if property is still enumerable */
37622
0
            res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
37623
0
            if (res < 0)
37624
0
                goto exception;
37625
0
            if (!res)
37626
0
                continue;
37627
0
            js_free_desc(ctx, &desc);
37628
0
            if (!(desc.flags & JS_PROP_ENUMERABLE))
37629
0
                continue;
37630
0
        }
37631
0
        switch(kind) {
37632
0
        default:
37633
0
        case JS_ITERATOR_KIND_KEY:
37634
0
            val = JS_AtomToValue(ctx, atom);
37635
0
            if (JS_IsException(val))
37636
0
                goto exception;
37637
0
            break;
37638
0
        case JS_ITERATOR_KIND_VALUE:
37639
0
            val = JS_GetProperty(ctx, obj, atom);
37640
0
            if (JS_IsException(val))
37641
0
                goto exception;
37642
0
            break;
37643
0
        case JS_ITERATOR_KIND_KEY_AND_VALUE:
37644
0
            val = JS_NewArray(ctx);
37645
0
            if (JS_IsException(val))
37646
0
                goto exception;
37647
0
            key = JS_AtomToValue(ctx, atom);
37648
0
            if (JS_IsException(key))
37649
0
                goto exception1;
37650
0
            if (JS_CreateDataPropertyUint32(ctx, val, 0, key, JS_PROP_THROW) < 0)
37651
0
                goto exception1;
37652
0
            value = JS_GetProperty(ctx, obj, atom);
37653
0
            if (JS_IsException(value))
37654
0
                goto exception1;
37655
0
            if (JS_CreateDataPropertyUint32(ctx, val, 1, value, JS_PROP_THROW) < 0)
37656
0
                goto exception1;
37657
0
            break;
37658
0
        }
37659
0
        if (JS_CreateDataPropertyUint32(ctx, r, j++, val, 0) < 0)
37660
0
            goto exception;
37661
0
    }
37662
0
    goto done;
37663
37664
0
exception1:
37665
0
    JS_FreeValue(ctx, val);
37666
0
exception:
37667
0
    JS_FreeValue(ctx, r);
37668
0
    r = JS_EXCEPTION;
37669
0
done:
37670
0
    js_free_prop_enum(ctx, atoms, len);
37671
0
    JS_FreeValue(ctx, obj);
37672
0
    return r;
37673
0
}
37674
37675
static JSValue js_object_getOwnPropertyNames(JSContext *ctx, JSValueConst this_val,
37676
                                             int argc, JSValueConst *argv)
37677
0
{
37678
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
37679
0
                                   JS_GPN_STRING_MASK, JS_ITERATOR_KIND_KEY);
37680
0
}
37681
37682
static JSValue js_object_getOwnPropertySymbols(JSContext *ctx, JSValueConst this_val,
37683
                                             int argc, JSValueConst *argv)
37684
0
{
37685
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
37686
0
                                   JS_GPN_SYMBOL_MASK, JS_ITERATOR_KIND_KEY);
37687
0
}
37688
37689
static JSValue js_object_keys(JSContext *ctx, JSValueConst this_val,
37690
                              int argc, JSValueConst *argv, int kind)
37691
0
{
37692
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
37693
0
                                   JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK, kind);
37694
0
}
37695
37696
static JSValue js_object_isExtensible(JSContext *ctx, JSValueConst this_val,
37697
                                      int argc, JSValueConst *argv, int reflect)
37698
0
{
37699
0
    JSValueConst obj;
37700
0
    int ret;
37701
37702
0
    obj = argv[0];
37703
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
37704
0
        if (reflect)
37705
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
37706
0
        else
37707
0
            return JS_FALSE;
37708
0
    }
37709
0
    ret = JS_IsExtensible(ctx, obj);
37710
0
    if (ret < 0)
37711
0
        return JS_EXCEPTION;
37712
0
    else
37713
0
        return JS_NewBool(ctx, ret);
37714
0
}
37715
37716
static JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val,
37717
                                           int argc, JSValueConst *argv, int reflect)
37718
0
{
37719
0
    JSValueConst obj;
37720
0
    int ret;
37721
37722
0
    obj = argv[0];
37723
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
37724
0
        if (reflect)
37725
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
37726
0
        else
37727
0
            return JS_DupValue(ctx, obj);
37728
0
    }
37729
0
    ret = JS_PreventExtensions(ctx, obj);
37730
0
    if (ret < 0)
37731
0
        return JS_EXCEPTION;
37732
0
    if (reflect) {
37733
0
        return JS_NewBool(ctx, ret);
37734
0
    } else {
37735
0
        if (!ret)
37736
0
            return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
37737
0
        return JS_DupValue(ctx, obj);
37738
0
    }
37739
0
}
37740
37741
static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,
37742
                                        int argc, JSValueConst *argv)
37743
0
{
37744
0
    JSValue obj;
37745
0
    JSAtom atom;
37746
0
    JSObject *p;
37747
0
    BOOL ret;
37748
37749
0
    atom = JS_ValueToAtom(ctx, argv[0]); /* must be done first */
37750
0
    if (unlikely(atom == JS_ATOM_NULL))
37751
0
        return JS_EXCEPTION;
37752
0
    obj = JS_ToObject(ctx, this_val);
37753
0
    if (JS_IsException(obj)) {
37754
0
        JS_FreeAtom(ctx, atom);
37755
0
        return obj;
37756
0
    }
37757
0
    p = JS_VALUE_GET_OBJ(obj);
37758
0
    ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
37759
0
    JS_FreeAtom(ctx, atom);
37760
0
    JS_FreeValue(ctx, obj);
37761
0
    if (ret < 0)
37762
0
        return JS_EXCEPTION;
37763
0
    else
37764
0
        return JS_NewBool(ctx, ret);
37765
0
}
37766
37767
static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val,
37768
                                int argc, JSValueConst *argv)
37769
0
{
37770
0
    JSValue obj;
37771
0
    JSAtom atom;
37772
0
    JSObject *p;
37773
0
    BOOL ret;
37774
37775
0
    obj = JS_ToObject(ctx, argv[0]);
37776
0
    if (JS_IsException(obj))
37777
0
        return obj;
37778
0
    atom = JS_ValueToAtom(ctx, argv[1]);
37779
0
    if (unlikely(atom == JS_ATOM_NULL)) {
37780
0
        JS_FreeValue(ctx, obj);
37781
0
        return JS_EXCEPTION;
37782
0
    }
37783
0
    p = JS_VALUE_GET_OBJ(obj);
37784
0
    ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
37785
0
    JS_FreeAtom(ctx, atom);
37786
0
    JS_FreeValue(ctx, obj);
37787
0
    if (ret < 0)
37788
0
        return JS_EXCEPTION;
37789
0
    else
37790
0
        return JS_NewBool(ctx, ret);
37791
0
}
37792
37793
static JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val,
37794
                                 int argc, JSValueConst *argv)
37795
0
{
37796
0
    return JS_ToObject(ctx, this_val);
37797
0
}
37798
37799
static JSValue js_object_toString(JSContext *ctx, JSValueConst this_val,
37800
                                  int argc, JSValueConst *argv)
37801
0
{
37802
0
    JSValue obj, tag;
37803
0
    int is_array;
37804
0
    JSAtom atom;
37805
0
    JSObject *p;
37806
37807
0
    if (JS_IsNull(this_val)) {
37808
0
        tag = JS_NewString(ctx, "Null");
37809
0
    } else if (JS_IsUndefined(this_val)) {
37810
0
        tag = JS_NewString(ctx, "Undefined");
37811
0
    } else {
37812
0
        obj = JS_ToObject(ctx, this_val);
37813
0
        if (JS_IsException(obj))
37814
0
            return obj;
37815
0
        is_array = JS_IsArray(ctx, obj);
37816
0
        if (is_array < 0) {
37817
0
            JS_FreeValue(ctx, obj);
37818
0
            return JS_EXCEPTION;
37819
0
        }
37820
0
        if (is_array) {
37821
0
            atom = JS_ATOM_Array;
37822
0
        } else if (JS_IsFunction(ctx, obj)) {
37823
0
            atom = JS_ATOM_Function;
37824
0
        } else {
37825
0
            p = JS_VALUE_GET_OBJ(obj);
37826
0
            switch(p->class_id) {
37827
0
            case JS_CLASS_STRING:
37828
0
            case JS_CLASS_ARGUMENTS:
37829
0
            case JS_CLASS_MAPPED_ARGUMENTS:
37830
0
            case JS_CLASS_ERROR:
37831
0
            case JS_CLASS_BOOLEAN:
37832
0
            case JS_CLASS_NUMBER:
37833
0
            case JS_CLASS_DATE:
37834
0
            case JS_CLASS_REGEXP:
37835
0
                atom = ctx->rt->class_array[p->class_id].class_name;
37836
0
                break;
37837
0
            default:
37838
0
                atom = JS_ATOM_Object;
37839
0
                break;
37840
0
            }
37841
0
        }
37842
0
        tag = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_toStringTag);
37843
0
        JS_FreeValue(ctx, obj);
37844
0
        if (JS_IsException(tag))
37845
0
            return JS_EXCEPTION;
37846
0
        if (!JS_IsString(tag)) {
37847
0
            JS_FreeValue(ctx, tag);
37848
0
            tag = JS_AtomToString(ctx, atom);
37849
0
        }
37850
0
    }
37851
0
    return JS_ConcatString3(ctx, "[object ", tag, "]");
37852
0
}
37853
37854
static JSValue js_object_toLocaleString(JSContext *ctx, JSValueConst this_val,
37855
                                        int argc, JSValueConst *argv)
37856
0
{
37857
0
    return JS_Invoke(ctx, this_val, JS_ATOM_toString, 0, NULL);
37858
0
}
37859
37860
static JSValue js_object_assign(JSContext *ctx, JSValueConst this_val,
37861
                                int argc, JSValueConst *argv)
37862
0
{
37863
    // Object.assign(obj, source1)
37864
0
    JSValue obj, s;
37865
0
    int i;
37866
37867
0
    s = JS_UNDEFINED;
37868
0
    obj = JS_ToObject(ctx, argv[0]);
37869
0
    if (JS_IsException(obj))
37870
0
        goto exception;
37871
0
    for (i = 1; i < argc; i++) {
37872
0
        if (!JS_IsNull(argv[i]) && !JS_IsUndefined(argv[i])) {
37873
0
            s = JS_ToObject(ctx, argv[i]);
37874
0
            if (JS_IsException(s))
37875
0
                goto exception;
37876
0
            if (JS_CopyDataProperties(ctx, obj, s, JS_UNDEFINED, TRUE))
37877
0
                goto exception;
37878
0
            JS_FreeValue(ctx, s);
37879
0
        }
37880
0
    }
37881
0
    return obj;
37882
0
exception:
37883
0
    JS_FreeValue(ctx, obj);
37884
0
    JS_FreeValue(ctx, s);
37885
0
    return JS_EXCEPTION;
37886
0
}
37887
37888
static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val,
37889
                              int argc, JSValueConst *argv, int freeze_flag)
37890
39
{
37891
39
    JSValueConst obj = argv[0];
37892
39
    JSObject *p;
37893
39
    JSPropertyEnum *props;
37894
39
    uint32_t len, i;
37895
39
    int flags, desc_flags, res;
37896
37897
39
    if (!JS_IsObject(obj))
37898
0
        return JS_DupValue(ctx, obj);
37899
37900
39
    res = JS_PreventExtensions(ctx, obj);
37901
39
    if (res < 0)
37902
0
        return JS_EXCEPTION;
37903
39
    if (!res) {
37904
0
        return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
37905
0
    }
37906
37907
39
    p = JS_VALUE_GET_OBJ(obj);
37908
39
    flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
37909
39
    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
37910
0
        return JS_EXCEPTION;
37911
37912
117
    for(i = 0; i < len; i++) {
37913
78
        JSPropertyDescriptor desc;
37914
78
        JSAtom prop = props[i].atom;
37915
37916
78
        desc_flags = JS_PROP_THROW | JS_PROP_HAS_CONFIGURABLE;
37917
78
        if (freeze_flag) {
37918
78
            res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
37919
78
            if (res < 0)
37920
0
                goto exception;
37921
78
            if (res) {
37922
78
                if (desc.flags & JS_PROP_WRITABLE)
37923
0
                    desc_flags |= JS_PROP_HAS_WRITABLE;
37924
78
                js_free_desc(ctx, &desc);
37925
78
            }
37926
78
        }
37927
78
        if (JS_DefineProperty(ctx, obj, prop, JS_UNDEFINED,
37928
78
                              JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0)
37929
0
            goto exception;
37930
78
    }
37931
39
    js_free_prop_enum(ctx, props, len);
37932
39
    return JS_DupValue(ctx, obj);
37933
37934
0
 exception:
37935
0
    js_free_prop_enum(ctx, props, len);
37936
0
    return JS_EXCEPTION;
37937
39
}
37938
37939
static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val,
37940
                                  int argc, JSValueConst *argv, int is_frozen)
37941
0
{
37942
0
    JSValueConst obj = argv[0];
37943
0
    JSObject *p;
37944
0
    JSPropertyEnum *props;
37945
0
    uint32_t len, i;
37946
0
    int flags, res;
37947
37948
0
    if (!JS_IsObject(obj))
37949
0
        return JS_TRUE;
37950
37951
0
    p = JS_VALUE_GET_OBJ(obj);
37952
0
    flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
37953
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
37954
0
        return JS_EXCEPTION;
37955
37956
0
    for(i = 0; i < len; i++) {
37957
0
        JSPropertyDescriptor desc;
37958
0
        JSAtom prop = props[i].atom;
37959
37960
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
37961
0
        if (res < 0)
37962
0
            goto exception;
37963
0
        if (res) {
37964
0
            js_free_desc(ctx, &desc);
37965
0
            if ((desc.flags & JS_PROP_CONFIGURABLE)
37966
0
            ||  (is_frozen && (desc.flags & JS_PROP_WRITABLE))) {
37967
0
                res = FALSE;
37968
0
                goto done;
37969
0
            }
37970
0
        }
37971
0
    }
37972
0
    res = JS_IsExtensible(ctx, obj);
37973
0
    if (res < 0)
37974
0
        return JS_EXCEPTION;
37975
0
    res ^= 1;
37976
0
done:
37977
0
    js_free_prop_enum(ctx, props, len);
37978
0
    return JS_NewBool(ctx, res);
37979
37980
0
exception:
37981
0
    js_free_prop_enum(ctx, props, len);
37982
0
    return JS_EXCEPTION;
37983
0
}
37984
37985
static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val,
37986
                                     int argc, JSValueConst *argv)
37987
0
{
37988
0
    JSValue obj, iter, next_method = JS_UNDEFINED;
37989
0
    JSValueConst iterable;
37990
0
    BOOL done;
37991
37992
    /*  RequireObjectCoercible() not necessary because it is tested in
37993
        JS_GetIterator() by JS_GetProperty() */
37994
0
    iterable = argv[0];
37995
37996
0
    obj = JS_NewObject(ctx);
37997
0
    if (JS_IsException(obj))
37998
0
        return obj;
37999
38000
0
    iter = JS_GetIterator(ctx, iterable, FALSE);
38001
0
    if (JS_IsException(iter))
38002
0
        goto fail;
38003
0
    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
38004
0
    if (JS_IsException(next_method))
38005
0
        goto fail;
38006
38007
0
    for(;;) {
38008
0
        JSValue key, value, item;
38009
0
        item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
38010
0
        if (JS_IsException(item))
38011
0
            goto fail;
38012
0
        if (done) {
38013
0
            JS_FreeValue(ctx, item);
38014
0
            break;
38015
0
        }
38016
38017
0
        key = JS_UNDEFINED;
38018
0
        value = JS_UNDEFINED;
38019
0
        if (!JS_IsObject(item)) {
38020
0
            JS_ThrowTypeErrorNotAnObject(ctx);
38021
0
            goto fail1;
38022
0
        }
38023
0
        key = JS_GetPropertyUint32(ctx, item, 0);
38024
0
        if (JS_IsException(key))
38025
0
            goto fail1;
38026
0
        value = JS_GetPropertyUint32(ctx, item, 1);
38027
0
        if (JS_IsException(value)) {
38028
0
            JS_FreeValue(ctx, key);
38029
0
            goto fail1;
38030
0
        }
38031
0
        if (JS_DefinePropertyValueValue(ctx, obj, key, value,
38032
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0) {
38033
0
        fail1:
38034
0
            JS_FreeValue(ctx, item);
38035
0
            goto fail;
38036
0
        }
38037
0
        JS_FreeValue(ctx, item);
38038
0
    }
38039
0
    JS_FreeValue(ctx, next_method);
38040
0
    JS_FreeValue(ctx, iter);
38041
0
    return obj;
38042
0
 fail:
38043
0
    if (JS_IsObject(iter)) {
38044
        /* close the iterator object, preserving pending exception */
38045
0
        JS_IteratorClose(ctx, iter, TRUE);
38046
0
    }
38047
0
    JS_FreeValue(ctx, next_method);
38048
0
    JS_FreeValue(ctx, iter);
38049
0
    JS_FreeValue(ctx, obj);
38050
0
    return JS_EXCEPTION;
38051
0
}
38052
38053
#if 0
38054
/* Note: corresponds to ECMA spec: CreateDataPropertyOrThrow() */
38055
static JSValue js_object___setOwnProperty(JSContext *ctx, JSValueConst this_val,
38056
                                          int argc, JSValueConst *argv)
38057
{
38058
    int ret;
38059
    ret = JS_DefinePropertyValueValue(ctx, argv[0], JS_DupValue(ctx, argv[1]),
38060
                                      JS_DupValue(ctx, argv[2]),
38061
                                      JS_PROP_C_W_E | JS_PROP_THROW);
38062
    if (ret < 0)
38063
        return JS_EXCEPTION;
38064
    else
38065
        return JS_NewBool(ctx, ret);
38066
}
38067
38068
static JSValue js_object___toObject(JSContext *ctx, JSValueConst this_val,
38069
                                    int argc, JSValueConst *argv)
38070
{
38071
    return JS_ToObject(ctx, argv[0]);
38072
}
38073
38074
static JSValue js_object___toPrimitive(JSContext *ctx, JSValueConst this_val,
38075
                                       int argc, JSValueConst *argv)
38076
{
38077
    int hint = HINT_NONE;
38078
38079
    if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_INT)
38080
        hint = JS_VALUE_GET_INT(argv[1]);
38081
38082
    return JS_ToPrimitive(ctx, argv[0], hint);
38083
}
38084
#endif
38085
38086
/* return an empty string if not an object */
38087
static JSValue js_object___getClass(JSContext *ctx, JSValueConst this_val,
38088
                                    int argc, JSValueConst *argv)
38089
0
{
38090
0
    JSAtom atom;
38091
0
    JSObject *p;
38092
0
    uint32_t tag;
38093
0
    int class_id;
38094
38095
0
    tag = JS_VALUE_GET_NORM_TAG(argv[0]);
38096
0
    if (tag == JS_TAG_OBJECT) {
38097
0
        p = JS_VALUE_GET_OBJ(argv[0]);
38098
0
        class_id = p->class_id;
38099
0
        if (class_id == JS_CLASS_PROXY && JS_IsFunction(ctx, argv[0]))
38100
0
            class_id = JS_CLASS_BYTECODE_FUNCTION;
38101
0
        atom = ctx->rt->class_array[class_id].class_name;
38102
0
    } else {
38103
0
        atom = JS_ATOM_empty_string;
38104
0
    }
38105
0
    return JS_AtomToString(ctx, atom);
38106
0
}
38107
38108
static JSValue js_object_is(JSContext *ctx, JSValueConst this_val,
38109
                            int argc, JSValueConst *argv)
38110
0
{
38111
0
    return JS_NewBool(ctx, js_same_value(ctx, argv[0], argv[1]));
38112
0
}
38113
38114
#if 0
38115
static JSValue js_object___getObjectData(JSContext *ctx, JSValueConst this_val,
38116
                                         int argc, JSValueConst *argv)
38117
{
38118
    return JS_GetObjectData(ctx, argv[0]);
38119
}
38120
38121
static JSValue js_object___setObjectData(JSContext *ctx, JSValueConst this_val,
38122
                                         int argc, JSValueConst *argv)
38123
{
38124
    if (JS_SetObjectData(ctx, argv[0], JS_DupValue(ctx, argv[1])))
38125
        return JS_EXCEPTION;
38126
    return JS_DupValue(ctx, argv[1]);
38127
}
38128
38129
static JSValue js_object___toPropertyKey(JSContext *ctx, JSValueConst this_val,
38130
                                         int argc, JSValueConst *argv)
38131
{
38132
    return JS_ToPropertyKey(ctx, argv[0]);
38133
}
38134
38135
static JSValue js_object___isObject(JSContext *ctx, JSValueConst this_val,
38136
                                    int argc, JSValueConst *argv)
38137
{
38138
    return JS_NewBool(ctx, JS_IsObject(argv[0]));
38139
}
38140
38141
static JSValue js_object___isSameValueZero(JSContext *ctx, JSValueConst this_val,
38142
                                           int argc, JSValueConst *argv)
38143
{
38144
    return JS_NewBool(ctx, js_same_value_zero(ctx, argv[0], argv[1]));
38145
}
38146
38147
static JSValue js_object___isConstructor(JSContext *ctx, JSValueConst this_val,
38148
                                         int argc, JSValueConst *argv)
38149
{
38150
    return JS_NewBool(ctx, JS_IsConstructor(ctx, argv[0]));
38151
}
38152
#endif
38153
38154
static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj,
38155
                                     JSValueConst defaultConstructor)
38156
0
{
38157
0
    JSValue ctor, species;
38158
38159
0
    if (!JS_IsObject(obj))
38160
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
38161
0
    ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
38162
0
    if (JS_IsException(ctor))
38163
0
        return ctor;
38164
0
    if (JS_IsUndefined(ctor))
38165
0
        return JS_DupValue(ctx, defaultConstructor);
38166
0
    if (!JS_IsObject(ctor)) {
38167
0
        JS_FreeValue(ctx, ctor);
38168
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
38169
0
    }
38170
0
    species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
38171
0
    JS_FreeValue(ctx, ctor);
38172
0
    if (JS_IsException(species))
38173
0
        return species;
38174
0
    if (JS_IsUndefined(species) || JS_IsNull(species))
38175
0
        return JS_DupValue(ctx, defaultConstructor);
38176
0
    if (!JS_IsConstructor(ctx, species)) {
38177
0
        JS_FreeValue(ctx, species);
38178
0
        return JS_ThrowTypeError(ctx, "not a constructor");
38179
0
    }
38180
0
    return species;
38181
0
}
38182
38183
#if 0
38184
static JSValue js_object___speciesConstructor(JSContext *ctx, JSValueConst this_val,
38185
                                              int argc, JSValueConst *argv)
38186
{
38187
    return JS_SpeciesConstructor(ctx, argv[0], argv[1]);
38188
}
38189
#endif
38190
38191
static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val)
38192
0
{
38193
0
    JSValue val, ret;
38194
38195
0
    val = JS_ToObject(ctx, this_val);
38196
0
    if (JS_IsException(val))
38197
0
        return val;
38198
0
    ret = JS_GetPrototype(ctx, val);
38199
0
    JS_FreeValue(ctx, val);
38200
0
    return ret;
38201
0
}
38202
38203
static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val,
38204
                                       JSValueConst proto)
38205
0
{
38206
0
    if (JS_IsUndefined(this_val) || JS_IsNull(this_val))
38207
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
38208
0
    if (!JS_IsObject(proto) && !JS_IsNull(proto))
38209
0
        return JS_UNDEFINED;
38210
0
    if (JS_SetPrototypeInternal(ctx, this_val, proto, TRUE) < 0)
38211
0
        return JS_EXCEPTION;
38212
0
    else
38213
0
        return JS_UNDEFINED;
38214
0
}
38215
38216
static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val,
38217
                                       int argc, JSValueConst *argv)
38218
0
{
38219
0
    JSValue obj, v1;
38220
0
    JSValueConst v;
38221
0
    int res;
38222
38223
0
    v = argv[0];
38224
0
    if (!JS_IsObject(v))
38225
0
        return JS_FALSE;
38226
0
    obj = JS_ToObject(ctx, this_val);
38227
0
    if (JS_IsException(obj))
38228
0
        return JS_EXCEPTION;
38229
0
    v1 = JS_DupValue(ctx, v);
38230
0
    for(;;) {
38231
0
        v1 = JS_GetPrototypeFree(ctx, v1);
38232
0
        if (JS_IsException(v1))
38233
0
            goto exception;
38234
0
        if (JS_IsNull(v1)) {
38235
0
            res = FALSE;
38236
0
            break;
38237
0
        }
38238
0
        if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) {
38239
0
            res = TRUE;
38240
0
            break;
38241
0
        }
38242
        /* avoid infinite loop (possible with proxies) */
38243
0
        if (js_poll_interrupts(ctx))
38244
0
            goto exception;
38245
0
    }
38246
0
    JS_FreeValue(ctx, v1);
38247
0
    JS_FreeValue(ctx, obj);
38248
0
    return JS_NewBool(ctx, res);
38249
38250
0
exception:
38251
0
    JS_FreeValue(ctx, v1);
38252
0
    JS_FreeValue(ctx, obj);
38253
0
    return JS_EXCEPTION;
38254
0
}
38255
38256
static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_val,
38257
                                              int argc, JSValueConst *argv)
38258
0
{
38259
0
    JSValue obj, res = JS_EXCEPTION;
38260
0
    JSAtom prop = JS_ATOM_NULL;
38261
0
    JSPropertyDescriptor desc;
38262
0
    int has_prop;
38263
38264
0
    obj = JS_ToObject(ctx, this_val);
38265
0
    if (JS_IsException(obj))
38266
0
        goto exception;
38267
0
    prop = JS_ValueToAtom(ctx, argv[0]);
38268
0
    if (unlikely(prop == JS_ATOM_NULL))
38269
0
        goto exception;
38270
38271
0
    has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
38272
0
    if (has_prop < 0)
38273
0
        goto exception;
38274
0
    if (has_prop) {
38275
0
        res = JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE);
38276
0
        js_free_desc(ctx, &desc);
38277
0
    } else {
38278
0
        res = JS_FALSE;
38279
0
    }
38280
38281
0
exception:
38282
0
    JS_FreeAtom(ctx, prop);
38283
0
    JS_FreeValue(ctx, obj);
38284
0
    return res;
38285
0
}
38286
38287
static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val,
38288
                                          int argc, JSValueConst *argv, int setter)
38289
0
{
38290
0
    JSValue obj, res = JS_EXCEPTION;
38291
0
    JSAtom prop = JS_ATOM_NULL;
38292
0
    JSPropertyDescriptor desc;
38293
0
    int has_prop;
38294
38295
0
    obj = JS_ToObject(ctx, this_val);
38296
0
    if (JS_IsException(obj))
38297
0
        goto exception;
38298
0
    prop = JS_ValueToAtom(ctx, argv[0]);
38299
0
    if (unlikely(prop == JS_ATOM_NULL))
38300
0
        goto exception;
38301
38302
0
    for (;;) {
38303
0
        has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
38304
0
        if (has_prop < 0)
38305
0
            goto exception;
38306
0
        if (has_prop) {
38307
0
            if (desc.flags & JS_PROP_GETSET)
38308
0
                res = JS_DupValue(ctx, setter ? desc.setter : desc.getter);
38309
0
            else
38310
0
                res = JS_UNDEFINED;
38311
0
            js_free_desc(ctx, &desc);
38312
0
            break;
38313
0
        }
38314
0
        obj = JS_GetPrototypeFree(ctx, obj);
38315
0
        if (JS_IsException(obj))
38316
0
            goto exception;
38317
0
        if (JS_IsNull(obj)) {
38318
0
            res = JS_UNDEFINED;
38319
0
            break;
38320
0
        }
38321
        /* avoid infinite loop (possible with proxies) */
38322
0
        if (js_poll_interrupts(ctx))
38323
0
            goto exception;
38324
0
    }
38325
38326
0
exception:
38327
0
    JS_FreeAtom(ctx, prop);
38328
0
    JS_FreeValue(ctx, obj);
38329
0
    return res;
38330
0
}
38331
38332
static const JSCFunctionListEntry js_object_funcs[] = {
38333
    JS_CFUNC_DEF("create", 2, js_object_create ),
38334
    JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 0 ),
38335
    JS_CFUNC_DEF("setPrototypeOf", 2, js_object_setPrototypeOf ),
38336
    JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 0 ),
38337
    JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties ),
38338
    JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames ),
38339
    JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols ),
38340
    JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 0 ),
38341
    JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY ),
38342
    JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ),
38343
    JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ),
38344
    JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 0 ),
38345
    JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 0 ),
38346
    JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 0 ),
38347
    JS_CFUNC_DEF("getOwnPropertyDescriptors", 1, js_object_getOwnPropertyDescriptors ),
38348
    JS_CFUNC_DEF("is", 2, js_object_is ),
38349
    JS_CFUNC_DEF("assign", 2, js_object_assign ),
38350
    JS_CFUNC_MAGIC_DEF("seal", 1, js_object_seal, 0 ),
38351
    JS_CFUNC_MAGIC_DEF("freeze", 1, js_object_seal, 1 ),
38352
    JS_CFUNC_MAGIC_DEF("isSealed", 1, js_object_isSealed, 0 ),
38353
    JS_CFUNC_MAGIC_DEF("isFrozen", 1, js_object_isSealed, 1 ),
38354
    JS_CFUNC_DEF("__getClass", 1, js_object___getClass ),
38355
    //JS_CFUNC_DEF("__isObject", 1, js_object___isObject ),
38356
    //JS_CFUNC_DEF("__isConstructor", 1, js_object___isConstructor ),
38357
    //JS_CFUNC_DEF("__toObject", 1, js_object___toObject ),
38358
    //JS_CFUNC_DEF("__setOwnProperty", 3, js_object___setOwnProperty ),
38359
    //JS_CFUNC_DEF("__toPrimitive", 2, js_object___toPrimitive ),
38360
    //JS_CFUNC_DEF("__toPropertyKey", 1, js_object___toPropertyKey ),
38361
    //JS_CFUNC_DEF("__speciesConstructor", 2, js_object___speciesConstructor ),
38362
    //JS_CFUNC_DEF("__isSameValueZero", 2, js_object___isSameValueZero ),
38363
    //JS_CFUNC_DEF("__getObjectData", 1, js_object___getObjectData ),
38364
    //JS_CFUNC_DEF("__setObjectData", 2, js_object___setObjectData ),
38365
    JS_CFUNC_DEF("fromEntries", 1, js_object_fromEntries ),
38366
    JS_CFUNC_DEF("hasOwn", 2, js_object_hasOwn ),
38367
};
38368
38369
static const JSCFunctionListEntry js_object_proto_funcs[] = {
38370
    JS_CFUNC_DEF("toString", 0, js_object_toString ),
38371
    JS_CFUNC_DEF("toLocaleString", 0, js_object_toLocaleString ),
38372
    JS_CFUNC_DEF("valueOf", 0, js_object_valueOf ),
38373
    JS_CFUNC_DEF("hasOwnProperty", 1, js_object_hasOwnProperty ),
38374
    JS_CFUNC_DEF("isPrototypeOf", 1, js_object_isPrototypeOf ),
38375
    JS_CFUNC_DEF("propertyIsEnumerable", 1, js_object_propertyIsEnumerable ),
38376
    JS_CGETSET_DEF("__proto__", js_object_get___proto__, js_object_set___proto__ ),
38377
    JS_CFUNC_MAGIC_DEF("__defineGetter__", 2, js_object___defineGetter__, 0 ),
38378
    JS_CFUNC_MAGIC_DEF("__defineSetter__", 2, js_object___defineGetter__, 1 ),
38379
    JS_CFUNC_MAGIC_DEF("__lookupGetter__", 1, js_object___lookupGetter__, 0 ),
38380
    JS_CFUNC_MAGIC_DEF("__lookupSetter__", 1, js_object___lookupGetter__, 1 ),
38381
};
38382
38383
/* Function class */
38384
38385
static JSValue js_function_proto(JSContext *ctx, JSValueConst this_val,
38386
                                 int argc, JSValueConst *argv)
38387
0
{
38388
0
    return JS_UNDEFINED;
38389
0
}
38390
38391
/* XXX: add a specific eval mode so that Function("}), ({") is rejected */
38392
static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target,
38393
                                       int argc, JSValueConst *argv, int magic)
38394
0
{
38395
0
    JSFunctionKindEnum func_kind = magic;
38396
0
    int i, n, ret;
38397
0
    JSValue s, proto, obj = JS_UNDEFINED;
38398
0
    StringBuffer b_s, *b = &b_s;
38399
38400
0
    string_buffer_init(ctx, b, 0);
38401
0
    string_buffer_putc8(b, '(');
38402
38403
0
    if (func_kind == JS_FUNC_ASYNC || func_kind == JS_FUNC_ASYNC_GENERATOR) {
38404
0
        string_buffer_puts8(b, "async ");
38405
0
    }
38406
0
    string_buffer_puts8(b, "function");
38407
38408
0
    if (func_kind == JS_FUNC_GENERATOR || func_kind == JS_FUNC_ASYNC_GENERATOR) {
38409
0
        string_buffer_putc8(b, '*');
38410
0
    }
38411
0
    string_buffer_puts8(b, " anonymous(");
38412
38413
0
    n = argc - 1;
38414
0
    for(i = 0; i < n; i++) {
38415
0
        if (i != 0) {
38416
0
            string_buffer_putc8(b, ',');
38417
0
        }
38418
0
        if (string_buffer_concat_value(b, argv[i]))
38419
0
            goto fail;
38420
0
    }
38421
0
    string_buffer_puts8(b, "\n) {\n");
38422
0
    if (n >= 0) {
38423
0
        if (string_buffer_concat_value(b, argv[n]))
38424
0
            goto fail;
38425
0
    }
38426
0
    string_buffer_puts8(b, "\n})");
38427
0
    s = string_buffer_end(b);
38428
0
    if (JS_IsException(s))
38429
0
        goto fail1;
38430
38431
0
    obj = JS_EvalObject(ctx, ctx->global_obj, s, JS_EVAL_TYPE_INDIRECT, -1);
38432
0
    JS_FreeValue(ctx, s);
38433
0
    if (JS_IsException(obj))
38434
0
        goto fail1;
38435
0
    if (!JS_IsUndefined(new_target)) {
38436
        /* set the prototype */
38437
0
        proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
38438
0
        if (JS_IsException(proto))
38439
0
            goto fail1;
38440
0
        if (!JS_IsObject(proto)) {
38441
0
            JSContext *realm;
38442
0
            JS_FreeValue(ctx, proto);
38443
0
            realm = JS_GetFunctionRealm(ctx, new_target);
38444
0
            if (!realm)
38445
0
                goto fail1;
38446
0
            proto = JS_DupValue(ctx, realm->class_proto[func_kind_to_class_id[func_kind]]);
38447
0
        }
38448
0
        ret = JS_SetPrototypeInternal(ctx, obj, proto, TRUE);
38449
0
        JS_FreeValue(ctx, proto);
38450
0
        if (ret < 0)
38451
0
            goto fail1;
38452
0
    }
38453
0
    return obj;
38454
38455
0
 fail:
38456
0
    string_buffer_free(b);
38457
0
 fail1:
38458
0
    JS_FreeValue(ctx, obj);
38459
0
    return JS_EXCEPTION;
38460
0
}
38461
38462
static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
38463
                                       JSValueConst obj)
38464
0
{
38465
0
    JSValue len_val;
38466
0
    len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
38467
0
    if (JS_IsException(len_val)) {
38468
0
        *pres = 0;
38469
0
        return -1;
38470
0
    }
38471
0
    return JS_ToUint32Free(ctx, pres, len_val);
38472
0
}
38473
38474
static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
38475
                                       JSValueConst obj)
38476
0
{
38477
0
    JSValue len_val;
38478
0
    len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
38479
0
    if (JS_IsException(len_val)) {
38480
0
        *pres = 0;
38481
0
        return -1;
38482
0
    }
38483
0
    return JS_ToLengthFree(ctx, pres, len_val);
38484
0
}
38485
38486
static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len)
38487
0
{
38488
0
    uint32_t i;
38489
0
    for(i = 0; i < len; i++) {
38490
0
        JS_FreeValue(ctx, tab[i]);
38491
0
    }
38492
0
    js_free(ctx, tab);
38493
0
}
38494
38495
/* XXX: should use ValueArray */
38496
static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
38497
                               JSValueConst array_arg)
38498
0
{
38499
0
    uint32_t len, i;
38500
0
    JSValue *tab, ret;
38501
0
    JSObject *p;
38502
38503
0
    if (JS_VALUE_GET_TAG(array_arg) != JS_TAG_OBJECT) {
38504
0
        JS_ThrowTypeError(ctx, "not a object");
38505
0
        return NULL;
38506
0
    }
38507
0
    if (js_get_length32(ctx, &len, array_arg))
38508
0
        return NULL;
38509
0
    if (len > JS_MAX_LOCAL_VARS) {
38510
        // XXX: check for stack overflow?
38511
0
        JS_ThrowRangeError(ctx, "too many arguments in function call (only %d allowed)",
38512
0
                           JS_MAX_LOCAL_VARS);
38513
0
        return NULL;
38514
0
    }
38515
    /* avoid allocating 0 bytes */
38516
0
    tab = js_mallocz(ctx, sizeof(tab[0]) * max_uint32(1, len));
38517
0
    if (!tab)
38518
0
        return NULL;
38519
0
    p = JS_VALUE_GET_OBJ(array_arg);
38520
0
    if ((p->class_id == JS_CLASS_ARRAY || p->class_id == JS_CLASS_ARGUMENTS) &&
38521
0
        p->fast_array &&
38522
0
        len == p->u.array.count) {
38523
0
        for(i = 0; i < len; i++) {
38524
0
            tab[i] = JS_DupValue(ctx, p->u.array.u.values[i]);
38525
0
        }
38526
0
    } else {
38527
0
        for(i = 0; i < len; i++) {
38528
0
            ret = JS_GetPropertyUint32(ctx, array_arg, i);
38529
0
            if (JS_IsException(ret)) {
38530
0
                free_arg_list(ctx, tab, i);
38531
0
                return NULL;
38532
0
            }
38533
0
            tab[i] = ret;
38534
0
        }
38535
0
    }
38536
0
    *plen = len;
38537
0
    return tab;
38538
0
}
38539
38540
/* magic value: 0 = normal apply, 1 = apply for constructor, 2 =
38541
   Reflect.apply */
38542
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
38543
                                 int argc, JSValueConst *argv, int magic)
38544
0
{
38545
0
    JSValueConst this_arg, array_arg;
38546
0
    uint32_t len;
38547
0
    JSValue *tab, ret;
38548
38549
0
    if (check_function(ctx, this_val))
38550
0
        return JS_EXCEPTION;
38551
0
    this_arg = argv[0];
38552
0
    array_arg = argv[1];
38553
0
    if ((JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED ||
38554
0
         JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) && magic != 2) {
38555
0
        return JS_Call(ctx, this_val, this_arg, 0, NULL);
38556
0
    }
38557
0
    tab = build_arg_list(ctx, &len, array_arg);
38558
0
    if (!tab)
38559
0
        return JS_EXCEPTION;
38560
0
    if (magic & 1) {
38561
0
        ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab);
38562
0
    } else {
38563
0
        ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab);
38564
0
    }
38565
0
    free_arg_list(ctx, tab, len);
38566
0
    return ret;
38567
0
}
38568
38569
static JSValue js_function_call(JSContext *ctx, JSValueConst this_val,
38570
                                int argc, JSValueConst *argv)
38571
0
{
38572
0
    if (argc <= 0) {
38573
0
        return JS_Call(ctx, this_val, JS_UNDEFINED, 0, NULL);
38574
0
    } else {
38575
0
        return JS_Call(ctx, this_val, argv[0], argc - 1, argv + 1);
38576
0
    }
38577
0
}
38578
38579
static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val,
38580
                                int argc, JSValueConst *argv)
38581
0
{
38582
0
    JSBoundFunction *bf;
38583
0
    JSValue func_obj, name1, len_val;
38584
0
    JSObject *p;
38585
0
    int arg_count, i, ret;
38586
38587
0
    if (check_function(ctx, this_val))
38588
0
        return JS_EXCEPTION;
38589
38590
0
    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
38591
0
                                 JS_CLASS_BOUND_FUNCTION);
38592
0
    if (JS_IsException(func_obj))
38593
0
        return JS_EXCEPTION;
38594
0
    p = JS_VALUE_GET_OBJ(func_obj);
38595
0
    p->is_constructor = JS_IsConstructor(ctx, this_val);
38596
0
    arg_count = max_int(0, argc - 1);
38597
0
    bf = js_malloc(ctx, sizeof(*bf) + arg_count * sizeof(JSValue));
38598
0
    if (!bf)
38599
0
        goto exception;
38600
0
    bf->func_obj = JS_DupValue(ctx, this_val);
38601
0
    bf->this_val = JS_DupValue(ctx, argv[0]);
38602
0
    bf->argc = arg_count;
38603
0
    for(i = 0; i < arg_count; i++) {
38604
0
        bf->argv[i] = JS_DupValue(ctx, argv[i + 1]);
38605
0
    }
38606
0
    p->u.bound_function = bf;
38607
38608
    /* XXX: the spec could be simpler by only using GetOwnProperty */
38609
0
    ret = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_length);
38610
0
    if (ret < 0)
38611
0
        goto exception;
38612
0
    if (!ret) {
38613
0
        len_val = JS_NewInt32(ctx, 0);
38614
0
    } else {
38615
0
        len_val = JS_GetProperty(ctx, this_val, JS_ATOM_length);
38616
0
        if (JS_IsException(len_val))
38617
0
            goto exception;
38618
0
        if (JS_VALUE_GET_TAG(len_val) == JS_TAG_INT) {
38619
            /* most common case */
38620
0
            int len1 = JS_VALUE_GET_INT(len_val);
38621
0
            if (len1 <= arg_count)
38622
0
                len1 = 0;
38623
0
            else
38624
0
                len1 -= arg_count;
38625
0
            len_val = JS_NewInt32(ctx, len1);
38626
0
        } else if (JS_VALUE_GET_NORM_TAG(len_val) == JS_TAG_FLOAT64) {
38627
0
            double d = JS_VALUE_GET_FLOAT64(len_val);
38628
0
            if (isnan(d)) {
38629
0
                d = 0.0;
38630
0
            } else {
38631
0
                d = trunc(d);
38632
0
                if (d <= (double)arg_count)
38633
0
                    d = 0.0;
38634
0
                else
38635
0
                    d -= (double)arg_count; /* also converts -0 to +0 */
38636
0
            }
38637
0
            len_val = JS_NewFloat64(ctx, d);
38638
0
        } else {
38639
0
            JS_FreeValue(ctx, len_val);
38640
0
            len_val = JS_NewInt32(ctx, 0);
38641
0
        }
38642
0
    }
38643
0
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length,
38644
0
                           len_val, JS_PROP_CONFIGURABLE);
38645
38646
0
    name1 = JS_GetProperty(ctx, this_val, JS_ATOM_name);
38647
0
    if (JS_IsException(name1))
38648
0
        goto exception;
38649
0
    if (!JS_IsString(name1)) {
38650
0
        JS_FreeValue(ctx, name1);
38651
0
        name1 = JS_AtomToString(ctx, JS_ATOM_empty_string);
38652
0
    }
38653
0
    name1 = JS_ConcatString3(ctx, "bound ", name1, "");
38654
0
    if (JS_IsException(name1))
38655
0
        goto exception;
38656
0
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name1,
38657
0
                           JS_PROP_CONFIGURABLE);
38658
0
    return func_obj;
38659
0
 exception:
38660
0
    JS_FreeValue(ctx, func_obj);
38661
0
    return JS_EXCEPTION;
38662
0
}
38663
38664
static JSValue js_function_toString(JSContext *ctx, JSValueConst this_val,
38665
                                    int argc, JSValueConst *argv)
38666
0
{
38667
0
    JSObject *p;
38668
0
    JSFunctionKindEnum func_kind = JS_FUNC_NORMAL;
38669
38670
0
    if (check_function(ctx, this_val))
38671
0
        return JS_EXCEPTION;
38672
38673
0
    p = JS_VALUE_GET_OBJ(this_val);
38674
0
    if (js_class_has_bytecode(p->class_id)) {
38675
0
        JSFunctionBytecode *b = p->u.func.function_bytecode;
38676
0
        if (b->has_debug && b->debug.source) {
38677
0
            return JS_NewStringLen(ctx, b->debug.source, b->debug.source_len);
38678
0
        }
38679
0
        func_kind = b->func_kind;
38680
0
    }
38681
0
    {
38682
0
        JSValue name;
38683
0
        const char *pref, *suff;
38684
38685
0
        switch(func_kind) {
38686
0
        default:
38687
0
        case JS_FUNC_NORMAL:
38688
0
            pref = "function ";
38689
0
            break;
38690
0
        case JS_FUNC_GENERATOR:
38691
0
            pref = "function *";
38692
0
            break;
38693
0
        case JS_FUNC_ASYNC:
38694
0
            pref = "async function ";
38695
0
            break;
38696
0
        case JS_FUNC_ASYNC_GENERATOR:
38697
0
            pref = "async function *";
38698
0
            break;
38699
0
        }
38700
0
        suff = "() {\n    [native code]\n}";
38701
0
        name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
38702
0
        if (JS_IsUndefined(name))
38703
0
            name = JS_AtomToString(ctx, JS_ATOM_empty_string);
38704
0
        return JS_ConcatString3(ctx, pref, name, suff);
38705
0
    }
38706
0
}
38707
38708
static JSValue js_function_hasInstance(JSContext *ctx, JSValueConst this_val,
38709
                                       int argc, JSValueConst *argv)
38710
0
{
38711
0
    int ret;
38712
0
    ret = JS_OrdinaryIsInstanceOf(ctx, argv[0], this_val);
38713
0
    if (ret < 0)
38714
0
        return JS_EXCEPTION;
38715
0
    else
38716
0
        return JS_NewBool(ctx, ret);
38717
0
}
38718
38719
static const JSCFunctionListEntry js_function_proto_funcs[] = {
38720
    JS_CFUNC_DEF("call", 1, js_function_call ),
38721
    JS_CFUNC_MAGIC_DEF("apply", 2, js_function_apply, 0 ),
38722
    JS_CFUNC_DEF("bind", 1, js_function_bind ),
38723
    JS_CFUNC_DEF("toString", 0, js_function_toString ),
38724
    JS_CFUNC_DEF("[Symbol.hasInstance]", 1, js_function_hasInstance ),
38725
    JS_CGETSET_DEF("fileName", js_function_proto_fileName, NULL ),
38726
    JS_CGETSET_DEF("lineNumber", js_function_proto_lineNumber, NULL ),
38727
};
38728
38729
/* Error class */
38730
38731
static JSValue iterator_to_array(JSContext *ctx, JSValueConst items)
38732
0
{
38733
0
    JSValue iter, next_method = JS_UNDEFINED;
38734
0
    JSValue v, r = JS_UNDEFINED;
38735
0
    int64_t k;
38736
0
    BOOL done;
38737
38738
0
    iter = JS_GetIterator(ctx, items, FALSE);
38739
0
    if (JS_IsException(iter))
38740
0
        goto exception;
38741
0
    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
38742
0
    if (JS_IsException(next_method))
38743
0
        goto exception;
38744
0
    r = JS_NewArray(ctx);
38745
0
    if (JS_IsException(r))
38746
0
        goto exception;
38747
0
    for (k = 0;; k++) {
38748
0
        v = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
38749
0
        if (JS_IsException(v))
38750
0
            goto exception_close;
38751
0
        if (done)
38752
0
            break;
38753
0
        if (JS_DefinePropertyValueInt64(ctx, r, k, v,
38754
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38755
0
            goto exception_close;
38756
0
    }
38757
0
 done:
38758
0
    JS_FreeValue(ctx, next_method);
38759
0
    JS_FreeValue(ctx, iter);
38760
0
    return r;
38761
0
 exception_close:
38762
0
    JS_IteratorClose(ctx, iter, TRUE);
38763
0
 exception:
38764
0
    JS_FreeValue(ctx, r);
38765
0
    r = JS_EXCEPTION;
38766
0
    goto done;
38767
0
}
38768
38769
static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
38770
                                    int argc, JSValueConst *argv, int magic)
38771
0
{
38772
0
    JSValue obj, msg, proto;
38773
0
    JSValueConst message, options;
38774
0
    int arg_index;
38775
38776
0
    if (JS_IsUndefined(new_target))
38777
0
        new_target = JS_GetActiveFunction(ctx);
38778
0
    proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
38779
0
    if (JS_IsException(proto))
38780
0
        return proto;
38781
0
    if (!JS_IsObject(proto)) {
38782
0
        JSContext *realm;
38783
0
        JSValueConst proto1;
38784
38785
0
        JS_FreeValue(ctx, proto);
38786
0
        realm = JS_GetFunctionRealm(ctx, new_target);
38787
0
        if (!realm)
38788
0
            return JS_EXCEPTION;
38789
0
        if (magic < 0) {
38790
0
            proto1 = realm->class_proto[JS_CLASS_ERROR];
38791
0
        } else {
38792
0
            proto1 = realm->native_error_proto[magic];
38793
0
        }
38794
0
        proto = JS_DupValue(ctx, proto1);
38795
0
    }
38796
0
    obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_ERROR);
38797
0
    JS_FreeValue(ctx, proto);
38798
0
    if (JS_IsException(obj))
38799
0
        return obj;
38800
0
    arg_index = (magic == JS_AGGREGATE_ERROR);
38801
38802
0
    message = argv[arg_index++];
38803
0
    if (!JS_IsUndefined(message)) {
38804
0
        msg = JS_ToString(ctx, message);
38805
0
        if (unlikely(JS_IsException(msg)))
38806
0
            goto exception;
38807
0
        JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg,
38808
0
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
38809
0
    }
38810
38811
0
    if (arg_index < argc) {
38812
0
        options = argv[arg_index];
38813
0
        if (JS_IsObject(options)) {
38814
0
            int present = JS_HasProperty(ctx, options, JS_ATOM_cause);
38815
0
            if (present < 0)
38816
0
                goto exception;
38817
0
            if (present) {
38818
0
                JSValue cause = JS_GetProperty(ctx, options, JS_ATOM_cause);
38819
0
                if (JS_IsException(cause))
38820
0
                    goto exception;
38821
0
                JS_DefinePropertyValue(ctx, obj, JS_ATOM_cause, cause,
38822
0
                                       JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
38823
0
            }
38824
0
        }
38825
0
    }
38826
38827
0
    if (magic == JS_AGGREGATE_ERROR) {
38828
0
        JSValue error_list = iterator_to_array(ctx, argv[0]);
38829
0
        if (JS_IsException(error_list))
38830
0
            goto exception;
38831
0
        JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, error_list,
38832
0
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
38833
0
    }
38834
38835
    /* skip the Error() function in the backtrace */
38836
0
    build_backtrace(ctx, obj, NULL, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
38837
0
    return obj;
38838
0
 exception:
38839
0
    JS_FreeValue(ctx, obj);
38840
0
    return JS_EXCEPTION;
38841
0
}
38842
38843
static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
38844
                                 int argc, JSValueConst *argv)
38845
0
{
38846
0
    JSValue name, msg;
38847
38848
0
    if (!JS_IsObject(this_val))
38849
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
38850
0
    name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
38851
0
    if (JS_IsUndefined(name))
38852
0
        name = JS_AtomToString(ctx, JS_ATOM_Error);
38853
0
    else
38854
0
        name = JS_ToStringFree(ctx, name);
38855
0
    if (JS_IsException(name))
38856
0
        return JS_EXCEPTION;
38857
38858
0
    msg = JS_GetProperty(ctx, this_val, JS_ATOM_message);
38859
0
    if (JS_IsUndefined(msg))
38860
0
        msg = JS_AtomToString(ctx, JS_ATOM_empty_string);
38861
0
    else
38862
0
        msg = JS_ToStringFree(ctx, msg);
38863
0
    if (JS_IsException(msg)) {
38864
0
        JS_FreeValue(ctx, name);
38865
0
        return JS_EXCEPTION;
38866
0
    }
38867
0
    if (!JS_IsEmptyString(name) && !JS_IsEmptyString(msg))
38868
0
        name = JS_ConcatString3(ctx, "", name, ": ");
38869
0
    return JS_ConcatString(ctx, name, msg);
38870
0
}
38871
38872
static const JSCFunctionListEntry js_error_proto_funcs[] = {
38873
    JS_CFUNC_DEF("toString", 0, js_error_toString ),
38874
    JS_PROP_STRING_DEF("name", "Error", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
38875
    JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
38876
};
38877
38878
/* AggregateError */
38879
38880
/* used by C code. */
38881
static JSValue js_aggregate_error_constructor(JSContext *ctx,
38882
                                              JSValueConst errors)
38883
0
{
38884
0
    JSValue obj;
38885
38886
0
    obj = JS_NewObjectProtoClass(ctx,
38887
0
                                 ctx->native_error_proto[JS_AGGREGATE_ERROR],
38888
0
                                 JS_CLASS_ERROR);
38889
0
    if (JS_IsException(obj))
38890
0
        return obj;
38891
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, JS_DupValue(ctx, errors),
38892
0
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
38893
0
    return obj;
38894
0
}
38895
38896
/* Array */
38897
38898
static int JS_CopySubArray(JSContext *ctx,
38899
                           JSValueConst obj, int64_t to_pos,
38900
                           int64_t from_pos, int64_t count, int dir)
38901
0
{
38902
0
    JSObject *p;
38903
0
    int64_t i, from, to, len;
38904
0
    JSValue val;
38905
0
    int fromPresent;
38906
38907
0
    p = NULL;
38908
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
38909
0
        p = JS_VALUE_GET_OBJ(obj);
38910
0
        if (p->class_id != JS_CLASS_ARRAY || !p->fast_array) {
38911
0
            p = NULL;
38912
0
        }
38913
0
    }
38914
38915
0
    for (i = 0; i < count; ) {
38916
0
        if (dir < 0) {
38917
0
            from = from_pos + count - i - 1;
38918
0
            to = to_pos + count - i - 1;
38919
0
        } else {
38920
0
            from = from_pos + i;
38921
0
            to = to_pos + i;
38922
0
        }
38923
0
        if (p && p->fast_array &&
38924
0
            from >= 0 && from < (len = p->u.array.count)  &&
38925
0
            to >= 0 && to < len) {
38926
0
            int64_t l, j;
38927
            /* Fast path for fast arrays. Since we don't look at the
38928
               prototype chain, we can optimize only the cases where
38929
               all the elements are present in the array. */
38930
0
            l = count - i;
38931
0
            if (dir < 0) {
38932
0
                l = min_int64(l, from + 1);
38933
0
                l = min_int64(l, to + 1);
38934
0
                for(j = 0; j < l; j++) {
38935
0
                    set_value(ctx, &p->u.array.u.values[to - j],
38936
0
                              JS_DupValue(ctx, p->u.array.u.values[from - j]));
38937
0
                }
38938
0
            } else {
38939
0
                l = min_int64(l, len - from);
38940
0
                l = min_int64(l, len - to);
38941
0
                for(j = 0; j < l; j++) {
38942
0
                    set_value(ctx, &p->u.array.u.values[to + j],
38943
0
                              JS_DupValue(ctx, p->u.array.u.values[from + j]));
38944
0
                }
38945
0
            }
38946
0
            i += l;
38947
0
        } else {
38948
0
            fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
38949
0
            if (fromPresent < 0)
38950
0
                goto exception;
38951
38952
0
            if (fromPresent) {
38953
0
                if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)
38954
0
                    goto exception;
38955
0
            } else {
38956
0
                if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0)
38957
0
                    goto exception;
38958
0
            }
38959
0
            i++;
38960
0
        }
38961
0
    }
38962
0
    return 0;
38963
38964
0
 exception:
38965
0
    return -1;
38966
0
}
38967
38968
static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target,
38969
                                    int argc, JSValueConst *argv)
38970
0
{
38971
0
    JSValue obj;
38972
0
    int i;
38973
38974
0
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_ARRAY);
38975
0
    if (JS_IsException(obj))
38976
0
        return obj;
38977
0
    if (argc == 1 && JS_IsNumber(argv[0])) {
38978
0
        uint32_t len;
38979
0
        if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]), TRUE))
38980
0
            goto fail;
38981
0
        if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0)
38982
0
            goto fail;
38983
0
    } else {
38984
0
        for(i = 0; i < argc; i++) {
38985
0
            if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0)
38986
0
                goto fail;
38987
0
        }
38988
0
    }
38989
0
    return obj;
38990
0
fail:
38991
0
    JS_FreeValue(ctx, obj);
38992
0
    return JS_EXCEPTION;
38993
0
}
38994
38995
static JSValue js_array_from(JSContext *ctx, JSValueConst this_val,
38996
                             int argc, JSValueConst *argv)
38997
0
{
38998
    // from(items, mapfn = void 0, this_arg = void 0)
38999
0
    JSValueConst items = argv[0], mapfn, this_arg;
39000
0
    JSValueConst args[2];
39001
0
    JSValue stack[2];
39002
0
    JSValue iter, r, v, v2, arrayLike;
39003
0
    int64_t k, len;
39004
0
    int done, mapping;
39005
39006
0
    mapping = FALSE;
39007
0
    mapfn = JS_UNDEFINED;
39008
0
    this_arg = JS_UNDEFINED;
39009
0
    r = JS_UNDEFINED;
39010
0
    arrayLike = JS_UNDEFINED;
39011
0
    stack[0] = JS_UNDEFINED;
39012
0
    stack[1] = JS_UNDEFINED;
39013
39014
0
    if (argc > 1) {
39015
0
        mapfn = argv[1];
39016
0
        if (!JS_IsUndefined(mapfn)) {
39017
0
            if (check_function(ctx, mapfn))
39018
0
                goto exception;
39019
0
            mapping = 1;
39020
0
            if (argc > 2)
39021
0
                this_arg = argv[2];
39022
0
        }
39023
0
    }
39024
0
    iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
39025
0
    if (JS_IsException(iter))
39026
0
        goto exception;
39027
0
    if (!JS_IsUndefined(iter)) {
39028
0
        JS_FreeValue(ctx, iter);
39029
0
        if (JS_IsConstructor(ctx, this_val))
39030
0
            r = JS_CallConstructor(ctx, this_val, 0, NULL);
39031
0
        else
39032
0
            r = JS_NewArray(ctx);
39033
0
        if (JS_IsException(r))
39034
0
            goto exception;
39035
0
        stack[0] = JS_DupValue(ctx, items);
39036
0
        if (js_for_of_start(ctx, &stack[1], FALSE))
39037
0
            goto exception;
39038
0
        for (k = 0;; k++) {
39039
0
            v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done);
39040
0
            if (JS_IsException(v))
39041
0
                goto exception_close;
39042
0
            if (done)
39043
0
                break;
39044
0
            if (mapping) {
39045
0
                args[0] = v;
39046
0
                args[1] = JS_NewInt32(ctx, k);
39047
0
                v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
39048
0
                JS_FreeValue(ctx, v);
39049
0
                v = v2;
39050
0
                if (JS_IsException(v))
39051
0
                    goto exception_close;
39052
0
            }
39053
0
            if (JS_DefinePropertyValueInt64(ctx, r, k, v,
39054
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
39055
0
                goto exception_close;
39056
0
        }
39057
0
    } else {
39058
0
        arrayLike = JS_ToObject(ctx, items);
39059
0
        if (JS_IsException(arrayLike))
39060
0
            goto exception;
39061
0
        if (js_get_length64(ctx, &len, arrayLike) < 0)
39062
0
            goto exception;
39063
0
        v = JS_NewInt64(ctx, len);
39064
0
        args[0] = v;
39065
0
        if (JS_IsConstructor(ctx, this_val)) {
39066
0
            r = JS_CallConstructor(ctx, this_val, 1, args);
39067
0
        } else {
39068
0
            r = js_array_constructor(ctx, JS_UNDEFINED, 1, args);
39069
0
        }
39070
0
        JS_FreeValue(ctx, v);
39071
0
        if (JS_IsException(r))
39072
0
            goto exception;
39073
0
        for(k = 0; k < len; k++) {
39074
0
            v = JS_GetPropertyInt64(ctx, arrayLike, k);
39075
0
            if (JS_IsException(v))
39076
0
                goto exception;
39077
0
            if (mapping) {
39078
0
                args[0] = v;
39079
0
                args[1] = JS_NewInt32(ctx, k);
39080
0
                v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
39081
0
                JS_FreeValue(ctx, v);
39082
0
                v = v2;
39083
0
                if (JS_IsException(v))
39084
0
                    goto exception;
39085
0
            }
39086
0
            if (JS_DefinePropertyValueInt64(ctx, r, k, v,
39087
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
39088
0
                goto exception;
39089
0
        }
39090
0
    }
39091
0
    if (JS_SetProperty(ctx, r, JS_ATOM_length, JS_NewUint32(ctx, k)) < 0)
39092
0
        goto exception;
39093
0
    goto done;
39094
39095
0
 exception_close:
39096
0
    if (!JS_IsUndefined(stack[0]))
39097
0
        JS_IteratorClose(ctx, stack[0], TRUE);
39098
0
 exception:
39099
0
    JS_FreeValue(ctx, r);
39100
0
    r = JS_EXCEPTION;
39101
0
 done:
39102
0
    JS_FreeValue(ctx, arrayLike);
39103
0
    JS_FreeValue(ctx, stack[0]);
39104
0
    JS_FreeValue(ctx, stack[1]);
39105
0
    return r;
39106
0
}
39107
39108
static JSValue js_array_of(JSContext *ctx, JSValueConst this_val,
39109
                           int argc, JSValueConst *argv)
39110
0
{
39111
0
    JSValue obj, args[1];
39112
0
    int i;
39113
39114
0
    if (JS_IsConstructor(ctx, this_val)) {
39115
0
        args[0] = JS_NewInt32(ctx, argc);
39116
0
        obj = JS_CallConstructor(ctx, this_val, 1, (JSValueConst *)args);
39117
0
    } else {
39118
0
        obj = JS_NewArray(ctx);
39119
0
    }
39120
0
    if (JS_IsException(obj))
39121
0
        return JS_EXCEPTION;
39122
0
    for(i = 0; i < argc; i++) {
39123
0
        if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i]),
39124
0
                                        JS_PROP_THROW) < 0) {
39125
0
            goto fail;
39126
0
        }
39127
0
    }
39128
0
    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, argc)) < 0) {
39129
0
    fail:
39130
0
        JS_FreeValue(ctx, obj);
39131
0
        return JS_EXCEPTION;
39132
0
    }
39133
0
    return obj;
39134
0
}
39135
39136
static JSValue js_array_isArray(JSContext *ctx, JSValueConst this_val,
39137
                                int argc, JSValueConst *argv)
39138
0
{
39139
0
    int ret;
39140
0
    ret = JS_IsArray(ctx, argv[0]);
39141
0
    if (ret < 0)
39142
0
        return JS_EXCEPTION;
39143
0
    else
39144
0
        return JS_NewBool(ctx, ret);
39145
0
}
39146
39147
static JSValue js_get_this(JSContext *ctx,
39148
                           JSValueConst this_val)
39149
0
{
39150
0
    return JS_DupValue(ctx, this_val);
39151
0
}
39152
39153
static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj,
39154
                                     JSValueConst len_val)
39155
0
{
39156
0
    JSValue ctor, ret, species;
39157
0
    int res;
39158
0
    JSContext *realm;
39159
39160
0
    res = JS_IsArray(ctx, obj);
39161
0
    if (res < 0)
39162
0
        return JS_EXCEPTION;
39163
0
    if (!res)
39164
0
        return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
39165
0
    ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
39166
0
    if (JS_IsException(ctor))
39167
0
        return ctor;
39168
0
    if (JS_IsConstructor(ctx, ctor)) {
39169
        /* legacy web compatibility */
39170
0
        realm = JS_GetFunctionRealm(ctx, ctor);
39171
0
        if (!realm) {
39172
0
            JS_FreeValue(ctx, ctor);
39173
0
            return JS_EXCEPTION;
39174
0
        }
39175
0
        if (realm != ctx &&
39176
0
            js_same_value(ctx, ctor, realm->array_ctor)) {
39177
0
            JS_FreeValue(ctx, ctor);
39178
0
            ctor = JS_UNDEFINED;
39179
0
        }
39180
0
    }
39181
0
    if (JS_IsObject(ctor)) {
39182
0
        species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
39183
0
        JS_FreeValue(ctx, ctor);
39184
0
        if (JS_IsException(species))
39185
0
            return species;
39186
0
        ctor = species;
39187
0
        if (JS_IsNull(ctor))
39188
0
            ctor = JS_UNDEFINED;
39189
0
    }
39190
0
    if (JS_IsUndefined(ctor)) {
39191
0
        return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
39192
0
    } else {
39193
0
        ret = JS_CallConstructor(ctx, ctor, 1, &len_val);
39194
0
        JS_FreeValue(ctx, ctor);
39195
0
        return ret;
39196
0
    }
39197
0
}
39198
39199
static const JSCFunctionListEntry js_array_funcs[] = {
39200
    JS_CFUNC_DEF("isArray", 1, js_array_isArray ),
39201
    JS_CFUNC_DEF("from", 1, js_array_from ),
39202
    JS_CFUNC_DEF("of", 0, js_array_of ),
39203
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
39204
};
39205
39206
static int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj)
39207
0
{
39208
0
    JSValue val;
39209
39210
0
    if (!JS_IsObject(obj))
39211
0
        return FALSE;
39212
0
    val = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_isConcatSpreadable);
39213
0
    if (JS_IsException(val))
39214
0
        return -1;
39215
0
    if (!JS_IsUndefined(val))
39216
0
        return JS_ToBoolFree(ctx, val);
39217
0
    return JS_IsArray(ctx, obj);
39218
0
}
39219
39220
static JSValue js_array_at(JSContext *ctx, JSValueConst this_val,
39221
                           int argc, JSValueConst *argv)
39222
0
{
39223
0
    JSValue obj, ret;
39224
0
    int64_t len, idx;
39225
0
    JSValue *arrp;
39226
0
    uint32_t count;
39227
39228
0
    obj = JS_ToObject(ctx, this_val);
39229
0
    if (js_get_length64(ctx, &len, obj))
39230
0
        goto exception;
39231
39232
0
    if (JS_ToInt64Sat(ctx, &idx, argv[0]))
39233
0
        goto exception;
39234
39235
0
    if (idx < 0)
39236
0
        idx = len + idx;
39237
0
    if (idx < 0 || idx >= len) {
39238
0
        ret = JS_UNDEFINED;
39239
0
    } else if (js_get_fast_array(ctx, obj, &arrp, &count) && idx < count) {
39240
0
        ret = JS_DupValue(ctx, arrp[idx]);
39241
0
    } else {
39242
0
        int present = JS_TryGetPropertyInt64(ctx, obj, idx, &ret);
39243
0
        if (present < 0)
39244
0
            goto exception;
39245
0
        if (!present)
39246
0
            ret = JS_UNDEFINED;
39247
0
    }
39248
0
    JS_FreeValue(ctx, obj);
39249
0
    return ret;
39250
0
 exception:
39251
0
    JS_FreeValue(ctx, obj);
39252
0
    return JS_EXCEPTION;
39253
0
}
39254
39255
static JSValue js_array_with(JSContext *ctx, JSValueConst this_val,
39256
                             int argc, JSValueConst *argv)
39257
0
{
39258
0
    JSValue arr, obj, ret, *arrp, *pval;
39259
0
    JSObject *p;
39260
0
    int64_t i, len, idx;
39261
0
    uint32_t count32;
39262
39263
0
    ret = JS_EXCEPTION;
39264
0
    arr = JS_UNDEFINED;
39265
0
    obj = JS_ToObject(ctx, this_val);
39266
0
    if (js_get_length64(ctx, &len, obj))
39267
0
        goto exception;
39268
39269
0
    if (JS_ToInt64Sat(ctx, &idx, argv[0]))
39270
0
        goto exception;
39271
39272
0
    if (idx < 0)
39273
0
        idx = len + idx;
39274
39275
0
    if (idx < 0 || idx >= len) {
39276
0
        JS_ThrowRangeError(ctx, "invalid array index: %" PRId64, idx);
39277
0
        goto exception;
39278
0
    }
39279
39280
0
    arr = js_allocate_fast_array(ctx, len);
39281
0
    if (JS_IsException(arr))
39282
0
        goto exception;
39283
39284
0
    p = JS_VALUE_GET_OBJ(arr);
39285
0
    i = 0;
39286
0
    pval = p->u.array.u.values;
39287
0
    if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
39288
0
        for (; i < idx; i++, pval++)
39289
0
            *pval = JS_DupValue(ctx, arrp[i]);
39290
0
        *pval = JS_DupValue(ctx, argv[1]);
39291
0
        for (i++, pval++; i < len; i++, pval++)
39292
0
            *pval = JS_DupValue(ctx, arrp[i]);
39293
0
    } else {
39294
0
        for (; i < idx; i++, pval++)
39295
0
            if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
39296
0
                goto fill_and_fail;
39297
0
        *pval = JS_DupValue(ctx, argv[1]);
39298
0
        for (i++, pval++; i < len; i++, pval++) {
39299
0
            if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
39300
0
            fill_and_fail:
39301
0
                for (; i < len; i++, pval++)
39302
0
                    *pval = JS_UNDEFINED;
39303
0
                goto exception;
39304
0
            }
39305
0
        }
39306
0
    }
39307
39308
0
    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)
39309
0
        goto exception;
39310
39311
0
    ret = arr;
39312
0
    arr = JS_UNDEFINED;
39313
39314
0
exception:
39315
0
    JS_FreeValue(ctx, arr);
39316
0
    JS_FreeValue(ctx, obj);
39317
0
    return ret;
39318
0
}
39319
39320
static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val,
39321
                               int argc, JSValueConst *argv)
39322
0
{
39323
0
    JSValue obj, arr, val;
39324
0
    JSValueConst e;
39325
0
    int64_t len, k, n;
39326
0
    int i, res;
39327
39328
0
    arr = JS_UNDEFINED;
39329
0
    obj = JS_ToObject(ctx, this_val);
39330
0
    if (JS_IsException(obj))
39331
0
        goto exception;
39332
39333
0
    arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
39334
0
    if (JS_IsException(arr))
39335
0
        goto exception;
39336
0
    n = 0;
39337
0
    for (i = -1; i < argc; i++) {
39338
0
        if (i < 0)
39339
0
            e = obj;
39340
0
        else
39341
0
            e = argv[i];
39342
39343
0
        res = JS_isConcatSpreadable(ctx, e);
39344
0
        if (res < 0)
39345
0
            goto exception;
39346
0
        if (res) {
39347
0
            if (js_get_length64(ctx, &len, e))
39348
0
                goto exception;
39349
0
            if (n + len > MAX_SAFE_INTEGER) {
39350
0
                JS_ThrowTypeError(ctx, "Array loo long");
39351
0
                goto exception;
39352
0
            }
39353
0
            for (k = 0; k < len; k++, n++) {
39354
0
                res = JS_TryGetPropertyInt64(ctx, e, k, &val);
39355
0
                if (res < 0)
39356
0
                    goto exception;
39357
0
                if (res) {
39358
0
                    if (JS_DefinePropertyValueInt64(ctx, arr, n, val,
39359
0
                                                    JS_PROP_C_W_E | JS_PROP_THROW) < 0)
39360
0
                        goto exception;
39361
0
                }
39362
0
            }
39363
0
        } else {
39364
0
            if (n >= MAX_SAFE_INTEGER) {
39365
0
                JS_ThrowTypeError(ctx, "Array loo long");
39366
0
                goto exception;
39367
0
            }
39368
0
            if (JS_DefinePropertyValueInt64(ctx, arr, n, JS_DupValue(ctx, e),
39369
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
39370
0
                goto exception;
39371
0
            n++;
39372
0
        }
39373
0
    }
39374
0
    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
39375
0
        goto exception;
39376
39377
0
    JS_FreeValue(ctx, obj);
39378
0
    return arr;
39379
39380
0
exception:
39381
0
    JS_FreeValue(ctx, arr);
39382
0
    JS_FreeValue(ctx, obj);
39383
0
    return JS_EXCEPTION;
39384
0
}
39385
39386
0
#define special_every    0
39387
0
#define special_some     1
39388
#define special_forEach  2
39389
0
#define special_map      3
39390
0
#define special_filter   4
39391
0
#define special_TA       8
39392
39393
static int js_typed_array_get_length_internal(JSContext *ctx, JSValueConst obj);
39394
39395
static JSValue js_typed_array___speciesCreate(JSContext *ctx,
39396
                                              JSValueConst this_val,
39397
                                              int argc, JSValueConst *argv);
39398
39399
static JSValue js_array_every(JSContext *ctx, JSValueConst this_val,
39400
                              int argc, JSValueConst *argv, int special)
39401
0
{
39402
0
    JSValue obj, val, index_val, res, ret;
39403
0
    JSValueConst args[3];
39404
0
    JSValueConst func, this_arg;
39405
0
    int64_t len, k, n;
39406
0
    int present;
39407
39408
0
    ret = JS_UNDEFINED;
39409
0
    val = JS_UNDEFINED;
39410
0
    if (special & special_TA) {
39411
0
        obj = JS_DupValue(ctx, this_val);
39412
0
        len = js_typed_array_get_length_internal(ctx, obj);
39413
0
        if (len < 0)
39414
0
            goto exception;
39415
0
    } else {
39416
0
        obj = JS_ToObject(ctx, this_val);
39417
0
        if (js_get_length64(ctx, &len, obj))
39418
0
            goto exception;
39419
0
    }
39420
0
    func = argv[0];
39421
0
    this_arg = JS_UNDEFINED;
39422
0
    if (argc > 1)
39423
0
        this_arg = argv[1];
39424
39425
0
    if (check_function(ctx, func))
39426
0
        goto exception;
39427
39428
0
    switch (special) {
39429
0
    case special_every:
39430
0
    case special_every | special_TA:
39431
0
        ret = JS_TRUE;
39432
0
        break;
39433
0
    case special_some:
39434
0
    case special_some | special_TA:
39435
0
        ret = JS_FALSE;
39436
0
        break;
39437
0
    case special_map:
39438
        /* XXX: JS_ArraySpeciesCreate should take int64_t */
39439
0
        ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt64(ctx, len));
39440
0
        if (JS_IsException(ret))
39441
0
            goto exception;
39442
0
        break;
39443
0
    case special_filter:
39444
0
        ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
39445
0
        if (JS_IsException(ret))
39446
0
            goto exception;
39447
0
        break;
39448
0
    case special_map | special_TA:
39449
0
        args[0] = obj;
39450
0
        args[1] = JS_NewInt32(ctx, len);
39451
0
        ret = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
39452
0
        if (JS_IsException(ret))
39453
0
            goto exception;
39454
0
        break;
39455
0
    case special_filter | special_TA:
39456
0
        ret = JS_NewArray(ctx);
39457
0
        if (JS_IsException(ret))
39458
0
            goto exception;
39459
0
        break;
39460
0
    }
39461
0
    n = 0;
39462
39463
0
    for(k = 0; k < len; k++) {
39464
0
        if (special & special_TA) {
39465
0
            val = JS_GetPropertyInt64(ctx, obj, k);
39466
0
            if (JS_IsException(val))
39467
0
                goto exception;
39468
0
            present = TRUE;
39469
0
        } else {
39470
0
            present = JS_TryGetPropertyInt64(ctx, obj, k, &val);
39471
0
            if (present < 0)
39472
0
                goto exception;
39473
0
        }
39474
0
        if (present) {
39475
0
            index_val = JS_NewInt64(ctx, k);
39476
0
            if (JS_IsException(index_val))
39477
0
                goto exception;
39478
0
            args[0] = val;
39479
0
            args[1] = index_val;
39480
0
            args[2] = obj;
39481
0
            res = JS_Call(ctx, func, this_arg, 3, args);
39482
0
            JS_FreeValue(ctx, index_val);
39483
0
            if (JS_IsException(res))
39484
0
                goto exception;
39485
0
            switch (special) {
39486
0
            case special_every:
39487
0
            case special_every | special_TA:
39488
0
                if (!JS_ToBoolFree(ctx, res)) {
39489
0
                    ret = JS_FALSE;
39490
0
                    goto done;
39491
0
                }
39492
0
                break;
39493
0
            case special_some:
39494
0
            case special_some | special_TA:
39495
0
                if (JS_ToBoolFree(ctx, res)) {
39496
0
                    ret = JS_TRUE;
39497
0
                    goto done;
39498
0
                }
39499
0
                break;
39500
0
            case special_map:
39501
0
                if (JS_DefinePropertyValueInt64(ctx, ret, k, res,
39502
0
                                                JS_PROP_C_W_E | JS_PROP_THROW) < 0)
39503
0
                    goto exception;
39504
0
                break;
39505
0
            case special_map | special_TA:
39506
0
                if (JS_SetPropertyValue(ctx, ret, JS_NewInt32(ctx, k), res, JS_PROP_THROW) < 0)
39507
0
                    goto exception;
39508
0
                break;
39509
0
            case special_filter:
39510
0
            case special_filter | special_TA:
39511
0
                if (JS_ToBoolFree(ctx, res)) {
39512
0
                    if (JS_DefinePropertyValueInt64(ctx, ret, n++, JS_DupValue(ctx, val),
39513
0
                                                    JS_PROP_C_W_E | JS_PROP_THROW) < 0)
39514
0
                        goto exception;
39515
0
                }
39516
0
                break;
39517
0
            default:
39518
0
                JS_FreeValue(ctx, res);
39519
0
                break;
39520
0
            }
39521
0
            JS_FreeValue(ctx, val);
39522
0
            val = JS_UNDEFINED;
39523
0
        }
39524
0
    }
39525
0
done:
39526
0
    if (special == (special_filter | special_TA)) {
39527
0
        JSValue arr;
39528
0
        args[0] = obj;
39529
0
        args[1] = JS_NewInt32(ctx, n);
39530
0
        arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
39531
0
        if (JS_IsException(arr))
39532
0
            goto exception;
39533
0
        args[0] = ret;
39534
0
        res = JS_Invoke(ctx, arr, JS_ATOM_set, 1, args);
39535
0
        if (check_exception_free(ctx, res))
39536
0
            goto exception;
39537
0
        JS_FreeValue(ctx, ret);
39538
0
        ret = arr;
39539
0
    }
39540
0
    JS_FreeValue(ctx, val);
39541
0
    JS_FreeValue(ctx, obj);
39542
0
    return ret;
39543
39544
0
exception:
39545
0
    JS_FreeValue(ctx, ret);
39546
0
    JS_FreeValue(ctx, val);
39547
0
    JS_FreeValue(ctx, obj);
39548
0
    return JS_EXCEPTION;
39549
0
}
39550
39551
#define special_reduce       0
39552
0
#define special_reduceRight  1
39553
39554
static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val,
39555
                               int argc, JSValueConst *argv, int special)
39556
0
{
39557
0
    JSValue obj, val, index_val, acc, acc1;
39558
0
    JSValueConst args[4];
39559
0
    JSValueConst func;
39560
0
    int64_t len, k, k1;
39561
0
    int present;
39562
39563
0
    acc = JS_UNDEFINED;
39564
0
    val = JS_UNDEFINED;
39565
0
    if (special & special_TA) {
39566
0
        obj = JS_DupValue(ctx, this_val);
39567
0
        len = js_typed_array_get_length_internal(ctx, obj);
39568
0
        if (len < 0)
39569
0
            goto exception;
39570
0
    } else {
39571
0
        obj = JS_ToObject(ctx, this_val);
39572
0
        if (js_get_length64(ctx, &len, obj))
39573
0
            goto exception;
39574
0
    }
39575
0
    func = argv[0];
39576
39577
0
    if (check_function(ctx, func))
39578
0
        goto exception;
39579
39580
0
    k = 0;
39581
0
    if (argc > 1) {
39582
0
        acc = JS_DupValue(ctx, argv[1]);
39583
0
    } else {
39584
0
        for(;;) {
39585
0
            if (k >= len) {
39586
0
                JS_ThrowTypeError(ctx, "empty array");
39587
0
                goto exception;
39588
0
            }
39589
0
            k1 = (special & special_reduceRight) ? len - k - 1 : k;
39590
0
            k++;
39591
0
            if (special & special_TA) {
39592
0
                acc = JS_GetPropertyInt64(ctx, obj, k1);
39593
0
                if (JS_IsException(acc))
39594
0
                    goto exception;
39595
0
                break;
39596
0
            } else {
39597
0
                present = JS_TryGetPropertyInt64(ctx, obj, k1, &acc);
39598
0
                if (present < 0)
39599
0
                    goto exception;
39600
0
                if (present)
39601
0
                    break;
39602
0
            }
39603
0
        }
39604
0
    }
39605
0
    for (; k < len; k++) {
39606
0
        k1 = (special & special_reduceRight) ? len - k - 1 : k;
39607
0
        if (special & special_TA) {
39608
0
            val = JS_GetPropertyInt64(ctx, obj, k1);
39609
0
            if (JS_IsException(val))
39610
0
                goto exception;
39611
0
            present = TRUE;
39612
0
        } else {
39613
0
            present = JS_TryGetPropertyInt64(ctx, obj, k1, &val);
39614
0
            if (present < 0)
39615
0
                goto exception;
39616
0
        }
39617
0
        if (present) {
39618
0
            index_val = JS_NewInt64(ctx, k1);
39619
0
            if (JS_IsException(index_val))
39620
0
                goto exception;
39621
0
            args[0] = acc;
39622
0
            args[1] = val;
39623
0
            args[2] = index_val;
39624
0
            args[3] = obj;
39625
0
            acc1 = JS_Call(ctx, func, JS_UNDEFINED, 4, args);
39626
0
            JS_FreeValue(ctx, index_val);
39627
0
            JS_FreeValue(ctx, val);
39628
0
            val = JS_UNDEFINED;
39629
0
            if (JS_IsException(acc1))
39630
0
                goto exception;
39631
0
            JS_FreeValue(ctx, acc);
39632
0
            acc = acc1;
39633
0
        }
39634
0
    }
39635
0
    JS_FreeValue(ctx, obj);
39636
0
    return acc;
39637
39638
0
exception:
39639
0
    JS_FreeValue(ctx, acc);
39640
0
    JS_FreeValue(ctx, val);
39641
0
    JS_FreeValue(ctx, obj);
39642
0
    return JS_EXCEPTION;
39643
0
}
39644
39645
static JSValue js_array_fill(JSContext *ctx, JSValueConst this_val,
39646
                             int argc, JSValueConst *argv)
39647
0
{
39648
0
    JSValue obj;
39649
0
    int64_t len, start, end;
39650
39651
0
    obj = JS_ToObject(ctx, this_val);
39652
0
    if (js_get_length64(ctx, &len, obj))
39653
0
        goto exception;
39654
39655
0
    start = 0;
39656
0
    if (argc > 1 && !JS_IsUndefined(argv[1])) {
39657
0
        if (JS_ToInt64Clamp(ctx, &start, argv[1], 0, len, len))
39658
0
            goto exception;
39659
0
    }
39660
39661
0
    end = len;
39662
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
39663
0
        if (JS_ToInt64Clamp(ctx, &end, argv[2], 0, len, len))
39664
0
            goto exception;
39665
0
    }
39666
39667
    /* XXX: should special case fast arrays */
39668
0
    while (start < end) {
39669
0
        if (JS_SetPropertyInt64(ctx, obj, start,
39670
0
                                JS_DupValue(ctx, argv[0])) < 0)
39671
0
            goto exception;
39672
0
        start++;
39673
0
    }
39674
0
    return obj;
39675
39676
0
 exception:
39677
0
    JS_FreeValue(ctx, obj);
39678
0
    return JS_EXCEPTION;
39679
0
}
39680
39681
static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val,
39682
                                 int argc, JSValueConst *argv)
39683
0
{
39684
0
    JSValue obj, val;
39685
0
    int64_t len, n;
39686
0
    JSValue *arrp;
39687
0
    uint32_t count;
39688
0
    int res;
39689
39690
0
    obj = JS_ToObject(ctx, this_val);
39691
0
    if (js_get_length64(ctx, &len, obj))
39692
0
        goto exception;
39693
39694
0
    res = FALSE;
39695
0
    if (len > 0) {
39696
0
        n = 0;
39697
0
        if (argc > 1) {
39698
0
            if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
39699
0
                goto exception;
39700
0
        }
39701
0
        if (js_get_fast_array(ctx, obj, &arrp, &count)) {
39702
0
            for (; n < count; n++) {
39703
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),
39704
0
                                  JS_DupValue(ctx, arrp[n]),
39705
0
                                  JS_EQ_SAME_VALUE_ZERO)) {
39706
0
                    res = TRUE;
39707
0
                    goto done;
39708
0
                }
39709
0
            }
39710
0
        }
39711
0
        for (; n < len; n++) {
39712
0
            val = JS_GetPropertyInt64(ctx, obj, n);
39713
0
            if (JS_IsException(val))
39714
0
                goto exception;
39715
0
            if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val,
39716
0
                              JS_EQ_SAME_VALUE_ZERO)) {
39717
0
                res = TRUE;
39718
0
                break;
39719
0
            }
39720
0
        }
39721
0
    }
39722
0
 done:
39723
0
    JS_FreeValue(ctx, obj);
39724
0
    return JS_NewBool(ctx, res);
39725
39726
0
 exception:
39727
0
    JS_FreeValue(ctx, obj);
39728
0
    return JS_EXCEPTION;
39729
0
}
39730
39731
static JSValue js_array_indexOf(JSContext *ctx, JSValueConst this_val,
39732
                                int argc, JSValueConst *argv)
39733
0
{
39734
0
    JSValue obj, val;
39735
0
    int64_t len, n, res;
39736
0
    JSValue *arrp;
39737
0
    uint32_t count;
39738
39739
0
    obj = JS_ToObject(ctx, this_val);
39740
0
    if (js_get_length64(ctx, &len, obj))
39741
0
        goto exception;
39742
39743
0
    res = -1;
39744
0
    if (len > 0) {
39745
0
        n = 0;
39746
0
        if (argc > 1) {
39747
0
            if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
39748
0
                goto exception;
39749
0
        }
39750
0
        if (js_get_fast_array(ctx, obj, &arrp, &count)) {
39751
0
            for (; n < count; n++) {
39752
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),
39753
0
                                  JS_DupValue(ctx, arrp[n]), JS_EQ_STRICT)) {
39754
0
                    res = n;
39755
0
                    goto done;
39756
0
                }
39757
0
            }
39758
0
        }
39759
0
        for (; n < len; n++) {
39760
0
            int present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
39761
0
            if (present < 0)
39762
0
                goto exception;
39763
0
            if (present) {
39764
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
39765
0
                    res = n;
39766
0
                    break;
39767
0
                }
39768
0
            }
39769
0
        }
39770
0
    }
39771
0
 done:
39772
0
    JS_FreeValue(ctx, obj);
39773
0
    return JS_NewInt64(ctx, res);
39774
39775
0
 exception:
39776
0
    JS_FreeValue(ctx, obj);
39777
0
    return JS_EXCEPTION;
39778
0
}
39779
39780
static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val,
39781
                                    int argc, JSValueConst *argv)
39782
0
{
39783
0
    JSValue obj, val;
39784
0
    int64_t len, n, res;
39785
0
    int present;
39786
39787
0
    obj = JS_ToObject(ctx, this_val);
39788
0
    if (js_get_length64(ctx, &len, obj))
39789
0
        goto exception;
39790
39791
0
    res = -1;
39792
0
    if (len > 0) {
39793
0
        n = len - 1;
39794
0
        if (argc > 1) {
39795
0
            if (JS_ToInt64Clamp(ctx, &n, argv[1], -1, len - 1, len))
39796
0
                goto exception;
39797
0
        }
39798
        /* XXX: should special case fast arrays */
39799
0
        for (; n >= 0; n--) {
39800
0
            present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
39801
0
            if (present < 0)
39802
0
                goto exception;
39803
0
            if (present) {
39804
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
39805
0
                    res = n;
39806
0
                    break;
39807
0
                }
39808
0
            }
39809
0
        }
39810
0
    }
39811
0
    JS_FreeValue(ctx, obj);
39812
0
    return JS_NewInt64(ctx, res);
39813
39814
0
 exception:
39815
0
    JS_FreeValue(ctx, obj);
39816
0
    return JS_EXCEPTION;
39817
0
}
39818
39819
enum {
39820
    ArrayFind,
39821
    ArrayFindIndex,
39822
    ArrayFindLast,
39823
    ArrayFindLastIndex,
39824
};
39825
39826
static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
39827
                             int argc, JSValueConst *argv, int mode)
39828
0
{
39829
0
    JSValueConst func, this_arg;
39830
0
    JSValueConst args[3];
39831
0
    JSValue obj, val, index_val, res;
39832
0
    int64_t len, k, end;
39833
0
    int dir;
39834
39835
0
    index_val = JS_UNDEFINED;
39836
0
    val = JS_UNDEFINED;
39837
0
    obj = JS_ToObject(ctx, this_val);
39838
0
    if (js_get_length64(ctx, &len, obj))
39839
0
        goto exception;
39840
39841
0
    func = argv[0];
39842
0
    if (check_function(ctx, func))
39843
0
        goto exception;
39844
39845
0
    this_arg = JS_UNDEFINED;
39846
0
    if (argc > 1)
39847
0
        this_arg = argv[1];
39848
39849
0
    k = 0;
39850
0
    dir = 1;
39851
0
    end = len;
39852
0
    if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {
39853
0
        k = len - 1;
39854
0
        dir = -1;
39855
0
        end = -1;
39856
0
    }
39857
39858
    // TODO(bnoordhuis) add fast path for fast arrays
39859
0
    for(; k != end; k += dir) {
39860
0
        index_val = JS_NewInt64(ctx, k);
39861
0
        if (JS_IsException(index_val))
39862
0
            goto exception;
39863
0
        val = JS_GetPropertyValue(ctx, obj, index_val);
39864
0
        if (JS_IsException(val))
39865
0
            goto exception;
39866
0
        args[0] = val;
39867
0
        args[1] = index_val;
39868
0
        args[2] = this_val;
39869
0
        res = JS_Call(ctx, func, this_arg, 3, args);
39870
0
        if (JS_IsException(res))
39871
0
            goto exception;
39872
0
        if (JS_ToBoolFree(ctx, res)) {
39873
0
            if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {
39874
0
                JS_FreeValue(ctx, val);
39875
0
                JS_FreeValue(ctx, obj);
39876
0
                return index_val;
39877
0
            } else {
39878
0
                JS_FreeValue(ctx, index_val);
39879
0
                JS_FreeValue(ctx, obj);
39880
0
                return val;
39881
0
            }
39882
0
        }
39883
0
        JS_FreeValue(ctx, val);
39884
0
        JS_FreeValue(ctx, index_val);
39885
0
    }
39886
0
    JS_FreeValue(ctx, obj);
39887
0
    if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)
39888
0
        return JS_NewInt32(ctx, -1);
39889
0
    else
39890
0
        return JS_UNDEFINED;
39891
39892
0
exception:
39893
0
    JS_FreeValue(ctx, index_val);
39894
0
    JS_FreeValue(ctx, val);
39895
0
    JS_FreeValue(ctx, obj);
39896
0
    return JS_EXCEPTION;
39897
0
}
39898
39899
static JSValue js_array_toString(JSContext *ctx, JSValueConst this_val,
39900
                                 int argc, JSValueConst *argv)
39901
0
{
39902
0
    JSValue obj, method, ret;
39903
39904
0
    obj = JS_ToObject(ctx, this_val);
39905
0
    if (JS_IsException(obj))
39906
0
        return JS_EXCEPTION;
39907
0
    method = JS_GetProperty(ctx, obj, JS_ATOM_join);
39908
0
    if (JS_IsException(method)) {
39909
0
        ret = JS_EXCEPTION;
39910
0
    } else
39911
0
    if (!JS_IsFunction(ctx, method)) {
39912
        /* Use intrinsic Object.prototype.toString */
39913
0
        JS_FreeValue(ctx, method);
39914
0
        ret = js_object_toString(ctx, obj, 0, NULL);
39915
0
    } else {
39916
0
        ret = JS_CallFree(ctx, method, obj, 0, NULL);
39917
0
    }
39918
0
    JS_FreeValue(ctx, obj);
39919
0
    return ret;
39920
0
}
39921
39922
static JSValue js_array_join(JSContext *ctx, JSValueConst this_val,
39923
                             int argc, JSValueConst *argv, int toLocaleString)
39924
0
{
39925
0
    JSValue obj, sep = JS_UNDEFINED, el;
39926
0
    StringBuffer b_s, *b = &b_s;
39927
0
    JSString *p = NULL;
39928
0
    int64_t i, n;
39929
0
    int c;
39930
39931
0
    obj = JS_ToObject(ctx, this_val);
39932
0
    if (js_get_length64(ctx, &n, obj))
39933
0
        goto exception;
39934
39935
0
    c = ',';    /* default separator */
39936
0
    if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
39937
0
        sep = JS_ToString(ctx, argv[0]);
39938
0
        if (JS_IsException(sep))
39939
0
            goto exception;
39940
0
        p = JS_VALUE_GET_STRING(sep);
39941
0
        if (p->len == 1 && !p->is_wide_char)
39942
0
            c = p->u.str8[0];
39943
0
        else
39944
0
            c = -1;
39945
0
    }
39946
0
    string_buffer_init(ctx, b, 0);
39947
39948
0
    for(i = 0; i < n; i++) {
39949
0
        if (i > 0) {
39950
0
            if (c >= 0) {
39951
0
                string_buffer_putc8(b, c);
39952
0
            } else {
39953
0
                string_buffer_concat(b, p, 0, p->len);
39954
0
            }
39955
0
        }
39956
0
        el = JS_GetPropertyUint32(ctx, obj, i);
39957
0
        if (JS_IsException(el))
39958
0
            goto fail;
39959
0
        if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
39960
0
            if (toLocaleString) {
39961
0
                el = JS_ToLocaleStringFree(ctx, el);
39962
0
            }
39963
0
            if (string_buffer_concat_value_free(b, el))
39964
0
                goto fail;
39965
0
        }
39966
0
    }
39967
0
    JS_FreeValue(ctx, sep);
39968
0
    JS_FreeValue(ctx, obj);
39969
0
    return string_buffer_end(b);
39970
39971
0
fail:
39972
0
    string_buffer_free(b);
39973
0
    JS_FreeValue(ctx, sep);
39974
0
exception:
39975
0
    JS_FreeValue(ctx, obj);
39976
0
    return JS_EXCEPTION;
39977
0
}
39978
39979
static JSValue js_array_pop(JSContext *ctx, JSValueConst this_val,
39980
                            int argc, JSValueConst *argv, int shift)
39981
0
{
39982
0
    JSValue obj, res = JS_UNDEFINED;
39983
0
    int64_t len, newLen;
39984
0
    JSValue *arrp;
39985
0
    uint32_t count32;
39986
39987
0
    obj = JS_ToObject(ctx, this_val);
39988
0
    if (js_get_length64(ctx, &len, obj))
39989
0
        goto exception;
39990
0
    newLen = 0;
39991
0
    if (len > 0) {
39992
0
        newLen = len - 1;
39993
        /* Special case fast arrays */
39994
0
        if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
39995
0
            JSObject *p = JS_VALUE_GET_OBJ(obj);
39996
0
            if (shift) {
39997
0
                res = arrp[0];
39998
0
                memmove(arrp, arrp + 1, (count32 - 1) * sizeof(*arrp));
39999
0
                p->u.array.count--;
40000
0
            } else {
40001
0
                res = arrp[count32 - 1];
40002
0
                p->u.array.count--;
40003
0
            }
40004
0
        } else {
40005
0
            if (shift) {
40006
0
                res = JS_GetPropertyInt64(ctx, obj, 0);
40007
0
                if (JS_IsException(res))
40008
0
                    goto exception;
40009
0
                if (JS_CopySubArray(ctx, obj, 0, 1, len - 1, +1))
40010
0
                    goto exception;
40011
0
            } else {
40012
0
                res = JS_GetPropertyInt64(ctx, obj, newLen);
40013
0
                if (JS_IsException(res))
40014
0
                    goto exception;
40015
0
            }
40016
0
            if (JS_DeletePropertyInt64(ctx, obj, newLen, JS_PROP_THROW) < 0)
40017
0
                goto exception;
40018
0
        }
40019
0
    }
40020
0
    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
40021
0
        goto exception;
40022
40023
0
    JS_FreeValue(ctx, obj);
40024
0
    return res;
40025
40026
0
 exception:
40027
0
    JS_FreeValue(ctx, res);
40028
0
    JS_FreeValue(ctx, obj);
40029
0
    return JS_EXCEPTION;
40030
0
}
40031
40032
static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
40033
                             int argc, JSValueConst *argv, int unshift)
40034
0
{
40035
0
    JSValue obj;
40036
0
    int i;
40037
0
    int64_t len, from, newLen;
40038
40039
0
    obj = JS_ToObject(ctx, this_val);
40040
0
    if (js_get_length64(ctx, &len, obj))
40041
0
        goto exception;
40042
0
    newLen = len + argc;
40043
0
    if (newLen > MAX_SAFE_INTEGER) {
40044
0
        JS_ThrowTypeError(ctx, "Array loo long");
40045
0
        goto exception;
40046
0
    }
40047
0
    from = len;
40048
0
    if (unshift && argc > 0) {
40049
0
        if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
40050
0
            goto exception;
40051
0
        from = 0;
40052
0
    }
40053
0
    for(i = 0; i < argc; i++) {
40054
0
        if (JS_SetPropertyInt64(ctx, obj, from + i,
40055
0
                                JS_DupValue(ctx, argv[i])) < 0)
40056
0
            goto exception;
40057
0
    }
40058
0
    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
40059
0
        goto exception;
40060
40061
0
    JS_FreeValue(ctx, obj);
40062
0
    return JS_NewInt64(ctx, newLen);
40063
40064
0
 exception:
40065
0
    JS_FreeValue(ctx, obj);
40066
0
    return JS_EXCEPTION;
40067
0
}
40068
40069
static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val,
40070
                                int argc, JSValueConst *argv)
40071
0
{
40072
0
    JSValue obj, lval, hval;
40073
0
    JSValue *arrp;
40074
0
    int64_t len, l, h;
40075
0
    int l_present, h_present;
40076
0
    uint32_t count32;
40077
40078
0
    lval = JS_UNDEFINED;
40079
0
    obj = JS_ToObject(ctx, this_val);
40080
0
    if (js_get_length64(ctx, &len, obj))
40081
0
        goto exception;
40082
40083
    /* Special case fast arrays */
40084
0
    if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
40085
0
        uint32_t ll, hh;
40086
40087
0
        if (count32 > 1) {
40088
0
            for (ll = 0, hh = count32 - 1; ll < hh; ll++, hh--) {
40089
0
                lval = arrp[ll];
40090
0
                arrp[ll] = arrp[hh];
40091
0
                arrp[hh] = lval;
40092
0
            }
40093
0
        }
40094
0
        return obj;
40095
0
    }
40096
40097
0
    for (l = 0, h = len - 1; l < h; l++, h--) {
40098
0
        l_present = JS_TryGetPropertyInt64(ctx, obj, l, &lval);
40099
0
        if (l_present < 0)
40100
0
            goto exception;
40101
0
        h_present = JS_TryGetPropertyInt64(ctx, obj, h, &hval);
40102
0
        if (h_present < 0)
40103
0
            goto exception;
40104
0
        if (h_present) {
40105
0
            if (JS_SetPropertyInt64(ctx, obj, l, hval) < 0)
40106
0
                goto exception;
40107
40108
0
            if (l_present) {
40109
0
                if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
40110
0
                    lval = JS_UNDEFINED;
40111
0
                    goto exception;
40112
0
                }
40113
0
                lval = JS_UNDEFINED;
40114
0
            } else {
40115
0
                if (JS_DeletePropertyInt64(ctx, obj, h, JS_PROP_THROW) < 0)
40116
0
                    goto exception;
40117
0
            }
40118
0
        } else {
40119
0
            if (l_present) {
40120
0
                if (JS_DeletePropertyInt64(ctx, obj, l, JS_PROP_THROW) < 0)
40121
0
                    goto exception;
40122
0
                if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
40123
0
                    lval = JS_UNDEFINED;
40124
0
                    goto exception;
40125
0
                }
40126
0
                lval = JS_UNDEFINED;
40127
0
            }
40128
0
        }
40129
0
    }
40130
0
    return obj;
40131
40132
0
 exception:
40133
0
    JS_FreeValue(ctx, lval);
40134
0
    JS_FreeValue(ctx, obj);
40135
0
    return JS_EXCEPTION;
40136
0
}
40137
40138
// Note: a.toReversed() is a.slice().reverse() with the twist that a.slice()
40139
// leaves holes in sparse arrays intact whereas a.toReversed() replaces them
40140
// with undefined, thus in effect creating a dense array.
40141
// Does not use Array[@@species], always returns a base Array.
40142
static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val,
40143
                                   int argc, JSValueConst *argv)
40144
0
{
40145
0
    JSValue arr, obj, ret, *arrp, *pval;
40146
0
    JSObject *p;
40147
0
    int64_t i, len;
40148
0
    uint32_t count32;
40149
40150
0
    ret = JS_EXCEPTION;
40151
0
    arr = JS_UNDEFINED;
40152
0
    obj = JS_ToObject(ctx, this_val);
40153
0
    if (js_get_length64(ctx, &len, obj))
40154
0
        goto exception;
40155
40156
0
    arr = js_allocate_fast_array(ctx, len);
40157
0
    if (JS_IsException(arr))
40158
0
        goto exception;
40159
40160
0
    if (len > 0) {
40161
0
        p = JS_VALUE_GET_OBJ(arr);
40162
40163
0
        i = len - 1;
40164
0
        pval = p->u.array.u.values;
40165
0
        if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
40166
0
            for (; i >= 0; i--, pval++)
40167
0
                *pval = JS_DupValue(ctx, arrp[i]);
40168
0
        } else {
40169
            // Query order is observable; test262 expects descending order.
40170
0
            for (; i >= 0; i--, pval++) {
40171
0
                if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
40172
                    // Exception; initialize remaining elements.
40173
0
                    for (; i >= 0; i--, pval++)
40174
0
                        *pval = JS_UNDEFINED;
40175
0
                    goto exception;
40176
0
                }
40177
0
            }
40178
0
        }
40179
40180
0
        if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)
40181
0
            goto exception;
40182
0
    }
40183
40184
0
    ret = arr;
40185
0
    arr = JS_UNDEFINED;
40186
40187
0
exception:
40188
0
    JS_FreeValue(ctx, arr);
40189
0
    JS_FreeValue(ctx, obj);
40190
0
    return ret;
40191
0
}
40192
40193
static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
40194
                              int argc, JSValueConst *argv, int splice)
40195
0
{
40196
0
    JSValue obj, arr, val, len_val;
40197
0
    int64_t len, start, k, final, n, count, del_count, new_len;
40198
0
    int kPresent;
40199
0
    JSValue *arrp;
40200
0
    uint32_t count32, i, item_count;
40201
40202
0
    arr = JS_UNDEFINED;
40203
0
    obj = JS_ToObject(ctx, this_val);
40204
0
    if (js_get_length64(ctx, &len, obj))
40205
0
        goto exception;
40206
40207
0
    if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
40208
0
        goto exception;
40209
40210
0
    if (splice) {
40211
0
        if (argc == 0) {
40212
0
            item_count = 0;
40213
0
            del_count = 0;
40214
0
        } else
40215
0
        if (argc == 1) {
40216
0
            item_count = 0;
40217
0
            del_count = len - start;
40218
0
        } else {
40219
0
            item_count = argc - 2;
40220
0
            if (JS_ToInt64Clamp(ctx, &del_count, argv[1], 0, len - start, 0))
40221
0
                goto exception;
40222
0
        }
40223
0
        if (len + item_count - del_count > MAX_SAFE_INTEGER) {
40224
0
            JS_ThrowTypeError(ctx, "Array loo long");
40225
0
            goto exception;
40226
0
        }
40227
0
        count = del_count;
40228
0
    } else {
40229
0
        item_count = 0; /* avoid warning */
40230
0
        final = len;
40231
0
        if (!JS_IsUndefined(argv[1])) {
40232
0
            if (JS_ToInt64Clamp(ctx, &final, argv[1], 0, len, len))
40233
0
                goto exception;
40234
0
        }
40235
0
        count = max_int64(final - start, 0);
40236
0
    }
40237
0
    len_val = JS_NewInt64(ctx, count);
40238
0
    arr = JS_ArraySpeciesCreate(ctx, obj, len_val);
40239
0
    JS_FreeValue(ctx, len_val);
40240
0
    if (JS_IsException(arr))
40241
0
        goto exception;
40242
40243
0
    k = start;
40244
0
    final = start + count;
40245
0
    n = 0;
40246
    /* The fast array test on arr ensures that
40247
       JS_CreateDataPropertyUint32() won't modify obj in case arr is
40248
       an exotic object */
40249
    /* Special case fast arrays */
40250
0
    if (js_get_fast_array(ctx, obj, &arrp, &count32) &&
40251
0
        js_is_fast_array(ctx, arr)) {
40252
        /* XXX: should share code with fast array constructor */
40253
0
        for (; k < final && k < count32; k++, n++) {
40254
0
            if (JS_CreateDataPropertyUint32(ctx, arr, n, JS_DupValue(ctx, arrp[k]), JS_PROP_THROW) < 0)
40255
0
                goto exception;
40256
0
        }
40257
0
    }
40258
    /* Copy the remaining elements if any (handle case of inherited properties) */
40259
0
    for (; k < final; k++, n++) {
40260
0
        kPresent = JS_TryGetPropertyInt64(ctx, obj, k, &val);
40261
0
        if (kPresent < 0)
40262
0
            goto exception;
40263
0
        if (kPresent) {
40264
0
            if (JS_CreateDataPropertyUint32(ctx, arr, n, val, JS_PROP_THROW) < 0)
40265
0
                goto exception;
40266
0
        }
40267
0
    }
40268
0
    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
40269
0
        goto exception;
40270
40271
0
    if (splice) {
40272
0
        new_len = len + item_count - del_count;
40273
0
        if (item_count != del_count) {
40274
0
            if (JS_CopySubArray(ctx, obj, start + item_count,
40275
0
                                start + del_count, len - (start + del_count),
40276
0
                                item_count <= del_count ? +1 : -1) < 0)
40277
0
                goto exception;
40278
40279
0
            for (k = len; k-- > new_len; ) {
40280
0
                if (JS_DeletePropertyInt64(ctx, obj, k, JS_PROP_THROW) < 0)
40281
0
                    goto exception;
40282
0
            }
40283
0
        }
40284
0
        for (i = 0; i < item_count; i++) {
40285
0
            if (JS_SetPropertyInt64(ctx, obj, start + i, JS_DupValue(ctx, argv[i + 2])) < 0)
40286
0
                goto exception;
40287
0
        }
40288
0
        if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, new_len)) < 0)
40289
0
            goto exception;
40290
0
    }
40291
0
    JS_FreeValue(ctx, obj);
40292
0
    return arr;
40293
40294
0
 exception:
40295
0
    JS_FreeValue(ctx, obj);
40296
0
    JS_FreeValue(ctx, arr);
40297
0
    return JS_EXCEPTION;
40298
0
}
40299
40300
static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val,
40301
                                  int argc, JSValueConst *argv)
40302
0
{
40303
0
    JSValue arr, obj, ret, *arrp, *pval, *last;
40304
0
    JSObject *p;
40305
0
    int64_t i, j, len, newlen, start, add, del;
40306
0
    uint32_t count32;
40307
40308
0
    pval = NULL;
40309
0
    last = NULL;
40310
0
    ret = JS_EXCEPTION;
40311
0
    arr = JS_UNDEFINED;
40312
40313
0
    obj = JS_ToObject(ctx, this_val);
40314
0
    if (js_get_length64(ctx, &len, obj))
40315
0
        goto exception;
40316
40317
0
    start = 0;
40318
0
    if (argc > 0)
40319
0
        if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
40320
0
            goto exception;
40321
40322
0
    del = 0;
40323
0
    if (argc > 0)
40324
0
        del = len - start;
40325
0
    if (argc > 1)
40326
0
        if (JS_ToInt64Clamp(ctx, &del, argv[1], 0, del, 0))
40327
0
            goto exception;
40328
40329
0
    add = 0;
40330
0
    if (argc > 2)
40331
0
        add = argc - 2;
40332
40333
0
    newlen = len + add - del;
40334
0
    if (newlen > MAX_SAFE_INTEGER) {
40335
0
        JS_ThrowTypeError(ctx, "invalid array length");
40336
0
        goto exception;
40337
0
    }
40338
40339
0
    arr = js_allocate_fast_array(ctx, newlen);
40340
0
    if (JS_IsException(arr))
40341
0
        goto exception;
40342
40343
0
    if (newlen <= 0)
40344
0
        goto done;
40345
40346
0
    p = JS_VALUE_GET_OBJ(arr);
40347
0
    pval = &p->u.array.u.values[0];
40348
0
    last = &p->u.array.u.values[newlen];
40349
40350
0
    if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
40351
0
        for (i = 0; i < start; i++, pval++)
40352
0
            *pval = JS_DupValue(ctx, arrp[i]);
40353
0
        for (j = 0; j < add; j++, pval++)
40354
0
            *pval = JS_DupValue(ctx, argv[2 + j]);
40355
0
        for (i += del; i < len; i++, pval++)
40356
0
            *pval = JS_DupValue(ctx, arrp[i]);
40357
0
    } else {
40358
0
        for (i = 0; i < start; i++, pval++)
40359
0
            if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
40360
0
                goto exception;
40361
0
        for (j = 0; j < add; j++, pval++)
40362
0
            *pval = JS_DupValue(ctx, argv[2 + j]);
40363
0
        for (i += del; i < len; i++, pval++)
40364
0
            if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
40365
0
                goto exception;
40366
0
    }
40367
40368
0
    assert(pval == last);
40369
40370
0
    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, newlen)) < 0)
40371
0
        goto exception;
40372
40373
0
done:
40374
0
    ret = arr;
40375
0
    arr = JS_UNDEFINED;
40376
40377
0
exception:
40378
0
    while (pval != last)
40379
0
        *pval++ = JS_UNDEFINED;
40380
40381
0
    JS_FreeValue(ctx, arr);
40382
0
    JS_FreeValue(ctx, obj);
40383
0
    return ret;
40384
0
}
40385
40386
static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val,
40387
                                   int argc, JSValueConst *argv)
40388
0
{
40389
0
    JSValue obj;
40390
0
    int64_t len, from, to, final, count;
40391
40392
0
    obj = JS_ToObject(ctx, this_val);
40393
0
    if (js_get_length64(ctx, &len, obj))
40394
0
        goto exception;
40395
40396
0
    if (JS_ToInt64Clamp(ctx, &to, argv[0], 0, len, len))
40397
0
        goto exception;
40398
40399
0
    if (JS_ToInt64Clamp(ctx, &from, argv[1], 0, len, len))
40400
0
        goto exception;
40401
40402
0
    final = len;
40403
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
40404
0
        if (JS_ToInt64Clamp(ctx, &final, argv[2], 0, len, len))
40405
0
            goto exception;
40406
0
    }
40407
40408
0
    count = min_int64(final - from, len - to);
40409
40410
0
    if (JS_CopySubArray(ctx, obj, to, from, count,
40411
0
                        (from < to && to < from + count) ? -1 : +1))
40412
0
        goto exception;
40413
40414
0
    return obj;
40415
40416
0
 exception:
40417
0
    JS_FreeValue(ctx, obj);
40418
0
    return JS_EXCEPTION;
40419
0
}
40420
40421
static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
40422
                                   JSValueConst source, int64_t sourceLen,
40423
                                   int64_t targetIndex, int depth,
40424
                                   JSValueConst mapperFunction,
40425
                                   JSValueConst thisArg)
40426
0
{
40427
0
    JSValue element;
40428
0
    int64_t sourceIndex, elementLen;
40429
0
    int present, is_array;
40430
40431
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
40432
0
        JS_ThrowStackOverflow(ctx);
40433
0
        return -1;
40434
0
    }
40435
40436
0
    for (sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
40437
0
        present = JS_TryGetPropertyInt64(ctx, source, sourceIndex, &element);
40438
0
        if (present < 0)
40439
0
            return -1;
40440
0
        if (!present)
40441
0
            continue;
40442
0
        if (!JS_IsUndefined(mapperFunction)) {
40443
0
            JSValueConst args[3] = { element, JS_NewInt64(ctx, sourceIndex), source };
40444
0
            element = JS_Call(ctx, mapperFunction, thisArg, 3, args);
40445
0
            JS_FreeValue(ctx, (JSValue)args[0]);
40446
0
            JS_FreeValue(ctx, (JSValue)args[1]);
40447
0
            if (JS_IsException(element))
40448
0
                return -1;
40449
0
        }
40450
0
        if (depth > 0) {
40451
0
            is_array = JS_IsArray(ctx, element);
40452
0
            if (is_array < 0)
40453
0
                goto fail;
40454
0
            if (is_array) {
40455
0
                if (js_get_length64(ctx, &elementLen, element) < 0)
40456
0
                    goto fail;
40457
0
                targetIndex = JS_FlattenIntoArray(ctx, target, element,
40458
0
                                                  elementLen, targetIndex,
40459
0
                                                  depth - 1,
40460
0
                                                  JS_UNDEFINED, JS_UNDEFINED);
40461
0
                if (targetIndex < 0)
40462
0
                    goto fail;
40463
0
                JS_FreeValue(ctx, element);
40464
0
                continue;
40465
0
            }
40466
0
        }
40467
0
        if (targetIndex >= MAX_SAFE_INTEGER) {
40468
0
            JS_ThrowTypeError(ctx, "Array too long");
40469
0
            goto fail;
40470
0
        }
40471
0
        if (JS_DefinePropertyValueInt64(ctx, target, targetIndex, element,
40472
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
40473
0
            return -1;
40474
0
        targetIndex++;
40475
0
    }
40476
0
    return targetIndex;
40477
40478
0
fail:
40479
0
    JS_FreeValue(ctx, element);
40480
0
    return -1;
40481
0
}
40482
40483
static JSValue js_array_flatten(JSContext *ctx, JSValueConst this_val,
40484
                                int argc, JSValueConst *argv, int map)
40485
0
{
40486
0
    JSValue obj, arr;
40487
0
    JSValueConst mapperFunction, thisArg;
40488
0
    int64_t sourceLen;
40489
0
    int depthNum;
40490
40491
0
    arr = JS_UNDEFINED;
40492
0
    obj = JS_ToObject(ctx, this_val);
40493
0
    if (js_get_length64(ctx, &sourceLen, obj))
40494
0
        goto exception;
40495
40496
0
    depthNum = 1;
40497
0
    mapperFunction = JS_UNDEFINED;
40498
0
    thisArg = JS_UNDEFINED;
40499
0
    if (map) {
40500
0
        mapperFunction = argv[0];
40501
0
        if (argc > 1) {
40502
0
            thisArg = argv[1];
40503
0
        }
40504
0
        if (check_function(ctx, mapperFunction))
40505
0
            goto exception;
40506
0
    } else {
40507
0
        if (argc > 0 && !JS_IsUndefined(argv[0])) {
40508
0
            if (JS_ToInt32Sat(ctx, &depthNum, argv[0]) < 0)
40509
0
                goto exception;
40510
0
        }
40511
0
    }
40512
0
    arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
40513
0
    if (JS_IsException(arr))
40514
0
        goto exception;
40515
0
    if (JS_FlattenIntoArray(ctx, arr, obj, sourceLen, 0, depthNum,
40516
0
                            mapperFunction, thisArg) < 0)
40517
0
        goto exception;
40518
0
    JS_FreeValue(ctx, obj);
40519
0
    return arr;
40520
40521
0
exception:
40522
0
    JS_FreeValue(ctx, obj);
40523
0
    JS_FreeValue(ctx, arr);
40524
0
    return JS_EXCEPTION;
40525
0
}
40526
40527
/* Array sort */
40528
40529
typedef struct ValueSlot {
40530
    JSValue val;
40531
    JSString *str;
40532
    int64_t pos;
40533
} ValueSlot;
40534
40535
struct array_sort_context {
40536
    JSContext *ctx;
40537
    int exception;
40538
    int has_method;
40539
    JSValueConst method;
40540
};
40541
40542
0
static int js_array_cmp_generic(const void *a, const void *b, void *opaque) {
40543
0
    struct array_sort_context *psc = opaque;
40544
0
    JSContext *ctx = psc->ctx;
40545
0
    JSValueConst argv[2];
40546
0
    JSValue res;
40547
0
    ValueSlot *ap = (ValueSlot *)(void *)a;
40548
0
    ValueSlot *bp = (ValueSlot *)(void *)b;
40549
0
    int cmp;
40550
40551
0
    if (psc->exception)
40552
0
        return 0;
40553
40554
0
    if (psc->has_method) {
40555
        /* custom sort function is specified as returning 0 for identical
40556
         * objects: avoid method call overhead.
40557
         */
40558
0
        if (!memcmp(&ap->val, &bp->val, sizeof(ap->val)))
40559
0
            goto cmp_same;
40560
0
        argv[0] = ap->val;
40561
0
        argv[1] = bp->val;
40562
0
        res = JS_Call(ctx, psc->method, JS_UNDEFINED, 2, argv);
40563
0
        if (JS_IsException(res))
40564
0
            goto exception;
40565
0
        if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
40566
0
            int val = JS_VALUE_GET_INT(res);
40567
0
            cmp = (val > 0) - (val < 0);
40568
0
        } else {
40569
0
            double val;
40570
0
            if (JS_ToFloat64Free(ctx, &val, res) < 0)
40571
0
                goto exception;
40572
0
            cmp = (val > 0) - (val < 0);
40573
0
        }
40574
0
    } else {
40575
        /* Not supposed to bypass ToString even for identical objects as
40576
         * tested in test262/test/built-ins/Array/prototype/sort/bug_596_1.js
40577
         */
40578
0
        if (!ap->str) {
40579
0
            JSValue str = JS_ToString(ctx, ap->val);
40580
0
            if (JS_IsException(str))
40581
0
                goto exception;
40582
0
            ap->str = JS_VALUE_GET_STRING(str);
40583
0
        }
40584
0
        if (!bp->str) {
40585
0
            JSValue str = JS_ToString(ctx, bp->val);
40586
0
            if (JS_IsException(str))
40587
0
                goto exception;
40588
0
            bp->str = JS_VALUE_GET_STRING(str);
40589
0
        }
40590
0
        cmp = js_string_compare(ctx, ap->str, bp->str);
40591
0
    }
40592
0
    if (cmp != 0)
40593
0
        return cmp;
40594
0
cmp_same:
40595
    /* make sort stable: compare array offsets */
40596
0
    return (ap->pos > bp->pos) - (ap->pos < bp->pos);
40597
40598
0
exception:
40599
0
    psc->exception = 1;
40600
0
    return 0;
40601
0
}
40602
40603
static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val,
40604
                             int argc, JSValueConst *argv)
40605
0
{
40606
0
    struct array_sort_context asc = { ctx, 0, 0, argv[0] };
40607
0
    JSValue obj = JS_UNDEFINED;
40608
0
    ValueSlot *array = NULL;
40609
0
    size_t array_size = 0, pos = 0, n = 0;
40610
0
    int64_t i, len, undefined_count = 0;
40611
0
    int present;
40612
40613
0
    if (!JS_IsUndefined(asc.method)) {
40614
0
        if (check_function(ctx, asc.method))
40615
0
            goto exception;
40616
0
        asc.has_method = 1;
40617
0
    }
40618
0
    obj = JS_ToObject(ctx, this_val);
40619
0
    if (js_get_length64(ctx, &len, obj))
40620
0
        goto exception;
40621
40622
    /* XXX: should special case fast arrays */
40623
0
    for (i = 0; i < len; i++) {
40624
0
        if (pos >= array_size) {
40625
0
            size_t new_size, slack;
40626
0
            ValueSlot *new_array;
40627
0
            new_size = (array_size + (array_size >> 1) + 31) & ~15;
40628
0
            new_array = js_realloc2(ctx, array, new_size * sizeof(*array), &slack);
40629
0
            if (new_array == NULL)
40630
0
                goto exception;
40631
0
            new_size += slack / sizeof(*new_array);
40632
0
            array = new_array;
40633
0
            array_size = new_size;
40634
0
        }
40635
0
        present = JS_TryGetPropertyInt64(ctx, obj, i, &array[pos].val);
40636
0
        if (present < 0)
40637
0
            goto exception;
40638
0
        if (present == 0)
40639
0
            continue;
40640
0
        if (JS_IsUndefined(array[pos].val)) {
40641
0
            undefined_count++;
40642
0
            continue;
40643
0
        }
40644
0
        array[pos].str = NULL;
40645
0
        array[pos].pos = i;
40646
0
        pos++;
40647
0
    }
40648
0
    rqsort(array, pos, sizeof(*array), js_array_cmp_generic, &asc);
40649
0
    if (asc.exception)
40650
0
        goto exception;
40651
40652
    /* XXX: should special case fast arrays */
40653
0
    while (n < pos) {
40654
0
        if (array[n].str)
40655
0
            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
40656
0
        if (array[n].pos == n) {
40657
0
            JS_FreeValue(ctx, array[n].val);
40658
0
        } else {
40659
0
            if (JS_SetPropertyInt64(ctx, obj, n, array[n].val) < 0) {
40660
0
                n++;
40661
0
                goto exception;
40662
0
            }
40663
0
        }
40664
0
        n++;
40665
0
    }
40666
0
    js_free(ctx, array);
40667
0
    for (i = n; undefined_count-- > 0; i++) {
40668
0
        if (JS_SetPropertyInt64(ctx, obj, i, JS_UNDEFINED) < 0)
40669
0
            goto fail;
40670
0
    }
40671
0
    for (; i < len; i++) {
40672
0
        if (JS_DeletePropertyInt64(ctx, obj, i, JS_PROP_THROW) < 0)
40673
0
            goto fail;
40674
0
    }
40675
0
    return obj;
40676
40677
0
exception:
40678
0
    for (; n < pos; n++) {
40679
0
        JS_FreeValue(ctx, array[n].val);
40680
0
        if (array[n].str)
40681
0
            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
40682
0
    }
40683
0
    js_free(ctx, array);
40684
0
fail:
40685
0
    JS_FreeValue(ctx, obj);
40686
0
    return JS_EXCEPTION;
40687
0
}
40688
40689
// Note: a.toSorted() is a.slice().sort() with the twist that a.slice()
40690
// leaves holes in sparse arrays intact whereas a.toSorted() replaces them
40691
// with undefined, thus in effect creating a dense array.
40692
// Does not use Array[@@species], always returns a base Array.
40693
static JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val,
40694
                                 int argc, JSValueConst *argv)
40695
0
{
40696
0
    JSValue arr, obj, ret, *arrp, *pval;
40697
0
    JSObject *p;
40698
0
    int64_t i, len;
40699
0
    uint32_t count32;
40700
0
    int ok;
40701
40702
0
    ok = JS_IsUndefined(argv[0]) || JS_IsFunction(ctx, argv[0]);
40703
0
    if (!ok)
40704
0
        return JS_ThrowTypeError(ctx, "not a function");
40705
40706
0
    ret = JS_EXCEPTION;
40707
0
    arr = JS_UNDEFINED;
40708
0
    obj = JS_ToObject(ctx, this_val);
40709
0
    if (js_get_length64(ctx, &len, obj))
40710
0
        goto exception;
40711
40712
0
    arr = js_allocate_fast_array(ctx, len);
40713
0
    if (JS_IsException(arr))
40714
0
        goto exception;
40715
40716
0
    if (len > 0) {
40717
0
        p = JS_VALUE_GET_OBJ(arr);
40718
0
        i = 0;
40719
0
        pval = p->u.array.u.values;
40720
0
        if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
40721
0
            for (; i < len; i++, pval++)
40722
0
                *pval = JS_DupValue(ctx, arrp[i]);
40723
0
        } else {
40724
0
            for (; i < len; i++, pval++) {
40725
0
                if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
40726
0
                    for (; i < len; i++, pval++)
40727
0
                        *pval = JS_UNDEFINED;
40728
0
                    goto exception;
40729
0
                }
40730
0
            }
40731
0
        }
40732
40733
0
        if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)
40734
0
            goto exception;
40735
0
    }
40736
40737
0
    ret = js_array_sort(ctx, arr, argc, argv);
40738
0
    if (JS_IsException(ret))
40739
0
        goto exception;
40740
0
    JS_FreeValue(ctx, ret);
40741
40742
0
    ret = arr;
40743
0
    arr = JS_UNDEFINED;
40744
40745
0
exception:
40746
0
    JS_FreeValue(ctx, arr);
40747
0
    JS_FreeValue(ctx, obj);
40748
0
    return ret;
40749
0
}
40750
40751
typedef struct JSArrayIteratorData {
40752
    JSValue obj;
40753
    JSIteratorKindEnum kind;
40754
    uint32_t idx;
40755
} JSArrayIteratorData;
40756
40757
static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val)
40758
0
{
40759
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
40760
0
    JSArrayIteratorData *it = p->u.array_iterator_data;
40761
0
    if (it) {
40762
0
        JS_FreeValueRT(rt, it->obj);
40763
0
        js_free_rt(rt, it);
40764
0
    }
40765
0
}
40766
40767
static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
40768
                                   JS_MarkFunc *mark_func)
40769
0
{
40770
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
40771
0
    JSArrayIteratorData *it = p->u.array_iterator_data;
40772
0
    if (it) {
40773
0
        JS_MarkValue(rt, it->obj, mark_func);
40774
0
    }
40775
0
}
40776
40777
static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab)
40778
0
{
40779
0
    JSValue obj;
40780
0
    int i;
40781
40782
0
    obj = JS_NewArray(ctx);
40783
0
    if (JS_IsException(obj))
40784
0
        return JS_EXCEPTION;
40785
0
    for(i = 0; i < len; i++) {
40786
0
        if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, tab[i]), 0) < 0) {
40787
0
            JS_FreeValue(ctx, obj);
40788
0
            return JS_EXCEPTION;
40789
0
        }
40790
0
    }
40791
0
    return obj;
40792
0
}
40793
40794
static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
40795
                                        int argc, JSValueConst *argv, int magic)
40796
0
{
40797
0
    JSValue enum_obj, arr;
40798
0
    JSArrayIteratorData *it;
40799
0
    JSIteratorKindEnum kind;
40800
0
    int class_id;
40801
40802
0
    kind = magic & 3;
40803
0
    if (magic & 4) {
40804
        /* string iterator case */
40805
0
        arr = JS_ToStringCheckObject(ctx, this_val);
40806
0
        class_id = JS_CLASS_STRING_ITERATOR;
40807
0
    } else {
40808
0
        arr = JS_ToObject(ctx, this_val);
40809
0
        class_id = JS_CLASS_ARRAY_ITERATOR;
40810
0
    }
40811
0
    if (JS_IsException(arr))
40812
0
        goto fail;
40813
0
    enum_obj = JS_NewObjectClass(ctx, class_id);
40814
0
    if (JS_IsException(enum_obj))
40815
0
        goto fail;
40816
0
    it = js_malloc(ctx, sizeof(*it));
40817
0
    if (!it)
40818
0
        goto fail1;
40819
0
    it->obj = arr;
40820
0
    it->kind = kind;
40821
0
    it->idx = 0;
40822
0
    JS_SetOpaque(enum_obj, it);
40823
0
    return enum_obj;
40824
0
 fail1:
40825
0
    JS_FreeValue(ctx, enum_obj);
40826
0
 fail:
40827
0
    JS_FreeValue(ctx, arr);
40828
0
    return JS_EXCEPTION;
40829
0
}
40830
40831
static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
40832
                                      int argc, JSValueConst *argv,
40833
                                      BOOL *pdone, int magic)
40834
0
{
40835
0
    JSArrayIteratorData *it;
40836
0
    uint32_t len, idx;
40837
0
    JSValue val, obj;
40838
0
    JSObject *p;
40839
40840
0
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_ITERATOR);
40841
0
    if (!it)
40842
0
        goto fail1;
40843
0
    if (JS_IsUndefined(it->obj))
40844
0
        goto done;
40845
0
    p = JS_VALUE_GET_OBJ(it->obj);
40846
0
    if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
40847
0
        p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
40848
0
        if (typed_array_is_detached(ctx, p)) {
40849
0
            JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
40850
0
            goto fail1;
40851
0
        }
40852
0
        len = p->u.array.count;
40853
0
    } else {
40854
0
        if (js_get_length32(ctx, &len, it->obj)) {
40855
0
        fail1:
40856
0
            *pdone = FALSE;
40857
0
            return JS_EXCEPTION;
40858
0
        }
40859
0
    }
40860
0
    idx = it->idx;
40861
0
    if (idx >= len) {
40862
0
        JS_FreeValue(ctx, it->obj);
40863
0
        it->obj = JS_UNDEFINED;
40864
0
    done:
40865
0
        *pdone = TRUE;
40866
0
        return JS_UNDEFINED;
40867
0
    }
40868
0
    it->idx = idx + 1;
40869
0
    *pdone = FALSE;
40870
0
    if (it->kind == JS_ITERATOR_KIND_KEY) {
40871
0
        return JS_NewUint32(ctx, idx);
40872
0
    } else {
40873
0
        val = JS_GetPropertyUint32(ctx, it->obj, idx);
40874
0
        if (JS_IsException(val))
40875
0
            return JS_EXCEPTION;
40876
0
        if (it->kind == JS_ITERATOR_KIND_VALUE) {
40877
0
            return val;
40878
0
        } else {
40879
0
            JSValueConst args[2];
40880
0
            JSValue num;
40881
0
            num = JS_NewUint32(ctx, idx);
40882
0
            args[0] = num;
40883
0
            args[1] = val;
40884
0
            obj = js_create_array(ctx, 2, args);
40885
0
            JS_FreeValue(ctx, val);
40886
0
            JS_FreeValue(ctx, num);
40887
0
            return obj;
40888
0
        }
40889
0
    }
40890
0
}
40891
40892
static JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val,
40893
                                          int argc, JSValueConst *argv)
40894
0
{
40895
0
    return JS_DupValue(ctx, this_val);
40896
0
}
40897
40898
static const JSCFunctionListEntry js_iterator_proto_funcs[] = {
40899
    JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator ),
40900
};
40901
40902
static const JSCFunctionListEntry js_array_proto_funcs[] = {
40903
    JS_CFUNC_DEF("at", 1, js_array_at ),
40904
    JS_CFUNC_DEF("with", 2, js_array_with ),
40905
    JS_CFUNC_DEF("concat", 1, js_array_concat ),
40906
    JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every ),
40907
    JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some ),
40908
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach ),
40909
    JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map ),
40910
    JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter ),
40911
    JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ),
40912
    JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ),
40913
    JS_CFUNC_DEF("fill", 1, js_array_fill ),
40914
    JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, ArrayFind ),
40915
    JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, ArrayFindIndex ),
40916
    JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, ArrayFindLast ),
40917
    JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, ArrayFindLastIndex ),
40918
    JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ),
40919
    JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ),
40920
    JS_CFUNC_DEF("includes", 1, js_array_includes ),
40921
    JS_CFUNC_MAGIC_DEF("join", 1, js_array_join, 0 ),
40922
    JS_CFUNC_DEF("toString", 0, js_array_toString ),
40923
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_array_join, 1 ),
40924
    JS_CFUNC_MAGIC_DEF("pop", 0, js_array_pop, 0 ),
40925
    JS_CFUNC_MAGIC_DEF("push", 1, js_array_push, 0 ),
40926
    JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1 ),
40927
    JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ),
40928
    JS_CFUNC_DEF("reverse", 0, js_array_reverse ),
40929
    JS_CFUNC_DEF("toReversed", 0, js_array_toReversed ),
40930
    JS_CFUNC_DEF("sort", 1, js_array_sort ),
40931
    JS_CFUNC_DEF("toSorted", 1, js_array_toSorted ),
40932
    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ),
40933
    JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ),
40934
    JS_CFUNC_DEF("toSpliced", 2, js_array_toSpliced ),
40935
    JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ),
40936
    JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ),
40937
    JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ),
40938
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ),
40939
    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
40940
    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ),
40941
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
40942
};
40943
40944
static const JSCFunctionListEntry js_array_iterator_proto_funcs[] = {
40945
    JS_ITERATOR_NEXT_DEF("next", 0, js_array_iterator_next, 0 ),
40946
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Array Iterator", JS_PROP_CONFIGURABLE ),
40947
};
40948
40949
/* Number */
40950
40951
static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
40952
                                     int argc, JSValueConst *argv)
40953
0
{
40954
0
    JSValue val, obj;
40955
0
    if (argc == 0) {
40956
0
        val = JS_NewInt32(ctx, 0);
40957
0
    } else {
40958
0
        val = JS_ToNumeric(ctx, argv[0]);
40959
0
        if (JS_IsException(val))
40960
0
            return val;
40961
0
        switch(JS_VALUE_GET_TAG(val)) {
40962
0
        case JS_TAG_BIG_INT:
40963
0
#ifdef CONFIG_BIGNUM
40964
0
        case JS_TAG_BIG_FLOAT:
40965
0
#endif
40966
0
            {
40967
0
                JSBigFloat *p = JS_VALUE_GET_PTR(val);
40968
0
                double d;
40969
0
                bf_get_float64(&p->num, &d, BF_RNDN);
40970
0
                JS_FreeValue(ctx, val);
40971
0
                val = __JS_NewFloat64(ctx, d);
40972
0
            }
40973
0
            break;
40974
0
#ifdef CONFIG_BIGNUM
40975
0
        case JS_TAG_BIG_DECIMAL:
40976
0
            val = JS_ToStringFree(ctx, val);
40977
0
            if (JS_IsException(val))
40978
0
                return val;
40979
0
            val = JS_ToNumberFree(ctx, val);
40980
0
            if (JS_IsException(val))
40981
0
                return val;
40982
0
            break;
40983
0
#endif
40984
0
        default:
40985
0
            break;
40986
0
        }
40987
0
    }
40988
0
    if (!JS_IsUndefined(new_target)) {
40989
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);
40990
0
        if (!JS_IsException(obj))
40991
0
            JS_SetObjectData(ctx, obj, val);
40992
0
        return obj;
40993
0
    } else {
40994
0
        return val;
40995
0
    }
40996
0
}
40997
40998
#if 0
40999
static JSValue js_number___toInteger(JSContext *ctx, JSValueConst this_val,
41000
                                     int argc, JSValueConst *argv)
41001
{
41002
    return JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[0]));
41003
}
41004
41005
static JSValue js_number___toLength(JSContext *ctx, JSValueConst this_val,
41006
                                    int argc, JSValueConst *argv)
41007
{
41008
    int64_t v;
41009
    if (JS_ToLengthFree(ctx, &v, JS_DupValue(ctx, argv[0])))
41010
        return JS_EXCEPTION;
41011
    return JS_NewInt64(ctx, v);
41012
}
41013
#endif
41014
41015
static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,
41016
                               int argc, JSValueConst *argv)
41017
0
{
41018
0
    if (!JS_IsNumber(argv[0]))
41019
0
        return JS_FALSE;
41020
0
    return js_global_isNaN(ctx, this_val, argc, argv);
41021
0
}
41022
41023
static JSValue js_number_isFinite(JSContext *ctx, JSValueConst this_val,
41024
                                  int argc, JSValueConst *argv)
41025
0
{
41026
0
    if (!JS_IsNumber(argv[0]))
41027
0
        return JS_FALSE;
41028
0
    return js_global_isFinite(ctx, this_val, argc, argv);
41029
0
}
41030
41031
static JSValue js_number_isInteger(JSContext *ctx, JSValueConst this_val,
41032
                                   int argc, JSValueConst *argv)
41033
0
{
41034
0
    int ret;
41035
0
    ret = JS_NumberIsInteger(ctx, argv[0]);
41036
0
    if (ret < 0)
41037
0
        return JS_EXCEPTION;
41038
0
    else
41039
0
        return JS_NewBool(ctx, ret);
41040
0
}
41041
41042
static JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val,
41043
                                       int argc, JSValueConst *argv)
41044
0
{
41045
0
    double d;
41046
0
    if (!JS_IsNumber(argv[0]))
41047
0
        return JS_FALSE;
41048
0
    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
41049
0
        return JS_EXCEPTION;
41050
0
    return JS_NewBool(ctx, is_safe_integer(d));
41051
0
}
41052
41053
static const JSCFunctionListEntry js_number_funcs[] = {
41054
    /* global ParseInt and parseFloat should be defined already or delayed */
41055
    JS_ALIAS_BASE_DEF("parseInt", "parseInt", 0 ),
41056
    JS_ALIAS_BASE_DEF("parseFloat", "parseFloat", 0 ),
41057
    JS_CFUNC_DEF("isNaN", 1, js_number_isNaN ),
41058
    JS_CFUNC_DEF("isFinite", 1, js_number_isFinite ),
41059
    JS_CFUNC_DEF("isInteger", 1, js_number_isInteger ),
41060
    JS_CFUNC_DEF("isSafeInteger", 1, js_number_isSafeInteger ),
41061
    JS_PROP_DOUBLE_DEF("MAX_VALUE", 1.7976931348623157e+308, 0 ),
41062
    JS_PROP_DOUBLE_DEF("MIN_VALUE", 5e-324, 0 ),
41063
    JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
41064
    JS_PROP_DOUBLE_DEF("NEGATIVE_INFINITY", -INFINITY, 0 ),
41065
    JS_PROP_DOUBLE_DEF("POSITIVE_INFINITY", INFINITY, 0 ),
41066
    JS_PROP_DOUBLE_DEF("EPSILON", 2.220446049250313e-16, 0 ), /* ES6 */
41067
    JS_PROP_DOUBLE_DEF("MAX_SAFE_INTEGER", 9007199254740991.0, 0 ), /* ES6 */
41068
    JS_PROP_DOUBLE_DEF("MIN_SAFE_INTEGER", -9007199254740991.0, 0 ), /* ES6 */
41069
    //JS_CFUNC_DEF("__toInteger", 1, js_number___toInteger ),
41070
    //JS_CFUNC_DEF("__toLength", 1, js_number___toLength ),
41071
};
41072
41073
static JSValue js_thisNumberValue(JSContext *ctx, JSValueConst this_val)
41074
0
{
41075
0
    if (JS_IsNumber(this_val))
41076
0
        return JS_DupValue(ctx, this_val);
41077
41078
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
41079
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
41080
0
        if (p->class_id == JS_CLASS_NUMBER) {
41081
0
            if (JS_IsNumber(p->u.object_data))
41082
0
                return JS_DupValue(ctx, p->u.object_data);
41083
0
        }
41084
0
    }
41085
0
    return JS_ThrowTypeError(ctx, "not a number");
41086
0
}
41087
41088
static JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val,
41089
                                 int argc, JSValueConst *argv)
41090
0
{
41091
0
    return js_thisNumberValue(ctx, this_val);
41092
0
}
41093
41094
static int js_get_radix(JSContext *ctx, JSValueConst val)
41095
0
{
41096
0
    int radix;
41097
0
    if (JS_ToInt32Sat(ctx, &radix, val))
41098
0
        return -1;
41099
0
    if (radix < 2 || radix > 36) {
41100
0
        JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
41101
0
        return -1;
41102
0
    }
41103
0
    return radix;
41104
0
}
41105
41106
static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
41107
                                  int argc, JSValueConst *argv, int magic)
41108
0
{
41109
0
    JSValue val;
41110
0
    int base;
41111
0
    double d;
41112
41113
0
    val = js_thisNumberValue(ctx, this_val);
41114
0
    if (JS_IsException(val))
41115
0
        return val;
41116
0
    if (magic || JS_IsUndefined(argv[0])) {
41117
0
        base = 10;
41118
0
    } else {
41119
0
        base = js_get_radix(ctx, argv[0]);
41120
0
        if (base < 0)
41121
0
            goto fail;
41122
0
    }
41123
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
41124
0
        char buf1[70], *ptr;
41125
0
        ptr = i64toa(buf1 + sizeof(buf1), JS_VALUE_GET_INT(val), base);
41126
0
        return JS_NewString(ctx, ptr);
41127
0
    }
41128
0
    if (JS_ToFloat64Free(ctx, &d, val))
41129
0
        return JS_EXCEPTION;
41130
0
    if (base != 10 && isfinite(d)) {
41131
0
        return js_dtoa_radix(ctx, d, base);
41132
0
    }
41133
0
    return js_dtoa(ctx, d, base, 0, JS_DTOA_VAR_FORMAT);
41134
0
 fail:
41135
0
    JS_FreeValue(ctx, val);
41136
0
    return JS_EXCEPTION;
41137
0
}
41138
41139
static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
41140
                                 int argc, JSValueConst *argv)
41141
0
{
41142
0
    JSValue val;
41143
0
    int f;
41144
0
    double d;
41145
41146
0
    val = js_thisNumberValue(ctx, this_val);
41147
0
    if (JS_IsException(val))
41148
0
        return val;
41149
0
    if (JS_ToFloat64Free(ctx, &d, val))
41150
0
        return JS_EXCEPTION;
41151
0
    if (JS_ToInt32Sat(ctx, &f, argv[0]))
41152
0
        return JS_EXCEPTION;
41153
0
    if (f < 0 || f > 100)
41154
0
        return JS_ThrowRangeError(ctx, "invalid number of digits");
41155
0
    if (fabs(d) >= 1e21) {
41156
0
        return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d));
41157
0
    } else {
41158
0
        return js_dtoa(ctx, d, 10, f, JS_DTOA_FRAC_FORMAT);
41159
0
    }
41160
0
}
41161
41162
static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
41163
                                       int argc, JSValueConst *argv)
41164
0
{
41165
0
    JSValue val;
41166
0
    int f, flags;
41167
0
    double d;
41168
41169
0
    val = js_thisNumberValue(ctx, this_val);
41170
0
    if (JS_IsException(val))
41171
0
        return val;
41172
0
    if (JS_ToFloat64Free(ctx, &d, val))
41173
0
        return JS_EXCEPTION;
41174
0
    if (JS_ToInt32Sat(ctx, &f, argv[0]))
41175
0
        return JS_EXCEPTION;
41176
0
    if (!isfinite(d)) {
41177
0
        return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
41178
0
    }
41179
0
    if (JS_IsUndefined(argv[0])) {
41180
0
        flags = 0;
41181
0
        f = 0;
41182
0
    } else {
41183
0
        if (f < 0 || f > 100)
41184
0
            return JS_ThrowRangeError(ctx, "invalid number of digits");
41185
0
        f++;
41186
0
        flags = JS_DTOA_FIXED_FORMAT;
41187
0
    }
41188
0
    return js_dtoa(ctx, d, 10, f, flags | JS_DTOA_FORCE_EXP);
41189
0
}
41190
41191
static JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,
41192
                                     int argc, JSValueConst *argv)
41193
0
{
41194
0
    JSValue val;
41195
0
    int p;
41196
0
    double d;
41197
41198
0
    val = js_thisNumberValue(ctx, this_val);
41199
0
    if (JS_IsException(val))
41200
0
        return val;
41201
0
    if (JS_ToFloat64Free(ctx, &d, val))
41202
0
        return JS_EXCEPTION;
41203
0
    if (JS_IsUndefined(argv[0]))
41204
0
        goto to_string;
41205
0
    if (JS_ToInt32Sat(ctx, &p, argv[0]))
41206
0
        return JS_EXCEPTION;
41207
0
    if (!isfinite(d)) {
41208
0
    to_string:
41209
0
        return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
41210
0
    }
41211
0
    if (p < 1 || p > 100)
41212
0
        return JS_ThrowRangeError(ctx, "invalid number of digits");
41213
0
    return js_dtoa(ctx, d, 10, p, JS_DTOA_FIXED_FORMAT);
41214
0
}
41215
41216
static const JSCFunctionListEntry js_number_proto_funcs[] = {
41217
    JS_CFUNC_DEF("toExponential", 1, js_number_toExponential ),
41218
    JS_CFUNC_DEF("toFixed", 1, js_number_toFixed ),
41219
    JS_CFUNC_DEF("toPrecision", 1, js_number_toPrecision ),
41220
    JS_CFUNC_MAGIC_DEF("toString", 1, js_number_toString, 0 ),
41221
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_number_toString, 1 ),
41222
    JS_CFUNC_DEF("valueOf", 0, js_number_valueOf ),
41223
};
41224
41225
static JSValue js_parseInt(JSContext *ctx, JSValueConst this_val,
41226
                           int argc, JSValueConst *argv)
41227
0
{
41228
0
    const char *str, *p;
41229
0
    int radix, flags;
41230
0
    JSValue ret;
41231
41232
0
    str = JS_ToCString(ctx, argv[0]);
41233
0
    if (!str)
41234
0
        return JS_EXCEPTION;
41235
0
    if (JS_ToInt32(ctx, &radix, argv[1])) {
41236
0
        JS_FreeCString(ctx, str);
41237
0
        return JS_EXCEPTION;
41238
0
    }
41239
0
    if (radix != 0 && (radix < 2 || radix > 36)) {
41240
0
        ret = JS_NAN;
41241
0
    } else {
41242
0
        p = str;
41243
0
        p += skip_spaces(p);
41244
0
        flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN;
41245
0
        ret = js_atof(ctx, p, NULL, radix, flags);
41246
0
    }
41247
0
    JS_FreeCString(ctx, str);
41248
0
    return ret;
41249
0
}
41250
41251
static JSValue js_parseFloat(JSContext *ctx, JSValueConst this_val,
41252
                             int argc, JSValueConst *argv)
41253
0
{
41254
0
    const char *str, *p;
41255
0
    JSValue ret;
41256
41257
0
    str = JS_ToCString(ctx, argv[0]);
41258
0
    if (!str)
41259
0
        return JS_EXCEPTION;
41260
0
    p = str;
41261
0
    p += skip_spaces(p);
41262
0
    ret = js_atof(ctx, p, NULL, 10, 0);
41263
0
    JS_FreeCString(ctx, str);
41264
0
    return ret;
41265
0
}
41266
41267
/* Boolean */
41268
static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst new_target,
41269
                                     int argc, JSValueConst *argv)
41270
0
{
41271
0
    JSValue val, obj;
41272
0
    val = JS_NewBool(ctx, JS_ToBool(ctx, argv[0]));
41273
0
    if (!JS_IsUndefined(new_target)) {
41274
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_BOOLEAN);
41275
0
        if (!JS_IsException(obj))
41276
0
            JS_SetObjectData(ctx, obj, val);
41277
0
        return obj;
41278
0
    } else {
41279
0
        return val;
41280
0
    }
41281
0
}
41282
41283
static JSValue js_thisBooleanValue(JSContext *ctx, JSValueConst this_val)
41284
0
{
41285
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_BOOL)
41286
0
        return JS_DupValue(ctx, this_val);
41287
41288
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
41289
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
41290
0
        if (p->class_id == JS_CLASS_BOOLEAN) {
41291
0
            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_BOOL)
41292
0
                return p->u.object_data;
41293
0
        }
41294
0
    }
41295
0
    return JS_ThrowTypeError(ctx, "not a boolean");
41296
0
}
41297
41298
static JSValue js_boolean_toString(JSContext *ctx, JSValueConst this_val,
41299
                                   int argc, JSValueConst *argv)
41300
0
{
41301
0
    JSValue val = js_thisBooleanValue(ctx, this_val);
41302
0
    if (JS_IsException(val))
41303
0
        return val;
41304
0
    return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
41305
0
                       JS_ATOM_true : JS_ATOM_false);
41306
0
}
41307
41308
static JSValue js_boolean_valueOf(JSContext *ctx, JSValueConst this_val,
41309
                                  int argc, JSValueConst *argv)
41310
0
{
41311
0
    return js_thisBooleanValue(ctx, this_val);
41312
0
}
41313
41314
static const JSCFunctionListEntry js_boolean_proto_funcs[] = {
41315
    JS_CFUNC_DEF("toString", 0, js_boolean_toString ),
41316
    JS_CFUNC_DEF("valueOf", 0, js_boolean_valueOf ),
41317
};
41318
41319
/* String */
41320
41321
static int js_string_get_own_property(JSContext *ctx,
41322
                                      JSPropertyDescriptor *desc,
41323
                                      JSValueConst obj, JSAtom prop)
41324
0
{
41325
0
    JSObject *p;
41326
0
    JSString *p1;
41327
0
    uint32_t idx, ch;
41328
41329
    /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
41330
0
    if (__JS_AtomIsTaggedInt(prop)) {
41331
0
        p = JS_VALUE_GET_OBJ(obj);
41332
0
        if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
41333
0
            p1 = JS_VALUE_GET_STRING(p->u.object_data);
41334
0
            idx = __JS_AtomToUInt32(prop);
41335
0
            if (idx < p1->len) {
41336
0
                if (desc) {
41337
0
                    ch = string_get(p1, idx);
41338
0
                    desc->flags = JS_PROP_ENUMERABLE;
41339
0
                    desc->value = js_new_string_char(ctx, ch);
41340
0
                    desc->getter = JS_UNDEFINED;
41341
0
                    desc->setter = JS_UNDEFINED;
41342
0
                }
41343
0
                return TRUE;
41344
0
            }
41345
0
        }
41346
0
    }
41347
0
    return FALSE;
41348
0
}
41349
41350
static int js_string_define_own_property(JSContext *ctx,
41351
                                         JSValueConst this_obj,
41352
                                         JSAtom prop, JSValueConst val,
41353
                                         JSValueConst getter,
41354
                                         JSValueConst setter, int flags)
41355
195
{
41356
195
    uint32_t idx;
41357
195
    JSObject *p;
41358
195
    JSString *p1, *p2;
41359
41360
195
    if (__JS_AtomIsTaggedInt(prop)) {
41361
0
        idx = __JS_AtomToUInt32(prop);
41362
0
        p = JS_VALUE_GET_OBJ(this_obj);
41363
0
        if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING)
41364
0
            goto def;
41365
0
        p1 = JS_VALUE_GET_STRING(p->u.object_data);
41366
0
        if (idx >= p1->len)
41367
0
            goto def;
41368
0
        if (!check_define_prop_flags(JS_PROP_ENUMERABLE, flags))
41369
0
            goto fail;
41370
        /* check that the same value is configured */
41371
0
        if (flags & JS_PROP_HAS_VALUE) {
41372
0
            if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
41373
0
                goto fail;
41374
0
            p2 = JS_VALUE_GET_STRING(val);
41375
0
            if (p2->len != 1)
41376
0
                goto fail;
41377
0
            if (string_get(p1, idx) != string_get(p2, 0)) {
41378
0
            fail:
41379
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
41380
0
            }
41381
0
        }
41382
0
        return TRUE;
41383
195
    } else {
41384
195
    def:
41385
195
        return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
41386
195
                                 flags | JS_PROP_NO_EXOTIC);
41387
195
    }
41388
195
}
41389
41390
static int js_string_delete_property(JSContext *ctx,
41391
                                     JSValueConst obj, JSAtom prop)
41392
0
{
41393
0
    uint32_t idx;
41394
41395
0
    if (__JS_AtomIsTaggedInt(prop)) {
41396
0
        idx = __JS_AtomToUInt32(prop);
41397
0
        if (idx < js_string_obj_get_length(ctx, obj)) {
41398
0
            return FALSE;
41399
0
        }
41400
0
    }
41401
0
    return TRUE;
41402
0
}
41403
41404
static const JSClassExoticMethods js_string_exotic_methods = {
41405
    .get_own_property = js_string_get_own_property,
41406
    .define_own_property = js_string_define_own_property,
41407
    .delete_property = js_string_delete_property,
41408
};
41409
41410
static JSValue js_string_constructor(JSContext *ctx, JSValueConst new_target,
41411
                                     int argc, JSValueConst *argv)
41412
0
{
41413
0
    JSValue val, obj;
41414
0
    if (argc == 0) {
41415
0
        val = JS_AtomToString(ctx, JS_ATOM_empty_string);
41416
0
    } else {
41417
0
        if (JS_IsUndefined(new_target) && JS_IsSymbol(argv[0])) {
41418
0
            JSAtomStruct *p = JS_VALUE_GET_PTR(argv[0]);
41419
0
            val = JS_ConcatString3(ctx, "Symbol(", JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p)), ")");
41420
0
        } else {
41421
0
            val = JS_ToString(ctx, argv[0]);
41422
0
        }
41423
0
        if (JS_IsException(val))
41424
0
            return val;
41425
0
    }
41426
0
    if (!JS_IsUndefined(new_target)) {
41427
0
        JSString *p1 = JS_VALUE_GET_STRING(val);
41428
41429
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING);
41430
0
        if (!JS_IsException(obj)) {
41431
0
            JS_SetObjectData(ctx, obj, val);
41432
0
            JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
41433
0
        }
41434
0
        return obj;
41435
0
    } else {
41436
0
        return val;
41437
0
    }
41438
0
}
41439
41440
static JSValue js_thisStringValue(JSContext *ctx, JSValueConst this_val)
41441
0
{
41442
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING)
41443
0
        return JS_DupValue(ctx, this_val);
41444
41445
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
41446
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
41447
0
        if (p->class_id == JS_CLASS_STRING) {
41448
0
            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING)
41449
0
                return JS_DupValue(ctx, p->u.object_data);
41450
0
        }
41451
0
    }
41452
0
    return JS_ThrowTypeError(ctx, "not a string");
41453
0
}
41454
41455
static JSValue js_string_fromCharCode(JSContext *ctx, JSValueConst this_val,
41456
                                      int argc, JSValueConst *argv)
41457
0
{
41458
0
    int i;
41459
0
    StringBuffer b_s, *b = &b_s;
41460
41461
0
    string_buffer_init(ctx, b, argc);
41462
41463
0
    for(i = 0; i < argc; i++) {
41464
0
        int32_t c;
41465
0
        if (JS_ToInt32(ctx, &c, argv[i]) || string_buffer_putc16(b, c & 0xffff)) {
41466
0
            string_buffer_free(b);
41467
0
            return JS_EXCEPTION;
41468
0
        }
41469
0
    }
41470
0
    return string_buffer_end(b);
41471
0
}
41472
41473
static JSValue js_string_fromCodePoint(JSContext *ctx, JSValueConst this_val,
41474
                                       int argc, JSValueConst *argv)
41475
0
{
41476
0
    double d;
41477
0
    int i, c;
41478
0
    StringBuffer b_s, *b = &b_s;
41479
41480
    /* XXX: could pre-compute string length if all arguments are JS_TAG_INT */
41481
41482
0
    if (string_buffer_init(ctx, b, argc))
41483
0
        goto fail;
41484
0
    for(i = 0; i < argc; i++) {
41485
0
        if (JS_VALUE_GET_TAG(argv[i]) == JS_TAG_INT) {
41486
0
            c = JS_VALUE_GET_INT(argv[i]);
41487
0
            if (c < 0 || c > 0x10ffff)
41488
0
                goto range_error;
41489
0
        } else {
41490
0
            if (JS_ToFloat64(ctx, &d, argv[i]))
41491
0
                goto fail;
41492
0
            if (isnan(d) || d < 0 || d > 0x10ffff || (c = (int)d) != d)
41493
0
                goto range_error;
41494
0
        }
41495
0
        if (string_buffer_putc(b, c))
41496
0
            goto fail;
41497
0
    }
41498
0
    return string_buffer_end(b);
41499
41500
0
 range_error:
41501
0
    JS_ThrowRangeError(ctx, "invalid code point");
41502
0
 fail:
41503
0
    string_buffer_free(b);
41504
0
    return JS_EXCEPTION;
41505
0
}
41506
41507
static JSValue js_string_raw(JSContext *ctx, JSValueConst this_val,
41508
                             int argc, JSValueConst *argv)
41509
0
{
41510
    // raw(temp,...a)
41511
0
    JSValue cooked, val, raw;
41512
0
    StringBuffer b_s, *b = &b_s;
41513
0
    int64_t i, n;
41514
41515
0
    string_buffer_init(ctx, b, 0);
41516
0
    raw = JS_UNDEFINED;
41517
0
    cooked = JS_ToObject(ctx, argv[0]);
41518
0
    if (JS_IsException(cooked))
41519
0
        goto exception;
41520
0
    raw = JS_ToObjectFree(ctx, JS_GetProperty(ctx, cooked, JS_ATOM_raw));
41521
0
    if (JS_IsException(raw))
41522
0
        goto exception;
41523
0
    if (js_get_length64(ctx, &n, raw) < 0)
41524
0
        goto exception;
41525
41526
0
    for (i = 0; i < n; i++) {
41527
0
        val = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, raw, i));
41528
0
        if (JS_IsException(val))
41529
0
            goto exception;
41530
0
        string_buffer_concat_value_free(b, val);
41531
0
        if (i < n - 1 && i + 1 < argc) {
41532
0
            if (string_buffer_concat_value(b, argv[i + 1]))
41533
0
                goto exception;
41534
0
        }
41535
0
    }
41536
0
    JS_FreeValue(ctx, cooked);
41537
0
    JS_FreeValue(ctx, raw);
41538
0
    return string_buffer_end(b);
41539
41540
0
exception:
41541
0
    JS_FreeValue(ctx, cooked);
41542
0
    JS_FreeValue(ctx, raw);
41543
0
    string_buffer_free(b);
41544
0
    return JS_EXCEPTION;
41545
0
}
41546
41547
/* only used in test262 */
41548
JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
41549
                                 int argc, JSValueConst *argv)
41550
0
{
41551
0
    uint32_t start, end, i, n;
41552
0
    StringBuffer b_s, *b = &b_s;
41553
41554
0
    if (JS_ToUint32(ctx, &start, argv[0]) ||
41555
0
        JS_ToUint32(ctx, &end, argv[1]))
41556
0
        return JS_EXCEPTION;
41557
0
    end = min_uint32(end, 0x10ffff + 1);
41558
41559
0
    if (start > end) {
41560
0
        start = end;
41561
0
    }
41562
0
    n = end - start;
41563
0
    if (end > 0x10000) {
41564
0
        n += end - max_uint32(start, 0x10000);
41565
0
    }
41566
0
    if (string_buffer_init2(ctx, b, n, end >= 0x100))
41567
0
        return JS_EXCEPTION;
41568
0
    for(i = start; i < end; i++) {
41569
0
        string_buffer_putc(b, i);
41570
0
    }
41571
0
    return string_buffer_end(b);
41572
0
}
41573
41574
#if 0
41575
static JSValue js_string___isSpace(JSContext *ctx, JSValueConst this_val,
41576
                                   int argc, JSValueConst *argv)
41577
{
41578
    int c;
41579
    if (JS_ToInt32(ctx, &c, argv[0]))
41580
        return JS_EXCEPTION;
41581
    return JS_NewBool(ctx, lre_is_space(c));
41582
}
41583
#endif
41584
41585
static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val,
41586
                                     int argc, JSValueConst *argv)
41587
0
{
41588
0
    JSValue val, ret;
41589
0
    JSString *p;
41590
0
    int idx, c;
41591
41592
0
    val = JS_ToStringCheckObject(ctx, this_val);
41593
0
    if (JS_IsException(val))
41594
0
        return val;
41595
0
    p = JS_VALUE_GET_STRING(val);
41596
0
    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
41597
0
        JS_FreeValue(ctx, val);
41598
0
        return JS_EXCEPTION;
41599
0
    }
41600
0
    if (idx < 0 || idx >= p->len) {
41601
0
        ret = JS_NAN;
41602
0
    } else {
41603
0
        c = string_get(p, idx);
41604
0
        ret = JS_NewInt32(ctx, c);
41605
0
    }
41606
0
    JS_FreeValue(ctx, val);
41607
0
    return ret;
41608
0
}
41609
41610
static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val,
41611
                                int argc, JSValueConst *argv, int is_at)
41612
0
{
41613
0
    JSValue val, ret;
41614
0
    JSString *p;
41615
0
    int idx, c;
41616
41617
0
    val = JS_ToStringCheckObject(ctx, this_val);
41618
0
    if (JS_IsException(val))
41619
0
        return val;
41620
0
    p = JS_VALUE_GET_STRING(val);
41621
0
    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
41622
0
        JS_FreeValue(ctx, val);
41623
0
        return JS_EXCEPTION;
41624
0
    }
41625
0
    if (idx < 0 && is_at)
41626
0
        idx += p->len;
41627
0
    if (idx < 0 || idx >= p->len) {
41628
0
        if (is_at)
41629
0
            ret = JS_UNDEFINED;
41630
0
        else
41631
0
            ret = js_new_string8(ctx, NULL, 0);
41632
0
    } else {
41633
0
        c = string_get(p, idx);
41634
0
        ret = js_new_string_char(ctx, c);
41635
0
    }
41636
0
    JS_FreeValue(ctx, val);
41637
0
    return ret;
41638
0
}
41639
41640
static JSValue js_string_codePointAt(JSContext *ctx, JSValueConst this_val,
41641
                                     int argc, JSValueConst *argv)
41642
0
{
41643
0
    JSValue val, ret;
41644
0
    JSString *p;
41645
0
    int idx, c;
41646
41647
0
    val = JS_ToStringCheckObject(ctx, this_val);
41648
0
    if (JS_IsException(val))
41649
0
        return val;
41650
0
    p = JS_VALUE_GET_STRING(val);
41651
0
    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
41652
0
        JS_FreeValue(ctx, val);
41653
0
        return JS_EXCEPTION;
41654
0
    }
41655
0
    if (idx < 0 || idx >= p->len) {
41656
0
        ret = JS_UNDEFINED;
41657
0
    } else {
41658
0
        c = string_getc(p, &idx);
41659
0
        ret = JS_NewInt32(ctx, c);
41660
0
    }
41661
0
    JS_FreeValue(ctx, val);
41662
0
    return ret;
41663
0
}
41664
41665
static JSValue js_string_concat(JSContext *ctx, JSValueConst this_val,
41666
                                int argc, JSValueConst *argv)
41667
0
{
41668
0
    JSValue r;
41669
0
    int i;
41670
41671
    /* XXX: Use more efficient method */
41672
    /* XXX: This method is OK if r has a single refcount */
41673
    /* XXX: should use string_buffer? */
41674
0
    r = JS_ToStringCheckObject(ctx, this_val);
41675
0
    for (i = 0; i < argc; i++) {
41676
0
        if (JS_IsException(r))
41677
0
            break;
41678
0
        r = JS_ConcatString(ctx, r, JS_DupValue(ctx, argv[i]));
41679
0
    }
41680
0
    return r;
41681
0
}
41682
41683
static int string_cmp(JSString *p1, JSString *p2, int x1, int x2, int len)
41684
0
{
41685
0
    int i, c1, c2;
41686
0
    for (i = 0; i < len; i++) {
41687
0
        if ((c1 = string_get(p1, x1 + i)) != (c2 = string_get(p2, x2 + i)))
41688
0
            return c1 - c2;
41689
0
    }
41690
0
    return 0;
41691
0
}
41692
41693
static int string_indexof_char(JSString *p, int c, int from)
41694
0
{
41695
    /* assuming 0 <= from <= p->len */
41696
0
    int i, len = p->len;
41697
0
    if (p->is_wide_char) {
41698
0
        for (i = from; i < len; i++) {
41699
0
            if (p->u.str16[i] == c)
41700
0
                return i;
41701
0
        }
41702
0
    } else {
41703
0
        if ((c & ~0xff) == 0) {
41704
0
            for (i = from; i < len; i++) {
41705
0
                if (p->u.str8[i] == (uint8_t)c)
41706
0
                    return i;
41707
0
            }
41708
0
        }
41709
0
    }
41710
0
    return -1;
41711
0
}
41712
41713
static int string_indexof(JSString *p1, JSString *p2, int from)
41714
0
{
41715
    /* assuming 0 <= from <= p1->len */
41716
0
    int c, i, j, len1 = p1->len, len2 = p2->len;
41717
0
    if (len2 == 0)
41718
0
        return from;
41719
0
    for (i = from, c = string_get(p2, 0); i + len2 <= len1; i = j + 1) {
41720
0
        j = string_indexof_char(p1, c, i);
41721
0
        if (j < 0 || j + len2 > len1)
41722
0
            break;
41723
0
        if (!string_cmp(p1, p2, j + 1, 1, len2 - 1))
41724
0
            return j;
41725
0
    }
41726
0
    return -1;
41727
0
}
41728
41729
static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode)
41730
0
{
41731
0
    if (!unicode || index >= p->len || !p->is_wide_char) {
41732
0
        index++;
41733
0
    } else {
41734
0
        int index32 = (int)index;
41735
0
        string_getc(p, &index32);
41736
0
        index = index32;
41737
0
    }
41738
0
    return index;
41739
0
}
41740
41741
/* return the position of the first invalid character in the string or
41742
   -1 if none */
41743
static int js_string_find_invalid_codepoint(JSString *p)
41744
0
{
41745
0
    int i;
41746
0
    if (!p->is_wide_char)
41747
0
        return -1;
41748
0
    for(i = 0; i < p->len; i++) {
41749
0
        uint32_t c = p->u.str16[i];
41750
0
        if (is_surrogate(c)) {
41751
0
            if (is_hi_surrogate(c) && (i + 1) < p->len
41752
0
            &&  is_lo_surrogate(p->u.str16[i + 1])) {
41753
0
                i++;
41754
0
            } else {
41755
0
                return i;
41756
0
            }
41757
0
        }
41758
0
    }
41759
0
    return -1;
41760
0
}
41761
41762
static JSValue js_string_isWellFormed(JSContext *ctx, JSValueConst this_val,
41763
                                      int argc, JSValueConst *argv)
41764
0
{
41765
0
    JSValue str;
41766
0
    JSString *p;
41767
0
    BOOL ret;
41768
41769
0
    str = JS_ToStringCheckObject(ctx, this_val);
41770
0
    if (JS_IsException(str))
41771
0
        return JS_EXCEPTION;
41772
0
    p = JS_VALUE_GET_STRING(str);
41773
0
    ret = (js_string_find_invalid_codepoint(p) < 0);
41774
0
    JS_FreeValue(ctx, str);
41775
0
    return JS_NewBool(ctx, ret);
41776
0
}
41777
41778
static JSValue js_string_toWellFormed(JSContext *ctx, JSValueConst this_val,
41779
                                      int argc, JSValueConst *argv)
41780
0
{
41781
0
    JSValue str, ret;
41782
0
    JSString *p;
41783
0
    int i;
41784
41785
0
    str = JS_ToStringCheckObject(ctx, this_val);
41786
0
    if (JS_IsException(str))
41787
0
        return JS_EXCEPTION;
41788
41789
0
    p = JS_VALUE_GET_STRING(str);
41790
    /* avoid reallocating the string if it is well-formed */
41791
0
    i = js_string_find_invalid_codepoint(p);
41792
0
    if (i < 0)
41793
0
        return str;
41794
41795
0
    ret = js_new_string16(ctx, p->u.str16, p->len);
41796
0
    JS_FreeValue(ctx, str);
41797
0
    if (JS_IsException(ret))
41798
0
        return JS_EXCEPTION;
41799
41800
0
    p = JS_VALUE_GET_STRING(ret);
41801
0
    for (; i < p->len; i++) {
41802
0
        uint32_t c = p->u.str16[i];
41803
0
        if (is_surrogate(c)) {
41804
0
            if (is_hi_surrogate(c) && (i + 1) < p->len
41805
0
            &&  is_lo_surrogate(p->u.str16[i + 1])) {
41806
0
                i++;
41807
0
            } else {
41808
0
                p->u.str16[i] = 0xFFFD;
41809
0
            }
41810
0
        }
41811
0
    }
41812
0
    return ret;
41813
0
}
41814
41815
static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val,
41816
                                 int argc, JSValueConst *argv, int lastIndexOf)
41817
0
{
41818
0
    JSValue str, v;
41819
0
    int i, len, v_len, pos, start, stop, ret, inc;
41820
0
    JSString *p;
41821
0
    JSString *p1;
41822
41823
0
    str = JS_ToStringCheckObject(ctx, this_val);
41824
0
    if (JS_IsException(str))
41825
0
        return str;
41826
0
    v = JS_ToString(ctx, argv[0]);
41827
0
    if (JS_IsException(v))
41828
0
        goto fail;
41829
0
    p = JS_VALUE_GET_STRING(str);
41830
0
    p1 = JS_VALUE_GET_STRING(v);
41831
0
    len = p->len;
41832
0
    v_len = p1->len;
41833
0
    if (lastIndexOf) {
41834
0
        pos = len - v_len;
41835
0
        if (argc > 1) {
41836
0
            double d;
41837
0
            if (JS_ToFloat64(ctx, &d, argv[1]))
41838
0
                goto fail;
41839
0
            if (!isnan(d)) {
41840
0
                if (d <= 0)
41841
0
                    pos = 0;
41842
0
                else if (d < pos)
41843
0
                    pos = d;
41844
0
            }
41845
0
        }
41846
0
        start = pos;
41847
0
        stop = 0;
41848
0
        inc = -1;
41849
0
    } else {
41850
0
        pos = 0;
41851
0
        if (argc > 1) {
41852
0
            if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
41853
0
                goto fail;
41854
0
        }
41855
0
        start = pos;
41856
0
        stop = len - v_len;
41857
0
        inc = 1;
41858
0
    }
41859
0
    ret = -1;
41860
0
    if (len >= v_len && inc * (stop - start) >= 0) {
41861
0
        for (i = start;; i += inc) {
41862
0
            if (!string_cmp(p, p1, i, 0, v_len)) {
41863
0
                ret = i;
41864
0
                break;
41865
0
            }
41866
0
            if (i == stop)
41867
0
                break;
41868
0
        }
41869
0
    }
41870
0
    JS_FreeValue(ctx, str);
41871
0
    JS_FreeValue(ctx, v);
41872
0
    return JS_NewInt32(ctx, ret);
41873
41874
0
fail:
41875
0
    JS_FreeValue(ctx, str);
41876
0
    JS_FreeValue(ctx, v);
41877
0
    return JS_EXCEPTION;
41878
0
}
41879
41880
/* return < 0 if exception or TRUE/FALSE */
41881
static int js_is_regexp(JSContext *ctx, JSValueConst obj);
41882
41883
static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val,
41884
                                  int argc, JSValueConst *argv, int magic)
41885
0
{
41886
0
    JSValue str, v = JS_UNDEFINED;
41887
0
    int i, len, v_len, pos, start, stop, ret;
41888
0
    JSString *p;
41889
0
    JSString *p1;
41890
41891
0
    str = JS_ToStringCheckObject(ctx, this_val);
41892
0
    if (JS_IsException(str))
41893
0
        return str;
41894
0
    ret = js_is_regexp(ctx, argv[0]);
41895
0
    if (ret) {
41896
0
        if (ret > 0)
41897
0
            JS_ThrowTypeError(ctx, "regexp not supported");
41898
0
        goto fail;
41899
0
    }
41900
0
    v = JS_ToString(ctx, argv[0]);
41901
0
    if (JS_IsException(v))
41902
0
        goto fail;
41903
0
    p = JS_VALUE_GET_STRING(str);
41904
0
    p1 = JS_VALUE_GET_STRING(v);
41905
0
    len = p->len;
41906
0
    v_len = p1->len;
41907
0
    pos = (magic == 2) ? len : 0;
41908
0
    if (argc > 1 && !JS_IsUndefined(argv[1])) {
41909
0
        if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
41910
0
            goto fail;
41911
0
    }
41912
0
    len -= v_len;
41913
0
    ret = 0;
41914
0
    if (magic == 0) {
41915
0
        start = pos;
41916
0
        stop = len;
41917
0
    } else {
41918
0
        if (magic == 1) {
41919
0
            if (pos > len)
41920
0
                goto done;
41921
0
        } else {
41922
0
            pos -= v_len;
41923
0
        }
41924
0
        start = stop = pos;
41925
0
    }
41926
0
    if (start >= 0 && start <= stop) {
41927
0
        for (i = start;; i++) {
41928
0
            if (!string_cmp(p, p1, i, 0, v_len)) {
41929
0
                ret = 1;
41930
0
                break;
41931
0
            }
41932
0
            if (i == stop)
41933
0
                break;
41934
0
        }
41935
0
    }
41936
0
 done:
41937
0
    JS_FreeValue(ctx, str);
41938
0
    JS_FreeValue(ctx, v);
41939
0
    return JS_NewBool(ctx, ret);
41940
41941
0
fail:
41942
0
    JS_FreeValue(ctx, str);
41943
0
    JS_FreeValue(ctx, v);
41944
0
    return JS_EXCEPTION;
41945
0
}
41946
41947
static int check_regexp_g_flag(JSContext *ctx, JSValueConst regexp)
41948
0
{
41949
0
    int ret;
41950
0
    JSValue flags;
41951
41952
0
    ret = js_is_regexp(ctx, regexp);
41953
0
    if (ret < 0)
41954
0
        return -1;
41955
0
    if (ret) {
41956
0
        flags = JS_GetProperty(ctx, regexp, JS_ATOM_flags);
41957
0
        if (JS_IsException(flags))
41958
0
            return -1;
41959
0
        if (JS_IsUndefined(flags) || JS_IsNull(flags)) {
41960
0
            JS_ThrowTypeError(ctx, "cannot convert to object");
41961
0
            return -1;
41962
0
        }
41963
0
        flags = JS_ToStringFree(ctx, flags);
41964
0
        if (JS_IsException(flags))
41965
0
            return -1;
41966
0
        ret = string_indexof_char(JS_VALUE_GET_STRING(flags), 'g', 0);
41967
0
        JS_FreeValue(ctx, flags);
41968
0
        if (ret < 0) {
41969
0
            JS_ThrowTypeError(ctx, "regexp must have the 'g' flag");
41970
0
            return -1;
41971
0
        }
41972
0
    }
41973
0
    return 0;
41974
0
}
41975
41976
static JSValue js_string_match(JSContext *ctx, JSValueConst this_val,
41977
                               int argc, JSValueConst *argv, int atom)
41978
0
{
41979
    // match(rx), search(rx), matchAll(rx)
41980
    // atom is JS_ATOM_Symbol_match, JS_ATOM_Symbol_search, or JS_ATOM_Symbol_matchAll
41981
0
    JSValueConst O = this_val, regexp = argv[0], args[2];
41982
0
    JSValue matcher, S, rx, result, str;
41983
0
    int args_len;
41984
41985
0
    if (JS_IsUndefined(O) || JS_IsNull(O))
41986
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
41987
41988
0
    if (!JS_IsUndefined(regexp) && !JS_IsNull(regexp)) {
41989
0
        matcher = JS_GetProperty(ctx, regexp, atom);
41990
0
        if (JS_IsException(matcher))
41991
0
            return JS_EXCEPTION;
41992
0
        if (atom == JS_ATOM_Symbol_matchAll) {
41993
0
            if (check_regexp_g_flag(ctx, regexp) < 0) {
41994
0
                JS_FreeValue(ctx, matcher);
41995
0
                return JS_EXCEPTION;
41996
0
            }
41997
0
        }
41998
0
        if (!JS_IsUndefined(matcher) && !JS_IsNull(matcher)) {
41999
0
            return JS_CallFree(ctx, matcher, regexp, 1, &O);
42000
0
        }
42001
0
    }
42002
0
    S = JS_ToString(ctx, O);
42003
0
    if (JS_IsException(S))
42004
0
        return JS_EXCEPTION;
42005
0
    args_len = 1;
42006
0
    args[0] = regexp;
42007
0
    str = JS_UNDEFINED;
42008
0
    if (atom == JS_ATOM_Symbol_matchAll) {
42009
0
        str = JS_NewString(ctx, "g");
42010
0
        if (JS_IsException(str))
42011
0
            goto fail;
42012
0
        args[args_len++] = (JSValueConst)str;
42013
0
    }
42014
0
    rx = JS_CallConstructor(ctx, ctx->regexp_ctor, args_len, args);
42015
0
    JS_FreeValue(ctx, str);
42016
0
    if (JS_IsException(rx)) {
42017
0
    fail:
42018
0
        JS_FreeValue(ctx, S);
42019
0
        return JS_EXCEPTION;
42020
0
    }
42021
0
    result = JS_InvokeFree(ctx, rx, atom, 1, (JSValueConst *)&S);
42022
0
    JS_FreeValue(ctx, S);
42023
0
    return result;
42024
0
}
42025
42026
static JSValue js_string___GetSubstitution(JSContext *ctx, JSValueConst this_val,
42027
                                           int argc, JSValueConst *argv)
42028
0
{
42029
    // GetSubstitution(matched, str, position, captures, namedCaptures, rep)
42030
0
    JSValueConst matched, str, captures, namedCaptures, rep;
42031
0
    JSValue capture, name, s;
42032
0
    uint32_t position, len, matched_len, captures_len;
42033
0
    int i, j, j0, k, k1;
42034
0
    int c, c1;
42035
0
    StringBuffer b_s, *b = &b_s;
42036
0
    JSString *sp, *rp;
42037
42038
0
    matched = argv[0];
42039
0
    str = argv[1];
42040
0
    captures = argv[3];
42041
0
    namedCaptures = argv[4];
42042
0
    rep = argv[5];
42043
42044
0
    if (!JS_IsString(rep) || !JS_IsString(str))
42045
0
        return JS_ThrowTypeError(ctx, "not a string");
42046
42047
0
    sp = JS_VALUE_GET_STRING(str);
42048
0
    rp = JS_VALUE_GET_STRING(rep);
42049
42050
0
    string_buffer_init(ctx, b, 0);
42051
42052
0
    captures_len = 0;
42053
0
    if (!JS_IsUndefined(captures)) {
42054
0
        if (js_get_length32(ctx, &captures_len, captures))
42055
0
            goto exception;
42056
0
    }
42057
0
    if (js_get_length32(ctx, &matched_len, matched))
42058
0
        goto exception;
42059
0
    if (JS_ToUint32(ctx, &position, argv[2]) < 0)
42060
0
        goto exception;
42061
42062
0
    len = rp->len;
42063
0
    i = 0;
42064
0
    for(;;) {
42065
0
        j = string_indexof_char(rp, '$', i);
42066
0
        if (j < 0 || j + 1 >= len)
42067
0
            break;
42068
0
        string_buffer_concat(b, rp, i, j);
42069
0
        j0 = j++;
42070
0
        c = string_get(rp, j++);
42071
0
        if (c == '$') {
42072
0
            string_buffer_putc8(b, '$');
42073
0
        } else if (c == '&') {
42074
0
            if (string_buffer_concat_value(b, matched))
42075
0
                goto exception;
42076
0
        } else if (c == '`') {
42077
0
            string_buffer_concat(b, sp, 0, position);
42078
0
        } else if (c == '\'') {
42079
0
            string_buffer_concat(b, sp, position + matched_len, sp->len);
42080
0
        } else if (c >= '0' && c <= '9') {
42081
0
            k = c - '0';
42082
0
            if (j < len) {
42083
0
                c1 = string_get(rp, j);
42084
0
                if (c1 >= '0' && c1 <= '9') {
42085
                    /* This behavior is specified in ES6 and refined in ECMA 2019 */
42086
                    /* ECMA 2019 does not have the extra test, but
42087
                       Test262 S15.5.4.11_A3_T1..3 require this behavior */
42088
0
                    k1 = k * 10 + c1 - '0';
42089
0
                    if (k1 >= 1 && k1 < captures_len) {
42090
0
                        k = k1;
42091
0
                        j++;
42092
0
                    }
42093
0
                }
42094
0
            }
42095
0
            if (k >= 1 && k < captures_len) {
42096
0
                s = JS_GetPropertyInt64(ctx, captures, k);
42097
0
                if (JS_IsException(s))
42098
0
                    goto exception;
42099
0
                if (!JS_IsUndefined(s)) {
42100
0
                    if (string_buffer_concat_value_free(b, s))
42101
0
                        goto exception;
42102
0
                }
42103
0
            } else {
42104
0
                goto norep;
42105
0
            }
42106
0
        } else if (c == '<' && !JS_IsUndefined(namedCaptures)) {
42107
0
            k = string_indexof_char(rp, '>', j);
42108
0
            if (k < 0)
42109
0
                goto norep;
42110
0
            name = js_sub_string(ctx, rp, j, k);
42111
0
            if (JS_IsException(name))
42112
0
                goto exception;
42113
0
            capture = JS_GetPropertyValue(ctx, namedCaptures, name);
42114
0
            if (JS_IsException(capture))
42115
0
                goto exception;
42116
0
            if (!JS_IsUndefined(capture)) {
42117
0
                if (string_buffer_concat_value_free(b, capture))
42118
0
                    goto exception;
42119
0
            }
42120
0
            j = k + 1;
42121
0
        } else {
42122
0
        norep:
42123
0
            string_buffer_concat(b, rp, j0, j);
42124
0
        }
42125
0
        i = j;
42126
0
    }
42127
0
    string_buffer_concat(b, rp, i, rp->len);
42128
0
    return string_buffer_end(b);
42129
0
exception:
42130
0
    string_buffer_free(b);
42131
0
    return JS_EXCEPTION;
42132
0
}
42133
42134
static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val,
42135
                                 int argc, JSValueConst *argv,
42136
                                 int is_replaceAll)
42137
0
{
42138
    // replace(rx, rep)
42139
0
    JSValueConst O = this_val, searchValue = argv[0], replaceValue = argv[1];
42140
0
    JSValueConst args[6];
42141
0
    JSValue str, search_str, replaceValue_str, repl_str;
42142
0
    JSString *sp, *searchp;
42143
0
    StringBuffer b_s, *b = &b_s;
42144
0
    int pos, functionalReplace, endOfLastMatch;
42145
0
    BOOL is_first;
42146
42147
0
    if (JS_IsUndefined(O) || JS_IsNull(O))
42148
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
42149
42150
0
    search_str = JS_UNDEFINED;
42151
0
    replaceValue_str = JS_UNDEFINED;
42152
0
    repl_str = JS_UNDEFINED;
42153
42154
0
    if (!JS_IsUndefined(searchValue) && !JS_IsNull(searchValue)) {
42155
0
        JSValue replacer;
42156
0
        if (is_replaceAll) {
42157
0
            if (check_regexp_g_flag(ctx, searchValue) < 0)
42158
0
                return JS_EXCEPTION;
42159
0
        }
42160
0
        replacer = JS_GetProperty(ctx, searchValue, JS_ATOM_Symbol_replace);
42161
0
        if (JS_IsException(replacer))
42162
0
            return JS_EXCEPTION;
42163
0
        if (!JS_IsUndefined(replacer) && !JS_IsNull(replacer)) {
42164
0
            args[0] = O;
42165
0
            args[1] = replaceValue;
42166
0
            return JS_CallFree(ctx, replacer, searchValue, 2, args);
42167
0
        }
42168
0
    }
42169
0
    string_buffer_init(ctx, b, 0);
42170
42171
0
    str = JS_ToString(ctx, O);
42172
0
    if (JS_IsException(str))
42173
0
        goto exception;
42174
0
    search_str = JS_ToString(ctx, searchValue);
42175
0
    if (JS_IsException(search_str))
42176
0
        goto exception;
42177
0
    functionalReplace = JS_IsFunction(ctx, replaceValue);
42178
0
    if (!functionalReplace) {
42179
0
        replaceValue_str = JS_ToString(ctx, replaceValue);
42180
0
        if (JS_IsException(replaceValue_str))
42181
0
            goto exception;
42182
0
    }
42183
42184
0
    sp = JS_VALUE_GET_STRING(str);
42185
0
    searchp = JS_VALUE_GET_STRING(search_str);
42186
0
    endOfLastMatch = 0;
42187
0
    is_first = TRUE;
42188
0
    for(;;) {
42189
0
        if (unlikely(searchp->len == 0)) {
42190
0
            if (is_first)
42191
0
                pos = 0;
42192
0
            else if (endOfLastMatch >= sp->len)
42193
0
                pos = -1;
42194
0
            else
42195
0
                pos = endOfLastMatch + 1;
42196
0
        } else {
42197
0
            pos = string_indexof(sp, searchp, endOfLastMatch);
42198
0
        }
42199
0
        if (pos < 0) {
42200
0
            if (is_first) {
42201
0
                string_buffer_free(b);
42202
0
                JS_FreeValue(ctx, search_str);
42203
0
                JS_FreeValue(ctx, replaceValue_str);
42204
0
                return str;
42205
0
            } else {
42206
0
                break;
42207
0
            }
42208
0
        }
42209
0
        if (functionalReplace) {
42210
0
            args[0] = search_str;
42211
0
            args[1] = JS_NewInt32(ctx, pos);
42212
0
            args[2] = str;
42213
0
            repl_str = JS_ToStringFree(ctx, JS_Call(ctx, replaceValue, JS_UNDEFINED, 3, args));
42214
0
        } else {
42215
0
            args[0] = search_str;
42216
0
            args[1] = str;
42217
0
            args[2] = JS_NewInt32(ctx, pos);
42218
0
            args[3] = JS_UNDEFINED;
42219
0
            args[4] = JS_UNDEFINED;
42220
0
            args[5] = replaceValue_str;
42221
0
            repl_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
42222
0
        }
42223
0
        if (JS_IsException(repl_str))
42224
0
            goto exception;
42225
42226
0
        string_buffer_concat(b, sp, endOfLastMatch, pos);
42227
0
        string_buffer_concat_value_free(b, repl_str);
42228
0
        endOfLastMatch = pos + searchp->len;
42229
0
        is_first = FALSE;
42230
0
        if (!is_replaceAll)
42231
0
            break;
42232
0
    }
42233
0
    string_buffer_concat(b, sp, endOfLastMatch, sp->len);
42234
0
    JS_FreeValue(ctx, search_str);
42235
0
    JS_FreeValue(ctx, replaceValue_str);
42236
0
    JS_FreeValue(ctx, str);
42237
0
    return string_buffer_end(b);
42238
42239
0
exception:
42240
0
    string_buffer_free(b);
42241
0
    JS_FreeValue(ctx, search_str);
42242
0
    JS_FreeValue(ctx, replaceValue_str);
42243
0
    JS_FreeValue(ctx, str);
42244
0
    return JS_EXCEPTION;
42245
0
}
42246
42247
static JSValue js_string_split(JSContext *ctx, JSValueConst this_val,
42248
                               int argc, JSValueConst *argv)
42249
0
{
42250
    // split(sep, limit)
42251
0
    JSValueConst O = this_val, separator = argv[0], limit = argv[1];
42252
0
    JSValueConst args[2];
42253
0
    JSValue S, A, R, T;
42254
0
    uint32_t lim, lengthA;
42255
0
    int64_t p, q, s, r, e;
42256
0
    JSString *sp, *rp;
42257
42258
0
    if (JS_IsUndefined(O) || JS_IsNull(O))
42259
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
42260
42261
0
    S = JS_UNDEFINED;
42262
0
    A = JS_UNDEFINED;
42263
0
    R = JS_UNDEFINED;
42264
42265
0
    if (!JS_IsUndefined(separator) && !JS_IsNull(separator)) {
42266
0
        JSValue splitter;
42267
0
        splitter = JS_GetProperty(ctx, separator, JS_ATOM_Symbol_split);
42268
0
        if (JS_IsException(splitter))
42269
0
            return JS_EXCEPTION;
42270
0
        if (!JS_IsUndefined(splitter) && !JS_IsNull(splitter)) {
42271
0
            args[0] = O;
42272
0
            args[1] = limit;
42273
0
            return JS_CallFree(ctx, splitter, separator, 2, args);
42274
0
        }
42275
0
    }
42276
0
    S = JS_ToString(ctx, O);
42277
0
    if (JS_IsException(S))
42278
0
        goto exception;
42279
0
    A = JS_NewArray(ctx);
42280
0
    if (JS_IsException(A))
42281
0
        goto exception;
42282
0
    lengthA = 0;
42283
0
    if (JS_IsUndefined(limit)) {
42284
0
        lim = 0xffffffff;
42285
0
    } else {
42286
0
        if (JS_ToUint32(ctx, &lim, limit) < 0)
42287
0
            goto exception;
42288
0
    }
42289
0
    sp = JS_VALUE_GET_STRING(S);
42290
0
    s = sp->len;
42291
0
    R = JS_ToString(ctx, separator);
42292
0
    if (JS_IsException(R))
42293
0
        goto exception;
42294
0
    rp = JS_VALUE_GET_STRING(R);
42295
0
    r = rp->len;
42296
0
    p = 0;
42297
0
    if (lim == 0)
42298
0
        goto done;
42299
0
    if (JS_IsUndefined(separator))
42300
0
        goto add_tail;
42301
0
    if (s == 0) {
42302
0
        if (r != 0)
42303
0
            goto add_tail;
42304
0
        goto done;
42305
0
    }
42306
0
    q = p;
42307
0
    for (q = p; (q += !r) <= s - r - !r; q = p = e + r) {
42308
0
        e = string_indexof(sp, rp, q);
42309
0
        if (e < 0)
42310
0
            break;
42311
0
        T = js_sub_string(ctx, sp, p, e);
42312
0
        if (JS_IsException(T))
42313
0
            goto exception;
42314
0
        if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T, 0) < 0)
42315
0
            goto exception;
42316
0
        if (lengthA == lim)
42317
0
            goto done;
42318
0
    }
42319
0
add_tail:
42320
0
    T = js_sub_string(ctx, sp, p, s);
42321
0
    if (JS_IsException(T))
42322
0
        goto exception;
42323
0
    if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T,0 ) < 0)
42324
0
        goto exception;
42325
0
done:
42326
0
    JS_FreeValue(ctx, S);
42327
0
    JS_FreeValue(ctx, R);
42328
0
    return A;
42329
42330
0
exception:
42331
0
    JS_FreeValue(ctx, A);
42332
0
    JS_FreeValue(ctx, S);
42333
0
    JS_FreeValue(ctx, R);
42334
0
    return JS_EXCEPTION;
42335
0
}
42336
42337
static JSValue js_string_substring(JSContext *ctx, JSValueConst this_val,
42338
                                   int argc, JSValueConst *argv)
42339
0
{
42340
0
    JSValue str, ret;
42341
0
    int a, b, start, end;
42342
0
    JSString *p;
42343
42344
0
    str = JS_ToStringCheckObject(ctx, this_val);
42345
0
    if (JS_IsException(str))
42346
0
        return str;
42347
0
    p = JS_VALUE_GET_STRING(str);
42348
0
    if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, p->len, 0)) {
42349
0
        JS_FreeValue(ctx, str);
42350
0
        return JS_EXCEPTION;
42351
0
    }
42352
0
    b = p->len;
42353
0
    if (!JS_IsUndefined(argv[1])) {
42354
0
        if (JS_ToInt32Clamp(ctx, &b, argv[1], 0, p->len, 0)) {
42355
0
            JS_FreeValue(ctx, str);
42356
0
            return JS_EXCEPTION;
42357
0
        }
42358
0
    }
42359
0
    if (a < b) {
42360
0
        start = a;
42361
0
        end = b;
42362
0
    } else {
42363
0
        start = b;
42364
0
        end = a;
42365
0
    }
42366
0
    ret = js_sub_string(ctx, p, start, end);
42367
0
    JS_FreeValue(ctx, str);
42368
0
    return ret;
42369
0
}
42370
42371
static JSValue js_string_substr(JSContext *ctx, JSValueConst this_val,
42372
                                int argc, JSValueConst *argv)
42373
0
{
42374
0
    JSValue str, ret;
42375
0
    int a, len, n;
42376
0
    JSString *p;
42377
42378
0
    str = JS_ToStringCheckObject(ctx, this_val);
42379
0
    if (JS_IsException(str))
42380
0
        return str;
42381
0
    p = JS_VALUE_GET_STRING(str);
42382
0
    len = p->len;
42383
0
    if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, len, len)) {
42384
0
        JS_FreeValue(ctx, str);
42385
0
        return JS_EXCEPTION;
42386
0
    }
42387
0
    n = len - a;
42388
0
    if (!JS_IsUndefined(argv[1])) {
42389
0
        if (JS_ToInt32Clamp(ctx, &n, argv[1], 0, len - a, 0)) {
42390
0
            JS_FreeValue(ctx, str);
42391
0
            return JS_EXCEPTION;
42392
0
        }
42393
0
    }
42394
0
    ret = js_sub_string(ctx, p, a, a + n);
42395
0
    JS_FreeValue(ctx, str);
42396
0
    return ret;
42397
0
}
42398
42399
static JSValue js_string_slice(JSContext *ctx, JSValueConst this_val,
42400
                               int argc, JSValueConst *argv)
42401
0
{
42402
0
    JSValue str, ret;
42403
0
    int len, start, end;
42404
0
    JSString *p;
42405
42406
0
    str = JS_ToStringCheckObject(ctx, this_val);
42407
0
    if (JS_IsException(str))
42408
0
        return str;
42409
0
    p = JS_VALUE_GET_STRING(str);
42410
0
    len = p->len;
42411
0
    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) {
42412
0
        JS_FreeValue(ctx, str);
42413
0
        return JS_EXCEPTION;
42414
0
    }
42415
0
    end = len;
42416
0
    if (!JS_IsUndefined(argv[1])) {
42417
0
        if (JS_ToInt32Clamp(ctx, &end, argv[1], 0, len, len)) {
42418
0
            JS_FreeValue(ctx, str);
42419
0
            return JS_EXCEPTION;
42420
0
        }
42421
0
    }
42422
0
    ret = js_sub_string(ctx, p, start, max_int(end, start));
42423
0
    JS_FreeValue(ctx, str);
42424
0
    return ret;
42425
0
}
42426
42427
static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val,
42428
                             int argc, JSValueConst *argv, int padEnd)
42429
0
{
42430
0
    JSValue str, v = JS_UNDEFINED;
42431
0
    StringBuffer b_s, *b = &b_s;
42432
0
    JSString *p, *p1 = NULL;
42433
0
    int n, len, c = ' ';
42434
42435
0
    str = JS_ToStringCheckObject(ctx, this_val);
42436
0
    if (JS_IsException(str))
42437
0
        goto fail1;
42438
0
    if (JS_ToInt32Sat(ctx, &n, argv[0]))
42439
0
        goto fail2;
42440
0
    p = JS_VALUE_GET_STRING(str);
42441
0
    len = p->len;
42442
0
    if (len >= n)
42443
0
        return str;
42444
0
    if (argc > 1 && !JS_IsUndefined(argv[1])) {
42445
0
        v = JS_ToString(ctx, argv[1]);
42446
0
        if (JS_IsException(v))
42447
0
            goto fail2;
42448
0
        p1 = JS_VALUE_GET_STRING(v);
42449
0
        if (p1->len == 0) {
42450
0
            JS_FreeValue(ctx, v);
42451
0
            return str;
42452
0
        }
42453
0
        if (p1->len == 1) {
42454
0
            c = string_get(p1, 0);
42455
0
            p1 = NULL;
42456
0
        }
42457
0
    }
42458
0
    if (n > JS_STRING_LEN_MAX) {
42459
0
        JS_ThrowRangeError(ctx, "invalid string length");
42460
0
        goto fail2;
42461
0
    }
42462
0
    if (string_buffer_init(ctx, b, n))
42463
0
        goto fail3;
42464
0
    n -= len;
42465
0
    if (padEnd) {
42466
0
        if (string_buffer_concat(b, p, 0, len))
42467
0
            goto fail;
42468
0
    }
42469
0
    if (p1) {
42470
0
        while (n > 0) {
42471
0
            int chunk = min_int(n, p1->len);
42472
0
            if (string_buffer_concat(b, p1, 0, chunk))
42473
0
                goto fail;
42474
0
            n -= chunk;
42475
0
        }
42476
0
    } else {
42477
0
        if (string_buffer_fill(b, c, n))
42478
0
            goto fail;
42479
0
    }
42480
0
    if (!padEnd) {
42481
0
        if (string_buffer_concat(b, p, 0, len))
42482
0
            goto fail;
42483
0
    }
42484
0
    JS_FreeValue(ctx, v);
42485
0
    JS_FreeValue(ctx, str);
42486
0
    return string_buffer_end(b);
42487
42488
0
fail:
42489
0
    string_buffer_free(b);
42490
0
fail3:
42491
0
    JS_FreeValue(ctx, v);
42492
0
fail2:
42493
0
    JS_FreeValue(ctx, str);
42494
0
fail1:
42495
0
    return JS_EXCEPTION;
42496
0
}
42497
42498
static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val,
42499
                                int argc, JSValueConst *argv)
42500
0
{
42501
0
    JSValue str;
42502
0
    StringBuffer b_s, *b = &b_s;
42503
0
    JSString *p;
42504
0
    int64_t val;
42505
0
    int n, len;
42506
42507
0
    str = JS_ToStringCheckObject(ctx, this_val);
42508
0
    if (JS_IsException(str))
42509
0
        goto fail;
42510
0
    if (JS_ToInt64Sat(ctx, &val, argv[0]))
42511
0
        goto fail;
42512
0
    if (val < 0 || val > 2147483647) {
42513
0
        JS_ThrowRangeError(ctx, "invalid repeat count");
42514
0
        goto fail;
42515
0
    }
42516
0
    n = val;
42517
0
    p = JS_VALUE_GET_STRING(str);
42518
0
    len = p->len;
42519
0
    if (len == 0 || n == 1)
42520
0
        return str;
42521
    // XXX: potential arithmetic overflow
42522
0
    if (val * len > JS_STRING_LEN_MAX) {
42523
0
        JS_ThrowRangeError(ctx, "invalid string length");
42524
0
        goto fail;
42525
0
    }
42526
0
    if (string_buffer_init2(ctx, b, n * len, p->is_wide_char))
42527
0
        goto fail;
42528
0
    if (len == 1) {
42529
0
        string_buffer_fill(b, string_get(p, 0), n);
42530
0
    } else {
42531
0
        while (n-- > 0) {
42532
0
            string_buffer_concat(b, p, 0, len);
42533
0
        }
42534
0
    }
42535
0
    JS_FreeValue(ctx, str);
42536
0
    return string_buffer_end(b);
42537
42538
0
fail:
42539
0
    JS_FreeValue(ctx, str);
42540
0
    return JS_EXCEPTION;
42541
0
}
42542
42543
static JSValue js_string_trim(JSContext *ctx, JSValueConst this_val,
42544
                              int argc, JSValueConst *argv, int magic)
42545
0
{
42546
0
    JSValue str, ret;
42547
0
    int a, b, len;
42548
0
    JSString *p;
42549
42550
0
    str = JS_ToStringCheckObject(ctx, this_val);
42551
0
    if (JS_IsException(str))
42552
0
        return str;
42553
0
    p = JS_VALUE_GET_STRING(str);
42554
0
    a = 0;
42555
0
    b = len = p->len;
42556
0
    if (magic & 1) {
42557
0
        while (a < len && lre_is_space(string_get(p, a)))
42558
0
            a++;
42559
0
    }
42560
0
    if (magic & 2) {
42561
0
        while (b > a && lre_is_space(string_get(p, b - 1)))
42562
0
            b--;
42563
0
    }
42564
0
    ret = js_sub_string(ctx, p, a, b);
42565
0
    JS_FreeValue(ctx, str);
42566
0
    return ret;
42567
0
}
42568
42569
static JSValue js_string___quote(JSContext *ctx, JSValueConst this_val,
42570
                                 int argc, JSValueConst *argv)
42571
0
{
42572
0
    return JS_ToQuotedString(ctx, this_val);
42573
0
}
42574
42575
/* return 0 if before the first char */
42576
static int string_prevc(JSString *p, int *pidx)
42577
0
{
42578
0
    int idx, c, c1;
42579
42580
0
    idx = *pidx;
42581
0
    if (idx <= 0)
42582
0
        return 0;
42583
0
    idx--;
42584
0
    if (p->is_wide_char) {
42585
0
        c = p->u.str16[idx];
42586
0
        if (is_lo_surrogate(c) && idx > 0) {
42587
0
            c1 = p->u.str16[idx - 1];
42588
0
            if (is_hi_surrogate(c1)) {
42589
0
                c = from_surrogate(c1, c);
42590
0
                idx--;
42591
0
            }
42592
0
        }
42593
0
    } else {
42594
0
        c = p->u.str8[idx];
42595
0
    }
42596
0
    *pidx = idx;
42597
0
    return c;
42598
0
}
42599
42600
static BOOL test_final_sigma(JSString *p, int sigma_pos)
42601
0
{
42602
0
    int k, c1;
42603
42604
    /* before C: skip case ignorable chars and check there is
42605
       a cased letter */
42606
0
    k = sigma_pos;
42607
0
    for(;;) {
42608
0
        c1 = string_prevc(p, &k);
42609
0
        if (!lre_is_case_ignorable(c1))
42610
0
            break;
42611
0
    }
42612
0
    if (!lre_is_cased(c1))
42613
0
        return FALSE;
42614
42615
    /* after C: skip case ignorable chars and check there is
42616
       no cased letter */
42617
0
    k = sigma_pos + 1;
42618
0
    for(;;) {
42619
0
        if (k >= p->len)
42620
0
            return TRUE;
42621
0
        c1 = string_getc(p, &k);
42622
0
        if (!lre_is_case_ignorable(c1))
42623
0
            break;
42624
0
    }
42625
0
    return !lre_is_cased(c1);
42626
0
}
42627
42628
static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val,
42629
                                     int argc, JSValueConst *argv, int to_lower)
42630
0
{
42631
0
    JSValue val;
42632
0
    StringBuffer b_s, *b = &b_s;
42633
0
    JSString *p;
42634
0
    int i, c, j, l;
42635
0
    uint32_t res[LRE_CC_RES_LEN_MAX];
42636
42637
0
    val = JS_ToStringCheckObject(ctx, this_val);
42638
0
    if (JS_IsException(val))
42639
0
        return val;
42640
0
    p = JS_VALUE_GET_STRING(val);
42641
0
    if (p->len == 0)
42642
0
        return val;
42643
0
    if (string_buffer_init(ctx, b, p->len))
42644
0
        goto fail;
42645
0
    for(i = 0; i < p->len;) {
42646
0
        c = string_getc(p, &i);
42647
0
        if (c == 0x3a3 && to_lower && test_final_sigma(p, i - 1)) {
42648
0
            res[0] = 0x3c2; /* final sigma */
42649
0
            l = 1;
42650
0
        } else {
42651
0
            l = lre_case_conv(res, c, to_lower);
42652
0
        }
42653
0
        for(j = 0; j < l; j++) {
42654
0
            if (string_buffer_putc(b, res[j]))
42655
0
                goto fail;
42656
0
        }
42657
0
    }
42658
0
    JS_FreeValue(ctx, val);
42659
0
    return string_buffer_end(b);
42660
0
 fail:
42661
0
    JS_FreeValue(ctx, val);
42662
0
    string_buffer_free(b);
42663
0
    return JS_EXCEPTION;
42664
0
}
42665
42666
#ifdef CONFIG_ALL_UNICODE
42667
42668
/* return (-1, NULL) if exception, otherwise (len, buf) */
42669
static int JS_ToUTF32String(JSContext *ctx, uint32_t **pbuf, JSValueConst val1)
42670
0
{
42671
0
    JSValue val;
42672
0
    JSString *p;
42673
0
    uint32_t *buf;
42674
0
    int i, j, len;
42675
42676
0
    val = JS_ToString(ctx, val1);
42677
0
    if (JS_IsException(val))
42678
0
        return -1;
42679
0
    p = JS_VALUE_GET_STRING(val);
42680
0
    len = p->len;
42681
    /* UTF32 buffer length is len minus the number of correct surrogates pairs */
42682
0
    buf = js_malloc(ctx, sizeof(buf[0]) * max_int(len, 1));
42683
0
    if (!buf) {
42684
0
        JS_FreeValue(ctx, val);
42685
0
        goto fail;
42686
0
    }
42687
0
    for(i = j = 0; i < len;)
42688
0
        buf[j++] = string_getc(p, &i);
42689
0
    JS_FreeValue(ctx, val);
42690
0
    *pbuf = buf;
42691
0
    return j;
42692
0
 fail:
42693
0
    *pbuf = NULL;
42694
0
    return -1;
42695
0
}
42696
42697
static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len)
42698
0
{
42699
0
    int i;
42700
0
    StringBuffer b_s, *b = &b_s;
42701
0
    if (string_buffer_init(ctx, b, len))
42702
0
        return JS_EXCEPTION;
42703
0
    for(i = 0; i < len; i++) {
42704
0
        if (string_buffer_putc(b, buf[i]))
42705
0
            goto fail;
42706
0
    }
42707
0
    return string_buffer_end(b);
42708
0
 fail:
42709
0
    string_buffer_free(b);
42710
0
    return JS_EXCEPTION;
42711
0
}
42712
42713
static int js_string_normalize1(JSContext *ctx, uint32_t **pout_buf,
42714
                                JSValueConst val,
42715
                                UnicodeNormalizationEnum n_type)
42716
0
{
42717
0
    int buf_len, out_len;
42718
0
    uint32_t *buf, *out_buf;
42719
42720
0
    buf_len = JS_ToUTF32String(ctx, &buf, val);
42721
0
    if (buf_len < 0)
42722
0
        return -1;
42723
0
    out_len = unicode_normalize(&out_buf, buf, buf_len, n_type,
42724
0
                                ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
42725
0
    js_free(ctx, buf);
42726
0
    if (out_len < 0)
42727
0
        return -1;
42728
0
    *pout_buf = out_buf;
42729
0
    return out_len;
42730
0
}
42731
42732
static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val,
42733
                                   int argc, JSValueConst *argv)
42734
0
{
42735
0
    const char *form, *p;
42736
0
    size_t form_len;
42737
0
    int is_compat, out_len;
42738
0
    UnicodeNormalizationEnum n_type;
42739
0
    JSValue val;
42740
0
    uint32_t *out_buf;
42741
42742
0
    val = JS_ToStringCheckObject(ctx, this_val);
42743
0
    if (JS_IsException(val))
42744
0
        return val;
42745
42746
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
42747
0
        n_type = UNICODE_NFC;
42748
0
    } else {
42749
0
        form = JS_ToCStringLen(ctx, &form_len, argv[0]);
42750
0
        if (!form)
42751
0
            goto fail1;
42752
0
        p = form;
42753
0
        if (p[0] != 'N' || p[1] != 'F')
42754
0
            goto bad_form;
42755
0
        p += 2;
42756
0
        is_compat = FALSE;
42757
0
        if (*p == 'K') {
42758
0
            is_compat = TRUE;
42759
0
            p++;
42760
0
        }
42761
0
        if (*p == 'C' || *p == 'D') {
42762
0
            n_type = UNICODE_NFC + is_compat * 2 + (*p - 'C');
42763
0
            if ((p + 1 - form) != form_len)
42764
0
                goto bad_form;
42765
0
        } else {
42766
0
        bad_form:
42767
0
            JS_FreeCString(ctx, form);
42768
0
            JS_ThrowRangeError(ctx, "bad normalization form");
42769
0
        fail1:
42770
0
            JS_FreeValue(ctx, val);
42771
0
            return JS_EXCEPTION;
42772
0
        }
42773
0
        JS_FreeCString(ctx, form);
42774
0
    }
42775
42776
0
    out_len = js_string_normalize1(ctx, &out_buf, val, n_type);
42777
0
    JS_FreeValue(ctx, val);
42778
0
    if (out_len < 0)
42779
0
        return JS_EXCEPTION;
42780
0
    val = JS_NewUTF32String(ctx, out_buf, out_len);
42781
0
    js_free(ctx, out_buf);
42782
0
    return val;
42783
0
}
42784
42785
/* return < 0, 0 or > 0 */
42786
static int js_UTF32_compare(const uint32_t *buf1, int buf1_len,
42787
                            const uint32_t *buf2, int buf2_len)
42788
0
{
42789
0
    int i, len, c, res;
42790
0
    len = min_int(buf1_len, buf2_len);
42791
0
    for(i = 0; i < len; i++) {
42792
        /* Note: range is limited so a subtraction is valid */
42793
0
        c = buf1[i] - buf2[i];
42794
0
        if (c != 0)
42795
0
            return c;
42796
0
    }
42797
0
    if (buf1_len == buf2_len)
42798
0
        res = 0;
42799
0
    else if (buf1_len < buf2_len)
42800
0
        res = -1;
42801
0
    else
42802
0
        res = 1;
42803
0
    return res;
42804
0
}
42805
42806
static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
42807
                                       int argc, JSValueConst *argv)
42808
0
{
42809
0
    JSValue a, b;
42810
0
    int cmp, a_len, b_len;
42811
0
    uint32_t *a_buf, *b_buf;
42812
42813
0
    a = JS_ToStringCheckObject(ctx, this_val);
42814
0
    if (JS_IsException(a))
42815
0
        return JS_EXCEPTION;
42816
0
    b = JS_ToString(ctx, argv[0]);
42817
0
    if (JS_IsException(b)) {
42818
0
        JS_FreeValue(ctx, a);
42819
0
        return JS_EXCEPTION;
42820
0
    }
42821
0
    a_len = js_string_normalize1(ctx, &a_buf, a, UNICODE_NFC);
42822
0
    JS_FreeValue(ctx, a);
42823
0
    if (a_len < 0) {
42824
0
        JS_FreeValue(ctx, b);
42825
0
        return JS_EXCEPTION;
42826
0
    }
42827
42828
0
    b_len = js_string_normalize1(ctx, &b_buf, b, UNICODE_NFC);
42829
0
    JS_FreeValue(ctx, b);
42830
0
    if (b_len < 0) {
42831
0
        js_free(ctx, a_buf);
42832
0
        return JS_EXCEPTION;
42833
0
    }
42834
0
    cmp = js_UTF32_compare(a_buf, a_len, b_buf, b_len);
42835
0
    js_free(ctx, a_buf);
42836
0
    js_free(ctx, b_buf);
42837
0
    return JS_NewInt32(ctx, cmp);
42838
0
}
42839
#else /* CONFIG_ALL_UNICODE */
42840
static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
42841
                                       int argc, JSValueConst *argv)
42842
{
42843
    JSValue a, b;
42844
    int cmp;
42845
42846
    a = JS_ToStringCheckObject(ctx, this_val);
42847
    if (JS_IsException(a))
42848
        return JS_EXCEPTION;
42849
    b = JS_ToString(ctx, argv[0]);
42850
    if (JS_IsException(b)) {
42851
        JS_FreeValue(ctx, a);
42852
        return JS_EXCEPTION;
42853
    }
42854
    cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b));
42855
    JS_FreeValue(ctx, a);
42856
    JS_FreeValue(ctx, b);
42857
    return JS_NewInt32(ctx, cmp);
42858
}
42859
#endif /* !CONFIG_ALL_UNICODE */
42860
42861
/* also used for String.prototype.valueOf */
42862
static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val,
42863
                                  int argc, JSValueConst *argv)
42864
0
{
42865
0
    return js_thisStringValue(ctx, this_val);
42866
0
}
42867
42868
#if 0
42869
static JSValue js_string___toStringCheckObject(JSContext *ctx, JSValueConst this_val,
42870
                                               int argc, JSValueConst *argv)
42871
{
42872
    return JS_ToStringCheckObject(ctx, argv[0]);
42873
}
42874
42875
static JSValue js_string___toString(JSContext *ctx, JSValueConst this_val,
42876
                                    int argc, JSValueConst *argv)
42877
{
42878
    return JS_ToString(ctx, argv[0]);
42879
}
42880
42881
static JSValue js_string___advanceStringIndex(JSContext *ctx, JSValueConst
42882
                                              this_val,
42883
                                              int argc, JSValueConst *argv)
42884
{
42885
    JSValue str;
42886
    int idx;
42887
    BOOL is_unicode;
42888
    JSString *p;
42889
42890
    str = JS_ToString(ctx, argv[0]);
42891
    if (JS_IsException(str))
42892
        return str;
42893
    if (JS_ToInt32Sat(ctx, &idx, argv[1])) {
42894
        JS_FreeValue(ctx, str);
42895
        return JS_EXCEPTION;
42896
    }
42897
    is_unicode = JS_ToBool(ctx, argv[2]);
42898
    p = JS_VALUE_GET_STRING(str);
42899
    if (!is_unicode || (unsigned)idx >= p->len || !p->is_wide_char) {
42900
        idx++;
42901
    } else {
42902
        string_getc(p, &idx);
42903
    }
42904
    JS_FreeValue(ctx, str);
42905
    return JS_NewInt32(ctx, idx);
42906
}
42907
#endif
42908
42909
/* String Iterator */
42910
42911
static JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val,
42912
                                       int argc, JSValueConst *argv,
42913
                                       BOOL *pdone, int magic)
42914
0
{
42915
0
    JSArrayIteratorData *it;
42916
0
    uint32_t idx, c, start;
42917
0
    JSString *p;
42918
42919
0
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_STRING_ITERATOR);
42920
0
    if (!it) {
42921
0
        *pdone = FALSE;
42922
0
        return JS_EXCEPTION;
42923
0
    }
42924
0
    if (JS_IsUndefined(it->obj))
42925
0
        goto done;
42926
0
    p = JS_VALUE_GET_STRING(it->obj);
42927
0
    idx = it->idx;
42928
0
    if (idx >= p->len) {
42929
0
        JS_FreeValue(ctx, it->obj);
42930
0
        it->obj = JS_UNDEFINED;
42931
0
    done:
42932
0
        *pdone = TRUE;
42933
0
        return JS_UNDEFINED;
42934
0
    }
42935
42936
0
    start = idx;
42937
0
    c = string_getc(p, (int *)&idx);
42938
0
    it->idx = idx;
42939
0
    *pdone = FALSE;
42940
0
    if (c <= 0xffff) {
42941
0
        return js_new_string_char(ctx, c);
42942
0
    } else {
42943
0
        return js_new_string16(ctx, p->u.str16 + start, 2);
42944
0
    }
42945
0
}
42946
42947
/* ES6 Annex B 2.3.2 etc. */
42948
enum {
42949
    magic_string_anchor,
42950
    magic_string_big,
42951
    magic_string_blink,
42952
    magic_string_bold,
42953
    magic_string_fixed,
42954
    magic_string_fontcolor,
42955
    magic_string_fontsize,
42956
    magic_string_italics,
42957
    magic_string_link,
42958
    magic_string_small,
42959
    magic_string_strike,
42960
    magic_string_sub,
42961
    magic_string_sup,
42962
};
42963
42964
static JSValue js_string_CreateHTML(JSContext *ctx, JSValueConst this_val,
42965
                                    int argc, JSValueConst *argv, int magic)
42966
0
{
42967
0
    JSValue str;
42968
0
    const JSString *p;
42969
0
    StringBuffer b_s, *b = &b_s;
42970
0
    static struct { const char *tag, *attr; } const defs[] = {
42971
0
        { "a", "name" }, { "big", NULL }, { "blink", NULL }, { "b", NULL },
42972
0
        { "tt", NULL }, { "font", "color" }, { "font", "size" }, { "i", NULL },
42973
0
        { "a", "href" }, { "small", NULL }, { "strike", NULL },
42974
0
        { "sub", NULL }, { "sup", NULL },
42975
0
    };
42976
42977
0
    str = JS_ToStringCheckObject(ctx, this_val);
42978
0
    if (JS_IsException(str))
42979
0
        return JS_EXCEPTION;
42980
0
    string_buffer_init(ctx, b, 7);
42981
0
    string_buffer_putc8(b, '<');
42982
0
    string_buffer_puts8(b, defs[magic].tag);
42983
0
    if (defs[magic].attr) {
42984
        // r += " " + attr + "=\"" + value + "\"";
42985
0
        JSValue value;
42986
0
        int i;
42987
42988
0
        string_buffer_putc8(b, ' ');
42989
0
        string_buffer_puts8(b, defs[magic].attr);
42990
0
        string_buffer_puts8(b, "=\"");
42991
0
        value = JS_ToStringCheckObject(ctx, argv[0]);
42992
0
        if (JS_IsException(value)) {
42993
0
            JS_FreeValue(ctx, str);
42994
0
            string_buffer_free(b);
42995
0
            return JS_EXCEPTION;
42996
0
        }
42997
0
        p = JS_VALUE_GET_STRING(value);
42998
0
        for (i = 0; i < p->len; i++) {
42999
0
            int c = string_get(p, i);
43000
0
            if (c == '"') {
43001
0
                string_buffer_puts8(b, "&quot;");
43002
0
            } else {
43003
0
                string_buffer_putc16(b, c);
43004
0
            }
43005
0
        }
43006
0
        JS_FreeValue(ctx, value);
43007
0
        string_buffer_putc8(b, '\"');
43008
0
    }
43009
    // return r + ">" + str + "</" + tag + ">";
43010
0
    string_buffer_putc8(b, '>');
43011
0
    string_buffer_concat_value_free(b, str);
43012
0
    string_buffer_puts8(b, "</");
43013
0
    string_buffer_puts8(b, defs[magic].tag);
43014
0
    string_buffer_putc8(b, '>');
43015
0
    return string_buffer_end(b);
43016
0
}
43017
43018
static const JSCFunctionListEntry js_string_funcs[] = {
43019
    JS_CFUNC_DEF("fromCharCode", 1, js_string_fromCharCode ),
43020
    JS_CFUNC_DEF("fromCodePoint", 1, js_string_fromCodePoint ),
43021
    JS_CFUNC_DEF("raw", 1, js_string_raw ),
43022
    //JS_CFUNC_DEF("__toString", 1, js_string___toString ),
43023
    //JS_CFUNC_DEF("__isSpace", 1, js_string___isSpace ),
43024
    //JS_CFUNC_DEF("__toStringCheckObject", 1, js_string___toStringCheckObject ),
43025
    //JS_CFUNC_DEF("__advanceStringIndex", 3, js_string___advanceStringIndex ),
43026
    //JS_CFUNC_DEF("__GetSubstitution", 6, js_string___GetSubstitution ),
43027
};
43028
43029
static const JSCFunctionListEntry js_string_proto_funcs[] = {
43030
    JS_PROP_INT32_DEF("length", 0, JS_PROP_CONFIGURABLE ),
43031
    JS_CFUNC_MAGIC_DEF("at", 1, js_string_charAt, 1 ),
43032
    JS_CFUNC_DEF("charCodeAt", 1, js_string_charCodeAt ),
43033
    JS_CFUNC_MAGIC_DEF("charAt", 1, js_string_charAt, 0 ),
43034
    JS_CFUNC_DEF("concat", 1, js_string_concat ),
43035
    JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ),
43036
    JS_CFUNC_DEF("isWellFormed", 0, js_string_isWellFormed ),
43037
    JS_CFUNC_DEF("toWellFormed", 0, js_string_toWellFormed ),
43038
    JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0 ),
43039
    JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1 ),
43040
    JS_CFUNC_MAGIC_DEF("includes", 1, js_string_includes, 0 ),
43041
    JS_CFUNC_MAGIC_DEF("endsWith", 1, js_string_includes, 2 ),
43042
    JS_CFUNC_MAGIC_DEF("startsWith", 1, js_string_includes, 1 ),
43043
    JS_CFUNC_MAGIC_DEF("match", 1, js_string_match, JS_ATOM_Symbol_match ),
43044
    JS_CFUNC_MAGIC_DEF("matchAll", 1, js_string_match, JS_ATOM_Symbol_matchAll ),
43045
    JS_CFUNC_MAGIC_DEF("search", 1, js_string_match, JS_ATOM_Symbol_search ),
43046
    JS_CFUNC_DEF("split", 2, js_string_split ),
43047
    JS_CFUNC_DEF("substring", 2, js_string_substring ),
43048
    JS_CFUNC_DEF("substr", 2, js_string_substr ),
43049
    JS_CFUNC_DEF("slice", 2, js_string_slice ),
43050
    JS_CFUNC_DEF("repeat", 1, js_string_repeat ),
43051
    JS_CFUNC_MAGIC_DEF("replace", 2, js_string_replace, 0 ),
43052
    JS_CFUNC_MAGIC_DEF("replaceAll", 2, js_string_replace, 1 ),
43053
    JS_CFUNC_MAGIC_DEF("padEnd", 1, js_string_pad, 1 ),
43054
    JS_CFUNC_MAGIC_DEF("padStart", 1, js_string_pad, 0 ),
43055
    JS_CFUNC_MAGIC_DEF("trim", 0, js_string_trim, 3 ),
43056
    JS_CFUNC_MAGIC_DEF("trimEnd", 0, js_string_trim, 2 ),
43057
    JS_ALIAS_DEF("trimRight", "trimEnd" ),
43058
    JS_CFUNC_MAGIC_DEF("trimStart", 0, js_string_trim, 1 ),
43059
    JS_ALIAS_DEF("trimLeft", "trimStart" ),
43060
    JS_CFUNC_DEF("toString", 0, js_string_toString ),
43061
    JS_CFUNC_DEF("valueOf", 0, js_string_toString ),
43062
    JS_CFUNC_DEF("__quote", 1, js_string___quote ),
43063
    JS_CFUNC_DEF("localeCompare", 1, js_string_localeCompare ),
43064
    JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ),
43065
    JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ),
43066
    JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ),
43067
    JS_CFUNC_MAGIC_DEF("toLocaleUpperCase", 0, js_string_toLowerCase, 0 ),
43068
    JS_CFUNC_MAGIC_DEF("[Symbol.iterator]", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE | 4 ),
43069
    /* ES6 Annex B 2.3.2 etc. */
43070
    JS_CFUNC_MAGIC_DEF("anchor", 1, js_string_CreateHTML, magic_string_anchor ),
43071
    JS_CFUNC_MAGIC_DEF("big", 0, js_string_CreateHTML, magic_string_big ),
43072
    JS_CFUNC_MAGIC_DEF("blink", 0, js_string_CreateHTML, magic_string_blink ),
43073
    JS_CFUNC_MAGIC_DEF("bold", 0, js_string_CreateHTML, magic_string_bold ),
43074
    JS_CFUNC_MAGIC_DEF("fixed", 0, js_string_CreateHTML, magic_string_fixed ),
43075
    JS_CFUNC_MAGIC_DEF("fontcolor", 1, js_string_CreateHTML, magic_string_fontcolor ),
43076
    JS_CFUNC_MAGIC_DEF("fontsize", 1, js_string_CreateHTML, magic_string_fontsize ),
43077
    JS_CFUNC_MAGIC_DEF("italics", 0, js_string_CreateHTML, magic_string_italics ),
43078
    JS_CFUNC_MAGIC_DEF("link", 1, js_string_CreateHTML, magic_string_link ),
43079
    JS_CFUNC_MAGIC_DEF("small", 0, js_string_CreateHTML, magic_string_small ),
43080
    JS_CFUNC_MAGIC_DEF("strike", 0, js_string_CreateHTML, magic_string_strike ),
43081
    JS_CFUNC_MAGIC_DEF("sub", 0, js_string_CreateHTML, magic_string_sub ),
43082
    JS_CFUNC_MAGIC_DEF("sup", 0, js_string_CreateHTML, magic_string_sup ),
43083
};
43084
43085
static const JSCFunctionListEntry js_string_iterator_proto_funcs[] = {
43086
    JS_ITERATOR_NEXT_DEF("next", 0, js_string_iterator_next, 0 ),
43087
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "String Iterator", JS_PROP_CONFIGURABLE ),
43088
};
43089
43090
#ifdef CONFIG_ALL_UNICODE
43091
static const JSCFunctionListEntry js_string_proto_normalize[] = {
43092
    JS_CFUNC_DEF("normalize", 0, js_string_normalize ),
43093
};
43094
#endif
43095
43096
void JS_AddIntrinsicStringNormalize(JSContext *ctx)
43097
39
{
43098
39
#ifdef CONFIG_ALL_UNICODE
43099
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_normalize,
43100
39
                               countof(js_string_proto_normalize));
43101
39
#endif
43102
39
}
43103
43104
/* Math */
43105
43106
/* precondition: a and b are not NaN */
43107
static double js_fmin(double a, double b)
43108
0
{
43109
0
    if (a == 0 && b == 0) {
43110
0
        JSFloat64Union a1, b1;
43111
0
        a1.d = a;
43112
0
        b1.d = b;
43113
0
        a1.u64 |= b1.u64;
43114
0
        return a1.d;
43115
0
    } else {
43116
0
        return fmin(a, b);
43117
0
    }
43118
0
}
43119
43120
/* precondition: a and b are not NaN */
43121
static double js_fmax(double a, double b)
43122
0
{
43123
0
    if (a == 0 && b == 0) {
43124
0
        JSFloat64Union a1, b1;
43125
0
        a1.d = a;
43126
0
        b1.d = b;
43127
0
        a1.u64 &= b1.u64;
43128
0
        return a1.d;
43129
0
    } else {
43130
0
        return fmax(a, b);
43131
0
    }
43132
0
}
43133
43134
static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
43135
                               int argc, JSValueConst *argv, int magic)
43136
0
{
43137
0
    BOOL is_max = magic;
43138
0
    double r, a;
43139
0
    int i;
43140
0
    uint32_t tag;
43141
43142
0
    if (unlikely(argc == 0)) {
43143
0
        return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
43144
0
    }
43145
43146
0
    tag = JS_VALUE_GET_TAG(argv[0]);
43147
0
    if (tag == JS_TAG_INT) {
43148
0
        int a1, r1 = JS_VALUE_GET_INT(argv[0]);
43149
0
        for(i = 1; i < argc; i++) {
43150
0
            tag = JS_VALUE_GET_TAG(argv[i]);
43151
0
            if (tag != JS_TAG_INT) {
43152
0
                r = r1;
43153
0
                goto generic_case;
43154
0
            }
43155
0
            a1 = JS_VALUE_GET_INT(argv[i]);
43156
0
            if (is_max)
43157
0
                r1 = max_int(r1, a1);
43158
0
            else
43159
0
                r1 = min_int(r1, a1);
43160
43161
0
        }
43162
0
        return JS_NewInt32(ctx, r1);
43163
0
    } else {
43164
0
        if (JS_ToFloat64(ctx, &r, argv[0]))
43165
0
            return JS_EXCEPTION;
43166
0
        i = 1;
43167
0
    generic_case:
43168
0
        while (i < argc) {
43169
0
            if (JS_ToFloat64(ctx, &a, argv[i]))
43170
0
                return JS_EXCEPTION;
43171
0
            if (!isnan(r)) {
43172
0
                if (isnan(a)) {
43173
0
                    r = a;
43174
0
                } else {
43175
0
                    if (is_max)
43176
0
                        r = js_fmax(r, a);
43177
0
                    else
43178
0
                        r = js_fmin(r, a);
43179
0
                }
43180
0
            }
43181
0
            i++;
43182
0
        }
43183
0
        return JS_NewFloat64(ctx, r);
43184
0
    }
43185
0
}
43186
43187
static double js_math_sign(double a)
43188
0
{
43189
0
    if (isnan(a) || a == 0.0)
43190
0
        return a;
43191
0
    if (a < 0)
43192
0
        return -1;
43193
0
    else
43194
0
        return 1;
43195
0
}
43196
43197
static double js_math_round(double a)
43198
0
{
43199
0
    JSFloat64Union u;
43200
0
    uint64_t frac_mask, one;
43201
0
    unsigned int e, s;
43202
43203
0
    u.d = a;
43204
0
    e = (u.u64 >> 52) & 0x7ff;
43205
0
    if (e < 1023) {
43206
        /* abs(a) < 1 */
43207
0
        if (e == (1023 - 1) && u.u64 != 0xbfe0000000000000) {
43208
            /* abs(a) > 0.5 or a = 0.5: return +/-1.0 */
43209
0
            u.u64 = (u.u64 & ((uint64_t)1 << 63)) | ((uint64_t)1023 << 52);
43210
0
        } else {
43211
            /* return +/-0.0 */
43212
0
            u.u64 &= (uint64_t)1 << 63;
43213
0
        }
43214
0
    } else if (e < (1023 + 52)) {
43215
0
        s = u.u64 >> 63;
43216
0
        one = (uint64_t)1 << (52 - (e - 1023));
43217
0
        frac_mask = one - 1;
43218
0
        u.u64 += (one >> 1) - s;
43219
0
        u.u64 &= ~frac_mask; /* truncate to an integer */
43220
0
    }
43221
    /* otherwise: abs(a) >= 2^52, or NaN, +/-Infinity: no change */
43222
0
    return u.d;
43223
0
}
43224
43225
static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
43226
                             int argc, JSValueConst *argv)
43227
0
{
43228
0
    double r, a;
43229
0
    int i;
43230
43231
0
    r = 0;
43232
0
    if (argc > 0) {
43233
0
        if (JS_ToFloat64(ctx, &r, argv[0]))
43234
0
            return JS_EXCEPTION;
43235
0
        if (argc == 1) {
43236
0
            r = fabs(r);
43237
0
        } else {
43238
            /* use the built-in function to minimize precision loss */
43239
0
            for (i = 1; i < argc; i++) {
43240
0
                if (JS_ToFloat64(ctx, &a, argv[i]))
43241
0
                    return JS_EXCEPTION;
43242
0
                r = hypot(r, a);
43243
0
            }
43244
0
        }
43245
0
    }
43246
0
    return JS_NewFloat64(ctx, r);
43247
0
}
43248
43249
static double js_math_fround(double a)
43250
0
{
43251
0
    return (float)a;
43252
0
}
43253
43254
static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,
43255
                            int argc, JSValueConst *argv)
43256
0
{
43257
0
    uint32_t a, b, c;
43258
0
    int32_t d;
43259
43260
0
    if (JS_ToUint32(ctx, &a, argv[0]))
43261
0
        return JS_EXCEPTION;
43262
0
    if (JS_ToUint32(ctx, &b, argv[1]))
43263
0
        return JS_EXCEPTION;
43264
0
    c = a * b;
43265
0
    memcpy(&d, &c, sizeof(d));
43266
0
    return JS_NewInt32(ctx, d);
43267
0
}
43268
43269
static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
43270
                             int argc, JSValueConst *argv)
43271
0
{
43272
0
    uint32_t a, r;
43273
43274
0
    if (JS_ToUint32(ctx, &a, argv[0]))
43275
0
        return JS_EXCEPTION;
43276
0
    if (a == 0)
43277
0
        r = 32;
43278
0
    else
43279
0
        r = clz32(a);
43280
0
    return JS_NewInt32(ctx, r);
43281
0
}
43282
43283
/* xorshift* random number generator by Marsaglia */
43284
static uint64_t xorshift64star(uint64_t *pstate)
43285
0
{
43286
0
    uint64_t x;
43287
0
    x = *pstate;
43288
0
    x ^= x >> 12;
43289
0
    x ^= x << 25;
43290
0
    x ^= x >> 27;
43291
0
    *pstate = x;
43292
0
    return x * 0x2545F4914F6CDD1D;
43293
0
}
43294
43295
static void js_random_init(JSContext *ctx)
43296
39
{
43297
39
    struct timeval tv;
43298
39
    gettimeofday(&tv, NULL);
43299
39
    ctx->random_state = ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
43300
    /* the state must be non zero */
43301
39
    if (ctx->random_state == 0)
43302
0
        ctx->random_state = 1;
43303
39
}
43304
43305
static JSValue js_math_random(JSContext *ctx, JSValueConst this_val,
43306
                              int argc, JSValueConst *argv)
43307
0
{
43308
0
    JSFloat64Union u;
43309
0
    uint64_t v;
43310
43311
0
    v = xorshift64star(&ctx->random_state);
43312
    /* 1.0 <= u.d < 2 */
43313
0
    u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12);
43314
0
    return __JS_NewFloat64(ctx, u.d - 1.0);
43315
0
}
43316
43317
static const JSCFunctionListEntry js_math_funcs[] = {
43318
    JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
43319
    JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
43320
    JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ),
43321
    JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ),
43322
    JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ),
43323
    JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),
43324
    JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt ),
43325
43326
    JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, acos ),
43327
    JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, asin ),
43328
    JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, atan ),
43329
    JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, atan2 ),
43330
    JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, cos ),
43331
    JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, exp ),
43332
    JS_CFUNC_SPECIAL_DEF("log", 1, f_f, log ),
43333
    JS_CFUNC_SPECIAL_DEF("pow", 2, f_f_f, js_pow ),
43334
    JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, sin ),
43335
    JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, tan ),
43336
    /* ES6 */
43337
    JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, trunc ),
43338
    JS_CFUNC_SPECIAL_DEF("sign", 1, f_f, js_math_sign ),
43339
    JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, cosh ),
43340
    JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, sinh ),
43341
    JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, tanh ),
43342
    JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, acosh ),
43343
    JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, asinh ),
43344
    JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, atanh ),
43345
    JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, expm1 ),
43346
    JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, log1p ),
43347
    JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2 ),
43348
    JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, log10 ),
43349
    JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, cbrt ),
43350
    JS_CFUNC_DEF("hypot", 2, js_math_hypot ),
43351
    JS_CFUNC_DEF("random", 0, js_math_random ),
43352
    JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround ),
43353
    JS_CFUNC_DEF("imul", 2, js_math_imul ),
43354
    JS_CFUNC_DEF("clz32", 1, js_math_clz32 ),
43355
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Math", JS_PROP_CONFIGURABLE ),
43356
    JS_PROP_DOUBLE_DEF("E", 2.718281828459045, 0 ),
43357
    JS_PROP_DOUBLE_DEF("LN10", 2.302585092994046, 0 ),
43358
    JS_PROP_DOUBLE_DEF("LN2", 0.6931471805599453, 0 ),
43359
    JS_PROP_DOUBLE_DEF("LOG2E", 1.4426950408889634, 0 ),
43360
    JS_PROP_DOUBLE_DEF("LOG10E", 0.4342944819032518, 0 ),
43361
    JS_PROP_DOUBLE_DEF("PI", 3.141592653589793, 0 ),
43362
    JS_PROP_DOUBLE_DEF("SQRT1_2", 0.7071067811865476, 0 ),
43363
    JS_PROP_DOUBLE_DEF("SQRT2", 1.4142135623730951, 0 ),
43364
};
43365
43366
static const JSCFunctionListEntry js_math_obj[] = {
43367
    JS_OBJECT_DEF("Math", js_math_funcs, countof(js_math_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
43368
};
43369
43370
/* Date */
43371
43372
/* OS dependent. d = argv[0] is in ms from 1970. Return the difference
43373
   between UTC time and local time 'd' in minutes */
43374
static int getTimezoneOffset(int64_t time)
43375
0
{
43376
0
    time_t ti;
43377
0
    int res;
43378
43379
0
    time /= 1000; /* convert to seconds */
43380
0
    if (sizeof(time_t) == 4) {
43381
        /* on 32-bit systems, we need to clamp the time value to the
43382
           range of `time_t`. This is better than truncating values to
43383
           32 bits and hopefully provides the same result as 64-bit
43384
           implementation of localtime_r.
43385
         */
43386
0
        if ((time_t)-1 < 0) {
43387
0
            if (time < INT32_MIN) {
43388
0
                time = INT32_MIN;
43389
0
            } else if (time > INT32_MAX) {
43390
0
                time = INT32_MAX;
43391
0
            }
43392
0
        } else {
43393
0
            if (time < 0) {
43394
0
                time = 0;
43395
0
            } else if (time > UINT32_MAX) {
43396
0
                time = UINT32_MAX;
43397
0
            }
43398
0
        }
43399
0
    }
43400
0
    ti = time;
43401
#if defined(_WIN32)
43402
    {
43403
        struct tm *tm;
43404
        time_t gm_ti, loc_ti;
43405
43406
        tm = gmtime(&ti);
43407
        gm_ti = mktime(tm);
43408
43409
        tm = localtime(&ti);
43410
        loc_ti = mktime(tm);
43411
43412
        res = (gm_ti - loc_ti) / 60;
43413
    }
43414
#else
43415
0
    {
43416
0
        struct tm tm;
43417
0
        localtime_r(&ti, &tm);
43418
0
        res = -tm.tm_gmtoff / 60;
43419
0
    }
43420
0
#endif
43421
0
    return res;
43422
0
}
43423
43424
#if 0
43425
static JSValue js___date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
43426
                                           int argc, JSValueConst *argv)
43427
{
43428
    double dd;
43429
43430
    if (JS_ToFloat64(ctx, &dd, argv[0]))
43431
        return JS_EXCEPTION;
43432
    if (isnan(dd))
43433
        return __JS_NewFloat64(ctx, dd);
43434
    else
43435
        return JS_NewInt32(ctx, getTimezoneOffset((int64_t)dd));
43436
}
43437
43438
static JSValue js_get_prototype_from_ctor(JSContext *ctx, JSValueConst ctor,
43439
                                          JSValueConst def_proto)
43440
{
43441
    JSValue proto;
43442
    proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
43443
    if (JS_IsException(proto))
43444
        return proto;
43445
    if (!JS_IsObject(proto)) {
43446
        JS_FreeValue(ctx, proto);
43447
        proto = JS_DupValue(ctx, def_proto);
43448
    }
43449
    return proto;
43450
}
43451
43452
/* create a new date object */
43453
static JSValue js___date_create(JSContext *ctx, JSValueConst this_val,
43454
                                int argc, JSValueConst *argv)
43455
{
43456
    JSValue obj, proto;
43457
    proto = js_get_prototype_from_ctor(ctx, argv[0], argv[1]);
43458
    if (JS_IsException(proto))
43459
        return proto;
43460
    obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_DATE);
43461
    JS_FreeValue(ctx, proto);
43462
    if (!JS_IsException(obj))
43463
        JS_SetObjectData(ctx, obj, JS_DupValue(ctx, argv[2]));
43464
    return obj;
43465
}
43466
#endif
43467
43468
/* RegExp */
43469
43470
static void js_regexp_finalizer(JSRuntime *rt, JSValue val)
43471
0
{
43472
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
43473
0
    JSRegExp *re = &p->u.regexp;
43474
0
    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->bytecode));
43475
0
    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->pattern));
43476
0
}
43477
43478
/* create a string containing the RegExp bytecode */
43479
static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
43480
                                 JSValueConst flags)
43481
0
{
43482
0
    const char *str;
43483
0
    int re_flags, mask;
43484
0
    uint8_t *re_bytecode_buf;
43485
0
    size_t i, len;
43486
0
    int re_bytecode_len;
43487
0
    JSValue ret;
43488
0
    char error_msg[64];
43489
43490
0
    re_flags = 0;
43491
0
    if (!JS_IsUndefined(flags)) {
43492
0
        str = JS_ToCStringLen(ctx, &len, flags);
43493
0
        if (!str)
43494
0
            return JS_EXCEPTION;
43495
        /* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */
43496
0
        for (i = 0; i < len; i++) {
43497
0
            switch(str[i]) {
43498
0
            case 'd':
43499
0
                mask = LRE_FLAG_INDICES;
43500
0
                break;
43501
0
            case 'g':
43502
0
                mask = LRE_FLAG_GLOBAL;
43503
0
                break;
43504
0
            case 'i':
43505
0
                mask = LRE_FLAG_IGNORECASE;
43506
0
                break;
43507
0
            case 'm':
43508
0
                mask = LRE_FLAG_MULTILINE;
43509
0
                break;
43510
0
            case 's':
43511
0
                mask = LRE_FLAG_DOTALL;
43512
0
                break;
43513
0
            case 'u':
43514
0
                mask = LRE_FLAG_UNICODE;
43515
0
                break;
43516
0
            case 'y':
43517
0
                mask = LRE_FLAG_STICKY;
43518
0
                break;
43519
0
            default:
43520
0
                goto bad_flags;
43521
0
            }
43522
0
            if ((re_flags & mask) != 0) {
43523
0
            bad_flags:
43524
0
                JS_FreeCString(ctx, str);
43525
0
                return JS_ThrowSyntaxError(ctx, "invalid regular expression flags");
43526
0
            }
43527
0
            re_flags |= mask;
43528
0
        }
43529
0
        JS_FreeCString(ctx, str);
43530
0
    }
43531
43532
0
    str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & LRE_FLAG_UNICODE));
43533
0
    if (!str)
43534
0
        return JS_EXCEPTION;
43535
0
    re_bytecode_buf = lre_compile(&re_bytecode_len, error_msg,
43536
0
                                  sizeof(error_msg), str, len, re_flags, ctx);
43537
0
    JS_FreeCString(ctx, str);
43538
0
    if (!re_bytecode_buf) {
43539
0
        JS_ThrowSyntaxError(ctx, "%s", error_msg);
43540
0
        return JS_EXCEPTION;
43541
0
    }
43542
43543
0
    ret = js_new_string8(ctx, re_bytecode_buf, re_bytecode_len);
43544
0
    js_free(ctx, re_bytecode_buf);
43545
0
    return ret;
43546
0
}
43547
43548
/* create a RegExp object from a string containing the RegExp bytecode
43549
   and the source pattern */
43550
static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
43551
                                              JSValue pattern, JSValue bc)
43552
0
{
43553
0
    JSValue obj;
43554
0
    JSObject *p;
43555
0
    JSRegExp *re;
43556
43557
    /* sanity check */
43558
0
    if (JS_VALUE_GET_TAG(bc) != JS_TAG_STRING ||
43559
0
        JS_VALUE_GET_TAG(pattern) != JS_TAG_STRING) {
43560
0
        JS_ThrowTypeError(ctx, "string expected");
43561
0
    fail:
43562
0
        JS_FreeValue(ctx, bc);
43563
0
        JS_FreeValue(ctx, pattern);
43564
0
        return JS_EXCEPTION;
43565
0
    }
43566
43567
0
    obj = js_create_from_ctor(ctx, ctor, JS_CLASS_REGEXP);
43568
0
    if (JS_IsException(obj))
43569
0
        goto fail;
43570
0
    p = JS_VALUE_GET_OBJ(obj);
43571
0
    re = &p->u.regexp;
43572
0
    re->pattern = JS_VALUE_GET_STRING(pattern);
43573
0
    re->bytecode = JS_VALUE_GET_STRING(bc);
43574
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0),
43575
0
                           JS_PROP_WRITABLE);
43576
0
    return obj;
43577
0
}
43578
43579
static JSRegExp *js_get_regexp(JSContext *ctx, JSValueConst obj, BOOL throw_error)
43580
0
{
43581
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
43582
0
        JSObject *p = JS_VALUE_GET_OBJ(obj);
43583
0
        if (p->class_id == JS_CLASS_REGEXP)
43584
0
            return &p->u.regexp;
43585
0
    }
43586
0
    if (throw_error) {
43587
0
        JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
43588
0
    }
43589
0
    return NULL;
43590
0
}
43591
43592
/* return < 0 if exception or TRUE/FALSE */
43593
static int js_is_regexp(JSContext *ctx, JSValueConst obj)
43594
0
{
43595
0
    JSValue m;
43596
43597
0
    if (!JS_IsObject(obj))
43598
0
        return FALSE;
43599
0
    m = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_match);
43600
0
    if (JS_IsException(m))
43601
0
        return -1;
43602
0
    if (!JS_IsUndefined(m))
43603
0
        return JS_ToBoolFree(ctx, m);
43604
0
    return js_get_regexp(ctx, obj, FALSE) != NULL;
43605
0
}
43606
43607
static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target,
43608
                                     int argc, JSValueConst *argv)
43609
0
{
43610
0
    JSValue pattern, flags, bc, val;
43611
0
    JSValueConst pat, flags1;
43612
0
    JSRegExp *re;
43613
0
    int pat_is_regexp;
43614
43615
0
    pat = argv[0];
43616
0
    flags1 = argv[1];
43617
0
    pat_is_regexp = js_is_regexp(ctx, pat);
43618
0
    if (pat_is_regexp < 0)
43619
0
        return JS_EXCEPTION;
43620
0
    if (JS_IsUndefined(new_target)) {
43621
        /* called as a function */
43622
0
        new_target = JS_GetActiveFunction(ctx);
43623
0
        if (pat_is_regexp && JS_IsUndefined(flags1)) {
43624
0
            JSValue ctor;
43625
0
            BOOL res;
43626
0
            ctor = JS_GetProperty(ctx, pat, JS_ATOM_constructor);
43627
0
            if (JS_IsException(ctor))
43628
0
                return ctor;
43629
0
            res = js_same_value(ctx, ctor, new_target);
43630
0
            JS_FreeValue(ctx, ctor);
43631
0
            if (res)
43632
0
                return JS_DupValue(ctx, pat);
43633
0
        }
43634
0
    }
43635
0
    re = js_get_regexp(ctx, pat, FALSE);
43636
0
    if (re) {
43637
0
        pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
43638
0
        if (JS_IsUndefined(flags1)) {
43639
0
            bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
43640
0
            goto no_compilation;
43641
0
        } else {
43642
0
            flags = JS_ToString(ctx, flags1);
43643
0
            if (JS_IsException(flags))
43644
0
                goto fail;
43645
0
        }
43646
0
    } else {
43647
0
        flags = JS_UNDEFINED;
43648
0
        if (pat_is_regexp) {
43649
0
            pattern = JS_GetProperty(ctx, pat, JS_ATOM_source);
43650
0
            if (JS_IsException(pattern))
43651
0
                goto fail;
43652
0
            if (JS_IsUndefined(flags1)) {
43653
0
                flags = JS_GetProperty(ctx, pat, JS_ATOM_flags);
43654
0
                if (JS_IsException(flags))
43655
0
                    goto fail;
43656
0
            } else {
43657
0
                flags = JS_DupValue(ctx, flags1);
43658
0
            }
43659
0
        } else {
43660
0
            pattern = JS_DupValue(ctx, pat);
43661
0
            flags = JS_DupValue(ctx, flags1);
43662
0
        }
43663
0
        if (JS_IsUndefined(pattern)) {
43664
0
            pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
43665
0
        } else {
43666
0
            val = pattern;
43667
0
            pattern = JS_ToString(ctx, val);
43668
0
            JS_FreeValue(ctx, val);
43669
0
            if (JS_IsException(pattern))
43670
0
                goto fail;
43671
0
        }
43672
0
    }
43673
0
    bc = js_compile_regexp(ctx, pattern, flags);
43674
0
    if (JS_IsException(bc))
43675
0
        goto fail;
43676
0
    JS_FreeValue(ctx, flags);
43677
0
 no_compilation:
43678
0
    return js_regexp_constructor_internal(ctx, new_target, pattern, bc);
43679
0
 fail:
43680
0
    JS_FreeValue(ctx, pattern);
43681
0
    JS_FreeValue(ctx, flags);
43682
0
    return JS_EXCEPTION;
43683
0
}
43684
43685
static JSValue js_regexp_compile(JSContext *ctx, JSValueConst this_val,
43686
                                 int argc, JSValueConst *argv)
43687
0
{
43688
0
    JSRegExp *re1, *re;
43689
0
    JSValueConst pattern1, flags1;
43690
0
    JSValue bc, pattern;
43691
43692
0
    re = js_get_regexp(ctx, this_val, TRUE);
43693
0
    if (!re)
43694
0
        return JS_EXCEPTION;
43695
0
    pattern1 = argv[0];
43696
0
    flags1 = argv[1];
43697
0
    re1 = js_get_regexp(ctx, pattern1, FALSE);
43698
0
    if (re1) {
43699
0
        if (!JS_IsUndefined(flags1))
43700
0
            return JS_ThrowTypeError(ctx, "flags must be undefined");
43701
0
        pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->pattern));
43702
0
        bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->bytecode));
43703
0
    } else {
43704
0
        bc = JS_UNDEFINED;
43705
0
        if (JS_IsUndefined(pattern1))
43706
0
            pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
43707
0
        else
43708
0
            pattern = JS_ToString(ctx, pattern1);
43709
0
        if (JS_IsException(pattern))
43710
0
            goto fail;
43711
0
        bc = js_compile_regexp(ctx, pattern, flags1);
43712
0
        if (JS_IsException(bc))
43713
0
            goto fail;
43714
0
    }
43715
0
    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
43716
0
    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
43717
0
    re->pattern = JS_VALUE_GET_STRING(pattern);
43718
0
    re->bytecode = JS_VALUE_GET_STRING(bc);
43719
0
    if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
43720
0
                       JS_NewInt32(ctx, 0)) < 0)
43721
0
        return JS_EXCEPTION;
43722
0
    return JS_DupValue(ctx, this_val);
43723
0
 fail:
43724
0
    JS_FreeValue(ctx, pattern);
43725
0
    JS_FreeValue(ctx, bc);
43726
0
    return JS_EXCEPTION;
43727
0
}
43728
43729
#if 0
43730
static JSValue js_regexp_get___source(JSContext *ctx, JSValueConst this_val)
43731
{
43732
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
43733
    if (!re)
43734
        return JS_EXCEPTION;
43735
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
43736
}
43737
43738
static JSValue js_regexp_get___flags(JSContext *ctx, JSValueConst this_val)
43739
{
43740
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
43741
    int flags;
43742
43743
    if (!re)
43744
        return JS_EXCEPTION;
43745
    flags = lre_get_flags(re->bytecode->u.str8);
43746
    return JS_NewInt32(ctx, flags);
43747
}
43748
#endif
43749
43750
static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val)
43751
0
{
43752
0
    JSRegExp *re;
43753
0
    JSString *p;
43754
0
    StringBuffer b_s, *b = &b_s;
43755
0
    int i, n, c, c2, bra;
43756
43757
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
43758
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
43759
43760
0
    if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
43761
0
        goto empty_regex;
43762
43763
0
    re = js_get_regexp(ctx, this_val, TRUE);
43764
0
    if (!re)
43765
0
        return JS_EXCEPTION;
43766
43767
0
    p = re->pattern;
43768
43769
0
    if (p->len == 0) {
43770
0
    empty_regex:
43771
0
        return JS_NewString(ctx, "(?:)");
43772
0
    }
43773
0
    string_buffer_init2(ctx, b, p->len, p->is_wide_char);
43774
43775
    /* Escape '/' and newline sequences as needed */
43776
0
    bra = 0;
43777
0
    for (i = 0, n = p->len; i < n;) {
43778
0
        c2 = -1;
43779
0
        switch (c = string_get(p, i++)) {
43780
0
        case '\\':
43781
0
            if (i < n)
43782
0
                c2 = string_get(p, i++);
43783
0
            break;
43784
0
        case ']':
43785
0
            bra = 0;
43786
0
            break;
43787
0
        case '[':
43788
0
            if (!bra) {
43789
0
                if (i < n && string_get(p, i) == ']')
43790
0
                    c2 = string_get(p, i++);
43791
0
                bra = 1;
43792
0
            }
43793
0
            break;
43794
0
        case '\n':
43795
0
            c = '\\';
43796
0
            c2 = 'n';
43797
0
            break;
43798
0
        case '\r':
43799
0
            c = '\\';
43800
0
            c2 = 'r';
43801
0
            break;
43802
0
        case '/':
43803
0
            if (!bra) {
43804
0
                c = '\\';
43805
0
                c2 = '/';
43806
0
            }
43807
0
            break;
43808
0
        }
43809
0
        string_buffer_putc16(b, c);
43810
0
        if (c2 >= 0)
43811
0
            string_buffer_putc16(b, c2);
43812
0
    }
43813
0
    return string_buffer_end(b);
43814
0
}
43815
43816
static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mask)
43817
0
{
43818
0
    JSRegExp *re;
43819
0
    int flags;
43820
43821
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
43822
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
43823
43824
0
    re = js_get_regexp(ctx, this_val, FALSE);
43825
0
    if (!re) {
43826
0
        if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
43827
0
            return JS_UNDEFINED;
43828
0
        else
43829
0
            return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
43830
0
    }
43831
43832
0
    flags = lre_get_flags(re->bytecode->u.str8);
43833
0
    return JS_NewBool(ctx, flags & mask);
43834
0
}
43835
43836
static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val)
43837
0
{
43838
0
    char str[8], *p = str;
43839
0
    int res;
43840
43841
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
43842
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
43843
43844
0
    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "hasIndices"));
43845
0
    if (res < 0)
43846
0
        goto exception;
43847
0
    if (res)
43848
0
        *p++ = 'd';
43849
0
    res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_global));
43850
0
    if (res < 0)
43851
0
        goto exception;
43852
0
    if (res)
43853
0
        *p++ = 'g';
43854
0
    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "ignoreCase"));
43855
0
    if (res < 0)
43856
0
        goto exception;
43857
0
    if (res)
43858
0
        *p++ = 'i';
43859
0
    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "multiline"));
43860
0
    if (res < 0)
43861
0
        goto exception;
43862
0
    if (res)
43863
0
        *p++ = 'm';
43864
0
    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "dotAll"));
43865
0
    if (res < 0)
43866
0
        goto exception;
43867
0
    if (res)
43868
0
        *p++ = 's';
43869
0
    res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_unicode));
43870
0
    if (res < 0)
43871
0
        goto exception;
43872
0
    if (res)
43873
0
        *p++ = 'u';
43874
0
    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "sticky"));
43875
0
    if (res < 0)
43876
0
        goto exception;
43877
0
    if (res)
43878
0
        *p++ = 'y';
43879
0
    return JS_NewStringLen(ctx, str, p - str);
43880
43881
0
exception:
43882
0
    return JS_EXCEPTION;
43883
0
}
43884
43885
static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,
43886
                                  int argc, JSValueConst *argv)
43887
0
{
43888
0
    JSValue pattern, flags;
43889
0
    StringBuffer b_s, *b = &b_s;
43890
43891
0
    if (!JS_IsObject(this_val))
43892
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
43893
43894
0
    string_buffer_init(ctx, b, 0);
43895
0
    string_buffer_putc8(b, '/');
43896
0
    pattern = JS_GetProperty(ctx, this_val, JS_ATOM_source);
43897
0
    if (string_buffer_concat_value_free(b, pattern))
43898
0
        goto fail;
43899
0
    string_buffer_putc8(b, '/');
43900
0
    flags = JS_GetProperty(ctx, this_val, JS_ATOM_flags);
43901
0
    if (string_buffer_concat_value_free(b, flags))
43902
0
        goto fail;
43903
0
    return string_buffer_end(b);
43904
43905
0
fail:
43906
0
    string_buffer_free(b);
43907
0
    return JS_EXCEPTION;
43908
0
}
43909
43910
BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size)
43911
389k
{
43912
389k
    JSContext *ctx = opaque;
43913
389k
    return js_check_stack_overflow(ctx->rt, alloca_size);
43914
389k
}
43915
43916
void *lre_realloc(void *opaque, void *ptr, size_t size)
43917
633k
{
43918
633k
    JSContext *ctx = opaque;
43919
    /* No JS exception is raised here */
43920
633k
    return js_realloc_rt(ctx->rt, ptr, size);
43921
633k
}
43922
43923
static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
43924
                              int argc, JSValueConst *argv)
43925
0
{
43926
0
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
43927
0
    JSString *str;
43928
0
    JSValue t, ret, str_val, obj, val, groups;
43929
0
    JSValue indices, indices_groups;
43930
0
    uint8_t *re_bytecode;
43931
0
    uint8_t **capture, *str_buf;
43932
0
    int rc, capture_count, shift, i, re_flags;
43933
0
    int64_t last_index;
43934
0
    const char *group_name_ptr;
43935
43936
0
    if (!re)
43937
0
        return JS_EXCEPTION;
43938
43939
0
    str_val = JS_ToString(ctx, argv[0]);
43940
0
    if (JS_IsException(str_val))
43941
0
        return JS_EXCEPTION;
43942
43943
0
    ret = JS_EXCEPTION;
43944
0
    obj = JS_NULL;
43945
0
    groups = JS_UNDEFINED;
43946
0
    indices = JS_UNDEFINED;
43947
0
    indices_groups = JS_UNDEFINED;
43948
0
    capture = NULL;
43949
43950
0
    val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
43951
0
    if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val))
43952
0
        goto fail;
43953
43954
0
    re_bytecode = re->bytecode->u.str8;
43955
0
    re_flags = lre_get_flags(re_bytecode);
43956
0
    if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
43957
0
        last_index = 0;
43958
0
    }
43959
0
    str = JS_VALUE_GET_STRING(str_val);
43960
0
    capture_count = lre_get_capture_count(re_bytecode);
43961
0
    if (capture_count > 0) {
43962
0
        capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
43963
0
        if (!capture)
43964
0
            goto fail;
43965
0
    }
43966
0
    shift = str->is_wide_char;
43967
0
    str_buf = str->u.str8;
43968
0
    if (last_index > str->len) {
43969
0
        rc = 2;
43970
0
    } else {
43971
0
        rc = lre_exec(capture, re_bytecode,
43972
0
                      str_buf, last_index, str->len,
43973
0
                      shift, ctx);
43974
0
    }
43975
0
    if (rc != 1) {
43976
0
        if (rc >= 0) {
43977
0
            if (rc == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
43978
0
                if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
43979
0
                                   JS_NewInt32(ctx, 0)) < 0)
43980
0
                    goto fail;
43981
0
            }
43982
0
        } else {
43983
0
            JS_ThrowInternalError(ctx, "out of memory in regexp execution");
43984
0
            goto fail;
43985
0
        }
43986
0
    } else {
43987
0
        int prop_flags;
43988
0
        if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
43989
0
            if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
43990
0
                               JS_NewInt32(ctx, (capture[1] - str_buf) >> shift)) < 0)
43991
0
                goto fail;
43992
0
        }
43993
0
        obj = JS_NewArray(ctx);
43994
0
        if (JS_IsException(obj))
43995
0
            goto fail;
43996
0
        prop_flags = JS_PROP_C_W_E | JS_PROP_THROW;
43997
0
        group_name_ptr = lre_get_groupnames(re_bytecode);
43998
0
        if (group_name_ptr) {
43999
0
            groups = JS_NewObjectProto(ctx, JS_NULL);
44000
0
            if (JS_IsException(groups))
44001
0
                goto fail;
44002
0
        }
44003
0
        if (re_flags & LRE_FLAG_INDICES) {
44004
0
            indices = JS_NewArray(ctx);
44005
0
            if (JS_IsException(indices))
44006
0
                goto fail;
44007
0
            if (group_name_ptr) {
44008
0
                indices_groups = JS_NewObjectProto(ctx, JS_NULL);
44009
0
                if (JS_IsException(indices_groups))
44010
0
                    goto fail;
44011
0
            }
44012
0
        }
44013
44014
0
        for(i = 0; i < capture_count; i++) {
44015
0
            const char *name = NULL;
44016
0
            uint8_t **match = &capture[2 * i];
44017
0
            int start = -1;
44018
0
            int end = -1;
44019
0
            JSValue val;
44020
44021
0
            if (group_name_ptr && i > 0) {
44022
0
                if (*group_name_ptr) name = group_name_ptr;
44023
0
                group_name_ptr += strlen(group_name_ptr) + 1;
44024
0
            }
44025
44026
0
            if (match[0] && match[1]) {
44027
0
                start = (match[0] - str_buf) >> shift;
44028
0
                end = (match[1] - str_buf) >> shift;
44029
0
            }
44030
44031
0
            if (!JS_IsUndefined(indices)) {
44032
0
                val = JS_UNDEFINED;
44033
0
                if (start != -1) {
44034
0
                    val = JS_NewArray(ctx);
44035
0
                    if (JS_IsException(val))
44036
0
                        goto fail;
44037
0
                    if (JS_DefinePropertyValueUint32(ctx, val, 0,
44038
0
                                                     JS_NewInt32(ctx, start),
44039
0
                                                     prop_flags) < 0) {
44040
0
                        JS_FreeValue(ctx, val);
44041
0
                        goto fail;
44042
0
                    }
44043
0
                    if (JS_DefinePropertyValueUint32(ctx, val, 1,
44044
0
                                                     JS_NewInt32(ctx, end),
44045
0
                                                     prop_flags) < 0) {
44046
0
                        JS_FreeValue(ctx, val);
44047
0
                        goto fail;
44048
0
                    }
44049
0
                }
44050
0
                if (name && !JS_IsUndefined(indices_groups)) {
44051
0
                    val = JS_DupValue(ctx, val);
44052
0
                    if (JS_DefinePropertyValueStr(ctx, indices_groups,
44053
0
                                                  name, val, prop_flags) < 0) {
44054
0
                        JS_FreeValue(ctx, val);
44055
0
                        goto fail;
44056
0
                    }
44057
0
                }
44058
0
                if (JS_DefinePropertyValueUint32(ctx, indices, i, val,
44059
0
                                                 prop_flags) < 0) {
44060
0
                    goto fail;
44061
0
                }
44062
0
            }
44063
44064
0
            val = JS_UNDEFINED;
44065
0
            if (start != -1) {
44066
0
                val = js_sub_string(ctx, str, start, end);
44067
0
                if (JS_IsException(val))
44068
0
                    goto fail;
44069
0
            }
44070
44071
0
            if (name) {
44072
0
                if (JS_DefinePropertyValueStr(ctx, groups, name,
44073
0
                                              JS_DupValue(ctx, val),
44074
0
                                              prop_flags) < 0) {
44075
0
                    JS_FreeValue(ctx, val);
44076
0
                    goto fail;
44077
0
                }
44078
0
            }
44079
44080
0
            if (JS_DefinePropertyValueUint32(ctx, obj, i, val, prop_flags) < 0)
44081
0
                goto fail;
44082
0
        }
44083
44084
0
        t = groups, groups = JS_UNDEFINED;
44085
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_groups,
44086
0
                                   t, prop_flags) < 0) {
44087
0
            goto fail;
44088
0
        }
44089
44090
0
        t = JS_NewInt32(ctx, (capture[0] - str_buf) >> shift);
44091
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index, t, prop_flags) < 0)
44092
0
            goto fail;
44093
44094
0
        t = str_val, str_val = JS_UNDEFINED;
44095
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, t, prop_flags) < 0)
44096
0
            goto fail;
44097
44098
0
        if (!JS_IsUndefined(indices)) {
44099
0
            t = indices_groups, indices_groups = JS_UNDEFINED;
44100
0
            if (JS_DefinePropertyValue(ctx, indices, JS_ATOM_groups,
44101
0
                                       t, prop_flags) < 0) {
44102
0
                goto fail;
44103
0
            }
44104
0
            t = indices, indices = JS_UNDEFINED;
44105
0
            if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_indices,
44106
0
                                       t, prop_flags) < 0) {
44107
0
                goto fail;
44108
0
            }
44109
0
        }
44110
0
    }
44111
0
    ret = obj;
44112
0
    obj = JS_UNDEFINED;
44113
0
fail:
44114
0
    JS_FreeValue(ctx, indices_groups);
44115
0
    JS_FreeValue(ctx, indices);
44116
0
    JS_FreeValue(ctx, str_val);
44117
0
    JS_FreeValue(ctx, groups);
44118
0
    JS_FreeValue(ctx, obj);
44119
0
    js_free(ctx, capture);
44120
0
    return ret;
44121
0
}
44122
44123
/* delete portions of a string that match a given regex */
44124
static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueConst arg)
44125
0
{
44126
0
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
44127
0
    JSString *str;
44128
0
    JSValue str_val, val;
44129
0
    uint8_t *re_bytecode;
44130
0
    int ret;
44131
0
    uint8_t **capture, *str_buf;
44132
0
    int capture_count, shift, re_flags;
44133
0
    int next_src_pos, start, end;
44134
0
    int64_t last_index;
44135
0
    StringBuffer b_s, *b = &b_s;
44136
44137
0
    if (!re)
44138
0
        return JS_EXCEPTION;
44139
44140
0
    string_buffer_init(ctx, b, 0);
44141
44142
0
    capture = NULL;
44143
0
    str_val = JS_ToString(ctx, arg);
44144
0
    if (JS_IsException(str_val))
44145
0
        goto fail;
44146
0
    str = JS_VALUE_GET_STRING(str_val);
44147
0
    re_bytecode = re->bytecode->u.str8;
44148
0
    re_flags = lre_get_flags(re_bytecode);
44149
0
    if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
44150
0
        last_index = 0;
44151
0
    } else {
44152
0
        val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
44153
0
        if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val))
44154
0
            goto fail;
44155
0
    }
44156
0
    capture_count = lre_get_capture_count(re_bytecode);
44157
0
    if (capture_count > 0) {
44158
0
        capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
44159
0
        if (!capture)
44160
0
            goto fail;
44161
0
    }
44162
0
    shift = str->is_wide_char;
44163
0
    str_buf = str->u.str8;
44164
0
    next_src_pos = 0;
44165
0
    for (;;) {
44166
0
        if (last_index > str->len)
44167
0
            break;
44168
44169
0
        ret = lre_exec(capture, re_bytecode,
44170
0
                       str_buf, last_index, str->len, shift, ctx);
44171
0
        if (ret != 1) {
44172
0
            if (ret >= 0) {
44173
0
                if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
44174
0
                    if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
44175
0
                                       JS_NewInt32(ctx, 0)) < 0)
44176
0
                        goto fail;
44177
0
                }
44178
0
            } else {
44179
0
                JS_ThrowInternalError(ctx, "out of memory in regexp execution");
44180
0
                goto fail;
44181
0
            }
44182
0
            break;
44183
0
        }
44184
0
        start = (capture[0] - str_buf) >> shift;
44185
0
        end = (capture[1] - str_buf) >> shift;
44186
0
        last_index = end;
44187
0
        if (next_src_pos < start) {
44188
0
            if (string_buffer_concat(b, str, next_src_pos, start))
44189
0
                goto fail;
44190
0
        }
44191
0
        next_src_pos = end;
44192
0
        if (!(re_flags & LRE_FLAG_GLOBAL)) {
44193
0
            if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
44194
0
                               JS_NewInt32(ctx, end)) < 0)
44195
0
                goto fail;
44196
0
            break;
44197
0
        }
44198
0
        if (end == start) {
44199
0
            if (!(re_flags & LRE_FLAG_UNICODE) || (unsigned)end >= str->len || !str->is_wide_char) {
44200
0
                end++;
44201
0
            } else {
44202
0
                string_getc(str, &end);
44203
0
            }
44204
0
        }
44205
0
        last_index = end;
44206
0
    }
44207
0
    if (string_buffer_concat(b, str, next_src_pos, str->len))
44208
0
        goto fail;
44209
0
    JS_FreeValue(ctx, str_val);
44210
0
    js_free(ctx, capture);
44211
0
    return string_buffer_end(b);
44212
0
fail:
44213
0
    JS_FreeValue(ctx, str_val);
44214
0
    js_free(ctx, capture);
44215
0
    string_buffer_free(b);
44216
0
    return JS_EXCEPTION;
44217
0
}
44218
44219
static JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s)
44220
0
{
44221
0
    JSValue method, ret;
44222
44223
0
    method = JS_GetProperty(ctx, r, JS_ATOM_exec);
44224
0
    if (JS_IsException(method))
44225
0
        return method;
44226
0
    if (JS_IsFunction(ctx, method)) {
44227
0
        ret = JS_CallFree(ctx, method, r, 1, &s);
44228
0
        if (JS_IsException(ret))
44229
0
            return ret;
44230
0
        if (!JS_IsObject(ret) && !JS_IsNull(ret)) {
44231
0
            JS_FreeValue(ctx, ret);
44232
0
            return JS_ThrowTypeError(ctx, "RegExp exec method must return an object or null");
44233
0
        }
44234
0
        return ret;
44235
0
    }
44236
0
    JS_FreeValue(ctx, method);
44237
0
    return js_regexp_exec(ctx, r, 1, &s);
44238
0
}
44239
44240
#if 0
44241
static JSValue js_regexp___RegExpExec(JSContext *ctx, JSValueConst this_val,
44242
                                      int argc, JSValueConst *argv)
44243
{
44244
    return JS_RegExpExec(ctx, argv[0], argv[1]);
44245
}
44246
static JSValue js_regexp___RegExpDelete(JSContext *ctx, JSValueConst this_val,
44247
                                        int argc, JSValueConst *argv)
44248
{
44249
    return JS_RegExpDelete(ctx, argv[0], argv[1]);
44250
}
44251
#endif
44252
44253
static JSValue js_regexp_test(JSContext *ctx, JSValueConst this_val,
44254
                              int argc, JSValueConst *argv)
44255
0
{
44256
0
    JSValue val;
44257
0
    BOOL ret;
44258
44259
0
    val = JS_RegExpExec(ctx, this_val, argv[0]);
44260
0
    if (JS_IsException(val))
44261
0
        return JS_EXCEPTION;
44262
0
    ret = !JS_IsNull(val);
44263
0
    JS_FreeValue(ctx, val);
44264
0
    return JS_NewBool(ctx, ret);
44265
0
}
44266
44267
static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
44268
                                      int argc, JSValueConst *argv)
44269
0
{
44270
    // [Symbol.match](str)
44271
0
    JSValueConst rx = this_val;
44272
0
    JSValue A, S, flags, result, matchStr;
44273
0
    int global, n, fullUnicode, isEmpty;
44274
0
    JSString *p;
44275
44276
0
    if (!JS_IsObject(rx))
44277
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44278
44279
0
    A = JS_UNDEFINED;
44280
0
    flags = JS_UNDEFINED;
44281
0
    result = JS_UNDEFINED;
44282
0
    matchStr = JS_UNDEFINED;
44283
0
    S = JS_ToString(ctx, argv[0]);
44284
0
    if (JS_IsException(S))
44285
0
        goto exception;
44286
44287
0
    flags = JS_GetProperty(ctx, rx, JS_ATOM_flags);
44288
0
    if (JS_IsException(flags))
44289
0
        goto exception;
44290
0
    flags = JS_ToStringFree(ctx, flags);
44291
0
    if (JS_IsException(flags))
44292
0
        goto exception;
44293
0
    p = JS_VALUE_GET_STRING(flags);
44294
44295
    // TODO(bnoordhuis) query 'u' flag the same way?
44296
0
    global = (-1 != string_indexof_char(p, 'g', 0));
44297
0
    if (!global) {
44298
0
        A = JS_RegExpExec(ctx, rx, S);
44299
0
    } else {
44300
0
        fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
44301
0
        if (fullUnicode < 0)
44302
0
            goto exception;
44303
44304
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
44305
0
            goto exception;
44306
0
        A = JS_NewArray(ctx);
44307
0
        if (JS_IsException(A))
44308
0
            goto exception;
44309
0
        n = 0;
44310
0
        for(;;) {
44311
0
            JS_FreeValue(ctx, result);
44312
0
            result = JS_RegExpExec(ctx, rx, S);
44313
0
            if (JS_IsException(result))
44314
0
                goto exception;
44315
0
            if (JS_IsNull(result))
44316
0
                break;
44317
0
            matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
44318
0
            if (JS_IsException(matchStr))
44319
0
                goto exception;
44320
0
            isEmpty = JS_IsEmptyString(matchStr);
44321
0
            if (JS_SetPropertyInt64(ctx, A, n++, matchStr) < 0)
44322
0
                goto exception;
44323
0
            if (isEmpty) {
44324
0
                int64_t thisIndex, nextIndex;
44325
0
                if (JS_ToLengthFree(ctx, &thisIndex,
44326
0
                                    JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
44327
0
                    goto exception;
44328
0
                p = JS_VALUE_GET_STRING(S);
44329
0
                nextIndex = string_advance_index(p, thisIndex, fullUnicode);
44330
0
                if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
44331
0
                    goto exception;
44332
0
            }
44333
0
        }
44334
0
        if (n == 0) {
44335
0
            JS_FreeValue(ctx, A);
44336
0
            A = JS_NULL;
44337
0
        }
44338
0
    }
44339
0
    JS_FreeValue(ctx, result);
44340
0
    JS_FreeValue(ctx, flags);
44341
0
    JS_FreeValue(ctx, S);
44342
0
    return A;
44343
44344
0
exception:
44345
0
    JS_FreeValue(ctx, A);
44346
0
    JS_FreeValue(ctx, result);
44347
0
    JS_FreeValue(ctx, flags);
44348
0
    JS_FreeValue(ctx, S);
44349
0
    return JS_EXCEPTION;
44350
0
}
44351
44352
typedef struct JSRegExpStringIteratorData {
44353
    JSValue iterating_regexp;
44354
    JSValue iterated_string;
44355
    BOOL global;
44356
    BOOL unicode;
44357
    BOOL done;
44358
} JSRegExpStringIteratorData;
44359
44360
static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val)
44361
0
{
44362
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
44363
0
    JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
44364
0
    if (it) {
44365
0
        JS_FreeValueRT(rt, it->iterating_regexp);
44366
0
        JS_FreeValueRT(rt, it->iterated_string);
44367
0
        js_free_rt(rt, it);
44368
0
    }
44369
0
}
44370
44371
static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
44372
                                           JS_MarkFunc *mark_func)
44373
0
{
44374
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
44375
0
    JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
44376
0
    if (it) {
44377
0
        JS_MarkValue(rt, it->iterating_regexp, mark_func);
44378
0
        JS_MarkValue(rt, it->iterated_string, mark_func);
44379
0
    }
44380
0
}
44381
44382
static JSValue js_regexp_string_iterator_next(JSContext *ctx,
44383
                                              JSValueConst this_val,
44384
                                              int argc, JSValueConst *argv,
44385
                                              BOOL *pdone, int magic)
44386
0
{
44387
0
    JSRegExpStringIteratorData *it;
44388
0
    JSValueConst R, S;
44389
0
    JSValue matchStr = JS_UNDEFINED, match = JS_UNDEFINED;
44390
0
    JSString *sp;
44391
44392
0
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_REGEXP_STRING_ITERATOR);
44393
0
    if (!it)
44394
0
        goto exception;
44395
0
    if (it->done) {
44396
0
        *pdone = TRUE;
44397
0
        return JS_UNDEFINED;
44398
0
    }
44399
0
    R = it->iterating_regexp;
44400
0
    S = it->iterated_string;
44401
0
    match = JS_RegExpExec(ctx, R, S);
44402
0
    if (JS_IsException(match))
44403
0
        goto exception;
44404
0
    if (JS_IsNull(match)) {
44405
0
        it->done = TRUE;
44406
0
        *pdone = TRUE;
44407
0
        return JS_UNDEFINED;
44408
0
    } else if (it->global) {
44409
0
        matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, match, 0));
44410
0
        if (JS_IsException(matchStr))
44411
0
            goto exception;
44412
0
        if (JS_IsEmptyString(matchStr)) {
44413
0
            int64_t thisIndex, nextIndex;
44414
0
            if (JS_ToLengthFree(ctx, &thisIndex,
44415
0
                                JS_GetProperty(ctx, R, JS_ATOM_lastIndex)) < 0)
44416
0
                goto exception;
44417
0
            sp = JS_VALUE_GET_STRING(S);
44418
0
            nextIndex = string_advance_index(sp, thisIndex, it->unicode);
44419
0
            if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex,
44420
0
                               JS_NewInt64(ctx, nextIndex)) < 0)
44421
0
                goto exception;
44422
0
        }
44423
0
        JS_FreeValue(ctx, matchStr);
44424
0
    } else {
44425
0
        it->done = TRUE;
44426
0
    }
44427
0
    *pdone = FALSE;
44428
0
    return match;
44429
0
 exception:
44430
0
    JS_FreeValue(ctx, match);
44431
0
    JS_FreeValue(ctx, matchStr);
44432
0
    *pdone = FALSE;
44433
0
    return JS_EXCEPTION;
44434
0
}
44435
44436
static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,
44437
                                         int argc, JSValueConst *argv)
44438
0
{
44439
    // [Symbol.matchAll](str)
44440
0
    JSValueConst R = this_val;
44441
0
    JSValue S, C, flags, matcher, iter;
44442
0
    JSValueConst args[2];
44443
0
    JSString *strp;
44444
0
    int64_t lastIndex;
44445
0
    JSRegExpStringIteratorData *it;
44446
44447
0
    if (!JS_IsObject(R))
44448
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44449
44450
0
    C = JS_UNDEFINED;
44451
0
    flags = JS_UNDEFINED;
44452
0
    matcher = JS_UNDEFINED;
44453
0
    iter = JS_UNDEFINED;
44454
44455
0
    S = JS_ToString(ctx, argv[0]);
44456
0
    if (JS_IsException(S))
44457
0
        goto exception;
44458
0
    C = JS_SpeciesConstructor(ctx, R, ctx->regexp_ctor);
44459
0
    if (JS_IsException(C))
44460
0
        goto exception;
44461
0
    flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, R, JS_ATOM_flags));
44462
0
    if (JS_IsException(flags))
44463
0
        goto exception;
44464
0
    args[0] = R;
44465
0
    args[1] = flags;
44466
0
    matcher = JS_CallConstructor(ctx, C, 2, args);
44467
0
    if (JS_IsException(matcher))
44468
0
        goto exception;
44469
0
    if (JS_ToLengthFree(ctx, &lastIndex,
44470
0
                        JS_GetProperty(ctx, R, JS_ATOM_lastIndex)))
44471
0
        goto exception;
44472
0
    if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex,
44473
0
                       JS_NewInt64(ctx, lastIndex)) < 0)
44474
0
        goto exception;
44475
44476
0
    iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR);
44477
0
    if (JS_IsException(iter))
44478
0
        goto exception;
44479
0
    it = js_malloc(ctx, sizeof(*it));
44480
0
    if (!it)
44481
0
        goto exception;
44482
0
    it->iterating_regexp = matcher;
44483
0
    it->iterated_string = S;
44484
0
    strp = JS_VALUE_GET_STRING(flags);
44485
0
    it->global = string_indexof_char(strp, 'g', 0) >= 0;
44486
0
    it->unicode = string_indexof_char(strp, 'u', 0) >= 0;
44487
0
    it->done = FALSE;
44488
0
    JS_SetOpaque(iter, it);
44489
44490
0
    JS_FreeValue(ctx, C);
44491
0
    JS_FreeValue(ctx, flags);
44492
0
    return iter;
44493
0
 exception:
44494
0
    JS_FreeValue(ctx, S);
44495
0
    JS_FreeValue(ctx, C);
44496
0
    JS_FreeValue(ctx, flags);
44497
0
    JS_FreeValue(ctx, matcher);
44498
0
    JS_FreeValue(ctx, iter);
44499
0
    return JS_EXCEPTION;
44500
0
}
44501
44502
typedef struct ValueBuffer {
44503
    JSContext *ctx;
44504
    JSValue *arr;
44505
    JSValue def[4];
44506
    int len;
44507
    int size;
44508
    int error_status;
44509
} ValueBuffer;
44510
44511
static int value_buffer_init(JSContext *ctx, ValueBuffer *b)
44512
0
{
44513
0
    b->ctx = ctx;
44514
0
    b->len = 0;
44515
0
    b->size = 4;
44516
0
    b->error_status = 0;
44517
0
    b->arr = b->def;
44518
0
    return 0;
44519
0
}
44520
44521
static void value_buffer_free(ValueBuffer *b)
44522
0
{
44523
0
    while (b->len > 0)
44524
0
        JS_FreeValue(b->ctx, b->arr[--b->len]);
44525
0
    if (b->arr != b->def)
44526
0
        js_free(b->ctx, b->arr);
44527
0
    b->arr = b->def;
44528
0
    b->size = 4;
44529
0
}
44530
44531
static int value_buffer_append(ValueBuffer *b, JSValue val)
44532
0
{
44533
0
    if (b->error_status)
44534
0
        return -1;
44535
44536
0
    if (b->len >= b->size) {
44537
0
        int new_size = (b->len + (b->len >> 1) + 31) & ~16;
44538
0
        size_t slack;
44539
0
        JSValue *new_arr;
44540
44541
0
        if (b->arr == b->def) {
44542
0
            new_arr = js_realloc2(b->ctx, NULL, sizeof(*b->arr) * new_size, &slack);
44543
0
            if (new_arr)
44544
0
                memcpy(new_arr, b->def, sizeof b->def);
44545
0
        } else {
44546
0
            new_arr = js_realloc2(b->ctx, b->arr, sizeof(*b->arr) * new_size, &slack);
44547
0
        }
44548
0
        if (!new_arr) {
44549
0
            value_buffer_free(b);
44550
0
            JS_FreeValue(b->ctx, val);
44551
0
            b->error_status = -1;
44552
0
            return -1;
44553
0
        }
44554
0
        new_size += slack / sizeof(*new_arr);
44555
0
        b->arr = new_arr;
44556
0
        b->size = new_size;
44557
0
    }
44558
0
    b->arr[b->len++] = val;
44559
0
    return 0;
44560
0
}
44561
44562
static int js_is_standard_regexp(JSContext *ctx, JSValueConst rx)
44563
0
{
44564
0
    JSValue val;
44565
0
    int res;
44566
44567
0
    val = JS_GetProperty(ctx, rx, JS_ATOM_constructor);
44568
0
    if (JS_IsException(val))
44569
0
        return -1;
44570
    // rx.constructor === RegExp
44571
0
    res = js_same_value(ctx, val, ctx->regexp_ctor);
44572
0
    JS_FreeValue(ctx, val);
44573
0
    if (res) {
44574
0
        val = JS_GetProperty(ctx, rx, JS_ATOM_exec);
44575
0
        if (JS_IsException(val))
44576
0
            return -1;
44577
        // rx.exec === RE_exec
44578
0
        res = JS_IsCFunction(ctx, val, js_regexp_exec, 0);
44579
0
        JS_FreeValue(ctx, val);
44580
0
    }
44581
0
    return res;
44582
0
}
44583
44584
static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
44585
                                        int argc, JSValueConst *argv)
44586
0
{
44587
    // [Symbol.replace](str, rep)
44588
0
    JSValueConst rx = this_val, rep = argv[1];
44589
0
    JSValueConst args[6];
44590
0
    JSValue flags, str, rep_val, matched, tab, rep_str, namedCaptures, res;
44591
0
    JSString *p, *sp, *rp;
44592
0
    StringBuffer b_s, *b = &b_s;
44593
0
    ValueBuffer v_b, *results = &v_b;
44594
0
    int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode;
44595
0
    uint32_t nCaptures;
44596
0
    int64_t position;
44597
44598
0
    if (!JS_IsObject(rx))
44599
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44600
44601
0
    string_buffer_init(ctx, b, 0);
44602
0
    value_buffer_init(ctx, results);
44603
44604
0
    rep_val = JS_UNDEFINED;
44605
0
    matched = JS_UNDEFINED;
44606
0
    tab = JS_UNDEFINED;
44607
0
    flags = JS_UNDEFINED;
44608
0
    rep_str = JS_UNDEFINED;
44609
0
    namedCaptures = JS_UNDEFINED;
44610
44611
0
    str = JS_ToString(ctx, argv[0]);
44612
0
    if (JS_IsException(str))
44613
0
        goto exception;
44614
44615
0
    sp = JS_VALUE_GET_STRING(str);
44616
0
    rp = NULL;
44617
0
    functionalReplace = JS_IsFunction(ctx, rep);
44618
0
    if (!functionalReplace) {
44619
0
        rep_val = JS_ToString(ctx, rep);
44620
0
        if (JS_IsException(rep_val))
44621
0
            goto exception;
44622
0
        rp = JS_VALUE_GET_STRING(rep_val);
44623
0
    }
44624
44625
0
    flags = JS_GetProperty(ctx, rx, JS_ATOM_flags);
44626
0
    if (JS_IsException(flags))
44627
0
        goto exception;
44628
0
    flags = JS_ToStringFree(ctx, flags);
44629
0
    if (JS_IsException(flags))
44630
0
        goto exception;
44631
0
    p = JS_VALUE_GET_STRING(flags);
44632
44633
    // TODO(bnoordhuis) query 'u' flag the same way?
44634
0
    fullUnicode = 0;
44635
0
    is_global = (-1 != string_indexof_char(p, 'g', 0));
44636
0
    if (is_global) {
44637
0
        fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
44638
0
        if (fullUnicode < 0)
44639
0
            goto exception;
44640
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
44641
0
            goto exception;
44642
0
    }
44643
44644
0
    if (rp && rp->len == 0 && is_global && js_is_standard_regexp(ctx, rx)) {
44645
        /* use faster version for simple cases */
44646
0
        res = JS_RegExpDelete(ctx, rx, str);
44647
0
        goto done;
44648
0
    }
44649
0
    for(;;) {
44650
0
        JSValue result;
44651
0
        result = JS_RegExpExec(ctx, rx, str);
44652
0
        if (JS_IsException(result))
44653
0
            goto exception;
44654
0
        if (JS_IsNull(result))
44655
0
            break;
44656
0
        if (value_buffer_append(results, result) < 0)
44657
0
            goto exception;
44658
0
        if (!is_global)
44659
0
            break;
44660
0
        JS_FreeValue(ctx, matched);
44661
0
        matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
44662
0
        if (JS_IsException(matched))
44663
0
            goto exception;
44664
0
        if (JS_IsEmptyString(matched)) {
44665
            /* always advance of at least one char */
44666
0
            int64_t thisIndex, nextIndex;
44667
0
            if (JS_ToLengthFree(ctx, &thisIndex, JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
44668
0
                goto exception;
44669
0
            nextIndex = string_advance_index(sp, thisIndex, fullUnicode);
44670
0
            if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
44671
0
                goto exception;
44672
0
        }
44673
0
    }
44674
0
    nextSourcePosition = 0;
44675
0
    for(j = 0; j < results->len; j++) {
44676
0
        JSValueConst result;
44677
0
        result = results->arr[j];
44678
0
        if (js_get_length32(ctx, &nCaptures, result) < 0)
44679
0
            goto exception;
44680
0
        JS_FreeValue(ctx, matched);
44681
0
        matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
44682
0
        if (JS_IsException(matched))
44683
0
            goto exception;
44684
0
        if (JS_ToLengthFree(ctx, &position, JS_GetProperty(ctx, result, JS_ATOM_index)))
44685
0
            goto exception;
44686
0
        if (position > sp->len)
44687
0
            position = sp->len;
44688
0
        else if (position < 0)
44689
0
            position = 0;
44690
        /* ignore substition if going backward (can happen
44691
           with custom regexp object) */
44692
0
        JS_FreeValue(ctx, tab);
44693
0
        tab = JS_NewArray(ctx);
44694
0
        if (JS_IsException(tab))
44695
0
            goto exception;
44696
0
        if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched),
44697
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
44698
0
            goto exception;
44699
0
        for(n = 1; n < nCaptures; n++) {
44700
0
            JSValue capN;
44701
0
            capN = JS_GetPropertyInt64(ctx, result, n);
44702
0
            if (JS_IsException(capN))
44703
0
                goto exception;
44704
0
            if (!JS_IsUndefined(capN)) {
44705
0
                capN = JS_ToStringFree(ctx, capN);
44706
0
                if (JS_IsException(capN))
44707
0
                    goto exception;
44708
0
            }
44709
0
            if (JS_DefinePropertyValueInt64(ctx, tab, n, capN,
44710
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
44711
0
                goto exception;
44712
0
        }
44713
0
        JS_FreeValue(ctx, namedCaptures);
44714
0
        namedCaptures = JS_GetProperty(ctx, result, JS_ATOM_groups);
44715
0
        if (JS_IsException(namedCaptures))
44716
0
            goto exception;
44717
0
        if (functionalReplace) {
44718
0
            if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
44719
0
                goto exception;
44720
0
            if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
44721
0
                goto exception;
44722
0
            if (!JS_IsUndefined(namedCaptures)) {
44723
0
                if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
44724
0
                    goto exception;
44725
0
            }
44726
0
            args[0] = JS_UNDEFINED;
44727
0
            args[1] = tab;
44728
0
            JS_FreeValue(ctx, rep_str);
44729
0
            rep_str = JS_ToStringFree(ctx, js_function_apply(ctx, rep, 2, args, 0));
44730
0
        } else {
44731
0
            JSValue namedCaptures1;
44732
0
            if (!JS_IsUndefined(namedCaptures)) {
44733
0
                namedCaptures1 = JS_ToObject(ctx, namedCaptures);
44734
0
                if (JS_IsException(namedCaptures1))
44735
0
                    goto exception;
44736
0
            } else {
44737
0
                namedCaptures1 = JS_UNDEFINED;
44738
0
            }
44739
0
            args[0] = matched;
44740
0
            args[1] = str;
44741
0
            args[2] = JS_NewInt32(ctx, position);
44742
0
            args[3] = tab;
44743
0
            args[4] = namedCaptures1;
44744
0
            args[5] = rep_val;
44745
0
            JS_FreeValue(ctx, rep_str);
44746
0
            rep_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
44747
0
            JS_FreeValue(ctx, namedCaptures1);
44748
0
        }
44749
0
        if (JS_IsException(rep_str))
44750
0
            goto exception;
44751
0
        if (position >= nextSourcePosition) {
44752
0
            string_buffer_concat(b, sp, nextSourcePosition, position);
44753
0
            string_buffer_concat_value(b, rep_str);
44754
0
            nextSourcePosition = position + JS_VALUE_GET_STRING(matched)->len;
44755
0
        }
44756
0
    }
44757
0
    string_buffer_concat(b, sp, nextSourcePosition, sp->len);
44758
0
    res = string_buffer_end(b);
44759
0
    goto done1;
44760
44761
0
exception:
44762
0
    res = JS_EXCEPTION;
44763
0
done:
44764
0
    string_buffer_free(b);
44765
0
done1:
44766
0
    value_buffer_free(results);
44767
0
    JS_FreeValue(ctx, rep_val);
44768
0
    JS_FreeValue(ctx, matched);
44769
0
    JS_FreeValue(ctx, flags);
44770
0
    JS_FreeValue(ctx, tab);
44771
0
    JS_FreeValue(ctx, rep_str);
44772
0
    JS_FreeValue(ctx, namedCaptures);
44773
0
    JS_FreeValue(ctx, str);
44774
0
    return res;
44775
0
}
44776
44777
static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val,
44778
                                       int argc, JSValueConst *argv)
44779
0
{
44780
0
    JSValueConst rx = this_val;
44781
0
    JSValue str, previousLastIndex, currentLastIndex, result, index;
44782
44783
0
    if (!JS_IsObject(rx))
44784
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44785
44786
0
    result = JS_UNDEFINED;
44787
0
    currentLastIndex = JS_UNDEFINED;
44788
0
    previousLastIndex = JS_UNDEFINED;
44789
0
    str = JS_ToString(ctx, argv[0]);
44790
0
    if (JS_IsException(str))
44791
0
        goto exception;
44792
44793
0
    previousLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
44794
0
    if (JS_IsException(previousLastIndex))
44795
0
        goto exception;
44796
44797
0
    if (!js_same_value(ctx, previousLastIndex, JS_NewInt32(ctx, 0))) {
44798
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) {
44799
0
            goto exception;
44800
0
        }
44801
0
    }
44802
0
    result = JS_RegExpExec(ctx, rx, str);
44803
0
    if (JS_IsException(result))
44804
0
        goto exception;
44805
0
    currentLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
44806
0
    if (JS_IsException(currentLastIndex))
44807
0
        goto exception;
44808
0
    if (js_same_value(ctx, currentLastIndex, previousLastIndex)) {
44809
0
        JS_FreeValue(ctx, previousLastIndex);
44810
0
    } else {
44811
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) {
44812
0
            previousLastIndex = JS_UNDEFINED;
44813
0
            goto exception;
44814
0
        }
44815
0
    }
44816
0
    JS_FreeValue(ctx, str);
44817
0
    JS_FreeValue(ctx, currentLastIndex);
44818
44819
0
    if (JS_IsNull(result)) {
44820
0
        return JS_NewInt32(ctx, -1);
44821
0
    } else {
44822
0
        index = JS_GetProperty(ctx, result, JS_ATOM_index);
44823
0
        JS_FreeValue(ctx, result);
44824
0
        return index;
44825
0
    }
44826
44827
0
exception:
44828
0
    JS_FreeValue(ctx, result);
44829
0
    JS_FreeValue(ctx, str);
44830
0
    JS_FreeValue(ctx, currentLastIndex);
44831
0
    JS_FreeValue(ctx, previousLastIndex);
44832
0
    return JS_EXCEPTION;
44833
0
}
44834
44835
static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
44836
                                       int argc, JSValueConst *argv)
44837
0
{
44838
    // [Symbol.split](str, limit)
44839
0
    JSValueConst rx = this_val;
44840
0
    JSValueConst args[2];
44841
0
    JSValue str, ctor, splitter, A, flags, z, sub;
44842
0
    JSString *strp;
44843
0
    uint32_t lim, size, p, q;
44844
0
    int unicodeMatching;
44845
0
    int64_t lengthA, e, numberOfCaptures, i;
44846
44847
0
    if (!JS_IsObject(rx))
44848
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44849
44850
0
    ctor = JS_UNDEFINED;
44851
0
    splitter = JS_UNDEFINED;
44852
0
    A = JS_UNDEFINED;
44853
0
    flags = JS_UNDEFINED;
44854
0
    z = JS_UNDEFINED;
44855
0
    str = JS_ToString(ctx, argv[0]);
44856
0
    if (JS_IsException(str))
44857
0
        goto exception;
44858
0
    ctor = JS_SpeciesConstructor(ctx, rx, ctx->regexp_ctor);
44859
0
    if (JS_IsException(ctor))
44860
0
        goto exception;
44861
0
    flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_flags));
44862
0
    if (JS_IsException(flags))
44863
0
        goto exception;
44864
0
    strp = JS_VALUE_GET_STRING(flags);
44865
0
    unicodeMatching = string_indexof_char(strp, 'u', 0) >= 0;
44866
0
    if (string_indexof_char(strp, 'y', 0) < 0) {
44867
0
        flags = JS_ConcatString3(ctx, "", flags, "y");
44868
0
        if (JS_IsException(flags))
44869
0
            goto exception;
44870
0
    }
44871
0
    args[0] = rx;
44872
0
    args[1] = flags;
44873
0
    splitter = JS_CallConstructor(ctx, ctor, 2, args);
44874
0
    if (JS_IsException(splitter))
44875
0
        goto exception;
44876
0
    A = JS_NewArray(ctx);
44877
0
    if (JS_IsException(A))
44878
0
        goto exception;
44879
0
    lengthA = 0;
44880
0
    if (JS_IsUndefined(argv[1])) {
44881
0
        lim = 0xffffffff;
44882
0
    } else {
44883
0
        if (JS_ToUint32(ctx, &lim, argv[1]) < 0)
44884
0
            goto exception;
44885
0
        if (lim == 0)
44886
0
            goto done;
44887
0
    }
44888
0
    strp = JS_VALUE_GET_STRING(str);
44889
0
    p = q = 0;
44890
0
    size = strp->len;
44891
0
    if (size == 0) {
44892
0
        z = JS_RegExpExec(ctx, splitter, str);
44893
0
        if (JS_IsException(z))
44894
0
            goto exception;
44895
0
        if (JS_IsNull(z))
44896
0
            goto add_tail;
44897
0
        goto done;
44898
0
    }
44899
0
    while (q < size) {
44900
0
        if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0)
44901
0
            goto exception;
44902
0
        JS_FreeValue(ctx, z);
44903
0
        z = JS_RegExpExec(ctx, splitter, str);
44904
0
        if (JS_IsException(z))
44905
0
            goto exception;
44906
0
        if (JS_IsNull(z)) {
44907
0
            q = string_advance_index(strp, q, unicodeMatching);
44908
0
        } else {
44909
0
            if (JS_ToLengthFree(ctx, &e, JS_GetProperty(ctx, splitter, JS_ATOM_lastIndex)))
44910
0
                goto exception;
44911
0
            if (e > size)
44912
0
                e = size;
44913
0
            if (e == p) {
44914
0
                q = string_advance_index(strp, q, unicodeMatching);
44915
0
            } else {
44916
0
                sub = js_sub_string(ctx, strp, p, q);
44917
0
                if (JS_IsException(sub))
44918
0
                    goto exception;
44919
0
                if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub,
44920
0
                                                JS_PROP_C_W_E | JS_PROP_THROW) < 0)
44921
0
                    goto exception;
44922
0
                if (lengthA == lim)
44923
0
                    goto done;
44924
0
                p = e;
44925
0
                if (js_get_length64(ctx, &numberOfCaptures, z))
44926
0
                    goto exception;
44927
0
                for(i = 1; i < numberOfCaptures; i++) {
44928
0
                    sub = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, z, i));
44929
0
                    if (JS_IsException(sub))
44930
0
                        goto exception;
44931
0
                    if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
44932
0
                        goto exception;
44933
0
                    if (lengthA == lim)
44934
0
                        goto done;
44935
0
                }
44936
0
                q = p;
44937
0
            }
44938
0
        }
44939
0
    }
44940
0
add_tail:
44941
0
    if (p > size)
44942
0
        p = size;
44943
0
    sub = js_sub_string(ctx, strp, p, size);
44944
0
    if (JS_IsException(sub))
44945
0
        goto exception;
44946
0
    if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
44947
0
        goto exception;
44948
0
    goto done;
44949
0
exception:
44950
0
    JS_FreeValue(ctx, A);
44951
0
    A = JS_EXCEPTION;
44952
0
done:
44953
0
    JS_FreeValue(ctx, str);
44954
0
    JS_FreeValue(ctx, ctor);
44955
0
    JS_FreeValue(ctx, splitter);
44956
0
    JS_FreeValue(ctx, flags);
44957
0
    JS_FreeValue(ctx, z);
44958
0
    return A;
44959
0
}
44960
44961
static const JSCFunctionListEntry js_regexp_funcs[] = {
44962
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
44963
    //JS_CFUNC_DEF("__RegExpExec", 2, js_regexp___RegExpExec ),
44964
    //JS_CFUNC_DEF("__RegExpDelete", 2, js_regexp___RegExpDelete ),
44965
};
44966
44967
static const JSCFunctionListEntry js_regexp_proto_funcs[] = {
44968
    JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ),
44969
    JS_CGETSET_DEF("source", js_regexp_get_source, NULL ),
44970
    JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, LRE_FLAG_GLOBAL ),
44971
    JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, LRE_FLAG_IGNORECASE ),
44972
    JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, LRE_FLAG_MULTILINE ),
44973
    JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, LRE_FLAG_DOTALL ),
44974
    JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE ),
44975
    JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, LRE_FLAG_STICKY ),
44976
    JS_CGETSET_MAGIC_DEF("hasIndices", js_regexp_get_flag, NULL, LRE_FLAG_INDICES ),
44977
    JS_CFUNC_DEF("exec", 1, js_regexp_exec ),
44978
    JS_CFUNC_DEF("compile", 2, js_regexp_compile ),
44979
    JS_CFUNC_DEF("test", 1, js_regexp_test ),
44980
    JS_CFUNC_DEF("toString", 0, js_regexp_toString ),
44981
    JS_CFUNC_DEF("[Symbol.replace]", 2, js_regexp_Symbol_replace ),
44982
    JS_CFUNC_DEF("[Symbol.match]", 1, js_regexp_Symbol_match ),
44983
    JS_CFUNC_DEF("[Symbol.matchAll]", 1, js_regexp_Symbol_matchAll ),
44984
    JS_CFUNC_DEF("[Symbol.search]", 1, js_regexp_Symbol_search ),
44985
    JS_CFUNC_DEF("[Symbol.split]", 2, js_regexp_Symbol_split ),
44986
    //JS_CGETSET_DEF("__source", js_regexp_get___source, NULL ),
44987
    //JS_CGETSET_DEF("__flags", js_regexp_get___flags, NULL ),
44988
};
44989
44990
static const JSCFunctionListEntry js_regexp_string_iterator_proto_funcs[] = {
44991
    JS_ITERATOR_NEXT_DEF("next", 0, js_regexp_string_iterator_next, 0 ),
44992
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "RegExp String Iterator", JS_PROP_CONFIGURABLE ),
44993
};
44994
44995
void JS_AddIntrinsicRegExpCompiler(JSContext *ctx)
44996
39
{
44997
39
    ctx->compile_regexp = js_compile_regexp;
44998
39
}
44999
45000
void JS_AddIntrinsicRegExp(JSContext *ctx)
45001
39
{
45002
39
    JSValueConst obj;
45003
45004
39
    JS_AddIntrinsicRegExpCompiler(ctx);
45005
45006
39
    ctx->class_proto[JS_CLASS_REGEXP] = JS_NewObject(ctx);
45007
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP], js_regexp_proto_funcs,
45008
39
                               countof(js_regexp_proto_funcs));
45009
39
    obj = JS_NewGlobalCConstructor(ctx, "RegExp", js_regexp_constructor, 2,
45010
39
                                   ctx->class_proto[JS_CLASS_REGEXP]);
45011
39
    ctx->regexp_ctor = JS_DupValue(ctx, obj);
45012
39
    JS_SetPropertyFunctionList(ctx, obj, js_regexp_funcs, countof(js_regexp_funcs));
45013
45014
39
    ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR] =
45015
39
        JS_NewObjectProto(ctx, ctx->iterator_proto);
45016
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR],
45017
39
                               js_regexp_string_iterator_proto_funcs,
45018
39
                               countof(js_regexp_string_iterator_proto_funcs));
45019
39
}
45020
45021
/* JSON */
45022
45023
static int json_parse_expect(JSParseState *s, int tok)
45024
0
{
45025
0
    if (s->token.val != tok) {
45026
        /* XXX: dump token correctly in all cases */
45027
0
        return js_parse_error(s, "expecting '%c'", tok);
45028
0
    }
45029
0
    return json_next_token(s);
45030
0
}
45031
45032
static JSValue json_parse_value(JSParseState *s)
45033
0
{
45034
0
    JSContext *ctx = s->ctx;
45035
0
    JSValue val = JS_NULL;
45036
0
    int ret;
45037
45038
0
    switch(s->token.val) {
45039
0
    case '{':
45040
0
        {
45041
0
            JSValue prop_val;
45042
0
            JSAtom prop_name;
45043
45044
0
            if (json_next_token(s))
45045
0
                goto fail;
45046
0
            val = JS_NewObject(ctx);
45047
0
            if (JS_IsException(val))
45048
0
                goto fail;
45049
0
            if (s->token.val != '}') {
45050
0
                for(;;) {
45051
0
                    if (s->token.val == TOK_STRING) {
45052
0
                        prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);
45053
0
                        if (prop_name == JS_ATOM_NULL)
45054
0
                            goto fail;
45055
0
                    } else if (s->ext_json && s->token.val == TOK_IDENT) {
45056
0
                        prop_name = JS_DupAtom(ctx, s->token.u.ident.atom);
45057
0
                    } else {
45058
0
                        js_parse_error(s, "expecting property name");
45059
0
                        goto fail;
45060
0
                    }
45061
0
                    if (json_next_token(s))
45062
0
                        goto fail1;
45063
0
                    if (json_parse_expect(s, ':'))
45064
0
                        goto fail1;
45065
0
                    prop_val = json_parse_value(s);
45066
0
                    if (JS_IsException(prop_val)) {
45067
0
                    fail1:
45068
0
                        JS_FreeAtom(ctx, prop_name);
45069
0
                        goto fail;
45070
0
                    }
45071
0
                    ret = JS_DefinePropertyValue(ctx, val, prop_name,
45072
0
                                                 prop_val, JS_PROP_C_W_E);
45073
0
                    JS_FreeAtom(ctx, prop_name);
45074
0
                    if (ret < 0)
45075
0
                        goto fail;
45076
45077
0
                    if (s->token.val != ',')
45078
0
                        break;
45079
0
                    if (json_next_token(s))
45080
0
                        goto fail;
45081
0
                    if (s->ext_json && s->token.val == '}')
45082
0
                        break;
45083
0
                }
45084
0
            }
45085
0
            if (json_parse_expect(s, '}'))
45086
0
                goto fail;
45087
0
        }
45088
0
        break;
45089
0
    case '[':
45090
0
        {
45091
0
            JSValue el;
45092
0
            uint32_t idx;
45093
45094
0
            if (json_next_token(s))
45095
0
                goto fail;
45096
0
            val = JS_NewArray(ctx);
45097
0
            if (JS_IsException(val))
45098
0
                goto fail;
45099
0
            if (s->token.val != ']') {
45100
0
                idx = 0;
45101
0
                for(;;) {
45102
0
                    el = json_parse_value(s);
45103
0
                    if (JS_IsException(el))
45104
0
                        goto fail;
45105
0
                    ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E);
45106
0
                    if (ret < 0)
45107
0
                        goto fail;
45108
0
                    if (s->token.val != ',')
45109
0
                        break;
45110
0
                    if (json_next_token(s))
45111
0
                        goto fail;
45112
0
                    idx++;
45113
0
                    if (s->ext_json && s->token.val == ']')
45114
0
                        break;
45115
0
                }
45116
0
            }
45117
0
            if (json_parse_expect(s, ']'))
45118
0
                goto fail;
45119
0
        }
45120
0
        break;
45121
0
    case TOK_STRING:
45122
0
        val = JS_DupValue(ctx, s->token.u.str.str);
45123
0
        if (json_next_token(s))
45124
0
            goto fail;
45125
0
        break;
45126
0
    case TOK_NUMBER:
45127
0
        val = s->token.u.num.val;
45128
0
        if (json_next_token(s))
45129
0
            goto fail;
45130
0
        break;
45131
0
    case TOK_IDENT:
45132
0
        if (s->token.u.ident.atom == JS_ATOM_false ||
45133
0
            s->token.u.ident.atom == JS_ATOM_true) {
45134
0
            val = JS_NewBool(ctx, s->token.u.ident.atom == JS_ATOM_true);
45135
0
        } else if (s->token.u.ident.atom == JS_ATOM_null) {
45136
0
            val = JS_NULL;
45137
0
        } else {
45138
0
            goto def_token;
45139
0
        }
45140
0
        if (json_next_token(s))
45141
0
            goto fail;
45142
0
        break;
45143
0
    default:
45144
0
    def_token:
45145
0
        if (s->token.val == TOK_EOF) {
45146
0
            js_parse_error(s, "Unexpected end of JSON input");
45147
0
        } else {
45148
0
            js_parse_error(s, "unexpected token: '%.*s'",
45149
0
                           (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
45150
0
        }
45151
0
        goto fail;
45152
0
    }
45153
0
    return val;
45154
0
 fail:
45155
0
    JS_FreeValue(ctx, val);
45156
0
    return JS_EXCEPTION;
45157
0
}
45158
45159
JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
45160
                      const char *filename, int flags)
45161
0
{
45162
0
    JSParseState s1, *s = &s1;
45163
0
    JSValue val = JS_UNDEFINED;
45164
45165
0
    js_parse_init(ctx, s, buf, buf_len, filename);
45166
0
    s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);
45167
0
    if (json_next_token(s))
45168
0
        goto fail;
45169
0
    val = json_parse_value(s);
45170
0
    if (JS_IsException(val))
45171
0
        goto fail;
45172
0
    if (s->token.val != TOK_EOF) {
45173
0
        if (js_parse_error(s, "unexpected data at the end"))
45174
0
            goto fail;
45175
0
    }
45176
0
    return val;
45177
0
 fail:
45178
0
    JS_FreeValue(ctx, val);
45179
0
    free_token(s, &s->token);
45180
0
    return JS_EXCEPTION;
45181
0
}
45182
45183
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
45184
                     const char *filename)
45185
0
{
45186
0
    return JS_ParseJSON2(ctx, buf, buf_len, filename, 0);
45187
0
}
45188
45189
static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
45190
                                         JSAtom name, JSValueConst reviver)
45191
0
{
45192
0
    JSValue val, new_el, name_val, res;
45193
0
    JSValueConst args[2];
45194
0
    int ret, is_array;
45195
0
    uint32_t i, len = 0;
45196
0
    JSAtom prop;
45197
0
    JSPropertyEnum *atoms = NULL;
45198
45199
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
45200
0
        return JS_ThrowStackOverflow(ctx);
45201
0
    }
45202
45203
0
    val = JS_GetProperty(ctx, holder, name);
45204
0
    if (JS_IsException(val))
45205
0
        return val;
45206
0
    if (JS_IsObject(val)) {
45207
0
        is_array = JS_IsArray(ctx, val);
45208
0
        if (is_array < 0)
45209
0
            goto fail;
45210
0
        if (is_array) {
45211
0
            if (js_get_length32(ctx, &len, val))
45212
0
                goto fail;
45213
0
        } else {
45214
0
            ret = JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, JS_VALUE_GET_OBJ(val), JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
45215
0
            if (ret < 0)
45216
0
                goto fail;
45217
0
        }
45218
0
        for(i = 0; i < len; i++) {
45219
0
            if (is_array) {
45220
0
                prop = JS_NewAtomUInt32(ctx, i);
45221
0
                if (prop == JS_ATOM_NULL)
45222
0
                    goto fail;
45223
0
            } else {
45224
0
                prop = JS_DupAtom(ctx, atoms[i].atom);
45225
0
            }
45226
0
            new_el = internalize_json_property(ctx, val, prop, reviver);
45227
0
            if (JS_IsException(new_el)) {
45228
0
                JS_FreeAtom(ctx, prop);
45229
0
                goto fail;
45230
0
            }
45231
0
            if (JS_IsUndefined(new_el)) {
45232
0
                ret = JS_DeleteProperty(ctx, val, prop, 0);
45233
0
            } else {
45234
0
                ret = JS_DefinePropertyValue(ctx, val, prop, new_el, JS_PROP_C_W_E);
45235
0
            }
45236
0
            JS_FreeAtom(ctx, prop);
45237
0
            if (ret < 0)
45238
0
                goto fail;
45239
0
        }
45240
0
    }
45241
0
    js_free_prop_enum(ctx, atoms, len);
45242
0
    atoms = NULL;
45243
0
    name_val = JS_AtomToValue(ctx, name);
45244
0
    if (JS_IsException(name_val))
45245
0
        goto fail;
45246
0
    args[0] = name_val;
45247
0
    args[1] = val;
45248
0
    res = JS_Call(ctx, reviver, holder, 2, args);
45249
0
    JS_FreeValue(ctx, name_val);
45250
0
    JS_FreeValue(ctx, val);
45251
0
    return res;
45252
0
 fail:
45253
0
    js_free_prop_enum(ctx, atoms, len);
45254
0
    JS_FreeValue(ctx, val);
45255
0
    return JS_EXCEPTION;
45256
0
}
45257
45258
static JSValue js_json_parse(JSContext *ctx, JSValueConst this_val,
45259
                             int argc, JSValueConst *argv)
45260
0
{
45261
0
    JSValue obj, root;
45262
0
    JSValueConst reviver;
45263
0
    const char *str;
45264
0
    size_t len;
45265
45266
0
    str = JS_ToCStringLen(ctx, &len, argv[0]);
45267
0
    if (!str)
45268
0
        return JS_EXCEPTION;
45269
0
    obj = JS_ParseJSON(ctx, str, len, "<input>");
45270
0
    JS_FreeCString(ctx, str);
45271
0
    if (JS_IsException(obj))
45272
0
        return obj;
45273
0
    if (argc > 1 && JS_IsFunction(ctx, argv[1])) {
45274
0
        reviver = argv[1];
45275
0
        root = JS_NewObject(ctx);
45276
0
        if (JS_IsException(root)) {
45277
0
            JS_FreeValue(ctx, obj);
45278
0
            return JS_EXCEPTION;
45279
0
        }
45280
0
        if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj,
45281
0
                                   JS_PROP_C_W_E) < 0) {
45282
0
            JS_FreeValue(ctx, root);
45283
0
            return JS_EXCEPTION;
45284
0
        }
45285
0
        obj = internalize_json_property(ctx, root, JS_ATOM_empty_string,
45286
0
                                        reviver);
45287
0
        JS_FreeValue(ctx, root);
45288
0
    }
45289
0
    return obj;
45290
0
}
45291
45292
typedef struct JSONStringifyContext {
45293
    JSValueConst replacer_func;
45294
    JSValue stack;
45295
    JSValue property_list;
45296
    JSValue gap;
45297
    JSValue empty;
45298
    StringBuffer *b;
45299
} JSONStringifyContext;
45300
45301
0
static JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) {
45302
0
    JSValue r = JS_ToQuotedString(ctx, val);
45303
0
    JS_FreeValue(ctx, val);
45304
0
    return r;
45305
0
}
45306
45307
static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
45308
                             JSValueConst holder, JSValue val, JSValueConst key)
45309
0
{
45310
0
    JSValue v;
45311
0
    JSValueConst args[2];
45312
45313
    /* check for object.toJSON method */
45314
    /* ECMA specifies this is done only for Object and BigInt */
45315
    /* we do it for BigFloat and BigDecimal as an extension */
45316
0
    if (JS_IsObject(val) || JS_IsBigInt(ctx, val)
45317
0
#ifdef CONFIG_BIGNUM
45318
0
    ||  JS_IsBigFloat(val) || JS_IsBigDecimal(val)
45319
0
#endif
45320
0
        ) {
45321
0
        JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);
45322
0
        if (JS_IsException(f))
45323
0
            goto exception;
45324
0
        if (JS_IsFunction(ctx, f)) {
45325
0
            v = JS_CallFree(ctx, f, val, 1, &key);
45326
0
            JS_FreeValue(ctx, val);
45327
0
            val = v;
45328
0
            if (JS_IsException(val))
45329
0
                goto exception;
45330
0
        } else {
45331
0
            JS_FreeValue(ctx, f);
45332
0
        }
45333
0
    }
45334
45335
0
    if (!JS_IsUndefined(jsc->replacer_func)) {
45336
0
        args[0] = key;
45337
0
        args[1] = val;
45338
0
        v = JS_Call(ctx, jsc->replacer_func, holder, 2, args);
45339
0
        JS_FreeValue(ctx, val);
45340
0
        val = v;
45341
0
        if (JS_IsException(val))
45342
0
            goto exception;
45343
0
    }
45344
45345
0
    switch (JS_VALUE_GET_NORM_TAG(val)) {
45346
0
    case JS_TAG_OBJECT:
45347
0
        if (JS_IsFunction(ctx, val))
45348
0
            break;
45349
0
    case JS_TAG_STRING:
45350
0
    case JS_TAG_INT:
45351
0
    case JS_TAG_FLOAT64:
45352
0
    case JS_TAG_BOOL:
45353
0
    case JS_TAG_NULL:
45354
0
    case JS_TAG_BIG_INT:
45355
0
#ifdef CONFIG_BIGNUM
45356
0
    case JS_TAG_BIG_FLOAT:
45357
0
    case JS_TAG_BIG_DECIMAL:
45358
0
#endif
45359
0
    case JS_TAG_EXCEPTION:
45360
0
        return val;
45361
0
    default:
45362
0
        break;
45363
0
    }
45364
0
    JS_FreeValue(ctx, val);
45365
0
    return JS_UNDEFINED;
45366
45367
0
exception:
45368
0
    JS_FreeValue(ctx, val);
45369
0
    return JS_EXCEPTION;
45370
0
}
45371
45372
static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
45373
                          JSValueConst holder, JSValue val,
45374
                          JSValueConst indent)
45375
0
{
45376
0
    JSValue indent1, sep, sep1, tab, v, prop;
45377
0
    JSObject *p;
45378
0
    int64_t i, len;
45379
0
    int cl, ret;
45380
0
    BOOL has_content;
45381
45382
0
    indent1 = JS_UNDEFINED;
45383
0
    sep = JS_UNDEFINED;
45384
0
    sep1 = JS_UNDEFINED;
45385
0
    tab = JS_UNDEFINED;
45386
0
    prop = JS_UNDEFINED;
45387
45388
0
    if (JS_IsObject(val)) {
45389
0
        p = JS_VALUE_GET_OBJ(val);
45390
0
        cl = p->class_id;
45391
0
        if (cl == JS_CLASS_STRING) {
45392
0
            val = JS_ToStringFree(ctx, val);
45393
0
            if (JS_IsException(val))
45394
0
                goto exception;
45395
0
            goto concat_primitive;
45396
0
        } else if (cl == JS_CLASS_NUMBER) {
45397
0
            val = JS_ToNumberFree(ctx, val);
45398
0
            if (JS_IsException(val))
45399
0
                goto exception;
45400
0
            goto concat_primitive;
45401
0
        } else if (cl == JS_CLASS_BOOLEAN || cl == JS_CLASS_BIG_INT
45402
0
#ifdef CONFIG_BIGNUM
45403
0
               || cl == JS_CLASS_BIG_FLOAT
45404
0
               || cl == JS_CLASS_BIG_DECIMAL
45405
0
#endif
45406
0
                   )
45407
0
        {
45408
            /* This will thow the same error as for the primitive object */
45409
0
            set_value(ctx, &val, JS_DupValue(ctx, p->u.object_data));
45410
0
            goto concat_primitive;
45411
0
        }
45412
0
        v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val);
45413
0
        if (JS_IsException(v))
45414
0
            goto exception;
45415
0
        if (JS_ToBoolFree(ctx, v)) {
45416
0
            JS_ThrowTypeError(ctx, "circular reference");
45417
0
            goto exception;
45418
0
        }
45419
0
        indent1 = JS_ConcatString(ctx, JS_DupValue(ctx, indent), JS_DupValue(ctx, jsc->gap));
45420
0
        if (JS_IsException(indent1))
45421
0
            goto exception;
45422
0
        if (!JS_IsEmptyString(jsc->gap)) {
45423
0
            sep = JS_ConcatString3(ctx, "\n", JS_DupValue(ctx, indent1), "");
45424
0
            if (JS_IsException(sep))
45425
0
                goto exception;
45426
0
            sep1 = JS_NewString(ctx, " ");
45427
0
            if (JS_IsException(sep1))
45428
0
                goto exception;
45429
0
        } else {
45430
0
            sep = JS_DupValue(ctx, jsc->empty);
45431
0
            sep1 = JS_DupValue(ctx, jsc->empty);
45432
0
        }
45433
0
        v = js_array_push(ctx, jsc->stack, 1, (JSValueConst *)&val, 0);
45434
0
        if (check_exception_free(ctx, v))
45435
0
            goto exception;
45436
0
        ret = JS_IsArray(ctx, val);
45437
0
        if (ret < 0)
45438
0
            goto exception;
45439
0
        if (ret) {
45440
0
            if (js_get_length64(ctx, &len, val))
45441
0
                goto exception;
45442
0
            string_buffer_putc8(jsc->b, '[');
45443
0
            for(i = 0; i < len; i++) {
45444
0
                if (i > 0)
45445
0
                    string_buffer_putc8(jsc->b, ',');
45446
0
                string_buffer_concat_value(jsc->b, sep);
45447
0
                v = JS_GetPropertyInt64(ctx, val, i);
45448
0
                if (JS_IsException(v))
45449
0
                    goto exception;
45450
                /* XXX: could do this string conversion only when needed */
45451
0
                prop = JS_ToStringFree(ctx, JS_NewInt64(ctx, i));
45452
0
                if (JS_IsException(prop))
45453
0
                    goto exception;
45454
0
                v = js_json_check(ctx, jsc, val, v, prop);
45455
0
                JS_FreeValue(ctx, prop);
45456
0
                prop = JS_UNDEFINED;
45457
0
                if (JS_IsException(v))
45458
0
                    goto exception;
45459
0
                if (JS_IsUndefined(v))
45460
0
                    v = JS_NULL;
45461
0
                if (js_json_to_str(ctx, jsc, val, v, indent1))
45462
0
                    goto exception;
45463
0
            }
45464
0
            if (len > 0 && !JS_IsEmptyString(jsc->gap)) {
45465
0
                string_buffer_putc8(jsc->b, '\n');
45466
0
                string_buffer_concat_value(jsc->b, indent);
45467
0
            }
45468
0
            string_buffer_putc8(jsc->b, ']');
45469
0
        } else {
45470
0
            if (!JS_IsUndefined(jsc->property_list))
45471
0
                tab = JS_DupValue(ctx, jsc->property_list);
45472
0
            else
45473
0
                tab = js_object_keys(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val, JS_ITERATOR_KIND_KEY);
45474
0
            if (JS_IsException(tab))
45475
0
                goto exception;
45476
0
            if (js_get_length64(ctx, &len, tab))
45477
0
                goto exception;
45478
0
            string_buffer_putc8(jsc->b, '{');
45479
0
            has_content = FALSE;
45480
0
            for(i = 0; i < len; i++) {
45481
0
                JS_FreeValue(ctx, prop);
45482
0
                prop = JS_GetPropertyInt64(ctx, tab, i);
45483
0
                if (JS_IsException(prop))
45484
0
                    goto exception;
45485
0
                v = JS_GetPropertyValue(ctx, val, JS_DupValue(ctx, prop));
45486
0
                if (JS_IsException(v))
45487
0
                    goto exception;
45488
0
                v = js_json_check(ctx, jsc, val, v, prop);
45489
0
                if (JS_IsException(v))
45490
0
                    goto exception;
45491
0
                if (!JS_IsUndefined(v)) {
45492
0
                    if (has_content)
45493
0
                        string_buffer_putc8(jsc->b, ',');
45494
0
                    prop = JS_ToQuotedStringFree(ctx, prop);
45495
0
                    if (JS_IsException(prop)) {
45496
0
                        JS_FreeValue(ctx, v);
45497
0
                        goto exception;
45498
0
                    }
45499
0
                    string_buffer_concat_value(jsc->b, sep);
45500
0
                    string_buffer_concat_value(jsc->b, prop);
45501
0
                    string_buffer_putc8(jsc->b, ':');
45502
0
                    string_buffer_concat_value(jsc->b, sep1);
45503
0
                    if (js_json_to_str(ctx, jsc, val, v, indent1))
45504
0
                        goto exception;
45505
0
                    has_content = TRUE;
45506
0
                }
45507
0
            }
45508
0
            if (has_content && !JS_IsEmptyString(jsc->gap)) {
45509
0
                string_buffer_putc8(jsc->b, '\n');
45510
0
                string_buffer_concat_value(jsc->b, indent);
45511
0
            }
45512
0
            string_buffer_putc8(jsc->b, '}');
45513
0
        }
45514
0
        if (check_exception_free(ctx, js_array_pop(ctx, jsc->stack, 0, NULL, 0)))
45515
0
            goto exception;
45516
0
        JS_FreeValue(ctx, val);
45517
0
        JS_FreeValue(ctx, tab);
45518
0
        JS_FreeValue(ctx, sep);
45519
0
        JS_FreeValue(ctx, sep1);
45520
0
        JS_FreeValue(ctx, indent1);
45521
0
        JS_FreeValue(ctx, prop);
45522
0
        return 0;
45523
0
    }
45524
0
 concat_primitive:
45525
0
    switch (JS_VALUE_GET_NORM_TAG(val)) {
45526
0
    case JS_TAG_STRING:
45527
0
        val = JS_ToQuotedStringFree(ctx, val);
45528
0
        if (JS_IsException(val))
45529
0
            goto exception;
45530
0
        goto concat_value;
45531
0
    case JS_TAG_FLOAT64:
45532
0
        if (!isfinite(JS_VALUE_GET_FLOAT64(val))) {
45533
0
            val = JS_NULL;
45534
0
        }
45535
0
        goto concat_value;
45536
0
    case JS_TAG_INT:
45537
0
    case JS_TAG_BOOL:
45538
0
    case JS_TAG_NULL:
45539
0
    concat_value:
45540
0
        return string_buffer_concat_value_free(jsc->b, val);
45541
0
    case JS_TAG_BIG_INT:
45542
0
#ifdef CONFIG_BIGNUM
45543
0
    case JS_TAG_BIG_FLOAT:
45544
0
    case JS_TAG_BIG_DECIMAL:
45545
0
#endif
45546
        /* reject big numbers: use toJSON method to override */
45547
0
        JS_ThrowTypeError(ctx, "Do not know how to serialize a BigInt");
45548
0
        goto exception;
45549
0
    default:
45550
0
        JS_FreeValue(ctx, val);
45551
0
        return 0;
45552
0
    }
45553
45554
0
exception:
45555
0
    JS_FreeValue(ctx, val);
45556
0
    JS_FreeValue(ctx, tab);
45557
0
    JS_FreeValue(ctx, sep);
45558
0
    JS_FreeValue(ctx, sep1);
45559
0
    JS_FreeValue(ctx, indent1);
45560
0
    JS_FreeValue(ctx, prop);
45561
0
    return -1;
45562
0
}
45563
45564
JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
45565
                         JSValueConst replacer, JSValueConst space0)
45566
0
{
45567
0
    StringBuffer b_s;
45568
0
    JSONStringifyContext jsc_s, *jsc = &jsc_s;
45569
0
    JSValue val, v, space, ret, wrapper;
45570
0
    int res;
45571
0
    int64_t i, j, n;
45572
45573
0
    jsc->replacer_func = JS_UNDEFINED;
45574
0
    jsc->stack = JS_UNDEFINED;
45575
0
    jsc->property_list = JS_UNDEFINED;
45576
0
    jsc->gap = JS_UNDEFINED;
45577
0
    jsc->b = &b_s;
45578
0
    jsc->empty = JS_AtomToString(ctx, JS_ATOM_empty_string);
45579
0
    ret = JS_UNDEFINED;
45580
0
    wrapper = JS_UNDEFINED;
45581
45582
0
    string_buffer_init(ctx, jsc->b, 0);
45583
0
    jsc->stack = JS_NewArray(ctx);
45584
0
    if (JS_IsException(jsc->stack))
45585
0
        goto exception;
45586
0
    if (JS_IsFunction(ctx, replacer)) {
45587
0
        jsc->replacer_func = replacer;
45588
0
    } else {
45589
0
        res = JS_IsArray(ctx, replacer);
45590
0
        if (res < 0)
45591
0
            goto exception;
45592
0
        if (res) {
45593
            /* XXX: enumeration is not fully correct */
45594
0
            jsc->property_list = JS_NewArray(ctx);
45595
0
            if (JS_IsException(jsc->property_list))
45596
0
                goto exception;
45597
0
            if (js_get_length64(ctx, &n, replacer))
45598
0
                goto exception;
45599
0
            for (i = j = 0; i < n; i++) {
45600
0
                JSValue present;
45601
0
                v = JS_GetPropertyInt64(ctx, replacer, i);
45602
0
                if (JS_IsException(v))
45603
0
                    goto exception;
45604
0
                if (JS_IsObject(v)) {
45605
0
                    JSObject *p = JS_VALUE_GET_OBJ(v);
45606
0
                    if (p->class_id == JS_CLASS_STRING ||
45607
0
                        p->class_id == JS_CLASS_NUMBER) {
45608
0
                        v = JS_ToStringFree(ctx, v);
45609
0
                        if (JS_IsException(v))
45610
0
                            goto exception;
45611
0
                    } else {
45612
0
                        JS_FreeValue(ctx, v);
45613
0
                        continue;
45614
0
                    }
45615
0
                } else if (JS_IsNumber(v)) {
45616
0
                    v = JS_ToStringFree(ctx, v);
45617
0
                    if (JS_IsException(v))
45618
0
                        goto exception;
45619
0
                } else if (!JS_IsString(v)) {
45620
0
                    JS_FreeValue(ctx, v);
45621
0
                    continue;
45622
0
                }
45623
0
                present = js_array_includes(ctx, jsc->property_list,
45624
0
                                            1, (JSValueConst *)&v);
45625
0
                if (JS_IsException(present)) {
45626
0
                    JS_FreeValue(ctx, v);
45627
0
                    goto exception;
45628
0
                }
45629
0
                if (!JS_ToBoolFree(ctx, present)) {
45630
0
                    JS_SetPropertyInt64(ctx, jsc->property_list, j++, v);
45631
0
                } else {
45632
0
                    JS_FreeValue(ctx, v);
45633
0
                }
45634
0
            }
45635
0
        }
45636
0
    }
45637
0
    space = JS_DupValue(ctx, space0);
45638
0
    if (JS_IsObject(space)) {
45639
0
        JSObject *p = JS_VALUE_GET_OBJ(space);
45640
0
        if (p->class_id == JS_CLASS_NUMBER) {
45641
0
            space = JS_ToNumberFree(ctx, space);
45642
0
        } else if (p->class_id == JS_CLASS_STRING) {
45643
0
            space = JS_ToStringFree(ctx, space);
45644
0
        }
45645
0
        if (JS_IsException(space)) {
45646
0
            JS_FreeValue(ctx, space);
45647
0
            goto exception;
45648
0
        }
45649
0
    }
45650
0
    if (JS_IsNumber(space)) {
45651
0
        int n;
45652
0
        if (JS_ToInt32Clamp(ctx, &n, space, 0, 10, 0))
45653
0
            goto exception;
45654
0
        jsc->gap = JS_NewStringLen(ctx, "          ", n);
45655
0
    } else if (JS_IsString(space)) {
45656
0
        JSString *p = JS_VALUE_GET_STRING(space);
45657
0
        jsc->gap = js_sub_string(ctx, p, 0, min_int(p->len, 10));
45658
0
    } else {
45659
0
        jsc->gap = JS_DupValue(ctx, jsc->empty);
45660
0
    }
45661
0
    JS_FreeValue(ctx, space);
45662
0
    if (JS_IsException(jsc->gap))
45663
0
        goto exception;
45664
0
    wrapper = JS_NewObject(ctx);
45665
0
    if (JS_IsException(wrapper))
45666
0
        goto exception;
45667
0
    if (JS_DefinePropertyValue(ctx, wrapper, JS_ATOM_empty_string,
45668
0
                               JS_DupValue(ctx, obj), JS_PROP_C_W_E) < 0)
45669
0
        goto exception;
45670
0
    val = JS_DupValue(ctx, obj);
45671
45672
0
    val = js_json_check(ctx, jsc, wrapper, val, jsc->empty);
45673
0
    if (JS_IsException(val))
45674
0
        goto exception;
45675
0
    if (JS_IsUndefined(val)) {
45676
0
        ret = JS_UNDEFINED;
45677
0
        goto done1;
45678
0
    }
45679
0
    if (js_json_to_str(ctx, jsc, wrapper, val, jsc->empty))
45680
0
        goto exception;
45681
45682
0
    ret = string_buffer_end(jsc->b);
45683
0
    goto done;
45684
45685
0
exception:
45686
0
    ret = JS_EXCEPTION;
45687
0
done1:
45688
0
    string_buffer_free(jsc->b);
45689
0
done:
45690
0
    JS_FreeValue(ctx, wrapper);
45691
0
    JS_FreeValue(ctx, jsc->empty);
45692
0
    JS_FreeValue(ctx, jsc->gap);
45693
0
    JS_FreeValue(ctx, jsc->property_list);
45694
0
    JS_FreeValue(ctx, jsc->stack);
45695
0
    return ret;
45696
0
}
45697
45698
static JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val,
45699
                                 int argc, JSValueConst *argv)
45700
0
{
45701
    // stringify(val, replacer, space)
45702
0
    return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]);
45703
0
}
45704
45705
static const JSCFunctionListEntry js_json_funcs[] = {
45706
    JS_CFUNC_DEF("parse", 2, js_json_parse ),
45707
    JS_CFUNC_DEF("stringify", 3, js_json_stringify ),
45708
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "JSON", JS_PROP_CONFIGURABLE ),
45709
};
45710
45711
static const JSCFunctionListEntry js_json_obj[] = {
45712
    JS_OBJECT_DEF("JSON", js_json_funcs, countof(js_json_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
45713
};
45714
45715
void JS_AddIntrinsicJSON(JSContext *ctx)
45716
39
{
45717
    /* add JSON as autoinit object */
45718
39
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_json_obj, countof(js_json_obj));
45719
39
}
45720
45721
/* Reflect */
45722
45723
static JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val,
45724
                                int argc, JSValueConst *argv)
45725
0
{
45726
0
    return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2);
45727
0
}
45728
45729
static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
45730
                                    int argc, JSValueConst *argv)
45731
0
{
45732
0
    JSValueConst func, array_arg, new_target;
45733
0
    JSValue *tab, ret;
45734
0
    uint32_t len;
45735
45736
0
    func = argv[0];
45737
0
    array_arg = argv[1];
45738
0
    if (argc > 2) {
45739
0
        new_target = argv[2];
45740
0
        if (!JS_IsConstructor(ctx, new_target))
45741
0
            return JS_ThrowTypeError(ctx, "not a constructor");
45742
0
    } else {
45743
0
        new_target = func;
45744
0
    }
45745
0
    tab = build_arg_list(ctx, &len, array_arg);
45746
0
    if (!tab)
45747
0
        return JS_EXCEPTION;
45748
0
    ret = JS_CallConstructor2(ctx, func, new_target, len, (JSValueConst *)tab);
45749
0
    free_arg_list(ctx, tab, len);
45750
0
    return ret;
45751
0
}
45752
45753
static JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val,
45754
                                         int argc, JSValueConst *argv)
45755
0
{
45756
0
    JSValueConst obj;
45757
0
    JSAtom atom;
45758
0
    int ret;
45759
45760
0
    obj = argv[0];
45761
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
45762
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45763
0
    atom = JS_ValueToAtom(ctx, argv[1]);
45764
0
    if (unlikely(atom == JS_ATOM_NULL))
45765
0
        return JS_EXCEPTION;
45766
0
    ret = JS_DeleteProperty(ctx, obj, atom, 0);
45767
0
    JS_FreeAtom(ctx, atom);
45768
0
    if (ret < 0)
45769
0
        return JS_EXCEPTION;
45770
0
    else
45771
0
        return JS_NewBool(ctx, ret);
45772
0
}
45773
45774
static JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val,
45775
                              int argc, JSValueConst *argv)
45776
0
{
45777
0
    JSValueConst obj, prop, receiver;
45778
0
    JSAtom atom;
45779
0
    JSValue ret;
45780
45781
0
    obj = argv[0];
45782
0
    prop = argv[1];
45783
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
45784
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45785
0
    if (argc > 2)
45786
0
        receiver = argv[2];
45787
0
    else
45788
0
        receiver = obj;
45789
0
    atom = JS_ValueToAtom(ctx, prop);
45790
0
    if (unlikely(atom == JS_ATOM_NULL))
45791
0
        return JS_EXCEPTION;
45792
0
    ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, FALSE);
45793
0
    JS_FreeAtom(ctx, atom);
45794
0
    return ret;
45795
0
}
45796
45797
static JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val,
45798
                              int argc, JSValueConst *argv)
45799
0
{
45800
0
    JSValueConst obj, prop;
45801
0
    JSAtom atom;
45802
0
    int ret;
45803
45804
0
    obj = argv[0];
45805
0
    prop = argv[1];
45806
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
45807
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45808
0
    atom = JS_ValueToAtom(ctx, prop);
45809
0
    if (unlikely(atom == JS_ATOM_NULL))
45810
0
        return JS_EXCEPTION;
45811
0
    ret = JS_HasProperty(ctx, obj, atom);
45812
0
    JS_FreeAtom(ctx, atom);
45813
0
    if (ret < 0)
45814
0
        return JS_EXCEPTION;
45815
0
    else
45816
0
        return JS_NewBool(ctx, ret);
45817
0
}
45818
45819
static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
45820
                              int argc, JSValueConst *argv)
45821
0
{
45822
0
    JSValueConst obj, prop, val, receiver;
45823
0
    int ret;
45824
0
    JSAtom atom;
45825
45826
0
    obj = argv[0];
45827
0
    prop = argv[1];
45828
0
    val = argv[2];
45829
0
    if (argc > 3)
45830
0
        receiver = argv[3];
45831
0
    else
45832
0
        receiver = obj;
45833
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
45834
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45835
0
    atom = JS_ValueToAtom(ctx, prop);
45836
0
    if (unlikely(atom == JS_ATOM_NULL))
45837
0
        return JS_EXCEPTION;
45838
0
    ret = JS_SetPropertyInternal(ctx, obj, atom,
45839
0
                                 JS_DupValue(ctx, val), receiver, 0);
45840
0
    JS_FreeAtom(ctx, atom);
45841
0
    if (ret < 0)
45842
0
        return JS_EXCEPTION;
45843
0
    else
45844
0
        return JS_NewBool(ctx, ret);
45845
0
}
45846
45847
static JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
45848
                                         int argc, JSValueConst *argv)
45849
0
{
45850
0
    int ret;
45851
0
    ret = JS_SetPrototypeInternal(ctx, argv[0], argv[1], FALSE);
45852
0
    if (ret < 0)
45853
0
        return JS_EXCEPTION;
45854
0
    else
45855
0
        return JS_NewBool(ctx, ret);
45856
0
}
45857
45858
static JSValue js_reflect_ownKeys(JSContext *ctx, JSValueConst this_val,
45859
                                  int argc, JSValueConst *argv)
45860
0
{
45861
0
    if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
45862
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45863
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
45864
0
                                   JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK,
45865
0
                                   JS_ITERATOR_KIND_KEY);
45866
0
}
45867
45868
static const JSCFunctionListEntry js_reflect_funcs[] = {
45869
    JS_CFUNC_DEF("apply", 3, js_reflect_apply ),
45870
    JS_CFUNC_DEF("construct", 2, js_reflect_construct ),
45871
    JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 1 ),
45872
    JS_CFUNC_DEF("deleteProperty", 2, js_reflect_deleteProperty ),
45873
    JS_CFUNC_DEF("get", 2, js_reflect_get ),
45874
    JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 1 ),
45875
    JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 1 ),
45876
    JS_CFUNC_DEF("has", 2, js_reflect_has ),
45877
    JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 1 ),
45878
    JS_CFUNC_DEF("ownKeys", 1, js_reflect_ownKeys ),
45879
    JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 1 ),
45880
    JS_CFUNC_DEF("set", 3, js_reflect_set ),
45881
    JS_CFUNC_DEF("setPrototypeOf", 2, js_reflect_setPrototypeOf ),
45882
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Reflect", JS_PROP_CONFIGURABLE ),
45883
};
45884
45885
static const JSCFunctionListEntry js_reflect_obj[] = {
45886
    JS_OBJECT_DEF("Reflect", js_reflect_funcs, countof(js_reflect_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
45887
};
45888
45889
/* Proxy */
45890
45891
static void js_proxy_finalizer(JSRuntime *rt, JSValue val)
45892
0
{
45893
0
    JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
45894
0
    if (s) {
45895
0
        JS_FreeValueRT(rt, s->target);
45896
0
        JS_FreeValueRT(rt, s->handler);
45897
0
        js_free_rt(rt, s);
45898
0
    }
45899
0
}
45900
45901
static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
45902
                          JS_MarkFunc *mark_func)
45903
0
{
45904
0
    JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
45905
0
    if (s) {
45906
0
        JS_MarkValue(rt, s->target, mark_func);
45907
0
        JS_MarkValue(rt, s->handler, mark_func);
45908
0
    }
45909
0
}
45910
45911
static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx)
45912
0
{
45913
0
    return JS_ThrowTypeError(ctx, "revoked proxy");
45914
0
}
45915
45916
static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod,
45917
                                     JSValueConst obj, JSAtom name)
45918
0
{
45919
0
    JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
45920
0
    JSValue method;
45921
45922
    /* safer to test recursion in all proxy methods */
45923
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
45924
0
        JS_ThrowStackOverflow(ctx);
45925
0
        return NULL;
45926
0
    }
45927
45928
    /* 's' should never be NULL */
45929
0
    if (s->is_revoked) {
45930
0
        JS_ThrowTypeErrorRevokedProxy(ctx);
45931
0
        return NULL;
45932
0
    }
45933
0
    method = JS_GetProperty(ctx, s->handler, name);
45934
0
    if (JS_IsException(method))
45935
0
        return NULL;
45936
0
    if (JS_IsNull(method))
45937
0
        method = JS_UNDEFINED;
45938
0
    *pmethod = method;
45939
0
    return s;
45940
0
}
45941
45942
static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
45943
0
{
45944
0
    JSProxyData *s;
45945
0
    JSValue method, ret, proto1;
45946
0
    int res;
45947
45948
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_getPrototypeOf);
45949
0
    if (!s)
45950
0
        return JS_EXCEPTION;
45951
0
    if (JS_IsUndefined(method))
45952
0
        return JS_GetPrototype(ctx, s->target);
45953
0
    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
45954
0
    if (JS_IsException(ret))
45955
0
        return ret;
45956
0
    if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL &&
45957
0
        JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
45958
0
        goto fail;
45959
0
    }
45960
0
    res = JS_IsExtensible(ctx, s->target);
45961
0
    if (res < 0) {
45962
0
        JS_FreeValue(ctx, ret);
45963
0
        return JS_EXCEPTION;
45964
0
    }
45965
0
    if (!res) {
45966
        /* check invariant */
45967
0
        proto1 = JS_GetPrototype(ctx, s->target);
45968
0
        if (JS_IsException(proto1)) {
45969
0
            JS_FreeValue(ctx, ret);
45970
0
            return JS_EXCEPTION;
45971
0
        }
45972
0
        if (JS_VALUE_GET_OBJ(proto1) != JS_VALUE_GET_OBJ(ret)) {
45973
0
            JS_FreeValue(ctx, proto1);
45974
0
        fail:
45975
0
            JS_FreeValue(ctx, ret);
45976
0
            return JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
45977
0
        }
45978
0
        JS_FreeValue(ctx, proto1);
45979
0
    }
45980
0
    return ret;
45981
0
}
45982
45983
static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
45984
                                   JSValueConst proto_val, BOOL throw_flag)
45985
0
{
45986
0
    JSProxyData *s;
45987
0
    JSValue method, ret, proto1;
45988
0
    JSValueConst args[2];
45989
0
    BOOL res;
45990
0
    int res2;
45991
45992
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_setPrototypeOf);
45993
0
    if (!s)
45994
0
        return -1;
45995
0
    if (JS_IsUndefined(method))
45996
0
        return JS_SetPrototypeInternal(ctx, s->target, proto_val, throw_flag);
45997
0
    args[0] = s->target;
45998
0
    args[1] = proto_val;
45999
0
    ret = JS_CallFree(ctx, method, s->handler, 2, args);
46000
0
    if (JS_IsException(ret))
46001
0
        return -1;
46002
0
    res = JS_ToBoolFree(ctx, ret);
46003
0
    if (!res) {
46004
0
        if (throw_flag) {
46005
0
            JS_ThrowTypeError(ctx, "proxy: bad prototype");
46006
0
            return -1;
46007
0
        } else {
46008
0
            return FALSE;
46009
0
        }
46010
0
    }
46011
0
    res2 = JS_IsExtensible(ctx, s->target);
46012
0
    if (res2 < 0)
46013
0
        return -1;
46014
0
    if (!res2) {
46015
0
        proto1 = JS_GetPrototype(ctx, s->target);
46016
0
        if (JS_IsException(proto1))
46017
0
            return -1;
46018
0
        if (JS_VALUE_GET_OBJ(proto_val) != JS_VALUE_GET_OBJ(proto1)) {
46019
0
            JS_FreeValue(ctx, proto1);
46020
0
            JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
46021
0
            return -1;
46022
0
        }
46023
0
        JS_FreeValue(ctx, proto1);
46024
0
    }
46025
0
    return TRUE;
46026
0
}
46027
46028
static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj)
46029
0
{
46030
0
    JSProxyData *s;
46031
0
    JSValue method, ret;
46032
0
    BOOL res;
46033
0
    int res2;
46034
46035
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_isExtensible);
46036
0
    if (!s)
46037
0
        return -1;
46038
0
    if (JS_IsUndefined(method))
46039
0
        return JS_IsExtensible(ctx, s->target);
46040
0
    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
46041
0
    if (JS_IsException(ret))
46042
0
        return -1;
46043
0
    res = JS_ToBoolFree(ctx, ret);
46044
0
    res2 = JS_IsExtensible(ctx, s->target);
46045
0
    if (res2 < 0)
46046
0
        return res2;
46047
0
    if (res != res2) {
46048
0
        JS_ThrowTypeError(ctx, "proxy: inconsistent isExtensible");
46049
0
        return -1;
46050
0
    }
46051
0
    return res;
46052
0
}
46053
46054
static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj)
46055
0
{
46056
0
    JSProxyData *s;
46057
0
    JSValue method, ret;
46058
0
    BOOL res;
46059
0
    int res2;
46060
46061
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_preventExtensions);
46062
0
    if (!s)
46063
0
        return -1;
46064
0
    if (JS_IsUndefined(method))
46065
0
        return JS_PreventExtensions(ctx, s->target);
46066
0
    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
46067
0
    if (JS_IsException(ret))
46068
0
        return -1;
46069
0
    res = JS_ToBoolFree(ctx, ret);
46070
0
    if (res) {
46071
0
        res2 = JS_IsExtensible(ctx, s->target);
46072
0
        if (res2 < 0)
46073
0
            return res2;
46074
0
        if (res2) {
46075
0
            JS_ThrowTypeError(ctx, "proxy: inconsistent preventExtensions");
46076
0
            return -1;
46077
0
        }
46078
0
    }
46079
0
    return res;
46080
0
}
46081
46082
static int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
46083
0
{
46084
0
    JSProxyData *s;
46085
0
    JSValue method, ret1, atom_val;
46086
0
    int ret, res;
46087
0
    JSObject *p;
46088
0
    JSValueConst args[2];
46089
0
    BOOL res2;
46090
46091
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_has);
46092
0
    if (!s)
46093
0
        return -1;
46094
0
    if (JS_IsUndefined(method))
46095
0
        return JS_HasProperty(ctx, s->target, atom);
46096
0
    atom_val = JS_AtomToValue(ctx, atom);
46097
0
    if (JS_IsException(atom_val)) {
46098
0
        JS_FreeValue(ctx, method);
46099
0
        return -1;
46100
0
    }
46101
0
    args[0] = s->target;
46102
0
    args[1] = atom_val;
46103
0
    ret1 = JS_CallFree(ctx, method, s->handler, 2, args);
46104
0
    JS_FreeValue(ctx, atom_val);
46105
0
    if (JS_IsException(ret1))
46106
0
        return -1;
46107
0
    ret = JS_ToBoolFree(ctx, ret1);
46108
0
    if (!ret) {
46109
0
        JSPropertyDescriptor desc;
46110
0
        p = JS_VALUE_GET_OBJ(s->target);
46111
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
46112
0
        if (res < 0)
46113
0
            return -1;
46114
0
        if (res) {
46115
0
            res2 = !(desc.flags & JS_PROP_CONFIGURABLE);
46116
0
            js_free_desc(ctx, &desc);
46117
0
            if (res2 || !p->extensible) {
46118
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent has");
46119
0
                return -1;
46120
0
            }
46121
0
        }
46122
0
    }
46123
0
    return ret;
46124
0
}
46125
46126
static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,
46127
                            JSValueConst receiver)
46128
0
{
46129
0
    JSProxyData *s;
46130
0
    JSValue method, ret, atom_val;
46131
0
    int res;
46132
0
    JSValueConst args[3];
46133
0
    JSPropertyDescriptor desc;
46134
46135
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_get);
46136
0
    if (!s)
46137
0
        return JS_EXCEPTION;
46138
    /* Note: recursion is possible thru the prototype of s->target */
46139
0
    if (JS_IsUndefined(method))
46140
0
        return JS_GetPropertyInternal(ctx, s->target, atom, receiver, FALSE);
46141
0
    atom_val = JS_AtomToValue(ctx, atom);
46142
0
    if (JS_IsException(atom_val)) {
46143
0
        JS_FreeValue(ctx, method);
46144
0
        return JS_EXCEPTION;
46145
0
    }
46146
0
    args[0] = s->target;
46147
0
    args[1] = atom_val;
46148
0
    args[2] = receiver;
46149
0
    ret = JS_CallFree(ctx, method, s->handler, 3, args);
46150
0
    JS_FreeValue(ctx, atom_val);
46151
0
    if (JS_IsException(ret))
46152
0
        return JS_EXCEPTION;
46153
0
    res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
46154
0
    if (res < 0)
46155
0
        return JS_EXCEPTION;
46156
0
    if (res) {
46157
0
        if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
46158
0
            if (!js_same_value(ctx, desc.value, ret)) {
46159
0
                goto fail;
46160
0
            }
46161
0
        } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET) {
46162
0
            if (JS_IsUndefined(desc.getter) && !JS_IsUndefined(ret)) {
46163
0
            fail:
46164
0
                js_free_desc(ctx, &desc);
46165
0
                JS_FreeValue(ctx, ret);
46166
0
                return JS_ThrowTypeError(ctx, "proxy: inconsistent get");
46167
0
            }
46168
0
        }
46169
0
        js_free_desc(ctx, &desc);
46170
0
    }
46171
0
    return ret;
46172
0
}
46173
46174
static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
46175
                        JSValueConst value, JSValueConst receiver, int flags)
46176
0
{
46177
0
    JSProxyData *s;
46178
0
    JSValue method, ret1, atom_val;
46179
0
    int ret, res;
46180
0
    JSValueConst args[4];
46181
46182
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_set);
46183
0
    if (!s)
46184
0
        return -1;
46185
0
    if (JS_IsUndefined(method)) {
46186
0
        return JS_SetPropertyInternal(ctx, s->target, atom,
46187
0
                                      JS_DupValue(ctx, value), receiver,
46188
0
                                      flags);
46189
0
    }
46190
0
    atom_val = JS_AtomToValue(ctx, atom);
46191
0
    if (JS_IsException(atom_val)) {
46192
0
        JS_FreeValue(ctx, method);
46193
0
        return -1;
46194
0
    }
46195
0
    args[0] = s->target;
46196
0
    args[1] = atom_val;
46197
0
    args[2] = value;
46198
0
    args[3] = receiver;
46199
0
    ret1 = JS_CallFree(ctx, method, s->handler, 4, args);
46200
0
    JS_FreeValue(ctx, atom_val);
46201
0
    if (JS_IsException(ret1))
46202
0
        return -1;
46203
0
    ret = JS_ToBoolFree(ctx, ret1);
46204
0
    if (ret) {
46205
0
        JSPropertyDescriptor desc;
46206
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
46207
0
        if (res < 0)
46208
0
            return -1;
46209
0
        if (res) {
46210
0
            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
46211
0
                if (!js_same_value(ctx, desc.value, value)) {
46212
0
                    goto fail;
46213
0
                }
46214
0
            } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET && JS_IsUndefined(desc.setter)) {
46215
0
                fail:
46216
0
                    js_free_desc(ctx, &desc);
46217
0
                    JS_ThrowTypeError(ctx, "proxy: inconsistent set");
46218
0
                    return -1;
46219
0
            }
46220
0
            js_free_desc(ctx, &desc);
46221
0
        }
46222
0
    } else {
46223
0
        if ((flags & JS_PROP_THROW) ||
46224
0
            ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
46225
0
            JS_ThrowTypeError(ctx, "proxy: cannot set property");
46226
0
            return -1;
46227
0
        }
46228
0
    }
46229
0
    return ret;
46230
0
}
46231
46232
static JSValue js_create_desc(JSContext *ctx, JSValueConst val,
46233
                              JSValueConst getter, JSValueConst setter,
46234
                              int flags)
46235
0
{
46236
0
    JSValue ret;
46237
0
    ret = JS_NewObject(ctx);
46238
0
    if (JS_IsException(ret))
46239
0
        return ret;
46240
0
    if (flags & JS_PROP_HAS_GET) {
46241
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, getter),
46242
0
                               JS_PROP_C_W_E);
46243
0
    }
46244
0
    if (flags & JS_PROP_HAS_SET) {
46245
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, setter),
46246
0
                               JS_PROP_C_W_E);
46247
0
    }
46248
0
    if (flags & JS_PROP_HAS_VALUE) {
46249
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, val),
46250
0
                               JS_PROP_C_W_E);
46251
0
    }
46252
0
    if (flags & JS_PROP_HAS_WRITABLE) {
46253
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
46254
0
                               JS_NewBool(ctx, flags & JS_PROP_WRITABLE),
46255
0
                               JS_PROP_C_W_E);
46256
0
    }
46257
0
    if (flags & JS_PROP_HAS_ENUMERABLE) {
46258
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
46259
0
                               JS_NewBool(ctx, flags & JS_PROP_ENUMERABLE),
46260
0
                               JS_PROP_C_W_E);
46261
0
    }
46262
0
    if (flags & JS_PROP_HAS_CONFIGURABLE) {
46263
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
46264
0
                               JS_NewBool(ctx, flags & JS_PROP_CONFIGURABLE),
46265
0
                               JS_PROP_C_W_E);
46266
0
    }
46267
0
    return ret;
46268
0
}
46269
46270
static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc,
46271
                                     JSValueConst obj, JSAtom prop)
46272
0
{
46273
0
    JSProxyData *s;
46274
0
    JSValue method, trap_result_obj, prop_val;
46275
0
    int res, target_desc_ret, ret;
46276
0
    JSObject *p;
46277
0
    JSValueConst args[2];
46278
0
    JSPropertyDescriptor result_desc, target_desc;
46279
46280
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_getOwnPropertyDescriptor);
46281
0
    if (!s)
46282
0
        return -1;
46283
0
    p = JS_VALUE_GET_OBJ(s->target);
46284
0
    if (JS_IsUndefined(method)) {
46285
0
        return JS_GetOwnPropertyInternal(ctx, pdesc, p, prop);
46286
0
    }
46287
0
    prop_val = JS_AtomToValue(ctx, prop);
46288
0
    if (JS_IsException(prop_val)) {
46289
0
        JS_FreeValue(ctx, method);
46290
0
        return -1;
46291
0
    }
46292
0
    args[0] = s->target;
46293
0
    args[1] = prop_val;
46294
0
    trap_result_obj = JS_CallFree(ctx, method, s->handler, 2, args);
46295
0
    JS_FreeValue(ctx, prop_val);
46296
0
    if (JS_IsException(trap_result_obj))
46297
0
        return -1;
46298
0
    if (!JS_IsObject(trap_result_obj) && !JS_IsUndefined(trap_result_obj)) {
46299
0
        JS_FreeValue(ctx, trap_result_obj);
46300
0
        goto fail;
46301
0
    }
46302
0
    target_desc_ret = JS_GetOwnPropertyInternal(ctx, &target_desc, p, prop);
46303
0
    if (target_desc_ret < 0) {
46304
0
        JS_FreeValue(ctx, trap_result_obj);
46305
0
        return -1;
46306
0
    }
46307
0
    if (target_desc_ret)
46308
0
        js_free_desc(ctx, &target_desc);
46309
0
    if (JS_IsUndefined(trap_result_obj)) {
46310
0
        if (target_desc_ret) {
46311
0
            if (!(target_desc.flags & JS_PROP_CONFIGURABLE) || !p->extensible)
46312
0
                goto fail;
46313
0
        }
46314
0
        ret = FALSE;
46315
0
    } else {
46316
0
        int flags1, extensible_target;
46317
0
        extensible_target = JS_IsExtensible(ctx, s->target);
46318
0
        if (extensible_target < 0) {
46319
0
            JS_FreeValue(ctx, trap_result_obj);
46320
0
            return -1;
46321
0
        }
46322
0
        res = js_obj_to_desc(ctx, &result_desc, trap_result_obj);
46323
0
        JS_FreeValue(ctx, trap_result_obj);
46324
0
        if (res < 0)
46325
0
            return -1;
46326
46327
0
        if (target_desc_ret) {
46328
            /* convert result_desc.flags to defineProperty flags */
46329
0
            flags1 = result_desc.flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE;
46330
0
            if (result_desc.flags & JS_PROP_GETSET)
46331
0
                flags1 |= JS_PROP_HAS_GET | JS_PROP_HAS_SET;
46332
0
            else
46333
0
                flags1 |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE;
46334
            /* XXX: not complete check: need to compare value &
46335
               getter/setter as in defineproperty */
46336
0
            if (!check_define_prop_flags(target_desc.flags, flags1))
46337
0
                goto fail1;
46338
0
        } else {
46339
0
            if (!extensible_target)
46340
0
                goto fail1;
46341
0
        }
46342
0
        if (!(result_desc.flags & JS_PROP_CONFIGURABLE)) {
46343
0
            if (!target_desc_ret || (target_desc.flags & JS_PROP_CONFIGURABLE))
46344
0
                goto fail1;
46345
0
            if ((result_desc.flags &
46346
0
                 (JS_PROP_GETSET | JS_PROP_WRITABLE)) == 0 &&
46347
0
                target_desc_ret &&
46348
0
                (target_desc.flags & JS_PROP_WRITABLE) != 0) {
46349
                /* proxy-missing-checks */
46350
0
            fail1:
46351
0
                js_free_desc(ctx, &result_desc);
46352
0
            fail:
46353
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent getOwnPropertyDescriptor");
46354
0
                return -1;
46355
0
            }
46356
0
        }
46357
0
        ret = TRUE;
46358
0
        if (pdesc) {
46359
0
            *pdesc = result_desc;
46360
0
        } else {
46361
0
            js_free_desc(ctx, &result_desc);
46362
0
        }
46363
0
    }
46364
0
    return ret;
46365
0
}
46366
46367
static int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj,
46368
                                        JSAtom prop, JSValueConst val,
46369
                                        JSValueConst getter, JSValueConst setter,
46370
                                        int flags)
46371
0
{
46372
0
    JSProxyData *s;
46373
0
    JSValue method, ret1, prop_val, desc_val;
46374
0
    int res, ret;
46375
0
    JSObject *p;
46376
0
    JSValueConst args[3];
46377
0
    JSPropertyDescriptor desc;
46378
0
    BOOL setting_not_configurable;
46379
46380
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_defineProperty);
46381
0
    if (!s)
46382
0
        return -1;
46383
0
    if (JS_IsUndefined(method)) {
46384
0
        return JS_DefineProperty(ctx, s->target, prop, val, getter, setter, flags);
46385
0
    }
46386
0
    prop_val = JS_AtomToValue(ctx, prop);
46387
0
    if (JS_IsException(prop_val)) {
46388
0
        JS_FreeValue(ctx, method);
46389
0
        return -1;
46390
0
    }
46391
0
    desc_val = js_create_desc(ctx, val, getter, setter, flags);
46392
0
    if (JS_IsException(desc_val)) {
46393
0
        JS_FreeValue(ctx, prop_val);
46394
0
        JS_FreeValue(ctx, method);
46395
0
        return -1;
46396
0
    }
46397
0
    args[0] = s->target;
46398
0
    args[1] = prop_val;
46399
0
    args[2] = desc_val;
46400
0
    ret1 = JS_CallFree(ctx, method, s->handler, 3, args);
46401
0
    JS_FreeValue(ctx, prop_val);
46402
0
    JS_FreeValue(ctx, desc_val);
46403
0
    if (JS_IsException(ret1))
46404
0
        return -1;
46405
0
    ret = JS_ToBoolFree(ctx, ret1);
46406
0
    if (!ret) {
46407
0
        if (flags & JS_PROP_THROW) {
46408
0
            JS_ThrowTypeError(ctx, "proxy: defineProperty exception");
46409
0
            return -1;
46410
0
        } else {
46411
0
            return 0;
46412
0
        }
46413
0
    }
46414
0
    p = JS_VALUE_GET_OBJ(s->target);
46415
0
    res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
46416
0
    if (res < 0)
46417
0
        return -1;
46418
0
    setting_not_configurable = ((flags & (JS_PROP_HAS_CONFIGURABLE |
46419
0
                                          JS_PROP_CONFIGURABLE)) ==
46420
0
                                JS_PROP_HAS_CONFIGURABLE);
46421
0
    if (!res) {
46422
0
        if (!p->extensible || setting_not_configurable)
46423
0
            goto fail;
46424
0
    } else {
46425
0
        if (!check_define_prop_flags(desc.flags, flags) ||
46426
0
            ((desc.flags & JS_PROP_CONFIGURABLE) && setting_not_configurable)) {
46427
0
            goto fail1;
46428
0
        }
46429
0
        if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
46430
0
            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) ==
46431
0
                JS_PROP_GETSET) {
46432
0
                if ((flags & JS_PROP_HAS_GET) &&
46433
0
                    !js_same_value(ctx, getter, desc.getter)) {
46434
0
                    goto fail1;
46435
0
                }
46436
0
                if ((flags & JS_PROP_HAS_SET) &&
46437
0
                    !js_same_value(ctx, setter, desc.setter)) {
46438
0
                    goto fail1;
46439
0
                }
46440
0
            }
46441
0
        } else if (flags & JS_PROP_HAS_VALUE) {
46442
0
            if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) ==
46443
0
                JS_PROP_WRITABLE && !(flags & JS_PROP_WRITABLE)) {
46444
                /* missing-proxy-check feature */
46445
0
                goto fail1;
46446
0
            } else if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
46447
0
                !js_same_value(ctx, val, desc.value)) {
46448
0
                goto fail1;
46449
0
            }
46450
0
        }
46451
0
        if (flags & JS_PROP_HAS_WRITABLE) {
46452
0
            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE |
46453
0
                               JS_PROP_WRITABLE)) == JS_PROP_WRITABLE) {
46454
                /* proxy-missing-checks */
46455
0
            fail1:
46456
0
                js_free_desc(ctx, &desc);
46457
0
            fail:
46458
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent defineProperty");
46459
0
                return -1;
46460
0
            }
46461
0
        }
46462
0
        js_free_desc(ctx, &desc);
46463
0
    }
46464
0
    return 1;
46465
0
}
46466
46467
static int js_proxy_delete_property(JSContext *ctx, JSValueConst obj,
46468
                                    JSAtom atom)
46469
0
{
46470
0
    JSProxyData *s;
46471
0
    JSValue method, ret, atom_val;
46472
0
    int res, res2, is_extensible;
46473
0
    JSValueConst args[2];
46474
46475
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_deleteProperty);
46476
0
    if (!s)
46477
0
        return -1;
46478
0
    if (JS_IsUndefined(method)) {
46479
0
        return JS_DeleteProperty(ctx, s->target, atom, 0);
46480
0
    }
46481
0
    atom_val = JS_AtomToValue(ctx, atom);;
46482
0
    if (JS_IsException(atom_val)) {
46483
0
        JS_FreeValue(ctx, method);
46484
0
        return -1;
46485
0
    }
46486
0
    args[0] = s->target;
46487
0
    args[1] = atom_val;
46488
0
    ret = JS_CallFree(ctx, method, s->handler, 2, args);
46489
0
    JS_FreeValue(ctx, atom_val);
46490
0
    if (JS_IsException(ret))
46491
0
        return -1;
46492
0
    res = JS_ToBoolFree(ctx, ret);
46493
0
    if (res) {
46494
0
        JSPropertyDescriptor desc;
46495
0
        res2 = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
46496
0
        if (res2 < 0)
46497
0
            return -1;
46498
0
        if (res2) {
46499
0
            if (!(desc.flags & JS_PROP_CONFIGURABLE))
46500
0
                goto fail;
46501
0
            is_extensible = JS_IsExtensible(ctx, s->target);
46502
0
            if (is_extensible < 0)
46503
0
                goto fail1;
46504
0
            if (!is_extensible) {
46505
                /* proxy-missing-checks */
46506
0
            fail:
46507
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent deleteProperty");
46508
0
            fail1:
46509
0
                js_free_desc(ctx, &desc);
46510
0
                return -1;
46511
0
            }
46512
0
            js_free_desc(ctx, &desc);
46513
0
        }
46514
0
    }
46515
0
    return res;
46516
0
}
46517
46518
/* return the index of the property or -1 if not found */
46519
static int find_prop_key(const JSPropertyEnum *tab, int n, JSAtom atom)
46520
0
{
46521
0
    int i;
46522
0
    for(i = 0; i < n; i++) {
46523
0
        if (tab[i].atom == atom)
46524
0
            return i;
46525
0
    }
46526
0
    return -1;
46527
0
}
46528
46529
static int js_proxy_get_own_property_names(JSContext *ctx,
46530
                                           JSPropertyEnum **ptab,
46531
                                           uint32_t *plen,
46532
                                           JSValueConst obj)
46533
0
{
46534
0
    JSProxyData *s;
46535
0
    JSValue method, prop_array, val;
46536
0
    uint32_t len, i, len2;
46537
0
    JSPropertyEnum *tab, *tab2;
46538
0
    JSAtom atom;
46539
0
    JSPropertyDescriptor desc;
46540
0
    int res, is_extensible, idx;
46541
46542
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_ownKeys);
46543
0
    if (!s)
46544
0
        return -1;
46545
0
    if (JS_IsUndefined(method)) {
46546
0
        return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
46547
0
                                      JS_VALUE_GET_OBJ(s->target),
46548
0
                                      JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK);
46549
0
    }
46550
0
    prop_array = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
46551
0
    if (JS_IsException(prop_array))
46552
0
        return -1;
46553
0
    tab = NULL;
46554
0
    len = 0;
46555
0
    tab2 = NULL;
46556
0
    len2 = 0;
46557
0
    if (js_get_length32(ctx, &len, prop_array))
46558
0
        goto fail;
46559
0
    if (len > 0) {
46560
0
        tab = js_mallocz(ctx, sizeof(tab[0]) * len);
46561
0
        if (!tab)
46562
0
            goto fail;
46563
0
    }
46564
0
    for(i = 0; i < len; i++) {
46565
0
        val = JS_GetPropertyUint32(ctx, prop_array, i);
46566
0
        if (JS_IsException(val))
46567
0
            goto fail;
46568
0
        if (!JS_IsString(val) && !JS_IsSymbol(val)) {
46569
0
            JS_FreeValue(ctx, val);
46570
0
            JS_ThrowTypeError(ctx, "proxy: properties must be strings or symbols");
46571
0
            goto fail;
46572
0
        }
46573
0
        atom = JS_ValueToAtom(ctx, val);
46574
0
        JS_FreeValue(ctx, val);
46575
0
        if (atom == JS_ATOM_NULL)
46576
0
            goto fail;
46577
0
        tab[i].atom = atom;
46578
0
        tab[i].is_enumerable = FALSE; /* XXX: redundant? */
46579
0
    }
46580
46581
    /* check duplicate properties (XXX: inefficient, could store the
46582
     * properties an a temporary object to use the hash) */
46583
0
    for(i = 1; i < len; i++) {
46584
0
        if (find_prop_key(tab, i, tab[i].atom) >= 0) {
46585
0
            JS_ThrowTypeError(ctx, "proxy: duplicate property");
46586
0
            goto fail;
46587
0
        }
46588
0
    }
46589
46590
0
    is_extensible = JS_IsExtensible(ctx, s->target);
46591
0
    if (is_extensible < 0)
46592
0
        goto fail;
46593
46594
    /* check if there are non configurable properties */
46595
0
    if (s->is_revoked) {
46596
0
        JS_ThrowTypeErrorRevokedProxy(ctx);
46597
0
        goto fail;
46598
0
    }
46599
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &tab2, &len2, JS_VALUE_GET_OBJ(s->target),
46600
0
                               JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
46601
0
        goto fail;
46602
0
    for(i = 0; i < len2; i++) {
46603
0
        if (s->is_revoked) {
46604
0
            JS_ThrowTypeErrorRevokedProxy(ctx);
46605
0
            goto fail;
46606
0
        }
46607
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target),
46608
0
                                tab2[i].atom);
46609
0
        if (res < 0)
46610
0
            goto fail;
46611
0
        if (res) {  /* safety, property should be found */
46612
0
            js_free_desc(ctx, &desc);
46613
0
            if (!(desc.flags & JS_PROP_CONFIGURABLE) || !is_extensible) {
46614
0
                idx = find_prop_key(tab, len, tab2[i].atom);
46615
0
                if (idx < 0) {
46616
0
                    JS_ThrowTypeError(ctx, "proxy: target property must be present in proxy ownKeys");
46617
0
                    goto fail;
46618
0
                }
46619
                /* mark the property as found */
46620
0
                if (!is_extensible)
46621
0
                    tab[idx].is_enumerable = TRUE;
46622
0
            }
46623
0
        }
46624
0
    }
46625
0
    if (!is_extensible) {
46626
        /* check that all property in 'tab' were checked */
46627
0
        for(i = 0; i < len; i++) {
46628
0
            if (!tab[i].is_enumerable) {
46629
0
                JS_ThrowTypeError(ctx, "proxy: property not present in target were returned by non extensible proxy");
46630
0
                goto fail;
46631
0
            }
46632
0
        }
46633
0
    }
46634
46635
0
    js_free_prop_enum(ctx, tab2, len2);
46636
0
    JS_FreeValue(ctx, prop_array);
46637
0
    *ptab = tab;
46638
0
    *plen = len;
46639
0
    return 0;
46640
0
 fail:
46641
0
    js_free_prop_enum(ctx, tab2, len2);
46642
0
    js_free_prop_enum(ctx, tab, len);
46643
0
    JS_FreeValue(ctx, prop_array);
46644
0
    return -1;
46645
0
}
46646
46647
static JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj,
46648
                                         JSValueConst new_target,
46649
                                         int argc, JSValueConst *argv)
46650
0
{
46651
0
    JSProxyData *s;
46652
0
    JSValue method, arg_array, ret;
46653
0
    JSValueConst args[3];
46654
46655
0
    s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_construct);
46656
0
    if (!s)
46657
0
        return JS_EXCEPTION;
46658
0
    if (!JS_IsConstructor(ctx, s->target))
46659
0
        return JS_ThrowTypeError(ctx, "not a constructor");
46660
0
    if (JS_IsUndefined(method))
46661
0
        return JS_CallConstructor2(ctx, s->target, new_target, argc, argv);
46662
0
    arg_array = js_create_array(ctx, argc, argv);
46663
0
    if (JS_IsException(arg_array)) {
46664
0
        ret = JS_EXCEPTION;
46665
0
        goto fail;
46666
0
    }
46667
0
    args[0] = s->target;
46668
0
    args[1] = arg_array;
46669
0
    args[2] = new_target;
46670
0
    ret = JS_Call(ctx, method, s->handler, 3, args);
46671
0
    if (!JS_IsException(ret) && JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
46672
0
        JS_FreeValue(ctx, ret);
46673
0
        ret = JS_ThrowTypeErrorNotAnObject(ctx);
46674
0
    }
46675
0
 fail:
46676
0
    JS_FreeValue(ctx, method);
46677
0
    JS_FreeValue(ctx, arg_array);
46678
0
    return ret;
46679
0
}
46680
46681
static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,
46682
                             JSValueConst this_obj,
46683
                             int argc, JSValueConst *argv, int flags)
46684
0
{
46685
0
    JSProxyData *s;
46686
0
    JSValue method, arg_array, ret;
46687
0
    JSValueConst args[3];
46688
46689
0
    if (flags & JS_CALL_FLAG_CONSTRUCTOR)
46690
0
        return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv);
46691
46692
0
    s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_apply);
46693
0
    if (!s)
46694
0
        return JS_EXCEPTION;
46695
0
    if (!s->is_func) {
46696
0
        JS_FreeValue(ctx, method);
46697
0
        return JS_ThrowTypeError(ctx, "not a function");
46698
0
    }
46699
0
    if (JS_IsUndefined(method))
46700
0
        return JS_Call(ctx, s->target, this_obj, argc, argv);
46701
0
    arg_array = js_create_array(ctx, argc, argv);
46702
0
    if (JS_IsException(arg_array)) {
46703
0
        ret = JS_EXCEPTION;
46704
0
        goto fail;
46705
0
    }
46706
0
    args[0] = s->target;
46707
0
    args[1] = this_obj;
46708
0
    args[2] = arg_array;
46709
0
    ret = JS_Call(ctx, method, s->handler, 3, args);
46710
0
 fail:
46711
0
    JS_FreeValue(ctx, method);
46712
0
    JS_FreeValue(ctx, arg_array);
46713
0
    return ret;
46714
0
}
46715
46716
/* `js_resolve_proxy`: resolve the proxy chain
46717
   `*pval` is updated with to ultimate proxy target
46718
   `throw_exception` controls whether exceptions are thown or not
46719
   - return -1 in case of error
46720
   - otherwise return 0
46721
 */
46722
0
static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, BOOL throw_exception) {
46723
0
    int depth = 0;
46724
0
    JSObject *p;
46725
0
    JSProxyData *s;
46726
46727
0
    while (JS_VALUE_GET_TAG(*pval) == JS_TAG_OBJECT) {
46728
0
        p = JS_VALUE_GET_OBJ(*pval);
46729
0
        if (p->class_id != JS_CLASS_PROXY)
46730
0
            break;
46731
0
        if (depth++ > 1000) {
46732
0
            if (throw_exception)
46733
0
                JS_ThrowStackOverflow(ctx);
46734
0
            return -1;
46735
0
        }
46736
0
        s = p->u.opaque;
46737
0
        if (s->is_revoked) {
46738
0
            if (throw_exception)
46739
0
                JS_ThrowTypeErrorRevokedProxy(ctx);
46740
0
            return -1;
46741
0
        }
46742
0
        *pval = s->target;
46743
0
    }
46744
0
    return 0;
46745
0
}
46746
46747
static const JSClassExoticMethods js_proxy_exotic_methods = {
46748
    .get_own_property = js_proxy_get_own_property,
46749
    .define_own_property = js_proxy_define_own_property,
46750
    .delete_property = js_proxy_delete_property,
46751
    .get_own_property_names = js_proxy_get_own_property_names,
46752
    .has_property = js_proxy_has,
46753
    .get_property = js_proxy_get,
46754
    .set_property = js_proxy_set,
46755
};
46756
46757
static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val,
46758
                                    int argc, JSValueConst *argv)
46759
0
{
46760
0
    JSValueConst target, handler;
46761
0
    JSValue obj;
46762
0
    JSProxyData *s;
46763
46764
0
    target = argv[0];
46765
0
    handler = argv[1];
46766
0
    if (JS_VALUE_GET_TAG(target) != JS_TAG_OBJECT ||
46767
0
        JS_VALUE_GET_TAG(handler) != JS_TAG_OBJECT)
46768
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
46769
46770
0
    obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_PROXY);
46771
0
    if (JS_IsException(obj))
46772
0
        return obj;
46773
0
    s = js_malloc(ctx, sizeof(JSProxyData));
46774
0
    if (!s) {
46775
0
        JS_FreeValue(ctx, obj);
46776
0
        return JS_EXCEPTION;
46777
0
    }
46778
0
    s->target = JS_DupValue(ctx, target);
46779
0
    s->handler = JS_DupValue(ctx, handler);
46780
0
    s->is_func = JS_IsFunction(ctx, target);
46781
0
    s->is_revoked = FALSE;
46782
0
    JS_SetOpaque(obj, s);
46783
0
    JS_SetConstructorBit(ctx, obj, JS_IsConstructor(ctx, target));
46784
0
    return obj;
46785
0
}
46786
46787
static JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val,
46788
                               int argc, JSValueConst *argv, int magic,
46789
                               JSValue *func_data)
46790
0
{
46791
0
    JSProxyData *s = JS_GetOpaque(func_data[0], JS_CLASS_PROXY);
46792
0
    if (s) {
46793
        /* We do not free the handler and target in case they are
46794
           referenced as constants in the C call stack */
46795
0
        s->is_revoked = TRUE;
46796
0
        JS_FreeValue(ctx, func_data[0]);
46797
0
        func_data[0] = JS_NULL;
46798
0
    }
46799
0
    return JS_UNDEFINED;
46800
0
}
46801
46802
static JSValue js_proxy_revoke_constructor(JSContext *ctx,
46803
                                           JSValueConst proxy_obj)
46804
0
{
46805
0
    return JS_NewCFunctionData(ctx, js_proxy_revoke, 0, 0, 1, &proxy_obj);
46806
0
}
46807
46808
static JSValue js_proxy_revocable(JSContext *ctx, JSValueConst this_val,
46809
                                 int argc, JSValueConst *argv)
46810
0
{
46811
0
    JSValue proxy_obj, revoke_obj = JS_UNDEFINED, obj;
46812
46813
0
    proxy_obj = js_proxy_constructor(ctx, JS_UNDEFINED, argc, argv);
46814
0
    if (JS_IsException(proxy_obj))
46815
0
        goto fail;
46816
0
    revoke_obj = js_proxy_revoke_constructor(ctx, proxy_obj);
46817
0
    if (JS_IsException(revoke_obj))
46818
0
        goto fail;
46819
0
    obj = JS_NewObject(ctx);
46820
0
    if (JS_IsException(obj))
46821
0
        goto fail;
46822
    // XXX: exceptions?
46823
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_proxy, proxy_obj, JS_PROP_C_W_E);
46824
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_revoke, revoke_obj, JS_PROP_C_W_E);
46825
0
    return obj;
46826
0
 fail:
46827
0
    JS_FreeValue(ctx, proxy_obj);
46828
0
    JS_FreeValue(ctx, revoke_obj);
46829
0
    return JS_EXCEPTION;
46830
0
}
46831
46832
static const JSCFunctionListEntry js_proxy_funcs[] = {
46833
    JS_CFUNC_DEF("revocable", 2, js_proxy_revocable ),
46834
};
46835
46836
static const JSClassShortDef js_proxy_class_def[] = {
46837
    { JS_ATOM_Object, js_proxy_finalizer, js_proxy_mark }, /* JS_CLASS_PROXY */
46838
};
46839
46840
void JS_AddIntrinsicProxy(JSContext *ctx)
46841
39
{
46842
39
    JSRuntime *rt = ctx->rt;
46843
39
    JSValue obj1;
46844
46845
39
    if (!JS_IsRegisteredClass(rt, JS_CLASS_PROXY)) {
46846
39
        init_class_range(rt, js_proxy_class_def, JS_CLASS_PROXY,
46847
39
                         countof(js_proxy_class_def));
46848
39
        rt->class_array[JS_CLASS_PROXY].exotic = &js_proxy_exotic_methods;
46849
39
        rt->class_array[JS_CLASS_PROXY].call = js_proxy_call;
46850
39
    }
46851
46852
39
    obj1 = JS_NewCFunction2(ctx, js_proxy_constructor, "Proxy", 2,
46853
39
                            JS_CFUNC_constructor, 0);
46854
39
    JS_SetConstructorBit(ctx, obj1, TRUE);
46855
39
    JS_SetPropertyFunctionList(ctx, obj1, js_proxy_funcs,
46856
39
                               countof(js_proxy_funcs));
46857
39
    JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Proxy",
46858
39
                              obj1, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
46859
39
}
46860
46861
/* Symbol */
46862
46863
static JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target,
46864
                                     int argc, JSValueConst *argv)
46865
0
{
46866
0
    JSValue str;
46867
0
    JSString *p;
46868
46869
0
    if (!JS_IsUndefined(new_target))
46870
0
        return JS_ThrowTypeError(ctx, "not a constructor");
46871
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
46872
0
        p = NULL;
46873
0
    } else {
46874
0
        str = JS_ToString(ctx, argv[0]);
46875
0
        if (JS_IsException(str))
46876
0
            return JS_EXCEPTION;
46877
0
        p = JS_VALUE_GET_STRING(str);
46878
0
    }
46879
0
    return JS_NewSymbol(ctx, p, JS_ATOM_TYPE_SYMBOL);
46880
0
}
46881
46882
static JSValue js_thisSymbolValue(JSContext *ctx, JSValueConst this_val)
46883
0
{
46884
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_SYMBOL)
46885
0
        return JS_DupValue(ctx, this_val);
46886
46887
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
46888
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
46889
0
        if (p->class_id == JS_CLASS_SYMBOL) {
46890
0
            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_SYMBOL)
46891
0
                return JS_DupValue(ctx, p->u.object_data);
46892
0
        }
46893
0
    }
46894
0
    return JS_ThrowTypeError(ctx, "not a symbol");
46895
0
}
46896
46897
static JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val,
46898
                                  int argc, JSValueConst *argv)
46899
0
{
46900
0
    JSValue val, ret;
46901
0
    val = js_thisSymbolValue(ctx, this_val);
46902
0
    if (JS_IsException(val))
46903
0
        return val;
46904
    /* XXX: use JS_ToStringInternal() with a flags */
46905
0
    ret = js_string_constructor(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val);
46906
0
    JS_FreeValue(ctx, val);
46907
0
    return ret;
46908
0
}
46909
46910
static JSValue js_symbol_valueOf(JSContext *ctx, JSValueConst this_val,
46911
                                 int argc, JSValueConst *argv)
46912
0
{
46913
0
    return js_thisSymbolValue(ctx, this_val);
46914
0
}
46915
46916
static JSValue js_symbol_get_description(JSContext *ctx, JSValueConst this_val)
46917
0
{
46918
0
    JSValue val, ret;
46919
0
    JSAtomStruct *p;
46920
46921
0
    val = js_thisSymbolValue(ctx, this_val);
46922
0
    if (JS_IsException(val))
46923
0
        return val;
46924
0
    p = JS_VALUE_GET_PTR(val);
46925
0
    if (p->len == 0 && p->is_wide_char != 0) {
46926
0
        ret = JS_UNDEFINED;
46927
0
    } else {
46928
0
        ret = JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p));
46929
0
    }
46930
0
    JS_FreeValue(ctx, val);
46931
0
    return ret;
46932
0
}
46933
46934
static const JSCFunctionListEntry js_symbol_proto_funcs[] = {
46935
    JS_CFUNC_DEF("toString", 0, js_symbol_toString ),
46936
    JS_CFUNC_DEF("valueOf", 0, js_symbol_valueOf ),
46937
    // XXX: should have writable: false
46938
    JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_symbol_valueOf ),
46939
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Symbol", JS_PROP_CONFIGURABLE ),
46940
    JS_CGETSET_DEF("description", js_symbol_get_description, NULL ),
46941
};
46942
46943
static JSValue js_symbol_for(JSContext *ctx, JSValueConst this_val,
46944
                             int argc, JSValueConst *argv)
46945
0
{
46946
0
    JSValue str;
46947
46948
0
    str = JS_ToString(ctx, argv[0]);
46949
0
    if (JS_IsException(str))
46950
0
        return JS_EXCEPTION;
46951
0
    return JS_NewSymbol(ctx, JS_VALUE_GET_STRING(str), JS_ATOM_TYPE_GLOBAL_SYMBOL);
46952
0
}
46953
46954
static JSValue js_symbol_keyFor(JSContext *ctx, JSValueConst this_val,
46955
                                int argc, JSValueConst *argv)
46956
0
{
46957
0
    JSAtomStruct *p;
46958
46959
0
    if (!JS_IsSymbol(argv[0]))
46960
0
        return JS_ThrowTypeError(ctx, "not a symbol");
46961
0
    p = JS_VALUE_GET_PTR(argv[0]);
46962
0
    if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL)
46963
0
        return JS_UNDEFINED;
46964
0
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
46965
0
}
46966
46967
static const JSCFunctionListEntry js_symbol_funcs[] = {
46968
    JS_CFUNC_DEF("for", 1, js_symbol_for ),
46969
    JS_CFUNC_DEF("keyFor", 1, js_symbol_keyFor ),
46970
};
46971
46972
/* Set/Map/WeakSet/WeakMap */
46973
46974
typedef struct JSMapRecord {
46975
    int ref_count; /* used during enumeration to avoid freeing the record */
46976
    BOOL empty; /* TRUE if the record is deleted */
46977
    struct JSMapState *map;
46978
    struct JSMapRecord *next_weak_ref;
46979
    struct list_head link;
46980
    struct list_head hash_link;
46981
    JSValue key;
46982
    JSValue value;
46983
} JSMapRecord;
46984
46985
typedef struct JSMapState {
46986
    BOOL is_weak; /* TRUE if WeakSet/WeakMap */
46987
    struct list_head records; /* list of JSMapRecord.link */
46988
    uint32_t record_count;
46989
    struct list_head *hash_table;
46990
    uint32_t hash_size; /* must be a power of two */
46991
    uint32_t record_count_threshold; /* count at which a hash table
46992
                                        resize is needed */
46993
} JSMapState;
46994
46995
0
#define MAGIC_SET (1 << 0)
46996
0
#define MAGIC_WEAK (1 << 1)
46997
46998
static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
46999
                                  int argc, JSValueConst *argv, int magic)
47000
0
{
47001
0
    JSMapState *s;
47002
0
    JSValue obj, adder = JS_UNDEFINED, iter = JS_UNDEFINED, next_method = JS_UNDEFINED;
47003
0
    JSValueConst arr;
47004
0
    BOOL is_set, is_weak;
47005
47006
0
    is_set = magic & MAGIC_SET;
47007
0
    is_weak = ((magic & MAGIC_WEAK) != 0);
47008
0
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_MAP + magic);
47009
0
    if (JS_IsException(obj))
47010
0
        return JS_EXCEPTION;
47011
0
    s = js_mallocz(ctx, sizeof(*s));
47012
0
    if (!s)
47013
0
        goto fail;
47014
0
    init_list_head(&s->records);
47015
0
    s->is_weak = is_weak;
47016
0
    JS_SetOpaque(obj, s);
47017
0
    s->hash_size = 1;
47018
0
    s->hash_table = js_malloc(ctx, sizeof(s->hash_table[0]) * s->hash_size);
47019
0
    if (!s->hash_table)
47020
0
        goto fail;
47021
0
    init_list_head(&s->hash_table[0]);
47022
0
    s->record_count_threshold = 4;
47023
47024
0
    arr = JS_UNDEFINED;
47025
0
    if (argc > 0)
47026
0
        arr = argv[0];
47027
0
    if (!JS_IsUndefined(arr) && !JS_IsNull(arr)) {
47028
0
        JSValue item, ret;
47029
0
        BOOL done;
47030
47031
0
        adder = JS_GetProperty(ctx, obj, is_set ? JS_ATOM_add : JS_ATOM_set);
47032
0
        if (JS_IsException(adder))
47033
0
            goto fail;
47034
0
        if (!JS_IsFunction(ctx, adder)) {
47035
0
            JS_ThrowTypeError(ctx, "set/add is not a function");
47036
0
            goto fail;
47037
0
        }
47038
47039
0
        iter = JS_GetIterator(ctx, arr, FALSE);
47040
0
        if (JS_IsException(iter))
47041
0
            goto fail;
47042
0
        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
47043
0
        if (JS_IsException(next_method))
47044
0
            goto fail;
47045
47046
0
        for(;;) {
47047
0
            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
47048
0
            if (JS_IsException(item))
47049
0
                goto fail;
47050
0
            if (done) {
47051
0
                JS_FreeValue(ctx, item);
47052
0
                break;
47053
0
            }
47054
0
            if (is_set) {
47055
0
                ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item);
47056
0
                if (JS_IsException(ret)) {
47057
0
                    JS_FreeValue(ctx, item);
47058
0
                    goto fail;
47059
0
                }
47060
0
            } else {
47061
0
                JSValue key, value;
47062
0
                JSValueConst args[2];
47063
0
                key = JS_UNDEFINED;
47064
0
                value = JS_UNDEFINED;
47065
0
                if (!JS_IsObject(item)) {
47066
0
                    JS_ThrowTypeErrorNotAnObject(ctx);
47067
0
                    goto fail1;
47068
0
                }
47069
0
                key = JS_GetPropertyUint32(ctx, item, 0);
47070
0
                if (JS_IsException(key))
47071
0
                    goto fail1;
47072
0
                value = JS_GetPropertyUint32(ctx, item, 1);
47073
0
                if (JS_IsException(value))
47074
0
                    goto fail1;
47075
0
                args[0] = key;
47076
0
                args[1] = value;
47077
0
                ret = JS_Call(ctx, adder, obj, 2, args);
47078
0
                if (JS_IsException(ret)) {
47079
0
                fail1:
47080
0
                    JS_FreeValue(ctx, item);
47081
0
                    JS_FreeValue(ctx, key);
47082
0
                    JS_FreeValue(ctx, value);
47083
0
                    goto fail;
47084
0
                }
47085
0
                JS_FreeValue(ctx, key);
47086
0
                JS_FreeValue(ctx, value);
47087
0
            }
47088
0
            JS_FreeValue(ctx, ret);
47089
0
            JS_FreeValue(ctx, item);
47090
0
        }
47091
0
        JS_FreeValue(ctx, next_method);
47092
0
        JS_FreeValue(ctx, iter);
47093
0
        JS_FreeValue(ctx, adder);
47094
0
    }
47095
0
    return obj;
47096
0
 fail:
47097
0
    if (JS_IsObject(iter)) {
47098
        /* close the iterator object, preserving pending exception */
47099
0
        JS_IteratorClose(ctx, iter, TRUE);
47100
0
    }
47101
0
    JS_FreeValue(ctx, next_method);
47102
0
    JS_FreeValue(ctx, iter);
47103
0
    JS_FreeValue(ctx, adder);
47104
0
    JS_FreeValue(ctx, obj);
47105
0
    return JS_EXCEPTION;
47106
0
}
47107
47108
/* XXX: could normalize strings to speed up comparison */
47109
static JSValueConst map_normalize_key(JSContext *ctx, JSValueConst key)
47110
0
{
47111
0
    uint32_t tag = JS_VALUE_GET_TAG(key);
47112
    /* convert -0.0 to +0.0 */
47113
0
    if (JS_TAG_IS_FLOAT64(tag) && JS_VALUE_GET_FLOAT64(key) == 0.0) {
47114
0
        key = JS_NewInt32(ctx, 0);
47115
0
    }
47116
0
    return key;
47117
0
}
47118
47119
/* XXX: better hash ? */
47120
static uint32_t map_hash_key(JSContext *ctx, JSValueConst key)
47121
0
{
47122
0
    uint32_t tag = JS_VALUE_GET_NORM_TAG(key);
47123
0
    uint32_t h;
47124
0
    double d;
47125
0
    JSFloat64Union u;
47126
47127
0
    switch(tag) {
47128
0
    case JS_TAG_BOOL:
47129
0
        h = JS_VALUE_GET_INT(key);
47130
0
        break;
47131
0
    case JS_TAG_STRING:
47132
0
        h = hash_string(JS_VALUE_GET_STRING(key), 0);
47133
0
        break;
47134
0
    case JS_TAG_OBJECT:
47135
0
    case JS_TAG_SYMBOL:
47136
0
        h = (uintptr_t)JS_VALUE_GET_PTR(key) * 3163;
47137
0
        break;
47138
0
    case JS_TAG_INT:
47139
0
        d = JS_VALUE_GET_INT(key);
47140
0
        goto hash_float64;
47141
0
    case JS_TAG_FLOAT64:
47142
0
        d = JS_VALUE_GET_FLOAT64(key);
47143
        /* normalize the NaN */
47144
0
        if (isnan(d))
47145
0
            d = JS_FLOAT64_NAN;
47146
0
    hash_float64:
47147
0
        u.d = d;
47148
0
        h = (u.u32[0] ^ u.u32[1]) * 3163;
47149
0
        return h ^= JS_TAG_FLOAT64;
47150
0
    default:
47151
0
        h = 0; /* XXX: bignum support */
47152
0
        break;
47153
0
    }
47154
0
    h ^= tag;
47155
0
    return h;
47156
0
}
47157
47158
static JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s,
47159
                                    JSValueConst key)
47160
0
{
47161
0
    struct list_head *el;
47162
0
    JSMapRecord *mr;
47163
0
    uint32_t h;
47164
0
    h = map_hash_key(ctx, key) & (s->hash_size - 1);
47165
0
    list_for_each(el, &s->hash_table[h]) {
47166
0
        mr = list_entry(el, JSMapRecord, hash_link);
47167
0
        if (js_same_value_zero(ctx, mr->key, key))
47168
0
            return mr;
47169
0
    }
47170
0
    return NULL;
47171
0
}
47172
47173
static void map_hash_resize(JSContext *ctx, JSMapState *s)
47174
0
{
47175
0
    uint32_t new_hash_size, i, h;
47176
0
    size_t slack;
47177
0
    struct list_head *new_hash_table, *el;
47178
0
    JSMapRecord *mr;
47179
47180
    /* XXX: no reporting of memory allocation failure */
47181
0
    if (s->hash_size == 1)
47182
0
        new_hash_size = 4;
47183
0
    else
47184
0
        new_hash_size = s->hash_size * 2;
47185
0
    new_hash_table = js_realloc2(ctx, s->hash_table,
47186
0
                                 sizeof(new_hash_table[0]) * new_hash_size, &slack);
47187
0
    if (!new_hash_table)
47188
0
        return;
47189
0
    new_hash_size += slack / sizeof(*new_hash_table);
47190
47191
0
    for(i = 0; i < new_hash_size; i++)
47192
0
        init_list_head(&new_hash_table[i]);
47193
47194
0
    list_for_each(el, &s->records) {
47195
0
        mr = list_entry(el, JSMapRecord, link);
47196
0
        if (!mr->empty) {
47197
0
            h = map_hash_key(ctx, mr->key) & (new_hash_size - 1);
47198
0
            list_add_tail(&mr->hash_link, &new_hash_table[h]);
47199
0
        }
47200
0
    }
47201
0
    s->hash_table = new_hash_table;
47202
0
    s->hash_size = new_hash_size;
47203
0
    s->record_count_threshold = new_hash_size * 2;
47204
0
}
47205
47206
static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
47207
                                   JSValueConst key)
47208
0
{
47209
0
    uint32_t h;
47210
0
    JSMapRecord *mr;
47211
47212
0
    mr = js_malloc(ctx, sizeof(*mr));
47213
0
    if (!mr)
47214
0
        return NULL;
47215
0
    mr->ref_count = 1;
47216
0
    mr->map = s;
47217
0
    mr->empty = FALSE;
47218
0
    if (s->is_weak) {
47219
0
        JSObject *p = JS_VALUE_GET_OBJ(key);
47220
        /* Add the weak reference */
47221
0
        mr->next_weak_ref = p->first_weak_ref;
47222
0
        p->first_weak_ref = mr;
47223
0
    } else {
47224
0
        JS_DupValue(ctx, key);
47225
0
    }
47226
0
    mr->key = (JSValue)key;
47227
0
    h = map_hash_key(ctx, key) & (s->hash_size - 1);
47228
0
    list_add_tail(&mr->hash_link, &s->hash_table[h]);
47229
0
    list_add_tail(&mr->link, &s->records);
47230
0
    s->record_count++;
47231
0
    if (s->record_count >= s->record_count_threshold) {
47232
0
        map_hash_resize(ctx, s);
47233
0
    }
47234
0
    return mr;
47235
0
}
47236
47237
/* Remove the weak reference from the object weak
47238
   reference list. we don't use a doubly linked list to
47239
   save space, assuming a given object has few weak
47240
       references to it */
47241
static void delete_weak_ref(JSRuntime *rt, JSMapRecord *mr)
47242
0
{
47243
0
    JSMapRecord **pmr, *mr1;
47244
0
    JSObject *p;
47245
47246
0
    p = JS_VALUE_GET_OBJ(mr->key);
47247
0
    pmr = &p->first_weak_ref;
47248
0
    for(;;) {
47249
0
        mr1 = *pmr;
47250
0
        assert(mr1 != NULL);
47251
0
        if (mr1 == mr)
47252
0
            break;
47253
0
        pmr = &mr1->next_weak_ref;
47254
0
    }
47255
0
    *pmr = mr1->next_weak_ref;
47256
0
}
47257
47258
static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr)
47259
0
{
47260
0
    if (mr->empty)
47261
0
        return;
47262
0
    list_del(&mr->hash_link);
47263
0
    if (s->is_weak) {
47264
0
        delete_weak_ref(rt, mr);
47265
0
    } else {
47266
0
        JS_FreeValueRT(rt, mr->key);
47267
0
    }
47268
0
    JS_FreeValueRT(rt, mr->value);
47269
0
    if (--mr->ref_count == 0) {
47270
0
        list_del(&mr->link);
47271
0
        js_free_rt(rt, mr);
47272
0
    } else {
47273
        /* keep a zombie record for iterators */
47274
0
        mr->empty = TRUE;
47275
0
        mr->key = JS_UNDEFINED;
47276
0
        mr->value = JS_UNDEFINED;
47277
0
    }
47278
0
    s->record_count--;
47279
0
}
47280
47281
static void map_decref_record(JSRuntime *rt, JSMapRecord *mr)
47282
0
{
47283
0
    if (--mr->ref_count == 0) {
47284
        /* the record can be safely removed */
47285
0
        assert(mr->empty);
47286
0
        list_del(&mr->link);
47287
0
        js_free_rt(rt, mr);
47288
0
    }
47289
0
}
47290
47291
static void reset_weak_ref(JSRuntime *rt, JSObject *p)
47292
0
{
47293
0
    JSMapRecord *mr, *mr_next;
47294
0
    JSMapState *s;
47295
47296
    /* first pass to remove the records from the WeakMap/WeakSet
47297
       lists */
47298
0
    for(mr = p->first_weak_ref; mr != NULL; mr = mr->next_weak_ref) {
47299
0
        s = mr->map;
47300
0
        assert(s->is_weak);
47301
0
        assert(!mr->empty); /* no iterator on WeakMap/WeakSet */
47302
0
        list_del(&mr->hash_link);
47303
0
        list_del(&mr->link);
47304
0
    }
47305
47306
    /* second pass to free the values to avoid modifying the weak
47307
       reference list while traversing it. */
47308
0
    for(mr = p->first_weak_ref; mr != NULL; mr = mr_next) {
47309
0
        mr_next = mr->next_weak_ref;
47310
0
        JS_FreeValueRT(rt, mr->value);
47311
0
        js_free_rt(rt, mr);
47312
0
    }
47313
47314
0
    p->first_weak_ref = NULL; /* fail safe */
47315
0
}
47316
47317
static JSValue js_map_set(JSContext *ctx, JSValueConst this_val,
47318
                          int argc, JSValueConst *argv, int magic)
47319
0
{
47320
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
47321
0
    JSMapRecord *mr;
47322
0
    JSValueConst key, value;
47323
47324
0
    if (!s)
47325
0
        return JS_EXCEPTION;
47326
0
    key = map_normalize_key(ctx, argv[0]);
47327
0
    if (s->is_weak && !JS_IsObject(key))
47328
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
47329
0
    if (magic & MAGIC_SET)
47330
0
        value = JS_UNDEFINED;
47331
0
    else
47332
0
        value = argv[1];
47333
0
    mr = map_find_record(ctx, s, key);
47334
0
    if (mr) {
47335
0
        JS_FreeValue(ctx, mr->value);
47336
0
    } else {
47337
0
        mr = map_add_record(ctx, s, key);
47338
0
        if (!mr)
47339
0
            return JS_EXCEPTION;
47340
0
    }
47341
0
    mr->value = JS_DupValue(ctx, value);
47342
0
    return JS_DupValue(ctx, this_val);
47343
0
}
47344
47345
static JSValue js_map_get(JSContext *ctx, JSValueConst this_val,
47346
                          int argc, JSValueConst *argv, int magic)
47347
0
{
47348
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
47349
0
    JSMapRecord *mr;
47350
0
    JSValueConst key;
47351
47352
0
    if (!s)
47353
0
        return JS_EXCEPTION;
47354
0
    key = map_normalize_key(ctx, argv[0]);
47355
0
    mr = map_find_record(ctx, s, key);
47356
0
    if (!mr)
47357
0
        return JS_UNDEFINED;
47358
0
    else
47359
0
        return JS_DupValue(ctx, mr->value);
47360
0
}
47361
47362
static JSValue js_map_has(JSContext *ctx, JSValueConst this_val,
47363
                          int argc, JSValueConst *argv, int magic)
47364
0
{
47365
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
47366
0
    JSMapRecord *mr;
47367
0
    JSValueConst key;
47368
47369
0
    if (!s)
47370
0
        return JS_EXCEPTION;
47371
0
    key = map_normalize_key(ctx, argv[0]);
47372
0
    mr = map_find_record(ctx, s, key);
47373
0
    return JS_NewBool(ctx, mr != NULL);
47374
0
}
47375
47376
static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val,
47377
                             int argc, JSValueConst *argv, int magic)
47378
0
{
47379
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
47380
0
    JSMapRecord *mr;
47381
0
    JSValueConst key;
47382
47383
0
    if (!s)
47384
0
        return JS_EXCEPTION;
47385
0
    key = map_normalize_key(ctx, argv[0]);
47386
0
    mr = map_find_record(ctx, s, key);
47387
0
    if (!mr)
47388
0
        return JS_FALSE;
47389
0
    map_delete_record(ctx->rt, s, mr);
47390
0
    return JS_TRUE;
47391
0
}
47392
47393
static JSValue js_map_clear(JSContext *ctx, JSValueConst this_val,
47394
                            int argc, JSValueConst *argv, int magic)
47395
0
{
47396
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
47397
0
    struct list_head *el, *el1;
47398
0
    JSMapRecord *mr;
47399
47400
0
    if (!s)
47401
0
        return JS_EXCEPTION;
47402
0
    list_for_each_safe(el, el1, &s->records) {
47403
0
        mr = list_entry(el, JSMapRecord, link);
47404
0
        map_delete_record(ctx->rt, s, mr);
47405
0
    }
47406
0
    return JS_UNDEFINED;
47407
0
}
47408
47409
static JSValue js_map_get_size(JSContext *ctx, JSValueConst this_val, int magic)
47410
0
{
47411
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
47412
0
    if (!s)
47413
0
        return JS_EXCEPTION;
47414
0
    return JS_NewUint32(ctx, s->record_count);
47415
0
}
47416
47417
static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,
47418
                              int argc, JSValueConst *argv, int magic)
47419
0
{
47420
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
47421
0
    JSValueConst func, this_arg;
47422
0
    JSValue ret, args[3];
47423
0
    struct list_head *el;
47424
0
    JSMapRecord *mr;
47425
47426
0
    if (!s)
47427
0
        return JS_EXCEPTION;
47428
0
    func = argv[0];
47429
0
    if (argc > 1)
47430
0
        this_arg = argv[1];
47431
0
    else
47432
0
        this_arg = JS_UNDEFINED;
47433
0
    if (check_function(ctx, func))
47434
0
        return JS_EXCEPTION;
47435
    /* Note: the list can be modified while traversing it, but the
47436
       current element is locked */
47437
0
    el = s->records.next;
47438
0
    while (el != &s->records) {
47439
0
        mr = list_entry(el, JSMapRecord, link);
47440
0
        if (!mr->empty) {
47441
0
            mr->ref_count++;
47442
            /* must duplicate in case the record is deleted */
47443
0
            args[1] = JS_DupValue(ctx, mr->key);
47444
0
            if (magic)
47445
0
                args[0] = args[1];
47446
0
            else
47447
0
                args[0] = JS_DupValue(ctx, mr->value);
47448
0
            args[2] = (JSValue)this_val;
47449
0
            ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args);
47450
0
            JS_FreeValue(ctx, args[0]);
47451
0
            if (!magic)
47452
0
                JS_FreeValue(ctx, args[1]);
47453
0
            el = el->next;
47454
0
            map_decref_record(ctx->rt, mr);
47455
0
            if (JS_IsException(ret))
47456
0
                return ret;
47457
0
            JS_FreeValue(ctx, ret);
47458
0
        } else {
47459
0
            el = el->next;
47460
0
        }
47461
0
    }
47462
0
    return JS_UNDEFINED;
47463
0
}
47464
47465
static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val,
47466
                                 int argc, JSValueConst *argv, int is_map)
47467
0
{
47468
0
    JSValueConst cb, args[2];
47469
0
    JSValue res, iter, next, groups, key, v, prop;
47470
0
    JSAtom key_atom = JS_ATOM_NULL;
47471
0
    int64_t idx;
47472
0
    BOOL done;
47473
47474
    // "is function?" check must be observed before argv[0] is accessed
47475
0
    cb = argv[1];
47476
0
    if (check_function(ctx, cb))
47477
0
        return JS_EXCEPTION;
47478
47479
0
    iter = JS_GetIterator(ctx, argv[0], /*is_async*/FALSE);
47480
0
    if (JS_IsException(iter))
47481
0
        return JS_EXCEPTION;
47482
47483
0
    key = JS_UNDEFINED;
47484
0
    key_atom = JS_ATOM_NULL;
47485
0
    v = JS_UNDEFINED;
47486
0
    prop = JS_UNDEFINED;
47487
0
    groups = JS_UNDEFINED;
47488
47489
0
    next = JS_GetProperty(ctx, iter, JS_ATOM_next);
47490
0
    if (JS_IsException(next))
47491
0
        goto exception;
47492
47493
0
    if (is_map) {
47494
0
        groups = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, 0);
47495
0
    } else {
47496
0
        groups = JS_NewObjectProto(ctx, JS_NULL);
47497
0
    }
47498
0
    if (JS_IsException(groups))
47499
0
        goto exception;
47500
47501
0
    for (idx = 0; ; idx++) {
47502
0
        if (idx >= MAX_SAFE_INTEGER) {
47503
0
            JS_ThrowTypeError(ctx, "too many elements");
47504
0
            goto iterator_close_exception;
47505
0
        }
47506
0
        v = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
47507
0
        if (JS_IsException(v))
47508
0
            goto exception;
47509
0
        if (done)
47510
0
            break; // v is JS_UNDEFINED
47511
47512
0
        args[0] = v;
47513
0
        args[1] = JS_NewInt64(ctx, idx);
47514
0
        key = JS_Call(ctx, cb, ctx->global_obj, 2, args);
47515
0
        if (JS_IsException(key))
47516
0
            goto iterator_close_exception;
47517
47518
0
        if (is_map) {
47519
0
            prop = js_map_get(ctx, groups, 1, (JSValueConst *)&key, 0);
47520
0
        } else {
47521
0
            key_atom = JS_ValueToAtom(ctx, key);
47522
0
            JS_FreeValue(ctx, key);
47523
0
            key = JS_UNDEFINED;
47524
0
            if (key_atom == JS_ATOM_NULL)
47525
0
                goto iterator_close_exception;
47526
0
            prop = JS_GetProperty(ctx, groups, key_atom);
47527
0
        }
47528
0
        if (JS_IsException(prop))
47529
0
            goto exception;
47530
47531
0
        if (JS_IsUndefined(prop)) {
47532
0
            prop = JS_NewArray(ctx);
47533
0
            if (JS_IsException(prop))
47534
0
                goto exception;
47535
0
            if (is_map) {
47536
0
                args[0] = key;
47537
0
                args[1] = prop;
47538
0
                res = js_map_set(ctx, groups, 2, args, 0);
47539
0
                if (JS_IsException(res))
47540
0
                    goto exception;
47541
0
                JS_FreeValue(ctx, res);
47542
0
            } else {
47543
0
                prop = JS_DupValue(ctx, prop);
47544
0
                if (JS_DefinePropertyValue(ctx, groups, key_atom, prop,
47545
0
                                           JS_PROP_C_W_E) < 0) {
47546
0
                    goto exception;
47547
0
                }
47548
0
            }
47549
0
        }
47550
0
        res = js_array_push(ctx, prop, 1, (JSValueConst *)&v, /*unshift*/0);
47551
0
        if (JS_IsException(res))
47552
0
            goto exception;
47553
        // res is an int64
47554
47555
0
        JS_FreeValue(ctx, prop);
47556
0
        JS_FreeValue(ctx, key);
47557
0
        JS_FreeAtom(ctx, key_atom);
47558
0
        JS_FreeValue(ctx, v);
47559
0
        prop = JS_UNDEFINED;
47560
0
        key = JS_UNDEFINED;
47561
0
        key_atom = JS_ATOM_NULL;
47562
0
        v = JS_UNDEFINED;
47563
0
    }
47564
47565
0
    JS_FreeValue(ctx, iter);
47566
0
    JS_FreeValue(ctx, next);
47567
0
    return groups;
47568
47569
0
 iterator_close_exception:
47570
0
    JS_IteratorClose(ctx, iter, TRUE);
47571
0
 exception:
47572
0
    JS_FreeAtom(ctx, key_atom);
47573
0
    JS_FreeValue(ctx, prop);
47574
0
    JS_FreeValue(ctx, key);
47575
0
    JS_FreeValue(ctx, v);
47576
0
    JS_FreeValue(ctx, groups);
47577
0
    JS_FreeValue(ctx, iter);
47578
0
    JS_FreeValue(ctx, next);
47579
0
    return JS_EXCEPTION;
47580
0
}
47581
47582
static void js_map_finalizer(JSRuntime *rt, JSValue val)
47583
0
{
47584
0
    JSObject *p;
47585
0
    JSMapState *s;
47586
0
    struct list_head *el, *el1;
47587
0
    JSMapRecord *mr;
47588
47589
0
    p = JS_VALUE_GET_OBJ(val);
47590
0
    s = p->u.map_state;
47591
0
    if (s) {
47592
        /* if the object is deleted we are sure that no iterator is
47593
           using it */
47594
0
        list_for_each_safe(el, el1, &s->records) {
47595
0
            mr = list_entry(el, JSMapRecord, link);
47596
0
            if (!mr->empty) {
47597
0
                if (s->is_weak)
47598
0
                    delete_weak_ref(rt, mr);
47599
0
                else
47600
0
                    JS_FreeValueRT(rt, mr->key);
47601
0
                JS_FreeValueRT(rt, mr->value);
47602
0
            }
47603
0
            js_free_rt(rt, mr);
47604
0
        }
47605
0
        js_free_rt(rt, s->hash_table);
47606
0
        js_free_rt(rt, s);
47607
0
    }
47608
0
}
47609
47610
static void js_map_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
47611
0
{
47612
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
47613
0
    JSMapState *s;
47614
0
    struct list_head *el;
47615
0
    JSMapRecord *mr;
47616
47617
0
    s = p->u.map_state;
47618
0
    if (s) {
47619
0
        list_for_each(el, &s->records) {
47620
0
            mr = list_entry(el, JSMapRecord, link);
47621
0
            if (!s->is_weak)
47622
0
                JS_MarkValue(rt, mr->key, mark_func);
47623
0
            JS_MarkValue(rt, mr->value, mark_func);
47624
0
        }
47625
0
    }
47626
0
}
47627
47628
/* Map Iterator */
47629
47630
typedef struct JSMapIteratorData {
47631
    JSValue obj;
47632
    JSIteratorKindEnum kind;
47633
    JSMapRecord *cur_record;
47634
} JSMapIteratorData;
47635
47636
static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val)
47637
0
{
47638
0
    JSObject *p;
47639
0
    JSMapIteratorData *it;
47640
47641
0
    p = JS_VALUE_GET_OBJ(val);
47642
0
    it = p->u.map_iterator_data;
47643
0
    if (it) {
47644
        /* During the GC sweep phase the Map finalizer may be
47645
           called before the Map iterator finalizer */
47646
0
        if (JS_IsLiveObject(rt, it->obj) && it->cur_record) {
47647
0
            map_decref_record(rt, it->cur_record);
47648
0
        }
47649
0
        JS_FreeValueRT(rt, it->obj);
47650
0
        js_free_rt(rt, it);
47651
0
    }
47652
0
}
47653
47654
static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
47655
                                 JS_MarkFunc *mark_func)
47656
0
{
47657
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
47658
0
    JSMapIteratorData *it;
47659
0
    it = p->u.map_iterator_data;
47660
0
    if (it) {
47661
        /* the record is already marked by the object */
47662
0
        JS_MarkValue(rt, it->obj, mark_func);
47663
0
    }
47664
0
}
47665
47666
static JSValue js_create_map_iterator(JSContext *ctx, JSValueConst this_val,
47667
                                      int argc, JSValueConst *argv, int magic)
47668
0
{
47669
0
    JSIteratorKindEnum kind;
47670
0
    JSMapState *s;
47671
0
    JSMapIteratorData *it;
47672
0
    JSValue enum_obj;
47673
47674
0
    kind = magic >> 2;
47675
0
    magic &= 3;
47676
0
    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
47677
0
    if (!s)
47678
0
        return JS_EXCEPTION;
47679
0
    enum_obj = JS_NewObjectClass(ctx, JS_CLASS_MAP_ITERATOR + magic);
47680
0
    if (JS_IsException(enum_obj))
47681
0
        goto fail;
47682
0
    it = js_malloc(ctx, sizeof(*it));
47683
0
    if (!it) {
47684
0
        JS_FreeValue(ctx, enum_obj);
47685
0
        goto fail;
47686
0
    }
47687
0
    it->obj = JS_DupValue(ctx, this_val);
47688
0
    it->kind = kind;
47689
0
    it->cur_record = NULL;
47690
0
    JS_SetOpaque(enum_obj, it);
47691
0
    return enum_obj;
47692
0
 fail:
47693
0
    return JS_EXCEPTION;
47694
0
}
47695
47696
static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val,
47697
                                    int argc, JSValueConst *argv,
47698
                                    BOOL *pdone, int magic)
47699
0
{
47700
0
    JSMapIteratorData *it;
47701
0
    JSMapState *s;
47702
0
    JSMapRecord *mr;
47703
0
    struct list_head *el;
47704
47705
0
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP_ITERATOR + magic);
47706
0
    if (!it) {
47707
0
        *pdone = FALSE;
47708
0
        return JS_EXCEPTION;
47709
0
    }
47710
0
    if (JS_IsUndefined(it->obj))
47711
0
        goto done;
47712
0
    s = JS_GetOpaque(it->obj, JS_CLASS_MAP + magic);
47713
0
    assert(s != NULL);
47714
0
    if (!it->cur_record) {
47715
0
        el = s->records.next;
47716
0
    } else {
47717
0
        mr = it->cur_record;
47718
0
        el = mr->link.next;
47719
0
        map_decref_record(ctx->rt, mr); /* the record can be freed here */
47720
0
    }
47721
0
    for(;;) {
47722
0
        if (el == &s->records) {
47723
            /* no more record  */
47724
0
            it->cur_record = NULL;
47725
0
            JS_FreeValue(ctx, it->obj);
47726
0
            it->obj = JS_UNDEFINED;
47727
0
        done:
47728
            /* end of enumeration */
47729
0
            *pdone = TRUE;
47730
0
            return JS_UNDEFINED;
47731
0
        }
47732
0
        mr = list_entry(el, JSMapRecord, link);
47733
0
        if (!mr->empty)
47734
0
            break;
47735
        /* get the next record */
47736
0
        el = mr->link.next;
47737
0
    }
47738
47739
    /* lock the record so that it won't be freed */
47740
0
    mr->ref_count++;
47741
0
    it->cur_record = mr;
47742
0
    *pdone = FALSE;
47743
47744
0
    if (it->kind == JS_ITERATOR_KIND_KEY) {
47745
0
        return JS_DupValue(ctx, mr->key);
47746
0
    } else {
47747
0
        JSValueConst args[2];
47748
0
        args[0] = mr->key;
47749
0
        if (magic)
47750
0
            args[1] = mr->key;
47751
0
        else
47752
0
            args[1] = mr->value;
47753
0
        if (it->kind == JS_ITERATOR_KIND_VALUE) {
47754
0
            return JS_DupValue(ctx, args[1]);
47755
0
        } else {
47756
0
            return js_create_array(ctx, 2, args);
47757
0
        }
47758
0
    }
47759
0
}
47760
47761
static const JSCFunctionListEntry js_map_funcs[] = {
47762
    JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 1 ),
47763
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
47764
};
47765
47766
static const JSCFunctionListEntry js_map_proto_funcs[] = {
47767
    JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, 0 ),
47768
    JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, 0 ),
47769
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, 0 ),
47770
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, 0 ),
47771
    JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, 0 ),
47772
    JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, 0),
47773
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, 0 ),
47774
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_VALUE << 2) | 0 ),
47775
    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | 0 ),
47776
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | 0 ),
47777
    JS_ALIAS_DEF("[Symbol.iterator]", "entries" ),
47778
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map", JS_PROP_CONFIGURABLE ),
47779
};
47780
47781
static const JSCFunctionListEntry js_map_iterator_proto_funcs[] = {
47782
    JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, 0 ),
47783
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map Iterator", JS_PROP_CONFIGURABLE ),
47784
};
47785
47786
static const JSCFunctionListEntry js_set_proto_funcs[] = {
47787
    JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET ),
47788
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET ),
47789
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET ),
47790
    JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, MAGIC_SET ),
47791
    JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, MAGIC_SET ),
47792
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, MAGIC_SET ),
47793
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | MAGIC_SET ),
47794
    JS_ALIAS_DEF("keys", "values" ),
47795
    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
47796
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | MAGIC_SET ),
47797
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set", JS_PROP_CONFIGURABLE ),
47798
};
47799
47800
static const JSCFunctionListEntry js_set_iterator_proto_funcs[] = {
47801
    JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, MAGIC_SET ),
47802
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set Iterator", JS_PROP_CONFIGURABLE ),
47803
};
47804
47805
static const JSCFunctionListEntry js_weak_map_proto_funcs[] = {
47806
    JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, MAGIC_WEAK ),
47807
    JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, MAGIC_WEAK ),
47808
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_WEAK ),
47809
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_WEAK ),
47810
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakMap", JS_PROP_CONFIGURABLE ),
47811
};
47812
47813
static const JSCFunctionListEntry js_weak_set_proto_funcs[] = {
47814
    JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET | MAGIC_WEAK ),
47815
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET | MAGIC_WEAK ),
47816
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET | MAGIC_WEAK ),
47817
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakSet", JS_PROP_CONFIGURABLE ),
47818
};
47819
47820
static const JSCFunctionListEntry * const js_map_proto_funcs_ptr[6] = {
47821
    js_map_proto_funcs,
47822
    js_set_proto_funcs,
47823
    js_weak_map_proto_funcs,
47824
    js_weak_set_proto_funcs,
47825
    js_map_iterator_proto_funcs,
47826
    js_set_iterator_proto_funcs,
47827
};
47828
47829
static const uint8_t js_map_proto_funcs_count[6] = {
47830
    countof(js_map_proto_funcs),
47831
    countof(js_set_proto_funcs),
47832
    countof(js_weak_map_proto_funcs),
47833
    countof(js_weak_set_proto_funcs),
47834
    countof(js_map_iterator_proto_funcs),
47835
    countof(js_set_iterator_proto_funcs),
47836
};
47837
47838
void JS_AddIntrinsicMapSet(JSContext *ctx)
47839
39
{
47840
39
    int i;
47841
39
    JSValue obj1;
47842
39
    char buf[ATOM_GET_STR_BUF_SIZE];
47843
47844
195
    for(i = 0; i < 4; i++) {
47845
156
        const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf),
47846
156
                                         JS_ATOM_Map + i);
47847
156
        ctx->class_proto[JS_CLASS_MAP + i] = JS_NewObject(ctx);
47848
156
        JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP + i],
47849
156
                                   js_map_proto_funcs_ptr[i],
47850
156
                                   js_map_proto_funcs_count[i]);
47851
156
        obj1 = JS_NewCFunctionMagic(ctx, js_map_constructor, name, 0,
47852
156
                                    JS_CFUNC_constructor_magic, i);
47853
156
        if (i < 2) {
47854
78
            JS_SetPropertyFunctionList(ctx, obj1, js_map_funcs,
47855
78
                                       countof(js_map_funcs));
47856
78
        }
47857
156
        JS_NewGlobalCConstructor2(ctx, obj1, name, ctx->class_proto[JS_CLASS_MAP + i]);
47858
156
    }
47859
47860
117
    for(i = 0; i < 2; i++) {
47861
78
        ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] =
47862
78
            JS_NewObjectProto(ctx, ctx->iterator_proto);
47863
78
        JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP_ITERATOR + i],
47864
78
                                   js_map_proto_funcs_ptr[i + 4],
47865
78
                                   js_map_proto_funcs_count[i + 4]);
47866
78
    }
47867
39
}
47868
47869
/* Generator */
47870
static const JSCFunctionListEntry js_generator_function_proto_funcs[] = {
47871
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "GeneratorFunction", JS_PROP_CONFIGURABLE),
47872
};
47873
47874
static const JSCFunctionListEntry js_generator_proto_funcs[] = {
47875
    JS_ITERATOR_NEXT_DEF("next", 1, js_generator_next, GEN_MAGIC_NEXT ),
47876
    JS_ITERATOR_NEXT_DEF("return", 1, js_generator_next, GEN_MAGIC_RETURN ),
47877
    JS_ITERATOR_NEXT_DEF("throw", 1, js_generator_next, GEN_MAGIC_THROW ),
47878
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Generator", JS_PROP_CONFIGURABLE),
47879
};
47880
47881
/* Promise */
47882
47883
typedef struct JSPromiseData {
47884
    JSPromiseStateEnum promise_state;
47885
    /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */
47886
    struct list_head promise_reactions[2];
47887
    BOOL is_handled; /* Note: only useful to debug */
47888
    JSValue promise_result;
47889
} JSPromiseData;
47890
47891
typedef struct JSPromiseFunctionDataResolved {
47892
    int ref_count;
47893
    BOOL already_resolved;
47894
} JSPromiseFunctionDataResolved;
47895
47896
typedef struct JSPromiseFunctionData {
47897
    JSValue promise;
47898
    JSPromiseFunctionDataResolved *presolved;
47899
} JSPromiseFunctionData;
47900
47901
typedef struct JSPromiseReactionData {
47902
    struct list_head link; /* not used in promise_reaction_job */
47903
    JSValue resolving_funcs[2];
47904
    JSValue handler;
47905
} JSPromiseReactionData;
47906
47907
JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise)
47908
78
{
47909
78
    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
47910
78
    if (!s)
47911
0
        return -1;
47912
78
    return s->promise_state;
47913
78
}
47914
47915
JSValue JS_PromiseResult(JSContext *ctx, JSValue promise)
47916
39
{
47917
39
    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
47918
39
    if (!s)
47919
0
        return JS_UNDEFINED;
47920
39
    return JS_DupValue(ctx, s->promise_result);
47921
39
}
47922
47923
static int js_create_resolving_functions(JSContext *ctx, JSValue *args,
47924
                                         JSValueConst promise);
47925
47926
static void promise_reaction_data_free(JSRuntime *rt,
47927
                                       JSPromiseReactionData *rd)
47928
0
{
47929
0
    JS_FreeValueRT(rt, rd->resolving_funcs[0]);
47930
0
    JS_FreeValueRT(rt, rd->resolving_funcs[1]);
47931
0
    JS_FreeValueRT(rt, rd->handler);
47932
0
    js_free_rt(rt, rd);
47933
0
}
47934
47935
static JSValue promise_reaction_job(JSContext *ctx, int argc,
47936
                                    JSValueConst *argv)
47937
0
{
47938
0
    JSValueConst handler, arg, func;
47939
0
    JSValue res, res2;
47940
0
    BOOL is_reject;
47941
47942
0
    assert(argc == 5);
47943
0
    handler = argv[2];
47944
0
    is_reject = JS_ToBool(ctx, argv[3]);
47945
0
    arg = argv[4];
47946
#ifdef DUMP_PROMISE
47947
    printf("promise_reaction_job: is_reject=%d\n", is_reject);
47948
#endif
47949
47950
0
    if (JS_IsUndefined(handler)) {
47951
0
        if (is_reject) {
47952
0
            res = JS_Throw(ctx, JS_DupValue(ctx, arg));
47953
0
        } else {
47954
0
            res = JS_DupValue(ctx, arg);
47955
0
        }
47956
0
    } else {
47957
0
        res = JS_Call(ctx, handler, JS_UNDEFINED, 1, &arg);
47958
0
    }
47959
0
    is_reject = JS_IsException(res);
47960
0
    if (is_reject)
47961
0
        res = JS_GetException(ctx);
47962
0
    func = argv[is_reject];
47963
    /* as an extension, we support undefined as value to avoid
47964
       creating a dummy promise in the 'await' implementation of async
47965
       functions */
47966
0
    if (!JS_IsUndefined(func)) {
47967
0
        res2 = JS_Call(ctx, func, JS_UNDEFINED,
47968
0
                       1, (JSValueConst *)&res);
47969
0
    } else {
47970
0
        res2 = JS_UNDEFINED;
47971
0
    }
47972
0
    JS_FreeValue(ctx, res);
47973
47974
0
    return res2;
47975
0
}
47976
47977
void JS_SetHostPromiseRejectionTracker(JSRuntime *rt,
47978
                                       JSHostPromiseRejectionTracker *cb,
47979
                                       void *opaque)
47980
0
{
47981
0
    rt->host_promise_rejection_tracker = cb;
47982
0
    rt->host_promise_rejection_tracker_opaque = opaque;
47983
0
}
47984
47985
static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise,
47986
                                      JSValueConst value, BOOL is_reject)
47987
78
{
47988
78
    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
47989
78
    struct list_head *el, *el1;
47990
78
    JSPromiseReactionData *rd;
47991
78
    JSValueConst args[5];
47992
47993
78
    if (!s || s->promise_state != JS_PROMISE_PENDING)
47994
0
        return; /* should never happen */
47995
78
    set_value(ctx, &s->promise_result, JS_DupValue(ctx, value));
47996
78
    s->promise_state = JS_PROMISE_FULFILLED + is_reject;
47997
#ifdef DUMP_PROMISE
47998
    printf("fulfill_or_reject_promise: is_reject=%d\n", is_reject);
47999
#endif
48000
78
    if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
48001
0
        JSRuntime *rt = ctx->rt;
48002
0
        if (rt->host_promise_rejection_tracker) {
48003
0
            rt->host_promise_rejection_tracker(ctx, promise, value, FALSE,
48004
0
                                               rt->host_promise_rejection_tracker_opaque);
48005
0
        }
48006
0
    }
48007
48008
78
    list_for_each_safe(el, el1, &s->promise_reactions[is_reject]) {
48009
0
        rd = list_entry(el, JSPromiseReactionData, link);
48010
0
        args[0] = rd->resolving_funcs[0];
48011
0
        args[1] = rd->resolving_funcs[1];
48012
0
        args[2] = rd->handler;
48013
0
        args[3] = JS_NewBool(ctx, is_reject);
48014
0
        args[4] = value;
48015
0
        JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
48016
0
        list_del(&rd->link);
48017
0
        promise_reaction_data_free(ctx->rt, rd);
48018
0
    }
48019
48020
78
    list_for_each_safe(el, el1, &s->promise_reactions[1 - is_reject]) {
48021
0
        rd = list_entry(el, JSPromiseReactionData, link);
48022
0
        list_del(&rd->link);
48023
0
        promise_reaction_data_free(ctx->rt, rd);
48024
0
    }
48025
78
}
48026
48027
static void reject_promise(JSContext *ctx, JSValueConst promise,
48028
                           JSValueConst value)
48029
0
{
48030
0
    fulfill_or_reject_promise(ctx, promise, value, TRUE);
48031
0
}
48032
48033
static JSValue js_promise_resolve_thenable_job(JSContext *ctx,
48034
                                               int argc, JSValueConst *argv)
48035
0
{
48036
0
    JSValueConst promise, thenable, then;
48037
0
    JSValue args[2], res;
48038
48039
#ifdef DUMP_PROMISE
48040
    printf("js_promise_resolve_thenable_job\n");
48041
#endif
48042
0
    assert(argc == 3);
48043
0
    promise = argv[0];
48044
0
    thenable = argv[1];
48045
0
    then = argv[2];
48046
0
    if (js_create_resolving_functions(ctx, args, promise) < 0)
48047
0
        return JS_EXCEPTION;
48048
0
    res = JS_Call(ctx, then, thenable, 2, (JSValueConst *)args);
48049
0
    if (JS_IsException(res)) {
48050
0
        JSValue error = JS_GetException(ctx);
48051
0
        res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
48052
0
        JS_FreeValue(ctx, error);
48053
0
    }
48054
0
    JS_FreeValue(ctx, args[0]);
48055
0
    JS_FreeValue(ctx, args[1]);
48056
0
    return res;
48057
0
}
48058
48059
static void js_promise_resolve_function_free_resolved(JSRuntime *rt,
48060
                                                      JSPromiseFunctionDataResolved *sr)
48061
234
{
48062
234
    if (--sr->ref_count == 0) {
48063
78
        js_free_rt(rt, sr);
48064
78
    }
48065
234
}
48066
48067
static int js_create_resolving_functions(JSContext *ctx,
48068
                                         JSValue *resolving_funcs,
48069
                                         JSValueConst promise)
48070
48071
78
{
48072
78
    JSValue obj;
48073
78
    JSPromiseFunctionData *s;
48074
78
    JSPromiseFunctionDataResolved *sr;
48075
78
    int i, ret;
48076
48077
78
    sr = js_malloc(ctx, sizeof(*sr));
48078
78
    if (!sr)
48079
0
        return -1;
48080
78
    sr->ref_count = 1;
48081
78
    sr->already_resolved = FALSE; /* must be shared between the two functions */
48082
78
    ret = 0;
48083
234
    for(i = 0; i < 2; i++) {
48084
156
        obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
48085
156
                                     JS_CLASS_PROMISE_RESOLVE_FUNCTION + i);
48086
156
        if (JS_IsException(obj))
48087
0
            goto fail;
48088
156
        s = js_malloc(ctx, sizeof(*s));
48089
156
        if (!s) {
48090
0
            JS_FreeValue(ctx, obj);
48091
0
        fail:
48092
48093
0
            if (i != 0)
48094
0
                JS_FreeValue(ctx, resolving_funcs[0]);
48095
0
            ret = -1;
48096
0
            break;
48097
0
        }
48098
156
        sr->ref_count++;
48099
156
        s->presolved = sr;
48100
156
        s->promise = JS_DupValue(ctx, promise);
48101
156
        JS_SetOpaque(obj, s);
48102
156
        js_function_set_properties(ctx, obj, JS_ATOM_empty_string, 1);
48103
156
        resolving_funcs[i] = obj;
48104
156
    }
48105
78
    js_promise_resolve_function_free_resolved(ctx->rt, sr);
48106
78
    return ret;
48107
78
}
48108
48109
static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val)
48110
156
{
48111
156
    JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
48112
156
    if (s) {
48113
156
        js_promise_resolve_function_free_resolved(rt, s->presolved);
48114
156
        JS_FreeValueRT(rt, s->promise);
48115
156
        js_free_rt(rt, s);
48116
156
    }
48117
156
}
48118
48119
static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
48120
                                             JS_MarkFunc *mark_func)
48121
292
{
48122
292
    JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
48123
292
    if (s) {
48124
292
        JS_MarkValue(rt, s->promise, mark_func);
48125
292
    }
48126
292
}
48127
48128
static JSValue js_promise_resolve_function_call(JSContext *ctx,
48129
                                                JSValueConst func_obj,
48130
                                                JSValueConst this_val,
48131
                                                int argc, JSValueConst *argv,
48132
                                                int flags)
48133
78
{
48134
78
    JSObject *p = JS_VALUE_GET_OBJ(func_obj);
48135
78
    JSPromiseFunctionData *s;
48136
78
    JSValueConst resolution, args[3];
48137
78
    JSValue then;
48138
78
    BOOL is_reject;
48139
48140
78
    s = p->u.promise_function_data;
48141
78
    if (!s || s->presolved->already_resolved)
48142
0
        return JS_UNDEFINED;
48143
78
    s->presolved->already_resolved = TRUE;
48144
78
    is_reject = p->class_id - JS_CLASS_PROMISE_RESOLVE_FUNCTION;
48145
78
    if (argc > 0)
48146
78
        resolution = argv[0];
48147
0
    else
48148
0
        resolution = JS_UNDEFINED;
48149
#ifdef DUMP_PROMISE
48150
    printf("js_promise_resolving_function_call: is_reject=%d resolution=", is_reject);
48151
    JS_DumpValue(ctx, resolution);
48152
    printf("\n");
48153
#endif
48154
78
    if (is_reject || !JS_IsObject(resolution)) {
48155
78
        goto done;
48156
78
    } else if (js_same_value(ctx, resolution, s->promise)) {
48157
0
        JS_ThrowTypeError(ctx, "promise self resolution");
48158
0
        goto fail_reject;
48159
0
    }
48160
0
    then = JS_GetProperty(ctx, resolution, JS_ATOM_then);
48161
0
    if (JS_IsException(then)) {
48162
0
        JSValue error;
48163
0
    fail_reject:
48164
0
        error = JS_GetException(ctx);
48165
0
        reject_promise(ctx, s->promise, error);
48166
0
        JS_FreeValue(ctx, error);
48167
0
    } else if (!JS_IsFunction(ctx, then)) {
48168
0
        JS_FreeValue(ctx, then);
48169
78
    done:
48170
78
        fulfill_or_reject_promise(ctx, s->promise, resolution, is_reject);
48171
78
    } else {
48172
0
        args[0] = s->promise;
48173
0
        args[1] = resolution;
48174
0
        args[2] = then;
48175
0
        JS_EnqueueJob(ctx, js_promise_resolve_thenable_job, 3, args);
48176
0
        JS_FreeValue(ctx, then);
48177
0
    }
48178
78
    return JS_UNDEFINED;
48179
0
}
48180
48181
static void js_promise_finalizer(JSRuntime *rt, JSValue val)
48182
78
{
48183
78
    JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
48184
78
    struct list_head *el, *el1;
48185
78
    int i;
48186
48187
78
    if (!s)
48188
0
        return;
48189
234
    for(i = 0; i < 2; i++) {
48190
156
        list_for_each_safe(el, el1, &s->promise_reactions[i]) {
48191
0
            JSPromiseReactionData *rd =
48192
0
                list_entry(el, JSPromiseReactionData, link);
48193
0
            promise_reaction_data_free(rt, rd);
48194
0
        }
48195
156
    }
48196
78
    JS_FreeValueRT(rt, s->promise_result);
48197
78
    js_free_rt(rt, s);
48198
78
}
48199
48200
static void js_promise_mark(JSRuntime *rt, JSValueConst val,
48201
                            JS_MarkFunc *mark_func)
48202
146
{
48203
146
    JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
48204
146
    struct list_head *el;
48205
146
    int i;
48206
48207
146
    if (!s)
48208
0
        return;
48209
438
    for(i = 0; i < 2; i++) {
48210
292
        list_for_each(el, &s->promise_reactions[i]) {
48211
0
            JSPromiseReactionData *rd =
48212
0
                list_entry(el, JSPromiseReactionData, link);
48213
0
            JS_MarkValue(rt, rd->resolving_funcs[0], mark_func);
48214
0
            JS_MarkValue(rt, rd->resolving_funcs[1], mark_func);
48215
0
            JS_MarkValue(rt, rd->handler, mark_func);
48216
0
        }
48217
292
    }
48218
146
    JS_MarkValue(rt, s->promise_result, mark_func);
48219
146
}
48220
48221
static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target,
48222
                                      int argc, JSValueConst *argv)
48223
78
{
48224
78
    JSValueConst executor;
48225
78
    JSValue obj;
48226
78
    JSPromiseData *s;
48227
78
    JSValue args[2], ret;
48228
78
    int i;
48229
48230
78
    executor = argv[0];
48231
78
    if (check_function(ctx, executor))
48232
0
        return JS_EXCEPTION;
48233
78
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_PROMISE);
48234
78
    if (JS_IsException(obj))
48235
0
        return JS_EXCEPTION;
48236
78
    s = js_mallocz(ctx, sizeof(*s));
48237
78
    if (!s)
48238
0
        goto fail;
48239
78
    s->promise_state = JS_PROMISE_PENDING;
48240
78
    s->is_handled = FALSE;
48241
234
    for(i = 0; i < 2; i++)
48242
156
        init_list_head(&s->promise_reactions[i]);
48243
78
    s->promise_result = JS_UNDEFINED;
48244
78
    JS_SetOpaque(obj, s);
48245
78
    if (js_create_resolving_functions(ctx, args, obj))
48246
0
        goto fail;
48247
78
    ret = JS_Call(ctx, executor, JS_UNDEFINED, 2, (JSValueConst *)args);
48248
78
    if (JS_IsException(ret)) {
48249
0
        JSValue ret2, error;
48250
0
        error = JS_GetException(ctx);
48251
0
        ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
48252
0
        JS_FreeValue(ctx, error);
48253
0
        if (JS_IsException(ret2))
48254
0
            goto fail1;
48255
0
        JS_FreeValue(ctx, ret2);
48256
0
    }
48257
78
    JS_FreeValue(ctx, ret);
48258
78
    JS_FreeValue(ctx, args[0]);
48259
78
    JS_FreeValue(ctx, args[1]);
48260
78
    return obj;
48261
0
 fail1:
48262
0
    JS_FreeValue(ctx, args[0]);
48263
0
    JS_FreeValue(ctx, args[1]);
48264
0
 fail:
48265
0
    JS_FreeValue(ctx, obj);
48266
0
    return JS_EXCEPTION;
48267
0
}
48268
48269
static JSValue js_promise_executor(JSContext *ctx,
48270
                                   JSValueConst this_val,
48271
                                   int argc, JSValueConst *argv,
48272
                                   int magic, JSValue *func_data)
48273
78
{
48274
78
    int i;
48275
48276
234
    for(i = 0; i < 2; i++) {
48277
156
        if (!JS_IsUndefined(func_data[i]))
48278
0
            return JS_ThrowTypeError(ctx, "resolving function already set");
48279
156
        func_data[i] = JS_DupValue(ctx, argv[i]);
48280
156
    }
48281
78
    return JS_UNDEFINED;
48282
78
}
48283
48284
static JSValue js_promise_executor_new(JSContext *ctx)
48285
78
{
48286
78
    JSValueConst func_data[2];
48287
48288
78
    func_data[0] = JS_UNDEFINED;
48289
78
    func_data[1] = JS_UNDEFINED;
48290
78
    return JS_NewCFunctionData(ctx, js_promise_executor, 2,
48291
78
                               0, 2, func_data);
48292
78
}
48293
48294
static JSValue js_new_promise_capability(JSContext *ctx,
48295
                                         JSValue *resolving_funcs,
48296
                                         JSValueConst ctor)
48297
78
{
48298
78
    JSValue executor, result_promise;
48299
78
    JSCFunctionDataRecord *s;
48300
78
    int i;
48301
48302
78
    executor = js_promise_executor_new(ctx);
48303
78
    if (JS_IsException(executor))
48304
0
        return executor;
48305
48306
78
    if (JS_IsUndefined(ctor)) {
48307
78
        result_promise = js_promise_constructor(ctx, ctor, 1,
48308
78
                                                (JSValueConst *)&executor);
48309
78
    } else {
48310
0
        result_promise = JS_CallConstructor(ctx, ctor, 1,
48311
0
                                            (JSValueConst *)&executor);
48312
0
    }
48313
78
    if (JS_IsException(result_promise))
48314
0
        goto fail;
48315
78
    s = JS_GetOpaque(executor, JS_CLASS_C_FUNCTION_DATA);
48316
234
    for(i = 0; i < 2; i++) {
48317
156
        if (check_function(ctx, s->data[i]))
48318
0
            goto fail;
48319
156
    }
48320
234
    for(i = 0; i < 2; i++)
48321
156
        resolving_funcs[i] = JS_DupValue(ctx, s->data[i]);
48322
78
    JS_FreeValue(ctx, executor);
48323
78
    return result_promise;
48324
0
 fail:
48325
0
    JS_FreeValue(ctx, executor);
48326
0
    JS_FreeValue(ctx, result_promise);
48327
0
    return JS_EXCEPTION;
48328
78
}
48329
48330
JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs)
48331
78
{
48332
78
    return js_new_promise_capability(ctx, resolving_funcs, JS_UNDEFINED);
48333
78
}
48334
48335
static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
48336
                                  int argc, JSValueConst *argv, int magic)
48337
0
{
48338
0
    JSValue result_promise, resolving_funcs[2], ret;
48339
0
    BOOL is_reject = magic;
48340
48341
0
    if (!JS_IsObject(this_val))
48342
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
48343
0
    if (!is_reject && JS_GetOpaque(argv[0], JS_CLASS_PROMISE)) {
48344
0
        JSValue ctor;
48345
0
        BOOL is_same;
48346
0
        ctor = JS_GetProperty(ctx, argv[0], JS_ATOM_constructor);
48347
0
        if (JS_IsException(ctor))
48348
0
            return ctor;
48349
0
        is_same = js_same_value(ctx, ctor, this_val);
48350
0
        JS_FreeValue(ctx, ctor);
48351
0
        if (is_same)
48352
0
            return JS_DupValue(ctx, argv[0]);
48353
0
    }
48354
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
48355
0
    if (JS_IsException(result_promise))
48356
0
        return result_promise;
48357
0
    ret = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, argv);
48358
0
    JS_FreeValue(ctx, resolving_funcs[0]);
48359
0
    JS_FreeValue(ctx, resolving_funcs[1]);
48360
0
    if (JS_IsException(ret)) {
48361
0
        JS_FreeValue(ctx, result_promise);
48362
0
        return ret;
48363
0
    }
48364
0
    JS_FreeValue(ctx, ret);
48365
0
    return result_promise;
48366
0
}
48367
48368
static JSValue js_promise_withResolvers(JSContext *ctx,
48369
                                        JSValueConst this_val,
48370
                                        int argc, JSValueConst *argv)
48371
0
{
48372
0
    JSValue result_promise, resolving_funcs[2], obj;
48373
0
    if (!JS_IsObject(this_val))
48374
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
48375
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
48376
0
    if (JS_IsException(result_promise))
48377
0
        return result_promise;
48378
0
    obj = JS_NewObject(ctx);
48379
0
    if (JS_IsException(obj)) {
48380
0
        JS_FreeValue(ctx, resolving_funcs[0]);
48381
0
        JS_FreeValue(ctx, resolving_funcs[1]);
48382
0
        JS_FreeValue(ctx, result_promise);
48383
0
        return JS_EXCEPTION;
48384
0
    }
48385
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_promise, result_promise, JS_PROP_C_W_E);
48386
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_resolve, resolving_funcs[0], JS_PROP_C_W_E);
48387
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1], JS_PROP_C_W_E);
48388
0
    return obj;
48389
0
}
48390
48391
static __exception int remainingElementsCount_add(JSContext *ctx,
48392
                                                  JSValueConst resolve_element_env,
48393
                                                  int addend)
48394
0
{
48395
0
    JSValue val;
48396
0
    int remainingElementsCount;
48397
48398
0
    val = JS_GetPropertyUint32(ctx, resolve_element_env, 0);
48399
0
    if (JS_IsException(val))
48400
0
        return -1;
48401
0
    if (JS_ToInt32Free(ctx, &remainingElementsCount, val))
48402
0
        return -1;
48403
0
    remainingElementsCount += addend;
48404
0
    if (JS_SetPropertyUint32(ctx, resolve_element_env, 0,
48405
0
                             JS_NewInt32(ctx, remainingElementsCount)) < 0)
48406
0
        return -1;
48407
0
    return (remainingElementsCount == 0);
48408
0
}
48409
48410
#define PROMISE_MAGIC_all        0
48411
0
#define PROMISE_MAGIC_allSettled 1
48412
0
#define PROMISE_MAGIC_any        2
48413
48414
static JSValue js_promise_all_resolve_element(JSContext *ctx,
48415
                                              JSValueConst this_val,
48416
                                              int argc, JSValueConst *argv,
48417
                                              int magic,
48418
                                              JSValue *func_data)
48419
0
{
48420
0
    int resolve_type = magic & 3;
48421
0
    int is_reject = magic & 4;
48422
0
    BOOL alreadyCalled = JS_ToBool(ctx, func_data[0]);
48423
0
    JSValueConst values = func_data[2];
48424
0
    JSValueConst resolve = func_data[3];
48425
0
    JSValueConst resolve_element_env = func_data[4];
48426
0
    JSValue ret, obj;
48427
0
    int is_zero, index;
48428
48429
0
    if (JS_ToInt32(ctx, &index, func_data[1]))
48430
0
        return JS_EXCEPTION;
48431
0
    if (alreadyCalled)
48432
0
        return JS_UNDEFINED;
48433
0
    func_data[0] = JS_NewBool(ctx, TRUE);
48434
48435
0
    if (resolve_type == PROMISE_MAGIC_allSettled) {
48436
0
        JSValue str;
48437
48438
0
        obj = JS_NewObject(ctx);
48439
0
        if (JS_IsException(obj))
48440
0
            return JS_EXCEPTION;
48441
0
        str = JS_NewString(ctx, is_reject ? "rejected" : "fulfilled");
48442
0
        if (JS_IsException(str))
48443
0
            goto fail1;
48444
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_status,
48445
0
                                   str,
48446
0
                                   JS_PROP_C_W_E) < 0)
48447
0
            goto fail1;
48448
0
        if (JS_DefinePropertyValue(ctx, obj,
48449
0
                                   is_reject ? JS_ATOM_reason : JS_ATOM_value,
48450
0
                                   JS_DupValue(ctx, argv[0]),
48451
0
                                   JS_PROP_C_W_E) < 0) {
48452
0
        fail1:
48453
0
            JS_FreeValue(ctx, obj);
48454
0
            return JS_EXCEPTION;
48455
0
        }
48456
0
    } else {
48457
0
        obj = JS_DupValue(ctx, argv[0]);
48458
0
    }
48459
0
    if (JS_DefinePropertyValueUint32(ctx, values, index,
48460
0
                                     obj, JS_PROP_C_W_E) < 0)
48461
0
        return JS_EXCEPTION;
48462
48463
0
    is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
48464
0
    if (is_zero < 0)
48465
0
        return JS_EXCEPTION;
48466
0
    if (is_zero) {
48467
0
        if (resolve_type == PROMISE_MAGIC_any) {
48468
0
            JSValue error;
48469
0
            error = js_aggregate_error_constructor(ctx, values);
48470
0
            if (JS_IsException(error))
48471
0
                return JS_EXCEPTION;
48472
0
            ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&error);
48473
0
            JS_FreeValue(ctx, error);
48474
0
        } else {
48475
0
            ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values);
48476
0
        }
48477
0
        if (JS_IsException(ret))
48478
0
            return ret;
48479
0
        JS_FreeValue(ctx, ret);
48480
0
    }
48481
0
    return JS_UNDEFINED;
48482
0
}
48483
48484
/* magic = 0: Promise.all 1: Promise.allSettled */
48485
static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
48486
                              int argc, JSValueConst *argv, int magic)
48487
0
{
48488
0
    JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
48489
0
    JSValue next_method = JS_UNDEFINED, values = JS_UNDEFINED;
48490
0
    JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element;
48491
0
    JSValue promise_resolve = JS_UNDEFINED, iter = JS_UNDEFINED;
48492
0
    JSValueConst then_args[2], resolve_element_data[5];
48493
0
    BOOL done;
48494
0
    int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any);
48495
48496
0
    if (!JS_IsObject(this_val))
48497
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
48498
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
48499
0
    if (JS_IsException(result_promise))
48500
0
        return result_promise;
48501
0
    promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
48502
0
    if (JS_IsException(promise_resolve) ||
48503
0
        check_function(ctx, promise_resolve))
48504
0
        goto fail_reject;
48505
0
    iter = JS_GetIterator(ctx, argv[0], FALSE);
48506
0
    if (JS_IsException(iter)) {
48507
0
        JSValue error;
48508
0
    fail_reject:
48509
0
        error = JS_GetException(ctx);
48510
0
        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
48511
0
                       (JSValueConst *)&error);
48512
0
        JS_FreeValue(ctx, error);
48513
0
        if (JS_IsException(ret))
48514
0
            goto fail;
48515
0
        JS_FreeValue(ctx, ret);
48516
0
    } else {
48517
0
        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
48518
0
        if (JS_IsException(next_method))
48519
0
            goto fail_reject;
48520
0
        values = JS_NewArray(ctx);
48521
0
        if (JS_IsException(values))
48522
0
            goto fail_reject;
48523
0
        resolve_element_env = JS_NewArray(ctx);
48524
0
        if (JS_IsException(resolve_element_env))
48525
0
            goto fail_reject;
48526
        /* remainingElementsCount field */
48527
0
        if (JS_DefinePropertyValueUint32(ctx, resolve_element_env, 0,
48528
0
                                         JS_NewInt32(ctx, 1),
48529
0
                                         JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
48530
0
            goto fail_reject;
48531
48532
0
        index = 0;
48533
0
        for(;;) {
48534
            /* XXX: conformance: should close the iterator if error on 'done'
48535
               access, but not on 'value' access */
48536
0
            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
48537
0
            if (JS_IsException(item))
48538
0
                goto fail_reject;
48539
0
            if (done)
48540
0
                break;
48541
0
            next_promise = JS_Call(ctx, promise_resolve,
48542
0
                                   this_val, 1, (JSValueConst *)&item);
48543
0
            JS_FreeValue(ctx, item);
48544
0
            if (JS_IsException(next_promise)) {
48545
0
            fail_reject1:
48546
0
                JS_IteratorClose(ctx, iter, TRUE);
48547
0
                goto fail_reject;
48548
0
            }
48549
0
            resolve_element_data[0] = JS_NewBool(ctx, FALSE);
48550
0
            resolve_element_data[1] = (JSValueConst)JS_NewInt32(ctx, index);
48551
0
            resolve_element_data[2] = values;
48552
0
            resolve_element_data[3] = resolving_funcs[is_promise_any];
48553
0
            resolve_element_data[4] = resolve_element_env;
48554
0
            resolve_element =
48555
0
                JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
48556
0
                                    magic, 5, resolve_element_data);
48557
0
            if (JS_IsException(resolve_element)) {
48558
0
                JS_FreeValue(ctx, next_promise);
48559
0
                goto fail_reject1;
48560
0
            }
48561
48562
0
            if (magic == PROMISE_MAGIC_allSettled) {
48563
0
                reject_element =
48564
0
                    JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
48565
0
                                        magic | 4, 5, resolve_element_data);
48566
0
                if (JS_IsException(reject_element)) {
48567
0
                    JS_FreeValue(ctx, next_promise);
48568
0
                    goto fail_reject1;
48569
0
                }
48570
0
            } else if (magic == PROMISE_MAGIC_any) {
48571
0
                if (JS_DefinePropertyValueUint32(ctx, values, index,
48572
0
                                                 JS_UNDEFINED, JS_PROP_C_W_E) < 0)
48573
0
                    goto fail_reject1;
48574
0
                reject_element = resolve_element;
48575
0
                resolve_element = JS_DupValue(ctx, resolving_funcs[0]);
48576
0
            } else {
48577
0
                reject_element = JS_DupValue(ctx, resolving_funcs[1]);
48578
0
            }
48579
48580
0
            if (remainingElementsCount_add(ctx, resolve_element_env, 1) < 0) {
48581
0
                JS_FreeValue(ctx, next_promise);
48582
0
                JS_FreeValue(ctx, resolve_element);
48583
0
                JS_FreeValue(ctx, reject_element);
48584
0
                goto fail_reject1;
48585
0
            }
48586
48587
0
            then_args[0] = resolve_element;
48588
0
            then_args[1] = reject_element;
48589
0
            ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2, then_args);
48590
0
            JS_FreeValue(ctx, resolve_element);
48591
0
            JS_FreeValue(ctx, reject_element);
48592
0
            if (check_exception_free(ctx, ret))
48593
0
                goto fail_reject1;
48594
0
            index++;
48595
0
        }
48596
48597
0
        is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
48598
0
        if (is_zero < 0)
48599
0
            goto fail_reject;
48600
0
        if (is_zero) {
48601
0
            if (magic == PROMISE_MAGIC_any) {
48602
0
                JSValue error;
48603
0
                error = js_aggregate_error_constructor(ctx, values);
48604
0
                if (JS_IsException(error))
48605
0
                    goto fail_reject;
48606
0
                JS_FreeValue(ctx, values);
48607
0
                values = error;
48608
0
            }
48609
0
            ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED,
48610
0
                          1, (JSValueConst *)&values);
48611
0
            if (check_exception_free(ctx, ret))
48612
0
                goto fail_reject;
48613
0
        }
48614
0
    }
48615
0
 done:
48616
0
    JS_FreeValue(ctx, promise_resolve);
48617
0
    JS_FreeValue(ctx, resolve_element_env);
48618
0
    JS_FreeValue(ctx, values);
48619
0
    JS_FreeValue(ctx, next_method);
48620
0
    JS_FreeValue(ctx, iter);
48621
0
    JS_FreeValue(ctx, resolving_funcs[0]);
48622
0
    JS_FreeValue(ctx, resolving_funcs[1]);
48623
0
    return result_promise;
48624
0
 fail:
48625
0
    JS_FreeValue(ctx, result_promise);
48626
0
    result_promise = JS_EXCEPTION;
48627
0
    goto done;
48628
0
}
48629
48630
static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
48631
                               int argc, JSValueConst *argv)
48632
0
{
48633
0
    JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
48634
0
    JSValue next_method = JS_UNDEFINED, iter = JS_UNDEFINED;
48635
0
    JSValue promise_resolve = JS_UNDEFINED;
48636
0
    BOOL done;
48637
48638
0
    if (!JS_IsObject(this_val))
48639
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
48640
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
48641
0
    if (JS_IsException(result_promise))
48642
0
        return result_promise;
48643
0
    promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
48644
0
    if (JS_IsException(promise_resolve) ||
48645
0
        check_function(ctx, promise_resolve))
48646
0
        goto fail_reject;
48647
0
    iter = JS_GetIterator(ctx, argv[0], FALSE);
48648
0
    if (JS_IsException(iter)) {
48649
0
        JSValue error;
48650
0
    fail_reject:
48651
0
        error = JS_GetException(ctx);
48652
0
        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
48653
0
                       (JSValueConst *)&error);
48654
0
        JS_FreeValue(ctx, error);
48655
0
        if (JS_IsException(ret))
48656
0
            goto fail;
48657
0
        JS_FreeValue(ctx, ret);
48658
0
    } else {
48659
0
        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
48660
0
        if (JS_IsException(next_method))
48661
0
            goto fail_reject;
48662
48663
0
        for(;;) {
48664
            /* XXX: conformance: should close the iterator if error on 'done'
48665
               access, but not on 'value' access */
48666
0
            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
48667
0
            if (JS_IsException(item))
48668
0
                goto fail_reject;
48669
0
            if (done)
48670
0
                break;
48671
0
            next_promise = JS_Call(ctx, promise_resolve,
48672
0
                                   this_val, 1, (JSValueConst *)&item);
48673
0
            JS_FreeValue(ctx, item);
48674
0
            if (JS_IsException(next_promise)) {
48675
0
            fail_reject1:
48676
0
                JS_IteratorClose(ctx, iter, TRUE);
48677
0
                goto fail_reject;
48678
0
            }
48679
0
            ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2,
48680
0
                                (JSValueConst *)resolving_funcs);
48681
0
            if (check_exception_free(ctx, ret))
48682
0
                goto fail_reject1;
48683
0
        }
48684
0
    }
48685
0
 done:
48686
0
    JS_FreeValue(ctx, promise_resolve);
48687
0
    JS_FreeValue(ctx, next_method);
48688
0
    JS_FreeValue(ctx, iter);
48689
0
    JS_FreeValue(ctx, resolving_funcs[0]);
48690
0
    JS_FreeValue(ctx, resolving_funcs[1]);
48691
0
    return result_promise;
48692
0
 fail:
48693
    //JS_FreeValue(ctx, next_method); // why not???
48694
0
    JS_FreeValue(ctx, result_promise);
48695
0
    result_promise = JS_EXCEPTION;
48696
0
    goto done;
48697
0
}
48698
48699
static __exception int perform_promise_then(JSContext *ctx,
48700
                                            JSValueConst promise,
48701
                                            JSValueConst *resolve_reject,
48702
                                            JSValueConst *cap_resolving_funcs)
48703
0
{
48704
0
    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
48705
0
    JSPromiseReactionData *rd_array[2], *rd;
48706
0
    int i, j;
48707
48708
0
    rd_array[0] = NULL;
48709
0
    rd_array[1] = NULL;
48710
0
    for(i = 0; i < 2; i++) {
48711
0
        JSValueConst handler;
48712
0
        rd = js_mallocz(ctx, sizeof(*rd));
48713
0
        if (!rd) {
48714
0
            if (i == 1)
48715
0
                promise_reaction_data_free(ctx->rt, rd_array[0]);
48716
0
            return -1;
48717
0
        }
48718
0
        for(j = 0; j < 2; j++)
48719
0
            rd->resolving_funcs[j] = JS_DupValue(ctx, cap_resolving_funcs[j]);
48720
0
        handler = resolve_reject[i];
48721
0
        if (!JS_IsFunction(ctx, handler))
48722
0
            handler = JS_UNDEFINED;
48723
0
        rd->handler = JS_DupValue(ctx, handler);
48724
0
        rd_array[i] = rd;
48725
0
    }
48726
48727
0
    if (s->promise_state == JS_PROMISE_PENDING) {
48728
0
        for(i = 0; i < 2; i++)
48729
0
            list_add_tail(&rd_array[i]->link, &s->promise_reactions[i]);
48730
0
    } else {
48731
0
        JSValueConst args[5];
48732
0
        if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
48733
0
            JSRuntime *rt = ctx->rt;
48734
0
            if (rt->host_promise_rejection_tracker) {
48735
0
                rt->host_promise_rejection_tracker(ctx, promise, s->promise_result,
48736
0
                                                   TRUE, rt->host_promise_rejection_tracker_opaque);
48737
0
            }
48738
0
        }
48739
0
        i = s->promise_state - JS_PROMISE_FULFILLED;
48740
0
        rd = rd_array[i];
48741
0
        args[0] = rd->resolving_funcs[0];
48742
0
        args[1] = rd->resolving_funcs[1];
48743
0
        args[2] = rd->handler;
48744
0
        args[3] = JS_NewBool(ctx, i);
48745
0
        args[4] = s->promise_result;
48746
0
        JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
48747
0
        for(i = 0; i < 2; i++)
48748
0
            promise_reaction_data_free(ctx->rt, rd_array[i]);
48749
0
    }
48750
0
    s->is_handled = TRUE;
48751
0
    return 0;
48752
0
}
48753
48754
static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
48755
                               int argc, JSValueConst *argv)
48756
0
{
48757
0
    JSValue ctor, result_promise, resolving_funcs[2];
48758
0
    JSPromiseData *s;
48759
0
    int i, ret;
48760
48761
0
    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_PROMISE);
48762
0
    if (!s)
48763
0
        return JS_EXCEPTION;
48764
48765
0
    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
48766
0
    if (JS_IsException(ctor))
48767
0
        return ctor;
48768
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
48769
0
    JS_FreeValue(ctx, ctor);
48770
0
    if (JS_IsException(result_promise))
48771
0
        return result_promise;
48772
0
    ret = perform_promise_then(ctx, this_val, argv,
48773
0
                               (JSValueConst *)resolving_funcs);
48774
0
    for(i = 0; i < 2; i++)
48775
0
        JS_FreeValue(ctx, resolving_funcs[i]);
48776
0
    if (ret) {
48777
0
        JS_FreeValue(ctx, result_promise);
48778
0
        return JS_EXCEPTION;
48779
0
    }
48780
0
    return result_promise;
48781
0
}
48782
48783
static JSValue js_promise_catch(JSContext *ctx, JSValueConst this_val,
48784
                                int argc, JSValueConst *argv)
48785
0
{
48786
0
    JSValueConst args[2];
48787
0
    args[0] = JS_UNDEFINED;
48788
0
    args[1] = argv[0];
48789
0
    return JS_Invoke(ctx, this_val, JS_ATOM_then, 2, args);
48790
0
}
48791
48792
static JSValue js_promise_finally_value_thunk(JSContext *ctx, JSValueConst this_val,
48793
                                              int argc, JSValueConst *argv,
48794
                                              int magic, JSValue *func_data)
48795
0
{
48796
0
    return JS_DupValue(ctx, func_data[0]);
48797
0
}
48798
48799
static JSValue js_promise_finally_thrower(JSContext *ctx, JSValueConst this_val,
48800
                                          int argc, JSValueConst *argv,
48801
                                          int magic, JSValue *func_data)
48802
0
{
48803
0
    return JS_Throw(ctx, JS_DupValue(ctx, func_data[0]));
48804
0
}
48805
48806
static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_val,
48807
                                            int argc, JSValueConst *argv,
48808
                                            int magic, JSValue *func_data)
48809
0
{
48810
0
    JSValueConst ctor = func_data[0];
48811
0
    JSValueConst onFinally = func_data[1];
48812
0
    JSValue res, promise, ret, then_func;
48813
48814
0
    res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL);
48815
0
    if (JS_IsException(res))
48816
0
        return res;
48817
0
    promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0);
48818
0
    JS_FreeValue(ctx, res);
48819
0
    if (JS_IsException(promise))
48820
0
        return promise;
48821
0
    if (magic == 0) {
48822
0
        then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0,
48823
0
                                        0, 1, argv);
48824
0
    } else {
48825
0
        then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 0,
48826
0
                                        0, 1, argv);
48827
0
    }
48828
0
    if (JS_IsException(then_func)) {
48829
0
        JS_FreeValue(ctx, promise);
48830
0
        return then_func;
48831
0
    }
48832
0
    ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, (JSValueConst *)&then_func);
48833
0
    JS_FreeValue(ctx, then_func);
48834
0
    return ret;
48835
0
}
48836
48837
static JSValue js_promise_finally(JSContext *ctx, JSValueConst this_val,
48838
                                  int argc, JSValueConst *argv)
48839
0
{
48840
0
    JSValueConst onFinally = argv[0];
48841
0
    JSValue ctor, ret;
48842
0
    JSValue then_funcs[2];
48843
0
    JSValueConst func_data[2];
48844
0
    int i;
48845
48846
0
    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
48847
0
    if (JS_IsException(ctor))
48848
0
        return ctor;
48849
0
    if (!JS_IsFunction(ctx, onFinally)) {
48850
0
        then_funcs[0] = JS_DupValue(ctx, onFinally);
48851
0
        then_funcs[1] = JS_DupValue(ctx, onFinally);
48852
0
    } else {
48853
0
        func_data[0] = ctor;
48854
0
        func_data[1] = onFinally;
48855
0
        for(i = 0; i < 2; i++) {
48856
0
            then_funcs[i] = JS_NewCFunctionData(ctx, js_promise_then_finally_func, 1, i, 2, func_data);
48857
0
            if (JS_IsException(then_funcs[i])) {
48858
0
                if (i == 1)
48859
0
                    JS_FreeValue(ctx, then_funcs[0]);
48860
0
                JS_FreeValue(ctx, ctor);
48861
0
                return JS_EXCEPTION;
48862
0
            }
48863
0
        }
48864
0
    }
48865
0
    JS_FreeValue(ctx, ctor);
48866
0
    ret = JS_Invoke(ctx, this_val, JS_ATOM_then, 2, (JSValueConst *)then_funcs);
48867
0
    JS_FreeValue(ctx, then_funcs[0]);
48868
0
    JS_FreeValue(ctx, then_funcs[1]);
48869
0
    return ret;
48870
0
}
48871
48872
static const JSCFunctionListEntry js_promise_funcs[] = {
48873
    JS_CFUNC_MAGIC_DEF("resolve", 1, js_promise_resolve, 0 ),
48874
    JS_CFUNC_MAGIC_DEF("reject", 1, js_promise_resolve, 1 ),
48875
    JS_CFUNC_MAGIC_DEF("all", 1, js_promise_all, PROMISE_MAGIC_all ),
48876
    JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ),
48877
    JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ),
48878
    JS_CFUNC_DEF("race", 1, js_promise_race ),
48879
    JS_CFUNC_DEF("withResolvers", 0, js_promise_withResolvers ),
48880
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
48881
};
48882
48883
static const JSCFunctionListEntry js_promise_proto_funcs[] = {
48884
    JS_CFUNC_DEF("then", 2, js_promise_then ),
48885
    JS_CFUNC_DEF("catch", 1, js_promise_catch ),
48886
    JS_CFUNC_DEF("finally", 1, js_promise_finally ),
48887
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Promise", JS_PROP_CONFIGURABLE ),
48888
};
48889
48890
/* AsyncFunction */
48891
static const JSCFunctionListEntry js_async_function_proto_funcs[] = {
48892
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncFunction", JS_PROP_CONFIGURABLE ),
48893
};
48894
48895
static JSValue js_async_from_sync_iterator_unwrap(JSContext *ctx,
48896
                                                  JSValueConst this_val,
48897
                                                  int argc, JSValueConst *argv,
48898
                                                  int magic, JSValue *func_data)
48899
0
{
48900
0
    return js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]),
48901
0
                                     JS_ToBool(ctx, func_data[0]));
48902
0
}
48903
48904
static JSValue js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx,
48905
                                                              BOOL done)
48906
0
{
48907
0
    JSValueConst func_data[1];
48908
48909
0
    func_data[0] = (JSValueConst)JS_NewBool(ctx, done);
48910
0
    return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_unwrap,
48911
0
                               1, 0, 1, func_data);
48912
0
}
48913
48914
/* AsyncIteratorPrototype */
48915
48916
static const JSCFunctionListEntry js_async_iterator_proto_funcs[] = {
48917
    JS_CFUNC_DEF("[Symbol.asyncIterator]", 0, js_iterator_proto_iterator ),
48918
};
48919
48920
/* AsyncFromSyncIteratorPrototype */
48921
48922
typedef struct JSAsyncFromSyncIteratorData {
48923
    JSValue sync_iter;
48924
    JSValue next_method;
48925
} JSAsyncFromSyncIteratorData;
48926
48927
static void js_async_from_sync_iterator_finalizer(JSRuntime *rt, JSValue val)
48928
0
{
48929
0
    JSAsyncFromSyncIteratorData *s =
48930
0
        JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
48931
0
    if (s) {
48932
0
        JS_FreeValueRT(rt, s->sync_iter);
48933
0
        JS_FreeValueRT(rt, s->next_method);
48934
0
        js_free_rt(rt, s);
48935
0
    }
48936
0
}
48937
48938
static void js_async_from_sync_iterator_mark(JSRuntime *rt, JSValueConst val,
48939
                                             JS_MarkFunc *mark_func)
48940
0
{
48941
0
    JSAsyncFromSyncIteratorData *s =
48942
0
        JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
48943
0
    if (s) {
48944
0
        JS_MarkValue(rt, s->sync_iter, mark_func);
48945
0
        JS_MarkValue(rt, s->next_method, mark_func);
48946
0
    }
48947
0
}
48948
48949
static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
48950
                                              JSValueConst sync_iter)
48951
0
{
48952
0
    JSValue async_iter, next_method;
48953
0
    JSAsyncFromSyncIteratorData *s;
48954
48955
0
    next_method = JS_GetProperty(ctx, sync_iter, JS_ATOM_next);
48956
0
    if (JS_IsException(next_method))
48957
0
        return JS_EXCEPTION;
48958
0
    async_iter = JS_NewObjectClass(ctx, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
48959
0
    if (JS_IsException(async_iter)) {
48960
0
        JS_FreeValue(ctx, next_method);
48961
0
        return async_iter;
48962
0
    }
48963
0
    s = js_mallocz(ctx, sizeof(*s));
48964
0
    if (!s) {
48965
0
        JS_FreeValue(ctx, async_iter);
48966
0
        JS_FreeValue(ctx, next_method);
48967
0
        return JS_EXCEPTION;
48968
0
    }
48969
0
    s->sync_iter = JS_DupValue(ctx, sync_iter);
48970
0
    s->next_method = next_method;
48971
0
    JS_SetOpaque(async_iter, s);
48972
0
    return async_iter;
48973
0
}
48974
48975
static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst this_val,
48976
                                                int argc, JSValueConst *argv,
48977
                                                int magic)
48978
0
{
48979
0
    JSValue promise, resolving_funcs[2], value, err, method;
48980
0
    JSAsyncFromSyncIteratorData *s;
48981
0
    int done;
48982
0
    int is_reject;
48983
48984
0
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
48985
0
    if (JS_IsException(promise))
48986
0
        return JS_EXCEPTION;
48987
0
    s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
48988
0
    if (!s) {
48989
0
        JS_ThrowTypeError(ctx, "not an Async-from-Sync Iterator");
48990
0
        goto reject;
48991
0
    }
48992
48993
0
    if (magic == GEN_MAGIC_NEXT) {
48994
0
        method = JS_DupValue(ctx, s->next_method);
48995
0
    } else {
48996
0
        method = JS_GetProperty(ctx, s->sync_iter,
48997
0
                                magic == GEN_MAGIC_RETURN ? JS_ATOM_return :
48998
0
                                JS_ATOM_throw);
48999
0
        if (JS_IsException(method))
49000
0
            goto reject;
49001
0
        if (JS_IsUndefined(method) || JS_IsNull(method)) {
49002
0
            if (magic == GEN_MAGIC_RETURN) {
49003
0
                err = js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]), TRUE);
49004
0
                is_reject = 0;
49005
0
            } else {
49006
0
                err = JS_DupValue(ctx, argv[0]);
49007
0
                is_reject = 1;
49008
0
            }
49009
0
            goto done_resolve;
49010
0
        }
49011
0
    }
49012
0
    value = JS_IteratorNext2(ctx, s->sync_iter, method,
49013
0
                             argc >= 1 ? 1 : 0, argv, &done);
49014
0
    JS_FreeValue(ctx, method);
49015
0
    if (JS_IsException(value))
49016
0
        goto reject;
49017
0
    if (done == 2) {
49018
0
        JSValue obj = value;
49019
0
        value = JS_IteratorGetCompleteValue(ctx, obj, &done);
49020
0
        JS_FreeValue(ctx, obj);
49021
0
        if (JS_IsException(value))
49022
0
            goto reject;
49023
0
    }
49024
49025
0
    if (JS_IsException(value)) {
49026
0
        JSValue res2;
49027
0
    reject:
49028
0
        err = JS_GetException(ctx);
49029
0
        is_reject = 1;
49030
0
    done_resolve:
49031
0
        res2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED,
49032
0
                       1, (JSValueConst *)&err);
49033
0
        JS_FreeValue(ctx, err);
49034
0
        JS_FreeValue(ctx, res2);
49035
0
        JS_FreeValue(ctx, resolving_funcs[0]);
49036
0
        JS_FreeValue(ctx, resolving_funcs[1]);
49037
0
        return promise;
49038
0
    }
49039
0
    {
49040
0
        JSValue value_wrapper_promise, resolve_reject[2];
49041
0
        int res;
49042
49043
0
        value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor,
49044
0
                                                   1, (JSValueConst *)&value, 0);
49045
0
        if (JS_IsException(value_wrapper_promise)) {
49046
0
            JS_FreeValue(ctx, value);
49047
0
            goto reject;
49048
0
        }
49049
49050
0
        resolve_reject[0] =
49051
0
            js_async_from_sync_iterator_unwrap_func_create(ctx, done);
49052
0
        if (JS_IsException(resolve_reject[0])) {
49053
0
            JS_FreeValue(ctx, value_wrapper_promise);
49054
0
            goto fail;
49055
0
        }
49056
0
        JS_FreeValue(ctx, value);
49057
0
        resolve_reject[1] = JS_UNDEFINED;
49058
49059
0
        res = perform_promise_then(ctx, value_wrapper_promise,
49060
0
                                   (JSValueConst *)resolve_reject,
49061
0
                                   (JSValueConst *)resolving_funcs);
49062
0
        JS_FreeValue(ctx, resolve_reject[0]);
49063
0
        JS_FreeValue(ctx, value_wrapper_promise);
49064
0
        JS_FreeValue(ctx, resolving_funcs[0]);
49065
0
        JS_FreeValue(ctx, resolving_funcs[1]);
49066
0
        if (res) {
49067
0
            JS_FreeValue(ctx, promise);
49068
0
            return JS_EXCEPTION;
49069
0
        }
49070
0
    }
49071
0
    return promise;
49072
0
 fail:
49073
0
    JS_FreeValue(ctx, value);
49074
0
    JS_FreeValue(ctx, resolving_funcs[0]);
49075
0
    JS_FreeValue(ctx, resolving_funcs[1]);
49076
0
    JS_FreeValue(ctx, promise);
49077
0
    return JS_EXCEPTION;
49078
0
}
49079
49080
static const JSCFunctionListEntry js_async_from_sync_iterator_proto_funcs[] = {
49081
    JS_CFUNC_MAGIC_DEF("next", 1, js_async_from_sync_iterator_next, GEN_MAGIC_NEXT ),
49082
    JS_CFUNC_MAGIC_DEF("return", 1, js_async_from_sync_iterator_next, GEN_MAGIC_RETURN ),
49083
    JS_CFUNC_MAGIC_DEF("throw", 1, js_async_from_sync_iterator_next, GEN_MAGIC_THROW ),
49084
};
49085
49086
/* AsyncGeneratorFunction */
49087
49088
static const JSCFunctionListEntry js_async_generator_function_proto_funcs[] = {
49089
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGeneratorFunction", JS_PROP_CONFIGURABLE ),
49090
};
49091
49092
/* AsyncGenerator prototype */
49093
49094
static const JSCFunctionListEntry js_async_generator_proto_funcs[] = {
49095
    JS_CFUNC_MAGIC_DEF("next", 1, js_async_generator_next, GEN_MAGIC_NEXT ),
49096
    JS_CFUNC_MAGIC_DEF("return", 1, js_async_generator_next, GEN_MAGIC_RETURN ),
49097
    JS_CFUNC_MAGIC_DEF("throw", 1, js_async_generator_next, GEN_MAGIC_THROW ),
49098
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGenerator", JS_PROP_CONFIGURABLE ),
49099
};
49100
49101
static JSClassShortDef const js_async_class_def[] = {
49102
    { JS_ATOM_Promise, js_promise_finalizer, js_promise_mark },                      /* JS_CLASS_PROMISE */
49103
    { JS_ATOM_PromiseResolveFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_RESOLVE_FUNCTION */
49104
    { JS_ATOM_PromiseRejectFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_REJECT_FUNCTION */
49105
    { JS_ATOM_AsyncFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_FUNCTION */
49106
    { JS_ATOM_AsyncFunctionResolve, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_RESOLVE */
49107
    { JS_ATOM_AsyncFunctionReject, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_REJECT */
49108
    { JS_ATOM_empty_string, js_async_from_sync_iterator_finalizer, js_async_from_sync_iterator_mark }, /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
49109
    { JS_ATOM_AsyncGeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_GENERATOR_FUNCTION */
49110
    { JS_ATOM_AsyncGenerator, js_async_generator_finalizer, js_async_generator_mark },  /* JS_CLASS_ASYNC_GENERATOR */
49111
};
49112
49113
void JS_AddIntrinsicPromise(JSContext *ctx)
49114
39
{
49115
39
    JSRuntime *rt = ctx->rt;
49116
39
    JSValue obj1;
49117
49118
39
    if (!JS_IsRegisteredClass(rt, JS_CLASS_PROMISE)) {
49119
39
        init_class_range(rt, js_async_class_def, JS_CLASS_PROMISE,
49120
39
                         countof(js_async_class_def));
49121
39
        rt->class_array[JS_CLASS_PROMISE_RESOLVE_FUNCTION].call = js_promise_resolve_function_call;
49122
39
        rt->class_array[JS_CLASS_PROMISE_REJECT_FUNCTION].call = js_promise_resolve_function_call;
49123
39
        rt->class_array[JS_CLASS_ASYNC_FUNCTION].call = js_async_function_call;
49124
39
        rt->class_array[JS_CLASS_ASYNC_FUNCTION_RESOLVE].call = js_async_function_resolve_call;
49125
39
        rt->class_array[JS_CLASS_ASYNC_FUNCTION_REJECT].call = js_async_function_resolve_call;
49126
39
        rt->class_array[JS_CLASS_ASYNC_GENERATOR_FUNCTION].call = js_async_generator_function_call;
49127
39
    }
49128
49129
    /* Promise */
49130
39
    ctx->class_proto[JS_CLASS_PROMISE] = JS_NewObject(ctx);
49131
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_PROMISE],
49132
39
                               js_promise_proto_funcs,
49133
39
                               countof(js_promise_proto_funcs));
49134
39
    obj1 = JS_NewCFunction2(ctx, js_promise_constructor, "Promise", 1,
49135
39
                            JS_CFUNC_constructor, 0);
49136
39
    ctx->promise_ctor = JS_DupValue(ctx, obj1);
49137
39
    JS_SetPropertyFunctionList(ctx, obj1,
49138
39
                               js_promise_funcs,
49139
39
                               countof(js_promise_funcs));
49140
39
    JS_NewGlobalCConstructor2(ctx, obj1, "Promise",
49141
39
                              ctx->class_proto[JS_CLASS_PROMISE]);
49142
49143
    /* AsyncFunction */
49144
39
    ctx->class_proto[JS_CLASS_ASYNC_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
49145
39
    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
49146
39
                            "AsyncFunction", 1,
49147
39
                            JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC,
49148
39
                            ctx->function_ctor);
49149
39
    JS_SetPropertyFunctionList(ctx,
49150
39
                               ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
49151
39
                               js_async_function_proto_funcs,
49152
39
                               countof(js_async_function_proto_funcs));
49153
39
    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
49154
39
                       0, JS_PROP_CONFIGURABLE);
49155
39
    JS_FreeValue(ctx, obj1);
49156
49157
    /* AsyncIteratorPrototype */
49158
39
    ctx->async_iterator_proto = JS_NewObject(ctx);
49159
39
    JS_SetPropertyFunctionList(ctx, ctx->async_iterator_proto,
49160
39
                               js_async_iterator_proto_funcs,
49161
39
                               countof(js_async_iterator_proto_funcs));
49162
49163
    /* AsyncFromSyncIteratorPrototype */
49164
39
    ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR] =
49165
39
        JS_NewObjectProto(ctx, ctx->async_iterator_proto);
49166
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR],
49167
39
                               js_async_from_sync_iterator_proto_funcs,
49168
39
                               countof(js_async_from_sync_iterator_proto_funcs));
49169
49170
    /* AsyncGeneratorPrototype */
49171
39
    ctx->class_proto[JS_CLASS_ASYNC_GENERATOR] =
49172
39
        JS_NewObjectProto(ctx, ctx->async_iterator_proto);
49173
39
    JS_SetPropertyFunctionList(ctx,
49174
39
                               ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
49175
39
                               js_async_generator_proto_funcs,
49176
39
                               countof(js_async_generator_proto_funcs));
49177
49178
    /* AsyncGeneratorFunction */
49179
39
    ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION] =
49180
39
        JS_NewObjectProto(ctx, ctx->function_proto);
49181
39
    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
49182
39
                            "AsyncGeneratorFunction", 1,
49183
39
                            JS_CFUNC_constructor_or_func_magic,
49184
39
                            JS_FUNC_ASYNC_GENERATOR,
49185
39
                            ctx->function_ctor);
49186
39
    JS_SetPropertyFunctionList(ctx,
49187
39
                               ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
49188
39
                               js_async_generator_function_proto_funcs,
49189
39
                               countof(js_async_generator_function_proto_funcs));
49190
39
    JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
49191
39
                       ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
49192
39
                       JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
49193
39
    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
49194
39
                       0, JS_PROP_CONFIGURABLE);
49195
39
    JS_FreeValue(ctx, obj1);
49196
39
}
49197
49198
/* URI handling */
49199
49200
0
static int string_get_hex(JSString *p, int k, int n) {
49201
0
    int c = 0, h;
49202
0
    while (n-- > 0) {
49203
0
        if ((h = from_hex(string_get(p, k++))) < 0)
49204
0
            return -1;
49205
0
        c = (c << 4) | h;
49206
0
    }
49207
0
    return c;
49208
0
}
49209
49210
0
static int isURIReserved(int c) {
49211
0
    return c < 0x100 && memchr(";/?:@&=+$,#", c, sizeof(";/?:@&=+$,#") - 1) != NULL;
49212
0
}
49213
49214
static int __attribute__((format(printf, 2, 3))) js_throw_URIError(JSContext *ctx, const char *fmt, ...)
49215
0
{
49216
0
    va_list ap;
49217
49218
0
    va_start(ap, fmt);
49219
0
    JS_ThrowError(ctx, JS_URI_ERROR, fmt, ap);
49220
0
    va_end(ap);
49221
0
    return -1;
49222
0
}
49223
49224
0
static int hex_decode(JSContext *ctx, JSString *p, int k) {
49225
0
    int c;
49226
49227
0
    if (k >= p->len || string_get(p, k) != '%')
49228
0
        return js_throw_URIError(ctx, "expecting %%");
49229
0
    if (k + 2 >= p->len || (c = string_get_hex(p, k + 1, 2)) < 0)
49230
0
        return js_throw_URIError(ctx, "expecting hex digit");
49231
49232
0
    return c;
49233
0
}
49234
49235
static JSValue js_global_decodeURI(JSContext *ctx, JSValueConst this_val,
49236
                                   int argc, JSValueConst *argv, int isComponent)
49237
0
{
49238
0
    JSValue str;
49239
0
    StringBuffer b_s, *b = &b_s;
49240
0
    JSString *p;
49241
0
    int k, c, c1, n, c_min;
49242
49243
0
    str = JS_ToString(ctx, argv[0]);
49244
0
    if (JS_IsException(str))
49245
0
        return str;
49246
49247
0
    string_buffer_init(ctx, b, 0);
49248
49249
0
    p = JS_VALUE_GET_STRING(str);
49250
0
    for (k = 0; k < p->len;) {
49251
0
        c = string_get(p, k);
49252
0
        if (c == '%') {
49253
0
            c = hex_decode(ctx, p, k);
49254
0
            if (c < 0)
49255
0
                goto fail;
49256
0
            k += 3;
49257
0
            if (c < 0x80) {
49258
0
                if (!isComponent && isURIReserved(c)) {
49259
0
                    c = '%';
49260
0
                    k -= 2;
49261
0
                }
49262
0
            } else {
49263
                /* Decode URI-encoded UTF-8 sequence */
49264
0
                if (c >= 0xc0 && c <= 0xdf) {
49265
0
                    n = 1;
49266
0
                    c_min = 0x80;
49267
0
                    c &= 0x1f;
49268
0
                } else if (c >= 0xe0 && c <= 0xef) {
49269
0
                    n = 2;
49270
0
                    c_min = 0x800;
49271
0
                    c &= 0xf;
49272
0
                } else if (c >= 0xf0 && c <= 0xf7) {
49273
0
                    n = 3;
49274
0
                    c_min = 0x10000;
49275
0
                    c &= 0x7;
49276
0
                } else {
49277
0
                    n = 0;
49278
0
                    c_min = 1;
49279
0
                    c = 0;
49280
0
                }
49281
0
                while (n-- > 0) {
49282
0
                    c1 = hex_decode(ctx, p, k);
49283
0
                    if (c1 < 0)
49284
0
                        goto fail;
49285
0
                    k += 3;
49286
0
                    if ((c1 & 0xc0) != 0x80) {
49287
0
                        c = 0;
49288
0
                        break;
49289
0
                    }
49290
0
                    c = (c << 6) | (c1 & 0x3f);
49291
0
                }
49292
0
                if (c < c_min || c > 0x10FFFF || is_surrogate(c)) {
49293
0
                    js_throw_URIError(ctx, "malformed UTF-8");
49294
0
                    goto fail;
49295
0
                }
49296
0
            }
49297
0
        } else {
49298
0
            k++;
49299
0
        }
49300
0
        string_buffer_putc(b, c);
49301
0
    }
49302
0
    JS_FreeValue(ctx, str);
49303
0
    return string_buffer_end(b);
49304
49305
0
fail:
49306
0
    JS_FreeValue(ctx, str);
49307
0
    string_buffer_free(b);
49308
0
    return JS_EXCEPTION;
49309
0
}
49310
49311
0
static int isUnescaped(int c) {
49312
0
    static char const unescaped_chars[] =
49313
0
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
49314
0
        "abcdefghijklmnopqrstuvwxyz"
49315
0
        "0123456789"
49316
0
        "@*_+-./";
49317
0
    return c < 0x100 &&
49318
0
        memchr(unescaped_chars, c, sizeof(unescaped_chars) - 1);
49319
0
}
49320
49321
0
static int isURIUnescaped(int c, int isComponent) {
49322
0
    return c < 0x100 &&
49323
0
        ((c >= 0x61 && c <= 0x7a) ||
49324
0
         (c >= 0x41 && c <= 0x5a) ||
49325
0
         (c >= 0x30 && c <= 0x39) ||
49326
0
         memchr("-_.!~*'()", c, sizeof("-_.!~*'()") - 1) != NULL ||
49327
0
         (!isComponent && isURIReserved(c)));
49328
0
}
49329
49330
0
static int encodeURI_hex(StringBuffer *b, int c) {
49331
0
    uint8_t buf[6];
49332
0
    int n = 0;
49333
0
    const char *hex = "0123456789ABCDEF";
49334
49335
0
    buf[n++] = '%';
49336
0
    if (c >= 256) {
49337
0
        buf[n++] = 'u';
49338
0
        buf[n++] = hex[(c >> 12) & 15];
49339
0
        buf[n++] = hex[(c >>  8) & 15];
49340
0
    }
49341
0
    buf[n++] = hex[(c >> 4) & 15];
49342
0
    buf[n++] = hex[(c >> 0) & 15];
49343
0
    return string_buffer_write8(b, buf, n);
49344
0
}
49345
49346
static JSValue js_global_encodeURI(JSContext *ctx, JSValueConst this_val,
49347
                                   int argc, JSValueConst *argv,
49348
                                   int isComponent)
49349
0
{
49350
0
    JSValue str;
49351
0
    StringBuffer b_s, *b = &b_s;
49352
0
    JSString *p;
49353
0
    int k, c, c1;
49354
49355
0
    str = JS_ToString(ctx, argv[0]);
49356
0
    if (JS_IsException(str))
49357
0
        return str;
49358
49359
0
    p = JS_VALUE_GET_STRING(str);
49360
0
    string_buffer_init(ctx, b, p->len);
49361
0
    for (k = 0; k < p->len;) {
49362
0
        c = string_get(p, k);
49363
0
        k++;
49364
0
        if (isURIUnescaped(c, isComponent)) {
49365
0
            string_buffer_putc16(b, c);
49366
0
        } else {
49367
0
            if (is_lo_surrogate(c)) {
49368
0
                js_throw_URIError(ctx, "invalid character");
49369
0
                goto fail;
49370
0
            } else if (is_hi_surrogate(c)) {
49371
0
                if (k >= p->len) {
49372
0
                    js_throw_URIError(ctx, "expecting surrogate pair");
49373
0
                    goto fail;
49374
0
                }
49375
0
                c1 = string_get(p, k);
49376
0
                k++;
49377
0
                if (!is_lo_surrogate(c1)) {
49378
0
                    js_throw_URIError(ctx, "expecting surrogate pair");
49379
0
                    goto fail;
49380
0
                }
49381
0
                c = from_surrogate(c, c1);
49382
0
            }
49383
0
            if (c < 0x80) {
49384
0
                encodeURI_hex(b, c);
49385
0
            } else {
49386
                /* XXX: use C UTF-8 conversion ? */
49387
0
                if (c < 0x800) {
49388
0
                    encodeURI_hex(b, (c >> 6) | 0xc0);
49389
0
                } else {
49390
0
                    if (c < 0x10000) {
49391
0
                        encodeURI_hex(b, (c >> 12) | 0xe0);
49392
0
                    } else {
49393
0
                        encodeURI_hex(b, (c >> 18) | 0xf0);
49394
0
                        encodeURI_hex(b, ((c >> 12) & 0x3f) | 0x80);
49395
0
                    }
49396
0
                    encodeURI_hex(b, ((c >> 6) & 0x3f) | 0x80);
49397
0
                }
49398
0
                encodeURI_hex(b, (c & 0x3f) | 0x80);
49399
0
            }
49400
0
        }
49401
0
    }
49402
0
    JS_FreeValue(ctx, str);
49403
0
    return string_buffer_end(b);
49404
49405
0
fail:
49406
0
    JS_FreeValue(ctx, str);
49407
0
    string_buffer_free(b);
49408
0
    return JS_EXCEPTION;
49409
0
}
49410
49411
static JSValue js_global_escape(JSContext *ctx, JSValueConst this_val,
49412
                                int argc, JSValueConst *argv)
49413
0
{
49414
0
    JSValue str;
49415
0
    StringBuffer b_s, *b = &b_s;
49416
0
    JSString *p;
49417
0
    int i, len, c;
49418
49419
0
    str = JS_ToString(ctx, argv[0]);
49420
0
    if (JS_IsException(str))
49421
0
        return str;
49422
49423
0
    p = JS_VALUE_GET_STRING(str);
49424
0
    string_buffer_init(ctx, b, p->len);
49425
0
    for (i = 0, len = p->len; i < len; i++) {
49426
0
        c = string_get(p, i);
49427
0
        if (isUnescaped(c)) {
49428
0
            string_buffer_putc16(b, c);
49429
0
        } else {
49430
0
            encodeURI_hex(b, c);
49431
0
        }
49432
0
    }
49433
0
    JS_FreeValue(ctx, str);
49434
0
    return string_buffer_end(b);
49435
0
}
49436
49437
static JSValue js_global_unescape(JSContext *ctx, JSValueConst this_val,
49438
                                  int argc, JSValueConst *argv)
49439
0
{
49440
0
    JSValue str;
49441
0
    StringBuffer b_s, *b = &b_s;
49442
0
    JSString *p;
49443
0
    int i, len, c, n;
49444
49445
0
    str = JS_ToString(ctx, argv[0]);
49446
0
    if (JS_IsException(str))
49447
0
        return str;
49448
49449
0
    string_buffer_init(ctx, b, 0);
49450
0
    p = JS_VALUE_GET_STRING(str);
49451
0
    for (i = 0, len = p->len; i < len; i++) {
49452
0
        c = string_get(p, i);
49453
0
        if (c == '%') {
49454
0
            if (i + 6 <= len
49455
0
            &&  string_get(p, i + 1) == 'u'
49456
0
            &&  (n = string_get_hex(p, i + 2, 4)) >= 0) {
49457
0
                c = n;
49458
0
                i += 6 - 1;
49459
0
            } else
49460
0
            if (i + 3 <= len
49461
0
            &&  (n = string_get_hex(p, i + 1, 2)) >= 0) {
49462
0
                c = n;
49463
0
                i += 3 - 1;
49464
0
            }
49465
0
        }
49466
0
        string_buffer_putc16(b, c);
49467
0
    }
49468
0
    JS_FreeValue(ctx, str);
49469
0
    return string_buffer_end(b);
49470
0
}
49471
49472
/* global object */
49473
49474
static const JSCFunctionListEntry js_global_funcs[] = {
49475
    JS_CFUNC_DEF("parseInt", 2, js_parseInt ),
49476
    JS_CFUNC_DEF("parseFloat", 1, js_parseFloat ),
49477
    JS_CFUNC_DEF("isNaN", 1, js_global_isNaN ),
49478
    JS_CFUNC_DEF("isFinite", 1, js_global_isFinite ),
49479
49480
    JS_CFUNC_MAGIC_DEF("decodeURI", 1, js_global_decodeURI, 0 ),
49481
    JS_CFUNC_MAGIC_DEF("decodeURIComponent", 1, js_global_decodeURI, 1 ),
49482
    JS_CFUNC_MAGIC_DEF("encodeURI", 1, js_global_encodeURI, 0 ),
49483
    JS_CFUNC_MAGIC_DEF("encodeURIComponent", 1, js_global_encodeURI, 1 ),
49484
    JS_CFUNC_DEF("escape", 1, js_global_escape ),
49485
    JS_CFUNC_DEF("unescape", 1, js_global_unescape ),
49486
    JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ),
49487
    JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
49488
    JS_PROP_UNDEFINED_DEF("undefined", 0 ),
49489
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "global", JS_PROP_CONFIGURABLE ),
49490
};
49491
49492
/* Date */
49493
49494
0
static int64_t math_mod(int64_t a, int64_t b) {
49495
    /* return positive modulo */
49496
0
    int64_t m = a % b;
49497
0
    return m + (m < 0) * b;
49498
0
}
49499
49500
0
static int64_t floor_div(int64_t a, int64_t b) {
49501
    /* integer division rounding toward -Infinity */
49502
0
    int64_t m = a % b;
49503
0
    return (a - (m + (m < 0) * b)) / b;
49504
0
}
49505
49506
static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
49507
                             int argc, JSValueConst *argv);
49508
49509
static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val)
49510
0
{
49511
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
49512
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
49513
0
        if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data))
49514
0
            return JS_ToFloat64(ctx, valp, p->u.object_data);
49515
0
    }
49516
0
    JS_ThrowTypeError(ctx, "not a Date object");
49517
0
    return -1;
49518
0
}
49519
49520
static JSValue JS_SetThisTimeValue(JSContext *ctx, JSValueConst this_val, double v)
49521
0
{
49522
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
49523
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
49524
0
        if (p->class_id == JS_CLASS_DATE) {
49525
0
            JS_FreeValue(ctx, p->u.object_data);
49526
0
            p->u.object_data = JS_NewFloat64(ctx, v);
49527
0
            return JS_DupValue(ctx, p->u.object_data);
49528
0
        }
49529
0
    }
49530
0
    return JS_ThrowTypeError(ctx, "not a Date object");
49531
0
}
49532
49533
0
static int64_t days_from_year(int64_t y) {
49534
0
    return 365 * (y - 1970) + floor_div(y - 1969, 4) -
49535
0
        floor_div(y - 1901, 100) + floor_div(y - 1601, 400);
49536
0
}
49537
49538
0
static int64_t days_in_year(int64_t y) {
49539
0
    return 365 + !(y % 4) - !(y % 100) + !(y % 400);
49540
0
}
49541
49542
/* return the year, update days */
49543
0
static int64_t year_from_days(int64_t *days) {
49544
0
    int64_t y, d1, nd, d = *days;
49545
0
    y = floor_div(d * 10000, 3652425) + 1970;
49546
    /* the initial approximation is very good, so only a few
49547
       iterations are necessary */
49548
0
    for(;;) {
49549
0
        d1 = d - days_from_year(y);
49550
0
        if (d1 < 0) {
49551
0
            y--;
49552
0
            d1 += days_in_year(y);
49553
0
        } else {
49554
0
            nd = days_in_year(y);
49555
0
            if (d1 < nd)
49556
0
                break;
49557
0
            d1 -= nd;
49558
0
            y++;
49559
0
        }
49560
0
    }
49561
0
    *days = d1;
49562
0
    return y;
49563
0
}
49564
49565
static int const month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
49566
static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
49567
static char const day_names[] = "SunMonTueWedThuFriSat";
49568
49569
static __exception int get_date_fields(JSContext *ctx, JSValueConst obj,
49570
                                       double fields[minimum_length(9)], int is_local, int force)
49571
0
{
49572
0
    double dval;
49573
0
    int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0;
49574
49575
0
    if (JS_ThisTimeValue(ctx, &dval, obj))
49576
0
        return -1;
49577
49578
0
    if (isnan(dval)) {
49579
0
        if (!force)
49580
0
            return FALSE; /* NaN */
49581
0
        d = 0;        /* initialize all fields to 0 */
49582
0
    } else {
49583
0
        d = dval;     /* assuming -8.64e15 <= dval <= -8.64e15 */
49584
0
        if (is_local) {
49585
0
            tz = -getTimezoneOffset(d);
49586
0
            d += tz * 60000;
49587
0
        }
49588
0
    }
49589
49590
    /* result is >= 0, we can use % */
49591
0
    h = math_mod(d, 86400000);
49592
0
    days = (d - h) / 86400000;
49593
0
    ms = h % 1000;
49594
0
    h = (h - ms) / 1000;
49595
0
    s = h % 60;
49596
0
    h = (h - s) / 60;
49597
0
    m = h % 60;
49598
0
    h = (h - m) / 60;
49599
0
    wd = math_mod(days + 4, 7); /* week day */
49600
0
    y = year_from_days(&days);
49601
49602
0
    for(i = 0; i < 11; i++) {
49603
0
        md = month_days[i];
49604
0
        if (i == 1)
49605
0
            md += days_in_year(y) - 365;
49606
0
        if (days < md)
49607
0
            break;
49608
0
        days -= md;
49609
0
    }
49610
0
    fields[0] = y;
49611
0
    fields[1] = i;
49612
0
    fields[2] = days + 1;
49613
0
    fields[3] = h;
49614
0
    fields[4] = m;
49615
0
    fields[5] = s;
49616
0
    fields[6] = ms;
49617
0
    fields[7] = wd;
49618
0
    fields[8] = tz;
49619
0
    return TRUE;
49620
0
}
49621
49622
0
static double time_clip(double t) {
49623
0
    if (t >= -8.64e15 && t <= 8.64e15)
49624
0
        return trunc(t) + 0.0;  /* convert -0 to +0 */
49625
0
    else
49626
0
        return NAN;
49627
0
}
49628
49629
/* The spec mandates the use of 'double' and it specifies the order
49630
   of the operations */
49631
0
static double set_date_fields(double fields[minimum_length(7)], int is_local) {
49632
0
    double y, m, dt, ym, mn, day, h, s, milli, time, tv;
49633
0
    int yi, mi, i;
49634
0
    int64_t days;
49635
0
    volatile double temp;  /* enforce evaluation order */
49636
49637
    /* emulate 21.4.1.15 MakeDay ( year, month, date ) */
49638
0
    y = fields[0];
49639
0
    m = fields[1];
49640
0
    dt = fields[2];
49641
0
    ym = y + floor(m / 12);
49642
0
    mn = fmod(m, 12);
49643
0
    if (mn < 0)
49644
0
        mn += 12;
49645
0
    if (ym < -271821 || ym > 275760)
49646
0
        return NAN;
49647
49648
0
    yi = ym;
49649
0
    mi = mn;
49650
0
    days = days_from_year(yi);
49651
0
    for(i = 0; i < mi; i++) {
49652
0
        days += month_days[i];
49653
0
        if (i == 1)
49654
0
            days += days_in_year(yi) - 365;
49655
0
    }
49656
0
    day = days + dt - 1;
49657
49658
    /* emulate 21.4.1.14 MakeTime ( hour, min, sec, ms ) */
49659
0
    h = fields[3];
49660
0
    m = fields[4];
49661
0
    s = fields[5];
49662
0
    milli = fields[6];
49663
    /* Use a volatile intermediary variable to ensure order of evaluation
49664
     * as specified in ECMA. This fixes a test262 error on
49665
     * test262/test/built-ins/Date/UTC/fp-evaluation-order.js.
49666
     * Without the volatile qualifier, the compile can generate code
49667
     * that performs the computation in a different order or with instructions
49668
     * that produce a different result such as FMA (float multiply and add).
49669
     */
49670
0
    time = h * 3600000;
49671
0
    time += (temp = m * 60000);
49672
0
    time += (temp = s * 1000);
49673
0
    time += milli;
49674
49675
    /* emulate 21.4.1.16 MakeDate ( day, time ) */
49676
0
    tv = (temp = day * 86400000) + time;   /* prevent generation of FMA */
49677
0
    if (!isfinite(tv))
49678
0
        return NAN;
49679
49680
    /* adjust for local time and clip */
49681
0
    if (is_local) {
49682
0
        int64_t ti = tv < INT64_MIN ? INT64_MIN : tv >= 0x1p63 ? INT64_MAX : (int64_t)tv;
49683
0
        tv += getTimezoneOffset(ti) * 60000;
49684
0
    }
49685
0
    return time_clip(tv);
49686
0
}
49687
49688
static JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
49689
                              int argc, JSValueConst *argv, int magic)
49690
0
{
49691
    // get_date_field(obj, n, is_local)
49692
0
    double fields[9];
49693
0
    int res, n, is_local;
49694
49695
0
    is_local = magic & 0x0F;
49696
0
    n = (magic >> 4) & 0x0F;
49697
0
    res = get_date_fields(ctx, this_val, fields, is_local, 0);
49698
0
    if (res < 0)
49699
0
        return JS_EXCEPTION;
49700
0
    if (!res)
49701
0
        return JS_NAN;
49702
49703
0
    if (magic & 0x100) {    // getYear
49704
0
        fields[0] -= 1900;
49705
0
    }
49706
0
    return JS_NewFloat64(ctx, fields[n]);
49707
0
}
49708
49709
static JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
49710
                              int argc, JSValueConst *argv, int magic)
49711
0
{
49712
    // _field(obj, first_field, end_field, args, is_local)
49713
0
    double fields[9];
49714
0
    int res, first_field, end_field, is_local, i, n;
49715
0
    double d, a;
49716
49717
0
    d = NAN;
49718
0
    first_field = (magic >> 8) & 0x0F;
49719
0
    end_field = (magic >> 4) & 0x0F;
49720
0
    is_local = magic & 0x0F;
49721
49722
0
    res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0);
49723
0
    if (res < 0)
49724
0
        return JS_EXCEPTION;
49725
49726
    // Argument coercion is observable and must be done unconditionally.
49727
0
    n = min_int(argc, end_field - first_field);
49728
0
    for(i = 0; i < n; i++) {
49729
0
        if (JS_ToFloat64(ctx, &a, argv[i]))
49730
0
            return JS_EXCEPTION;
49731
0
        if (!isfinite(a))
49732
0
            res = FALSE;
49733
0
        fields[first_field + i] = trunc(a);
49734
0
    }
49735
0
    if (res && argc > 0)
49736
0
        d = set_date_fields(fields, is_local);
49737
49738
0
    return JS_SetThisTimeValue(ctx, this_val, d);
49739
0
}
49740
49741
/* fmt:
49742
   0: toUTCString: "Tue, 02 Jan 2018 23:04:46 GMT"
49743
   1: toString: "Wed Jan 03 2018 00:05:22 GMT+0100 (CET)"
49744
   2: toISOString: "2018-01-02T23:02:56.927Z"
49745
   3: toLocaleString: "1/2/2018, 11:40:40 PM"
49746
   part: 1=date, 2=time 3=all
49747
   XXX: should use a variant of strftime().
49748
 */
49749
static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
49750
                               int argc, JSValueConst *argv, int magic)
49751
0
{
49752
    // _string(obj, fmt, part)
49753
0
    char buf[64];
49754
0
    double fields[9];
49755
0
    int res, fmt, part, pos;
49756
0
    int y, mon, d, h, m, s, ms, wd, tz;
49757
49758
0
    fmt = (magic >> 4) & 0x0F;
49759
0
    part = magic & 0x0F;
49760
49761
0
    res = get_date_fields(ctx, this_val, fields, fmt & 1, 0);
49762
0
    if (res < 0)
49763
0
        return JS_EXCEPTION;
49764
0
    if (!res) {
49765
0
        if (fmt == 2)
49766
0
            return JS_ThrowRangeError(ctx, "Date value is NaN");
49767
0
        else
49768
0
            return JS_NewString(ctx, "Invalid Date");
49769
0
    }
49770
49771
0
    y = fields[0];
49772
0
    mon = fields[1];
49773
0
    d = fields[2];
49774
0
    h = fields[3];
49775
0
    m = fields[4];
49776
0
    s = fields[5];
49777
0
    ms = fields[6];
49778
0
    wd = fields[7];
49779
0
    tz = fields[8];
49780
49781
0
    pos = 0;
49782
49783
0
    if (part & 1) { /* date part */
49784
0
        switch(fmt) {
49785
0
        case 0:
49786
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
49787
0
                            "%.3s, %02d %.3s %0*d ",
49788
0
                            day_names + wd * 3, d,
49789
0
                            month_names + mon * 3, 4 + (y < 0), y);
49790
0
            break;
49791
0
        case 1:
49792
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
49793
0
                            "%.3s %.3s %02d %0*d",
49794
0
                            day_names + wd * 3,
49795
0
                            month_names + mon * 3, d, 4 + (y < 0), y);
49796
0
            if (part == 3) {
49797
0
                buf[pos++] = ' ';
49798
0
            }
49799
0
            break;
49800
0
        case 2:
49801
0
            if (y >= 0 && y <= 9999) {
49802
0
                pos += snprintf(buf + pos, sizeof(buf) - pos,
49803
0
                                "%04d", y);
49804
0
            } else {
49805
0
                pos += snprintf(buf + pos, sizeof(buf) - pos,
49806
0
                                "%+07d", y);
49807
0
            }
49808
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
49809
0
                            "-%02d-%02dT", mon + 1, d);
49810
0
            break;
49811
0
        case 3:
49812
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
49813
0
                            "%02d/%02d/%0*d", mon + 1, d, 4 + (y < 0), y);
49814
0
            if (part == 3) {
49815
0
                buf[pos++] = ',';
49816
0
                buf[pos++] = ' ';
49817
0
            }
49818
0
            break;
49819
0
        }
49820
0
    }
49821
0
    if (part & 2) { /* time part */
49822
0
        switch(fmt) {
49823
0
        case 0:
49824
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
49825
0
                            "%02d:%02d:%02d GMT", h, m, s);
49826
0
            break;
49827
0
        case 1:
49828
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
49829
0
                            "%02d:%02d:%02d GMT", h, m, s);
49830
0
            if (tz < 0) {
49831
0
                buf[pos++] = '-';
49832
0
                tz = -tz;
49833
0
            } else {
49834
0
                buf[pos++] = '+';
49835
0
            }
49836
            /* tz is >= 0, can use % */
49837
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
49838
0
                            "%02d%02d", tz / 60, tz % 60);
49839
            /* XXX: tack the time zone code? */
49840
0
            break;
49841
0
        case 2:
49842
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
49843
0
                            "%02d:%02d:%02d.%03dZ", h, m, s, ms);
49844
0
            break;
49845
0
        case 3:
49846
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
49847
0
                            "%02d:%02d:%02d %cM", (h + 11) % 12 + 1, m, s,
49848
0
                            (h < 12) ? 'A' : 'P');
49849
0
            break;
49850
0
        }
49851
0
    }
49852
0
    return JS_NewStringLen(ctx, buf, pos);
49853
0
}
49854
49855
/* OS dependent: return the UTC time in ms since 1970. */
49856
0
static int64_t date_now(void) {
49857
0
    struct timeval tv;
49858
0
    gettimeofday(&tv, NULL);
49859
0
    return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
49860
0
}
49861
49862
static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,
49863
                                   int argc, JSValueConst *argv)
49864
0
{
49865
    // Date(y, mon, d, h, m, s, ms)
49866
0
    JSValue rv;
49867
0
    int i, n;
49868
0
    double a, val;
49869
49870
0
    if (JS_IsUndefined(new_target)) {
49871
        /* invoked as function */
49872
0
        argc = 0;
49873
0
    }
49874
0
    n = argc;
49875
0
    if (n == 0) {
49876
0
        val = date_now();
49877
0
    } else if (n == 1) {
49878
0
        JSValue v, dv;
49879
0
        if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
49880
0
            JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
49881
0
            if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data)) {
49882
0
                if (JS_ToFloat64(ctx, &val, p->u.object_data))
49883
0
                    return JS_EXCEPTION;
49884
0
                val = time_clip(val);
49885
0
                goto has_val;
49886
0
            }
49887
0
        }
49888
0
        v = JS_ToPrimitive(ctx, argv[0], HINT_NONE);
49889
0
        if (JS_IsString(v)) {
49890
0
            dv = js_Date_parse(ctx, JS_UNDEFINED, 1, (JSValueConst *)&v);
49891
0
            JS_FreeValue(ctx, v);
49892
0
            if (JS_IsException(dv))
49893
0
                return JS_EXCEPTION;
49894
0
            if (JS_ToFloat64Free(ctx, &val, dv))
49895
0
                return JS_EXCEPTION;
49896
0
        } else {
49897
0
            if (JS_ToFloat64Free(ctx, &val, v))
49898
0
                return JS_EXCEPTION;
49899
0
        }
49900
0
        val = time_clip(val);
49901
0
    } else {
49902
0
        double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
49903
0
        if (n > 7)
49904
0
            n = 7;
49905
0
        for(i = 0; i < n; i++) {
49906
0
            if (JS_ToFloat64(ctx, &a, argv[i]))
49907
0
                return JS_EXCEPTION;
49908
0
            if (!isfinite(a))
49909
0
                break;
49910
0
            fields[i] = trunc(a);
49911
0
            if (i == 0 && fields[0] >= 0 && fields[0] < 100)
49912
0
                fields[0] += 1900;
49913
0
        }
49914
0
        val = (i == n) ? set_date_fields(fields, 1) : NAN;
49915
0
    }
49916
0
has_val:
49917
#if 0
49918
    JSValueConst args[3];
49919
    args[0] = new_target;
49920
    args[1] = ctx->class_proto[JS_CLASS_DATE];
49921
    args[2] = JS_NewFloat64(ctx, val);
49922
    rv = js___date_create(ctx, JS_UNDEFINED, 3, args);
49923
#else
49924
0
    rv = js_create_from_ctor(ctx, new_target, JS_CLASS_DATE);
49925
0
    if (!JS_IsException(rv))
49926
0
        JS_SetObjectData(ctx, rv, JS_NewFloat64(ctx, val));
49927
0
#endif
49928
0
    if (!JS_IsException(rv) && JS_IsUndefined(new_target)) {
49929
        /* invoked as a function, return (new Date()).toString(); */
49930
0
        JSValue s;
49931
0
        s = get_date_string(ctx, rv, 0, NULL, 0x13);
49932
0
        JS_FreeValue(ctx, rv);
49933
0
        rv = s;
49934
0
    }
49935
0
    return rv;
49936
0
}
49937
49938
static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,
49939
                           int argc, JSValueConst *argv)
49940
0
{
49941
    // UTC(y, mon, d, h, m, s, ms)
49942
0
    double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
49943
0
    int i, n;
49944
0
    double a;
49945
49946
0
    n = argc;
49947
0
    if (n == 0)
49948
0
        return JS_NAN;
49949
0
    if (n > 7)
49950
0
        n = 7;
49951
0
    for(i = 0; i < n; i++) {
49952
0
        if (JS_ToFloat64(ctx, &a, argv[i]))
49953
0
            return JS_EXCEPTION;
49954
0
        if (!isfinite(a))
49955
0
            return JS_NAN;
49956
0
        fields[i] = trunc(a);
49957
0
        if (i == 0 && fields[0] >= 0 && fields[0] < 100)
49958
0
            fields[0] += 1900;
49959
0
    }
49960
0
    return JS_NewFloat64(ctx, set_date_fields(fields, 0));
49961
0
}
49962
49963
/* Date string parsing */
49964
49965
0
static BOOL string_skip_char(const uint8_t *sp, int *pp, int c) {
49966
0
    if (sp[*pp] == c) {
49967
0
        *pp += 1;
49968
0
        return TRUE;
49969
0
    } else {
49970
0
        return FALSE;
49971
0
    }
49972
0
}
49973
49974
/* skip spaces, update offset, return next char */
49975
0
static int string_skip_spaces(const uint8_t *sp, int *pp) {
49976
0
    int c;
49977
0
    while ((c = sp[*pp]) == ' ')
49978
0
        *pp += 1;
49979
0
    return c;
49980
0
}
49981
49982
/* skip dashes dots and commas */
49983
0
static int string_skip_separators(const uint8_t *sp, int *pp) {
49984
0
    int c;
49985
0
    while ((c = sp[*pp]) == '-' || c == '/' || c == '.' || c == ',')
49986
0
        *pp += 1;
49987
0
    return c;
49988
0
}
49989
49990
/* skip a word, stop on spaces, digits and separators, update offset */
49991
0
static int string_skip_until(const uint8_t *sp, int *pp, const char *stoplist) {
49992
0
    int c;
49993
0
    while (!strchr(stoplist, c = sp[*pp]))
49994
0
        *pp += 1;
49995
0
    return c;
49996
0
}
49997
49998
/* parse a numeric field (max_digits = 0 -> no maximum) */
49999
static BOOL string_get_digits(const uint8_t *sp, int *pp, int *pval,
50000
                              int min_digits, int max_digits)
50001
0
{
50002
0
    int v = 0;
50003
0
    int c, p = *pp, p_start;
50004
50005
0
    p_start = p;
50006
0
    while ((c = sp[p]) >= '0' && c <= '9') {
50007
0
        v = v * 10 + c - '0';
50008
0
        p++;
50009
0
        if (p - p_start == max_digits)
50010
0
            break;
50011
0
    }
50012
0
    if (p - p_start < min_digits)
50013
0
        return FALSE;
50014
0
    *pval = v;
50015
0
    *pp = p;
50016
0
    return TRUE;
50017
0
}
50018
50019
0
static BOOL string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) {
50020
    /* parse optional fractional part as milliseconds and truncate. */
50021
    /* spec does not indicate which rounding should be used */
50022
0
    int mul = 100, ms = 0, c, p_start, p = *pp;
50023
50024
0
    c = sp[p];
50025
0
    if (c == '.' || c == ',') {
50026
0
        p++;
50027
0
        p_start = p;
50028
0
        while ((c = sp[p]) >= '0' && c <= '9') {
50029
0
            ms += (c - '0') * mul;
50030
0
            mul /= 10;
50031
0
            p++;
50032
0
            if (p - p_start == 9)
50033
0
                break;
50034
0
        }
50035
0
        if (p > p_start) {
50036
            /* only consume the separator if digits are present */
50037
0
            *pval = ms;
50038
0
            *pp = p;
50039
0
        }
50040
0
    }
50041
0
    return TRUE;
50042
0
}
50043
50044
0
static uint8_t upper_ascii(uint8_t c) {
50045
0
    return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c;
50046
0
}
50047
50048
0
static BOOL string_get_tzoffset(const uint8_t *sp, int *pp, int *tzp, BOOL strict) {
50049
0
    int tz = 0, sgn, hh, mm, p = *pp;
50050
50051
0
    sgn = sp[p++];
50052
0
    if (sgn == '+' || sgn == '-') {
50053
0
        int n = p;
50054
0
        if (!string_get_digits(sp, &p, &hh, 1, 9))
50055
0
            return FALSE;
50056
0
        n = p - n;
50057
0
        if (strict && n != 2 && n != 4)
50058
0
            return FALSE;
50059
0
        while (n > 4) {
50060
0
            n -= 2;
50061
0
            hh /= 100;
50062
0
        }
50063
0
        if (n > 2) {
50064
0
            mm = hh % 100;
50065
0
            hh = hh / 100;
50066
0
        } else {
50067
0
            mm = 0;
50068
0
            if (string_skip_char(sp, &p, ':')  /* optional separator */
50069
0
            &&  !string_get_digits(sp, &p, &mm, 2, 2))
50070
0
                return FALSE;
50071
0
        }
50072
0
        if (hh > 23 || mm > 59)
50073
0
            return FALSE;
50074
0
        tz = hh * 60 + mm;
50075
0
        if (sgn != '+')
50076
0
            tz = -tz;
50077
0
    } else
50078
0
    if (sgn != 'Z') {
50079
0
        return FALSE;
50080
0
    }
50081
0
    *pp = p;
50082
0
    *tzp = tz;
50083
0
    return TRUE;
50084
0
}
50085
50086
0
static BOOL string_match(const uint8_t *sp, int *pp, const char *s) {
50087
0
    int p = *pp;
50088
0
    while (*s != '\0') {
50089
0
        if (upper_ascii(sp[p]) != upper_ascii(*s++))
50090
0
            return FALSE;
50091
0
        p++;
50092
0
    }
50093
0
    *pp = p;
50094
0
    return TRUE;
50095
0
}
50096
50097
0
static int find_abbrev(const uint8_t *sp, int p, const char *list, int count) {
50098
0
    int n, i;
50099
50100
0
    for (n = 0; n < count; n++) {
50101
0
        for (i = 0;; i++) {
50102
0
            if (upper_ascii(sp[p + i]) != upper_ascii(list[n * 3 + i]))
50103
0
                break;
50104
0
            if (i == 2)
50105
0
                return n;
50106
0
        }
50107
0
    }
50108
0
    return -1;
50109
0
}
50110
50111
0
static BOOL string_get_month(const uint8_t *sp, int *pp, int *pval) {
50112
0
    int n;
50113
50114
0
    n = find_abbrev(sp, *pp, month_names, 12);
50115
0
    if (n < 0)
50116
0
        return FALSE;
50117
50118
0
    *pval = n + 1;
50119
0
    *pp += 3;
50120
0
    return TRUE;
50121
0
}
50122
50123
/* parse toISOString format */
50124
0
static BOOL js_date_parse_isostring(const uint8_t *sp, int fields[9], BOOL *is_local) {
50125
0
    int sgn, i, p = 0;
50126
50127
    /* initialize fields to the beginning of the Epoch */
50128
0
    for (i = 0; i < 9; i++) {
50129
0
        fields[i] = (i == 2);
50130
0
    }
50131
0
    *is_local = FALSE;
50132
50133
    /* year is either yyyy digits or [+-]yyyyyy */
50134
0
    sgn = sp[p];
50135
0
    if (sgn == '-' || sgn == '+') {
50136
0
        p++;
50137
0
        if (!string_get_digits(sp, &p, &fields[0], 6, 6))
50138
0
            return FALSE;
50139
0
        if (sgn == '-') {
50140
0
            if (fields[0] == 0)
50141
0
                return FALSE; // reject -000000
50142
0
            fields[0] = -fields[0];
50143
0
        }
50144
0
    } else {
50145
0
        if (!string_get_digits(sp, &p, &fields[0], 4, 4))
50146
0
            return FALSE;
50147
0
    }
50148
0
    if (string_skip_char(sp, &p, '-')) {
50149
0
        if (!string_get_digits(sp, &p, &fields[1], 2, 2))  /* month */
50150
0
            return FALSE;
50151
0
        if (fields[1] < 1)
50152
0
            return FALSE;
50153
0
        fields[1] -= 1;
50154
0
        if (string_skip_char(sp, &p, '-')) {
50155
0
            if (!string_get_digits(sp, &p, &fields[2], 2, 2))  /* day */
50156
0
                return FALSE;
50157
0
            if (fields[2] < 1)
50158
0
                return FALSE;
50159
0
        }
50160
0
    }
50161
0
    if (string_skip_char(sp, &p, 'T')) {
50162
0
        *is_local = TRUE;
50163
0
        if (!string_get_digits(sp, &p, &fields[3], 2, 2)  /* hour */
50164
0
        ||  !string_skip_char(sp, &p, ':')
50165
0
        ||  !string_get_digits(sp, &p, &fields[4], 2, 2)) {  /* minute */
50166
0
            fields[3] = 100;  // reject unconditionally
50167
0
            return TRUE;
50168
0
        }
50169
0
        if (string_skip_char(sp, &p, ':')) {
50170
0
            if (!string_get_digits(sp, &p, &fields[5], 2, 2))  /* second */
50171
0
                return FALSE;
50172
0
            string_get_milliseconds(sp, &p, &fields[6]);
50173
0
        }
50174
0
    }
50175
    /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
50176
0
    if (sp[p]) {
50177
0
        *is_local = FALSE;
50178
0
        if (!string_get_tzoffset(sp, &p, &fields[8], TRUE))
50179
0
            return FALSE;
50180
0
    }
50181
    /* error if extraneous characters */
50182
0
    return sp[p] == '\0';
50183
0
}
50184
50185
static struct {
50186
    char name[6];
50187
    int16_t offset;
50188
} const js_tzabbr[] = {
50189
    { "GMT",   0 },         // Greenwich Mean Time
50190
    { "UTC",   0 },         // Coordinated Universal Time
50191
    { "UT",    0 },         // Universal Time
50192
    { "Z",     0 },         // Zulu Time
50193
    { "EDT",  -4 * 60 },    // Eastern Daylight Time
50194
    { "EST",  -5 * 60 },    // Eastern Standard Time
50195
    { "CDT",  -5 * 60 },    // Central Daylight Time
50196
    { "CST",  -6 * 60 },    // Central Standard Time
50197
    { "MDT",  -6 * 60 },    // Mountain Daylight Time
50198
    { "MST",  -7 * 60 },    // Mountain Standard Time
50199
    { "PDT",  -7 * 60 },    // Pacific Daylight Time
50200
    { "PST",  -8 * 60 },    // Pacific Standard Time
50201
    { "WET",  +0 * 60 },    // Western European Time
50202
    { "WEST", +1 * 60 },    // Western European Summer Time
50203
    { "CET",  +1 * 60 },    // Central European Time
50204
    { "CEST", +2 * 60 },    // Central European Summer Time
50205
    { "EET",  +2 * 60 },    // Eastern European Time
50206
    { "EEST", +3 * 60 },    // Eastern European Summer Time
50207
};
50208
50209
0
static BOOL string_get_tzabbr(const uint8_t *sp, int *pp, int *offset) {
50210
0
    for (size_t i = 0; i < countof(js_tzabbr); i++) {
50211
0
        if (string_match(sp, pp, js_tzabbr[i].name)) {
50212
0
            *offset = js_tzabbr[i].offset;
50213
0
            return TRUE;
50214
0
        }
50215
0
    }
50216
0
    return FALSE;
50217
0
}
50218
50219
/* parse toString, toUTCString and other formats */
50220
static BOOL js_date_parse_otherstring(const uint8_t *sp,
50221
                                      int fields[minimum_length(9)],
50222
0
                                      BOOL *is_local) {
50223
0
    int c, i, val, p = 0, p_start;
50224
0
    int num[3];
50225
0
    BOOL has_year = FALSE;
50226
0
    BOOL has_mon = FALSE;
50227
0
    BOOL has_time = FALSE;
50228
0
    int num_index = 0;
50229
50230
    /* initialize fields to the beginning of 2001-01-01 */
50231
0
    fields[0] = 2001;
50232
0
    fields[1] = 1;
50233
0
    fields[2] = 1;
50234
0
    for (i = 3; i < 9; i++) {
50235
0
        fields[i] = 0;
50236
0
    }
50237
0
    *is_local = TRUE;
50238
50239
0
    while (string_skip_spaces(sp, &p)) {
50240
0
        p_start = p;
50241
0
        if ((c = sp[p]) == '+' || c == '-') {
50242
0
            if (has_time && string_get_tzoffset(sp, &p, &fields[8], FALSE)) {
50243
0
                *is_local = FALSE;
50244
0
            } else {
50245
0
                p++;
50246
0
                if (string_get_digits(sp, &p, &val, 1, 9)) {
50247
0
                    if (c == '-') {
50248
0
                        if (val == 0)
50249
0
                            return FALSE;
50250
0
                        val = -val;
50251
0
                    }
50252
0
                    fields[0] = val;
50253
0
                    has_year = TRUE;
50254
0
                }
50255
0
            }
50256
0
        } else
50257
0
        if (string_get_digits(sp, &p, &val, 1, 9)) {
50258
0
            if (string_skip_char(sp, &p, ':')) {
50259
                /* time part */
50260
0
                fields[3] = val;
50261
0
                if (!string_get_digits(sp, &p, &fields[4], 1, 2))
50262
0
                    return FALSE;
50263
0
                if (string_skip_char(sp, &p, ':')) {
50264
0
                    if (!string_get_digits(sp, &p, &fields[5], 1, 2))
50265
0
                        return FALSE;
50266
0
                    string_get_milliseconds(sp, &p, &fields[6]);
50267
0
                }
50268
0
                has_time = TRUE;
50269
0
            } else {
50270
0
                if (p - p_start > 2) {
50271
0
                    fields[0] = val;
50272
0
                    has_year = TRUE;
50273
0
                } else
50274
0
                if (val < 1 || val > 31) {
50275
0
                    fields[0] = val + (val < 100) * 1900 + (val < 50) * 100;
50276
0
                    has_year = TRUE;
50277
0
                } else {
50278
0
                    if (num_index == 3)
50279
0
                        return FALSE;
50280
0
                    num[num_index++] = val;
50281
0
                }
50282
0
            }
50283
0
        } else
50284
0
        if (string_get_month(sp, &p, &fields[1])) {
50285
0
            has_mon = TRUE;
50286
0
            string_skip_until(sp, &p, "0123456789 -/(");
50287
0
        } else
50288
0
        if (has_time && string_match(sp, &p, "PM")) {
50289
0
            if (fields[3] < 12)
50290
0
                fields[3] += 12;
50291
0
            continue;
50292
0
        } else
50293
0
        if (has_time && string_match(sp, &p, "AM")) {
50294
0
            if (fields[3] == 12)
50295
0
                fields[3] -= 12;
50296
0
            continue;
50297
0
        } else
50298
0
        if (string_get_tzabbr(sp, &p, &fields[8])) {
50299
0
            *is_local = FALSE;
50300
0
            continue;
50301
0
        } else
50302
0
        if (c == '(') {  /* skip parenthesized phrase */
50303
0
            int level = 0;
50304
0
            while ((c = sp[p]) != '\0') {
50305
0
                p++;
50306
0
                level += (c == '(');
50307
0
                level -= (c == ')');
50308
0
                if (!level)
50309
0
                    break;
50310
0
            }
50311
0
            if (level > 0)
50312
0
                return FALSE;
50313
0
        } else
50314
0
        if (c == ')') {
50315
0
            return FALSE;
50316
0
        } else {
50317
0
            if (has_year + has_mon + has_time + num_index)
50318
0
                return FALSE;
50319
            /* skip a word */
50320
0
            string_skip_until(sp, &p, " -/(");
50321
0
        }
50322
0
        string_skip_separators(sp, &p);
50323
0
    }
50324
0
    if (num_index + has_year + has_mon > 3)
50325
0
        return FALSE;
50326
50327
0
    switch (num_index) {
50328
0
    case 0:
50329
0
        if (!has_year)
50330
0
            return FALSE;
50331
0
        break;
50332
0
    case 1:
50333
0
        if (has_mon)
50334
0
            fields[2] = num[0];
50335
0
        else
50336
0
            fields[1] = num[0];
50337
0
        break;
50338
0
    case 2:
50339
0
        if (has_year) {
50340
0
            fields[1] = num[0];
50341
0
            fields[2] = num[1];
50342
0
        } else
50343
0
        if (has_mon) {
50344
0
            fields[0] = num[1] + (num[1] < 100) * 1900 + (num[1] < 50) * 100;
50345
0
            fields[2] = num[0];
50346
0
        } else {
50347
0
            fields[1] = num[0];
50348
0
            fields[2] = num[1];
50349
0
        }
50350
0
        break;
50351
0
    case 3:
50352
0
        fields[0] = num[2] + (num[2] < 100) * 1900 + (num[2] < 50) * 100;
50353
0
        fields[1] = num[0];
50354
0
        fields[2] = num[1];
50355
0
        break;
50356
0
    default:
50357
0
        return FALSE;
50358
0
    }
50359
0
    if (fields[1] < 1 || fields[2] < 1)
50360
0
        return FALSE;
50361
0
    fields[1] -= 1;
50362
0
    return TRUE;
50363
0
}
50364
50365
static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
50366
                             int argc, JSValueConst *argv)
50367
0
{
50368
0
    JSValue s, rv;
50369
0
    int fields[9];
50370
0
    double fields1[9];
50371
0
    double d;
50372
0
    int i, c;
50373
0
    JSString *sp;
50374
0
    uint8_t buf[128];
50375
0
    BOOL is_local;
50376
50377
0
    rv = JS_NAN;
50378
50379
0
    s = JS_ToString(ctx, argv[0]);
50380
0
    if (JS_IsException(s))
50381
0
        return JS_EXCEPTION;
50382
50383
0
    sp = JS_VALUE_GET_STRING(s);
50384
    /* convert the string as a byte array */
50385
0
    for (i = 0; i < sp->len && i < (int)countof(buf) - 1; i++) {
50386
0
        c = string_get(sp, i);
50387
0
        if (c > 255)
50388
0
            c = (c == 0x2212) ? '-' : 'x';
50389
0
        buf[i] = c;
50390
0
    }
50391
0
    buf[i] = '\0';
50392
0
    if (js_date_parse_isostring(buf, fields, &is_local)
50393
0
    ||  js_date_parse_otherstring(buf, fields, &is_local)) {
50394
0
        static int const field_max[6] = { 0, 11, 31, 24, 59, 59 };
50395
0
        BOOL valid = TRUE;
50396
        /* check field maximum values */
50397
0
        for (i = 1; i < 6; i++) {
50398
0
            if (fields[i] > field_max[i])
50399
0
                valid = FALSE;
50400
0
        }
50401
        /* special case 24:00:00.000 */
50402
0
        if (fields[3] == 24 && (fields[4] | fields[5] | fields[6]))
50403
0
            valid = FALSE;
50404
0
        if (valid) {
50405
0
            for(i = 0; i < 7; i++)
50406
0
                fields1[i] = fields[i];
50407
0
            d = set_date_fields(fields1, is_local) - fields[8] * 60000;
50408
0
            rv = JS_NewFloat64(ctx, d);
50409
0
        }
50410
0
    }
50411
0
    JS_FreeValue(ctx, s);
50412
0
    return rv;
50413
0
}
50414
50415
static JSValue js_Date_now(JSContext *ctx, JSValueConst this_val,
50416
                           int argc, JSValueConst *argv)
50417
0
{
50418
    // now()
50419
0
    return JS_NewInt64(ctx, date_now());
50420
0
}
50421
50422
static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val,
50423
                                          int argc, JSValueConst *argv)
50424
0
{
50425
    // Symbol_toPrimitive(hint)
50426
0
    JSValueConst obj = this_val;
50427
0
    JSAtom hint = JS_ATOM_NULL;
50428
0
    int hint_num;
50429
50430
0
    if (!JS_IsObject(obj))
50431
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
50432
50433
0
    if (JS_IsString(argv[0])) {
50434
0
        hint = JS_ValueToAtom(ctx, argv[0]);
50435
0
        if (hint == JS_ATOM_NULL)
50436
0
            return JS_EXCEPTION;
50437
0
        JS_FreeAtom(ctx, hint);
50438
0
    }
50439
0
    switch (hint) {
50440
0
    case JS_ATOM_number:
50441
0
    case JS_ATOM_integer:
50442
0
        hint_num = HINT_NUMBER;
50443
0
        break;
50444
0
    case JS_ATOM_string:
50445
0
    case JS_ATOM_default:
50446
0
        hint_num = HINT_STRING;
50447
0
        break;
50448
0
    default:
50449
0
        return JS_ThrowTypeError(ctx, "invalid hint");
50450
0
    }
50451
0
    return JS_ToPrimitive(ctx, obj, hint_num | HINT_FORCE_ORDINARY);
50452
0
}
50453
50454
static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
50455
                                         int argc, JSValueConst *argv)
50456
0
{
50457
    // getTimezoneOffset()
50458
0
    double v;
50459
50460
0
    if (JS_ThisTimeValue(ctx, &v, this_val))
50461
0
        return JS_EXCEPTION;
50462
0
    if (isnan(v))
50463
0
        return JS_NAN;
50464
0
    else
50465
        /* assuming -8.64e15 <= v <= -8.64e15 */
50466
0
        return JS_NewInt64(ctx, getTimezoneOffset((int64_t)trunc(v)));
50467
0
}
50468
50469
static JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val,
50470
                               int argc, JSValueConst *argv)
50471
0
{
50472
    // getTime()
50473
0
    double v;
50474
50475
0
    if (JS_ThisTimeValue(ctx, &v, this_val))
50476
0
        return JS_EXCEPTION;
50477
0
    return JS_NewFloat64(ctx, v);
50478
0
}
50479
50480
static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val,
50481
                               int argc, JSValueConst *argv)
50482
0
{
50483
    // setTime(v)
50484
0
    double v;
50485
50486
0
    if (JS_ThisTimeValue(ctx, &v, this_val) || JS_ToFloat64(ctx, &v, argv[0]))
50487
0
        return JS_EXCEPTION;
50488
0
    return JS_SetThisTimeValue(ctx, this_val, time_clip(v));
50489
0
}
50490
50491
static JSValue js_date_setYear(JSContext *ctx, JSValueConst this_val,
50492
                               int argc, JSValueConst *argv)
50493
0
{
50494
    // setYear(y)
50495
0
    double y;
50496
0
    JSValueConst args[1];
50497
50498
0
    if (JS_ThisTimeValue(ctx, &y, this_val) || JS_ToFloat64(ctx, &y, argv[0]))
50499
0
        return JS_EXCEPTION;
50500
0
    y = +y;
50501
0
    if (isfinite(y)) {
50502
0
        y = trunc(y);
50503
0
        if (y >= 0 && y < 100)
50504
0
            y += 1900;
50505
0
    }
50506
0
    args[0] = JS_NewFloat64(ctx, y);
50507
0
    return set_date_field(ctx, this_val, 1, args, 0x011);
50508
0
}
50509
50510
static JSValue js_date_toJSON(JSContext *ctx, JSValueConst this_val,
50511
                              int argc, JSValueConst *argv)
50512
0
{
50513
    // toJSON(key)
50514
0
    JSValue obj, tv, method, rv;
50515
0
    double d;
50516
50517
0
    rv = JS_EXCEPTION;
50518
0
    tv = JS_UNDEFINED;
50519
50520
0
    obj = JS_ToObject(ctx, this_val);
50521
0
    tv = JS_ToPrimitive(ctx, obj, HINT_NUMBER);
50522
0
    if (JS_IsException(tv))
50523
0
        goto exception;
50524
0
    if (JS_IsNumber(tv)) {
50525
0
        if (JS_ToFloat64(ctx, &d, tv) < 0)
50526
0
            goto exception;
50527
0
        if (!isfinite(d)) {
50528
0
            rv = JS_NULL;
50529
0
            goto done;
50530
0
        }
50531
0
    }
50532
0
    method = JS_GetPropertyStr(ctx, obj, "toISOString");
50533
0
    if (JS_IsException(method))
50534
0
        goto exception;
50535
0
    if (!JS_IsFunction(ctx, method)) {
50536
0
        JS_ThrowTypeError(ctx, "object needs toISOString method");
50537
0
        JS_FreeValue(ctx, method);
50538
0
        goto exception;
50539
0
    }
50540
0
    rv = JS_CallFree(ctx, method, obj, 0, NULL);
50541
0
exception:
50542
0
done:
50543
0
    JS_FreeValue(ctx, obj);
50544
0
    JS_FreeValue(ctx, tv);
50545
0
    return rv;
50546
0
}
50547
50548
static const JSCFunctionListEntry js_date_funcs[] = {
50549
    JS_CFUNC_DEF("now", 0, js_Date_now ),
50550
    JS_CFUNC_DEF("parse", 1, js_Date_parse ),
50551
    JS_CFUNC_DEF("UTC", 7, js_Date_UTC ),
50552
};
50553
50554
static const JSCFunctionListEntry js_date_proto_funcs[] = {
50555
    JS_CFUNC_DEF("valueOf", 0, js_date_getTime ),
50556
    JS_CFUNC_MAGIC_DEF("toString", 0, get_date_string, 0x13 ),
50557
    JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_date_Symbol_toPrimitive ),
50558
    JS_CFUNC_MAGIC_DEF("toUTCString", 0, get_date_string, 0x03 ),
50559
    JS_ALIAS_DEF("toGMTString", "toUTCString" ),
50560
    JS_CFUNC_MAGIC_DEF("toISOString", 0, get_date_string, 0x23 ),
50561
    JS_CFUNC_MAGIC_DEF("toDateString", 0, get_date_string, 0x11 ),
50562
    JS_CFUNC_MAGIC_DEF("toTimeString", 0, get_date_string, 0x12 ),
50563
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, get_date_string, 0x33 ),
50564
    JS_CFUNC_MAGIC_DEF("toLocaleDateString", 0, get_date_string, 0x31 ),
50565
    JS_CFUNC_MAGIC_DEF("toLocaleTimeString", 0, get_date_string, 0x32 ),
50566
    JS_CFUNC_DEF("getTimezoneOffset", 0, js_date_getTimezoneOffset ),
50567
    JS_CFUNC_DEF("getTime", 0, js_date_getTime ),
50568
    JS_CFUNC_MAGIC_DEF("getYear", 0, get_date_field, 0x101 ),
50569
    JS_CFUNC_MAGIC_DEF("getFullYear", 0, get_date_field, 0x01 ),
50570
    JS_CFUNC_MAGIC_DEF("getUTCFullYear", 0, get_date_field, 0x00 ),
50571
    JS_CFUNC_MAGIC_DEF("getMonth", 0, get_date_field, 0x11 ),
50572
    JS_CFUNC_MAGIC_DEF("getUTCMonth", 0, get_date_field, 0x10 ),
50573
    JS_CFUNC_MAGIC_DEF("getDate", 0, get_date_field, 0x21 ),
50574
    JS_CFUNC_MAGIC_DEF("getUTCDate", 0, get_date_field, 0x20 ),
50575
    JS_CFUNC_MAGIC_DEF("getHours", 0, get_date_field, 0x31 ),
50576
    JS_CFUNC_MAGIC_DEF("getUTCHours", 0, get_date_field, 0x30 ),
50577
    JS_CFUNC_MAGIC_DEF("getMinutes", 0, get_date_field, 0x41 ),
50578
    JS_CFUNC_MAGIC_DEF("getUTCMinutes", 0, get_date_field, 0x40 ),
50579
    JS_CFUNC_MAGIC_DEF("getSeconds", 0, get_date_field, 0x51 ),
50580
    JS_CFUNC_MAGIC_DEF("getUTCSeconds", 0, get_date_field, 0x50 ),
50581
    JS_CFUNC_MAGIC_DEF("getMilliseconds", 0, get_date_field, 0x61 ),
50582
    JS_CFUNC_MAGIC_DEF("getUTCMilliseconds", 0, get_date_field, 0x60 ),
50583
    JS_CFUNC_MAGIC_DEF("getDay", 0, get_date_field, 0x71 ),
50584
    JS_CFUNC_MAGIC_DEF("getUTCDay", 0, get_date_field, 0x70 ),
50585
    JS_CFUNC_DEF("setTime", 1, js_date_setTime ),
50586
    JS_CFUNC_MAGIC_DEF("setMilliseconds", 1, set_date_field, 0x671 ),
50587
    JS_CFUNC_MAGIC_DEF("setUTCMilliseconds", 1, set_date_field, 0x670 ),
50588
    JS_CFUNC_MAGIC_DEF("setSeconds", 2, set_date_field, 0x571 ),
50589
    JS_CFUNC_MAGIC_DEF("setUTCSeconds", 2, set_date_field, 0x570 ),
50590
    JS_CFUNC_MAGIC_DEF("setMinutes", 3, set_date_field, 0x471 ),
50591
    JS_CFUNC_MAGIC_DEF("setUTCMinutes", 3, set_date_field, 0x470 ),
50592
    JS_CFUNC_MAGIC_DEF("setHours", 4, set_date_field, 0x371 ),
50593
    JS_CFUNC_MAGIC_DEF("setUTCHours", 4, set_date_field, 0x370 ),
50594
    JS_CFUNC_MAGIC_DEF("setDate", 1, set_date_field, 0x231 ),
50595
    JS_CFUNC_MAGIC_DEF("setUTCDate", 1, set_date_field, 0x230 ),
50596
    JS_CFUNC_MAGIC_DEF("setMonth", 2, set_date_field, 0x131 ),
50597
    JS_CFUNC_MAGIC_DEF("setUTCMonth", 2, set_date_field, 0x130 ),
50598
    JS_CFUNC_DEF("setYear", 1, js_date_setYear ),
50599
    JS_CFUNC_MAGIC_DEF("setFullYear", 3, set_date_field, 0x031 ),
50600
    JS_CFUNC_MAGIC_DEF("setUTCFullYear", 3, set_date_field, 0x030 ),
50601
    JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ),
50602
};
50603
50604
JSValue JS_NewDate(JSContext *ctx, double epoch_ms)
50605
0
{
50606
0
    JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_DATE);
50607
0
    if (JS_IsException(obj))
50608
0
        return JS_EXCEPTION;
50609
0
    JS_SetObjectData(ctx, obj, __JS_NewFloat64(ctx, time_clip(epoch_ms)));
50610
0
    return obj;
50611
0
}
50612
50613
void JS_AddIntrinsicDate(JSContext *ctx)
50614
39
{
50615
39
    JSValueConst obj;
50616
50617
    /* Date */
50618
39
    ctx->class_proto[JS_CLASS_DATE] = JS_NewObject(ctx);
50619
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATE], js_date_proto_funcs,
50620
39
                               countof(js_date_proto_funcs));
50621
39
    obj = JS_NewGlobalCConstructor(ctx, "Date", js_date_constructor, 7,
50622
39
                                   ctx->class_proto[JS_CLASS_DATE]);
50623
39
    JS_SetPropertyFunctionList(ctx, obj, js_date_funcs, countof(js_date_funcs));
50624
39
}
50625
50626
/* eval */
50627
50628
void JS_AddIntrinsicEval(JSContext *ctx)
50629
39
{
50630
39
    ctx->eval_internal = __JS_EvalInternal;
50631
39
}
50632
50633
#ifdef CONFIG_BIGNUM
50634
50635
/* Operators */
50636
50637
static void js_operator_set_finalizer(JSRuntime *rt, JSValue val)
50638
234
{
50639
234
    JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
50640
234
    int i, j;
50641
234
    JSBinaryOperatorDefEntry *ent;
50642
50643
234
    if (opset) {
50644
4.68k
        for(i = 0; i < JS_OVOP_COUNT; i++) {
50645
4.44k
            if (opset->self_ops[i])
50646
0
                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]));
50647
4.44k
        }
50648
234
        for(j = 0; j < opset->left.count; j++) {
50649
0
            ent = &opset->left.tab[j];
50650
0
            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
50651
0
                if (ent->ops[i])
50652
0
                    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
50653
0
            }
50654
0
        }
50655
234
        js_free_rt(rt, opset->left.tab);
50656
234
        for(j = 0; j < opset->right.count; j++) {
50657
0
            ent = &opset->right.tab[j];
50658
0
            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
50659
0
                if (ent->ops[i])
50660
0
                    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
50661
0
            }
50662
0
        }
50663
234
        js_free_rt(rt, opset->right.tab);
50664
234
        js_free_rt(rt, opset);
50665
234
    }
50666
234
}
50667
50668
static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
50669
                                 JS_MarkFunc *mark_func)
50670
876
{
50671
876
    JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
50672
876
    int i, j;
50673
876
    JSBinaryOperatorDefEntry *ent;
50674
50675
876
    if (opset) {
50676
17.5k
        for(i = 0; i < JS_OVOP_COUNT; i++) {
50677
16.6k
            if (opset->self_ops[i])
50678
0
                JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]),
50679
0
                             mark_func);
50680
16.6k
        }
50681
876
        for(j = 0; j < opset->left.count; j++) {
50682
0
            ent = &opset->left.tab[j];
50683
0
            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
50684
0
                if (ent->ops[i])
50685
0
                    JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
50686
0
                                 mark_func);
50687
0
            }
50688
0
        }
50689
876
        for(j = 0; j < opset->right.count; j++) {
50690
0
            ent = &opset->right.tab[j];
50691
0
            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
50692
0
                if (ent->ops[i])
50693
0
                    JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
50694
0
                                 mark_func);
50695
0
            }
50696
0
        }
50697
876
    }
50698
876
}
50699
50700
50701
/* create an OperatorSet object */
50702
static JSValue js_operators_create_internal(JSContext *ctx,
50703
                                            int argc, JSValueConst *argv,
50704
                                            BOOL is_primitive)
50705
234
{
50706
234
    JSValue opset_obj, prop, obj;
50707
234
    JSOperatorSetData *opset, *opset1;
50708
234
    JSBinaryOperatorDef *def;
50709
234
    JSValueConst arg;
50710
234
    int i, j;
50711
234
    JSBinaryOperatorDefEntry *new_tab;
50712
234
    JSBinaryOperatorDefEntry *ent;
50713
234
    uint32_t op_count;
50714
50715
234
    if (ctx->rt->operator_count == UINT32_MAX) {
50716
0
        return JS_ThrowTypeError(ctx, "too many operators");
50717
0
    }
50718
234
    opset_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_OPERATOR_SET);
50719
234
    if (JS_IsException(opset_obj))
50720
0
        goto fail;
50721
234
    opset = js_mallocz(ctx, sizeof(*opset));
50722
234
    if (!opset)
50723
0
        goto fail;
50724
234
    JS_SetOpaque(opset_obj, opset);
50725
234
    if (argc >= 1) {
50726
0
        arg = argv[0];
50727
        /* self operators */
50728
0
        for(i = 0; i < JS_OVOP_COUNT; i++) {
50729
0
            prop = JS_GetPropertyStr(ctx, arg, js_overloadable_operator_names[i]);
50730
0
            if (JS_IsException(prop))
50731
0
                goto fail;
50732
0
            if (!JS_IsUndefined(prop)) {
50733
0
                if (check_function(ctx, prop)) {
50734
0
                    JS_FreeValue(ctx, prop);
50735
0
                    goto fail;
50736
0
                }
50737
0
                opset->self_ops[i] = JS_VALUE_GET_OBJ(prop);
50738
0
            }
50739
0
        }
50740
0
    }
50741
    /* left & right operators */
50742
234
    for(j = 1; j < argc; j++) {
50743
0
        arg = argv[j];
50744
0
        prop = JS_GetPropertyStr(ctx, arg, "left");
50745
0
        if (JS_IsException(prop))
50746
0
            goto fail;
50747
0
        def = &opset->right;
50748
0
        if (JS_IsUndefined(prop)) {
50749
0
            prop = JS_GetPropertyStr(ctx, arg, "right");
50750
0
            if (JS_IsException(prop))
50751
0
                goto fail;
50752
0
            if (JS_IsUndefined(prop)) {
50753
0
                JS_ThrowTypeError(ctx, "left or right property must be present");
50754
0
                goto fail;
50755
0
            }
50756
0
            def = &opset->left;
50757
0
        }
50758
        /* get the operator set */
50759
0
        obj = JS_GetProperty(ctx, prop, JS_ATOM_prototype);
50760
0
        JS_FreeValue(ctx, prop);
50761
0
        if (JS_IsException(obj))
50762
0
            goto fail;
50763
0
        prop = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
50764
0
        JS_FreeValue(ctx, obj);
50765
0
        if (JS_IsException(prop))
50766
0
            goto fail;
50767
0
        opset1 = JS_GetOpaque2(ctx, prop, JS_CLASS_OPERATOR_SET);
50768
0
        if (!opset1) {
50769
0
            JS_FreeValue(ctx, prop);
50770
0
            goto fail;
50771
0
        }
50772
0
        op_count = opset1->operator_counter;
50773
0
        JS_FreeValue(ctx, prop);
50774
50775
        /* we assume there are few entries */
50776
0
        new_tab = js_realloc(ctx, def->tab,
50777
0
                             (def->count + 1) * sizeof(def->tab[0]));
50778
0
        if (!new_tab)
50779
0
            goto fail;
50780
0
        def->tab = new_tab;
50781
0
        def->count++;
50782
0
        ent = def->tab + def->count - 1;
50783
0
        memset(ent, 0, sizeof(def->tab[0]));
50784
0
        ent->operator_index = op_count;
50785
50786
0
        for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
50787
0
            prop = JS_GetPropertyStr(ctx, arg,
50788
0
                                     js_overloadable_operator_names[i]);
50789
0
            if (JS_IsException(prop))
50790
0
                goto fail;
50791
0
            if (!JS_IsUndefined(prop)) {
50792
0
                if (check_function(ctx, prop)) {
50793
0
                    JS_FreeValue(ctx, prop);
50794
0
                    goto fail;
50795
0
                }
50796
0
                ent->ops[i] = JS_VALUE_GET_OBJ(prop);
50797
0
            }
50798
0
        }
50799
0
    }
50800
234
    opset->is_primitive = is_primitive;
50801
234
    opset->operator_counter = ctx->rt->operator_count++;
50802
234
    return opset_obj;
50803
0
 fail:
50804
0
    JS_FreeValue(ctx, opset_obj);
50805
0
    return JS_EXCEPTION;
50806
234
}
50807
50808
static JSValue js_operators_create(JSContext *ctx, JSValueConst this_val,
50809
                                int argc, JSValueConst *argv)
50810
0
{
50811
0
    return js_operators_create_internal(ctx, argc, argv, FALSE);
50812
0
}
50813
50814
static JSValue js_operators_updateBigIntOperators(JSContext *ctx, JSValueConst this_val,
50815
                                                  int argc, JSValueConst *argv)
50816
0
{
50817
0
    JSValue opset_obj, prop;
50818
0
    JSOperatorSetData *opset;
50819
0
    const JSOverloadableOperatorEnum ops[2] = { JS_OVOP_DIV, JS_OVOP_POW };
50820
0
    JSOverloadableOperatorEnum op;
50821
0
    int i;
50822
50823
0
    opset_obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
50824
0
                               JS_ATOM_Symbol_operatorSet);
50825
0
    if (JS_IsException(opset_obj))
50826
0
        goto fail;
50827
0
    opset = JS_GetOpaque2(ctx, opset_obj, JS_CLASS_OPERATOR_SET);
50828
0
    if (!opset)
50829
0
        goto fail;
50830
0
    for(i = 0; i < countof(ops); i++) {
50831
0
        op = ops[i];
50832
0
        prop = JS_GetPropertyStr(ctx, argv[0],
50833
0
                                 js_overloadable_operator_names[op]);
50834
0
        if (JS_IsException(prop))
50835
0
            goto fail;
50836
0
        if (!JS_IsUndefined(prop)) {
50837
0
            if (!JS_IsNull(prop) && check_function(ctx, prop)) {
50838
0
                JS_FreeValue(ctx, prop);
50839
0
                goto fail;
50840
0
            }
50841
0
            if (opset->self_ops[op])
50842
0
                JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[op]));
50843
0
            if (JS_IsNull(prop)) {
50844
0
                opset->self_ops[op] = NULL;
50845
0
            } else {
50846
0
                opset->self_ops[op] = JS_VALUE_GET_PTR(prop);
50847
0
            }
50848
0
        }
50849
0
    }
50850
0
    JS_FreeValue(ctx, opset_obj);
50851
0
    return JS_UNDEFINED;
50852
0
 fail:
50853
0
    JS_FreeValue(ctx, opset_obj);
50854
0
    return JS_EXCEPTION;
50855
0
}
50856
50857
static int js_operators_set_default(JSContext *ctx, JSValueConst obj)
50858
234
{
50859
234
    JSValue opset_obj;
50860
50861
234
    if (!JS_IsObject(obj)) /* in case the prototype is not defined */
50862
0
        return 0;
50863
234
    opset_obj = js_operators_create_internal(ctx, 0, NULL, TRUE);
50864
234
    if (JS_IsException(opset_obj))
50865
0
        return -1;
50866
    /* cannot be modified by the user */
50867
234
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_operatorSet,
50868
234
                           opset_obj, 0);
50869
234
    return 0;
50870
234
}
50871
50872
static JSValue js_dummy_operators_ctor(JSContext *ctx, JSValueConst new_target,
50873
                                       int argc, JSValueConst *argv)
50874
0
{
50875
0
    return js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
50876
0
}
50877
50878
static JSValue js_global_operators(JSContext *ctx, JSValueConst this_val,
50879
                                   int argc, JSValueConst *argv)
50880
0
{
50881
0
    JSValue func_obj, proto, opset_obj;
50882
50883
0
    func_obj = JS_UNDEFINED;
50884
0
    proto = JS_NewObject(ctx);
50885
0
    if (JS_IsException(proto))
50886
0
        return JS_EXCEPTION;
50887
0
    opset_obj = js_operators_create_internal(ctx, argc, argv, FALSE);
50888
0
    if (JS_IsException(opset_obj))
50889
0
        goto fail;
50890
0
    JS_DefinePropertyValue(ctx, proto, JS_ATOM_Symbol_operatorSet,
50891
0
                           opset_obj, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
50892
0
    func_obj = JS_NewCFunction2(ctx, js_dummy_operators_ctor, "Operators",
50893
0
                                0, JS_CFUNC_constructor, 0);
50894
0
    if (JS_IsException(func_obj))
50895
0
        goto fail;
50896
0
    JS_SetConstructor2(ctx, func_obj, proto,
50897
0
                       0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
50898
0
    JS_FreeValue(ctx, proto);
50899
0
    return func_obj;
50900
0
 fail:
50901
0
    JS_FreeValue(ctx, proto);
50902
0
    JS_FreeValue(ctx, func_obj);
50903
0
    return JS_EXCEPTION;
50904
0
}
50905
50906
static const JSCFunctionListEntry js_operators_funcs[] = {
50907
    JS_CFUNC_DEF("create", 1, js_operators_create ),
50908
    JS_CFUNC_DEF("updateBigIntOperators", 2, js_operators_updateBigIntOperators ),
50909
};
50910
50911
/* must be called after all overloadable base types are initialized */
50912
void JS_AddIntrinsicOperators(JSContext *ctx)
50913
39
{
50914
39
    JSValue obj;
50915
50916
39
    ctx->allow_operator_overloading = TRUE;
50917
39
    obj = JS_NewCFunction(ctx, js_global_operators, "Operators", 1);
50918
39
    JS_SetPropertyFunctionList(ctx, obj,
50919
39
                               js_operators_funcs,
50920
39
                               countof(js_operators_funcs));
50921
39
    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Operators,
50922
39
                           obj,
50923
39
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
50924
    /* add default operatorSets */
50925
39
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BOOLEAN]);
50926
39
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_NUMBER]);
50927
39
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_STRING]);
50928
39
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_INT]);
50929
39
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT]);
50930
39
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
50931
39
}
50932
#endif /* CONFIG_BIGNUM */
50933
50934
/* BigInt */
50935
50936
static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
50937
0
{
50938
0
    uint32_t tag;
50939
50940
0
 redo:
50941
0
    tag = JS_VALUE_GET_NORM_TAG(val);
50942
0
    switch(tag) {
50943
0
    case JS_TAG_INT:
50944
0
    case JS_TAG_BOOL:
50945
0
        val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));
50946
0
        break;
50947
0
    case JS_TAG_BIG_INT:
50948
0
        break;
50949
0
    case JS_TAG_FLOAT64:
50950
0
#ifdef CONFIG_BIGNUM
50951
0
    case JS_TAG_BIG_FLOAT:
50952
0
#endif
50953
0
        {
50954
0
            bf_t *a, a_s;
50955
50956
0
            a = JS_ToBigFloat(ctx, &a_s, val);
50957
0
            if (!a) {
50958
0
                JS_FreeValue(ctx, val);
50959
0
                return JS_EXCEPTION;
50960
0
            }
50961
0
            if (!bf_is_finite(a)) {
50962
0
                JS_FreeValue(ctx, val);
50963
0
                val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to BigInt");
50964
0
            } else {
50965
0
                JSValue val1 = JS_NewBigInt(ctx);
50966
0
                bf_t *r;
50967
0
                int ret;
50968
0
                if (JS_IsException(val1)) {
50969
0
                    JS_FreeValue(ctx, val);
50970
0
                    return JS_EXCEPTION;
50971
0
                }
50972
0
                r = JS_GetBigInt(val1);
50973
0
                ret = bf_set(r, a);
50974
0
                ret |= bf_rint(r, BF_RNDZ);
50975
0
                JS_FreeValue(ctx, val);
50976
0
                if (ret & BF_ST_MEM_ERROR) {
50977
0
                    JS_FreeValue(ctx, val1);
50978
0
                    val = JS_ThrowOutOfMemory(ctx);
50979
0
                } else if (ret & BF_ST_INEXACT) {
50980
0
                    JS_FreeValue(ctx, val1);
50981
0
                    val = JS_ThrowRangeError(ctx, "cannot convert to BigInt: not an integer");
50982
0
                } else {
50983
0
                    val = JS_CompactBigInt(ctx, val1);
50984
0
                }
50985
0
            }
50986
0
            if (a == &a_s)
50987
0
                bf_delete(a);
50988
0
        }
50989
0
        break;
50990
0
#ifdef CONFIG_BIGNUM
50991
0
    case JS_TAG_BIG_DECIMAL:
50992
0
        val = JS_ToStringFree(ctx, val);
50993
0
        if (JS_IsException(val))
50994
0
            break;
50995
0
        goto redo;
50996
0
#endif
50997
0
    case JS_TAG_STRING:
50998
0
        val = JS_StringToBigIntErr(ctx, val);
50999
0
        break;
51000
0
    case JS_TAG_OBJECT:
51001
0
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
51002
0
        if (JS_IsException(val))
51003
0
            break;
51004
0
        goto redo;
51005
0
    case JS_TAG_NULL:
51006
0
    case JS_TAG_UNDEFINED:
51007
0
    default:
51008
0
        JS_FreeValue(ctx, val);
51009
0
        return JS_ThrowTypeError(ctx, "cannot convert to BigInt");
51010
0
    }
51011
0
    return val;
51012
0
}
51013
51014
static JSValue js_bigint_constructor(JSContext *ctx,
51015
                                     JSValueConst new_target,
51016
                                     int argc, JSValueConst *argv)
51017
0
{
51018
0
    if (!JS_IsUndefined(new_target))
51019
0
        return JS_ThrowTypeError(ctx, "not a constructor");
51020
0
    return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
51021
0
}
51022
51023
static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
51024
0
{
51025
0
    if (JS_IsBigInt(ctx, this_val))
51026
0
        return JS_DupValue(ctx, this_val);
51027
51028
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
51029
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
51030
0
        if (p->class_id == JS_CLASS_BIG_INT) {
51031
0
            if (JS_IsBigInt(ctx, p->u.object_data))
51032
0
                return JS_DupValue(ctx, p->u.object_data);
51033
0
        }
51034
0
    }
51035
0
    return JS_ThrowTypeError(ctx, "not a BigInt");
51036
0
}
51037
51038
static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val,
51039
                                  int argc, JSValueConst *argv)
51040
0
{
51041
0
    JSValue val;
51042
0
    int base;
51043
0
    JSValue ret;
51044
51045
0
    val = js_thisBigIntValue(ctx, this_val);
51046
0
    if (JS_IsException(val))
51047
0
        return val;
51048
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
51049
0
        base = 10;
51050
0
    } else {
51051
0
        base = js_get_radix(ctx, argv[0]);
51052
0
        if (base < 0)
51053
0
            goto fail;
51054
0
    }
51055
0
    ret = js_bigint_to_string1(ctx, val, base);
51056
0
    JS_FreeValue(ctx, val);
51057
0
    return ret;
51058
0
 fail:
51059
0
    JS_FreeValue(ctx, val);
51060
0
    return JS_EXCEPTION;
51061
0
}
51062
51063
static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val,
51064
                                 int argc, JSValueConst *argv)
51065
0
{
51066
0
    return js_thisBigIntValue(ctx, this_val);
51067
0
}
51068
51069
#ifdef CONFIG_BIGNUM
51070
static JSValue js_bigint_div(JSContext *ctx,
51071
                              JSValueConst this_val,
51072
                              int argc, JSValueConst *argv, int magic)
51073
0
{
51074
0
    bf_t a_s, b_s, *a, *b, *r, *q;
51075
0
    int status;
51076
0
    JSValue q_val, r_val;
51077
51078
0
    q_val = JS_NewBigInt(ctx);
51079
0
    if (JS_IsException(q_val))
51080
0
        return JS_EXCEPTION;
51081
0
    r_val = JS_NewBigInt(ctx);
51082
0
    if (JS_IsException(r_val))
51083
0
        goto fail;
51084
0
    b = NULL;
51085
0
    a = JS_ToBigInt(ctx, &a_s, argv[0]);
51086
0
    if (!a)
51087
0
        goto fail;
51088
0
    b = JS_ToBigInt(ctx, &b_s, argv[1]);
51089
0
    if (!b) {
51090
0
        JS_FreeBigInt(ctx, a, &a_s);
51091
0
        goto fail;
51092
0
    }
51093
0
    q = JS_GetBigInt(q_val);
51094
0
    r = JS_GetBigInt(r_val);
51095
0
    status = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, magic & 0xf);
51096
0
    JS_FreeBigInt(ctx, a, &a_s);
51097
0
    JS_FreeBigInt(ctx, b, &b_s);
51098
0
    if (unlikely(status)) {
51099
0
        throw_bf_exception(ctx, status);
51100
0
        goto fail;
51101
0
    }
51102
0
    q_val = JS_CompactBigInt(ctx, q_val);
51103
0
    if (magic & 0x10) {
51104
0
        JSValue ret;
51105
0
        ret = JS_NewArray(ctx);
51106
0
        if (JS_IsException(ret))
51107
0
            goto fail;
51108
0
        JS_SetPropertyUint32(ctx, ret, 0, q_val);
51109
0
        JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, r_val));
51110
0
        return ret;
51111
0
    } else {
51112
0
        JS_FreeValue(ctx, r_val);
51113
0
        return q_val;
51114
0
    }
51115
0
 fail:
51116
0
    JS_FreeValue(ctx, q_val);
51117
0
    JS_FreeValue(ctx, r_val);
51118
0
    return JS_EXCEPTION;
51119
0
}
51120
51121
static JSValue js_bigint_sqrt(JSContext *ctx,
51122
                               JSValueConst this_val,
51123
                               int argc, JSValueConst *argv, int magic)
51124
0
{
51125
0
    bf_t a_s, *a, *r, *rem;
51126
0
    int status;
51127
0
    JSValue r_val, rem_val;
51128
51129
0
    r_val = JS_NewBigInt(ctx);
51130
0
    if (JS_IsException(r_val))
51131
0
        return JS_EXCEPTION;
51132
0
    rem_val = JS_NewBigInt(ctx);
51133
0
    if (JS_IsException(rem_val))
51134
0
        return JS_EXCEPTION;
51135
0
    r = JS_GetBigInt(r_val);
51136
0
    rem = JS_GetBigInt(rem_val);
51137
51138
0
    a = JS_ToBigInt(ctx, &a_s, argv[0]);
51139
0
    if (!a)
51140
0
        goto fail;
51141
0
    status = bf_sqrtrem(r, rem, a);
51142
0
    JS_FreeBigInt(ctx, a, &a_s);
51143
0
    if (unlikely(status & ~BF_ST_INEXACT)) {
51144
0
        throw_bf_exception(ctx, status);
51145
0
        goto fail;
51146
0
    }
51147
0
    r_val = JS_CompactBigInt(ctx, r_val);
51148
0
    if (magic) {
51149
0
        JSValue ret;
51150
0
        ret = JS_NewArray(ctx);
51151
0
        if (JS_IsException(ret))
51152
0
            goto fail;
51153
0
        JS_SetPropertyUint32(ctx, ret, 0, r_val);
51154
0
        JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, rem_val));
51155
0
        return ret;
51156
0
    } else {
51157
0
        JS_FreeValue(ctx, rem_val);
51158
0
        return r_val;
51159
0
    }
51160
0
 fail:
51161
0
    JS_FreeValue(ctx, r_val);
51162
0
    JS_FreeValue(ctx, rem_val);
51163
0
    return JS_EXCEPTION;
51164
0
}
51165
51166
static JSValue js_bigint_op1(JSContext *ctx,
51167
                              JSValueConst this_val,
51168
                              int argc, JSValueConst *argv,
51169
                              int magic)
51170
0
{
51171
0
    bf_t a_s, *a;
51172
0
    int64_t res;
51173
51174
0
    a = JS_ToBigInt(ctx, &a_s, argv[0]);
51175
0
    if (!a)
51176
0
        return JS_EXCEPTION;
51177
0
    switch(magic) {
51178
0
    case 0: /* floorLog2 */
51179
0
        if (a->sign || a->expn <= 0) {
51180
0
            res = -1;
51181
0
        } else {
51182
0
            res = a->expn - 1;
51183
0
        }
51184
0
        break;
51185
0
    case 1: /* ctz */
51186
0
        if (bf_is_zero(a)) {
51187
0
            res = -1;
51188
0
        } else {
51189
0
            res = bf_get_exp_min(a);
51190
0
        }
51191
0
        break;
51192
0
    default:
51193
0
        abort();
51194
0
    }
51195
0
    JS_FreeBigInt(ctx, a, &a_s);
51196
0
    return JS_NewBigInt64(ctx, res);
51197
0
}
51198
#endif
51199
51200
static JSValue js_bigint_asUintN(JSContext *ctx,
51201
                                  JSValueConst this_val,
51202
                                  int argc, JSValueConst *argv, int asIntN)
51203
0
{
51204
0
    uint64_t bits;
51205
0
    bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s;
51206
0
    JSValue res;
51207
51208
0
    if (JS_ToIndex(ctx, &bits, argv[0]))
51209
0
        return JS_EXCEPTION;
51210
0
    res = JS_NewBigInt(ctx);
51211
0
    if (JS_IsException(res))
51212
0
        return JS_EXCEPTION;
51213
0
    r = JS_GetBigInt(res);
51214
0
    a = JS_ToBigInt(ctx, &a_s, argv[1]);
51215
0
    if (!a) {
51216
0
        JS_FreeValue(ctx, res);
51217
0
        return JS_EXCEPTION;
51218
0
    }
51219
    /* XXX: optimize */
51220
0
    r = JS_GetBigInt(res);
51221
0
    bf_init(ctx->bf_ctx, mask);
51222
0
    bf_set_ui(mask, 1);
51223
0
    bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
51224
0
    bf_add_si(mask, mask, -1, BF_PREC_INF, BF_RNDZ);
51225
0
    bf_logic_and(r, a, mask);
51226
0
    if (asIntN && bits != 0) {
51227
0
        bf_set_ui(mask, 1);
51228
0
        bf_mul_2exp(mask, bits - 1, BF_PREC_INF, BF_RNDZ);
51229
0
        if (bf_cmpu(r, mask) >= 0) {
51230
0
            bf_set_ui(mask, 1);
51231
0
            bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
51232
0
            bf_sub(r, r, mask, BF_PREC_INF, BF_RNDZ);
51233
0
        }
51234
0
    }
51235
0
    bf_delete(mask);
51236
0
    JS_FreeBigInt(ctx, a, &a_s);
51237
0
    return JS_CompactBigInt(ctx, res);
51238
0
}
51239
51240
static const JSCFunctionListEntry js_bigint_funcs[] = {
51241
    JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ),
51242
    JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ),
51243
#ifdef CONFIG_BIGNUM
51244
    /* QuickJS extensions */
51245
    JS_CFUNC_MAGIC_DEF("tdiv", 2, js_bigint_div, BF_RNDZ ),
51246
    JS_CFUNC_MAGIC_DEF("fdiv", 2, js_bigint_div, BF_RNDD ),
51247
    JS_CFUNC_MAGIC_DEF("cdiv", 2, js_bigint_div, BF_RNDU ),
51248
    JS_CFUNC_MAGIC_DEF("ediv", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN ),
51249
    JS_CFUNC_MAGIC_DEF("tdivrem", 2, js_bigint_div, BF_RNDZ | 0x10 ),
51250
    JS_CFUNC_MAGIC_DEF("fdivrem", 2, js_bigint_div, BF_RNDD | 0x10 ),
51251
    JS_CFUNC_MAGIC_DEF("cdivrem", 2, js_bigint_div, BF_RNDU | 0x10 ),
51252
    JS_CFUNC_MAGIC_DEF("edivrem", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN | 0x10 ),
51253
    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigint_sqrt, 0 ),
51254
    JS_CFUNC_MAGIC_DEF("sqrtrem", 1, js_bigint_sqrt, 1 ),
51255
    JS_CFUNC_MAGIC_DEF("floorLog2", 1, js_bigint_op1, 0 ),
51256
    JS_CFUNC_MAGIC_DEF("ctz", 1, js_bigint_op1, 1 ),
51257
#endif
51258
};
51259
51260
static const JSCFunctionListEntry js_bigint_proto_funcs[] = {
51261
    JS_CFUNC_DEF("toString", 0, js_bigint_toString ),
51262
    JS_CFUNC_DEF("valueOf", 0, js_bigint_valueOf ),
51263
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "BigInt", JS_PROP_CONFIGURABLE ),
51264
};
51265
51266
void JS_AddIntrinsicBigInt(JSContext *ctx)
51267
39
{
51268
39
    JSRuntime *rt = ctx->rt;
51269
39
    JSValueConst obj1;
51270
51271
39
    rt->bigint_ops.to_string = js_bigint_to_string;
51272
39
    rt->bigint_ops.from_string = js_string_to_bigint;
51273
39
    rt->bigint_ops.unary_arith = js_unary_arith_bigint;
51274
39
    rt->bigint_ops.binary_arith = js_binary_arith_bigint;
51275
39
    rt->bigint_ops.compare = js_compare_bigfloat;
51276
51277
39
    ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx);
51278
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
51279
39
                               js_bigint_proto_funcs,
51280
39
                               countof(js_bigint_proto_funcs));
51281
39
    obj1 = JS_NewGlobalCConstructor(ctx, "BigInt", js_bigint_constructor, 1,
51282
39
                                    ctx->class_proto[JS_CLASS_BIG_INT]);
51283
39
    JS_SetPropertyFunctionList(ctx, obj1, js_bigint_funcs,
51284
39
                               countof(js_bigint_funcs));
51285
39
}
51286
51287
#ifdef CONFIG_BIGNUM
51288
51289
/* BigFloat */
51290
51291
static JSValue js_thisBigFloatValue(JSContext *ctx, JSValueConst this_val)
51292
0
{
51293
0
    if (JS_IsBigFloat(this_val))
51294
0
        return JS_DupValue(ctx, this_val);
51295
51296
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
51297
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
51298
0
        if (p->class_id == JS_CLASS_BIG_FLOAT) {
51299
0
            if (JS_IsBigFloat(p->u.object_data))
51300
0
                return JS_DupValue(ctx, p->u.object_data);
51301
0
        }
51302
0
    }
51303
0
    return JS_ThrowTypeError(ctx, "not a bigfloat");
51304
0
}
51305
51306
static JSValue js_bigfloat_toString(JSContext *ctx, JSValueConst this_val,
51307
                                    int argc, JSValueConst *argv)
51308
0
{
51309
0
    JSValue val;
51310
0
    int base;
51311
0
    JSValue ret;
51312
51313
0
    val = js_thisBigFloatValue(ctx, this_val);
51314
0
    if (JS_IsException(val))
51315
0
        return val;
51316
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
51317
0
        base = 10;
51318
0
    } else {
51319
0
        base = js_get_radix(ctx, argv[0]);
51320
0
        if (base < 0)
51321
0
            goto fail;
51322
0
    }
51323
0
    ret = js_ftoa(ctx, val, base, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
51324
0
    JS_FreeValue(ctx, val);
51325
0
    return ret;
51326
0
 fail:
51327
0
    JS_FreeValue(ctx, val);
51328
0
    return JS_EXCEPTION;
51329
0
}
51330
51331
static JSValue js_bigfloat_valueOf(JSContext *ctx, JSValueConst this_val,
51332
                                   int argc, JSValueConst *argv)
51333
0
{
51334
0
    return js_thisBigFloatValue(ctx, this_val);
51335
0
}
51336
51337
static int bigfloat_get_rnd_mode(JSContext *ctx, JSValueConst val)
51338
0
{
51339
0
    int rnd_mode;
51340
0
    if (JS_ToInt32Sat(ctx, &rnd_mode, val))
51341
0
        return -1;
51342
0
    if (rnd_mode < BF_RNDN || rnd_mode > BF_RNDF) {
51343
0
        JS_ThrowRangeError(ctx, "invalid rounding mode");
51344
0
        return -1;
51345
0
    }
51346
0
    return rnd_mode;
51347
0
}
51348
51349
static JSValue js_bigfloat_toFixed(JSContext *ctx, JSValueConst this_val,
51350
                                 int argc, JSValueConst *argv)
51351
0
{
51352
0
    JSValue val, ret;
51353
0
    int64_t f;
51354
0
    int rnd_mode, radix;
51355
51356
0
    val = js_thisBigFloatValue(ctx, this_val);
51357
0
    if (JS_IsException(val))
51358
0
        return val;
51359
0
    if (JS_ToInt64Sat(ctx, &f, argv[0]))
51360
0
        goto fail;
51361
0
    if (f < 0 || f > BF_PREC_MAX) {
51362
0
        JS_ThrowRangeError(ctx, "invalid number of digits");
51363
0
        goto fail;
51364
0
    }
51365
0
    rnd_mode = BF_RNDNA;
51366
0
    radix = 10;
51367
    /* XXX: swap parameter order for rounding mode and radix */
51368
0
    if (argc > 1) {
51369
0
        rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
51370
0
        if (rnd_mode < 0)
51371
0
            goto fail;
51372
0
    }
51373
0
    if (argc > 2) {
51374
0
        radix = js_get_radix(ctx, argv[2]);
51375
0
        if (radix < 0)
51376
0
            goto fail;
51377
0
    }
51378
0
    ret = js_ftoa(ctx, val, radix, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
51379
0
    JS_FreeValue(ctx, val);
51380
0
    return ret;
51381
0
 fail:
51382
0
    JS_FreeValue(ctx, val);
51383
0
    return JS_EXCEPTION;
51384
0
}
51385
51386
static BOOL js_bigfloat_is_finite(JSContext *ctx, JSValueConst val)
51387
0
{
51388
0
    BOOL res;
51389
0
    uint32_t tag;
51390
51391
0
    tag = JS_VALUE_GET_NORM_TAG(val);
51392
0
    switch(tag) {
51393
0
    case JS_TAG_BIG_FLOAT:
51394
0
        {
51395
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
51396
0
            res = bf_is_finite(&p->num);
51397
0
        }
51398
0
        break;
51399
0
    default:
51400
0
        res = FALSE;
51401
0
        break;
51402
0
    }
51403
0
    return res;
51404
0
}
51405
51406
static JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val,
51407
                                       int argc, JSValueConst *argv)
51408
0
{
51409
0
    JSValue val, ret;
51410
0
    int64_t f;
51411
0
    int rnd_mode, radix;
51412
51413
0
    val = js_thisBigFloatValue(ctx, this_val);
51414
0
    if (JS_IsException(val))
51415
0
        return val;
51416
0
    if (JS_ToInt64Sat(ctx, &f, argv[0]))
51417
0
        goto fail;
51418
0
    if (!js_bigfloat_is_finite(ctx, val)) {
51419
0
        ret = JS_ToString(ctx, val);
51420
0
    } else if (JS_IsUndefined(argv[0])) {
51421
0
        ret = js_ftoa(ctx, val, 10, 0,
51422
0
                      BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
51423
0
    } else {
51424
0
        if (f < 0 || f > BF_PREC_MAX) {
51425
0
            JS_ThrowRangeError(ctx, "invalid number of digits");
51426
0
            goto fail;
51427
0
        }
51428
0
        rnd_mode = BF_RNDNA;
51429
0
        radix = 10;
51430
0
        if (argc > 1) {
51431
0
            rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
51432
0
            if (rnd_mode < 0)
51433
0
                goto fail;
51434
0
        }
51435
0
        if (argc > 2) {
51436
0
            radix = js_get_radix(ctx, argv[2]);
51437
0
            if (radix < 0)
51438
0
                goto fail;
51439
0
        }
51440
0
        ret = js_ftoa(ctx, val, radix, f + 1,
51441
0
                      rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
51442
0
    }
51443
0
    JS_FreeValue(ctx, val);
51444
0
    return ret;
51445
0
 fail:
51446
0
    JS_FreeValue(ctx, val);
51447
0
    return JS_EXCEPTION;
51448
0
}
51449
51450
static JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val,
51451
                                     int argc, JSValueConst *argv)
51452
0
{
51453
0
    JSValue val, ret;
51454
0
    int64_t p;
51455
0
    int rnd_mode, radix;
51456
51457
0
    val = js_thisBigFloatValue(ctx, this_val);
51458
0
    if (JS_IsException(val))
51459
0
        return val;
51460
0
    if (JS_IsUndefined(argv[0]))
51461
0
        goto to_string;
51462
0
    if (JS_ToInt64Sat(ctx, &p, argv[0]))
51463
0
        goto fail;
51464
0
    if (!js_bigfloat_is_finite(ctx, val)) {
51465
0
    to_string:
51466
0
        ret = JS_ToString(ctx, this_val);
51467
0
    } else {
51468
0
        if (p < 1 || p > BF_PREC_MAX) {
51469
0
            JS_ThrowRangeError(ctx, "invalid number of digits");
51470
0
            goto fail;
51471
0
        }
51472
0
        rnd_mode = BF_RNDNA;
51473
0
        radix = 10;
51474
0
        if (argc > 1) {
51475
0
            rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
51476
0
            if (rnd_mode < 0)
51477
0
                goto fail;
51478
0
        }
51479
0
        if (argc > 2) {
51480
0
            radix = js_get_radix(ctx, argv[2]);
51481
0
            if (radix < 0)
51482
0
                goto fail;
51483
0
        }
51484
0
        ret = js_ftoa(ctx, val, radix, p, rnd_mode | BF_FTOA_FORMAT_FIXED);
51485
0
    }
51486
0
    JS_FreeValue(ctx, val);
51487
0
    return ret;
51488
0
 fail:
51489
0
    JS_FreeValue(ctx, val);
51490
0
    return JS_EXCEPTION;
51491
0
}
51492
51493
static const JSCFunctionListEntry js_bigfloat_proto_funcs[] = {
51494
    JS_CFUNC_DEF("toString", 0, js_bigfloat_toString ),
51495
    JS_CFUNC_DEF("valueOf", 0, js_bigfloat_valueOf ),
51496
    JS_CFUNC_DEF("toPrecision", 1, js_bigfloat_toPrecision ),
51497
    JS_CFUNC_DEF("toFixed", 1, js_bigfloat_toFixed ),
51498
    JS_CFUNC_DEF("toExponential", 1, js_bigfloat_toExponential ),
51499
};
51500
51501
static JSValue js_bigfloat_constructor(JSContext *ctx,
51502
                                       JSValueConst new_target,
51503
                                       int argc, JSValueConst *argv)
51504
0
{
51505
0
    JSValue val;
51506
0
    if (!JS_IsUndefined(new_target))
51507
0
        return JS_ThrowTypeError(ctx, "not a constructor");
51508
0
    if (argc == 0) {
51509
0
        bf_t *r;
51510
0
        val = JS_NewBigFloat(ctx);
51511
0
        if (JS_IsException(val))
51512
0
            return val;
51513
0
        r = JS_GetBigFloat(val);
51514
0
        bf_set_zero(r, 0);
51515
0
    } else {
51516
0
        val = JS_DupValue(ctx, argv[0]);
51517
0
    redo:
51518
0
        switch(JS_VALUE_GET_NORM_TAG(val)) {
51519
0
        case JS_TAG_BIG_FLOAT:
51520
0
            break;
51521
0
        case JS_TAG_FLOAT64:
51522
0
            {
51523
0
                bf_t *r;
51524
0
                double d = JS_VALUE_GET_FLOAT64(val);
51525
0
                val = JS_NewBigFloat(ctx);
51526
0
                if (JS_IsException(val))
51527
0
                    break;
51528
0
                r = JS_GetBigFloat(val);
51529
0
                if (bf_set_float64(r, d))
51530
0
                    goto fail;
51531
0
            }
51532
0
            break;
51533
0
        case JS_TAG_INT:
51534
0
            {
51535
0
                bf_t *r;
51536
0
                int32_t v = JS_VALUE_GET_INT(val);
51537
0
                val = JS_NewBigFloat(ctx);
51538
0
                if (JS_IsException(val))
51539
0
                    break;
51540
0
                r = JS_GetBigFloat(val);
51541
0
                if (bf_set_si(r, v))
51542
0
                    goto fail;
51543
0
            }
51544
0
            break;
51545
0
        case JS_TAG_BIG_INT:
51546
            /* We keep the full precision of the integer */
51547
0
            {
51548
0
                JSBigFloat *p = JS_VALUE_GET_PTR(val);
51549
0
                val = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
51550
0
            }
51551
0
            break;
51552
0
        case JS_TAG_BIG_DECIMAL:
51553
0
            val = JS_ToStringFree(ctx, val);
51554
0
            if (JS_IsException(val))
51555
0
                break;
51556
0
            goto redo;
51557
0
        case JS_TAG_STRING:
51558
0
            {
51559
0
                const char *str, *p;
51560
0
                size_t len;
51561
0
                int err;
51562
51563
0
                str = JS_ToCStringLen(ctx, &len, val);
51564
0
                JS_FreeValue(ctx, val);
51565
0
                if (!str)
51566
0
                    return JS_EXCEPTION;
51567
0
                p = str;
51568
0
                p += skip_spaces(p);
51569
0
                if ((p - str) == len) {
51570
0
                    bf_t *r;
51571
0
                    val = JS_NewBigFloat(ctx);
51572
0
                    if (JS_IsException(val))
51573
0
                        break;
51574
0
                    r = JS_GetBigFloat(val);
51575
0
                    bf_set_zero(r, 0);
51576
0
                    err = 0;
51577
0
                } else {
51578
0
                    val = js_atof(ctx, p, &p, 0, ATOD_ACCEPT_BIN_OCT |
51579
0
                                  ATOD_TYPE_BIG_FLOAT |
51580
0
                                  ATOD_ACCEPT_PREFIX_AFTER_SIGN);
51581
0
                    if (JS_IsException(val)) {
51582
0
                        JS_FreeCString(ctx, str);
51583
0
                        return JS_EXCEPTION;
51584
0
                    }
51585
0
                    p += skip_spaces(p);
51586
0
                    err = ((p - str) != len);
51587
0
                }
51588
0
                JS_FreeCString(ctx, str);
51589
0
                if (err) {
51590
0
                    JS_FreeValue(ctx, val);
51591
0
                    return JS_ThrowSyntaxError(ctx, "invalid bigfloat literal");
51592
0
                }
51593
0
            }
51594
0
            break;
51595
0
        case JS_TAG_OBJECT:
51596
0
            val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
51597
0
            if (JS_IsException(val))
51598
0
                break;
51599
0
            goto redo;
51600
0
        case JS_TAG_NULL:
51601
0
        case JS_TAG_UNDEFINED:
51602
0
        default:
51603
0
            JS_FreeValue(ctx, val);
51604
0
            return JS_ThrowTypeError(ctx, "cannot convert to bigfloat");
51605
0
        }
51606
0
    }
51607
0
    return val;
51608
0
 fail:
51609
0
    JS_FreeValue(ctx, val);
51610
0
    return JS_EXCEPTION;
51611
0
}
51612
51613
static JSValue js_bigfloat_get_const(JSContext *ctx,
51614
                                     JSValueConst this_val, int magic)
51615
0
{
51616
0
    bf_t *r;
51617
0
    JSValue val;
51618
0
    val = JS_NewBigFloat(ctx);
51619
0
    if (JS_IsException(val))
51620
0
        return val;
51621
0
    r = JS_GetBigFloat(val);
51622
0
    switch(magic) {
51623
0
    case 0: /* PI */
51624
0
        bf_const_pi(r, ctx->fp_env.prec, ctx->fp_env.flags);
51625
0
        break;
51626
0
    case 1: /* LN2 */
51627
0
        bf_const_log2(r, ctx->fp_env.prec, ctx->fp_env.flags);
51628
0
        break;
51629
0
    case 2: /* MIN_VALUE */
51630
0
    case 3: /* MAX_VALUE */
51631
0
        {
51632
0
            slimb_t e_range, e;
51633
0
            e_range = (limb_t)1 << (bf_get_exp_bits(ctx->fp_env.flags) - 1);
51634
0
            bf_set_ui(r, 1);
51635
0
            if (magic == 2) {
51636
0
                e = -e_range + 2;
51637
0
                if (ctx->fp_env.flags & BF_FLAG_SUBNORMAL)
51638
0
                    e -= ctx->fp_env.prec - 1;
51639
0
                bf_mul_2exp(r, e, ctx->fp_env.prec, ctx->fp_env.flags);
51640
0
            } else {
51641
0
                bf_mul_2exp(r, ctx->fp_env.prec, ctx->fp_env.prec,
51642
0
                            ctx->fp_env.flags);
51643
0
                bf_add_si(r, r, -1, ctx->fp_env.prec, ctx->fp_env.flags);
51644
0
                bf_mul_2exp(r, e_range - ctx->fp_env.prec, ctx->fp_env.prec,
51645
0
                            ctx->fp_env.flags);
51646
0
            }
51647
0
        }
51648
0
        break;
51649
0
    case 4: /* EPSILON */
51650
0
        bf_set_ui(r, 1);
51651
0
        bf_mul_2exp(r, 1 - ctx->fp_env.prec,
51652
0
                    ctx->fp_env.prec, ctx->fp_env.flags);
51653
0
        break;
51654
0
    default:
51655
0
        abort();
51656
0
    }
51657
0
    return val;
51658
0
}
51659
51660
static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val,
51661
                                      int argc, JSValueConst *argv)
51662
0
{
51663
0
    bf_t *a;
51664
0
    const char *str;
51665
0
    JSValue ret;
51666
0
    int radix;
51667
0
    JSFloatEnv *fe;
51668
51669
0
    str = JS_ToCString(ctx, argv[0]);
51670
0
    if (!str)
51671
0
        return JS_EXCEPTION;
51672
0
    if (JS_ToInt32(ctx, &radix, argv[1])) {
51673
0
    fail:
51674
0
        JS_FreeCString(ctx, str);
51675
0
        return JS_EXCEPTION;
51676
0
    }
51677
0
    if (radix != 0 && (radix < 2 || radix > 36)) {
51678
0
        JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
51679
0
        goto fail;
51680
0
    }
51681
0
    fe = &ctx->fp_env;
51682
0
    if (argc > 2) {
51683
0
        fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
51684
0
        if (!fe)
51685
0
            goto fail;
51686
0
    }
51687
0
    ret = JS_NewBigFloat(ctx);
51688
0
    if (JS_IsException(ret))
51689
0
        goto done;
51690
0
    a = JS_GetBigFloat(ret);
51691
    /* XXX: use js_atof() */
51692
0
    bf_atof(a, str, NULL, radix, fe->prec, fe->flags);
51693
0
 done:
51694
0
    JS_FreeCString(ctx, str);
51695
0
    return ret;
51696
0
}
51697
51698
static JSValue js_bigfloat_isFinite(JSContext *ctx, JSValueConst this_val,
51699
                                    int argc, JSValueConst *argv)
51700
0
{
51701
0
    JSValueConst val = argv[0];
51702
0
    JSBigFloat *p;
51703
51704
0
    if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)
51705
0
        return JS_FALSE;
51706
0
    p = JS_VALUE_GET_PTR(val);
51707
0
    return JS_NewBool(ctx, bf_is_finite(&p->num));
51708
0
}
51709
51710
static JSValue js_bigfloat_isNaN(JSContext *ctx, JSValueConst this_val,
51711
                                 int argc, JSValueConst *argv)
51712
0
{
51713
0
    JSValueConst val = argv[0];
51714
0
    JSBigFloat *p;
51715
51716
0
    if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)
51717
0
        return JS_FALSE;
51718
0
    p = JS_VALUE_GET_PTR(val);
51719
0
    return JS_NewBool(ctx, bf_is_nan(&p->num));
51720
0
}
51721
51722
enum {
51723
    MATH_OP_ABS,
51724
    MATH_OP_FLOOR,
51725
    MATH_OP_CEIL,
51726
    MATH_OP_ROUND,
51727
    MATH_OP_TRUNC,
51728
    MATH_OP_SQRT,
51729
    MATH_OP_FPROUND,
51730
    MATH_OP_ACOS,
51731
    MATH_OP_ASIN,
51732
    MATH_OP_ATAN,
51733
    MATH_OP_ATAN2,
51734
    MATH_OP_COS,
51735
    MATH_OP_EXP,
51736
    MATH_OP_LOG,
51737
    MATH_OP_POW,
51738
    MATH_OP_SIN,
51739
    MATH_OP_TAN,
51740
    MATH_OP_FMOD,
51741
    MATH_OP_REM,
51742
    MATH_OP_SIGN,
51743
51744
    MATH_OP_ADD,
51745
    MATH_OP_SUB,
51746
    MATH_OP_MUL,
51747
    MATH_OP_DIV,
51748
};
51749
51750
static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val,
51751
                           int argc, JSValueConst *argv, int magic)
51752
0
{
51753
0
    bf_t a_s, *a, *r;
51754
0
    JSFloatEnv *fe;
51755
0
    int rnd_mode;
51756
0
    JSValue op1, res;
51757
51758
0
    op1 = JS_ToNumeric(ctx, argv[0]);
51759
0
    if (JS_IsException(op1))
51760
0
        return op1;
51761
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
51762
0
    if (!a) {
51763
0
        JS_FreeValue(ctx, op1);
51764
0
        return JS_EXCEPTION;
51765
0
    }
51766
0
    fe = &ctx->fp_env;
51767
0
    if (argc > 1) {
51768
0
        fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV);
51769
0
        if (!fe)
51770
0
            goto fail;
51771
0
    }
51772
0
    res = JS_NewBigFloat(ctx);
51773
0
    if (JS_IsException(res)) {
51774
0
    fail:
51775
0
        if (a == &a_s)
51776
0
            bf_delete(a);
51777
0
        JS_FreeValue(ctx, op1);
51778
0
        return JS_EXCEPTION;
51779
0
    }
51780
0
    r = JS_GetBigFloat(res);
51781
0
    switch (magic) {
51782
0
    case MATH_OP_ABS:
51783
0
        bf_set(r, a);
51784
0
        r->sign = 0;
51785
0
        break;
51786
0
    case MATH_OP_FLOOR:
51787
0
        rnd_mode = BF_RNDD;
51788
0
        goto rint;
51789
0
    case MATH_OP_CEIL:
51790
0
        rnd_mode = BF_RNDU;
51791
0
        goto rint;
51792
0
    case MATH_OP_ROUND:
51793
0
        rnd_mode = BF_RNDNA;
51794
0
        goto rint;
51795
0
    case MATH_OP_TRUNC:
51796
0
        rnd_mode = BF_RNDZ;
51797
0
    rint:
51798
0
        bf_set(r, a);
51799
0
        fe->status |= bf_rint(r, rnd_mode);
51800
0
        break;
51801
0
    case MATH_OP_SQRT:
51802
0
        fe->status |= bf_sqrt(r, a, fe->prec, fe->flags);
51803
0
        break;
51804
0
    case MATH_OP_FPROUND:
51805
0
        bf_set(r, a);
51806
0
        fe->status |= bf_round(r, fe->prec, fe->flags);
51807
0
        break;
51808
0
    case MATH_OP_ACOS:
51809
0
        fe->status |= bf_acos(r, a, fe->prec, fe->flags);
51810
0
        break;
51811
0
    case MATH_OP_ASIN:
51812
0
        fe->status |= bf_asin(r, a, fe->prec, fe->flags);
51813
0
        break;
51814
0
    case MATH_OP_ATAN:
51815
0
        fe->status |= bf_atan(r, a, fe->prec, fe->flags);
51816
0
        break;
51817
0
    case MATH_OP_COS:
51818
0
        fe->status |= bf_cos(r, a, fe->prec, fe->flags);
51819
0
        break;
51820
0
    case MATH_OP_EXP:
51821
0
        fe->status |= bf_exp(r, a, fe->prec, fe->flags);
51822
0
        break;
51823
0
    case MATH_OP_LOG:
51824
0
        fe->status |= bf_log(r, a, fe->prec, fe->flags);
51825
0
        break;
51826
0
    case MATH_OP_SIN:
51827
0
        fe->status |= bf_sin(r, a, fe->prec, fe->flags);
51828
0
        break;
51829
0
    case MATH_OP_TAN:
51830
0
        fe->status |= bf_tan(r, a, fe->prec, fe->flags);
51831
0
        break;
51832
0
    case MATH_OP_SIGN:
51833
0
        if (bf_is_nan(a) || bf_is_zero(a)) {
51834
0
            bf_set(r, a);
51835
0
        } else {
51836
0
            bf_set_si(r, 1 - 2 * a->sign);
51837
0
        }
51838
0
        break;
51839
0
    default:
51840
0
        abort();
51841
0
    }
51842
0
    if (a == &a_s)
51843
0
        bf_delete(a);
51844
0
    JS_FreeValue(ctx, op1);
51845
0
    return res;
51846
0
}
51847
51848
static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val,
51849
                            int argc, JSValueConst *argv, int magic)
51850
0
{
51851
0
    bf_t a_s, *a, b_s, *b, r_s, *r = &r_s;
51852
0
    JSFloatEnv *fe;
51853
0
    JSValue op1, op2, res;
51854
51855
0
    op1 = JS_ToNumeric(ctx, argv[0]);
51856
0
    if (JS_IsException(op1))
51857
0
        return op1;
51858
0
    op2 = JS_ToNumeric(ctx, argv[1]);
51859
0
    if (JS_IsException(op2)) {
51860
0
        JS_FreeValue(ctx, op1);
51861
0
        return op2;
51862
0
    }
51863
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
51864
0
    if (!a)
51865
0
        goto fail1;
51866
0
    b = JS_ToBigFloat(ctx, &b_s, op2);
51867
0
    if (!b)
51868
0
        goto fail2;
51869
0
    fe = &ctx->fp_env;
51870
0
    if (argc > 2) {
51871
0
        fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
51872
0
        if (!fe)
51873
0
            goto fail;
51874
0
    }
51875
0
    res = JS_NewBigFloat(ctx);
51876
0
    if (JS_IsException(res)) {
51877
0
    fail:
51878
0
        if (b == &b_s)
51879
0
            bf_delete(b);
51880
0
    fail2:
51881
0
        if (a == &a_s)
51882
0
            bf_delete(a);
51883
0
    fail1:
51884
0
        JS_FreeValue(ctx, op1);
51885
0
        JS_FreeValue(ctx, op2);
51886
0
        return JS_EXCEPTION;
51887
0
    }
51888
0
    r = JS_GetBigFloat(res);
51889
0
    switch (magic) {
51890
0
    case MATH_OP_ATAN2:
51891
0
        fe->status |= bf_atan2(r, a, b, fe->prec, fe->flags);
51892
0
        break;
51893
0
    case MATH_OP_POW:
51894
0
        fe->status |= bf_pow(r, a, b, fe->prec, fe->flags | BF_POW_JS_QUIRKS);
51895
0
        break;
51896
0
    case MATH_OP_FMOD:
51897
0
        fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
51898
0
        break;
51899
0
    case MATH_OP_REM:
51900
0
        fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDN);
51901
0
        break;
51902
0
    case MATH_OP_ADD:
51903
0
        fe->status |= bf_add(r, a, b, fe->prec, fe->flags);
51904
0
        break;
51905
0
    case MATH_OP_SUB:
51906
0
        fe->status |= bf_sub(r, a, b, fe->prec, fe->flags);
51907
0
        break;
51908
0
    case MATH_OP_MUL:
51909
0
        fe->status |= bf_mul(r, a, b, fe->prec, fe->flags);
51910
0
        break;
51911
0
    case MATH_OP_DIV:
51912
0
        fe->status |= bf_div(r, a, b, fe->prec, fe->flags);
51913
0
        break;
51914
0
    default:
51915
0
        abort();
51916
0
    }
51917
0
    if (a == &a_s)
51918
0
        bf_delete(a);
51919
0
    if (b == &b_s)
51920
0
        bf_delete(b);
51921
0
    JS_FreeValue(ctx, op1);
51922
0
    JS_FreeValue(ctx, op2);
51923
0
    return res;
51924
0
}
51925
51926
static const JSCFunctionListEntry js_bigfloat_funcs[] = {
51927
    JS_CGETSET_MAGIC_DEF("PI", js_bigfloat_get_const, NULL, 0 ),
51928
    JS_CGETSET_MAGIC_DEF("LN2", js_bigfloat_get_const, NULL, 1 ),
51929
    JS_CGETSET_MAGIC_DEF("MIN_VALUE", js_bigfloat_get_const, NULL, 2 ),
51930
    JS_CGETSET_MAGIC_DEF("MAX_VALUE", js_bigfloat_get_const, NULL, 3 ),
51931
    JS_CGETSET_MAGIC_DEF("EPSILON", js_bigfloat_get_const, NULL, 4 ),
51932
    JS_CFUNC_DEF("parseFloat", 1, js_bigfloat_parseFloat ),
51933
    JS_CFUNC_DEF("isFinite", 1, js_bigfloat_isFinite ),
51934
    JS_CFUNC_DEF("isNaN", 1, js_bigfloat_isNaN ),
51935
    JS_CFUNC_MAGIC_DEF("abs", 1, js_bigfloat_fop, MATH_OP_ABS ),
51936
    JS_CFUNC_MAGIC_DEF("fpRound", 1, js_bigfloat_fop, MATH_OP_FPROUND ),
51937
    JS_CFUNC_MAGIC_DEF("floor", 1, js_bigfloat_fop, MATH_OP_FLOOR ),
51938
    JS_CFUNC_MAGIC_DEF("ceil", 1, js_bigfloat_fop, MATH_OP_CEIL ),
51939
    JS_CFUNC_MAGIC_DEF("round", 1, js_bigfloat_fop, MATH_OP_ROUND ),
51940
    JS_CFUNC_MAGIC_DEF("trunc", 1, js_bigfloat_fop, MATH_OP_TRUNC ),
51941
    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigfloat_fop, MATH_OP_SQRT ),
51942
    JS_CFUNC_MAGIC_DEF("acos", 1, js_bigfloat_fop, MATH_OP_ACOS ),
51943
    JS_CFUNC_MAGIC_DEF("asin", 1, js_bigfloat_fop, MATH_OP_ASIN ),
51944
    JS_CFUNC_MAGIC_DEF("atan", 1, js_bigfloat_fop, MATH_OP_ATAN ),
51945
    JS_CFUNC_MAGIC_DEF("atan2", 2, js_bigfloat_fop2, MATH_OP_ATAN2 ),
51946
    JS_CFUNC_MAGIC_DEF("cos", 1, js_bigfloat_fop, MATH_OP_COS ),
51947
    JS_CFUNC_MAGIC_DEF("exp", 1, js_bigfloat_fop, MATH_OP_EXP ),
51948
    JS_CFUNC_MAGIC_DEF("log", 1, js_bigfloat_fop, MATH_OP_LOG ),
51949
    JS_CFUNC_MAGIC_DEF("pow", 2, js_bigfloat_fop2, MATH_OP_POW ),
51950
    JS_CFUNC_MAGIC_DEF("sin", 1, js_bigfloat_fop, MATH_OP_SIN ),
51951
    JS_CFUNC_MAGIC_DEF("tan", 1, js_bigfloat_fop, MATH_OP_TAN ),
51952
    JS_CFUNC_MAGIC_DEF("sign", 1, js_bigfloat_fop, MATH_OP_SIGN ),
51953
    JS_CFUNC_MAGIC_DEF("add", 2, js_bigfloat_fop2, MATH_OP_ADD ),
51954
    JS_CFUNC_MAGIC_DEF("sub", 2, js_bigfloat_fop2, MATH_OP_SUB ),
51955
    JS_CFUNC_MAGIC_DEF("mul", 2, js_bigfloat_fop2, MATH_OP_MUL ),
51956
    JS_CFUNC_MAGIC_DEF("div", 2, js_bigfloat_fop2, MATH_OP_DIV ),
51957
    JS_CFUNC_MAGIC_DEF("fmod", 2, js_bigfloat_fop2, MATH_OP_FMOD ),
51958
    JS_CFUNC_MAGIC_DEF("remainder", 2, js_bigfloat_fop2, MATH_OP_REM ),
51959
};
51960
51961
/* FloatEnv */
51962
51963
static JSValue js_float_env_constructor(JSContext *ctx,
51964
                                        JSValueConst new_target,
51965
                                        int argc, JSValueConst *argv)
51966
0
{
51967
0
    JSValue obj;
51968
0
    JSFloatEnv *fe;
51969
0
    int64_t prec;
51970
0
    int flags, rndmode;
51971
51972
0
    prec = ctx->fp_env.prec;
51973
0
    flags = ctx->fp_env.flags;
51974
0
    if (!JS_IsUndefined(argv[0])) {
51975
0
        if (JS_ToInt64Sat(ctx, &prec, argv[0]))
51976
0
            return JS_EXCEPTION;
51977
0
        if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
51978
0
            return JS_ThrowRangeError(ctx, "invalid precision");
51979
0
        flags = BF_RNDN; /* RNDN, max exponent size, no subnormal */
51980
0
        if (argc > 1 && !JS_IsUndefined(argv[1])) {
51981
0
            if (JS_ToInt32Sat(ctx, &rndmode, argv[1]))
51982
0
                return JS_EXCEPTION;
51983
0
            if (rndmode < BF_RNDN || rndmode > BF_RNDF)
51984
0
                return JS_ThrowRangeError(ctx, "invalid rounding mode");
51985
0
            flags = rndmode;
51986
0
        }
51987
0
    }
51988
51989
0
    obj = JS_NewObjectClass(ctx, JS_CLASS_FLOAT_ENV);
51990
0
    if (JS_IsException(obj))
51991
0
        return JS_EXCEPTION;
51992
0
    fe = js_malloc(ctx, sizeof(*fe));
51993
0
    if (!fe)
51994
0
        return JS_EXCEPTION;
51995
0
    fe->prec = prec;
51996
0
    fe->flags = flags;
51997
0
    fe->status = 0;
51998
0
    JS_SetOpaque(obj, fe);
51999
0
    return obj;
52000
0
}
52001
52002
static void js_float_env_finalizer(JSRuntime *rt, JSValue val)
52003
0
{
52004
0
    JSFloatEnv *fe = JS_GetOpaque(val, JS_CLASS_FLOAT_ENV);
52005
0
    js_free_rt(rt, fe);
52006
0
}
52007
52008
static JSValue js_float_env_get_prec(JSContext *ctx, JSValueConst this_val)
52009
0
{
52010
0
    return JS_NewInt64(ctx, ctx->fp_env.prec);
52011
0
}
52012
52013
static JSValue js_float_env_get_expBits(JSContext *ctx, JSValueConst this_val)
52014
0
{
52015
0
    return JS_NewInt32(ctx, bf_get_exp_bits(ctx->fp_env.flags));
52016
0
}
52017
52018
static JSValue js_float_env_setPrec(JSContext *ctx,
52019
                                    JSValueConst this_val,
52020
                                    int argc, JSValueConst *argv)
52021
0
{
52022
0
    JSValueConst func;
52023
0
    int exp_bits, flags, saved_flags;
52024
0
    JSValue ret;
52025
0
    limb_t saved_prec;
52026
0
    int64_t prec;
52027
52028
0
    func = argv[0];
52029
0
    if (JS_ToInt64Sat(ctx, &prec, argv[1]))
52030
0
        return JS_EXCEPTION;
52031
0
    if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
52032
0
        return JS_ThrowRangeError(ctx, "invalid precision");
52033
0
    exp_bits = BF_EXP_BITS_MAX;
52034
52035
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
52036
0
        if (JS_ToInt32Sat(ctx, &exp_bits, argv[2]))
52037
0
            return JS_EXCEPTION;
52038
0
        if (exp_bits < BF_EXP_BITS_MIN || exp_bits > BF_EXP_BITS_MAX)
52039
0
            return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
52040
0
    }
52041
52042
0
    flags = BF_RNDN | BF_FLAG_SUBNORMAL | bf_set_exp_bits(exp_bits);
52043
52044
0
    saved_prec = ctx->fp_env.prec;
52045
0
    saved_flags = ctx->fp_env.flags;
52046
52047
0
    ctx->fp_env.prec = prec;
52048
0
    ctx->fp_env.flags = flags;
52049
52050
0
    ret = JS_Call(ctx, func, JS_UNDEFINED, 0, NULL);
52051
    /* always restore the floating point precision */
52052
0
    ctx->fp_env.prec = saved_prec;
52053
0
    ctx->fp_env.flags = saved_flags;
52054
0
    return ret;
52055
0
}
52056
52057
0
#define FE_PREC      (-1)
52058
0
#define FE_EXP       (-2)
52059
0
#define FE_RNDMODE   (-3)
52060
0
#define FE_SUBNORMAL (-4)
52061
52062
static JSValue js_float_env_proto_get_status(JSContext *ctx, JSValueConst this_val, int magic)
52063
0
{
52064
0
    JSFloatEnv *fe;
52065
0
    fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
52066
0
    if (!fe)
52067
0
        return JS_EXCEPTION;
52068
0
    switch(magic) {
52069
0
    case FE_PREC:
52070
0
        return JS_NewInt64(ctx, fe->prec);
52071
0
    case FE_EXP:
52072
0
        return JS_NewInt32(ctx, bf_get_exp_bits(fe->flags));
52073
0
    case FE_RNDMODE:
52074
0
        return JS_NewInt32(ctx, fe->flags & BF_RND_MASK);
52075
0
    case FE_SUBNORMAL:
52076
0
        return JS_NewBool(ctx, fe->flags & BF_FLAG_SUBNORMAL);
52077
0
    default:
52078
0
        return JS_NewBool(ctx, fe->status & magic);
52079
0
    }
52080
0
}
52081
52082
static JSValue js_float_env_proto_set_status(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic)
52083
0
{
52084
0
    JSFloatEnv *fe;
52085
0
    int b;
52086
0
    int64_t prec;
52087
52088
0
    fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
52089
0
    if (!fe)
52090
0
        return JS_EXCEPTION;
52091
0
    switch(magic) {
52092
0
    case FE_PREC:
52093
0
        if (JS_ToInt64Sat(ctx, &prec, val))
52094
0
            return JS_EXCEPTION;
52095
0
        if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
52096
0
            return JS_ThrowRangeError(ctx, "invalid precision");
52097
0
        fe->prec = prec;
52098
0
        break;
52099
0
    case FE_EXP:
52100
0
        if (JS_ToInt32Sat(ctx, &b, val))
52101
0
            return JS_EXCEPTION;
52102
0
        if (b < BF_EXP_BITS_MIN || b > BF_EXP_BITS_MAX)
52103
0
            return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
52104
0
        fe->flags = (fe->flags & ~(BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)) |
52105
0
            bf_set_exp_bits(b);
52106
0
        break;
52107
0
    case FE_RNDMODE:
52108
0
        b = bigfloat_get_rnd_mode(ctx, val);
52109
0
        if (b < 0)
52110
0
            return JS_EXCEPTION;
52111
0
        fe->flags = (fe->flags & ~BF_RND_MASK) | b;
52112
0
        break;
52113
0
    case FE_SUBNORMAL:
52114
0
        b = JS_ToBool(ctx, val);
52115
0
        fe->flags = (fe->flags & ~BF_FLAG_SUBNORMAL) | (b ? BF_FLAG_SUBNORMAL: 0);
52116
0
        break;
52117
0
    default:
52118
0
        b = JS_ToBool(ctx, val);
52119
0
        fe->status = (fe->status & ~magic) & ((-b) & magic);
52120
0
        break;
52121
0
    }
52122
0
    return JS_UNDEFINED;
52123
0
}
52124
52125
static JSValue js_float_env_clearStatus(JSContext *ctx,
52126
                                        JSValueConst this_val,
52127
                                        int argc, JSValueConst *argv)
52128
0
{
52129
0
    JSFloatEnv *fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
52130
0
    if (!fe)
52131
0
        return JS_EXCEPTION;
52132
0
    fe->status = 0;
52133
0
    return JS_UNDEFINED;
52134
0
}
52135
52136
static const JSCFunctionListEntry js_float_env_funcs[] = {
52137
    JS_CGETSET_DEF("prec", js_float_env_get_prec, NULL ),
52138
    JS_CGETSET_DEF("expBits", js_float_env_get_expBits, NULL ),
52139
    JS_CFUNC_DEF("setPrec", 2, js_float_env_setPrec ),
52140
    JS_PROP_INT32_DEF("RNDN", BF_RNDN, 0 ),
52141
    JS_PROP_INT32_DEF("RNDZ", BF_RNDZ, 0 ),
52142
    JS_PROP_INT32_DEF("RNDU", BF_RNDU, 0 ),
52143
    JS_PROP_INT32_DEF("RNDD", BF_RNDD, 0 ),
52144
    JS_PROP_INT32_DEF("RNDNA", BF_RNDNA, 0 ),
52145
    JS_PROP_INT32_DEF("RNDA", BF_RNDA, 0 ),
52146
    JS_PROP_INT32_DEF("RNDF", BF_RNDF, 0 ),
52147
    JS_PROP_INT32_DEF("precMin", BF_PREC_MIN, 0 ),
52148
    JS_PROP_INT64_DEF("precMax", BF_PREC_MAX, 0 ),
52149
    JS_PROP_INT32_DEF("expBitsMin", BF_EXP_BITS_MIN, 0 ),
52150
    JS_PROP_INT32_DEF("expBitsMax", BF_EXP_BITS_MAX, 0 ),
52151
};
52152
52153
static const JSCFunctionListEntry js_float_env_proto_funcs[] = {
52154
    JS_CGETSET_MAGIC_DEF("prec", js_float_env_proto_get_status,
52155
                         js_float_env_proto_set_status, FE_PREC ),
52156
    JS_CGETSET_MAGIC_DEF("expBits", js_float_env_proto_get_status,
52157
                         js_float_env_proto_set_status, FE_EXP ),
52158
    JS_CGETSET_MAGIC_DEF("rndMode", js_float_env_proto_get_status,
52159
                         js_float_env_proto_set_status, FE_RNDMODE ),
52160
    JS_CGETSET_MAGIC_DEF("subnormal", js_float_env_proto_get_status,
52161
                         js_float_env_proto_set_status, FE_SUBNORMAL ),
52162
    JS_CGETSET_MAGIC_DEF("invalidOperation", js_float_env_proto_get_status,
52163
                         js_float_env_proto_set_status, BF_ST_INVALID_OP ),
52164
    JS_CGETSET_MAGIC_DEF("divideByZero", js_float_env_proto_get_status,
52165
                         js_float_env_proto_set_status, BF_ST_DIVIDE_ZERO ),
52166
    JS_CGETSET_MAGIC_DEF("overflow", js_float_env_proto_get_status,
52167
                         js_float_env_proto_set_status, BF_ST_OVERFLOW ),
52168
    JS_CGETSET_MAGIC_DEF("underflow", js_float_env_proto_get_status,
52169
                         js_float_env_proto_set_status, BF_ST_UNDERFLOW ),
52170
    JS_CGETSET_MAGIC_DEF("inexact", js_float_env_proto_get_status,
52171
                         js_float_env_proto_set_status, BF_ST_INEXACT ),
52172
    JS_CFUNC_DEF("clearStatus", 0, js_float_env_clearStatus ),
52173
};
52174
52175
void JS_AddIntrinsicBigFloat(JSContext *ctx)
52176
39
{
52177
39
    JSRuntime *rt = ctx->rt;
52178
39
    JSValueConst obj1;
52179
52180
39
    rt->bigfloat_ops.to_string = js_bigfloat_to_string;
52181
39
    rt->bigfloat_ops.from_string = js_string_to_bigfloat;
52182
39
    rt->bigfloat_ops.unary_arith = js_unary_arith_bigfloat;
52183
39
    rt->bigfloat_ops.binary_arith = js_binary_arith_bigfloat;
52184
39
    rt->bigfloat_ops.compare = js_compare_bigfloat;
52185
39
    rt->bigfloat_ops.mul_pow10_to_float64 = js_mul_pow10_to_float64;
52186
39
    rt->bigfloat_ops.mul_pow10 = js_mul_pow10;
52187
52188
39
    ctx->class_proto[JS_CLASS_BIG_FLOAT] = JS_NewObject(ctx);
52189
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT],
52190
39
                               js_bigfloat_proto_funcs,
52191
39
                               countof(js_bigfloat_proto_funcs));
52192
39
    obj1 = JS_NewGlobalCConstructor(ctx, "BigFloat", js_bigfloat_constructor, 1,
52193
39
                                    ctx->class_proto[JS_CLASS_BIG_FLOAT]);
52194
39
    JS_SetPropertyFunctionList(ctx, obj1, js_bigfloat_funcs,
52195
39
                               countof(js_bigfloat_funcs));
52196
52197
39
    ctx->class_proto[JS_CLASS_FLOAT_ENV] = JS_NewObject(ctx);
52198
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FLOAT_ENV],
52199
39
                               js_float_env_proto_funcs,
52200
39
                               countof(js_float_env_proto_funcs));
52201
39
    obj1 = JS_NewGlobalCConstructorOnly(ctx, "BigFloatEnv",
52202
39
                                        js_float_env_constructor, 1,
52203
39
                                        ctx->class_proto[JS_CLASS_FLOAT_ENV]);
52204
39
    JS_SetPropertyFunctionList(ctx, obj1, js_float_env_funcs,
52205
39
                               countof(js_float_env_funcs));
52206
39
}
52207
52208
/* BigDecimal */
52209
52210
static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
52211
                                   BOOL allow_null_or_undefined)
52212
0
{
52213
0
 redo:
52214
0
    switch(JS_VALUE_GET_NORM_TAG(val)) {
52215
0
    case JS_TAG_BIG_DECIMAL:
52216
0
        break;
52217
0
    case JS_TAG_NULL:
52218
0
        if (!allow_null_or_undefined)
52219
0
            goto fail;
52220
        /* fall thru */
52221
0
    case JS_TAG_BOOL:
52222
0
    case JS_TAG_INT:
52223
0
        {
52224
0
            bfdec_t *r;
52225
0
            int32_t v = JS_VALUE_GET_INT(val);
52226
52227
0
            val = JS_NewBigDecimal(ctx);
52228
0
            if (JS_IsException(val))
52229
0
                break;
52230
0
            r = JS_GetBigDecimal(val);
52231
0
            if (bfdec_set_si(r, v)) {
52232
0
                JS_FreeValue(ctx, val);
52233
0
                val = JS_EXCEPTION;
52234
0
                break;
52235
0
            }
52236
0
        }
52237
0
        break;
52238
0
    case JS_TAG_FLOAT64:
52239
0
    case JS_TAG_BIG_INT:
52240
0
    case JS_TAG_BIG_FLOAT:
52241
0
        val = JS_ToStringFree(ctx, val);
52242
0
        if (JS_IsException(val))
52243
0
            break;
52244
0
        goto redo;
52245
0
    case JS_TAG_STRING:
52246
0
        {
52247
0
            const char *str, *p;
52248
0
            size_t len;
52249
0
            int err;
52250
52251
0
            str = JS_ToCStringLen(ctx, &len, val);
52252
0
            JS_FreeValue(ctx, val);
52253
0
            if (!str)
52254
0
                return JS_EXCEPTION;
52255
0
            p = str;
52256
0
            p += skip_spaces(p);
52257
0
            if ((p - str) == len) {
52258
0
                bfdec_t *r;
52259
0
                val = JS_NewBigDecimal(ctx);
52260
0
                if (JS_IsException(val))
52261
0
                    break;
52262
0
                r = JS_GetBigDecimal(val);
52263
0
                bfdec_set_zero(r, 0);
52264
0
                err = 0;
52265
0
            } else {
52266
0
                val = js_atof(ctx, p, &p, 0, ATOD_TYPE_BIG_DECIMAL);
52267
0
                if (JS_IsException(val)) {
52268
0
                    JS_FreeCString(ctx, str);
52269
0
                    return JS_EXCEPTION;
52270
0
                }
52271
0
                p += skip_spaces(p);
52272
0
                err = ((p - str) != len);
52273
0
            }
52274
0
            JS_FreeCString(ctx, str);
52275
0
            if (err) {
52276
0
                JS_FreeValue(ctx, val);
52277
0
                return JS_ThrowSyntaxError(ctx, "invalid bigdecimal literal");
52278
0
            }
52279
0
        }
52280
0
        break;
52281
0
    case JS_TAG_OBJECT:
52282
0
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
52283
0
        if (JS_IsException(val))
52284
0
            break;
52285
0
        goto redo;
52286
0
    case JS_TAG_UNDEFINED:
52287
0
        {
52288
0
            bfdec_t *r;
52289
0
            if (!allow_null_or_undefined)
52290
0
                goto fail;
52291
0
            val = JS_NewBigDecimal(ctx);
52292
0
            if (JS_IsException(val))
52293
0
                break;
52294
0
            r = JS_GetBigDecimal(val);
52295
0
            bfdec_set_nan(r);
52296
0
        }
52297
0
        break;
52298
0
    default:
52299
0
    fail:
52300
0
        JS_FreeValue(ctx, val);
52301
0
        return JS_ThrowTypeError(ctx, "cannot convert to bigdecimal");
52302
0
    }
52303
0
    return val;
52304
0
}
52305
52306
static JSValue js_bigdecimal_constructor(JSContext *ctx,
52307
                                         JSValueConst new_target,
52308
                                         int argc, JSValueConst *argv)
52309
0
{
52310
0
    JSValue val;
52311
0
    if (!JS_IsUndefined(new_target))
52312
0
        return JS_ThrowTypeError(ctx, "not a constructor");
52313
0
    if (argc == 0) {
52314
0
        bfdec_t *r;
52315
0
        val = JS_NewBigDecimal(ctx);
52316
0
        if (JS_IsException(val))
52317
0
            return val;
52318
0
        r = JS_GetBigDecimal(val);
52319
0
        bfdec_set_zero(r, 0);
52320
0
    } else {
52321
0
        val = JS_ToBigDecimalFree(ctx, JS_DupValue(ctx, argv[0]), FALSE);
52322
0
    }
52323
0
    return val;
52324
0
}
52325
52326
static JSValue js_thisBigDecimalValue(JSContext *ctx, JSValueConst this_val)
52327
0
{
52328
0
    if (JS_IsBigDecimal(this_val))
52329
0
        return JS_DupValue(ctx, this_val);
52330
52331
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
52332
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
52333
0
        if (p->class_id == JS_CLASS_BIG_DECIMAL) {
52334
0
            if (JS_IsBigDecimal(p->u.object_data))
52335
0
                return JS_DupValue(ctx, p->u.object_data);
52336
0
        }
52337
0
    }
52338
0
    return JS_ThrowTypeError(ctx, "not a bigdecimal");
52339
0
}
52340
52341
static JSValue js_bigdecimal_toString(JSContext *ctx, JSValueConst this_val,
52342
                                      int argc, JSValueConst *argv)
52343
0
{
52344
0
    JSValue val;
52345
52346
0
    val = js_thisBigDecimalValue(ctx, this_val);
52347
0
    if (JS_IsException(val))
52348
0
        return val;
52349
0
    return JS_ToStringFree(ctx, val);
52350
0
}
52351
52352
static JSValue js_bigdecimal_valueOf(JSContext *ctx, JSValueConst this_val,
52353
                                   int argc, JSValueConst *argv)
52354
0
{
52355
0
    return js_thisBigDecimalValue(ctx, this_val);
52356
0
}
52357
52358
static int js_bigdecimal_get_rnd_mode(JSContext *ctx, JSValueConst obj)
52359
0
{
52360
0
    const char *str;
52361
0
    size_t size;
52362
0
    int rnd_mode;
52363
52364
0
    str = JS_ToCStringLen(ctx, &size, obj);
52365
0
    if (!str)
52366
0
        return -1;
52367
0
    if (strlen(str) != size)
52368
0
        goto invalid_rounding_mode;
52369
0
    if (!strcmp(str, "floor")) {
52370
0
        rnd_mode = BF_RNDD;
52371
0
    } else if (!strcmp(str, "ceiling")) {
52372
0
        rnd_mode = BF_RNDU;
52373
0
    } else if (!strcmp(str, "down")) {
52374
0
        rnd_mode = BF_RNDZ;
52375
0
    } else if (!strcmp(str, "up")) {
52376
0
        rnd_mode = BF_RNDA;
52377
0
    } else if (!strcmp(str, "half-even")) {
52378
0
        rnd_mode = BF_RNDN;
52379
0
    } else if (!strcmp(str, "half-up")) {
52380
0
        rnd_mode = BF_RNDNA;
52381
0
    } else {
52382
0
    invalid_rounding_mode:
52383
0
        JS_FreeCString(ctx, str);
52384
0
        JS_ThrowTypeError(ctx, "invalid rounding mode");
52385
0
        return -1;
52386
0
    }
52387
0
    JS_FreeCString(ctx, str);
52388
0
    return rnd_mode;
52389
0
}
52390
52391
typedef struct {
52392
    int64_t prec;
52393
    bf_flags_t flags;
52394
} BigDecimalEnv;
52395
52396
static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe,
52397
                                 JSValueConst obj)
52398
0
{
52399
0
    JSValue prop;
52400
0
    int64_t val;
52401
0
    BOOL has_prec;
52402
0
    int rnd_mode;
52403
52404
0
    if (!JS_IsObject(obj)) {
52405
0
        JS_ThrowTypeErrorNotAnObject(ctx);
52406
0
        return -1;
52407
0
    }
52408
0
    prop = JS_GetProperty(ctx, obj, JS_ATOM_roundingMode);
52409
0
    if (JS_IsException(prop))
52410
0
        return -1;
52411
0
    rnd_mode = js_bigdecimal_get_rnd_mode(ctx, prop);
52412
0
    JS_FreeValue(ctx, prop);
52413
0
    if (rnd_mode < 0)
52414
0
        return -1;
52415
0
    fe->flags = rnd_mode;
52416
52417
0
    prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits);
52418
0
    if (JS_IsException(prop))
52419
0
        return -1;
52420
0
    has_prec = FALSE;
52421
0
    if (!JS_IsUndefined(prop)) {
52422
0
        if (JS_ToInt64SatFree(ctx, &val, prop))
52423
0
            return -1;
52424
0
        if (val < 1 || val > BF_PREC_MAX)
52425
0
            goto invalid_precision;
52426
0
        fe->prec = val;
52427
0
        has_prec = TRUE;
52428
0
    }
52429
52430
0
    prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumFractionDigits);
52431
0
    if (JS_IsException(prop))
52432
0
        return -1;
52433
0
    if (!JS_IsUndefined(prop)) {
52434
0
        if (has_prec) {
52435
0
            JS_FreeValue(ctx, prop);
52436
0
            JS_ThrowTypeError(ctx, "cannot provide both maximumSignificantDigits and maximumFractionDigits");
52437
0
            return -1;
52438
0
        }
52439
0
        if (JS_ToInt64SatFree(ctx, &val, prop))
52440
0
            return -1;
52441
0
        if (val < 0 || val > BF_PREC_MAX) {
52442
0
        invalid_precision:
52443
0
            JS_ThrowTypeError(ctx, "invalid precision");
52444
0
            return -1;
52445
0
        }
52446
0
        fe->prec = val;
52447
0
        fe->flags |= BF_FLAG_RADPNT_PREC;
52448
0
        has_prec = TRUE;
52449
0
    }
52450
0
    if (!has_prec) {
52451
0
        JS_ThrowTypeError(ctx, "precision must be present");
52452
0
        return -1;
52453
0
    }
52454
0
    return 0;
52455
0
}
52456
52457
52458
static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val,
52459
                                 int argc, JSValueConst *argv, int magic)
52460
0
{
52461
0
    bfdec_t *a, *b, r_s, *r = &r_s;
52462
0
    JSValue op1, op2, res;
52463
0
    BigDecimalEnv fe_s, *fe = &fe_s;
52464
0
    int op_count, ret;
52465
52466
0
    if (magic == MATH_OP_SQRT ||
52467
0
        magic == MATH_OP_ROUND)
52468
0
        op_count = 1;
52469
0
    else
52470
0
        op_count = 2;
52471
52472
0
    op1 = JS_ToNumeric(ctx, argv[0]);
52473
0
    if (JS_IsException(op1))
52474
0
        return op1;
52475
0
    a = JS_ToBigDecimal(ctx, op1);
52476
0
    if (!a) {
52477
0
        JS_FreeValue(ctx, op1);
52478
0
        return JS_EXCEPTION;
52479
0
    }
52480
0
    if (op_count >= 2) {
52481
0
        op2 = JS_ToNumeric(ctx, argv[1]);
52482
0
        if (JS_IsException(op2)) {
52483
0
            JS_FreeValue(ctx, op1);
52484
0
            return op2;
52485
0
        }
52486
0
        b = JS_ToBigDecimal(ctx, op2);
52487
0
        if (!b)
52488
0
            goto fail;
52489
0
    } else {
52490
0
        op2 = JS_UNDEFINED;
52491
0
        b = NULL;
52492
0
    }
52493
0
    fe->flags = BF_RNDZ;
52494
0
    fe->prec = BF_PREC_INF;
52495
0
    if (op_count < argc) {
52496
0
        if (js_bigdecimal_get_env(ctx, fe, argv[op_count]))
52497
0
            goto fail;
52498
0
    }
52499
52500
0
    res = JS_NewBigDecimal(ctx);
52501
0
    if (JS_IsException(res)) {
52502
0
    fail:
52503
0
        JS_FreeValue(ctx, op1);
52504
0
        JS_FreeValue(ctx, op2);
52505
0
        return JS_EXCEPTION;
52506
0
    }
52507
0
    r = JS_GetBigDecimal(res);
52508
0
    switch (magic) {
52509
0
    case MATH_OP_ADD:
52510
0
        ret = bfdec_add(r, a, b, fe->prec, fe->flags);
52511
0
        break;
52512
0
    case MATH_OP_SUB:
52513
0
        ret = bfdec_sub(r, a, b, fe->prec, fe->flags);
52514
0
        break;
52515
0
    case MATH_OP_MUL:
52516
0
        ret = bfdec_mul(r, a, b, fe->prec, fe->flags);
52517
0
        break;
52518
0
    case MATH_OP_DIV:
52519
0
        ret = bfdec_div(r, a, b, fe->prec, fe->flags);
52520
0
        break;
52521
0
    case MATH_OP_FMOD:
52522
0
        ret = bfdec_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
52523
0
        break;
52524
0
    case MATH_OP_SQRT:
52525
0
        ret = bfdec_sqrt(r, a, fe->prec, fe->flags);
52526
0
        break;
52527
0
    case MATH_OP_ROUND:
52528
0
        ret = bfdec_set(r, a);
52529
0
        if (!(ret & BF_ST_MEM_ERROR))
52530
0
            ret = bfdec_round(r, fe->prec, fe->flags);
52531
0
        break;
52532
0
    default:
52533
0
        abort();
52534
0
    }
52535
0
    JS_FreeValue(ctx, op1);
52536
0
    JS_FreeValue(ctx, op2);
52537
0
    ret &= BF_ST_MEM_ERROR | BF_ST_DIVIDE_ZERO | BF_ST_INVALID_OP |
52538
0
        BF_ST_OVERFLOW;
52539
0
    if (ret != 0) {
52540
0
        JS_FreeValue(ctx, res);
52541
0
        return throw_bf_exception(ctx, ret);
52542
0
    } else {
52543
0
        return res;
52544
0
    }
52545
0
}
52546
52547
static JSValue js_bigdecimal_toFixed(JSContext *ctx, JSValueConst this_val,
52548
                                 int argc, JSValueConst *argv)
52549
0
{
52550
0
    JSValue val, ret;
52551
0
    int64_t f;
52552
0
    int rnd_mode;
52553
52554
0
    val = js_thisBigDecimalValue(ctx, this_val);
52555
0
    if (JS_IsException(val))
52556
0
        return val;
52557
0
    if (JS_ToInt64Sat(ctx, &f, argv[0]))
52558
0
        goto fail;
52559
0
    if (f < 0 || f > BF_PREC_MAX) {
52560
0
        JS_ThrowRangeError(ctx, "invalid number of digits");
52561
0
        goto fail;
52562
0
    }
52563
0
    rnd_mode = BF_RNDNA;
52564
0
    if (argc > 1) {
52565
0
        rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
52566
0
        if (rnd_mode < 0)
52567
0
            goto fail;
52568
0
    }
52569
0
    ret = js_bigdecimal_to_string1(ctx, val, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
52570
0
    JS_FreeValue(ctx, val);
52571
0
    return ret;
52572
0
 fail:
52573
0
    JS_FreeValue(ctx, val);
52574
0
    return JS_EXCEPTION;
52575
0
}
52576
52577
static JSValue js_bigdecimal_toExponential(JSContext *ctx, JSValueConst this_val,
52578
                                       int argc, JSValueConst *argv)
52579
0
{
52580
0
    JSValue val, ret;
52581
0
    int64_t f;
52582
0
    int rnd_mode;
52583
52584
0
    val = js_thisBigDecimalValue(ctx, this_val);
52585
0
    if (JS_IsException(val))
52586
0
        return val;
52587
0
    if (JS_ToInt64Sat(ctx, &f, argv[0]))
52588
0
        goto fail;
52589
0
    if (JS_IsUndefined(argv[0])) {
52590
0
        ret = js_bigdecimal_to_string1(ctx, val, 0,
52591
0
                  BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
52592
0
    } else {
52593
0
        if (f < 0 || f > BF_PREC_MAX) {
52594
0
            JS_ThrowRangeError(ctx, "invalid number of digits");
52595
0
            goto fail;
52596
0
        }
52597
0
        rnd_mode = BF_RNDNA;
52598
0
        if (argc > 1) {
52599
0
            rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
52600
0
            if (rnd_mode < 0)
52601
0
                goto fail;
52602
0
        }
52603
0
        ret = js_bigdecimal_to_string1(ctx, val, f + 1,
52604
0
                      rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
52605
0
    }
52606
0
    JS_FreeValue(ctx, val);
52607
0
    return ret;
52608
0
 fail:
52609
0
    JS_FreeValue(ctx, val);
52610
0
    return JS_EXCEPTION;
52611
0
}
52612
52613
static JSValue js_bigdecimal_toPrecision(JSContext *ctx, JSValueConst this_val,
52614
                                     int argc, JSValueConst *argv)
52615
0
{
52616
0
    JSValue val, ret;
52617
0
    int64_t p;
52618
0
    int rnd_mode;
52619
52620
0
    val = js_thisBigDecimalValue(ctx, this_val);
52621
0
    if (JS_IsException(val))
52622
0
        return val;
52623
0
    if (JS_IsUndefined(argv[0])) {
52624
0
        return JS_ToStringFree(ctx, val);
52625
0
    }
52626
0
    if (JS_ToInt64Sat(ctx, &p, argv[0]))
52627
0
        goto fail;
52628
0
    if (p < 1 || p > BF_PREC_MAX) {
52629
0
        JS_ThrowRangeError(ctx, "invalid number of digits");
52630
0
        goto fail;
52631
0
    }
52632
0
    rnd_mode = BF_RNDNA;
52633
0
    if (argc > 1) {
52634
0
        rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
52635
0
        if (rnd_mode < 0)
52636
0
            goto fail;
52637
0
    }
52638
0
    ret = js_bigdecimal_to_string1(ctx, val, p,
52639
0
                                   rnd_mode | BF_FTOA_FORMAT_FIXED);
52640
0
    JS_FreeValue(ctx, val);
52641
0
    return ret;
52642
0
 fail:
52643
0
    JS_FreeValue(ctx, val);
52644
0
    return JS_EXCEPTION;
52645
0
}
52646
52647
static const JSCFunctionListEntry js_bigdecimal_proto_funcs[] = {
52648
    JS_CFUNC_DEF("toString", 0, js_bigdecimal_toString ),
52649
    JS_CFUNC_DEF("valueOf", 0, js_bigdecimal_valueOf ),
52650
    JS_CFUNC_DEF("toPrecision", 1, js_bigdecimal_toPrecision ),
52651
    JS_CFUNC_DEF("toFixed", 1, js_bigdecimal_toFixed ),
52652
    JS_CFUNC_DEF("toExponential", 1, js_bigdecimal_toExponential ),
52653
};
52654
52655
static const JSCFunctionListEntry js_bigdecimal_funcs[] = {
52656
    JS_CFUNC_MAGIC_DEF("add", 2, js_bigdecimal_fop, MATH_OP_ADD ),
52657
    JS_CFUNC_MAGIC_DEF("sub", 2, js_bigdecimal_fop, MATH_OP_SUB ),
52658
    JS_CFUNC_MAGIC_DEF("mul", 2, js_bigdecimal_fop, MATH_OP_MUL ),
52659
    JS_CFUNC_MAGIC_DEF("div", 2, js_bigdecimal_fop, MATH_OP_DIV ),
52660
    JS_CFUNC_MAGIC_DEF("mod", 2, js_bigdecimal_fop, MATH_OP_FMOD ),
52661
    JS_CFUNC_MAGIC_DEF("round", 1, js_bigdecimal_fop, MATH_OP_ROUND ),
52662
    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigdecimal_fop, MATH_OP_SQRT ),
52663
};
52664
52665
void JS_AddIntrinsicBigDecimal(JSContext *ctx)
52666
39
{
52667
39
    JSRuntime *rt = ctx->rt;
52668
39
    JSValueConst obj1;
52669
52670
39
    rt->bigdecimal_ops.to_string = js_bigdecimal_to_string;
52671
39
    rt->bigdecimal_ops.from_string = js_string_to_bigdecimal;
52672
39
    rt->bigdecimal_ops.unary_arith = js_unary_arith_bigdecimal;
52673
39
    rt->bigdecimal_ops.binary_arith = js_binary_arith_bigdecimal;
52674
39
    rt->bigdecimal_ops.compare = js_compare_bigdecimal;
52675
52676
39
    ctx->class_proto[JS_CLASS_BIG_DECIMAL] = JS_NewObject(ctx);
52677
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL],
52678
39
                               js_bigdecimal_proto_funcs,
52679
39
                               countof(js_bigdecimal_proto_funcs));
52680
39
    obj1 = JS_NewGlobalCConstructor(ctx, "BigDecimal",
52681
39
                                    js_bigdecimal_constructor, 1,
52682
39
                                    ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
52683
39
    JS_SetPropertyFunctionList(ctx, obj1, js_bigdecimal_funcs,
52684
39
                               countof(js_bigdecimal_funcs));
52685
39
}
52686
52687
void JS_EnableBignumExt(JSContext *ctx, BOOL enable)
52688
39
{
52689
39
    ctx->bignum_ext = enable;
52690
39
}
52691
52692
#endif /* CONFIG_BIGNUM */
52693
52694
static const char * const native_error_name[JS_NATIVE_ERROR_COUNT] = {
52695
    "EvalError", "RangeError", "ReferenceError",
52696
    "SyntaxError", "TypeError", "URIError",
52697
    "InternalError", "AggregateError",
52698
};
52699
52700
/* Minimum amount of objects to be able to compile code and display
52701
   error messages. No JSAtom should be allocated by this function. */
52702
static void JS_AddIntrinsicBasicObjects(JSContext *ctx)
52703
39
{
52704
39
    JSValue proto;
52705
39
    int i;
52706
52707
39
    ctx->class_proto[JS_CLASS_OBJECT] = JS_NewObjectProto(ctx, JS_NULL);
52708
39
    ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, "", 0,
52709
39
                                           JS_CFUNC_generic, 0,
52710
39
                                           ctx->class_proto[JS_CLASS_OBJECT]);
52711
39
    ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = JS_DupValue(ctx, ctx->function_proto);
52712
39
    ctx->class_proto[JS_CLASS_ERROR] = JS_NewObject(ctx);
52713
#if 0
52714
    /* these are auto-initialized from js_error_proto_funcs,
52715
       but delaying might be a problem */
52716
    JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_name,
52717
                           JS_AtomToString(ctx, JS_ATOM_Error),
52718
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
52719
    JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_message,
52720
                           JS_AtomToString(ctx, JS_ATOM_empty_string),
52721
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
52722
#endif
52723
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ERROR],
52724
39
                               js_error_proto_funcs,
52725
39
                               countof(js_error_proto_funcs));
52726
52727
351
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
52728
312
        proto = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ERROR]);
52729
312
        JS_DefinePropertyValue(ctx, proto, JS_ATOM_name,
52730
312
                               JS_NewAtomString(ctx, native_error_name[i]),
52731
312
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
52732
312
        JS_DefinePropertyValue(ctx, proto, JS_ATOM_message,
52733
312
                               JS_AtomToString(ctx, JS_ATOM_empty_string),
52734
312
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
52735
312
        ctx->native_error_proto[i] = proto;
52736
312
    }
52737
52738
    /* the array prototype is an array */
52739
39
    ctx->class_proto[JS_CLASS_ARRAY] =
52740
39
        JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
52741
39
                               JS_CLASS_ARRAY);
52742
52743
39
    ctx->array_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]),
52744
39
                                     JS_PROP_INITIAL_HASH_SIZE, 1);
52745
39
    add_shape_property(ctx, &ctx->array_shape, NULL,
52746
39
                       JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH);
52747
52748
    /* XXX: could test it on first context creation to ensure that no
52749
       new atoms are created in JS_AddIntrinsicBasicObjects(). It is
52750
       necessary to avoid useless renumbering of atoms after
52751
       JS_EvalBinary() if it is done just after
52752
       JS_AddIntrinsicBasicObjects(). */
52753
    //    assert(ctx->rt->atom_count == JS_ATOM_END);
52754
39
}
52755
52756
void JS_AddIntrinsicBaseObjects(JSContext *ctx)
52757
39
{
52758
39
    int i;
52759
39
    JSValueConst obj, number_obj;
52760
39
    JSValue obj1;
52761
52762
39
    ctx->throw_type_error = JS_NewCFunction(ctx, js_throw_type_error, NULL, 0);
52763
52764
    /* add caller and arguments properties to throw a TypeError */
52765
39
    obj1 = JS_NewCFunction(ctx, js_function_proto_caller, NULL, 0);
52766
39
    JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_caller, JS_UNDEFINED,
52767
39
                      obj1, ctx->throw_type_error,
52768
39
                      JS_PROP_HAS_GET | JS_PROP_HAS_SET |
52769
39
                      JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
52770
39
    JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_arguments, JS_UNDEFINED,
52771
39
                      obj1, ctx->throw_type_error,
52772
39
                      JS_PROP_HAS_GET | JS_PROP_HAS_SET |
52773
39
                      JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
52774
39
    JS_FreeValue(ctx, obj1);
52775
39
    JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, (JSValueConst *)&ctx->throw_type_error, 1));
52776
52777
39
    ctx->global_obj = JS_NewObject(ctx);
52778
39
    ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL);
52779
52780
    /* Object */
52781
39
    obj = JS_NewGlobalCConstructor(ctx, "Object", js_object_constructor, 1,
52782
39
                                   ctx->class_proto[JS_CLASS_OBJECT]);
52783
39
    JS_SetPropertyFunctionList(ctx, obj, js_object_funcs, countof(js_object_funcs));
52784
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_OBJECT],
52785
39
                               js_object_proto_funcs, countof(js_object_proto_funcs));
52786
52787
    /* Function */
52788
39
    JS_SetPropertyFunctionList(ctx, ctx->function_proto, js_function_proto_funcs, countof(js_function_proto_funcs));
52789
39
    ctx->function_ctor = JS_NewCFunctionMagic(ctx, js_function_constructor,
52790
39
                                              "Function", 1, JS_CFUNC_constructor_or_func_magic,
52791
39
                                              JS_FUNC_NORMAL);
52792
39
    JS_NewGlobalCConstructor2(ctx, JS_DupValue(ctx, ctx->function_ctor), "Function",
52793
39
                              ctx->function_proto);
52794
52795
    /* Error */
52796
39
    obj1 = JS_NewCFunctionMagic(ctx, js_error_constructor,
52797
39
                                "Error", 1, JS_CFUNC_constructor_or_func_magic, -1);
52798
39
    JS_NewGlobalCConstructor2(ctx, obj1,
52799
39
                              "Error", ctx->class_proto[JS_CLASS_ERROR]);
52800
52801
    /* Used to squelch a -Wcast-function-type warning. */
52802
39
    JSCFunctionType ft = { .generic_magic = js_error_constructor };
52803
351
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
52804
312
        JSValue func_obj;
52805
312
        int n_args;
52806
312
        n_args = 1 + (i == JS_AGGREGATE_ERROR);
52807
312
        func_obj = JS_NewCFunction3(ctx, ft.generic,
52808
312
                                    native_error_name[i], n_args,
52809
312
                                    JS_CFUNC_constructor_or_func_magic, i, obj1);
52810
312
        JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i],
52811
312
                                  ctx->native_error_proto[i]);
52812
312
    }
52813
52814
    /* Iterator prototype */
52815
39
    ctx->iterator_proto = JS_NewObject(ctx);
52816
39
    JS_SetPropertyFunctionList(ctx, ctx->iterator_proto,
52817
39
                               js_iterator_proto_funcs,
52818
39
                               countof(js_iterator_proto_funcs));
52819
52820
    /* Array */
52821
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY],
52822
39
                               js_array_proto_funcs,
52823
39
                               countof(js_array_proto_funcs));
52824
52825
39
    obj = JS_NewGlobalCConstructor(ctx, "Array", js_array_constructor, 1,
52826
39
                                   ctx->class_proto[JS_CLASS_ARRAY]);
52827
39
    ctx->array_ctor = JS_DupValue(ctx, obj);
52828
39
    JS_SetPropertyFunctionList(ctx, obj, js_array_funcs,
52829
39
                               countof(js_array_funcs));
52830
52831
    /* XXX: create auto_initializer */
52832
39
    {
52833
        /* initialize Array.prototype[Symbol.unscopables] */
52834
39
        static const char unscopables[] =
52835
39
            "copyWithin" "\0"
52836
39
            "entries" "\0"
52837
39
            "fill" "\0"
52838
39
            "find" "\0"
52839
39
            "findIndex" "\0"
52840
39
            "findLast" "\0"
52841
39
            "findLastIndex" "\0"
52842
39
            "flat" "\0"
52843
39
            "flatMap" "\0"
52844
39
            "includes" "\0"
52845
39
            "keys" "\0"
52846
39
            "toReversed" "\0"
52847
39
            "toSorted" "\0"
52848
39
            "toSpliced" "\0"
52849
39
            "values" "\0";
52850
39
        const char *p = unscopables;
52851
39
        obj1 = JS_NewObjectProto(ctx, JS_NULL);
52852
624
        for(p = unscopables; *p; p += strlen(p) + 1) {
52853
585
            JS_DefinePropertyValueStr(ctx, obj1, p, JS_TRUE, JS_PROP_C_W_E);
52854
585
        }
52855
39
        JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ARRAY],
52856
39
                               JS_ATOM_Symbol_unscopables, obj1,
52857
39
                               JS_PROP_CONFIGURABLE);
52858
39
    }
52859
52860
    /* needed to initialize arguments[Symbol.iterator] */
52861
39
    ctx->array_proto_values =
52862
39
        JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_values);
52863
52864
39
    ctx->class_proto[JS_CLASS_ARRAY_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
52865
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_ITERATOR],
52866
39
                               js_array_iterator_proto_funcs,
52867
39
                               countof(js_array_iterator_proto_funcs));
52868
52869
    /* parseFloat and parseInteger must be defined before Number
52870
       because of the Number.parseFloat and Number.parseInteger
52871
       aliases */
52872
39
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_global_funcs,
52873
39
                               countof(js_global_funcs));
52874
52875
    /* Number */
52876
39
    ctx->class_proto[JS_CLASS_NUMBER] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
52877
39
                                                               JS_CLASS_NUMBER);
52878
39
    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_NUMBER], JS_NewInt32(ctx, 0));
52879
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_NUMBER],
52880
39
                               js_number_proto_funcs,
52881
39
                               countof(js_number_proto_funcs));
52882
39
    number_obj = JS_NewGlobalCConstructor(ctx, "Number", js_number_constructor, 1,
52883
39
                                          ctx->class_proto[JS_CLASS_NUMBER]);
52884
39
    JS_SetPropertyFunctionList(ctx, number_obj, js_number_funcs, countof(js_number_funcs));
52885
52886
    /* Boolean */
52887
39
    ctx->class_proto[JS_CLASS_BOOLEAN] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
52888
39
                                                                JS_CLASS_BOOLEAN);
52889
39
    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], JS_NewBool(ctx, FALSE));
52890
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], js_boolean_proto_funcs,
52891
39
                               countof(js_boolean_proto_funcs));
52892
39
    JS_NewGlobalCConstructor(ctx, "Boolean", js_boolean_constructor, 1,
52893
39
                             ctx->class_proto[JS_CLASS_BOOLEAN]);
52894
52895
    /* String */
52896
39
    ctx->class_proto[JS_CLASS_STRING] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
52897
39
                                                               JS_CLASS_STRING);
52898
39
    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_STRING], JS_AtomToString(ctx, JS_ATOM_empty_string));
52899
39
    obj = JS_NewGlobalCConstructor(ctx, "String", js_string_constructor, 1,
52900
39
                                   ctx->class_proto[JS_CLASS_STRING]);
52901
39
    JS_SetPropertyFunctionList(ctx, obj, js_string_funcs,
52902
39
                               countof(js_string_funcs));
52903
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_funcs,
52904
39
                               countof(js_string_proto_funcs));
52905
52906
39
    ctx->class_proto[JS_CLASS_STRING_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
52907
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING_ITERATOR],
52908
39
                               js_string_iterator_proto_funcs,
52909
39
                               countof(js_string_iterator_proto_funcs));
52910
52911
    /* Math: create as autoinit object */
52912
39
    js_random_init(ctx);
52913
39
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_math_obj, countof(js_math_obj));
52914
52915
    /* ES6 Reflect: create as autoinit object */
52916
39
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_reflect_obj, countof(js_reflect_obj));
52917
52918
    /* ES6 Symbol */
52919
39
    ctx->class_proto[JS_CLASS_SYMBOL] = JS_NewObject(ctx);
52920
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SYMBOL], js_symbol_proto_funcs,
52921
39
                               countof(js_symbol_proto_funcs));
52922
39
    obj = JS_NewGlobalCConstructor(ctx, "Symbol", js_symbol_constructor, 0,
52923
39
                                   ctx->class_proto[JS_CLASS_SYMBOL]);
52924
39
    JS_SetPropertyFunctionList(ctx, obj, js_symbol_funcs,
52925
39
                               countof(js_symbol_funcs));
52926
585
    for(i = JS_ATOM_Symbol_toPrimitive; i < JS_ATOM_END; i++) {
52927
546
        char buf[ATOM_GET_STR_BUF_SIZE];
52928
546
        const char *str, *p;
52929
546
        str = JS_AtomGetStr(ctx, buf, sizeof(buf), i);
52930
        /* skip "Symbol." */
52931
546
        p = strchr(str, '.');
52932
546
        if (p)
52933
546
            str = p + 1;
52934
546
        JS_DefinePropertyValueStr(ctx, obj, str, JS_AtomToValue(ctx, i), 0);
52935
546
    }
52936
52937
    /* ES6 Generator */
52938
39
    ctx->class_proto[JS_CLASS_GENERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
52939
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_GENERATOR],
52940
39
                               js_generator_proto_funcs,
52941
39
                               countof(js_generator_proto_funcs));
52942
52943
39
    ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
52944
39
    obj1 = JS_NewCFunctionMagic(ctx, js_function_constructor,
52945
39
                                "GeneratorFunction", 1,
52946
39
                                JS_CFUNC_constructor_or_func_magic, JS_FUNC_GENERATOR);
52947
39
    JS_SetPropertyFunctionList(ctx,
52948
39
                               ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
52949
39
                               js_generator_function_proto_funcs,
52950
39
                               countof(js_generator_function_proto_funcs));
52951
39
    JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
52952
39
                       ctx->class_proto[JS_CLASS_GENERATOR],
52953
39
                       JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
52954
39
    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
52955
39
                       0, JS_PROP_CONFIGURABLE);
52956
39
    JS_FreeValue(ctx, obj1);
52957
52958
    /* global properties */
52959
39
    ctx->eval_obj = JS_NewCFunction(ctx, js_global_eval, "eval", 1);
52960
39
    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_eval,
52961
39
                           JS_DupValue(ctx, ctx->eval_obj),
52962
39
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
52963
52964
39
    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_globalThis,
52965
39
                           JS_DupValue(ctx, ctx->global_obj),
52966
39
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
52967
39
}
52968
52969
/* Typed Arrays */
52970
52971
static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = {
52972
    0, 0, 0, 1, 1, 2, 2,
52973
    3, 3, /* BigInt64Array, BigUint64Array */
52974
    2, 3
52975
};
52976
52977
static JSValue js_array_buffer_constructor3(JSContext *ctx,
52978
                                            JSValueConst new_target,
52979
                                            uint64_t len, JSClassID class_id,
52980
                                            uint8_t *buf,
52981
                                            JSFreeArrayBufferDataFunc *free_func,
52982
                                            void *opaque, BOOL alloc_flag)
52983
0
{
52984
0
    JSRuntime *rt = ctx->rt;
52985
0
    JSValue obj;
52986
0
    JSArrayBuffer *abuf = NULL;
52987
52988
0
    obj = js_create_from_ctor(ctx, new_target, class_id);
52989
0
    if (JS_IsException(obj))
52990
0
        return obj;
52991
    /* XXX: we are currently limited to 2 GB */
52992
0
    if (len > INT32_MAX) {
52993
0
        JS_ThrowRangeError(ctx, "invalid array buffer length");
52994
0
        goto fail;
52995
0
    }
52996
0
    abuf = js_malloc(ctx, sizeof(*abuf));
52997
0
    if (!abuf)
52998
0
        goto fail;
52999
0
    abuf->byte_length = len;
53000
0
    if (alloc_flag) {
53001
0
        if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
53002
0
            rt->sab_funcs.sab_alloc) {
53003
0
            abuf->data = rt->sab_funcs.sab_alloc(rt->sab_funcs.sab_opaque,
53004
0
                                                 max_int(len, 1));
53005
0
            if (!abuf->data)
53006
0
                goto fail;
53007
0
            memset(abuf->data, 0, len);
53008
0
        } else {
53009
            /* the allocation must be done after the object creation */
53010
0
            abuf->data = js_mallocz(ctx, max_int(len, 1));
53011
0
            if (!abuf->data)
53012
0
                goto fail;
53013
0
        }
53014
0
    } else {
53015
0
        if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
53016
0
            rt->sab_funcs.sab_dup) {
53017
0
            rt->sab_funcs.sab_dup(rt->sab_funcs.sab_opaque, buf);
53018
0
        }
53019
0
        abuf->data = buf;
53020
0
    }
53021
0
    init_list_head(&abuf->array_list);
53022
0
    abuf->detached = FALSE;
53023
0
    abuf->shared = (class_id == JS_CLASS_SHARED_ARRAY_BUFFER);
53024
0
    abuf->opaque = opaque;
53025
0
    abuf->free_func = free_func;
53026
0
    if (alloc_flag && buf)
53027
0
        memcpy(abuf->data, buf, len);
53028
0
    JS_SetOpaque(obj, abuf);
53029
0
    return obj;
53030
0
 fail:
53031
0
    JS_FreeValue(ctx, obj);
53032
0
    js_free(ctx, abuf);
53033
0
    return JS_EXCEPTION;
53034
0
}
53035
53036
static void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr)
53037
0
{
53038
0
    js_free_rt(rt, ptr);
53039
0
}
53040
53041
static JSValue js_array_buffer_constructor2(JSContext *ctx,
53042
                                            JSValueConst new_target,
53043
                                            uint64_t len, JSClassID class_id)
53044
0
{
53045
0
    return js_array_buffer_constructor3(ctx, new_target, len, class_id,
53046
0
                                        NULL, js_array_buffer_free, NULL,
53047
0
                                        TRUE);
53048
0
}
53049
53050
static JSValue js_array_buffer_constructor1(JSContext *ctx,
53051
                                            JSValueConst new_target,
53052
                                            uint64_t len)
53053
0
{
53054
0
    return js_array_buffer_constructor2(ctx, new_target, len,
53055
0
                                        JS_CLASS_ARRAY_BUFFER);
53056
0
}
53057
53058
JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
53059
                          JSFreeArrayBufferDataFunc *free_func, void *opaque,
53060
                          BOOL is_shared)
53061
0
{
53062
0
    return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len,
53063
0
                                        is_shared ? JS_CLASS_SHARED_ARRAY_BUFFER : JS_CLASS_ARRAY_BUFFER,
53064
0
                                        buf, free_func, opaque, FALSE);
53065
0
}
53066
53067
/* create a new ArrayBuffer of length 'len' and copy 'buf' to it */
53068
JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len)
53069
0
{
53070
0
    return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len,
53071
0
                                        JS_CLASS_ARRAY_BUFFER,
53072
0
                                        (uint8_t *)buf,
53073
0
                                        js_array_buffer_free, NULL,
53074
0
                                        TRUE);
53075
0
}
53076
53077
static JSValue js_array_buffer_constructor(JSContext *ctx,
53078
                                           JSValueConst new_target,
53079
                                           int argc, JSValueConst *argv)
53080
0
{
53081
0
    uint64_t len;
53082
0
    if (JS_ToIndex(ctx, &len, argv[0]))
53083
0
        return JS_EXCEPTION;
53084
0
    return js_array_buffer_constructor1(ctx, new_target, len);
53085
0
}
53086
53087
static JSValue js_shared_array_buffer_constructor(JSContext *ctx,
53088
                                                  JSValueConst new_target,
53089
                                                  int argc, JSValueConst *argv)
53090
0
{
53091
0
    uint64_t len;
53092
0
    if (JS_ToIndex(ctx, &len, argv[0]))
53093
0
        return JS_EXCEPTION;
53094
0
    return js_array_buffer_constructor2(ctx, new_target, len,
53095
0
                                        JS_CLASS_SHARED_ARRAY_BUFFER);
53096
0
}
53097
53098
/* also used for SharedArrayBuffer */
53099
static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val)
53100
0
{
53101
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
53102
0
    JSArrayBuffer *abuf = p->u.array_buffer;
53103
0
    struct list_head *el, *el1;
53104
53105
0
    if (abuf) {
53106
        /* The ArrayBuffer finalizer may be called before the typed
53107
           array finalizers using it, so abuf->array_list is not
53108
           necessarily empty. */
53109
0
        list_for_each_safe(el, el1, &abuf->array_list) {
53110
0
            JSTypedArray *ta;
53111
0
            JSObject *p1;
53112
53113
0
            ta = list_entry(el, JSTypedArray, link);
53114
0
            ta->link.prev = NULL;
53115
0
            ta->link.next = NULL;
53116
0
            p1 = ta->obj;
53117
            /* Note: the typed array length and offset fields are not modified */
53118
0
            if (p1->class_id != JS_CLASS_DATAVIEW) {
53119
0
                p1->u.array.count = 0;
53120
0
                p1->u.array.u.ptr = NULL;
53121
0
            }
53122
0
        }
53123
0
        if (abuf->shared && rt->sab_funcs.sab_free) {
53124
0
            rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data);
53125
0
        } else {
53126
0
            if (abuf->free_func)
53127
0
                abuf->free_func(rt, abuf->opaque, abuf->data);
53128
0
        }
53129
0
        js_free_rt(rt, abuf);
53130
0
    }
53131
0
}
53132
53133
static JSValue js_array_buffer_isView(JSContext *ctx,
53134
                                      JSValueConst this_val,
53135
                                      int argc, JSValueConst *argv)
53136
0
{
53137
0
    JSObject *p;
53138
0
    BOOL res;
53139
0
    res = FALSE;
53140
0
    if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
53141
0
        p = JS_VALUE_GET_OBJ(argv[0]);
53142
0
        if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
53143
0
            p->class_id <= JS_CLASS_DATAVIEW) {
53144
0
            res = TRUE;
53145
0
        }
53146
0
    }
53147
0
    return JS_NewBool(ctx, res);
53148
0
}
53149
53150
static const JSCFunctionListEntry js_array_buffer_funcs[] = {
53151
    JS_CFUNC_DEF("isView", 1, js_array_buffer_isView ),
53152
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
53153
};
53154
53155
static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx)
53156
0
{
53157
0
    return JS_ThrowTypeError(ctx, "ArrayBuffer is detached");
53158
0
}
53159
53160
static JSValue js_array_buffer_get_byteLength(JSContext *ctx,
53161
                                              JSValueConst this_val,
53162
                                              int class_id)
53163
0
{
53164
0
    JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);
53165
0
    if (!abuf)
53166
0
        return JS_EXCEPTION;
53167
    /* return 0 if detached */
53168
0
    return JS_NewUint32(ctx, abuf->byte_length);
53169
0
}
53170
53171
void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
53172
0
{
53173
0
    JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);
53174
0
    struct list_head *el;
53175
53176
0
    if (!abuf || abuf->detached)
53177
0
        return;
53178
0
    if (abuf->free_func)
53179
0
        abuf->free_func(ctx->rt, abuf->opaque, abuf->data);
53180
0
    abuf->data = NULL;
53181
0
    abuf->byte_length = 0;
53182
0
    abuf->detached = TRUE;
53183
53184
0
    list_for_each(el, &abuf->array_list) {
53185
0
        JSTypedArray *ta;
53186
0
        JSObject *p;
53187
53188
0
        ta = list_entry(el, JSTypedArray, link);
53189
0
        p = ta->obj;
53190
        /* Note: the typed array length and offset fields are not modified */
53191
0
        if (p->class_id != JS_CLASS_DATAVIEW) {
53192
0
            p->u.array.count = 0;
53193
0
            p->u.array.u.ptr = NULL;
53194
0
        }
53195
0
    }
53196
0
}
53197
53198
/* get an ArrayBuffer or SharedArrayBuffer */
53199
static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj)
53200
0
{
53201
0
    JSObject *p;
53202
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
53203
0
        goto fail;
53204
0
    p = JS_VALUE_GET_OBJ(obj);
53205
0
    if (p->class_id != JS_CLASS_ARRAY_BUFFER &&
53206
0
        p->class_id != JS_CLASS_SHARED_ARRAY_BUFFER) {
53207
0
    fail:
53208
0
        JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_ARRAY_BUFFER);
53209
0
        return NULL;
53210
0
    }
53211
0
    return p->u.array_buffer;
53212
0
}
53213
53214
/* return NULL if exception. WARNING: any JS call can detach the
53215
   buffer and render the returned pointer invalid */
53216
uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj)
53217
0
{
53218
0
    JSArrayBuffer *abuf = js_get_array_buffer(ctx, obj);
53219
0
    if (!abuf)
53220
0
        goto fail;
53221
0
    if (abuf->detached) {
53222
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53223
0
        goto fail;
53224
0
    }
53225
0
    *psize = abuf->byte_length;
53226
0
    return abuf->data;
53227
0
 fail:
53228
0
    *psize = 0;
53229
0
    return NULL;
53230
0
}
53231
53232
static JSValue js_array_buffer_slice(JSContext *ctx,
53233
                                     JSValueConst this_val,
53234
                                     int argc, JSValueConst *argv, int class_id)
53235
0
{
53236
0
    JSArrayBuffer *abuf, *new_abuf;
53237
0
    int64_t len, start, end, new_len;
53238
0
    JSValue ctor, new_obj;
53239
53240
0
    abuf = JS_GetOpaque2(ctx, this_val, class_id);
53241
0
    if (!abuf)
53242
0
        return JS_EXCEPTION;
53243
0
    if (abuf->detached)
53244
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53245
0
    len = abuf->byte_length;
53246
53247
0
    if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
53248
0
        return JS_EXCEPTION;
53249
53250
0
    end = len;
53251
0
    if (!JS_IsUndefined(argv[1])) {
53252
0
        if (JS_ToInt64Clamp(ctx, &end, argv[1], 0, len, len))
53253
0
            return JS_EXCEPTION;
53254
0
    }
53255
0
    new_len = max_int64(end - start, 0);
53256
0
    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
53257
0
    if (JS_IsException(ctor))
53258
0
        return ctor;
53259
0
    if (JS_IsUndefined(ctor)) {
53260
0
        new_obj = js_array_buffer_constructor2(ctx, JS_UNDEFINED, new_len,
53261
0
                                               class_id);
53262
0
    } else {
53263
0
        JSValue args[1];
53264
0
        args[0] = JS_NewInt64(ctx, new_len);
53265
0
        new_obj = JS_CallConstructor(ctx, ctor, 1, (JSValueConst *)args);
53266
0
        JS_FreeValue(ctx, ctor);
53267
0
        JS_FreeValue(ctx, args[0]);
53268
0
    }
53269
0
    if (JS_IsException(new_obj))
53270
0
        return new_obj;
53271
0
    new_abuf = JS_GetOpaque2(ctx, new_obj, class_id);
53272
0
    if (!new_abuf)
53273
0
        goto fail;
53274
0
    if (js_same_value(ctx, new_obj, this_val)) {
53275
0
        JS_ThrowTypeError(ctx, "cannot use identical ArrayBuffer");
53276
0
        goto fail;
53277
0
    }
53278
0
    if (new_abuf->detached) {
53279
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53280
0
        goto fail;
53281
0
    }
53282
0
    if (new_abuf->byte_length < new_len) {
53283
0
        JS_ThrowTypeError(ctx, "new ArrayBuffer is too small");
53284
0
        goto fail;
53285
0
    }
53286
    /* must test again because of side effects */
53287
0
    if (abuf->detached) {
53288
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53289
0
        goto fail;
53290
0
    }
53291
0
    memcpy(new_abuf->data, abuf->data + start, new_len);
53292
0
    return new_obj;
53293
0
 fail:
53294
0
    JS_FreeValue(ctx, new_obj);
53295
0
    return JS_EXCEPTION;
53296
0
}
53297
53298
static const JSCFunctionListEntry js_array_buffer_proto_funcs[] = {
53299
    JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_ARRAY_BUFFER ),
53300
    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_ARRAY_BUFFER ),
53301
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "ArrayBuffer", JS_PROP_CONFIGURABLE ),
53302
};
53303
53304
/* SharedArrayBuffer */
53305
53306
static const JSCFunctionListEntry js_shared_array_buffer_funcs[] = {
53307
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
53308
};
53309
53310
static const JSCFunctionListEntry js_shared_array_buffer_proto_funcs[] = {
53311
    JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),
53312
    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_SHARED_ARRAY_BUFFER ),
53313
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "SharedArrayBuffer", JS_PROP_CONFIGURABLE ),
53314
};
53315
53316
static JSObject *get_typed_array(JSContext *ctx,
53317
                                 JSValueConst this_val,
53318
                                 int is_dataview)
53319
0
{
53320
0
    JSObject *p;
53321
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
53322
0
        goto fail;
53323
0
    p = JS_VALUE_GET_OBJ(this_val);
53324
0
    if (is_dataview) {
53325
0
        if (p->class_id != JS_CLASS_DATAVIEW)
53326
0
            goto fail;
53327
0
    } else {
53328
0
        if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&
53329
0
              p->class_id <= JS_CLASS_FLOAT64_ARRAY)) {
53330
0
        fail:
53331
0
            JS_ThrowTypeError(ctx, "not a %s", is_dataview ? "DataView" : "TypedArray");
53332
0
            return NULL;
53333
0
        }
53334
0
    }
53335
0
    return p;
53336
0
}
53337
53338
/* WARNING: 'p' must be a typed array */
53339
static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p)
53340
0
{
53341
0
    JSTypedArray *ta = p->u.typed_array;
53342
0
    JSArrayBuffer *abuf = ta->buffer->u.array_buffer;
53343
    /* XXX: could simplify test by ensuring that
53344
       p->u.array.u.ptr is NULL iff it is detached */
53345
0
    return abuf->detached;
53346
0
}
53347
53348
/* WARNING: 'p' must be a typed array. Works even if the array buffer
53349
   is detached */
53350
static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p)
53351
0
{
53352
0
    JSTypedArray *ta = p->u.typed_array;
53353
0
    int size_log2 = typed_array_size_log2(p->class_id);
53354
0
    return ta->length >> size_log2;
53355
0
}
53356
53357
static int validate_typed_array(JSContext *ctx, JSValueConst this_val)
53358
0
{
53359
0
    JSObject *p;
53360
0
    p = get_typed_array(ctx, this_val, 0);
53361
0
    if (!p)
53362
0
        return -1;
53363
0
    if (typed_array_is_detached(ctx, p)) {
53364
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53365
0
        return -1;
53366
0
    }
53367
0
    return 0;
53368
0
}
53369
53370
static JSValue js_typed_array_get_length(JSContext *ctx,
53371
                                         JSValueConst this_val)
53372
0
{
53373
0
    JSObject *p;
53374
0
    p = get_typed_array(ctx, this_val, 0);
53375
0
    if (!p)
53376
0
        return JS_EXCEPTION;
53377
0
    return JS_NewInt32(ctx, p->u.array.count);
53378
0
}
53379
53380
static JSValue js_typed_array_get_buffer(JSContext *ctx,
53381
                                         JSValueConst this_val, int is_dataview)
53382
0
{
53383
0
    JSObject *p;
53384
0
    JSTypedArray *ta;
53385
0
    p = get_typed_array(ctx, this_val, is_dataview);
53386
0
    if (!p)
53387
0
        return JS_EXCEPTION;
53388
0
    ta = p->u.typed_array;
53389
0
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
53390
0
}
53391
53392
static JSValue js_typed_array_get_byteLength(JSContext *ctx,
53393
                                             JSValueConst this_val,
53394
                                             int is_dataview)
53395
0
{
53396
0
    JSObject *p;
53397
0
    JSTypedArray *ta;
53398
0
    p = get_typed_array(ctx, this_val, is_dataview);
53399
0
    if (!p)
53400
0
        return JS_EXCEPTION;
53401
0
    if (typed_array_is_detached(ctx, p)) {
53402
0
        if (is_dataview) {
53403
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53404
0
        } else {
53405
0
            return JS_NewInt32(ctx, 0);
53406
0
        }
53407
0
    }
53408
0
    ta = p->u.typed_array;
53409
0
    return JS_NewInt32(ctx, ta->length);
53410
0
}
53411
53412
static JSValue js_typed_array_get_byteOffset(JSContext *ctx,
53413
                                             JSValueConst this_val,
53414
                                             int is_dataview)
53415
0
{
53416
0
    JSObject *p;
53417
0
    JSTypedArray *ta;
53418
0
    p = get_typed_array(ctx, this_val, is_dataview);
53419
0
    if (!p)
53420
0
        return JS_EXCEPTION;
53421
0
    if (typed_array_is_detached(ctx, p)) {
53422
0
        if (is_dataview) {
53423
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53424
0
        } else {
53425
0
            return JS_NewInt32(ctx, 0);
53426
0
        }
53427
0
    }
53428
0
    ta = p->u.typed_array;
53429
0
    return JS_NewInt32(ctx, ta->offset);
53430
0
}
53431
53432
JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv,
53433
                         JSTypedArrayEnum type)
53434
0
{
53435
0
    if (type < JS_TYPED_ARRAY_UINT8C || type > JS_TYPED_ARRAY_FLOAT64)
53436
0
        return JS_ThrowRangeError(ctx, "invalid typed array type");
53437
53438
0
    return js_typed_array_constructor(ctx, JS_UNDEFINED, argc, argv,
53439
0
                                      JS_CLASS_UINT8C_ARRAY + type);
53440
0
}
53441
53442
/* Return the buffer associated to the typed array or an exception if
53443
   it is not a typed array or if the buffer is detached. pbyte_offset,
53444
   pbyte_length or pbytes_per_element can be NULL. */
53445
JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
53446
                               size_t *pbyte_offset,
53447
                               size_t *pbyte_length,
53448
                               size_t *pbytes_per_element)
53449
0
{
53450
0
    JSObject *p;
53451
0
    JSTypedArray *ta;
53452
0
    p = get_typed_array(ctx, obj, FALSE);
53453
0
    if (!p)
53454
0
        return JS_EXCEPTION;
53455
0
    if (typed_array_is_detached(ctx, p))
53456
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53457
0
    ta = p->u.typed_array;
53458
0
    if (pbyte_offset)
53459
0
        *pbyte_offset = ta->offset;
53460
0
    if (pbyte_length)
53461
0
        *pbyte_length = ta->length;
53462
0
    if (pbytes_per_element) {
53463
0
        *pbytes_per_element = 1 << typed_array_size_log2(p->class_id);
53464
0
    }
53465
0
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
53466
0
}
53467
53468
static JSValue js_typed_array_get_toStringTag(JSContext *ctx,
53469
                                              JSValueConst this_val)
53470
0
{
53471
0
    JSObject *p;
53472
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
53473
0
        return JS_UNDEFINED;
53474
0
    p = JS_VALUE_GET_OBJ(this_val);
53475
0
    if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&
53476
0
          p->class_id <= JS_CLASS_FLOAT64_ARRAY))
53477
0
        return JS_UNDEFINED;
53478
0
    return JS_AtomToString(ctx, ctx->rt->class_array[p->class_id].class_name);
53479
0
}
53480
53481
static JSValue js_typed_array_set_internal(JSContext *ctx,
53482
                                           JSValueConst dst,
53483
                                           JSValueConst src,
53484
                                           JSValueConst off)
53485
0
{
53486
0
    JSObject *p;
53487
0
    JSObject *src_p;
53488
0
    uint32_t i;
53489
0
    int64_t src_len, offset;
53490
0
    JSValue val, src_obj = JS_UNDEFINED;
53491
53492
0
    p = get_typed_array(ctx, dst, 0);
53493
0
    if (!p)
53494
0
        goto fail;
53495
0
    if (JS_ToInt64Sat(ctx, &offset, off))
53496
0
        goto fail;
53497
0
    if (offset < 0)
53498
0
        goto range_error;
53499
0
    if (typed_array_is_detached(ctx, p)) {
53500
0
    detached:
53501
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53502
0
        goto fail;
53503
0
    }
53504
0
    src_obj = JS_ToObject(ctx, src);
53505
0
    if (JS_IsException(src_obj))
53506
0
        goto fail;
53507
0
    src_p = JS_VALUE_GET_OBJ(src_obj);
53508
0
    if (src_p->class_id >= JS_CLASS_UINT8C_ARRAY &&
53509
0
        src_p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
53510
0
        JSTypedArray *dest_ta = p->u.typed_array;
53511
0
        JSArrayBuffer *dest_abuf = dest_ta->buffer->u.array_buffer;
53512
0
        JSTypedArray *src_ta = src_p->u.typed_array;
53513
0
        JSArrayBuffer *src_abuf = src_ta->buffer->u.array_buffer;
53514
0
        int shift = typed_array_size_log2(p->class_id);
53515
53516
0
        if (src_abuf->detached)
53517
0
            goto detached;
53518
53519
0
        src_len = src_p->u.array.count;
53520
0
        if (offset > (int64_t)(p->u.array.count - src_len))
53521
0
            goto range_error;
53522
53523
        /* copying between typed objects */
53524
0
        if (src_p->class_id == p->class_id) {
53525
            /* same type, use memmove */
53526
0
            memmove(dest_abuf->data + dest_ta->offset + (offset << shift),
53527
0
                    src_abuf->data + src_ta->offset, src_len << shift);
53528
0
            goto done;
53529
0
        }
53530
0
        if (dest_abuf->data == src_abuf->data) {
53531
            /* copying between the same buffer using different types of mappings
53532
               would require a temporary buffer */
53533
0
        }
53534
        /* otherwise, default behavior is slow but correct */
53535
0
    } else {
53536
0
        if (js_get_length64(ctx, &src_len, src_obj))
53537
0
            goto fail;
53538
0
        if (offset > (int64_t)(p->u.array.count - src_len)) {
53539
0
        range_error:
53540
0
            JS_ThrowRangeError(ctx, "invalid array length");
53541
0
            goto fail;
53542
0
        }
53543
0
    }
53544
0
    for(i = 0; i < src_len; i++) {
53545
0
        val = JS_GetPropertyUint32(ctx, src_obj, i);
53546
0
        if (JS_IsException(val))
53547
0
            goto fail;
53548
0
        if (JS_SetPropertyUint32(ctx, dst, offset + i, val) < 0)
53549
0
            goto fail;
53550
0
    }
53551
0
done:
53552
0
    JS_FreeValue(ctx, src_obj);
53553
0
    return JS_UNDEFINED;
53554
0
fail:
53555
0
    JS_FreeValue(ctx, src_obj);
53556
0
    return JS_EXCEPTION;
53557
0
}
53558
53559
static JSValue js_typed_array_at(JSContext *ctx, JSValueConst this_val,
53560
                                 int argc, JSValueConst *argv)
53561
0
{
53562
0
    JSObject *p;
53563
0
    int64_t idx, len;
53564
53565
0
    p = get_typed_array(ctx, this_val, 0);
53566
0
    if (!p)
53567
0
        return JS_EXCEPTION;
53568
53569
0
    if (typed_array_is_detached(ctx, p)) {
53570
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53571
0
        return JS_EXCEPTION;
53572
0
    }
53573
53574
0
    if (JS_ToInt64Sat(ctx, &idx, argv[0]))
53575
0
        return JS_EXCEPTION;
53576
53577
0
    len = p->u.array.count;
53578
0
    if (idx < 0)
53579
0
        idx = len + idx;
53580
0
    if (idx < 0 || idx >= len)
53581
0
        return JS_UNDEFINED;
53582
0
    return JS_GetPropertyInt64(ctx, this_val, idx);
53583
0
}
53584
53585
static JSValue js_typed_array_with(JSContext *ctx, JSValueConst this_val,
53586
                                   int argc, JSValueConst *argv)
53587
0
{
53588
0
    JSValue arr, val;
53589
0
    JSObject *p;
53590
0
    int64_t idx, len;
53591
53592
0
    p = get_typed_array(ctx, this_val, /*is_dataview*/0);
53593
0
    if (!p)
53594
0
        return JS_EXCEPTION;
53595
53596
0
    if (JS_ToInt64Sat(ctx, &idx, argv[0]))
53597
0
        return JS_EXCEPTION;
53598
53599
0
    len = p->u.array.count;
53600
0
    if (idx < 0)
53601
0
        idx = len + idx;
53602
0
    if (idx < 0 || idx >= len)
53603
0
        return JS_ThrowRangeError(ctx, "invalid array index");
53604
53605
0
    val = JS_ToPrimitive(ctx, argv[1], HINT_NUMBER);
53606
0
    if (JS_IsException(val))
53607
0
        return JS_EXCEPTION;
53608
53609
0
    arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
53610
0
                                        p->class_id);
53611
0
    if (JS_IsException(arr)) {
53612
0
        JS_FreeValue(ctx, val);
53613
0
        return JS_EXCEPTION;
53614
0
    }
53615
0
    if (JS_SetPropertyInt64(ctx, arr, idx, val) < 0) {
53616
0
        JS_FreeValue(ctx, arr);
53617
0
        return JS_EXCEPTION;
53618
0
    }
53619
0
    return arr;
53620
0
}
53621
53622
static JSValue js_typed_array_set(JSContext *ctx,
53623
                                  JSValueConst this_val,
53624
                                  int argc, JSValueConst *argv)
53625
0
{
53626
0
    JSValueConst offset = JS_UNDEFINED;
53627
0
    if (argc > 1) {
53628
0
        offset = argv[1];
53629
0
    }
53630
0
    return js_typed_array_set_internal(ctx, this_val, argv[0], offset);
53631
0
}
53632
53633
static JSValue js_create_typed_array_iterator(JSContext *ctx, JSValueConst this_val,
53634
                                              int argc, JSValueConst *argv, int magic)
53635
0
{
53636
0
    if (validate_typed_array(ctx, this_val))
53637
0
        return JS_EXCEPTION;
53638
0
    return js_create_array_iterator(ctx, this_val, argc, argv, magic);
53639
0
}
53640
53641
/* return < 0 if exception */
53642
static int js_typed_array_get_length_internal(JSContext *ctx,
53643
                                              JSValueConst obj)
53644
0
{
53645
0
    JSObject *p;
53646
0
    p = get_typed_array(ctx, obj, 0);
53647
0
    if (!p)
53648
0
        return -1;
53649
0
    if (typed_array_is_detached(ctx, p)) {
53650
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53651
0
        return -1;
53652
0
    }
53653
0
    return p->u.array.count;
53654
0
}
53655
53656
#if 0
53657
/* validate a typed array and return its length */
53658
static JSValue js_typed_array___getLength(JSContext *ctx,
53659
                                          JSValueConst this_val,
53660
                                          int argc, JSValueConst *argv)
53661
{
53662
    BOOL ignore_detached = JS_ToBool(ctx, argv[1]);
53663
53664
    if (ignore_detached) {
53665
        return js_typed_array_get_length(ctx, argv[0]);
53666
    } else {
53667
        int len;
53668
        len = js_typed_array_get_length_internal(ctx, argv[0]);
53669
        if (len < 0)
53670
            return JS_EXCEPTION;
53671
        return JS_NewInt32(ctx, len);
53672
    }
53673
}
53674
#endif
53675
53676
static JSValue js_typed_array_create(JSContext *ctx, JSValueConst ctor,
53677
                                     int argc, JSValueConst *argv)
53678
0
{
53679
0
    JSValue ret;
53680
0
    int new_len;
53681
0
    int64_t len;
53682
53683
0
    ret = JS_CallConstructor(ctx, ctor, argc, argv);
53684
0
    if (JS_IsException(ret))
53685
0
        return ret;
53686
    /* validate the typed array */
53687
0
    new_len = js_typed_array_get_length_internal(ctx, ret);
53688
0
    if (new_len < 0)
53689
0
        goto fail;
53690
0
    if (argc == 1) {
53691
        /* ensure that it is large enough */
53692
0
        if (JS_ToLengthFree(ctx, &len, JS_DupValue(ctx, argv[0])))
53693
0
            goto fail;
53694
0
        if (new_len < len) {
53695
0
            JS_ThrowTypeError(ctx, "TypedArray length is too small");
53696
0
        fail:
53697
0
            JS_FreeValue(ctx, ret);
53698
0
            return JS_EXCEPTION;
53699
0
        }
53700
0
    }
53701
0
    return ret;
53702
0
}
53703
53704
#if 0
53705
static JSValue js_typed_array___create(JSContext *ctx,
53706
                                       JSValueConst this_val,
53707
                                       int argc, JSValueConst *argv)
53708
{
53709
    return js_typed_array_create(ctx, argv[0], max_int(argc - 1, 0), argv + 1);
53710
}
53711
#endif
53712
53713
static JSValue js_typed_array___speciesCreate(JSContext *ctx,
53714
                                              JSValueConst this_val,
53715
                                              int argc, JSValueConst *argv)
53716
0
{
53717
0
    JSValueConst obj;
53718
0
    JSObject *p;
53719
0
    JSValue ctor, ret;
53720
0
    int argc1;
53721
53722
0
    obj = argv[0];
53723
0
    p = get_typed_array(ctx, obj, 0);
53724
0
    if (!p)
53725
0
        return JS_EXCEPTION;
53726
0
    ctor = JS_SpeciesConstructor(ctx, obj, JS_UNDEFINED);
53727
0
    if (JS_IsException(ctor))
53728
0
        return ctor;
53729
0
    argc1 = max_int(argc - 1, 0);
53730
0
    if (JS_IsUndefined(ctor)) {
53731
0
        ret = js_typed_array_constructor(ctx, JS_UNDEFINED, argc1, argv + 1,
53732
0
                                         p->class_id);
53733
0
    } else {
53734
0
        ret = js_typed_array_create(ctx, ctor, argc1, argv + 1);
53735
0
        JS_FreeValue(ctx, ctor);
53736
0
    }
53737
0
    return ret;
53738
0
}
53739
53740
static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val,
53741
                                   int argc, JSValueConst *argv)
53742
0
{
53743
    // from(items, mapfn = void 0, this_arg = void 0)
53744
0
    JSValueConst items = argv[0], mapfn, this_arg;
53745
0
    JSValueConst args[2];
53746
0
    JSValue stack[2];
53747
0
    JSValue iter, arr, r, v, v2;
53748
0
    int64_t k, len;
53749
0
    int done, mapping;
53750
53751
0
    mapping = FALSE;
53752
0
    mapfn = JS_UNDEFINED;
53753
0
    this_arg = JS_UNDEFINED;
53754
0
    r = JS_UNDEFINED;
53755
0
    arr = JS_UNDEFINED;
53756
0
    stack[0] = JS_UNDEFINED;
53757
0
    stack[1] = JS_UNDEFINED;
53758
53759
0
    if (argc > 1) {
53760
0
        mapfn = argv[1];
53761
0
        if (!JS_IsUndefined(mapfn)) {
53762
0
            if (check_function(ctx, mapfn))
53763
0
                goto exception;
53764
0
            mapping = 1;
53765
0
            if (argc > 2)
53766
0
                this_arg = argv[2];
53767
0
        }
53768
0
    }
53769
0
    iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
53770
0
    if (JS_IsException(iter))
53771
0
        goto exception;
53772
0
    if (!JS_IsUndefined(iter)) {
53773
0
        JS_FreeValue(ctx, iter);
53774
0
        arr = JS_NewArray(ctx);
53775
0
        if (JS_IsException(arr))
53776
0
            goto exception;
53777
0
        stack[0] = JS_DupValue(ctx, items);
53778
0
        if (js_for_of_start(ctx, &stack[1], FALSE))
53779
0
            goto exception;
53780
0
        for (k = 0;; k++) {
53781
0
            v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done);
53782
0
            if (JS_IsException(v))
53783
0
                goto exception_close;
53784
0
            if (done)
53785
0
                break;
53786
0
            if (JS_DefinePropertyValueInt64(ctx, arr, k, v, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
53787
0
                goto exception_close;
53788
0
        }
53789
0
    } else {
53790
0
        arr = JS_ToObject(ctx, items);
53791
0
        if (JS_IsException(arr))
53792
0
            goto exception;
53793
0
    }
53794
0
    if (js_get_length64(ctx, &len, arr) < 0)
53795
0
        goto exception;
53796
0
    v = JS_NewInt64(ctx, len);
53797
0
    args[0] = v;
53798
0
    r = js_typed_array_create(ctx, this_val, 1, args);
53799
0
    JS_FreeValue(ctx, v);
53800
0
    if (JS_IsException(r))
53801
0
        goto exception;
53802
0
    for(k = 0; k < len; k++) {
53803
0
        v = JS_GetPropertyInt64(ctx, arr, k);
53804
0
        if (JS_IsException(v))
53805
0
            goto exception;
53806
0
        if (mapping) {
53807
0
            args[0] = v;
53808
0
            args[1] = JS_NewInt32(ctx, k);
53809
0
            v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
53810
0
            JS_FreeValue(ctx, v);
53811
0
            v = v2;
53812
0
            if (JS_IsException(v))
53813
0
                goto exception;
53814
0
        }
53815
0
        if (JS_SetPropertyInt64(ctx, r, k, v) < 0)
53816
0
            goto exception;
53817
0
    }
53818
0
    goto done;
53819
53820
0
 exception_close:
53821
0
    if (!JS_IsUndefined(stack[0]))
53822
0
        JS_IteratorClose(ctx, stack[0], TRUE);
53823
0
 exception:
53824
0
    JS_FreeValue(ctx, r);
53825
0
    r = JS_EXCEPTION;
53826
0
 done:
53827
0
    JS_FreeValue(ctx, arr);
53828
0
    JS_FreeValue(ctx, stack[0]);
53829
0
    JS_FreeValue(ctx, stack[1]);
53830
0
    return r;
53831
0
}
53832
53833
static JSValue js_typed_array_of(JSContext *ctx, JSValueConst this_val,
53834
                                 int argc, JSValueConst *argv)
53835
0
{
53836
0
    JSValue obj;
53837
0
    JSValueConst args[1];
53838
0
    int i;
53839
53840
0
    args[0] = JS_NewInt32(ctx, argc);
53841
0
    obj = js_typed_array_create(ctx, this_val, 1, args);
53842
0
    if (JS_IsException(obj))
53843
0
        return obj;
53844
53845
0
    for(i = 0; i < argc; i++) {
53846
0
        if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0) {
53847
0
            JS_FreeValue(ctx, obj);
53848
0
            return JS_EXCEPTION;
53849
0
        }
53850
0
    }
53851
0
    return obj;
53852
0
}
53853
53854
static JSValue js_typed_array_copyWithin(JSContext *ctx, JSValueConst this_val,
53855
                                         int argc, JSValueConst *argv)
53856
0
{
53857
0
    JSObject *p;
53858
0
    int len, to, from, final, count, shift;
53859
53860
0
    len = js_typed_array_get_length_internal(ctx, this_val);
53861
0
    if (len < 0)
53862
0
        return JS_EXCEPTION;
53863
53864
0
    if (JS_ToInt32Clamp(ctx, &to, argv[0], 0, len, len))
53865
0
        return JS_EXCEPTION;
53866
53867
0
    if (JS_ToInt32Clamp(ctx, &from, argv[1], 0, len, len))
53868
0
        return JS_EXCEPTION;
53869
53870
0
    final = len;
53871
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
53872
0
        if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
53873
0
            return JS_EXCEPTION;
53874
0
    }
53875
53876
0
    count = min_int(final - from, len - to);
53877
0
    if (count > 0) {
53878
0
        p = JS_VALUE_GET_OBJ(this_val);
53879
0
        if (typed_array_is_detached(ctx, p))
53880
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53881
0
        shift = typed_array_size_log2(p->class_id);
53882
0
        memmove(p->u.array.u.uint8_ptr + (to << shift),
53883
0
                p->u.array.u.uint8_ptr + (from << shift),
53884
0
                count << shift);
53885
0
    }
53886
0
    return JS_DupValue(ctx, this_val);
53887
0
}
53888
53889
static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val,
53890
                                   int argc, JSValueConst *argv)
53891
0
{
53892
0
    JSObject *p;
53893
0
    int len, k, final, shift;
53894
0
    uint64_t v64;
53895
53896
0
    len = js_typed_array_get_length_internal(ctx, this_val);
53897
0
    if (len < 0)
53898
0
        return JS_EXCEPTION;
53899
0
    p = JS_VALUE_GET_OBJ(this_val);
53900
53901
0
    if (p->class_id == JS_CLASS_UINT8C_ARRAY) {
53902
0
        int32_t v;
53903
0
        if (JS_ToUint8ClampFree(ctx, &v, JS_DupValue(ctx, argv[0])))
53904
0
            return JS_EXCEPTION;
53905
0
        v64 = v;
53906
0
    } else if (p->class_id <= JS_CLASS_UINT32_ARRAY) {
53907
0
        uint32_t v;
53908
0
        if (JS_ToUint32(ctx, &v, argv[0]))
53909
0
            return JS_EXCEPTION;
53910
0
        v64 = v;
53911
0
    } else if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
53912
0
        if (JS_ToBigInt64(ctx, (int64_t *)&v64, argv[0]))
53913
0
            return JS_EXCEPTION;
53914
0
    } else {
53915
0
        double d;
53916
0
        if (JS_ToFloat64(ctx, &d, argv[0]))
53917
0
            return JS_EXCEPTION;
53918
0
        if (p->class_id == JS_CLASS_FLOAT32_ARRAY) {
53919
0
            union {
53920
0
                float f;
53921
0
                uint32_t u32;
53922
0
            } u;
53923
0
            u.f = d;
53924
0
            v64 = u.u32;
53925
0
        } else {
53926
0
            JSFloat64Union u;
53927
0
            u.d = d;
53928
0
            v64 = u.u64;
53929
0
        }
53930
0
    }
53931
53932
0
    k = 0;
53933
0
    if (argc > 1) {
53934
0
        if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
53935
0
            return JS_EXCEPTION;
53936
0
    }
53937
53938
0
    final = len;
53939
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
53940
0
        if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
53941
0
            return JS_EXCEPTION;
53942
0
    }
53943
53944
0
    if (typed_array_is_detached(ctx, p))
53945
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53946
53947
0
    shift = typed_array_size_log2(p->class_id);
53948
0
    switch(shift) {
53949
0
    case 0:
53950
0
        if (k < final) {
53951
0
            memset(p->u.array.u.uint8_ptr + k, v64, final - k);
53952
0
        }
53953
0
        break;
53954
0
    case 1:
53955
0
        for(; k < final; k++) {
53956
0
            p->u.array.u.uint16_ptr[k] = v64;
53957
0
        }
53958
0
        break;
53959
0
    case 2:
53960
0
        for(; k < final; k++) {
53961
0
            p->u.array.u.uint32_ptr[k] = v64;
53962
0
        }
53963
0
        break;
53964
0
    case 3:
53965
0
        for(; k < final; k++) {
53966
0
            p->u.array.u.uint64_ptr[k] = v64;
53967
0
        }
53968
0
        break;
53969
0
    default:
53970
0
        abort();
53971
0
    }
53972
0
    return JS_DupValue(ctx, this_val);
53973
0
}
53974
53975
static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
53976
                                   int argc, JSValueConst *argv, int mode)
53977
0
{
53978
0
    JSValueConst func, this_arg;
53979
0
    JSValueConst args[3];
53980
0
    JSValue val, index_val, res;
53981
0
    int len, k, end;
53982
0
    int dir;
53983
53984
0
    val = JS_UNDEFINED;
53985
0
    len = js_typed_array_get_length_internal(ctx, this_val);
53986
0
    if (len < 0)
53987
0
        goto exception;
53988
53989
0
    func = argv[0];
53990
0
    if (check_function(ctx, func))
53991
0
        goto exception;
53992
53993
0
    this_arg = JS_UNDEFINED;
53994
0
    if (argc > 1)
53995
0
        this_arg = argv[1];
53996
53997
0
    k = 0;
53998
0
    dir = 1;
53999
0
    end = len;
54000
0
    if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {
54001
0
        k = len - 1;
54002
0
        dir = -1;
54003
0
        end = -1;
54004
0
    }
54005
54006
0
    for(; k != end; k += dir) {
54007
0
        index_val = JS_NewInt32(ctx, k);
54008
0
        val = JS_GetPropertyValue(ctx, this_val, index_val);
54009
0
        if (JS_IsException(val))
54010
0
            goto exception;
54011
0
        args[0] = val;
54012
0
        args[1] = index_val;
54013
0
        args[2] = this_val;
54014
0
        res = JS_Call(ctx, func, this_arg, 3, args);
54015
0
        if (JS_IsException(res))
54016
0
            goto exception;
54017
0
        if (JS_ToBoolFree(ctx, res)) {
54018
0
            if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {
54019
0
                JS_FreeValue(ctx, val);
54020
0
                return index_val;
54021
0
            } else {
54022
0
                return val;
54023
0
            }
54024
0
        }
54025
0
        JS_FreeValue(ctx, val);
54026
0
    }
54027
0
    if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)
54028
0
        return JS_NewInt32(ctx, -1);
54029
0
    else
54030
0
        return JS_UNDEFINED;
54031
54032
0
exception:
54033
0
    JS_FreeValue(ctx, val);
54034
0
    return JS_EXCEPTION;
54035
0
}
54036
54037
#define special_indexOf 0
54038
0
#define special_lastIndexOf 1
54039
0
#define special_includes -1
54040
54041
static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
54042
                                      int argc, JSValueConst *argv, int special)
54043
0
{
54044
0
    JSObject *p;
54045
0
    int len, tag, is_int, is_bigint, k, stop, inc, res = -1;
54046
0
    int64_t v64;
54047
0
    double d;
54048
0
    float f;
54049
54050
0
    len = js_typed_array_get_length_internal(ctx, this_val);
54051
0
    if (len < 0)
54052
0
        goto exception;
54053
0
    if (len == 0)
54054
0
        goto done;
54055
54056
0
    if (special == special_lastIndexOf) {
54057
0
        k = len - 1;
54058
0
        if (argc > 1) {
54059
0
            if (JS_ToFloat64(ctx, &d, argv[1]))
54060
0
                goto exception;
54061
0
            if (isnan(d)) {
54062
0
                k = 0;
54063
0
            } else {
54064
0
                if (d >= 0) {
54065
0
                    if (d < k) {
54066
0
                        k = d;
54067
0
                    }
54068
0
                } else {
54069
0
                    d += len;
54070
0
                    if (d < 0)
54071
0
                        goto done;
54072
0
                    k = d;
54073
0
                }
54074
0
            }
54075
0
        }
54076
0
        stop = -1;
54077
0
        inc = -1;
54078
0
    } else {
54079
0
        k = 0;
54080
0
        if (argc > 1) {
54081
0
            if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
54082
0
                goto exception;
54083
0
        }
54084
0
        stop = len;
54085
0
        inc = 1;
54086
0
    }
54087
54088
0
    p = JS_VALUE_GET_OBJ(this_val);
54089
    /* if the array was detached, no need to go further (but no
54090
       exception is raised) */
54091
0
    if (typed_array_is_detached(ctx, p)) {
54092
        /* "includes" scans all the properties, so "undefined" can match */
54093
0
        if (special == special_includes && JS_IsUndefined(argv[0]) && len > 0)
54094
0
            res = 0;
54095
0
        goto done;
54096
0
    }
54097
54098
0
    is_bigint = 0;
54099
0
    is_int = 0; /* avoid warning */
54100
0
    v64 = 0; /* avoid warning */
54101
0
    tag = JS_VALUE_GET_NORM_TAG(argv[0]);
54102
0
    if (tag == JS_TAG_INT) {
54103
0
        is_int = 1;
54104
0
        v64 = JS_VALUE_GET_INT(argv[0]);
54105
0
        d = v64;
54106
0
    } else
54107
0
    if (tag == JS_TAG_FLOAT64) {
54108
0
        d = JS_VALUE_GET_FLOAT64(argv[0]);
54109
0
        if (d >= INT64_MIN && d < 0x1p63) {
54110
0
            v64 = d;
54111
0
            is_int = (v64 == d);
54112
0
        }
54113
0
    } else if (tag == JS_TAG_BIG_INT) {
54114
0
        JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]);
54115
54116
0
        if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {
54117
0
            if (bf_get_int64(&v64, &p1->num, 0) != 0)
54118
0
                goto done;
54119
0
        } else if (p->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
54120
0
            if (bf_get_uint64((uint64_t *)&v64, &p1->num) != 0)
54121
0
                goto done;
54122
0
        } else {
54123
0
            goto done;
54124
0
        }
54125
0
        d = 0;
54126
0
        is_bigint = 1;
54127
0
    } else {
54128
0
        goto done;
54129
0
    }
54130
54131
0
    switch (p->class_id) {
54132
0
    case JS_CLASS_INT8_ARRAY:
54133
0
        if (is_int && (int8_t)v64 == v64)
54134
0
            goto scan8;
54135
0
        break;
54136
0
    case JS_CLASS_UINT8C_ARRAY:
54137
0
    case JS_CLASS_UINT8_ARRAY:
54138
0
        if (is_int && (uint8_t)v64 == v64) {
54139
0
            const uint8_t *pv, *pp;
54140
0
            uint16_t v;
54141
0
        scan8:
54142
0
            pv = p->u.array.u.uint8_ptr;
54143
0
            v = v64;
54144
0
            if (inc > 0) {
54145
0
                pp = memchr(pv + k, v, len - k);
54146
0
                if (pp)
54147
0
                    res = pp - pv;
54148
0
            } else {
54149
0
                for (; k != stop; k += inc) {
54150
0
                    if (pv[k] == v) {
54151
0
                        res = k;
54152
0
                        break;
54153
0
                    }
54154
0
                }
54155
0
            }
54156
0
        }
54157
0
        break;
54158
0
    case JS_CLASS_INT16_ARRAY:
54159
0
        if (is_int && (int16_t)v64 == v64)
54160
0
            goto scan16;
54161
0
        break;
54162
0
    case JS_CLASS_UINT16_ARRAY:
54163
0
        if (is_int && (uint16_t)v64 == v64) {
54164
0
            const uint16_t *pv;
54165
0
            uint16_t v;
54166
0
        scan16:
54167
0
            pv = p->u.array.u.uint16_ptr;
54168
0
            v = v64;
54169
0
            for (; k != stop; k += inc) {
54170
0
                if (pv[k] == v) {
54171
0
                    res = k;
54172
0
                    break;
54173
0
                }
54174
0
            }
54175
0
        }
54176
0
        break;
54177
0
    case JS_CLASS_INT32_ARRAY:
54178
0
        if (is_int && (int32_t)v64 == v64)
54179
0
            goto scan32;
54180
0
        break;
54181
0
    case JS_CLASS_UINT32_ARRAY:
54182
0
        if (is_int && (uint32_t)v64 == v64) {
54183
0
            const uint32_t *pv;
54184
0
            uint32_t v;
54185
0
        scan32:
54186
0
            pv = p->u.array.u.uint32_ptr;
54187
0
            v = v64;
54188
0
            for (; k != stop; k += inc) {
54189
0
                if (pv[k] == v) {
54190
0
                    res = k;
54191
0
                    break;
54192
0
                }
54193
0
            }
54194
0
        }
54195
0
        break;
54196
0
    case JS_CLASS_FLOAT32_ARRAY:
54197
0
        if (is_bigint)
54198
0
            break;
54199
0
        if (isnan(d)) {
54200
0
            const float *pv = p->u.array.u.float_ptr;
54201
            /* special case: indexOf returns -1, includes finds NaN */
54202
0
            if (special != special_includes)
54203
0
                goto done;
54204
0
            for (; k != stop; k += inc) {
54205
0
                if (isnan(pv[k])) {
54206
0
                    res = k;
54207
0
                    break;
54208
0
                }
54209
0
            }
54210
0
        } else if ((f = (float)d) == d) {
54211
0
            const float *pv = p->u.array.u.float_ptr;
54212
0
            for (; k != stop; k += inc) {
54213
0
                if (pv[k] == f) {
54214
0
                    res = k;
54215
0
                    break;
54216
0
                }
54217
0
            }
54218
0
        }
54219
0
        break;
54220
0
    case JS_CLASS_FLOAT64_ARRAY:
54221
0
        if (is_bigint)
54222
0
            break;
54223
0
        if (isnan(d)) {
54224
0
            const double *pv = p->u.array.u.double_ptr;
54225
            /* special case: indexOf returns -1, includes finds NaN */
54226
0
            if (special != special_includes)
54227
0
                goto done;
54228
0
            for (; k != stop; k += inc) {
54229
0
                if (isnan(pv[k])) {
54230
0
                    res = k;
54231
0
                    break;
54232
0
                }
54233
0
            }
54234
0
        } else {
54235
0
            const double *pv = p->u.array.u.double_ptr;
54236
0
            for (; k != stop; k += inc) {
54237
0
                if (pv[k] == d) {
54238
0
                    res = k;
54239
0
                    break;
54240
0
                }
54241
0
            }
54242
0
        }
54243
0
        break;
54244
0
    case JS_CLASS_BIG_INT64_ARRAY:
54245
0
        if (is_bigint || (is_math_mode(ctx) && is_int &&
54246
0
                          v64 >= -MAX_SAFE_INTEGER &&
54247
0
                          v64 <= MAX_SAFE_INTEGER)) {
54248
0
            goto scan64;
54249
0
        }
54250
0
        break;
54251
0
    case JS_CLASS_BIG_UINT64_ARRAY:
54252
0
        if (is_bigint || (is_math_mode(ctx) && is_int &&
54253
0
                          v64 >= 0 && v64 <= MAX_SAFE_INTEGER)) {
54254
0
            const uint64_t *pv;
54255
0
            uint64_t v;
54256
0
        scan64:
54257
0
            pv = p->u.array.u.uint64_ptr;
54258
0
            v = v64;
54259
0
            for (; k != stop; k += inc) {
54260
0
                if (pv[k] == v) {
54261
0
                    res = k;
54262
0
                    break;
54263
0
                }
54264
0
            }
54265
0
        }
54266
0
        break;
54267
0
    }
54268
54269
0
done:
54270
0
    if (special == special_includes)
54271
0
        return JS_NewBool(ctx, res >= 0);
54272
0
    else
54273
0
        return JS_NewInt32(ctx, res);
54274
54275
0
exception:
54276
0
    return JS_EXCEPTION;
54277
0
}
54278
54279
static JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val,
54280
                                   int argc, JSValueConst *argv, int toLocaleString)
54281
0
{
54282
0
    JSValue sep = JS_UNDEFINED, el;
54283
0
    StringBuffer b_s, *b = &b_s;
54284
0
    JSString *p = NULL;
54285
0
    int i, n;
54286
0
    int c;
54287
54288
0
    n = js_typed_array_get_length_internal(ctx, this_val);
54289
0
    if (n < 0)
54290
0
        goto exception;
54291
54292
0
    c = ',';    /* default separator */
54293
0
    if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
54294
0
        sep = JS_ToString(ctx, argv[0]);
54295
0
        if (JS_IsException(sep))
54296
0
            goto exception;
54297
0
        p = JS_VALUE_GET_STRING(sep);
54298
0
        if (p->len == 1 && !p->is_wide_char)
54299
0
            c = p->u.str8[0];
54300
0
        else
54301
0
            c = -1;
54302
0
    }
54303
0
    string_buffer_init(ctx, b, 0);
54304
54305
    /* XXX: optimize with direct access */
54306
0
    for(i = 0; i < n; i++) {
54307
0
        if (i > 0) {
54308
0
            if (c >= 0) {
54309
0
                if (string_buffer_putc8(b, c))
54310
0
                    goto fail;
54311
0
            } else {
54312
0
                if (string_buffer_concat(b, p, 0, p->len))
54313
0
                    goto fail;
54314
0
            }
54315
0
        }
54316
0
        el = JS_GetPropertyUint32(ctx, this_val, i);
54317
        /* Can return undefined for example if the typed array is detached */
54318
0
        if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
54319
0
            if (JS_IsException(el))
54320
0
                goto fail;
54321
0
            if (toLocaleString) {
54322
0
                el = JS_ToLocaleStringFree(ctx, el);
54323
0
            }
54324
0
            if (string_buffer_concat_value_free(b, el))
54325
0
                goto fail;
54326
0
        }
54327
0
    }
54328
0
    JS_FreeValue(ctx, sep);
54329
0
    return string_buffer_end(b);
54330
54331
0
fail:
54332
0
    string_buffer_free(b);
54333
0
    JS_FreeValue(ctx, sep);
54334
0
exception:
54335
0
    return JS_EXCEPTION;
54336
0
}
54337
54338
static JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val,
54339
                                      int argc, JSValueConst *argv)
54340
0
{
54341
0
    JSObject *p;
54342
0
    int len;
54343
54344
0
    len = js_typed_array_get_length_internal(ctx, this_val);
54345
0
    if (len < 0)
54346
0
        return JS_EXCEPTION;
54347
0
    if (len > 0) {
54348
0
        p = JS_VALUE_GET_OBJ(this_val);
54349
0
        switch (typed_array_size_log2(p->class_id)) {
54350
0
        case 0:
54351
0
            {
54352
0
                uint8_t *p1 = p->u.array.u.uint8_ptr;
54353
0
                uint8_t *p2 = p1 + len - 1;
54354
0
                while (p1 < p2) {
54355
0
                    uint8_t v = *p1;
54356
0
                    *p1++ = *p2;
54357
0
                    *p2-- = v;
54358
0
                }
54359
0
            }
54360
0
            break;
54361
0
        case 1:
54362
0
            {
54363
0
                uint16_t *p1 = p->u.array.u.uint16_ptr;
54364
0
                uint16_t *p2 = p1 + len - 1;
54365
0
                while (p1 < p2) {
54366
0
                    uint16_t v = *p1;
54367
0
                    *p1++ = *p2;
54368
0
                    *p2-- = v;
54369
0
                }
54370
0
            }
54371
0
            break;
54372
0
        case 2:
54373
0
            {
54374
0
                uint32_t *p1 = p->u.array.u.uint32_ptr;
54375
0
                uint32_t *p2 = p1 + len - 1;
54376
0
                while (p1 < p2) {
54377
0
                    uint32_t v = *p1;
54378
0
                    *p1++ = *p2;
54379
0
                    *p2-- = v;
54380
0
                }
54381
0
            }
54382
0
            break;
54383
0
        case 3:
54384
0
            {
54385
0
                uint64_t *p1 = p->u.array.u.uint64_ptr;
54386
0
                uint64_t *p2 = p1 + len - 1;
54387
0
                while (p1 < p2) {
54388
0
                    uint64_t v = *p1;
54389
0
                    *p1++ = *p2;
54390
0
                    *p2-- = v;
54391
0
                }
54392
0
            }
54393
0
            break;
54394
0
        default:
54395
0
            abort();
54396
0
        }
54397
0
    }
54398
0
    return JS_DupValue(ctx, this_val);
54399
0
}
54400
54401
static JSValue js_typed_array_toReversed(JSContext *ctx, JSValueConst this_val,
54402
                                         int argc, JSValueConst *argv)
54403
0
{
54404
0
    JSValue arr, ret;
54405
0
    JSObject *p;
54406
54407
0
    p = get_typed_array(ctx, this_val, /*is_dataview*/0);
54408
0
    if (!p)
54409
0
        return JS_EXCEPTION;
54410
0
    arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
54411
0
                                        p->class_id);
54412
0
    if (JS_IsException(arr))
54413
0
        return JS_EXCEPTION;
54414
0
    ret = js_typed_array_reverse(ctx, arr, argc, argv);
54415
0
    JS_FreeValue(ctx, arr);
54416
0
    return ret;
54417
0
}
54418
54419
static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val,
54420
                                    int argc, JSValueConst *argv)
54421
0
{
54422
0
    JSValueConst args[2];
54423
0
    JSValue arr, val;
54424
0
    JSObject *p, *p1;
54425
0
    int n, len, start, final, count, shift;
54426
54427
0
    arr = JS_UNDEFINED;
54428
0
    len = js_typed_array_get_length_internal(ctx, this_val);
54429
0
    if (len < 0)
54430
0
        goto exception;
54431
54432
0
    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
54433
0
        goto exception;
54434
0
    final = len;
54435
0
    if (!JS_IsUndefined(argv[1])) {
54436
0
        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
54437
0
            goto exception;
54438
0
    }
54439
0
    count = max_int(final - start, 0);
54440
54441
0
    p = get_typed_array(ctx, this_val, 0);
54442
0
    if (p == NULL)
54443
0
        goto exception;
54444
0
    shift = typed_array_size_log2(p->class_id);
54445
54446
0
    args[0] = this_val;
54447
0
    args[1] = JS_NewInt32(ctx, count);
54448
0
    arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
54449
0
    if (JS_IsException(arr))
54450
0
        goto exception;
54451
54452
0
    if (count > 0) {
54453
0
        if (validate_typed_array(ctx, this_val)
54454
0
        ||  validate_typed_array(ctx, arr))
54455
0
            goto exception;
54456
54457
0
        p1 = get_typed_array(ctx, arr, 0);
54458
0
        if (p1 != NULL && p->class_id == p1->class_id &&
54459
0
            typed_array_get_length(ctx, p1) >= count &&
54460
0
            typed_array_get_length(ctx, p) >= start + count) {
54461
0
            memcpy(p1->u.array.u.uint8_ptr,
54462
0
                   p->u.array.u.uint8_ptr + (start << shift),
54463
0
                   count << shift);
54464
0
        } else {
54465
0
            for (n = 0; n < count; n++) {
54466
0
                val = JS_GetPropertyValue(ctx, this_val, JS_NewInt32(ctx, start + n));
54467
0
                if (JS_IsException(val))
54468
0
                    goto exception;
54469
0
                if (JS_SetPropertyValue(ctx, arr, JS_NewInt32(ctx, n), val,
54470
0
                                        JS_PROP_THROW) < 0)
54471
0
                    goto exception;
54472
0
            }
54473
0
        }
54474
0
    }
54475
0
    return arr;
54476
54477
0
 exception:
54478
0
    JS_FreeValue(ctx, arr);
54479
0
    return JS_EXCEPTION;
54480
0
}
54481
54482
static JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val,
54483
                                       int argc, JSValueConst *argv)
54484
0
{
54485
0
    JSValueConst args[4];
54486
0
    JSValue arr, byteOffset, ta_buffer;
54487
0
    JSObject *p;
54488
0
    int len, start, final, count, shift, offset;
54489
54490
0
    p = get_typed_array(ctx, this_val, 0);
54491
0
    if (!p)
54492
0
        goto exception;
54493
0
    len = p->u.array.count;
54494
0
    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
54495
0
        goto exception;
54496
54497
0
    final = len;
54498
0
    if (!JS_IsUndefined(argv[1])) {
54499
0
        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
54500
0
            goto exception;
54501
0
    }
54502
0
    count = max_int(final - start, 0);
54503
0
    byteOffset = js_typed_array_get_byteOffset(ctx, this_val, 0);
54504
0
    if (JS_IsException(byteOffset))
54505
0
        goto exception;
54506
0
    shift = typed_array_size_log2(p->class_id);
54507
0
    offset = JS_VALUE_GET_INT(byteOffset) + (start << shift);
54508
0
    JS_FreeValue(ctx, byteOffset);
54509
0
    ta_buffer = js_typed_array_get_buffer(ctx, this_val, 0);
54510
0
    if (JS_IsException(ta_buffer))
54511
0
        goto exception;
54512
0
    args[0] = this_val;
54513
0
    args[1] = ta_buffer;
54514
0
    args[2] = JS_NewInt32(ctx, offset);
54515
0
    args[3] = JS_NewInt32(ctx, count);
54516
0
    arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 4, args);
54517
0
    JS_FreeValue(ctx, ta_buffer);
54518
0
    return arr;
54519
54520
0
 exception:
54521
0
    return JS_EXCEPTION;
54522
0
}
54523
54524
/* TypedArray.prototype.sort */
54525
54526
static int js_cmp_doubles(double x, double y)
54527
0
{
54528
0
    if (isnan(x))    return isnan(y) ? 0 : +1;
54529
0
    if (isnan(y))    return -1;
54530
0
    if (x < y)       return -1;
54531
0
    if (x > y)       return 1;
54532
0
    if (x != 0)      return 0;
54533
0
    if (signbit(x))  return signbit(y) ? 0 : -1;
54534
0
    else             return signbit(y) ? 1 : 0;
54535
0
}
54536
54537
0
static int js_TA_cmp_int8(const void *a, const void *b, void *opaque) {
54538
0
    return *(const int8_t *)a - *(const int8_t *)b;
54539
0
}
54540
54541
0
static int js_TA_cmp_uint8(const void *a, const void *b, void *opaque) {
54542
0
    return *(const uint8_t *)a - *(const uint8_t *)b;
54543
0
}
54544
54545
0
static int js_TA_cmp_int16(const void *a, const void *b, void *opaque) {
54546
0
    return *(const int16_t *)a - *(const int16_t *)b;
54547
0
}
54548
54549
0
static int js_TA_cmp_uint16(const void *a, const void *b, void *opaque) {
54550
0
    return *(const uint16_t *)a - *(const uint16_t *)b;
54551
0
}
54552
54553
0
static int js_TA_cmp_int32(const void *a, const void *b, void *opaque) {
54554
0
    int32_t x = *(const int32_t *)a;
54555
0
    int32_t y = *(const int32_t *)b;
54556
0
    return (y < x) - (y > x);
54557
0
}
54558
54559
0
static int js_TA_cmp_uint32(const void *a, const void *b, void *opaque) {
54560
0
    uint32_t x = *(const uint32_t *)a;
54561
0
    uint32_t y = *(const uint32_t *)b;
54562
0
    return (y < x) - (y > x);
54563
0
}
54564
54565
0
static int js_TA_cmp_int64(const void *a, const void *b, void *opaque) {
54566
0
    int64_t x = *(const int64_t *)a;
54567
0
    int64_t y = *(const int64_t *)b;
54568
0
    return (y < x) - (y > x);
54569
0
}
54570
54571
0
static int js_TA_cmp_uint64(const void *a, const void *b, void *opaque) {
54572
0
    uint64_t x = *(const uint64_t *)a;
54573
0
    uint64_t y = *(const uint64_t *)b;
54574
0
    return (y < x) - (y > x);
54575
0
}
54576
54577
0
static int js_TA_cmp_float32(const void *a, const void *b, void *opaque) {
54578
0
    return js_cmp_doubles(*(const float *)a, *(const float *)b);
54579
0
}
54580
54581
0
static int js_TA_cmp_float64(const void *a, const void *b, void *opaque) {
54582
0
    return js_cmp_doubles(*(const double *)a, *(const double *)b);
54583
0
}
54584
54585
0
static JSValue js_TA_get_int8(JSContext *ctx, const void *a) {
54586
0
    return JS_NewInt32(ctx, *(const int8_t *)a);
54587
0
}
54588
54589
0
static JSValue js_TA_get_uint8(JSContext *ctx, const void *a) {
54590
0
    return JS_NewInt32(ctx, *(const uint8_t *)a);
54591
0
}
54592
54593
0
static JSValue js_TA_get_int16(JSContext *ctx, const void *a) {
54594
0
    return JS_NewInt32(ctx, *(const int16_t *)a);
54595
0
}
54596
54597
0
static JSValue js_TA_get_uint16(JSContext *ctx, const void *a) {
54598
0
    return JS_NewInt32(ctx, *(const uint16_t *)a);
54599
0
}
54600
54601
0
static JSValue js_TA_get_int32(JSContext *ctx, const void *a) {
54602
0
    return JS_NewInt32(ctx, *(const int32_t *)a);
54603
0
}
54604
54605
0
static JSValue js_TA_get_uint32(JSContext *ctx, const void *a) {
54606
0
    return JS_NewUint32(ctx, *(const uint32_t *)a);
54607
0
}
54608
54609
0
static JSValue js_TA_get_int64(JSContext *ctx, const void *a) {
54610
0
    return JS_NewBigInt64(ctx, *(int64_t *)a);
54611
0
}
54612
54613
0
static JSValue js_TA_get_uint64(JSContext *ctx, const void *a) {
54614
0
    return JS_NewBigUint64(ctx, *(uint64_t *)a);
54615
0
}
54616
54617
0
static JSValue js_TA_get_float32(JSContext *ctx, const void *a) {
54618
0
    return __JS_NewFloat64(ctx, *(const float *)a);
54619
0
}
54620
54621
0
static JSValue js_TA_get_float64(JSContext *ctx, const void *a) {
54622
0
    return __JS_NewFloat64(ctx, *(const double *)a);
54623
0
}
54624
54625
struct TA_sort_context {
54626
    JSContext *ctx;
54627
    int exception; /* 1 = exception, 2 = detached typed array */
54628
    JSValueConst arr;
54629
    JSValueConst cmp;
54630
    JSValue (*getfun)(JSContext *ctx, const void *a);
54631
    uint8_t *array_ptr; /* cannot change unless the array is detached */
54632
    int elt_size;
54633
};
54634
54635
0
static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) {
54636
0
    struct TA_sort_context *psc = opaque;
54637
0
    JSContext *ctx = psc->ctx;
54638
0
    uint32_t a_idx, b_idx;
54639
0
    JSValueConst argv[2];
54640
0
    JSValue res;
54641
0
    int cmp;
54642
54643
0
    cmp = 0;
54644
0
    if (!psc->exception) {
54645
        /* Note: the typed array can be detached without causing an
54646
           error */
54647
0
        a_idx = *(uint32_t *)a;
54648
0
        b_idx = *(uint32_t *)b;
54649
0
        argv[0] = psc->getfun(ctx, psc->array_ptr +
54650
0
                              a_idx * (size_t)psc->elt_size);
54651
0
        argv[1] = psc->getfun(ctx, psc->array_ptr +
54652
0
                              b_idx * (size_t)(psc->elt_size));
54653
0
        res = JS_Call(ctx, psc->cmp, JS_UNDEFINED, 2, argv);
54654
0
        if (JS_IsException(res)) {
54655
0
            psc->exception = 1;
54656
0
            goto done;
54657
0
        }
54658
0
        if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
54659
0
            int val = JS_VALUE_GET_INT(res);
54660
0
            cmp = (val > 0) - (val < 0);
54661
0
        } else {
54662
0
            double val;
54663
0
            if (JS_ToFloat64Free(ctx, &val, res) < 0) {
54664
0
                psc->exception = 1;
54665
0
                goto done;
54666
0
            } else {
54667
0
                cmp = (val > 0) - (val < 0);
54668
0
            }
54669
0
        }
54670
0
        if (cmp == 0) {
54671
            /* make sort stable: compare array offsets */
54672
0
            cmp = (a_idx > b_idx) - (a_idx < b_idx);
54673
0
        }
54674
0
        if (unlikely(typed_array_is_detached(ctx,
54675
0
                                             JS_VALUE_GET_PTR(psc->arr)))) {
54676
0
            psc->exception = 2;
54677
0
        }
54678
0
    done:
54679
0
        JS_FreeValue(ctx, (JSValue)argv[0]);
54680
0
        JS_FreeValue(ctx, (JSValue)argv[1]);
54681
0
    }
54682
0
    return cmp;
54683
0
}
54684
54685
static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
54686
                                   int argc, JSValueConst *argv)
54687
0
{
54688
0
    JSObject *p;
54689
0
    int len;
54690
0
    size_t elt_size;
54691
0
    struct TA_sort_context tsc;
54692
0
    void *array_ptr;
54693
0
    int (*cmpfun)(const void *a, const void *b, void *opaque);
54694
54695
0
    tsc.ctx = ctx;
54696
0
    tsc.exception = 0;
54697
0
    tsc.arr = this_val;
54698
0
    tsc.cmp = argv[0];
54699
54700
0
    if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp))
54701
0
        return JS_EXCEPTION;
54702
0
    len = js_typed_array_get_length_internal(ctx, this_val);
54703
0
    if (len < 0)
54704
0
        return JS_EXCEPTION;
54705
54706
0
    if (len > 1) {
54707
0
        p = JS_VALUE_GET_OBJ(this_val);
54708
0
        switch (p->class_id) {
54709
0
        case JS_CLASS_INT8_ARRAY:
54710
0
            tsc.getfun = js_TA_get_int8;
54711
0
            cmpfun = js_TA_cmp_int8;
54712
0
            break;
54713
0
        case JS_CLASS_UINT8C_ARRAY:
54714
0
        case JS_CLASS_UINT8_ARRAY:
54715
0
            tsc.getfun = js_TA_get_uint8;
54716
0
            cmpfun = js_TA_cmp_uint8;
54717
0
            break;
54718
0
        case JS_CLASS_INT16_ARRAY:
54719
0
            tsc.getfun = js_TA_get_int16;
54720
0
            cmpfun = js_TA_cmp_int16;
54721
0
            break;
54722
0
        case JS_CLASS_UINT16_ARRAY:
54723
0
            tsc.getfun = js_TA_get_uint16;
54724
0
            cmpfun = js_TA_cmp_uint16;
54725
0
            break;
54726
0
        case JS_CLASS_INT32_ARRAY:
54727
0
            tsc.getfun = js_TA_get_int32;
54728
0
            cmpfun = js_TA_cmp_int32;
54729
0
            break;
54730
0
        case JS_CLASS_UINT32_ARRAY:
54731
0
            tsc.getfun = js_TA_get_uint32;
54732
0
            cmpfun = js_TA_cmp_uint32;
54733
0
            break;
54734
0
        case JS_CLASS_BIG_INT64_ARRAY:
54735
0
            tsc.getfun = js_TA_get_int64;
54736
0
            cmpfun = js_TA_cmp_int64;
54737
0
            break;
54738
0
        case JS_CLASS_BIG_UINT64_ARRAY:
54739
0
            tsc.getfun = js_TA_get_uint64;
54740
0
            cmpfun = js_TA_cmp_uint64;
54741
0
            break;
54742
0
        case JS_CLASS_FLOAT32_ARRAY:
54743
0
            tsc.getfun = js_TA_get_float32;
54744
0
            cmpfun = js_TA_cmp_float32;
54745
0
            break;
54746
0
        case JS_CLASS_FLOAT64_ARRAY:
54747
0
            tsc.getfun = js_TA_get_float64;
54748
0
            cmpfun = js_TA_cmp_float64;
54749
0
            break;
54750
0
        default:
54751
0
            abort();
54752
0
        }
54753
0
        array_ptr = p->u.array.u.ptr;
54754
0
        elt_size = 1 << typed_array_size_log2(p->class_id);
54755
0
        if (!JS_IsUndefined(tsc.cmp)) {
54756
0
            uint32_t *array_idx;
54757
0
            void *array_tmp;
54758
0
            size_t i, j;
54759
54760
            /* XXX: a stable sort would use less memory */
54761
0
            array_idx = js_malloc(ctx, len * sizeof(array_idx[0]));
54762
0
            if (!array_idx)
54763
0
                return JS_EXCEPTION;
54764
0
            for(i = 0; i < len; i++)
54765
0
                array_idx[i] = i;
54766
0
            tsc.array_ptr = array_ptr;
54767
0
            tsc.elt_size = elt_size;
54768
0
            rqsort(array_idx, len, sizeof(array_idx[0]),
54769
0
                   js_TA_cmp_generic, &tsc);
54770
0
            if (tsc.exception) {
54771
0
                if (tsc.exception == 1)
54772
0
                    goto fail;
54773
                /* detached typed array during the sort: no error */
54774
0
            } else {
54775
0
                array_tmp = js_malloc(ctx, len * elt_size);
54776
0
                if (!array_tmp) {
54777
0
                fail:
54778
0
                    js_free(ctx, array_idx);
54779
0
                    return JS_EXCEPTION;
54780
0
                }
54781
0
                memcpy(array_tmp, array_ptr, len * elt_size);
54782
0
                switch(elt_size) {
54783
0
                case 1:
54784
0
                    for(i = 0; i < len; i++) {
54785
0
                        j = array_idx[i];
54786
0
                        ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j];
54787
0
                    }
54788
0
                    break;
54789
0
                case 2:
54790
0
                    for(i = 0; i < len; i++) {
54791
0
                        j = array_idx[i];
54792
0
                        ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j];
54793
0
                    }
54794
0
                    break;
54795
0
                case 4:
54796
0
                    for(i = 0; i < len; i++) {
54797
0
                        j = array_idx[i];
54798
0
                        ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j];
54799
0
                    }
54800
0
                    break;
54801
0
                case 8:
54802
0
                    for(i = 0; i < len; i++) {
54803
0
                        j = array_idx[i];
54804
0
                        ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j];
54805
0
                    }
54806
0
                    break;
54807
0
                default:
54808
0
                    abort();
54809
0
                }
54810
0
                js_free(ctx, array_tmp);
54811
0
            }
54812
0
            js_free(ctx, array_idx);
54813
0
        } else {
54814
0
            rqsort(array_ptr, len, elt_size, cmpfun, &tsc);
54815
0
            if (tsc.exception)
54816
0
                return JS_EXCEPTION;
54817
0
        }
54818
0
    }
54819
0
    return JS_DupValue(ctx, this_val);
54820
0
}
54821
54822
static JSValue js_typed_array_toSorted(JSContext *ctx, JSValueConst this_val,
54823
                                       int argc, JSValueConst *argv)
54824
0
{
54825
0
    JSValue arr, ret;
54826
0
    JSObject *p;
54827
54828
0
    p = get_typed_array(ctx, this_val, /*is_dataview*/0);
54829
0
    if (!p)
54830
0
        return JS_EXCEPTION;
54831
0
    arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
54832
0
                                        p->class_id);
54833
0
    if (JS_IsException(arr))
54834
0
        return JS_EXCEPTION;
54835
0
    ret = js_typed_array_sort(ctx, arr, argc, argv);
54836
0
    JS_FreeValue(ctx, arr);
54837
0
    return ret;
54838
0
}
54839
54840
static const JSCFunctionListEntry js_typed_array_base_funcs[] = {
54841
    JS_CFUNC_DEF("from", 1, js_typed_array_from ),
54842
    JS_CFUNC_DEF("of", 0, js_typed_array_of ),
54843
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
54844
    //JS_CFUNC_DEF("__getLength", 2, js_typed_array___getLength ),
54845
    //JS_CFUNC_DEF("__create", 2, js_typed_array___create ),
54846
    //JS_CFUNC_DEF("__speciesCreate", 2, js_typed_array___speciesCreate ),
54847
};
54848
54849
static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = {
54850
    JS_CGETSET_DEF("length", js_typed_array_get_length, NULL ),
54851
    JS_CFUNC_DEF("at", 1, js_typed_array_at ),
54852
    JS_CFUNC_DEF("with", 2, js_typed_array_with ),
54853
    JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 0 ),
54854
    JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 0 ),
54855
    JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 0 ),
54856
    JS_CFUNC_DEF("set", 1, js_typed_array_set ),
54857
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_VALUE ),
54858
    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
54859
    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY ),
54860
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
54861
    JS_CGETSET_DEF("[Symbol.toStringTag]", js_typed_array_get_toStringTag, NULL ),
54862
    JS_CFUNC_DEF("copyWithin", 2, js_typed_array_copyWithin ),
54863
    JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every | special_TA ),
54864
    JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some | special_TA ),
54865
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach | special_TA ),
54866
    JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map | special_TA ),
54867
    JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter | special_TA ),
54868
    JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA ),
54869
    JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA ),
54870
    JS_CFUNC_DEF("fill", 1, js_typed_array_fill ),
54871
    JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, ArrayFind ),
54872
    JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, ArrayFindIndex ),
54873
    JS_CFUNC_MAGIC_DEF("findLast", 1, js_typed_array_find, ArrayFindLast ),
54874
    JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_typed_array_find, ArrayFindLastIndex ),
54875
    JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse ),
54876
    JS_CFUNC_DEF("toReversed", 0, js_typed_array_toReversed ),
54877
    JS_CFUNC_DEF("slice", 2, js_typed_array_slice ),
54878
    JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray ),
54879
    JS_CFUNC_DEF("sort", 1, js_typed_array_sort ),
54880
    JS_CFUNC_DEF("toSorted", 1, js_typed_array_toSorted ),
54881
    JS_CFUNC_MAGIC_DEF("join", 1, js_typed_array_join, 0 ),
54882
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_typed_array_join, 1 ),
54883
    JS_CFUNC_MAGIC_DEF("indexOf", 1, js_typed_array_indexOf, special_indexOf ),
54884
    JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_typed_array_indexOf, special_lastIndexOf ),
54885
    JS_CFUNC_MAGIC_DEF("includes", 1, js_typed_array_indexOf, special_includes ),
54886
    //JS_ALIAS_BASE_DEF("toString", "toString", 2 /* Array.prototype. */), @@@
54887
};
54888
54889
static JSValue js_typed_array_base_constructor(JSContext *ctx,
54890
                                               JSValueConst this_val,
54891
                                               int argc, JSValueConst *argv)
54892
0
{
54893
0
    return JS_ThrowTypeError(ctx, "cannot be called");
54894
0
}
54895
54896
/* 'obj' must be an allocated typed array object */
54897
static int typed_array_init(JSContext *ctx, JSValueConst obj,
54898
                            JSValue buffer, uint64_t offset, uint64_t len)
54899
0
{
54900
0
    JSTypedArray *ta;
54901
0
    JSObject *p, *pbuffer;
54902
0
    JSArrayBuffer *abuf;
54903
0
    int size_log2;
54904
54905
0
    p = JS_VALUE_GET_OBJ(obj);
54906
0
    size_log2 = typed_array_size_log2(p->class_id);
54907
0
    ta = js_malloc(ctx, sizeof(*ta));
54908
0
    if (!ta) {
54909
0
        JS_FreeValue(ctx, buffer);
54910
0
        return -1;
54911
0
    }
54912
0
    pbuffer = JS_VALUE_GET_OBJ(buffer);
54913
0
    abuf = pbuffer->u.array_buffer;
54914
0
    ta->obj = p;
54915
0
    ta->buffer = pbuffer;
54916
0
    ta->offset = offset;
54917
0
    ta->length = len << size_log2;
54918
0
    list_add_tail(&ta->link, &abuf->array_list);
54919
0
    p->u.typed_array = ta;
54920
0
    p->u.array.count = len;
54921
0
    p->u.array.u.ptr = abuf->data + offset;
54922
0
    return 0;
54923
0
}
54924
54925
54926
static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen,
54927
                                      JSValueConst obj, JSValueConst method)
54928
0
{
54929
0
    JSValue arr, iter, next_method = JS_UNDEFINED, val;
54930
0
    BOOL done;
54931
0
    uint32_t k;
54932
54933
0
    *plen = 0;
54934
0
    arr = JS_NewArray(ctx);
54935
0
    if (JS_IsException(arr))
54936
0
        return arr;
54937
0
    iter = JS_GetIterator2(ctx, obj, method);
54938
0
    if (JS_IsException(iter))
54939
0
        goto fail;
54940
0
    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
54941
0
    if (JS_IsException(next_method))
54942
0
        goto fail;
54943
0
    k = 0;
54944
0
    for(;;) {
54945
0
        val = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
54946
0
        if (JS_IsException(val))
54947
0
            goto fail;
54948
0
        if (done) {
54949
0
            JS_FreeValue(ctx, val);
54950
0
            break;
54951
0
        }
54952
0
        if (JS_CreateDataPropertyUint32(ctx, arr, k, val, JS_PROP_THROW) < 0)
54953
0
            goto fail;
54954
0
        k++;
54955
0
    }
54956
0
    JS_FreeValue(ctx, next_method);
54957
0
    JS_FreeValue(ctx, iter);
54958
0
    *plen = k;
54959
0
    return arr;
54960
0
 fail:
54961
0
    JS_FreeValue(ctx, next_method);
54962
0
    JS_FreeValue(ctx, iter);
54963
0
    JS_FreeValue(ctx, arr);
54964
0
    return JS_EXCEPTION;
54965
0
}
54966
54967
static JSValue js_typed_array_constructor_obj(JSContext *ctx,
54968
                                              JSValueConst new_target,
54969
                                              JSValueConst obj,
54970
                                              int classid)
54971
0
{
54972
0
    JSValue iter, ret, arr = JS_UNDEFINED, val, buffer;
54973
0
    uint32_t i;
54974
0
    int size_log2;
54975
0
    int64_t len;
54976
54977
0
    size_log2 = typed_array_size_log2(classid);
54978
0
    ret = js_create_from_ctor(ctx, new_target, classid);
54979
0
    if (JS_IsException(ret))
54980
0
        return JS_EXCEPTION;
54981
54982
0
    iter = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
54983
0
    if (JS_IsException(iter))
54984
0
        goto fail;
54985
0
    if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {
54986
0
        uint32_t len1;
54987
0
        arr = js_array_from_iterator(ctx, &len1, obj, iter);
54988
0
        JS_FreeValue(ctx, iter);
54989
0
        if (JS_IsException(arr))
54990
0
            goto fail;
54991
0
        len = len1;
54992
0
    } else {
54993
0
        if (js_get_length64(ctx, &len, obj))
54994
0
            goto fail;
54995
0
        arr = JS_DupValue(ctx, obj);
54996
0
    }
54997
54998
0
    buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
54999
0
                                          len << size_log2);
55000
0
    if (JS_IsException(buffer))
55001
0
        goto fail;
55002
0
    if (typed_array_init(ctx, ret, buffer, 0, len))
55003
0
        goto fail;
55004
55005
0
    for(i = 0; i < len; i++) {
55006
0
        val = JS_GetPropertyUint32(ctx, arr, i);
55007
0
        if (JS_IsException(val))
55008
0
            goto fail;
55009
0
        if (JS_SetPropertyUint32(ctx, ret, i, val) < 0)
55010
0
            goto fail;
55011
0
    }
55012
0
    JS_FreeValue(ctx, arr);
55013
0
    return ret;
55014
0
 fail:
55015
0
    JS_FreeValue(ctx, arr);
55016
0
    JS_FreeValue(ctx, ret);
55017
0
    return JS_EXCEPTION;
55018
0
}
55019
55020
static JSValue js_typed_array_constructor_ta(JSContext *ctx,
55021
                                             JSValueConst new_target,
55022
                                             JSValueConst src_obj,
55023
                                             int classid)
55024
0
{
55025
0
    JSObject *p, *src_buffer;
55026
0
    JSTypedArray *ta;
55027
0
    JSValue obj, buffer;
55028
0
    uint32_t len, i;
55029
0
    int size_log2;
55030
0
    JSArrayBuffer *src_abuf, *abuf;
55031
55032
0
    obj = js_create_from_ctor(ctx, new_target, classid);
55033
0
    if (JS_IsException(obj))
55034
0
        return obj;
55035
0
    p = JS_VALUE_GET_OBJ(src_obj);
55036
0
    if (typed_array_is_detached(ctx, p)) {
55037
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55038
0
        goto fail;
55039
0
    }
55040
0
    ta = p->u.typed_array;
55041
0
    len = p->u.array.count;
55042
0
    src_buffer = ta->buffer;
55043
0
    src_abuf = src_buffer->u.array_buffer;
55044
0
    size_log2 = typed_array_size_log2(classid);
55045
0
    buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
55046
0
                                          (uint64_t)len << size_log2);
55047
0
    if (JS_IsException(buffer))
55048
0
        goto fail;
55049
    /* necessary because it could have been detached */
55050
0
    if (typed_array_is_detached(ctx, p)) {
55051
0
        JS_FreeValue(ctx, buffer);
55052
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55053
0
        goto fail;
55054
0
    }
55055
0
    abuf = JS_GetOpaque(buffer, JS_CLASS_ARRAY_BUFFER);
55056
0
    if (typed_array_init(ctx, obj, buffer, 0, len))
55057
0
        goto fail;
55058
0
    if (p->class_id == classid) {
55059
        /* same type: copy the content */
55060
0
        memcpy(abuf->data, src_abuf->data + ta->offset, abuf->byte_length);
55061
0
    } else {
55062
0
        for(i = 0; i < len; i++) {
55063
0
            JSValue val;
55064
0
            val = JS_GetPropertyUint32(ctx, src_obj, i);
55065
0
            if (JS_IsException(val))
55066
0
                goto fail;
55067
0
            if (JS_SetPropertyUint32(ctx, obj, i, val) < 0)
55068
0
                goto fail;
55069
0
        }
55070
0
    }
55071
0
    return obj;
55072
0
 fail:
55073
0
    JS_FreeValue(ctx, obj);
55074
0
    return JS_EXCEPTION;
55075
0
}
55076
55077
static JSValue js_typed_array_constructor(JSContext *ctx,
55078
                                          JSValueConst new_target,
55079
                                          int argc, JSValueConst *argv,
55080
                                          int classid)
55081
0
{
55082
0
    JSValue buffer, obj;
55083
0
    JSArrayBuffer *abuf;
55084
0
    int size_log2;
55085
0
    uint64_t len, offset;
55086
55087
0
    size_log2 = typed_array_size_log2(classid);
55088
0
    if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) {
55089
0
        if (JS_ToIndex(ctx, &len, argv[0]))
55090
0
            return JS_EXCEPTION;
55091
0
        buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
55092
0
                                              len << size_log2);
55093
0
        if (JS_IsException(buffer))
55094
0
            return JS_EXCEPTION;
55095
0
        offset = 0;
55096
0
    } else {
55097
0
        JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
55098
0
        if (p->class_id == JS_CLASS_ARRAY_BUFFER ||
55099
0
            p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER) {
55100
0
            abuf = p->u.array_buffer;
55101
0
            if (JS_ToIndex(ctx, &offset, argv[1]))
55102
0
                return JS_EXCEPTION;
55103
0
            if (abuf->detached)
55104
0
                return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55105
0
            if ((offset & ((1 << size_log2) - 1)) != 0 ||
55106
0
                offset > abuf->byte_length)
55107
0
                return JS_ThrowRangeError(ctx, "invalid offset");
55108
0
            if (JS_IsUndefined(argv[2])) {
55109
0
                if ((abuf->byte_length & ((1 << size_log2) - 1)) != 0)
55110
0
                    goto invalid_length;
55111
0
                len = (abuf->byte_length - offset) >> size_log2;
55112
0
            } else {
55113
0
                if (JS_ToIndex(ctx, &len, argv[2]))
55114
0
                    return JS_EXCEPTION;
55115
0
                if (abuf->detached)
55116
0
                    return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55117
0
                if ((offset + (len << size_log2)) > abuf->byte_length) {
55118
0
                invalid_length:
55119
0
                    return JS_ThrowRangeError(ctx, "invalid length");
55120
0
                }
55121
0
            }
55122
0
            buffer = JS_DupValue(ctx, argv[0]);
55123
0
        } else {
55124
0
            if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
55125
0
                p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
55126
0
                return js_typed_array_constructor_ta(ctx, new_target, argv[0], classid);
55127
0
            } else {
55128
0
                return js_typed_array_constructor_obj(ctx, new_target, argv[0], classid);
55129
0
            }
55130
0
        }
55131
0
    }
55132
55133
0
    obj = js_create_from_ctor(ctx, new_target, classid);
55134
0
    if (JS_IsException(obj)) {
55135
0
        JS_FreeValue(ctx, buffer);
55136
0
        return JS_EXCEPTION;
55137
0
    }
55138
0
    if (typed_array_init(ctx, obj, buffer, offset, len)) {
55139
0
        JS_FreeValue(ctx, obj);
55140
0
        return JS_EXCEPTION;
55141
0
    }
55142
0
    return obj;
55143
0
}
55144
55145
static void js_typed_array_finalizer(JSRuntime *rt, JSValue val)
55146
0
{
55147
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
55148
0
    JSTypedArray *ta = p->u.typed_array;
55149
0
    if (ta) {
55150
        /* during the GC the finalizers are called in an arbitrary
55151
           order so the ArrayBuffer finalizer may have been called */
55152
0
        if (ta->link.next) {
55153
0
            list_del(&ta->link);
55154
0
        }
55155
0
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
55156
0
        js_free_rt(rt, ta);
55157
0
    }
55158
0
}
55159
55160
static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
55161
                                JS_MarkFunc *mark_func)
55162
0
{
55163
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
55164
0
    JSTypedArray *ta = p->u.typed_array;
55165
0
    if (ta) {
55166
0
        JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer), mark_func);
55167
0
    }
55168
0
}
55169
55170
static JSValue js_dataview_constructor(JSContext *ctx,
55171
                                       JSValueConst new_target,
55172
                                       int argc, JSValueConst *argv)
55173
0
{
55174
0
    JSArrayBuffer *abuf;
55175
0
    uint64_t offset;
55176
0
    uint32_t len;
55177
0
    JSValueConst buffer;
55178
0
    JSValue obj;
55179
0
    JSTypedArray *ta;
55180
0
    JSObject *p;
55181
55182
0
    buffer = argv[0];
55183
0
    abuf = js_get_array_buffer(ctx, buffer);
55184
0
    if (!abuf)
55185
0
        return JS_EXCEPTION;
55186
0
    offset = 0;
55187
0
    if (argc > 1) {
55188
0
        if (JS_ToIndex(ctx, &offset, argv[1]))
55189
0
            return JS_EXCEPTION;
55190
0
    }
55191
0
    if (abuf->detached)
55192
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55193
0
    if (offset > abuf->byte_length)
55194
0
        return JS_ThrowRangeError(ctx, "invalid byteOffset");
55195
0
    len = abuf->byte_length - offset;
55196
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
55197
0
        uint64_t l;
55198
0
        if (JS_ToIndex(ctx, &l, argv[2]))
55199
0
            return JS_EXCEPTION;
55200
0
        if (l > len)
55201
0
            return JS_ThrowRangeError(ctx, "invalid byteLength");
55202
0
        len = l;
55203
0
    }
55204
55205
0
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_DATAVIEW);
55206
0
    if (JS_IsException(obj))
55207
0
        return JS_EXCEPTION;
55208
0
    if (abuf->detached) {
55209
        /* could have been detached in js_create_from_ctor() */
55210
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55211
0
        goto fail;
55212
0
    }
55213
0
    ta = js_malloc(ctx, sizeof(*ta));
55214
0
    if (!ta) {
55215
0
    fail:
55216
0
        JS_FreeValue(ctx, obj);
55217
0
        return JS_EXCEPTION;
55218
0
    }
55219
0
    p = JS_VALUE_GET_OBJ(obj);
55220
0
    ta->obj = p;
55221
0
    ta->buffer = JS_VALUE_GET_OBJ(JS_DupValue(ctx, buffer));
55222
0
    ta->offset = offset;
55223
0
    ta->length = len;
55224
0
    list_add_tail(&ta->link, &abuf->array_list);
55225
0
    p->u.typed_array = ta;
55226
0
    return obj;
55227
0
}
55228
55229
static JSValue js_dataview_getValue(JSContext *ctx,
55230
                                    JSValueConst this_obj,
55231
                                    int argc, JSValueConst *argv, int class_id)
55232
0
{
55233
0
    JSTypedArray *ta;
55234
0
    JSArrayBuffer *abuf;
55235
0
    BOOL littleEndian, is_swap;
55236
0
    int size;
55237
0
    uint8_t *ptr;
55238
0
    uint32_t v;
55239
0
    uint64_t pos;
55240
55241
0
    ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
55242
0
    if (!ta)
55243
0
        return JS_EXCEPTION;
55244
0
    size = 1 << typed_array_size_log2(class_id);
55245
0
    if (JS_ToIndex(ctx, &pos, argv[0]))
55246
0
        return JS_EXCEPTION;
55247
0
    littleEndian = argc > 1 && JS_ToBool(ctx, argv[1]);
55248
0
    is_swap = littleEndian ^ !is_be();
55249
0
    abuf = ta->buffer->u.array_buffer;
55250
0
    if (abuf->detached)
55251
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55252
0
    if ((pos + size) > ta->length)
55253
0
        return JS_ThrowRangeError(ctx, "out of bound");
55254
0
    ptr = abuf->data + ta->offset + pos;
55255
55256
0
    switch(class_id) {
55257
0
    case JS_CLASS_INT8_ARRAY:
55258
0
        return JS_NewInt32(ctx, *(int8_t *)ptr);
55259
0
    case JS_CLASS_UINT8_ARRAY:
55260
0
        return JS_NewInt32(ctx, *(uint8_t *)ptr);
55261
0
    case JS_CLASS_INT16_ARRAY:
55262
0
        v = get_u16(ptr);
55263
0
        if (is_swap)
55264
0
            v = bswap16(v);
55265
0
        return JS_NewInt32(ctx, (int16_t)v);
55266
0
    case JS_CLASS_UINT16_ARRAY:
55267
0
        v = get_u16(ptr);
55268
0
        if (is_swap)
55269
0
            v = bswap16(v);
55270
0
        return JS_NewInt32(ctx, v);
55271
0
    case JS_CLASS_INT32_ARRAY:
55272
0
        v = get_u32(ptr);
55273
0
        if (is_swap)
55274
0
            v = bswap32(v);
55275
0
        return JS_NewInt32(ctx, v);
55276
0
    case JS_CLASS_UINT32_ARRAY:
55277
0
        v = get_u32(ptr);
55278
0
        if (is_swap)
55279
0
            v = bswap32(v);
55280
0
        return JS_NewUint32(ctx, v);
55281
0
    case JS_CLASS_BIG_INT64_ARRAY:
55282
0
        {
55283
0
            uint64_t v;
55284
0
            v = get_u64(ptr);
55285
0
            if (is_swap)
55286
0
                v = bswap64(v);
55287
0
            return JS_NewBigInt64(ctx, v);
55288
0
        }
55289
0
        break;
55290
0
    case JS_CLASS_BIG_UINT64_ARRAY:
55291
0
        {
55292
0
            uint64_t v;
55293
0
            v = get_u64(ptr);
55294
0
            if (is_swap)
55295
0
                v = bswap64(v);
55296
0
            return JS_NewBigUint64(ctx, v);
55297
0
        }
55298
0
        break;
55299
0
    case JS_CLASS_FLOAT32_ARRAY:
55300
0
        {
55301
0
            union {
55302
0
                float f;
55303
0
                uint32_t i;
55304
0
            } u;
55305
0
            v = get_u32(ptr);
55306
0
            if (is_swap)
55307
0
                v = bswap32(v);
55308
0
            u.i = v;
55309
0
            return __JS_NewFloat64(ctx, u.f);
55310
0
        }
55311
0
    case JS_CLASS_FLOAT64_ARRAY:
55312
0
        {
55313
0
            union {
55314
0
                double f;
55315
0
                uint64_t i;
55316
0
            } u;
55317
0
            u.i = get_u64(ptr);
55318
0
            if (is_swap)
55319
0
                u.i = bswap64(u.i);
55320
0
            return __JS_NewFloat64(ctx, u.f);
55321
0
        }
55322
0
    default:
55323
0
        abort();
55324
0
    }
55325
0
}
55326
55327
static JSValue js_dataview_setValue(JSContext *ctx,
55328
                                    JSValueConst this_obj,
55329
                                    int argc, JSValueConst *argv, int class_id)
55330
0
{
55331
0
    JSTypedArray *ta;
55332
0
    JSArrayBuffer *abuf;
55333
0
    BOOL littleEndian, is_swap;
55334
0
    int size;
55335
0
    uint8_t *ptr;
55336
0
    uint64_t v64;
55337
0
    uint32_t v;
55338
0
    uint64_t pos;
55339
0
    JSValueConst val;
55340
55341
0
    ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
55342
0
    if (!ta)
55343
0
        return JS_EXCEPTION;
55344
0
    size = 1 << typed_array_size_log2(class_id);
55345
0
    if (JS_ToIndex(ctx, &pos, argv[0]))
55346
0
        return JS_EXCEPTION;
55347
0
    val = argv[1];
55348
0
    v = 0; /* avoid warning */
55349
0
    v64 = 0; /* avoid warning */
55350
0
    if (class_id <= JS_CLASS_UINT32_ARRAY) {
55351
0
        if (JS_ToUint32(ctx, &v, val))
55352
0
            return JS_EXCEPTION;
55353
0
    } else if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
55354
0
        if (JS_ToBigInt64(ctx, (int64_t *)&v64, val))
55355
0
            return JS_EXCEPTION;
55356
0
    } else {
55357
0
        double d;
55358
0
        if (JS_ToFloat64(ctx, &d, val))
55359
0
            return JS_EXCEPTION;
55360
0
        if (class_id == JS_CLASS_FLOAT32_ARRAY) {
55361
0
            union {
55362
0
                float f;
55363
0
                uint32_t i;
55364
0
            } u;
55365
0
            u.f = d;
55366
0
            v = u.i;
55367
0
        } else {
55368
0
            JSFloat64Union u;
55369
0
            u.d = d;
55370
0
            v64 = u.u64;
55371
0
        }
55372
0
    }
55373
0
    littleEndian = argc > 2 && JS_ToBool(ctx, argv[2]);
55374
0
    is_swap = littleEndian ^ !is_be();
55375
0
    abuf = ta->buffer->u.array_buffer;
55376
0
    if (abuf->detached)
55377
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55378
0
    if ((pos + size) > ta->length)
55379
0
        return JS_ThrowRangeError(ctx, "out of bound");
55380
0
    ptr = abuf->data + ta->offset + pos;
55381
55382
0
    switch(class_id) {
55383
0
    case JS_CLASS_INT8_ARRAY:
55384
0
    case JS_CLASS_UINT8_ARRAY:
55385
0
        *ptr = v;
55386
0
        break;
55387
0
    case JS_CLASS_INT16_ARRAY:
55388
0
    case JS_CLASS_UINT16_ARRAY:
55389
0
        if (is_swap)
55390
0
            v = bswap16(v);
55391
0
        put_u16(ptr, v);
55392
0
        break;
55393
0
    case JS_CLASS_INT32_ARRAY:
55394
0
    case JS_CLASS_UINT32_ARRAY:
55395
0
    case JS_CLASS_FLOAT32_ARRAY:
55396
0
        if (is_swap)
55397
0
            v = bswap32(v);
55398
0
        put_u32(ptr, v);
55399
0
        break;
55400
0
    case JS_CLASS_BIG_INT64_ARRAY:
55401
0
    case JS_CLASS_BIG_UINT64_ARRAY:
55402
0
    case JS_CLASS_FLOAT64_ARRAY:
55403
0
        if (is_swap)
55404
0
            v64 = bswap64(v64);
55405
0
        put_u64(ptr, v64);
55406
0
        break;
55407
0
    default:
55408
0
        abort();
55409
0
    }
55410
0
    return JS_UNDEFINED;
55411
0
}
55412
55413
static const JSCFunctionListEntry js_dataview_proto_funcs[] = {
55414
    JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 1 ),
55415
    JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 1 ),
55416
    JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 1 ),
55417
    JS_CFUNC_MAGIC_DEF("getInt8", 1, js_dataview_getValue, JS_CLASS_INT8_ARRAY ),
55418
    JS_CFUNC_MAGIC_DEF("getUint8", 1, js_dataview_getValue, JS_CLASS_UINT8_ARRAY ),
55419
    JS_CFUNC_MAGIC_DEF("getInt16", 1, js_dataview_getValue, JS_CLASS_INT16_ARRAY ),
55420
    JS_CFUNC_MAGIC_DEF("getUint16", 1, js_dataview_getValue, JS_CLASS_UINT16_ARRAY ),
55421
    JS_CFUNC_MAGIC_DEF("getInt32", 1, js_dataview_getValue, JS_CLASS_INT32_ARRAY ),
55422
    JS_CFUNC_MAGIC_DEF("getUint32", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY ),
55423
    JS_CFUNC_MAGIC_DEF("getBigInt64", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY ),
55424
    JS_CFUNC_MAGIC_DEF("getBigUint64", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY ),
55425
    JS_CFUNC_MAGIC_DEF("getFloat32", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY ),
55426
    JS_CFUNC_MAGIC_DEF("getFloat64", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY ),
55427
    JS_CFUNC_MAGIC_DEF("setInt8", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY ),
55428
    JS_CFUNC_MAGIC_DEF("setUint8", 2, js_dataview_setValue, JS_CLASS_UINT8_ARRAY ),
55429
    JS_CFUNC_MAGIC_DEF("setInt16", 2, js_dataview_setValue, JS_CLASS_INT16_ARRAY ),
55430
    JS_CFUNC_MAGIC_DEF("setUint16", 2, js_dataview_setValue, JS_CLASS_UINT16_ARRAY ),
55431
    JS_CFUNC_MAGIC_DEF("setInt32", 2, js_dataview_setValue, JS_CLASS_INT32_ARRAY ),
55432
    JS_CFUNC_MAGIC_DEF("setUint32", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY ),
55433
    JS_CFUNC_MAGIC_DEF("setBigInt64", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY ),
55434
    JS_CFUNC_MAGIC_DEF("setBigUint64", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY ),
55435
    JS_CFUNC_MAGIC_DEF("setFloat32", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY ),
55436
    JS_CFUNC_MAGIC_DEF("setFloat64", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY ),
55437
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DataView", JS_PROP_CONFIGURABLE ),
55438
};
55439
55440
/* Atomics */
55441
#ifdef CONFIG_ATOMICS
55442
55443
typedef enum AtomicsOpEnum {
55444
    ATOMICS_OP_ADD,
55445
    ATOMICS_OP_AND,
55446
    ATOMICS_OP_OR,
55447
    ATOMICS_OP_SUB,
55448
    ATOMICS_OP_XOR,
55449
    ATOMICS_OP_EXCHANGE,
55450
    ATOMICS_OP_COMPARE_EXCHANGE,
55451
    ATOMICS_OP_LOAD,
55452
} AtomicsOpEnum;
55453
55454
static void *js_atomics_get_ptr(JSContext *ctx,
55455
                                JSArrayBuffer **pabuf,
55456
                                int *psize_log2, JSClassID *pclass_id,
55457
                                JSValueConst obj, JSValueConst idx_val,
55458
                                int is_waitable)
55459
0
{
55460
0
    JSObject *p;
55461
0
    JSTypedArray *ta;
55462
0
    JSArrayBuffer *abuf;
55463
0
    void *ptr;
55464
0
    uint64_t idx;
55465
0
    BOOL err;
55466
0
    int size_log2;
55467
55468
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
55469
0
        goto fail;
55470
0
    p = JS_VALUE_GET_OBJ(obj);
55471
0
    if (is_waitable)
55472
0
        err = (p->class_id != JS_CLASS_INT32_ARRAY &&
55473
0
               p->class_id != JS_CLASS_BIG_INT64_ARRAY);
55474
0
    else
55475
0
        err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
55476
0
                p->class_id <= JS_CLASS_BIG_UINT64_ARRAY);
55477
0
    if (err) {
55478
0
    fail:
55479
0
        JS_ThrowTypeError(ctx, "integer TypedArray expected");
55480
0
        return NULL;
55481
0
    }
55482
0
    ta = p->u.typed_array;
55483
0
    abuf = ta->buffer->u.array_buffer;
55484
0
    if (!abuf->shared) {
55485
0
        if (is_waitable == 2) {
55486
0
            JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray");
55487
0
            return NULL;
55488
0
        }
55489
0
        if (abuf->detached) {
55490
0
            JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55491
0
            return NULL;
55492
0
        }
55493
0
    }
55494
0
    if (JS_ToIndex(ctx, &idx, idx_val)) {
55495
0
        return NULL;
55496
0
    }
55497
    /* if the array buffer is detached, p->u.array.count = 0 */
55498
0
    if (idx >= p->u.array.count) {
55499
0
        JS_ThrowRangeError(ctx, "out-of-bound access");
55500
0
        return NULL;
55501
0
    }
55502
0
    size_log2 = typed_array_size_log2(p->class_id);
55503
0
    ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);
55504
0
    if (pabuf)
55505
0
        *pabuf = abuf;
55506
0
    if (psize_log2)
55507
0
        *psize_log2 = size_log2;
55508
0
    if (pclass_id)
55509
0
        *pclass_id = p->class_id;
55510
0
    return ptr;
55511
0
}
55512
55513
static JSValue js_atomics_op(JSContext *ctx,
55514
                             JSValueConst this_obj,
55515
                             int argc, JSValueConst *argv, int op)
55516
0
{
55517
0
    int size_log2;
55518
0
    uint64_t v, a, rep_val;
55519
0
    void *ptr;
55520
0
    JSValue ret;
55521
0
    JSClassID class_id;
55522
0
    JSArrayBuffer *abuf;
55523
55524
0
    ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, &class_id,
55525
0
                             argv[0], argv[1], 0);
55526
0
    if (!ptr)
55527
0
        return JS_EXCEPTION;
55528
0
    rep_val = 0;
55529
0
    if (op == ATOMICS_OP_LOAD) {
55530
0
        v = 0;
55531
0
    } else {
55532
0
        if (size_log2 == 3) {
55533
0
            int64_t v64;
55534
0
            if (JS_ToBigInt64(ctx, &v64, argv[2]))
55535
0
                return JS_EXCEPTION;
55536
0
            v = v64;
55537
0
            if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
55538
0
                if (JS_ToBigInt64(ctx, &v64, argv[3]))
55539
0
                    return JS_EXCEPTION;
55540
0
                rep_val = v64;
55541
0
            }
55542
0
        } else {
55543
0
                uint32_t v32;
55544
0
                if (JS_ToUint32(ctx, &v32, argv[2]))
55545
0
                    return JS_EXCEPTION;
55546
0
                v = v32;
55547
0
                if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
55548
0
                    if (JS_ToUint32(ctx, &v32, argv[3]))
55549
0
                        return JS_EXCEPTION;
55550
0
                    rep_val = v32;
55551
0
                }
55552
0
        }
55553
0
        if (abuf->detached)
55554
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55555
0
   }
55556
55557
0
   switch(op | (size_log2 << 3)) {
55558
55559
0
#define OP(op_name, func_name)                          \
55560
0
    case ATOMICS_OP_ ## op_name | (0 << 3):             \
55561
0
       a = func_name((_Atomic(uint8_t) *)ptr, v);       \
55562
0
       break;                                           \
55563
0
    case ATOMICS_OP_ ## op_name | (1 << 3):             \
55564
0
        a = func_name((_Atomic(uint16_t) *)ptr, v);     \
55565
0
        break;                                          \
55566
0
    case ATOMICS_OP_ ## op_name | (2 << 3):             \
55567
0
        a = func_name((_Atomic(uint32_t) *)ptr, v);     \
55568
0
        break;                                          \
55569
0
    case ATOMICS_OP_ ## op_name | (3 << 3):             \
55570
0
        a = func_name((_Atomic(uint64_t) *)ptr, v);     \
55571
0
        break;
55572
55573
0
        OP(ADD, atomic_fetch_add)
55574
0
        OP(AND, atomic_fetch_and)
55575
0
        OP(OR, atomic_fetch_or)
55576
0
        OP(SUB, atomic_fetch_sub)
55577
0
        OP(XOR, atomic_fetch_xor)
55578
0
        OP(EXCHANGE, atomic_exchange)
55579
0
#undef OP
55580
55581
0
    case ATOMICS_OP_LOAD | (0 << 3):
55582
0
        a = atomic_load((_Atomic(uint8_t) *)ptr);
55583
0
        break;
55584
0
    case ATOMICS_OP_LOAD | (1 << 3):
55585
0
        a = atomic_load((_Atomic(uint16_t) *)ptr);
55586
0
        break;
55587
0
    case ATOMICS_OP_LOAD | (2 << 3):
55588
0
        a = atomic_load((_Atomic(uint32_t) *)ptr);
55589
0
        break;
55590
0
    case ATOMICS_OP_LOAD | (3 << 3):
55591
0
        a = atomic_load((_Atomic(uint64_t) *)ptr);
55592
0
        break;
55593
55594
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3):
55595
0
        {
55596
0
            uint8_t v1 = v;
55597
0
            atomic_compare_exchange_strong((_Atomic(uint8_t) *)ptr, &v1, rep_val);
55598
0
            a = v1;
55599
0
        }
55600
0
        break;
55601
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (1 << 3):
55602
0
        {
55603
0
            uint16_t v1 = v;
55604
0
            atomic_compare_exchange_strong((_Atomic(uint16_t) *)ptr, &v1, rep_val);
55605
0
            a = v1;
55606
0
        }
55607
0
        break;
55608
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (2 << 3):
55609
0
        {
55610
0
            uint32_t v1 = v;
55611
0
            atomic_compare_exchange_strong((_Atomic(uint32_t) *)ptr, &v1, rep_val);
55612
0
            a = v1;
55613
0
        }
55614
0
        break;
55615
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3):
55616
0
        {
55617
0
            uint64_t v1 = v;
55618
0
            atomic_compare_exchange_strong((_Atomic(uint64_t) *)ptr, &v1, rep_val);
55619
0
            a = v1;
55620
0
        }
55621
0
        break;
55622
0
    default:
55623
0
        abort();
55624
0
    }
55625
55626
0
    switch(class_id) {
55627
0
    case JS_CLASS_INT8_ARRAY:
55628
0
        a = (int8_t)a;
55629
0
        goto done;
55630
0
    case JS_CLASS_UINT8_ARRAY:
55631
0
        a = (uint8_t)a;
55632
0
        goto done;
55633
0
    case JS_CLASS_INT16_ARRAY:
55634
0
        a = (int16_t)a;
55635
0
        goto done;
55636
0
    case JS_CLASS_UINT16_ARRAY:
55637
0
        a = (uint16_t)a;
55638
0
        goto done;
55639
0
    case JS_CLASS_INT32_ARRAY:
55640
0
    done:
55641
0
        ret = JS_NewInt32(ctx, a);
55642
0
        break;
55643
0
    case JS_CLASS_UINT32_ARRAY:
55644
0
        ret = JS_NewUint32(ctx, a);
55645
0
        break;
55646
0
    case JS_CLASS_BIG_INT64_ARRAY:
55647
0
        ret = JS_NewBigInt64(ctx, a);
55648
0
        break;
55649
0
    case JS_CLASS_BIG_UINT64_ARRAY:
55650
0
        ret = JS_NewBigUint64(ctx, a);
55651
0
        break;
55652
0
    default:
55653
0
        abort();
55654
0
    }
55655
0
    return ret;
55656
0
}
55657
55658
static JSValue js_atomics_store(JSContext *ctx,
55659
                                JSValueConst this_obj,
55660
                                int argc, JSValueConst *argv)
55661
0
{
55662
0
    int size_log2;
55663
0
    void *ptr;
55664
0
    JSValue ret;
55665
0
    JSArrayBuffer *abuf;
55666
55667
0
    ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, NULL,
55668
0
                             argv[0], argv[1], 0);
55669
0
    if (!ptr)
55670
0
        return JS_EXCEPTION;
55671
0
    if (size_log2 == 3) {
55672
0
        int64_t v64;
55673
0
        ret = JS_ToBigIntValueFree(ctx, JS_DupValue(ctx, argv[2]));
55674
0
        if (JS_IsException(ret))
55675
0
            return ret;
55676
0
        if (JS_ToBigInt64(ctx, &v64, ret)) {
55677
0
            JS_FreeValue(ctx, ret);
55678
0
            return JS_EXCEPTION;
55679
0
        }
55680
0
        if (abuf->detached)
55681
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55682
0
        atomic_store((_Atomic(uint64_t) *)ptr, v64);
55683
0
    } else {
55684
0
        uint32_t v;
55685
        /* XXX: spec, would be simpler to return the written value */
55686
0
        ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2]));
55687
0
        if (JS_IsException(ret))
55688
0
            return ret;
55689
0
        if (JS_ToUint32(ctx, &v, ret)) {
55690
0
            JS_FreeValue(ctx, ret);
55691
0
            return JS_EXCEPTION;
55692
0
        }
55693
0
        if (abuf->detached)
55694
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55695
0
        switch(size_log2) {
55696
0
        case 0:
55697
0
            atomic_store((_Atomic(uint8_t) *)ptr, v);
55698
0
            break;
55699
0
        case 1:
55700
0
            atomic_store((_Atomic(uint16_t) *)ptr, v);
55701
0
            break;
55702
0
        case 2:
55703
0
            atomic_store((_Atomic(uint32_t) *)ptr, v);
55704
0
            break;
55705
0
        default:
55706
0
            abort();
55707
0
        }
55708
0
    }
55709
0
    return ret;
55710
0
}
55711
55712
static JSValue js_atomics_isLockFree(JSContext *ctx,
55713
                                     JSValueConst this_obj,
55714
                                     int argc, JSValueConst *argv)
55715
0
{
55716
0
    int v, ret;
55717
0
    if (JS_ToInt32Sat(ctx, &v, argv[0]))
55718
0
        return JS_EXCEPTION;
55719
0
    ret = (v == 1 || v == 2 || v == 4 || v == 8);
55720
0
    return JS_NewBool(ctx, ret);
55721
0
}
55722
55723
typedef struct JSAtomicsWaiter {
55724
    struct list_head link;
55725
    BOOL linked;
55726
    pthread_cond_t cond;
55727
    int32_t *ptr;
55728
} JSAtomicsWaiter;
55729
55730
static pthread_mutex_t js_atomics_mutex = PTHREAD_MUTEX_INITIALIZER;
55731
static struct list_head js_atomics_waiter_list =
55732
    LIST_HEAD_INIT(js_atomics_waiter_list);
55733
55734
static JSValue js_atomics_wait(JSContext *ctx,
55735
                               JSValueConst this_obj,
55736
                               int argc, JSValueConst *argv)
55737
0
{
55738
0
    int64_t v;
55739
0
    int32_t v32;
55740
0
    void *ptr;
55741
0
    int64_t timeout;
55742
0
    struct timespec ts;
55743
0
    JSAtomicsWaiter waiter_s, *waiter;
55744
0
    int ret, size_log2, res;
55745
0
    double d;
55746
55747
0
    ptr = js_atomics_get_ptr(ctx, NULL, &size_log2, NULL,
55748
0
                             argv[0], argv[1], 2);
55749
0
    if (!ptr)
55750
0
        return JS_EXCEPTION;
55751
0
    if (size_log2 == 3) {
55752
0
        if (JS_ToBigInt64(ctx, &v, argv[2]))
55753
0
            return JS_EXCEPTION;
55754
0
    } else {
55755
0
        if (JS_ToInt32(ctx, &v32, argv[2]))
55756
0
            return JS_EXCEPTION;
55757
0
        v = v32;
55758
0
    }
55759
0
    if (JS_ToFloat64(ctx, &d, argv[3]))
55760
0
        return JS_EXCEPTION;
55761
    /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */
55762
0
    if (isnan(d) || d >= 0x1p63)
55763
0
        timeout = INT64_MAX;
55764
0
    else if (d < 0)
55765
0
        timeout = 0;
55766
0
    else
55767
0
        timeout = (int64_t)d;
55768
0
    if (!ctx->rt->can_block)
55769
0
        return JS_ThrowTypeError(ctx, "cannot block in this thread");
55770
55771
    /* XXX: inefficient if large number of waiters, should hash on
55772
       'ptr' value */
55773
    /* XXX: use Linux futexes when available ? */
55774
0
    pthread_mutex_lock(&js_atomics_mutex);
55775
0
    if (size_log2 == 3) {
55776
0
        res = *(int64_t *)ptr != v;
55777
0
    } else {
55778
0
        res = *(int32_t *)ptr != v;
55779
0
    }
55780
0
    if (res) {
55781
0
        pthread_mutex_unlock(&js_atomics_mutex);
55782
0
        return JS_AtomToString(ctx, JS_ATOM_not_equal);
55783
0
    }
55784
55785
0
    waiter = &waiter_s;
55786
0
    waiter->ptr = ptr;
55787
0
    pthread_cond_init(&waiter->cond, NULL);
55788
0
    waiter->linked = TRUE;
55789
0
    list_add_tail(&waiter->link, &js_atomics_waiter_list);
55790
55791
0
    if (timeout == INT64_MAX) {
55792
0
        pthread_cond_wait(&waiter->cond, &js_atomics_mutex);
55793
0
        ret = 0;
55794
0
    } else {
55795
        /* XXX: use clock monotonic */
55796
0
        clock_gettime(CLOCK_REALTIME, &ts);
55797
0
        ts.tv_sec += timeout / 1000;
55798
0
        ts.tv_nsec += (timeout % 1000) * 1000000;
55799
0
        if (ts.tv_nsec >= 1000000000) {
55800
0
            ts.tv_nsec -= 1000000000;
55801
0
            ts.tv_sec++;
55802
0
        }
55803
0
        ret = pthread_cond_timedwait(&waiter->cond, &js_atomics_mutex,
55804
0
                                     &ts);
55805
0
    }
55806
0
    if (waiter->linked)
55807
0
        list_del(&waiter->link);
55808
0
    pthread_mutex_unlock(&js_atomics_mutex);
55809
0
    pthread_cond_destroy(&waiter->cond);
55810
0
    if (ret == ETIMEDOUT) {
55811
0
        return JS_AtomToString(ctx, JS_ATOM_timed_out);
55812
0
    } else {
55813
0
        return JS_AtomToString(ctx, JS_ATOM_ok);
55814
0
    }
55815
0
}
55816
55817
static JSValue js_atomics_notify(JSContext *ctx,
55818
                                 JSValueConst this_obj,
55819
                                 int argc, JSValueConst *argv)
55820
0
{
55821
0
    struct list_head *el, *el1, waiter_list;
55822
0
    int32_t count, n;
55823
0
    void *ptr;
55824
0
    JSAtomicsWaiter *waiter;
55825
0
    JSArrayBuffer *abuf;
55826
55827
0
    ptr = js_atomics_get_ptr(ctx, &abuf, NULL, NULL, argv[0], argv[1], 1);
55828
0
    if (!ptr)
55829
0
        return JS_EXCEPTION;
55830
55831
0
    if (JS_IsUndefined(argv[2])) {
55832
0
        count = INT32_MAX;
55833
0
    } else {
55834
0
        if (JS_ToInt32Clamp(ctx, &count, argv[2], 0, INT32_MAX, 0))
55835
0
            return JS_EXCEPTION;
55836
0
    }
55837
0
    if (abuf->detached)
55838
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55839
55840
0
    n = 0;
55841
0
    if (abuf->shared && count > 0) {
55842
0
        pthread_mutex_lock(&js_atomics_mutex);
55843
0
        init_list_head(&waiter_list);
55844
0
        list_for_each_safe(el, el1, &js_atomics_waiter_list) {
55845
0
            waiter = list_entry(el, JSAtomicsWaiter, link);
55846
0
            if (waiter->ptr == ptr) {
55847
0
                list_del(&waiter->link);
55848
0
                waiter->linked = FALSE;
55849
0
                list_add_tail(&waiter->link, &waiter_list);
55850
0
                n++;
55851
0
                if (n >= count)
55852
0
                    break;
55853
0
            }
55854
0
        }
55855
0
        list_for_each(el, &waiter_list) {
55856
0
            waiter = list_entry(el, JSAtomicsWaiter, link);
55857
0
            pthread_cond_signal(&waiter->cond);
55858
0
        }
55859
0
        pthread_mutex_unlock(&js_atomics_mutex);
55860
0
    }
55861
0
    return JS_NewInt32(ctx, n);
55862
0
}
55863
55864
static const JSCFunctionListEntry js_atomics_funcs[] = {
55865
    JS_CFUNC_MAGIC_DEF("add", 3, js_atomics_op, ATOMICS_OP_ADD ),
55866
    JS_CFUNC_MAGIC_DEF("and", 3, js_atomics_op, ATOMICS_OP_AND ),
55867
    JS_CFUNC_MAGIC_DEF("or", 3, js_atomics_op, ATOMICS_OP_OR ),
55868
    JS_CFUNC_MAGIC_DEF("sub", 3, js_atomics_op, ATOMICS_OP_SUB ),
55869
    JS_CFUNC_MAGIC_DEF("xor", 3, js_atomics_op, ATOMICS_OP_XOR ),
55870
    JS_CFUNC_MAGIC_DEF("exchange", 3, js_atomics_op, ATOMICS_OP_EXCHANGE ),
55871
    JS_CFUNC_MAGIC_DEF("compareExchange", 4, js_atomics_op, ATOMICS_OP_COMPARE_EXCHANGE ),
55872
    JS_CFUNC_MAGIC_DEF("load", 2, js_atomics_op, ATOMICS_OP_LOAD ),
55873
    JS_CFUNC_DEF("store", 3, js_atomics_store ),
55874
    JS_CFUNC_DEF("isLockFree", 1, js_atomics_isLockFree ),
55875
    JS_CFUNC_DEF("wait", 4, js_atomics_wait ),
55876
    JS_CFUNC_DEF("notify", 3, js_atomics_notify ),
55877
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Atomics", JS_PROP_CONFIGURABLE ),
55878
};
55879
55880
static const JSCFunctionListEntry js_atomics_obj[] = {
55881
    JS_OBJECT_DEF("Atomics", js_atomics_funcs, countof(js_atomics_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
55882
};
55883
55884
void JS_AddIntrinsicAtomics(JSContext *ctx)
55885
39
{
55886
    /* add Atomics as autoinit object */
55887
39
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_atomics_obj, countof(js_atomics_obj));
55888
39
}
55889
55890
#endif /* CONFIG_ATOMICS */
55891
55892
void JS_AddIntrinsicTypedArrays(JSContext *ctx)
55893
39
{
55894
39
    JSValue typed_array_base_proto, typed_array_base_func;
55895
39
    JSValueConst array_buffer_func, shared_array_buffer_func;
55896
39
    int i;
55897
55898
39
    ctx->class_proto[JS_CLASS_ARRAY_BUFFER] = JS_NewObject(ctx);
55899
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_BUFFER],
55900
39
                               js_array_buffer_proto_funcs,
55901
39
                               countof(js_array_buffer_proto_funcs));
55902
55903
39
    array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "ArrayBuffer",
55904
39
                                                 js_array_buffer_constructor, 1,
55905
39
                                                 ctx->class_proto[JS_CLASS_ARRAY_BUFFER]);
55906
39
    JS_SetPropertyFunctionList(ctx, array_buffer_func,
55907
39
                               js_array_buffer_funcs,
55908
39
                               countof(js_array_buffer_funcs));
55909
55910
39
    ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER] = JS_NewObject(ctx);
55911
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER],
55912
39
                               js_shared_array_buffer_proto_funcs,
55913
39
                               countof(js_shared_array_buffer_proto_funcs));
55914
55915
39
    shared_array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "SharedArrayBuffer",
55916
39
                                                 js_shared_array_buffer_constructor, 1,
55917
39
                                                 ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER]);
55918
39
    JS_SetPropertyFunctionList(ctx, shared_array_buffer_func,
55919
39
                               js_shared_array_buffer_funcs,
55920
39
                               countof(js_shared_array_buffer_funcs));
55921
55922
39
    typed_array_base_proto = JS_NewObject(ctx);
55923
39
    JS_SetPropertyFunctionList(ctx, typed_array_base_proto,
55924
39
                               js_typed_array_base_proto_funcs,
55925
39
                               countof(js_typed_array_base_proto_funcs));
55926
55927
    /* TypedArray.prototype.toString must be the same object as Array.prototype.toString */
55928
39
    JSValue obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_toString);
55929
    /* XXX: should use alias method in JSCFunctionListEntry */ //@@@
55930
39
    JS_DefinePropertyValue(ctx, typed_array_base_proto, JS_ATOM_toString, obj,
55931
39
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
55932
55933
39
    typed_array_base_func = JS_NewCFunction(ctx, js_typed_array_base_constructor,
55934
39
                                            "TypedArray", 0);
55935
39
    JS_SetPropertyFunctionList(ctx, typed_array_base_func,
55936
39
                               js_typed_array_base_funcs,
55937
39
                               countof(js_typed_array_base_funcs));
55938
39
    JS_SetConstructor(ctx, typed_array_base_func, typed_array_base_proto);
55939
55940
    /* Used to squelch a -Wcast-function-type warning. */
55941
39
    JSCFunctionType ft = { .generic_magic = js_typed_array_constructor };
55942
468
    for(i = JS_CLASS_UINT8C_ARRAY; i < JS_CLASS_UINT8C_ARRAY + JS_TYPED_ARRAY_COUNT; i++) {
55943
429
        JSValue func_obj;
55944
429
        char buf[ATOM_GET_STR_BUF_SIZE];
55945
429
        const char *name;
55946
55947
429
        ctx->class_proto[i] = JS_NewObjectProto(ctx, typed_array_base_proto);
55948
429
        JS_DefinePropertyValueStr(ctx, ctx->class_proto[i],
55949
429
                                  "BYTES_PER_ELEMENT",
55950
429
                                  JS_NewInt32(ctx, 1 << typed_array_size_log2(i)),
55951
429
                                  0);
55952
429
        name = JS_AtomGetStr(ctx, buf, sizeof(buf),
55953
429
                             JS_ATOM_Uint8ClampedArray + i - JS_CLASS_UINT8C_ARRAY);
55954
429
        func_obj = JS_NewCFunction3(ctx, ft.generic,
55955
429
                                    name, 3, JS_CFUNC_constructor_magic, i,
55956
429
                                    typed_array_base_func);
55957
429
        JS_NewGlobalCConstructor2(ctx, func_obj, name, ctx->class_proto[i]);
55958
429
        JS_DefinePropertyValueStr(ctx, func_obj,
55959
429
                                  "BYTES_PER_ELEMENT",
55960
429
                                  JS_NewInt32(ctx, 1 << typed_array_size_log2(i)),
55961
429
                                  0);
55962
429
    }
55963
39
    JS_FreeValue(ctx, typed_array_base_proto);
55964
39
    JS_FreeValue(ctx, typed_array_base_func);
55965
55966
    /* DataView */
55967
39
    ctx->class_proto[JS_CLASS_DATAVIEW] = JS_NewObject(ctx);
55968
39
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATAVIEW],
55969
39
                               js_dataview_proto_funcs,
55970
39
                               countof(js_dataview_proto_funcs));
55971
39
    JS_NewGlobalCConstructorOnly(ctx, "DataView",
55972
39
                                 js_dataview_constructor, 1,
55973
39
                                 ctx->class_proto[JS_CLASS_DATAVIEW]);
55974
    /* Atomics */
55975
39
#ifdef CONFIG_ATOMICS
55976
39
    JS_AddIntrinsicAtomics(ctx);
55977
39
#endif
55978
39
}