Coverage Report

Created: 2023-11-19 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
#ifdef CONFIG_BIGNUM
48
#include "libbf.h"
49
#endif
50
51
1.33M
#define OPTIMIZE         1
52
#define SHORT_OPCODES    1
53
#if defined(EMSCRIPTEN)
54
#define DIRECT_DISPATCH  0
55
#else
56
#define DIRECT_DISPATCH  1
57
#endif
58
59
#if defined(__APPLE__)
60
#define MALLOC_OVERHEAD  0
61
#else
62
12.8M
#define MALLOC_OVERHEAD  8
63
#endif
64
65
#if !defined(_WIN32)
66
/* define it if printf uses the RNDN rounding mode instead of RNDNA */
67
#define CONFIG_PRINTF_RNDN
68
#endif
69
70
/* define to include Atomics.* operations which depend on the OS
71
   threads */
72
#if !defined(EMSCRIPTEN)
73
#define CONFIG_ATOMICS
74
#endif
75
76
#if !defined(EMSCRIPTEN)
77
/* enable stack limitation */
78
#define CONFIG_STACK_CHECK
79
#endif
80
81
82
/* dump object free */
83
//#define DUMP_FREE
84
//#define DUMP_CLOSURE
85
/* dump the bytecode of the compiled functions: combination of bits
86
   1: dump pass 3 final byte code
87
   2: dump pass 2 code
88
   4: dump pass 1 code
89
   8: dump stdlib functions
90
  16: dump bytecode in hex
91
  32: dump line number table
92
 */
93
//#define DUMP_BYTECODE  (1)
94
/* dump the occurence of the automatic GC */
95
//#define DUMP_GC
96
/* dump objects freed by the garbage collector */
97
//#define DUMP_GC_FREE
98
/* dump objects leaking when freeing the runtime */
99
//#define DUMP_LEAKS  1
100
/* dump memory usage before running the garbage collector */
101
//#define DUMP_MEM
102
//#define DUMP_OBJECTS    /* dump objects in JS_FreeContext */
103
//#define DUMP_ATOMS      /* dump atoms in JS_FreeContext */
104
//#define DUMP_SHAPES     /* dump shapes in JS_FreeContext */
105
//#define DUMP_MODULE_RESOLVE
106
//#define DUMP_PROMISE
107
//#define DUMP_READ_OBJECT
108
109
/* test the GC by forcing it before each object allocation */
110
//#define FORCE_GC_AT_MALLOC
111
112
#ifdef CONFIG_ATOMICS
113
#include <pthread.h>
114
#include <stdatomic.h>
115
#include <errno.h>
116
#endif
117
118
enum {
119
    /* classid tag        */    /* union usage   | properties */
120
    JS_CLASS_OBJECT = 1,        /* must be first */
121
    JS_CLASS_ARRAY,             /* u.array       | length */
122
    JS_CLASS_ERROR,
123
    JS_CLASS_NUMBER,            /* u.object_data */
124
    JS_CLASS_STRING,            /* u.object_data */
125
    JS_CLASS_BOOLEAN,           /* u.object_data */
126
    JS_CLASS_SYMBOL,            /* u.object_data */
127
    JS_CLASS_ARGUMENTS,         /* u.array       | length */
128
    JS_CLASS_MAPPED_ARGUMENTS,  /*               | length */
129
    JS_CLASS_DATE,              /* u.object_data */
130
    JS_CLASS_MODULE_NS,
131
    JS_CLASS_C_FUNCTION,        /* u.cfunc */
132
    JS_CLASS_BYTECODE_FUNCTION, /* u.func */
133
    JS_CLASS_BOUND_FUNCTION,    /* u.bound_function */
134
    JS_CLASS_C_FUNCTION_DATA,   /* u.c_function_data_record */
135
    JS_CLASS_GENERATOR_FUNCTION, /* u.func */
136
    JS_CLASS_FOR_IN_ITERATOR,   /* u.for_in_iterator */
137
    JS_CLASS_REGEXP,            /* u.regexp */
138
    JS_CLASS_ARRAY_BUFFER,      /* u.array_buffer */
139
    JS_CLASS_SHARED_ARRAY_BUFFER, /* u.array_buffer */
140
    JS_CLASS_UINT8C_ARRAY,      /* u.array (typed_array) */
141
    JS_CLASS_INT8_ARRAY,        /* u.array (typed_array) */
142
    JS_CLASS_UINT8_ARRAY,       /* u.array (typed_array) */
143
    JS_CLASS_INT16_ARRAY,       /* u.array (typed_array) */
144
    JS_CLASS_UINT16_ARRAY,      /* u.array (typed_array) */
145
    JS_CLASS_INT32_ARRAY,       /* u.array (typed_array) */
146
    JS_CLASS_UINT32_ARRAY,      /* u.array (typed_array) */
147
#ifdef CONFIG_BIGNUM
148
    JS_CLASS_BIG_INT64_ARRAY,   /* u.array (typed_array) */
149
    JS_CLASS_BIG_UINT64_ARRAY,  /* u.array (typed_array) */
150
#endif
151
    JS_CLASS_FLOAT32_ARRAY,     /* u.array (typed_array) */
152
    JS_CLASS_FLOAT64_ARRAY,     /* u.array (typed_array) */
153
    JS_CLASS_DATAVIEW,          /* u.typed_array */
154
#ifdef CONFIG_BIGNUM
155
    JS_CLASS_BIG_INT,           /* u.object_data */
156
    JS_CLASS_BIG_FLOAT,         /* u.object_data */
157
    JS_CLASS_FLOAT_ENV,         /* u.float_env */
158
    JS_CLASS_BIG_DECIMAL,       /* u.object_data */
159
    JS_CLASS_OPERATOR_SET,      /* u.operator_set */
160
#endif
161
    JS_CLASS_MAP,               /* u.map_state */
162
    JS_CLASS_SET,               /* u.map_state */
163
    JS_CLASS_WEAKMAP,           /* u.map_state */
164
    JS_CLASS_WEAKSET,           /* u.map_state */
165
    JS_CLASS_MAP_ITERATOR,      /* u.map_iterator_data */
166
    JS_CLASS_SET_ITERATOR,      /* u.map_iterator_data */
167
    JS_CLASS_ARRAY_ITERATOR,    /* u.array_iterator_data */
168
    JS_CLASS_STRING_ITERATOR,   /* u.array_iterator_data */
169
    JS_CLASS_REGEXP_STRING_ITERATOR,   /* u.regexp_string_iterator_data */
170
    JS_CLASS_GENERATOR,         /* u.generator_data */
171
    JS_CLASS_PROXY,             /* u.proxy_data */
172
    JS_CLASS_PROMISE,           /* u.promise_data */
173
    JS_CLASS_PROMISE_RESOLVE_FUNCTION,  /* u.promise_function_data */
174
    JS_CLASS_PROMISE_REJECT_FUNCTION,   /* u.promise_function_data */
175
    JS_CLASS_ASYNC_FUNCTION,            /* u.func */
176
    JS_CLASS_ASYNC_FUNCTION_RESOLVE,    /* u.async_function_data */
177
    JS_CLASS_ASYNC_FUNCTION_REJECT,     /* u.async_function_data */
178
    JS_CLASS_ASYNC_FROM_SYNC_ITERATOR,  /* u.async_from_sync_iterator_data */
179
    JS_CLASS_ASYNC_GENERATOR_FUNCTION,  /* u.func */
180
    JS_CLASS_ASYNC_GENERATOR,   /* u.async_generator_data */
181
182
    JS_CLASS_INIT_COUNT, /* last entry for predefined classes */
183
};
184
185
/* number of typed array types */
186
24
#define JS_TYPED_ARRAY_COUNT  (JS_CLASS_FLOAT64_ARRAY - JS_CLASS_UINT8C_ARRAY + 1)
187
static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT];
188
44
#define typed_array_size_log2(classid)  (typed_array_size_log2[(classid)- JS_CLASS_UINT8C_ARRAY])
189
190
typedef enum JSErrorEnum {
191
    JS_EVAL_ERROR,
192
    JS_RANGE_ERROR,
193
    JS_REFERENCE_ERROR,
194
    JS_SYNTAX_ERROR,
195
    JS_TYPE_ERROR,
196
    JS_URI_ERROR,
197
    JS_INTERNAL_ERROR,
198
    JS_AGGREGATE_ERROR,
199
    
200
    JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */
201
} JSErrorEnum;
202
203
47.2k
#define JS_MAX_LOCAL_VARS 65536
204
46.8k
#define JS_STACK_SIZE_MAX 65534
205
439k
#define JS_STRING_LEN_MAX ((1 << 30) - 1)
206
207
#define __exception __attribute__((warn_unused_result))
208
209
typedef struct JSShape JSShape;
210
typedef struct JSString JSString;
211
typedef struct JSString JSAtomStruct;
212
213
typedef enum {
214
    JS_GC_PHASE_NONE,
215
    JS_GC_PHASE_DECREF,
216
    JS_GC_PHASE_REMOVE_CYCLES,
217
} JSGCPhaseEnum;
218
219
typedef enum OPCodeEnum OPCodeEnum;
220
221
#ifdef CONFIG_BIGNUM
222
/* function pointers are used for numeric operations so that it is
223
   possible to remove some numeric types */
224
typedef struct {
225
    JSValue (*to_string)(JSContext *ctx, JSValueConst val);
226
    JSValue (*from_string)(JSContext *ctx, const char *buf,
227
                           int radix, int flags, slimb_t *pexponent);
228
    int (*unary_arith)(JSContext *ctx,
229
                       JSValue *pres, OPCodeEnum op, JSValue op1);
230
    int (*binary_arith)(JSContext *ctx, OPCodeEnum op,
231
                        JSValue *pres, JSValue op1, JSValue op2);
232
    int (*compare)(JSContext *ctx, OPCodeEnum op,
233
                   JSValue op1, JSValue op2);
234
    /* only for bigfloat: */
235
    JSValue (*mul_pow10_to_float64)(JSContext *ctx, const bf_t *a,
236
                                    int64_t exponent);
237
    int (*mul_pow10)(JSContext *ctx, JSValue *sp);
238
} JSNumericOperations;
239
#endif
240
241
struct JSRuntime {
242
    JSMallocFunctions mf;
243
    JSMallocState malloc_state;
244
    const char *rt_info;
245
246
    int atom_hash_size; /* power of two */
247
    int atom_count;
248
    int atom_size;
249
    int atom_count_resize; /* resize hash table at this count */
250
    uint32_t *atom_hash;
251
    JSAtomStruct **atom_array;
252
    int atom_free_index; /* 0 = none */
253
254
    int class_count;    /* size of class_array */
255
    JSClass *class_array;
256
257
    struct list_head context_list; /* list of JSContext.link */
258
    /* list of JSGCObjectHeader.link. List of allocated GC objects (used
259
       by the garbage collector) */
260
    struct list_head gc_obj_list;
261
    /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */
262
    struct list_head gc_zero_ref_count_list; 
263
    struct list_head tmp_obj_list; /* used during GC */
264
    JSGCPhaseEnum gc_phase : 8;
265
    size_t malloc_gc_threshold;
266
#ifdef DUMP_LEAKS
267
    struct list_head string_list; /* list of JSString.link */
268
#endif
269
    /* stack limitation */
270
    uintptr_t stack_size; /* in bytes, 0 if no limit */
271
    uintptr_t stack_top;
272
    uintptr_t stack_limit; /* lower stack limit */
273
    
274
    JSValue current_exception;
275
    /* true if inside an out of memory error, to avoid recursing */
276
    BOOL in_out_of_memory : 8;
277
278
    struct JSStackFrame *current_stack_frame;
279
280
    JSInterruptHandler *interrupt_handler;
281
    void *interrupt_opaque;
282
283
    JSHostPromiseRejectionTracker *host_promise_rejection_tracker;
284
    void *host_promise_rejection_tracker_opaque;
285
    
286
    struct list_head job_list; /* list of JSJobEntry.link */
287
288
    JSModuleNormalizeFunc *module_normalize_func;
289
    JSModuleLoaderFunc *module_loader_func;
290
    void *module_loader_opaque;
291
292
    BOOL can_block : 8; /* TRUE if Atomics.wait can block */
293
    /* used to allocate, free and clone SharedArrayBuffers */
294
    JSSharedArrayBufferFunctions sab_funcs;
295
    
296
    /* Shape hash table */
297
    int shape_hash_bits;
298
    int shape_hash_size;
299
    int shape_hash_count; /* number of hashed shapes */
300
    JSShape **shape_hash;
301
#ifdef CONFIG_BIGNUM
302
    bf_context_t bf_ctx;
303
    JSNumericOperations bigint_ops;
304
    JSNumericOperations bigfloat_ops;
305
    JSNumericOperations bigdecimal_ops;
306
    uint32_t operator_count;
307
#endif
308
    void *user_opaque;
309
};
310
311
struct JSClass {
312
    uint32_t class_id; /* 0 means free entry */
313
    JSAtom class_name;
314
    JSClassFinalizer *finalizer;
315
    JSClassGCMark *gc_mark;
316
    JSClassCall *call;
317
    /* pointers for exotic behavior, can be NULL if none are present */
318
    const JSClassExoticMethods *exotic;
319
};
320
321
133k
#define JS_MODE_STRICT (1 << 0)
322
282k
#define JS_MODE_STRIP  (1 << 1)
323
774k
#define JS_MODE_MATH   (1 << 2)
324
325
typedef struct JSStackFrame {
326
    struct JSStackFrame *prev_frame; /* NULL if first stack frame */
327
    JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */
328
    JSValue *arg_buf; /* arguments */
329
    JSValue *var_buf; /* variables */
330
    struct list_head var_ref_list; /* list of JSVarRef.link */
331
    const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
332
                        instruction after the call */
333
    int arg_count;
334
    int js_mode; /* 0 or JS_MODE_MATH for C functions */
335
    /* only used in generators. Current stack pointer value. NULL if
336
       the function is running. */ 
337
    JSValue *cur_sp;
338
} JSStackFrame;
339
340
typedef enum {
341
    JS_GC_OBJ_TYPE_JS_OBJECT,
342
    JS_GC_OBJ_TYPE_FUNCTION_BYTECODE,
343
    JS_GC_OBJ_TYPE_SHAPE,
344
    JS_GC_OBJ_TYPE_VAR_REF,
345
    JS_GC_OBJ_TYPE_ASYNC_FUNCTION,
346
    JS_GC_OBJ_TYPE_JS_CONTEXT,
347
} JSGCObjectTypeEnum;
348
349
/* header for GC objects. GC objects are C data structures with a
350
   reference count that can reference other GC objects. JS Objects are
351
   a particular type of GC object. */
352
struct JSGCObjectHeader {
353
    int ref_count; /* must come first, 32-bit */
354
    JSGCObjectTypeEnum gc_obj_type : 4;
355
    uint8_t mark : 4; /* used by the GC */
356
    uint8_t dummy1; /* not used by the GC */
357
    uint16_t dummy2; /* not used by the GC */
358
    struct list_head link;
359
};
360
361
typedef struct JSVarRef {
362
    union {
363
        JSGCObjectHeader header; /* must come first */
364
        struct {
365
            int __gc_ref_count; /* corresponds to header.ref_count */
366
            uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
367
368
            /* 0 : the JSVarRef is on the stack. header.link is an element
369
               of JSStackFrame.var_ref_list.
370
               1 : the JSVarRef is detached. header.link has the normal meanning 
371
            */
372
            uint8_t is_detached : 1; 
373
            uint8_t is_arg : 1;
374
            uint16_t var_idx; /* index of the corresponding function variable on
375
                                 the stack */
376
        };
377
    };
378
    JSValue *pvalue; /* pointer to the value, either on the stack or
379
                        to 'value' */
380
    JSValue value; /* used when the variable is no longer on the stack */
381
} JSVarRef;
382
383
#ifdef CONFIG_BIGNUM
384
typedef struct JSFloatEnv {
385
    limb_t prec;
386
    bf_flags_t flags;
387
    unsigned int status;
388
} JSFloatEnv;
389
390
/* the same structure is used for big integers and big floats. Big
391
   integers are never infinite or NaNs */
392
typedef struct JSBigFloat {
393
    JSRefCountHeader header; /* must come first, 32-bit */
394
    bf_t num;
395
} JSBigFloat;
396
397
typedef struct JSBigDecimal {
398
    JSRefCountHeader header; /* must come first, 32-bit */
399
    bfdec_t num;
400
} JSBigDecimal;
401
#endif
402
403
typedef enum {
404
    JS_AUTOINIT_ID_PROTOTYPE,
405
    JS_AUTOINIT_ID_MODULE_NS,
406
    JS_AUTOINIT_ID_PROP,
407
} JSAutoInitIDEnum;
408
409
/* must be large enough to have a negligible runtime cost and small
410
   enough to call the interrupt callback often. */
411
91
#define JS_INTERRUPT_COUNTER_INIT 10000
412
413
struct JSContext {
414
    JSGCObjectHeader header; /* must come first */
415
    JSRuntime *rt;
416
    struct list_head link;
417
418
    uint16_t binary_object_count;
419
    int binary_object_size;
420
421
    JSShape *array_shape;   /* initial shape for Array objects */
422
423
    JSValue *class_proto;
424
    JSValue function_proto;
425
    JSValue function_ctor;
426
    JSValue array_ctor;
427
    JSValue regexp_ctor;
428
    JSValue promise_ctor;
429
    JSValue native_error_proto[JS_NATIVE_ERROR_COUNT];
430
    JSValue iterator_proto;
431
    JSValue async_iterator_proto;
432
    JSValue array_proto_values;
433
    JSValue throw_type_error;
434
    JSValue eval_obj;
435
436
    JSValue global_obj; /* global object */
437
    JSValue global_var_obj; /* contains the global let/const definitions */
438
439
    uint64_t random_state;
440
#ifdef CONFIG_BIGNUM
441
    bf_context_t *bf_ctx;   /* points to rt->bf_ctx, shared by all contexts */
442
    JSFloatEnv fp_env; /* global FP environment */
443
    BOOL bignum_ext : 8; /* enable math mode */
444
    BOOL allow_operator_overloading : 8;
445
#endif
446
    /* when the counter reaches zero, JSRutime.interrupt_handler is called */
447
    int interrupt_counter;
448
    BOOL is_error_property_enabled;
449
450
    struct list_head loaded_modules; /* list of JSModuleDef.link */
451
452
    /* if NULL, RegExp compilation is not supported */
453
    JSValue (*compile_regexp)(JSContext *ctx, JSValueConst pattern,
454
                              JSValueConst flags);
455
    /* if NULL, eval is not supported */
456
    JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj,
457
                             const char *input, size_t input_len,
458
                             const char *filename, int flags, int scope_idx);
459
    void *user_opaque;
460
};
461
462
typedef union JSFloat64Union {
463
    double d;
464
    uint64_t u64;
465
    uint32_t u32[2];
466
} JSFloat64Union;
467
468
enum {
469
    JS_ATOM_TYPE_STRING = 1,
470
    JS_ATOM_TYPE_GLOBAL_SYMBOL,
471
    JS_ATOM_TYPE_SYMBOL,
472
    JS_ATOM_TYPE_PRIVATE,
473
};
474
475
enum {
476
    JS_ATOM_HASH_SYMBOL,
477
    JS_ATOM_HASH_PRIVATE,
478
};
479
480
typedef enum {
481
    JS_ATOM_KIND_STRING,
482
    JS_ATOM_KIND_SYMBOL,
483
    JS_ATOM_KIND_PRIVATE,
484
} JSAtomKindEnum;
485
486
831k
#define JS_ATOM_HASH_MASK  ((1 << 30) - 1)
487
488
struct JSString {
489
    JSRefCountHeader header; /* must come first, 32-bit */
490
    uint32_t len : 31;
491
    uint8_t is_wide_char : 1; /* 0 = 8 bits, 1 = 16 bits characters */
492
    /* for JS_ATOM_TYPE_SYMBOL: hash = 0, atom_type = 3,
493
       for JS_ATOM_TYPE_PRIVATE: hash = 1, atom_type = 3
494
       XXX: could change encoding to have one more bit in hash */
495
    uint32_t hash : 30;
496
    uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */
497
    uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */
498
#ifdef DUMP_LEAKS
499
    struct list_head link; /* string list */
500
#endif
501
    union {
502
        uint8_t str8[0]; /* 8 bit strings will get an extra null terminator */
503
        uint16_t str16[0];
504
    } u;
505
};
506
507
typedef struct JSClosureVar {
508
    uint8_t is_local : 1;
509
    uint8_t is_arg : 1;
510
    uint8_t is_const : 1;
511
    uint8_t is_lexical : 1;
512
    uint8_t var_kind : 4; /* see JSVarKindEnum */
513
    /* 8 bits available */
514
    uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the
515
                    parent function. otherwise: index to a closure
516
                    variable of the parent function */
517
    JSAtom var_name;
518
} JSClosureVar;
519
520
118
#define ARG_SCOPE_INDEX 1
521
577k
#define ARG_SCOPE_END (-2)
522
523
typedef struct JSVarScope {
524
    int parent;  /* index into fd->scopes of the enclosing scope */
525
    int first;   /* index into fd->vars of the last variable in this scope */
526
} JSVarScope;
527
528
typedef enum {
529
    /* XXX: add more variable kinds here instead of using bit fields */
530
    JS_VAR_NORMAL,
531
    JS_VAR_FUNCTION_DECL, /* lexical var with function declaration */
532
    JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator
533
                                 function declaration */
534
    JS_VAR_CATCH,
535
    JS_VAR_FUNCTION_NAME, /* function expression name */
536
    JS_VAR_PRIVATE_FIELD,
537
    JS_VAR_PRIVATE_METHOD,
538
    JS_VAR_PRIVATE_GETTER,
539
    JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */
540
    JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */
541
} JSVarKindEnum;
542
543
/* XXX: could use a different structure in bytecode functions to save
544
   memory */
545
typedef struct JSVarDef {
546
    JSAtom var_name;
547
    /* index into fd->scopes of this variable lexical scope */
548
    int scope_level;
549
    /* during compilation: 
550
        - if scope_level = 0: scope in which the variable is defined
551
        - if scope_level != 0: index into fd->vars of the next
552
          variable in the same or enclosing lexical scope
553
       in a bytecode function:
554
       index into fd->vars of the next
555
       variable in the same or enclosing lexical scope
556
    */
557
    int scope_next;    
558
    uint8_t is_const : 1;
559
    uint8_t is_lexical : 1;
560
    uint8_t is_captured : 1;
561
    uint8_t var_kind : 4; /* see JSVarKindEnum */
562
    /* only used during compilation: function pool index for lexical
563
       variables with var_kind =
564
       JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of
565
       the definition of the 'var' variables (they have scope_level =
566
       0) */
567
    int func_pool_idx : 24; /* only used during compilation : index in
568
                               the constant pool for hoisted function
569
                               definition */
570
} JSVarDef;
571
572
/* for the encoding of the pc2line table */
573
5.75M
#define PC2LINE_BASE     (-1)
574
11.3M
#define PC2LINE_RANGE    5
575
5.68M
#define PC2LINE_OP_FIRST 1
576
18.1k
#define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE)
577
578
typedef enum JSFunctionKindEnum {
579
    JS_FUNC_NORMAL = 0,
580
    JS_FUNC_GENERATOR = (1 << 0),
581
    JS_FUNC_ASYNC = (1 << 1),
582
    JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC),
583
} JSFunctionKindEnum;
584
585
typedef struct JSFunctionBytecode {
586
    JSGCObjectHeader header; /* must come first */
587
    uint8_t js_mode;
588
    uint8_t has_prototype : 1; /* true if a prototype field is necessary */
589
    uint8_t has_simple_parameter_list : 1;
590
    uint8_t is_derived_class_constructor : 1;
591
    /* true if home_object needs to be initialized */
592
    uint8_t need_home_object : 1;
593
    uint8_t func_kind : 2;
594
    uint8_t new_target_allowed : 1;
595
    uint8_t super_call_allowed : 1;
596
    uint8_t super_allowed : 1;
597
    uint8_t arguments_allowed : 1;
598
    uint8_t has_debug : 1;
599
    uint8_t backtrace_barrier : 1; /* stop backtrace on this function */
600
    uint8_t read_only_bytecode : 1;
601
    /* XXX: 4 bits available */
602
    uint8_t *byte_code_buf; /* (self pointer) */
603
    int byte_code_len;
604
    JSAtom func_name;
605
    JSVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */
606
    JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */
607
    uint16_t arg_count;
608
    uint16_t var_count;
609
    uint16_t defined_arg_count; /* for length function property */
610
    uint16_t stack_size; /* maximum stack size */
611
    JSContext *realm; /* function realm */
612
    JSValue *cpool; /* constant pool (self pointer) */
613
    int cpool_count;
614
    int closure_var_count;
615
    struct {
616
        /* debug info, move to separate structure to save memory? */
617
        JSAtom filename;
618
        int line_num;
619
        int source_len;
620
        int pc2line_len;
621
        uint8_t *pc2line_buf;
622
        char *source;
623
    } debug;
624
} JSFunctionBytecode;
625
626
typedef struct JSBoundFunction {
627
    JSValue func_obj;
628
    JSValue this_val;
629
    int argc;
630
    JSValue argv[0];
631
} JSBoundFunction;
632
633
typedef enum JSIteratorKindEnum {
634
    JS_ITERATOR_KIND_KEY,
635
    JS_ITERATOR_KIND_VALUE,
636
    JS_ITERATOR_KIND_KEY_AND_VALUE,
637
} JSIteratorKindEnum;
638
639
typedef struct JSForInIterator {
640
    JSValue obj;
641
    BOOL is_array;
642
    uint32_t array_length;
643
    uint32_t idx;
644
} JSForInIterator;
645
646
typedef struct JSRegExp {
647
    JSString *pattern;
648
    JSString *bytecode; /* also contains the flags */
649
} JSRegExp;
650
651
typedef struct JSProxyData {
652
    JSValue target;
653
    JSValue handler;
654
    uint8_t is_func;
655
    uint8_t is_revoked;
656
} JSProxyData;
657
658
typedef struct JSArrayBuffer {
659
    int byte_length; /* 0 if detached */
660
    uint8_t detached;
661
    uint8_t shared; /* if shared, the array buffer cannot be detached */
662
    uint8_t *data; /* NULL if detached */
663
    struct list_head array_list;
664
    void *opaque;
665
    JSFreeArrayBufferDataFunc *free_func;
666
} JSArrayBuffer;
667
668
typedef struct JSTypedArray {
669
    struct list_head link; /* link to arraybuffer */
670
    JSObject *obj; /* back pointer to the TypedArray/DataView object */
671
    JSObject *buffer; /* based array buffer */
672
    uint32_t offset; /* offset in the array buffer */
673
    uint32_t length; /* length in the array buffer */
674
} JSTypedArray;
675
676
typedef struct JSAsyncFunctionState {
677
    JSValue this_val; /* 'this' generator argument */
678
    int argc; /* number of function arguments */
679
    BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */
680
    JSStackFrame frame;
681
} JSAsyncFunctionState;
682
683
/* XXX: could use an object instead to avoid the
684
   JS_TAG_ASYNC_FUNCTION tag for the GC */
685
typedef struct JSAsyncFunctionData {
686
    JSGCObjectHeader header; /* must come first */
687
    JSValue resolving_funcs[2];
688
    BOOL is_active; /* true if the async function state is valid */
689
    JSAsyncFunctionState func_state;
690
} JSAsyncFunctionData;
691
692
typedef enum {
693
   /* binary operators */
694
   JS_OVOP_ADD,
695
   JS_OVOP_SUB,
696
   JS_OVOP_MUL,
697
   JS_OVOP_DIV,
698
   JS_OVOP_MOD,
699
   JS_OVOP_POW,
700
   JS_OVOP_OR,
701
   JS_OVOP_AND,
702
   JS_OVOP_XOR,
703
   JS_OVOP_SHL,
704
   JS_OVOP_SAR,
705
   JS_OVOP_SHR,
706
   JS_OVOP_EQ,
707
   JS_OVOP_LESS,
708
709
   JS_OVOP_BINARY_COUNT,
710
   /* unary operators */
711
   JS_OVOP_POS = JS_OVOP_BINARY_COUNT,
712
   JS_OVOP_NEG,
713
   JS_OVOP_INC,
714
   JS_OVOP_DEC,
715
   JS_OVOP_NOT,
716
717
   JS_OVOP_COUNT,
718
} JSOverloadableOperatorEnum;
719
720
typedef struct {
721
    uint32_t operator_index;
722
    JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */
723
} JSBinaryOperatorDefEntry;
724
725
typedef struct {
726
    int count;
727
    JSBinaryOperatorDefEntry *tab;
728
} JSBinaryOperatorDef;
729
730
typedef struct {
731
    uint32_t operator_counter;
732
    BOOL is_primitive; /* OperatorSet for a primitive type */
733
    /* NULL if no operator is defined */
734
    JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */
735
    JSBinaryOperatorDef left;
736
    JSBinaryOperatorDef right;
737
} JSOperatorSetData;
738
739
typedef struct JSReqModuleEntry {
740
    JSAtom module_name;
741
    JSModuleDef *module; /* used using resolution */
742
} JSReqModuleEntry;
743
744
typedef enum JSExportTypeEnum {
745
    JS_EXPORT_TYPE_LOCAL,
746
    JS_EXPORT_TYPE_INDIRECT,
747
} JSExportTypeEnum;
748
749
typedef struct JSExportEntry {
750
    union {
751
        struct {
752
            int var_idx; /* closure variable index */
753
            JSVarRef *var_ref; /* if != NULL, reference to the variable */
754
        } local; /* for local export */
755
        int req_module_idx; /* module for indirect export */
756
    } u;
757
    JSExportTypeEnum export_type;
758
    JSAtom local_name; /* '*' if export ns from. not used for local
759
                          export after compilation */
760
    JSAtom export_name; /* exported variable name */
761
} JSExportEntry;
762
763
typedef struct JSStarExportEntry {
764
    int req_module_idx; /* in req_module_entries */
765
} JSStarExportEntry;
766
767
typedef struct JSImportEntry {
768
    int var_idx; /* closure variable index */
769
    JSAtom import_name;
770
    int req_module_idx; /* in req_module_entries */
771
} JSImportEntry;
772
773
struct JSModuleDef {
774
    JSRefCountHeader header; /* must come first, 32-bit */
775
    JSAtom module_name;
776
    struct list_head link;
777
778
    JSReqModuleEntry *req_module_entries;
779
    int req_module_entries_count;
780
    int req_module_entries_size;
781
782
    JSExportEntry *export_entries;
783
    int export_entries_count;
784
    int export_entries_size;
785
786
    JSStarExportEntry *star_export_entries;
787
    int star_export_entries_count;
788
    int star_export_entries_size;
789
790
    JSImportEntry *import_entries;
791
    int import_entries_count;
792
    int import_entries_size;
793
794
    JSValue module_ns;
795
    JSValue func_obj; /* only used for JS modules */
796
    JSModuleInitFunc *init_func; /* only used for C modules */
797
    BOOL resolved : 8;
798
    BOOL func_created : 8;
799
    BOOL instantiated : 8;
800
    BOOL evaluated : 8;
801
    BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */
802
    /* true if evaluation yielded an exception. It is saved in
803
       eval_exception */
804
    BOOL eval_has_exception : 8; 
805
    JSValue eval_exception;
806
    JSValue meta_obj; /* for import.meta */
807
};
808
809
typedef struct JSJobEntry {
810
    struct list_head link;
811
    JSContext *ctx;
812
    JSJobFunc *job_func;
813
    int argc;
814
    JSValue argv[0];
815
} JSJobEntry;
816
817
typedef struct JSProperty {
818
    union {
819
        JSValue value;      /* JS_PROP_NORMAL */
820
        struct {            /* JS_PROP_GETSET */
821
            JSObject *getter; /* NULL if undefined */
822
            JSObject *setter; /* NULL if undefined */
823
        } getset;
824
        JSVarRef *var_ref;  /* JS_PROP_VARREF */
825
        struct {            /* JS_PROP_AUTOINIT */
826
            /* in order to use only 2 pointers, we compress the realm
827
               and the init function pointer */
828
            uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x)
829
                                       in the 2 low bits */
830
            void *opaque;
831
        } init;
832
    } u;
833
} JSProperty;
834
835
562k
#define JS_PROP_INITIAL_SIZE 2
836
562k
#define JS_PROP_INITIAL_HASH_SIZE 4 /* must be a power of two */
837
#define JS_ARRAY_INITIAL_SIZE 2
838
839
typedef struct JSShapeProperty {
840
    uint32_t hash_next : 26; /* 0 if last in list */
841
    uint32_t flags : 6;   /* JS_PROP_XXX */
842
    JSAtom atom; /* JS_ATOM_NULL = free property entry */
843
} JSShapeProperty;
844
845
struct JSShape {
846
    /* hash table of size hash_mask + 1 before the start of the
847
       structure (see prop_hash_end()). */
848
    JSGCObjectHeader header;
849
    /* true if the shape is inserted in the shape hash table. If not,
850
       JSShape.hash is not valid */
851
    uint8_t is_hashed;
852
    /* If true, the shape may have small array index properties 'n' with 0
853
       <= n <= 2^31-1. If false, the shape is guaranteed not to have
854
       small array index properties */
855
    uint8_t has_small_array_index;
856
    uint32_t hash; /* current hash value */
857
    uint32_t prop_hash_mask;
858
    int prop_size; /* allocated properties */
859
    int prop_count; /* include deleted properties */
860
    int deleted_prop_count;
861
    JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */
862
    JSObject *proto;
863
    JSShapeProperty prop[0]; /* prop_size elements */
864
};
865
866
struct JSObject {
867
    union {
868
        JSGCObjectHeader header;
869
        struct {
870
            int __gc_ref_count; /* corresponds to header.ref_count */
871
            uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
872
            
873
            uint8_t extensible : 1;
874
            uint8_t free_mark : 1; /* only used when freeing objects with cycles */
875
            uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */
876
            uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */
877
            uint8_t is_constructor : 1; /* TRUE if object is a constructor function */
878
            uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */
879
            uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */
880
            uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */
881
            uint16_t class_id; /* see JS_CLASS_x */
882
        };
883
    };
884
    /* byte offsets: 16/24 */
885
    JSShape *shape; /* prototype and property names + flag */
886
    JSProperty *prop; /* array of properties */
887
    /* byte offsets: 24/40 */
888
    struct JSMapRecord *first_weak_ref; /* XXX: use a bit and an external hash table? */
889
    /* byte offsets: 28/48 */
890
    union {
891
        void *opaque;
892
        struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */
893
        struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */
894
        struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */
895
        struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */
896
        struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */
897
#ifdef CONFIG_BIGNUM
898
        struct JSFloatEnv *float_env; /* JS_CLASS_FLOAT_ENV */
899
        struct JSOperatorSetData *operator_set; /* JS_CLASS_OPERATOR_SET */
900
#endif
901
        struct JSMapState *map_state;   /* JS_CLASS_MAP..JS_CLASS_WEAKSET */
902
        struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */
903
        struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */
904
        struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */
905
        struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */
906
        struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */
907
        struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */
908
        struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */
909
        struct JSAsyncFunctionData *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */
910
        struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
911
        struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */
912
        struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */
913
            /* also used by JS_CLASS_GENERATOR_FUNCTION, JS_CLASS_ASYNC_FUNCTION and JS_CLASS_ASYNC_GENERATOR_FUNCTION */
914
            struct JSFunctionBytecode *function_bytecode;
915
            JSVarRef **var_refs;
916
            JSObject *home_object; /* for 'super' access */
917
        } func;
918
        struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */
919
            JSContext *realm;
920
            JSCFunctionType c_function;
921
            uint8_t length;
922
            uint8_t cproto;
923
            int16_t magic;
924
        } cfunc;
925
        /* array part for fast arrays and typed arrays */
926
        struct { /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
927
            union {
928
                uint32_t size;          /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */
929
                struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
930
            } u1;
931
            union {
932
                JSValue *values;        /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */ 
933
                void *ptr;              /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
934
                int8_t *int8_ptr;       /* JS_CLASS_INT8_ARRAY */
935
                uint8_t *uint8_ptr;     /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */
936
                int16_t *int16_ptr;     /* JS_CLASS_INT16_ARRAY */
937
                uint16_t *uint16_ptr;   /* JS_CLASS_UINT16_ARRAY */
938
                int32_t *int32_ptr;     /* JS_CLASS_INT32_ARRAY */
939
                uint32_t *uint32_ptr;   /* JS_CLASS_UINT32_ARRAY */
940
                int64_t *int64_ptr;     /* JS_CLASS_INT64_ARRAY */
941
                uint64_t *uint64_ptr;   /* JS_CLASS_UINT64_ARRAY */
942
                float *float_ptr;       /* JS_CLASS_FLOAT32_ARRAY */
943
                double *double_ptr;     /* JS_CLASS_FLOAT64_ARRAY */
944
            } u;
945
            uint32_t count; /* <= 2^31-1. 0 for a detached typed array */
946
        } array;    /* 12/20 bytes */
947
        JSRegExp regexp;    /* JS_CLASS_REGEXP: 8/16 bytes */
948
        JSValue object_data;    /* for JS_SetObjectData(): 8/16/16 bytes */
949
    } u;
950
    /* byte sizes: 40/48/72 */
951
};
952
enum {
953
    __JS_ATOM_NULL = JS_ATOM_NULL,
954
#define DEF(name, str) JS_ATOM_ ## name,
955
#include "quickjs-atom.h"
956
#undef DEF
957
    JS_ATOM_END,
958
};
959
1.36M
#define JS_ATOM_LAST_KEYWORD JS_ATOM_super
960
1.33M
#define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield
961
962
static const char js_atom_init[] =
963
#define DEF(name, str) str "\0"
964
#include "quickjs-atom.h"
965
#undef DEF
966
;
967
968
typedef enum OPCodeFormat {
969
#define FMT(f) OP_FMT_ ## f,
970
#define DEF(id, size, n_pop, n_push, f)
971
#include "quickjs-opcode.h"
972
#undef DEF
973
#undef FMT
974
} OPCodeFormat;
975
976
enum OPCodeEnum {
977
#define FMT(f)
978
#define DEF(id, size, n_pop, n_push, f) OP_ ## id,
979
#define def(id, size, n_pop, n_push, f)
980
#include "quickjs-opcode.h"
981
#undef def
982
#undef DEF
983
#undef FMT
984
    OP_COUNT, /* excluding temporary opcodes */
985
    /* temporary opcodes : overlap with the short opcodes */
986
    OP_TEMP_START = OP_nop + 1,
987
    OP___dummy = OP_TEMP_START - 1,
988
#define FMT(f)
989
#define DEF(id, size, n_pop, n_push, f)
990
#define def(id, size, n_pop, n_push, f) OP_ ## id,
991
#include "quickjs-opcode.h"
992
#undef def
993
#undef DEF
994
#undef FMT
995
    OP_TEMP_END,
996
};
997
998
static int JS_InitAtoms(JSRuntime *rt);
999
static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
1000
                               int atom_type);
1001
static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p);
1002
static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b);
1003
static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
1004
                                  JSValueConst this_obj,
1005
                                  int argc, JSValueConst *argv, int flags);
1006
static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
1007
                                      JSValueConst this_obj,
1008
                                      int argc, JSValueConst *argv, int flags);
1009
static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
1010
                               JSValueConst this_obj, JSValueConst new_target,
1011
                               int argc, JSValue *argv, int flags);
1012
static JSValue JS_CallConstructorInternal(JSContext *ctx,
1013
                                          JSValueConst func_obj,
1014
                                          JSValueConst new_target,
1015
                                          int argc, JSValue *argv, int flags);
1016
static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
1017
                           int argc, JSValueConst *argv);
1018
static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
1019
                             int argc, JSValueConst *argv);
1020
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
1021
                                            JSValue val, BOOL is_array_ctor);
1022
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
1023
                             JSValueConst val, int flags, int scope_idx);
1024
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
1025
static __maybe_unused void JS_DumpAtoms(JSRuntime *rt);
1026
static __maybe_unused void JS_DumpString(JSRuntime *rt,
1027
                                                  const JSString *p);
1028
static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
1029
static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
1030
static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);
1031
static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
1032
                                                      JSValueConst val);
1033
static __maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val);
1034
static __maybe_unused void JS_PrintValue(JSContext *ctx,
1035
                                                  const char *str,
1036
                                                  JSValueConst val);
1037
static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
1038
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
1039
                                 int argc, JSValueConst *argv, int magic);
1040
static void js_array_finalizer(JSRuntime *rt, JSValue val);
1041
static void js_array_mark(JSRuntime *rt, JSValueConst val,
1042
                          JS_MarkFunc *mark_func);
1043
static void js_object_data_finalizer(JSRuntime *rt, JSValue val);
1044
static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
1045
                                JS_MarkFunc *mark_func);
1046
static void js_c_function_finalizer(JSRuntime *rt, JSValue val);
1047
static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
1048
                               JS_MarkFunc *mark_func);
1049
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val);
1050
static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
1051
                                JS_MarkFunc *mark_func);
1052
static void js_bound_function_finalizer(JSRuntime *rt, JSValue val);
1053
static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
1054
                                JS_MarkFunc *mark_func);
1055
static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val);
1056
static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
1057
                                JS_MarkFunc *mark_func);
1058
static void js_regexp_finalizer(JSRuntime *rt, JSValue val);
1059
static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val);
1060
static void js_typed_array_finalizer(JSRuntime *rt, JSValue val);
1061
static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
1062
                                JS_MarkFunc *mark_func);
1063
static void js_proxy_finalizer(JSRuntime *rt, JSValue val);
1064
static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
1065
                                JS_MarkFunc *mark_func);
1066
static void js_map_finalizer(JSRuntime *rt, JSValue val);
1067
static void js_map_mark(JSRuntime *rt, JSValueConst val,
1068
                                JS_MarkFunc *mark_func);
1069
static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val);
1070
static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
1071
                                JS_MarkFunc *mark_func);
1072
static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val);
1073
static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
1074
                                JS_MarkFunc *mark_func);
1075
static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val);
1076
static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
1077
                                JS_MarkFunc *mark_func);
1078
static void js_generator_finalizer(JSRuntime *rt, JSValue obj);
1079
static void js_generator_mark(JSRuntime *rt, JSValueConst val,
1080
                                JS_MarkFunc *mark_func);
1081
static void js_promise_finalizer(JSRuntime *rt, JSValue val);
1082
static void js_promise_mark(JSRuntime *rt, JSValueConst val,
1083
                                JS_MarkFunc *mark_func);
1084
static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val);
1085
static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
1086
                                JS_MarkFunc *mark_func);
1087
#ifdef CONFIG_BIGNUM
1088
static void js_operator_set_finalizer(JSRuntime *rt, JSValue val);
1089
static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
1090
                                 JS_MarkFunc *mark_func);
1091
#endif
1092
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
1093
static int JS_ToBoolFree(JSContext *ctx, JSValue val);
1094
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
1095
static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val);
1096
static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val);
1097
static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
1098
                                 JSValueConst flags);
1099
static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
1100
                                              JSValue pattern, JSValue bc);
1101
static void gc_decref(JSRuntime *rt);
1102
static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
1103
                        const JSClassDef *class_def, JSAtom name);
1104
1105
typedef enum JSStrictEqModeEnum {
1106
    JS_EQ_STRICT,
1107
    JS_EQ_SAME_VALUE,
1108
    JS_EQ_SAME_VALUE_ZERO,
1109
} JSStrictEqModeEnum;
1110
1111
static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
1112
                          JSStrictEqModeEnum eq_mode);
1113
static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2);
1114
static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2);
1115
static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
1116
static JSValue JS_ToObject(JSContext *ctx, JSValueConst val);
1117
static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val);
1118
static JSProperty *add_property(JSContext *ctx,
1119
                                JSObject *p, JSAtom prop, int prop_flags);
1120
#ifdef CONFIG_BIGNUM
1121
static void js_float_env_finalizer(JSRuntime *rt, JSValue val);
1122
static JSValue JS_NewBigFloat(JSContext *ctx);
1123
static inline bf_t *JS_GetBigFloat(JSValueConst val)
1124
0
{
1125
0
    JSBigFloat *p = JS_VALUE_GET_PTR(val);
1126
0
    return &p->num;
1127
0
}
1128
static JSValue JS_NewBigDecimal(JSContext *ctx);
1129
static inline bfdec_t *JS_GetBigDecimal(JSValueConst val)
1130
0
{
1131
0
    JSBigDecimal *p = JS_VALUE_GET_PTR(val);
1132
0
    return &p->num;
1133
0
}
1134
static JSValue JS_NewBigInt(JSContext *ctx);
1135
static inline bf_t *JS_GetBigInt(JSValueConst val)
1136
1.99k
{
1137
1.99k
    JSBigFloat *p = JS_VALUE_GET_PTR(val);
1138
1.99k
    return &p->num;
1139
1.99k
}
1140
static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
1141
                                 BOOL convert_to_safe_integer);
1142
static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val);
1143
static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
1144
static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);
1145
static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);
1146
static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val);
1147
static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
1148
                                   BOOL allow_null_or_undefined);
1149
static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val);
1150
#endif
1151
JSValue JS_ThrowOutOfMemory(JSContext *ctx);
1152
static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);
1153
static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj);
1154
static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
1155
                                   JSValueConst proto_val, BOOL throw_flag);
1156
static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj);
1157
static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj);
1158
static int js_proxy_isArray(JSContext *ctx, JSValueConst obj);
1159
static int JS_CreateProperty(JSContext *ctx, JSObject *p,
1160
                             JSAtom prop, JSValueConst val,
1161
                             JSValueConst getter, JSValueConst setter,
1162
                             int flags);
1163
static int js_string_memcmp(const JSString *p1, const JSString *p2, int len);
1164
static void reset_weak_ref(JSRuntime *rt, JSObject *p);
1165
static JSValue js_array_buffer_constructor3(JSContext *ctx,
1166
                                            JSValueConst new_target,
1167
                                            uint64_t len, JSClassID class_id,
1168
                                            uint8_t *buf,
1169
                                            JSFreeArrayBufferDataFunc *free_func,
1170
                                            void *opaque, BOOL alloc_flag);
1171
static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj);
1172
static JSValue js_typed_array_constructor(JSContext *ctx,
1173
                                          JSValueConst this_val,
1174
                                          int argc, JSValueConst *argv,
1175
                                          int classid);
1176
static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p);
1177
static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p);
1178
static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx);
1179
static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,
1180
                             BOOL is_arg);
1181
static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
1182
                                          JSValueConst this_obj,
1183
                                          int argc, JSValueConst *argv,
1184
                                          int flags);
1185
static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val);
1186
static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
1187
                                           JS_MarkFunc *mark_func);
1188
static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
1189
                               const char *input, size_t input_len,
1190
                               const char *filename, int flags, int scope_idx);
1191
static void js_free_module_def(JSContext *ctx, JSModuleDef *m);
1192
static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
1193
                               JS_MarkFunc *mark_func);
1194
static JSValue js_import_meta(JSContext *ctx);
1195
static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier);
1196
static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);
1197
static JSValue js_new_promise_capability(JSContext *ctx,
1198
                                         JSValue *resolving_funcs,
1199
                                         JSValueConst ctor);
1200
static __exception int perform_promise_then(JSContext *ctx,
1201
                                            JSValueConst promise,
1202
                                            JSValueConst *resolve_reject,
1203
                                            JSValueConst *cap_resolving_funcs);
1204
static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
1205
                                  int argc, JSValueConst *argv, int magic);
1206
static int js_string_compare(JSContext *ctx,
1207
                             const JSString *p1, const JSString *p2);
1208
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val);
1209
static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
1210
                               JSValue prop, JSValue val, int flags);
1211
static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val);
1212
static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val);
1213
static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val);
1214
static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
1215
                                     JSObject *p, JSAtom prop);
1216
static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc);
1217
static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
1218
                            JS_MarkFunc *mark_func);
1219
static void JS_AddIntrinsicBasicObjects(JSContext *ctx);
1220
static void js_free_shape(JSRuntime *rt, JSShape *sh);
1221
static void js_free_shape_null(JSRuntime *rt, JSShape *sh);
1222
static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
1223
                                   JSShapeProperty **pprs);
1224
static int init_shape_hash(JSRuntime *rt);
1225
static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
1226
                                       JSValueConst obj);
1227
static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
1228
                                       JSValueConst obj);
1229
static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len);
1230
static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
1231
                               JSValueConst array_arg);
1232
static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
1233
                              JSValue **arrpp, uint32_t *countp);
1234
static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
1235
                                              JSValueConst sync_iter);
1236
static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val);
1237
static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
1238
                                    JS_MarkFunc *mark_func);
1239
static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
1240
                                       JSValueConst this_val,
1241
                                       int argc, JSValueConst *argv, int flags);
1242
static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val);
1243
static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
1244
                          JSGCObjectTypeEnum type);
1245
static void remove_gc_object(JSGCObjectHeader *h);
1246
static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s);
1247
static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
1248
static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
1249
                                 void *opaque);
1250
static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
1251
                                               JSAtom atom, void *opaque);
1252
void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag);
1253
1254
static const JSClassExoticMethods js_arguments_exotic_methods;
1255
static const JSClassExoticMethods js_string_exotic_methods;
1256
static const JSClassExoticMethods js_proxy_exotic_methods;
1257
static const JSClassExoticMethods js_module_ns_exotic_methods;
1258
static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;
1259
1260
static void js_trigger_gc(JSRuntime *rt, size_t size)
1261
1.34M
{
1262
1.34M
    BOOL force_gc;
1263
#ifdef FORCE_GC_AT_MALLOC
1264
    force_gc = TRUE;
1265
#else
1266
1.34M
    force_gc = ((rt->malloc_state.malloc_size + size) >
1267
1.34M
                rt->malloc_gc_threshold);
1268
1.34M
#endif
1269
1.34M
    if (force_gc) {
1270
#ifdef DUMP_GC
1271
        printf("GC: size=%" PRIu64 "\n",
1272
               (uint64_t)rt->malloc_state.malloc_size);
1273
#endif
1274
23
        JS_RunGC(rt);
1275
23
        rt->malloc_gc_threshold = rt->malloc_state.malloc_size +
1276
23
            (rt->malloc_state.malloc_size >> 1);
1277
23
    }
1278
1.34M
}
1279
1280
static size_t js_malloc_usable_size_unknown(const void *ptr)
1281
0
{
1282
0
    return 0;
1283
0
}
1284
1285
void *js_malloc_rt(JSRuntime *rt, size_t size)
1286
6.60M
{
1287
6.60M
    return rt->mf.js_malloc(&rt->malloc_state, size);
1288
6.60M
}
1289
1290
void js_free_rt(JSRuntime *rt, void *ptr)
1291
6.16M
{
1292
6.16M
    rt->mf.js_free(&rt->malloc_state, ptr);
1293
6.16M
}
1294
1295
void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size)
1296
1.88M
{
1297
1.88M
    return rt->mf.js_realloc(&rt->malloc_state, ptr, size);
1298
1.88M
}
1299
1300
size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr)
1301
168k
{
1302
168k
    return rt->mf.js_malloc_usable_size(ptr);
1303
168k
}
1304
1305
void *js_mallocz_rt(JSRuntime *rt, size_t size)
1306
432k
{
1307
432k
    void *ptr;
1308
432k
    ptr = js_malloc_rt(rt, size);
1309
432k
    if (!ptr)
1310
2
        return NULL;
1311
432k
    return memset(ptr, 0, size);
1312
432k
}
1313
1314
#ifdef CONFIG_BIGNUM
1315
/* called by libbf */
1316
static void *js_bf_realloc(void *opaque, void *ptr, size_t size)
1317
9.73k
{
1318
9.73k
    JSRuntime *rt = opaque;
1319
9.73k
    return js_realloc_rt(rt, ptr, size);
1320
9.73k
}
1321
#endif /* CONFIG_BIGNUM */
1322
1323
/* Throw out of memory in case of error */
1324
void *js_malloc(JSContext *ctx, size_t size)
1325
4.96M
{
1326
4.96M
    void *ptr;
1327
4.96M
    ptr = js_malloc_rt(ctx->rt, size);
1328
4.96M
    if (unlikely(!ptr)) {
1329
12
        JS_ThrowOutOfMemory(ctx);
1330
12
        return NULL;
1331
12
    }
1332
4.96M
    return ptr;
1333
4.96M
}
1334
1335
/* Throw out of memory in case of error */
1336
void *js_mallocz(JSContext *ctx, size_t size)
1337
432k
{
1338
432k
    void *ptr;
1339
432k
    ptr = js_mallocz_rt(ctx->rt, size);
1340
432k
    if (unlikely(!ptr)) {
1341
2
        JS_ThrowOutOfMemory(ctx);
1342
2
        return NULL;
1343
2
    }
1344
432k
    return ptr;
1345
432k
}
1346
1347
void js_free(JSContext *ctx, void *ptr)
1348
986k
{
1349
986k
    js_free_rt(ctx->rt, ptr);
1350
986k
}
1351
1352
/* Throw out of memory in case of error */
1353
void *js_realloc(JSContext *ctx, void *ptr, size_t size)
1354
296k
{
1355
296k
    void *ret;
1356
296k
    ret = js_realloc_rt(ctx->rt, ptr, size);
1357
296k
    if (unlikely(!ret && size != 0)) {
1358
0
        JS_ThrowOutOfMemory(ctx);
1359
0
        return NULL;
1360
0
    }
1361
296k
    return ret;
1362
296k
}
1363
1364
/* store extra allocated size in *pslack if successful */
1365
void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack)
1366
96.3k
{
1367
96.3k
    void *ret;
1368
96.3k
    ret = js_realloc_rt(ctx->rt, ptr, size);
1369
96.3k
    if (unlikely(!ret && size != 0)) {
1370
6
        JS_ThrowOutOfMemory(ctx);
1371
6
        return NULL;
1372
6
    }
1373
96.3k
    if (pslack) {
1374
96.3k
        size_t new_size = js_malloc_usable_size_rt(ctx->rt, ret);
1375
96.3k
        *pslack = (new_size > size) ? new_size - size : 0;
1376
96.3k
    }
1377
96.3k
    return ret;
1378
96.3k
}
1379
1380
size_t js_malloc_usable_size(JSContext *ctx, const void *ptr)
1381
71.9k
{
1382
71.9k
    return js_malloc_usable_size_rt(ctx->rt, ptr);
1383
71.9k
}
1384
1385
/* Throw out of memory exception in case of error */
1386
char *js_strndup(JSContext *ctx, const char *s, size_t n)
1387
12.6k
{
1388
12.6k
    char *ptr;
1389
12.6k
    ptr = js_malloc(ctx, n + 1);
1390
12.6k
    if (ptr) {
1391
12.6k
        memcpy(ptr, s, n);
1392
12.6k
        ptr[n] = '\0';
1393
12.6k
    }
1394
12.6k
    return ptr;
1395
12.6k
}
1396
1397
char *js_strdup(JSContext *ctx, const char *str)
1398
0
{
1399
0
    return js_strndup(ctx, str, strlen(str));
1400
0
}
1401
1402
static no_inline int js_realloc_array(JSContext *ctx, void **parray,
1403
                                      int elem_size, int *psize, int req_size)
1404
93.0k
{
1405
93.0k
    int new_size;
1406
93.0k
    size_t slack;
1407
93.0k
    void *new_array;
1408
    /* XXX: potential arithmetic overflow */
1409
93.0k
    new_size = max_int(req_size, *psize * 3 / 2);
1410
93.0k
    new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack);
1411
93.0k
    if (!new_array)
1412
6
        return -1;
1413
93.0k
    new_size += slack / elem_size;
1414
93.0k
    *psize = new_size;
1415
93.0k
    *parray = new_array;
1416
93.0k
    return 0;
1417
93.0k
}
1418
1419
/* resize the array and update its size if req_size > *psize */
1420
static inline int js_resize_array(JSContext *ctx, void **parray, int elem_size,
1421
                                  int *psize, int req_size)
1422
2.56M
{
1423
2.56M
    if (unlikely(req_size > *psize))
1424
93.0k
        return js_realloc_array(ctx, parray, elem_size, psize, req_size);
1425
2.47M
    else
1426
2.47M
        return 0;
1427
2.56M
}
1428
1429
static inline void js_dbuf_init(JSContext *ctx, DynBuf *s)
1430
366k
{
1431
366k
    dbuf_init2(s, ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
1432
366k
}
1433
1434
738k
static inline int is_digit(int c) {
1435
738k
    return c >= '0' && c <= '9';
1436
738k
}
1437
1438
typedef struct JSClassShortDef {
1439
    JSAtom class_name;
1440
    JSClassFinalizer *finalizer;
1441
    JSClassGCMark *gc_mark;
1442
} JSClassShortDef;
1443
1444
static JSClassShortDef const js_std_class_def[] = {
1445
    { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_OBJECT */
1446
    { JS_ATOM_Array, js_array_finalizer, js_array_mark },       /* JS_CLASS_ARRAY */
1447
    { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */
1448
    { JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */
1449
    { JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */
1450
    { JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */
1451
    { JS_ATOM_Symbol, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_SYMBOL */
1452
    { JS_ATOM_Arguments, js_array_finalizer, js_array_mark },   /* JS_CLASS_ARGUMENTS */
1453
    { JS_ATOM_Arguments, NULL, NULL },                          /* JS_CLASS_MAPPED_ARGUMENTS */
1454
    { JS_ATOM_Date, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_DATE */
1455
    { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_MODULE_NS */
1456
    { JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark }, /* JS_CLASS_C_FUNCTION */
1457
    { JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */
1458
    { JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */
1459
    { JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */
1460
    { JS_ATOM_GeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_GENERATOR_FUNCTION */
1461
    { JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark },      /* JS_CLASS_FOR_IN_ITERATOR */
1462
    { JS_ATOM_RegExp, js_regexp_finalizer, NULL },                              /* JS_CLASS_REGEXP */
1463
    { JS_ATOM_ArrayBuffer, js_array_buffer_finalizer, NULL },                   /* JS_CLASS_ARRAY_BUFFER */
1464
    { JS_ATOM_SharedArrayBuffer, js_array_buffer_finalizer, NULL },             /* JS_CLASS_SHARED_ARRAY_BUFFER */
1465
    { JS_ATOM_Uint8ClampedArray, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8C_ARRAY */
1466
    { JS_ATOM_Int8Array, js_typed_array_finalizer, js_typed_array_mark },       /* JS_CLASS_INT8_ARRAY */
1467
    { JS_ATOM_Uint8Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_UINT8_ARRAY */
1468
    { JS_ATOM_Int16Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT16_ARRAY */
1469
    { JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT16_ARRAY */
1470
    { JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT32_ARRAY */
1471
    { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT32_ARRAY */
1472
#ifdef CONFIG_BIGNUM
1473
    { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark },   /* JS_CLASS_BIG_INT64_ARRAY */
1474
    { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark },  /* JS_CLASS_BIG_UINT64_ARRAY */
1475
#endif
1476
    { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT32_ARRAY */
1477
    { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT64_ARRAY */
1478
    { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark },        /* JS_CLASS_DATAVIEW */
1479
#ifdef CONFIG_BIGNUM
1480
    { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark },      /* JS_CLASS_BIG_INT */
1481
    { JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark },    /* JS_CLASS_BIG_FLOAT */
1482
    { JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL },      /* JS_CLASS_FLOAT_ENV */
1483
    { JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark },    /* JS_CLASS_BIG_DECIMAL */
1484
    { JS_ATOM_OperatorSet, js_operator_set_finalizer, js_operator_set_mark },    /* JS_CLASS_OPERATOR_SET */
1485
#endif
1486
    { JS_ATOM_Map, js_map_finalizer, js_map_mark },             /* JS_CLASS_MAP */
1487
    { JS_ATOM_Set, js_map_finalizer, js_map_mark },             /* JS_CLASS_SET */
1488
    { JS_ATOM_WeakMap, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKMAP */
1489
    { JS_ATOM_WeakSet, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKSET */
1490
    { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */
1491
    { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */
1492
    { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */
1493
    { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */
1494
    { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */
1495
    { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */
1496
};
1497
1498
static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab,
1499
                            int start, int count)
1500
7
{
1501
7
    JSClassDef cm_s, *cm = &cm_s;
1502
7
    int i, class_id;
1503
1504
168
    for(i = 0; i < count; i++) {
1505
161
        class_id = i + start;
1506
161
        memset(cm, 0, sizeof(*cm));
1507
161
        cm->finalizer = tab[i].finalizer;
1508
161
        cm->gc_mark = tab[i].gc_mark;
1509
161
        if (JS_NewClass1(rt, class_id, cm, tab[i].class_name) < 0)
1510
0
            return -1;
1511
161
    }
1512
7
    return 0;
1513
7
}
1514
1515
#ifdef CONFIG_BIGNUM
1516
static JSValue JS_ThrowUnsupportedOperation(JSContext *ctx)
1517
0
{
1518
0
    return JS_ThrowTypeError(ctx, "unsupported operation");
1519
0
}
1520
1521
static JSValue invalid_to_string(JSContext *ctx, JSValueConst val)
1522
0
{
1523
0
    return JS_ThrowUnsupportedOperation(ctx);
1524
0
}
1525
1526
static JSValue invalid_from_string(JSContext *ctx, const char *buf,
1527
                                   int radix, int flags, slimb_t *pexponent)
1528
0
{
1529
0
    return JS_NAN;
1530
0
}
1531
1532
static int invalid_unary_arith(JSContext *ctx,
1533
                               JSValue *pres, OPCodeEnum op, JSValue op1)
1534
0
{
1535
0
    JS_FreeValue(ctx, op1);
1536
0
    JS_ThrowUnsupportedOperation(ctx);
1537
0
    return -1;
1538
0
}
1539
1540
static int invalid_binary_arith(JSContext *ctx, OPCodeEnum op,
1541
                                JSValue *pres, JSValue op1, JSValue op2)
1542
0
{
1543
0
    JS_FreeValue(ctx, op1);
1544
0
    JS_FreeValue(ctx, op2);
1545
0
    JS_ThrowUnsupportedOperation(ctx);
1546
0
    return -1;
1547
0
}
1548
1549
static JSValue invalid_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
1550
                                            int64_t exponent)
1551
0
{
1552
0
    return JS_ThrowUnsupportedOperation(ctx);
1553
0
}
1554
1555
static int invalid_mul_pow10(JSContext *ctx, JSValue *sp)
1556
0
{
1557
0
    JS_ThrowUnsupportedOperation(ctx);
1558
0
    return -1;
1559
0
}
1560
1561
static void set_dummy_numeric_ops(JSNumericOperations *ops)
1562
9
{
1563
9
    ops->to_string = invalid_to_string;
1564
9
    ops->from_string = invalid_from_string;
1565
9
    ops->unary_arith = invalid_unary_arith;
1566
9
    ops->binary_arith = invalid_binary_arith;
1567
9
    ops->mul_pow10_to_float64 = invalid_mul_pow10_to_float64;
1568
9
    ops->mul_pow10 = invalid_mul_pow10;
1569
9
}
1570
1571
#endif /* CONFIG_BIGNUM */
1572
1573
#if !defined(CONFIG_STACK_CHECK)
1574
/* no stack limitation */
1575
static inline uintptr_t js_get_stack_pointer(void)
1576
{
1577
    return 0;
1578
}
1579
1580
static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
1581
{
1582
    return FALSE;
1583
}
1584
#else
1585
/* Note: OS and CPU dependent */
1586
static inline uintptr_t js_get_stack_pointer(void)
1587
2.23M
{
1588
2.23M
    return (uintptr_t)__builtin_frame_address(0);
1589
2.23M
}
1590
1591
static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
1592
2.23M
{
1593
2.23M
    uintptr_t sp;
1594
2.23M
    sp = js_get_stack_pointer() - alloca_size;
1595
2.23M
    return unlikely(sp < rt->stack_limit);
1596
2.23M
}
1597
#endif
1598
1599
JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
1600
3
{
1601
3
    JSRuntime *rt;
1602
3
    JSMallocState ms;
1603
1604
3
    memset(&ms, 0, sizeof(ms));
1605
3
    ms.opaque = opaque;
1606
3
    ms.malloc_limit = -1;
1607
1608
3
    rt = mf->js_malloc(&ms, sizeof(JSRuntime));
1609
3
    if (!rt)
1610
0
        return NULL;
1611
3
    memset(rt, 0, sizeof(*rt));
1612
3
    rt->mf = *mf;
1613
3
    if (!rt->mf.js_malloc_usable_size) {
1614
        /* use dummy function if none provided */
1615
0
        rt->mf.js_malloc_usable_size = js_malloc_usable_size_unknown;
1616
0
    }
1617
3
    rt->malloc_state = ms;
1618
3
    rt->malloc_gc_threshold = 256 * 1024;
1619
1620
3
#ifdef CONFIG_BIGNUM
1621
3
    bf_context_init(&rt->bf_ctx, js_bf_realloc, rt);
1622
3
    set_dummy_numeric_ops(&rt->bigint_ops);
1623
3
    set_dummy_numeric_ops(&rt->bigfloat_ops);
1624
3
    set_dummy_numeric_ops(&rt->bigdecimal_ops);
1625
3
#endif
1626
1627
3
    init_list_head(&rt->context_list);
1628
3
    init_list_head(&rt->gc_obj_list);
1629
3
    init_list_head(&rt->gc_zero_ref_count_list);
1630
3
    rt->gc_phase = JS_GC_PHASE_NONE;
1631
    
1632
#ifdef DUMP_LEAKS
1633
    init_list_head(&rt->string_list);
1634
#endif
1635
3
    init_list_head(&rt->job_list);
1636
1637
3
    if (JS_InitAtoms(rt))
1638
0
        goto fail;
1639
1640
    /* create the object, array and function classes */
1641
3
    if (init_class_range(rt, js_std_class_def, JS_CLASS_OBJECT,
1642
3
                         countof(js_std_class_def)) < 0)
1643
0
        goto fail;
1644
3
    rt->class_array[JS_CLASS_ARGUMENTS].exotic = &js_arguments_exotic_methods;
1645
3
    rt->class_array[JS_CLASS_STRING].exotic = &js_string_exotic_methods;
1646
3
    rt->class_array[JS_CLASS_MODULE_NS].exotic = &js_module_ns_exotic_methods;
1647
1648
3
    rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function;
1649
3
    rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_c_function_data_call;
1650
3
    rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function;
1651
3
    rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_generator_function_call;
1652
3
    if (init_shape_hash(rt))
1653
0
        goto fail;
1654
1655
3
    rt->stack_size = JS_DEFAULT_STACK_SIZE;
1656
3
    JS_UpdateStackTop(rt);
1657
1658
3
    rt->current_exception = JS_NULL;
1659
1660
3
    return rt;
1661
0
 fail:
1662
0
    JS_FreeRuntime(rt);
1663
0
    return NULL;
1664
3
}
1665
1666
void *JS_GetRuntimeOpaque(JSRuntime *rt)
1667
0
{
1668
0
    return rt->user_opaque;
1669
0
}
1670
1671
void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque)
1672
0
{
1673
0
    rt->user_opaque = opaque;
1674
0
}
1675
1676
/* default memory allocation functions with memory limitation */
1677
static inline size_t js_def_malloc_usable_size(void *ptr)
1678
15.2M
{
1679
#if defined(__APPLE__)
1680
    return malloc_size(ptr);
1681
#elif defined(_WIN32)
1682
    return _msize(ptr);
1683
#elif defined(EMSCRIPTEN)
1684
    return 0;
1685
#elif defined(__linux__)
1686
15.2M
    return malloc_usable_size(ptr);
1687
#else
1688
    /* change this to `return 0;` if compilation fails */
1689
    return malloc_usable_size(ptr);
1690
#endif
1691
15.2M
}
1692
1693
static void *js_def_malloc(JSMallocState *s, size_t size)
1694
6.98M
{
1695
6.98M
    void *ptr;
1696
1697
    /* Do not allocate zero bytes: behavior is platform dependent */
1698
6.98M
    assert(size != 0);
1699
1700
6.98M
    if (unlikely(s->malloc_size + size > s->malloc_limit))
1701
38
        return NULL;
1702
1703
6.98M
    ptr = malloc(size);
1704
6.98M
    if (!ptr)
1705
0
        return NULL;
1706
1707
6.98M
    s->malloc_count++;
1708
6.98M
    s->malloc_size += js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
1709
6.98M
    return ptr;
1710
6.98M
}
1711
1712
static void js_def_free(JSMallocState *s, void *ptr)
1713
6.16M
{
1714
6.16M
    if (!ptr)
1715
539k
        return;
1716
1717
5.62M
    s->malloc_count--;
1718
5.62M
    s->malloc_size -= js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
1719
5.62M
    free(ptr);
1720
5.62M
}
1721
1722
static void *js_def_realloc(JSMallocState *s, void *ptr, size_t size)
1723
1.88M
{
1724
1.88M
    size_t old_size;
1725
1726
1.88M
    if (!ptr) {
1727
430k
        if (size == 0)
1728
43.4k
            return NULL;
1729
387k
        return js_def_malloc(s, size);
1730
430k
    }
1731
1.45M
    old_size = js_def_malloc_usable_size(ptr);
1732
1.45M
    if (size == 0) {
1733
244k
        s->malloc_count--;
1734
244k
        s->malloc_size -= old_size + MALLOC_OVERHEAD;
1735
244k
        free(ptr);
1736
244k
        return NULL;
1737
244k
    }
1738
1.21M
    if (s->malloc_size + size - old_size > s->malloc_limit)
1739
324
        return NULL;
1740
1741
1.20M
    ptr = realloc(ptr, size);
1742
1.20M
    if (!ptr)
1743
0
        return NULL;
1744
1745
1.20M
    s->malloc_size += js_def_malloc_usable_size(ptr) - old_size;
1746
1.20M
    return ptr;
1747
1.20M
}
1748
1749
static const JSMallocFunctions def_malloc_funcs = {
1750
    js_def_malloc,
1751
    js_def_free,
1752
    js_def_realloc,
1753
#if defined(__APPLE__)
1754
    malloc_size,
1755
#elif defined(_WIN32)
1756
    (size_t (*)(const void *))_msize,
1757
#elif defined(EMSCRIPTEN)
1758
    NULL,
1759
#elif defined(__linux__)
1760
    (size_t (*)(const void *))malloc_usable_size,
1761
#else
1762
    /* change this to `NULL,` if compilation fails */
1763
    malloc_usable_size,
1764
#endif
1765
};
1766
1767
JSRuntime *JS_NewRuntime(void)
1768
3
{
1769
3
    return JS_NewRuntime2(&def_malloc_funcs, NULL);
1770
3
}
1771
1772
void JS_SetMemoryLimit(JSRuntime *rt, size_t limit)
1773
3
{
1774
3
    rt->malloc_state.malloc_limit = limit;
1775
3
}
1776
1777
/* use -1 to disable automatic GC */
1778
void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold)
1779
0
{
1780
0
    rt->malloc_gc_threshold = gc_threshold;
1781
0
}
1782
1783
#define malloc(s) malloc_is_forbidden(s)
1784
#define free(p) free_is_forbidden(p)
1785
#define realloc(p,s) realloc_is_forbidden(p,s)
1786
1787
void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque)
1788
2
{
1789
2
    rt->interrupt_handler = cb;
1790
2
    rt->interrupt_opaque = opaque;
1791
2
}
1792
1793
void JS_SetCanBlock(JSRuntime *rt, BOOL can_block)
1794
0
{
1795
0
    rt->can_block = can_block;
1796
0
}
1797
1798
void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
1799
                                      const JSSharedArrayBufferFunctions *sf)
1800
0
{
1801
0
    rt->sab_funcs = *sf;
1802
0
}
1803
1804
/* return 0 if OK, < 0 if exception */
1805
int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func,
1806
                  int argc, JSValueConst *argv)
1807
81.9k
{
1808
81.9k
    JSRuntime *rt = ctx->rt;
1809
81.9k
    JSJobEntry *e;
1810
81.9k
    int i;
1811
1812
81.9k
    e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue));
1813
81.9k
    if (!e)
1814
0
        return -1;
1815
81.9k
    e->ctx = ctx;
1816
81.9k
    e->job_func = job_func;
1817
81.9k
    e->argc = argc;
1818
409k
    for(i = 0; i < argc; i++) {
1819
327k
        e->argv[i] = JS_DupValue(ctx, argv[i]);
1820
327k
    }
1821
81.9k
    list_add_tail(&e->link, &rt->job_list);
1822
81.9k
    return 0;
1823
81.9k
}
1824
1825
BOOL JS_IsJobPending(JSRuntime *rt)
1826
0
{
1827
0
    return !list_empty(&rt->job_list);
1828
0
}
1829
1830
/* return < 0 if exception, 0 if no job pending, 1 if a job was
1831
   executed successfully. the context of the job is stored in '*pctx' */
1832
int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx)
1833
16
{
1834
16
    JSContext *ctx;
1835
16
    JSJobEntry *e;
1836
16
    JSValue res;
1837
16
    int i, ret;
1838
1839
16
    if (list_empty(&rt->job_list)) {
1840
16
        *pctx = NULL;
1841
16
        return 0;
1842
16
    }
1843
1844
    /* get the first pending job and execute it */
1845
0
    e = list_entry(rt->job_list.next, JSJobEntry, link);
1846
0
    list_del(&e->link);
1847
0
    ctx = e->ctx;
1848
0
    res = e->job_func(e->ctx, e->argc, (JSValueConst *)e->argv);
1849
0
    for(i = 0; i < e->argc; i++)
1850
0
        JS_FreeValue(ctx, e->argv[i]);
1851
0
    if (JS_IsException(res))
1852
0
        ret = -1;
1853
0
    else
1854
0
        ret = 1;
1855
0
    JS_FreeValue(ctx, res);
1856
0
    js_free(ctx, e);
1857
0
    *pctx = ctx;
1858
0
    return ret;
1859
16
}
1860
1861
static inline uint32_t atom_get_free(const JSAtomStruct *p)
1862
86.4k
{
1863
86.4k
    return (uintptr_t)p >> 1;
1864
86.4k
}
1865
1866
static inline BOOL atom_is_free(const JSAtomStruct *p)
1867
122k
{
1868
122k
    return (uintptr_t)p & 1;
1869
122k
}
1870
1871
static inline JSAtomStruct *atom_set_free(uint32_t v)
1872
87.0k
{
1873
87.0k
    return (JSAtomStruct *)(((uintptr_t)v << 1) | 1);
1874
87.0k
}
1875
1876
/* Note: the string contents are uninitialized */
1877
static JSString *js_alloc_string_rt(JSRuntime *rt, int max_len, int is_wide_char)
1878
1.16M
{
1879
1.16M
    JSString *str;
1880
1.16M
    str = js_malloc_rt(rt, sizeof(JSString) + (max_len << is_wide_char) + 1 - is_wide_char);
1881
1.16M
    if (unlikely(!str))
1882
0
        return NULL;
1883
1.16M
    str->header.ref_count = 1;
1884
1.16M
    str->is_wide_char = is_wide_char;
1885
1.16M
    str->len = max_len;
1886
1.16M
    str->atom_type = 0;
1887
1.16M
    str->hash = 0;          /* optional but costless */
1888
1.16M
    str->hash_next = 0;     /* optional */
1889
#ifdef DUMP_LEAKS
1890
    list_add_tail(&str->link, &rt->string_list);
1891
#endif
1892
1.16M
    return str;
1893
1.16M
}
1894
1895
static JSString *js_alloc_string(JSContext *ctx, int max_len, int is_wide_char)
1896
1.16M
{
1897
1.16M
    JSString *p;
1898
1.16M
    p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char);
1899
1.16M
    if (unlikely(!p)) {
1900
0
        JS_ThrowOutOfMemory(ctx);
1901
0
        return NULL;
1902
0
    }
1903
1.16M
    return p;
1904
1.16M
}
1905
1906
/* same as JS_FreeValueRT() but faster */
1907
static inline void js_free_string(JSRuntime *rt, JSString *str)
1908
91.4k
{
1909
91.4k
    if (--str->header.ref_count <= 0) {
1910
1.76k
        if (str->atom_type) {
1911
0
            JS_FreeAtomStruct(rt, str);
1912
1.76k
        } else {
1913
#ifdef DUMP_LEAKS
1914
            list_del(&str->link);
1915
#endif
1916
1.76k
            js_free_rt(rt, str);
1917
1.76k
        }
1918
1.76k
    }
1919
91.4k
}
1920
1921
void JS_SetRuntimeInfo(JSRuntime *rt, const char *s)
1922
0
{
1923
0
    if (rt)
1924
0
        rt->rt_info = s;
1925
0
}
1926
1927
void JS_FreeRuntime(JSRuntime *rt)
1928
0
{
1929
0
    struct list_head *el, *el1;
1930
0
    int i;
1931
1932
0
    JS_FreeValueRT(rt, rt->current_exception);
1933
1934
0
    list_for_each_safe(el, el1, &rt->job_list) {
1935
0
        JSJobEntry *e = list_entry(el, JSJobEntry, link);
1936
0
        for(i = 0; i < e->argc; i++)
1937
0
            JS_FreeValueRT(rt, e->argv[i]);
1938
0
        js_free_rt(rt, e);
1939
0
    }
1940
0
    init_list_head(&rt->job_list);
1941
1942
0
    JS_RunGC(rt);
1943
1944
#ifdef DUMP_LEAKS
1945
    /* leaking objects */
1946
    {
1947
        BOOL header_done;
1948
        JSGCObjectHeader *p;
1949
        int count;
1950
1951
        /* remove the internal refcounts to display only the object
1952
           referenced externally */
1953
        list_for_each(el, &rt->gc_obj_list) {
1954
            p = list_entry(el, JSGCObjectHeader, link);
1955
            p->mark = 0;
1956
        }
1957
        gc_decref(rt);
1958
1959
        header_done = FALSE;
1960
        list_for_each(el, &rt->gc_obj_list) {
1961
            p = list_entry(el, JSGCObjectHeader, link);
1962
            if (p->ref_count != 0) {
1963
                if (!header_done) {
1964
                    printf("Object leaks:\n");
1965
                    JS_DumpObjectHeader(rt);
1966
                    header_done = TRUE;
1967
                }
1968
                JS_DumpGCObject(rt, p);
1969
            }
1970
        }
1971
1972
        count = 0;
1973
        list_for_each(el, &rt->gc_obj_list) {
1974
            p = list_entry(el, JSGCObjectHeader, link);
1975
            if (p->ref_count == 0) {
1976
                count++;
1977
            }
1978
        }
1979
        if (count != 0)
1980
            printf("Secondary object leaks: %d\n", count);
1981
    }
1982
#endif
1983
0
    assert(list_empty(&rt->gc_obj_list));
1984
1985
    /* free the classes */
1986
0
    for(i = 0; i < rt->class_count; i++) {
1987
0
        JSClass *cl = &rt->class_array[i];
1988
0
        if (cl->class_id != 0) {
1989
0
            JS_FreeAtomRT(rt, cl->class_name);
1990
0
        }
1991
0
    }
1992
0
    js_free_rt(rt, rt->class_array);
1993
1994
0
#ifdef CONFIG_BIGNUM
1995
0
    bf_context_end(&rt->bf_ctx);
1996
0
#endif
1997
1998
#ifdef DUMP_LEAKS
1999
    /* only the atoms defined in JS_InitAtoms() should be left */
2000
    {
2001
        BOOL header_done = FALSE;
2002
2003
        for(i = 0; i < rt->atom_size; i++) {
2004
            JSAtomStruct *p = rt->atom_array[i];
2005
            if (!atom_is_free(p) /* && p->str*/) {
2006
                if (i >= JS_ATOM_END || p->header.ref_count != 1) {
2007
                    if (!header_done) {
2008
                        header_done = TRUE;
2009
                        if (rt->rt_info) {
2010
                            printf("%s:1: atom leakage:", rt->rt_info);
2011
                        } else {
2012
                            printf("Atom leaks:\n"
2013
                                   "    %6s %6s %s\n",
2014
                                   "ID", "REFCNT", "NAME");
2015
                        }
2016
                    }
2017
                    if (rt->rt_info) {
2018
                        printf(" ");
2019
                    } else {
2020
                        printf("    %6u %6u ", i, p->header.ref_count);
2021
                    }
2022
                    switch (p->atom_type) {
2023
                    case JS_ATOM_TYPE_STRING:
2024
                        JS_DumpString(rt, p);
2025
                        break;
2026
                    case JS_ATOM_TYPE_GLOBAL_SYMBOL:
2027
                        printf("Symbol.for(");
2028
                        JS_DumpString(rt, p);
2029
                        printf(")");
2030
                        break;
2031
                    case JS_ATOM_TYPE_SYMBOL:
2032
                        if (p->hash == JS_ATOM_HASH_SYMBOL) {
2033
                            printf("Symbol(");
2034
                            JS_DumpString(rt, p);
2035
                            printf(")");
2036
                        } else {
2037
                            printf("Private(");
2038
                            JS_DumpString(rt, p);
2039
                            printf(")");
2040
                        }
2041
                        break;
2042
                    }
2043
                    if (rt->rt_info) {
2044
                        printf(":%u", p->header.ref_count);
2045
                    } else {
2046
                        printf("\n");
2047
                    }
2048
                }
2049
            }
2050
        }
2051
        if (rt->rt_info && header_done)
2052
            printf("\n");
2053
    }
2054
#endif
2055
2056
    /* free the atoms */
2057
0
    for(i = 0; i < rt->atom_size; i++) {
2058
0
        JSAtomStruct *p = rt->atom_array[i];
2059
0
        if (!atom_is_free(p)) {
2060
#ifdef DUMP_LEAKS
2061
            list_del(&p->link);
2062
#endif
2063
0
            js_free_rt(rt, p);
2064
0
        }
2065
0
    }
2066
0
    js_free_rt(rt, rt->atom_array);
2067
0
    js_free_rt(rt, rt->atom_hash);
2068
0
    js_free_rt(rt, rt->shape_hash);
2069
#ifdef DUMP_LEAKS
2070
    if (!list_empty(&rt->string_list)) {
2071
        if (rt->rt_info) {
2072
            printf("%s:1: string leakage:", rt->rt_info);
2073
        } else {
2074
            printf("String leaks:\n"
2075
                   "    %6s %s\n",
2076
                   "REFCNT", "VALUE");
2077
        }
2078
        list_for_each_safe(el, el1, &rt->string_list) {
2079
            JSString *str = list_entry(el, JSString, link);
2080
            if (rt->rt_info) {
2081
                printf(" ");
2082
            } else {
2083
                printf("    %6u ", str->header.ref_count);
2084
            }
2085
            JS_DumpString(rt, str);
2086
            if (rt->rt_info) {
2087
                printf(":%u", str->header.ref_count);
2088
            } else {
2089
                printf("\n");
2090
            }
2091
            list_del(&str->link);
2092
            js_free_rt(rt, str);
2093
        }
2094
        if (rt->rt_info)
2095
            printf("\n");
2096
    }
2097
    {
2098
        JSMallocState *s = &rt->malloc_state;
2099
        if (s->malloc_count > 1) {
2100
            if (rt->rt_info)
2101
                printf("%s:1: ", rt->rt_info);
2102
            printf("Memory leak: %"PRIu64" bytes lost in %"PRIu64" block%s\n",
2103
                   (uint64_t)(s->malloc_size - sizeof(JSRuntime)),
2104
                   (uint64_t)(s->malloc_count - 1), &"s"[s->malloc_count == 2]);
2105
        }
2106
    }
2107
#endif
2108
2109
0
    {
2110
0
        JSMallocState ms = rt->malloc_state;
2111
0
        rt->mf.js_free(&ms, rt);
2112
0
    }
2113
0
}
2114
2115
JSContext *JS_NewContextRaw(JSRuntime *rt)
2116
3
{
2117
3
    JSContext *ctx;
2118
3
    int i;
2119
2120
3
    ctx = js_mallocz_rt(rt, sizeof(JSContext));
2121
3
    if (!ctx)
2122
0
        return NULL;
2123
3
    ctx->header.ref_count = 1;
2124
3
    add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT);
2125
2126
3
    ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) *
2127
3
                                    rt->class_count);
2128
3
    if (!ctx->class_proto) {
2129
0
        js_free_rt(rt, ctx);
2130
0
        return NULL;
2131
0
    }
2132
3
    ctx->rt = rt;
2133
3
    list_add_tail(&ctx->link, &rt->context_list);
2134
3
#ifdef CONFIG_BIGNUM
2135
3
    ctx->bf_ctx = &rt->bf_ctx;
2136
3
    ctx->fp_env.prec = 113;
2137
3
    ctx->fp_env.flags = bf_set_exp_bits(15) | BF_RNDN | BF_FLAG_SUBNORMAL;
2138
3
#endif
2139
177
    for(i = 0; i < rt->class_count; i++)
2140
174
        ctx->class_proto[i] = JS_NULL;
2141
3
    ctx->array_ctor = JS_NULL;
2142
3
    ctx->regexp_ctor = JS_NULL;
2143
3
    ctx->promise_ctor = JS_NULL;
2144
3
    init_list_head(&ctx->loaded_modules);
2145
2146
3
    JS_AddIntrinsicBasicObjects(ctx);
2147
3
    return ctx;
2148
3
}
2149
2150
JSContext *JS_NewContext(JSRuntime *rt)
2151
0
{
2152
0
    JSContext *ctx;
2153
2154
0
    ctx = JS_NewContextRaw(rt);
2155
0
    if (!ctx)
2156
0
        return NULL;
2157
2158
0
    JS_AddIntrinsicBaseObjects(ctx);
2159
0
    JS_AddIntrinsicDate(ctx);
2160
0
    JS_AddIntrinsicEval(ctx);
2161
0
    JS_AddIntrinsicStringNormalize(ctx);
2162
0
    JS_AddIntrinsicRegExp(ctx);
2163
0
    JS_AddIntrinsicJSON(ctx);
2164
0
    JS_AddIntrinsicProxy(ctx);
2165
0
    JS_AddIntrinsicMapSet(ctx);
2166
0
    JS_AddIntrinsicTypedArrays(ctx);
2167
0
    JS_AddIntrinsicPromise(ctx);
2168
0
#ifdef CONFIG_BIGNUM
2169
0
    JS_AddIntrinsicBigInt(ctx);
2170
0
#endif
2171
0
    return ctx;
2172
0
}
2173
2174
void *JS_GetContextOpaque(JSContext *ctx)
2175
0
{
2176
0
    return ctx->user_opaque;
2177
0
}
2178
2179
void JS_SetContextOpaque(JSContext *ctx, void *opaque)
2180
0
{
2181
0
    ctx->user_opaque = opaque;
2182
0
}
2183
2184
/* set the new value and free the old value after (freeing the value
2185
   can reallocate the object data) */
2186
static inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val)
2187
2.18M
{
2188
2.18M
    JSValue old_val;
2189
2.18M
    old_val = *pval;
2190
2.18M
    *pval = new_val;
2191
2.18M
    JS_FreeValue(ctx, old_val);
2192
2.18M
}
2193
2194
void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj)
2195
0
{
2196
0
    JSRuntime *rt = ctx->rt;
2197
0
    assert(class_id < rt->class_count);
2198
0
    set_value(ctx, &ctx->class_proto[class_id], obj);
2199
0
}
2200
2201
JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id)
2202
0
{
2203
0
    JSRuntime *rt = ctx->rt;
2204
0
    assert(class_id < rt->class_count);
2205
0
    return JS_DupValue(ctx, ctx->class_proto[class_id]);
2206
0
}
2207
2208
typedef enum JSFreeModuleEnum {
2209
    JS_FREE_MODULE_ALL,
2210
    JS_FREE_MODULE_NOT_RESOLVED,
2211
    JS_FREE_MODULE_NOT_EVALUATED,
2212
} JSFreeModuleEnum;
2213
2214
/* XXX: would be more efficient with separate module lists */
2215
static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag)
2216
2
{
2217
2
    struct list_head *el, *el1;
2218
5
    list_for_each_safe(el, el1, &ctx->loaded_modules) {
2219
5
        JSModuleDef *m = list_entry(el, JSModuleDef, link);
2220
5
        if (flag == JS_FREE_MODULE_ALL ||
2221
5
            (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved) ||
2222
5
            (flag == JS_FREE_MODULE_NOT_EVALUATED && !m->evaluated)) {
2223
2
            js_free_module_def(ctx, m);
2224
2
        }
2225
5
    }
2226
2
}
2227
2228
JSContext *JS_DupContext(JSContext *ctx)
2229
47.3k
{
2230
47.3k
    ctx->header.ref_count++;
2231
47.3k
    return ctx;
2232
47.3k
}
2233
2234
/* used by the GC */
2235
static void JS_MarkContext(JSRuntime *rt, JSContext *ctx,
2236
                           JS_MarkFunc *mark_func)
2237
46
{
2238
46
    int i;
2239
46
    struct list_head *el;
2240
2241
    /* modules are not seen by the GC, so we directly mark the objects
2242
       referenced by each module */
2243
100
    list_for_each(el, &ctx->loaded_modules) {
2244
100
        JSModuleDef *m = list_entry(el, JSModuleDef, link);
2245
100
        js_mark_module_def(rt, m, mark_func);
2246
100
    }
2247
2248
46
    JS_MarkValue(rt, ctx->global_obj, mark_func);
2249
46
    JS_MarkValue(rt, ctx->global_var_obj, mark_func);
2250
2251
46
    JS_MarkValue(rt, ctx->throw_type_error, mark_func);
2252
46
    JS_MarkValue(rt, ctx->eval_obj, mark_func);
2253
2254
46
    JS_MarkValue(rt, ctx->array_proto_values, mark_func);
2255
414
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
2256
368
        JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);
2257
368
    }
2258
2.71k
    for(i = 0; i < rt->class_count; i++) {
2259
2.66k
        JS_MarkValue(rt, ctx->class_proto[i], mark_func);
2260
2.66k
    }
2261
46
    JS_MarkValue(rt, ctx->iterator_proto, mark_func);
2262
46
    JS_MarkValue(rt, ctx->async_iterator_proto, mark_func);
2263
46
    JS_MarkValue(rt, ctx->promise_ctor, mark_func);
2264
46
    JS_MarkValue(rt, ctx->array_ctor, mark_func);
2265
46
    JS_MarkValue(rt, ctx->regexp_ctor, mark_func);
2266
46
    JS_MarkValue(rt, ctx->function_ctor, mark_func);
2267
46
    JS_MarkValue(rt, ctx->function_proto, mark_func);
2268
2269
46
    if (ctx->array_shape)
2270
46
        mark_func(rt, &ctx->array_shape->header);
2271
46
}
2272
2273
void JS_FreeContext(JSContext *ctx)
2274
46.4k
{
2275
46.4k
    JSRuntime *rt = ctx->rt;
2276
46.4k
    int i;
2277
2278
46.4k
    if (--ctx->header.ref_count > 0)
2279
46.4k
        return;
2280
0
    assert(ctx->header.ref_count == 0);
2281
    
2282
#ifdef DUMP_ATOMS
2283
    JS_DumpAtoms(ctx->rt);
2284
#endif
2285
#ifdef DUMP_SHAPES
2286
    JS_DumpShapes(ctx->rt);
2287
#endif
2288
#ifdef DUMP_OBJECTS
2289
    {
2290
        struct list_head *el;
2291
        JSGCObjectHeader *p;
2292
        printf("JSObjects: {\n");
2293
        JS_DumpObjectHeader(ctx->rt);
2294
        list_for_each(el, &rt->gc_obj_list) {
2295
            p = list_entry(el, JSGCObjectHeader, link);
2296
            JS_DumpGCObject(rt, p);
2297
        }
2298
        printf("}\n");
2299
    }
2300
#endif
2301
#ifdef DUMP_MEM
2302
    {
2303
        JSMemoryUsage stats;
2304
        JS_ComputeMemoryUsage(rt, &stats);
2305
        JS_DumpMemoryUsage(stdout, &stats, rt);
2306
    }
2307
#endif
2308
2309
0
    js_free_modules(ctx, JS_FREE_MODULE_ALL);
2310
2311
0
    JS_FreeValue(ctx, ctx->global_obj);
2312
0
    JS_FreeValue(ctx, ctx->global_var_obj);
2313
2314
0
    JS_FreeValue(ctx, ctx->throw_type_error);
2315
0
    JS_FreeValue(ctx, ctx->eval_obj);
2316
2317
0
    JS_FreeValue(ctx, ctx->array_proto_values);
2318
0
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
2319
0
        JS_FreeValue(ctx, ctx->native_error_proto[i]);
2320
0
    }
2321
0
    for(i = 0; i < rt->class_count; i++) {
2322
0
        JS_FreeValue(ctx, ctx->class_proto[i]);
2323
0
    }
2324
0
    js_free_rt(rt, ctx->class_proto);
2325
0
    JS_FreeValue(ctx, ctx->iterator_proto);
2326
0
    JS_FreeValue(ctx, ctx->async_iterator_proto);
2327
0
    JS_FreeValue(ctx, ctx->promise_ctor);
2328
0
    JS_FreeValue(ctx, ctx->array_ctor);
2329
0
    JS_FreeValue(ctx, ctx->regexp_ctor);
2330
0
    JS_FreeValue(ctx, ctx->function_ctor);
2331
0
    JS_FreeValue(ctx, ctx->function_proto);
2332
2333
0
    js_free_shape_null(ctx->rt, ctx->array_shape);
2334
2335
0
    list_del(&ctx->link);
2336
0
    remove_gc_object(&ctx->header);
2337
0
    js_free_rt(ctx->rt, ctx);
2338
0
}
2339
2340
JSRuntime *JS_GetRuntime(JSContext *ctx)
2341
18
{
2342
18
    return ctx->rt;
2343
18
}
2344
2345
static void update_stack_limit(JSRuntime *rt)
2346
3
{
2347
3
    if (rt->stack_size == 0) {
2348
0
        rt->stack_limit = 0; /* no limit */
2349
3
    } else {
2350
3
        rt->stack_limit = rt->stack_top - rt->stack_size;
2351
3
    }
2352
3
}
2353
2354
void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size)
2355
0
{
2356
0
    rt->stack_size = stack_size;
2357
0
    update_stack_limit(rt);
2358
0
}
2359
2360
void JS_UpdateStackTop(JSRuntime *rt)
2361
3
{
2362
3
    rt->stack_top = js_get_stack_pointer();
2363
3
    update_stack_limit(rt);
2364
3
}
2365
2366
static inline BOOL is_strict_mode(JSContext *ctx)
2367
1.12k
{
2368
1.12k
    JSStackFrame *sf = ctx->rt->current_stack_frame;
2369
1.12k
    return (sf && (sf->js_mode & JS_MODE_STRICT));
2370
1.12k
}
2371
2372
#ifdef CONFIG_BIGNUM
2373
static inline BOOL is_math_mode(JSContext *ctx)
2374
194k
{
2375
194k
    JSStackFrame *sf = ctx->rt->current_stack_frame;
2376
194k
    return (sf && (sf->js_mode & JS_MODE_MATH));
2377
194k
}
2378
#endif
2379
2380
/* JSAtom support */
2381
2382
85.5M
#define JS_ATOM_TAG_INT (1U << 31)
2383
153k
#define JS_ATOM_MAX_INT (JS_ATOM_TAG_INT - 1)
2384
17
#define JS_ATOM_MAX     ((1U << 30) - 1)
2385
2386
/* return the max count from the hash size */
2387
8
#define JS_ATOM_COUNT_RESIZE(n) ((n) * 2)
2388
2389
static inline BOOL __JS_AtomIsConst(JSAtom v)
2390
20.9M
{
2391
#if defined(DUMP_LEAKS) && DUMP_LEAKS > 1
2392
        return (int32_t)v <= 0;
2393
#else
2394
20.9M
        return (int32_t)v < JS_ATOM_END;
2395
20.9M
#endif
2396
20.9M
}
2397
2398
static inline BOOL __JS_AtomIsTaggedInt(JSAtom v)
2399
46.0M
{
2400
46.0M
    return (v & JS_ATOM_TAG_INT) != 0;
2401
46.0M
}
2402
2403
static inline JSAtom __JS_AtomFromUInt32(uint32_t v)
2404
497k
{
2405
497k
    return v | JS_ATOM_TAG_INT;
2406
497k
}
2407
2408
static inline uint32_t __JS_AtomToUInt32(JSAtom atom)
2409
38.8M
{
2410
38.8M
    return atom & ~JS_ATOM_TAG_INT;
2411
38.8M
}
2412
2413
static inline int is_num(int c)
2414
46.7k
{
2415
46.7k
    return c >= '0' && c <= '9';
2416
46.7k
}
2417
2418
/* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */
2419
static inline BOOL is_num_string(uint32_t *pval, const JSString *p)
2420
95.4k
{
2421
95.4k
    uint32_t n;
2422
95.4k
    uint64_t n64;
2423
95.4k
    int c, i, len;
2424
2425
95.4k
    len = p->len;
2426
95.4k
    if (len == 0 || len > 10)
2427
48.7k
        return FALSE;
2428
46.7k
    if (p->is_wide_char)
2429
1.70k
        c = p->u.str16[0];
2430
45.0k
    else
2431
45.0k
        c = p->u.str8[0];
2432
46.7k
    if (is_num(c)) {
2433
68
        if (c == '0') {
2434
10
            if (len != 1)
2435
8
                return FALSE;
2436
2
            n = 0;
2437
58
        } else {
2438
58
            n = c - '0';
2439
104
            for(i = 1; i < len; i++) {
2440
64
                if (p->is_wide_char)
2441
0
                    c = p->u.str16[i];
2442
64
                else
2443
64
                    c = p->u.str8[i];
2444
64
                if (!is_num(c))
2445
18
                    return FALSE;
2446
46
                n64 = (uint64_t)n * 10 + (c - '0');
2447
46
                if ((n64 >> 32) != 0)
2448
0
                    return FALSE;
2449
46
                n = n64;
2450
46
            }
2451
58
        }
2452
42
        *pval = n;
2453
42
        return TRUE;
2454
46.6k
    } else {
2455
46.6k
        return FALSE;
2456
46.6k
    }
2457
46.7k
}
2458
2459
/* XXX: could use faster version ? */
2460
static inline uint32_t hash_string8(const uint8_t *str, size_t len, uint32_t h)
2461
830k
{
2462
830k
    size_t i;
2463
2464
4.92M
    for(i = 0; i < len; i++)
2465
4.09M
        h = h * 263 + str[i];
2466
830k
    return h;
2467
830k
}
2468
2469
static inline uint32_t hash_string16(const uint16_t *str,
2470
                                     size_t len, uint32_t h)
2471
1.72k
{
2472
1.72k
    size_t i;
2473
2474
1.02M
    for(i = 0; i < len; i++)
2475
1.02M
        h = h * 263 + str[i];
2476
1.72k
    return h;
2477
1.72k
}
2478
2479
static uint32_t hash_string(const JSString *str, uint32_t h)
2480
95.0k
{
2481
95.0k
    if (str->is_wide_char)
2482
1.72k
        h = hash_string16(str->u.str16, str->len, h);
2483
93.3k
    else
2484
93.3k
        h = hash_string8(str->u.str8, str->len, h);
2485
95.0k
    return h;
2486
95.0k
}
2487
2488
static __maybe_unused void JS_DumpString(JSRuntime *rt,
2489
                                                  const JSString *p)
2490
0
{
2491
0
    int i, c, sep;
2492
0
2493
0
    if (p == NULL) {
2494
0
        printf("<null>");
2495
0
        return;
2496
0
    }
2497
0
    printf("%d", p->header.ref_count);
2498
0
    sep = (p->header.ref_count == 1) ? '\"' : '\'';
2499
0
    putchar(sep);
2500
0
    for(i = 0; i < p->len; i++) {
2501
0
        if (p->is_wide_char)
2502
0
            c = p->u.str16[i];
2503
0
        else
2504
0
            c = p->u.str8[i];
2505
0
        if (c == sep || c == '\\') {
2506
0
            putchar('\\');
2507
0
            putchar(c);
2508
0
        } else if (c >= ' ' && c <= 126) {
2509
0
            putchar(c);
2510
0
        } else if (c == '\n') {
2511
0
            putchar('\\');
2512
0
            putchar('n');
2513
0
        } else {
2514
0
            printf("\\u%04x", c);
2515
0
        }
2516
0
    }
2517
0
    putchar(sep);
2518
0
}
2519
2520
static __maybe_unused void JS_DumpAtoms(JSRuntime *rt)
2521
0
{
2522
0
    JSAtomStruct *p;
2523
0
    int h, i;
2524
0
    /* This only dumps hashed atoms, not JS_ATOM_TYPE_SYMBOL atoms */
2525
0
    printf("JSAtom count=%d size=%d hash_size=%d:\n",
2526
0
           rt->atom_count, rt->atom_size, rt->atom_hash_size);
2527
0
    printf("JSAtom hash table: {\n");
2528
0
    for(i = 0; i < rt->atom_hash_size; i++) {
2529
0
        h = rt->atom_hash[i];
2530
0
        if (h) {
2531
0
            printf("  %d:", i);
2532
0
            while (h) {
2533
0
                p = rt->atom_array[h];
2534
0
                printf(" ");
2535
0
                JS_DumpString(rt, p);
2536
0
                h = p->hash_next;
2537
0
            }
2538
0
            printf("\n");
2539
0
        }
2540
0
    }
2541
0
    printf("}\n");
2542
0
    printf("JSAtom table: {\n");
2543
0
    for(i = 0; i < rt->atom_size; i++) {
2544
0
        p = rt->atom_array[i];
2545
0
        if (!atom_is_free(p)) {
2546
0
            printf("  %d: { %d %08x ", i, p->atom_type, p->hash);
2547
0
            if (!(p->len == 0 && p->is_wide_char != 0))
2548
0
                JS_DumpString(rt, p);
2549
0
            printf(" %d }\n", p->hash_next);
2550
0
        }
2551
0
    }
2552
0
    printf("}\n");
2553
0
}
2554
2555
static int JS_ResizeAtomHash(JSRuntime *rt, int new_hash_size)
2556
8
{
2557
8
    JSAtomStruct *p;
2558
8
    uint32_t new_hash_mask, h, i, hash_next1, j, *new_hash;
2559
2560
8
    assert((new_hash_size & (new_hash_size - 1)) == 0); /* power of two */
2561
8
    new_hash_mask = new_hash_size - 1;
2562
8
    new_hash = js_mallocz_rt(rt, sizeof(rt->atom_hash[0]) * new_hash_size);
2563
8
    if (!new_hash)
2564
0
        return -1;
2565
4.10k
    for(i = 0; i < rt->atom_hash_size; i++) {
2566
4.09k
        h = rt->atom_hash[i];
2567
6.66k
        while (h != 0) {
2568
2.57k
            p = rt->atom_array[h];
2569
2.57k
            hash_next1 = p->hash_next;
2570
            /* add in new hash table */
2571
2.57k
            j = p->hash & new_hash_mask;
2572
2.57k
            p->hash_next = new_hash[j];
2573
2.57k
            new_hash[j] = h;
2574
2.57k
            h = hash_next1;
2575
2.57k
        }
2576
4.09k
    }
2577
8
    js_free_rt(rt, rt->atom_hash);
2578
8
    rt->atom_hash = new_hash;
2579
8
    rt->atom_hash_size = new_hash_size;
2580
8
    rt->atom_count_resize = JS_ATOM_COUNT_RESIZE(new_hash_size);
2581
    //    JS_DumpAtoms(rt);
2582
8
    return 0;
2583
8
}
2584
2585
static int JS_InitAtoms(JSRuntime *rt)
2586
3
{
2587
3
    int i, len, atom_type;
2588
3
    const char *p;
2589
2590
3
    rt->atom_hash_size = 0;
2591
3
    rt->atom_hash = NULL;
2592
3
    rt->atom_count = 0;
2593
3
    rt->atom_size = 0;
2594
3
    rt->atom_free_index = 0;
2595
3
    if (JS_ResizeAtomHash(rt, 256))     /* there are at least 195 predefined atoms */
2596
0
        return -1;
2597
2598
3
    p = js_atom_init;
2599
675
    for(i = 1; i < JS_ATOM_END; i++) {
2600
672
        if (i == JS_ATOM_Private_brand)
2601
3
            atom_type = JS_ATOM_TYPE_PRIVATE;
2602
669
        else if (i >= JS_ATOM_Symbol_toPrimitive)
2603
42
            atom_type = JS_ATOM_TYPE_SYMBOL;
2604
627
        else
2605
627
            atom_type = JS_ATOM_TYPE_STRING;
2606
672
        len = strlen(p);
2607
672
        if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL)
2608
0
            return -1;
2609
672
        p = p + len + 1;
2610
672
    }
2611
3
    return 0;
2612
3
}
2613
2614
static JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v)
2615
161
{
2616
161
    JSAtomStruct *p;
2617
2618
161
    if (!__JS_AtomIsConst(v)) {
2619
0
        p = rt->atom_array[v];
2620
0
        p->header.ref_count++;
2621
0
    }
2622
161
    return v;
2623
161
}
2624
2625
JSAtom JS_DupAtom(JSContext *ctx, JSAtom v)
2626
9.42M
{
2627
9.42M
    JSRuntime *rt;
2628
9.42M
    JSAtomStruct *p;
2629
2630
9.42M
    if (!__JS_AtomIsConst(v)) {
2631
4.15M
        rt = ctx->rt;
2632
4.15M
        p = rt->atom_array[v];
2633
4.15M
        p->header.ref_count++;
2634
4.15M
    }
2635
9.42M
    return v;
2636
9.42M
}
2637
2638
static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v)
2639
2.51M
{
2640
2.51M
    JSRuntime *rt;
2641
2.51M
    JSAtomStruct *p;
2642
2643
2.51M
    rt = ctx->rt;
2644
2.51M
    if (__JS_AtomIsTaggedInt(v))
2645
2.51M
        return JS_ATOM_KIND_STRING;
2646
402
    p = rt->atom_array[v];
2647
402
    switch(p->atom_type) {
2648
396
    case JS_ATOM_TYPE_STRING:
2649
396
        return JS_ATOM_KIND_STRING;
2650
0
    case JS_ATOM_TYPE_GLOBAL_SYMBOL:
2651
0
        return JS_ATOM_KIND_SYMBOL;
2652
6
    case JS_ATOM_TYPE_SYMBOL:
2653
6
        switch(p->hash) {
2654
6
        case JS_ATOM_HASH_SYMBOL:
2655
6
            return JS_ATOM_KIND_SYMBOL;
2656
0
        case JS_ATOM_HASH_PRIVATE:
2657
0
            return JS_ATOM_KIND_PRIVATE;
2658
0
        default:
2659
0
            abort();
2660
6
        }
2661
0
    default:
2662
0
        abort();
2663
402
    }
2664
402
}
2665
2666
static BOOL JS_AtomIsString(JSContext *ctx, JSAtom v)
2667
0
{
2668
0
    return JS_AtomGetKind(ctx, v) == JS_ATOM_KIND_STRING;
2669
0
}
2670
2671
static JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p)
2672
680
{
2673
680
    uint32_t i = p->hash_next;  /* atom_index */
2674
680
    if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
2675
678
        JSAtomStruct *p1;
2676
2677
678
        i = rt->atom_hash[p->hash & (rt->atom_hash_size - 1)];
2678
678
        p1 = rt->atom_array[i];
2679
691
        while (p1 != p) {
2680
13
            assert(i != 0);
2681
13
            i = p1->hash_next;
2682
13
            p1 = rt->atom_array[i];
2683
13
        }
2684
678
    }
2685
680
    return i;
2686
680
}
2687
2688
/* string case (internal). Return JS_ATOM_NULL if error. 'str' is
2689
   freed. */
2690
static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
2691
137k
{
2692
137k
    uint32_t h, h1, i;
2693
137k
    JSAtomStruct *p;
2694
137k
    int len;
2695
2696
#if 0
2697
    printf("__JS_NewAtom: ");  JS_DumpString(rt, str); printf("\n");
2698
#endif
2699
137k
    if (atom_type < JS_ATOM_TYPE_SYMBOL) {
2700
        /* str is not NULL */
2701
95.7k
        if (str->atom_type == atom_type) {
2702
            /* str is the atom, return its index */
2703
678
            i = js_get_atom_index(rt, str);
2704
            /* reduce string refcount and increase atom's unless constant */
2705
678
            if (__JS_AtomIsConst(i))
2706
639
                str->header.ref_count--;
2707
678
            return i;
2708
678
        }
2709
        /* try and locate an already registered atom */
2710
95.0k
        len = str->len;
2711
95.0k
        h = hash_string(str, atom_type);
2712
95.0k
        h &= JS_ATOM_HASH_MASK;
2713
95.0k
        h1 = h & (rt->atom_hash_size - 1);
2714
95.0k
        i = rt->atom_hash[h1];
2715
108k
        while (i != 0) {
2716
63.1k
            p = rt->atom_array[i];
2717
63.1k
            if (p->hash == h &&
2718
63.1k
                p->atom_type == atom_type &&
2719
63.1k
                p->len == len &&
2720
63.1k
                js_string_memcmp(p, str, len) == 0) {
2721
50.0k
                if (!__JS_AtomIsConst(i))
2722
50.0k
                    p->header.ref_count++;
2723
50.0k
                goto done;
2724
50.0k
            }
2725
13.0k
            i = p->hash_next;
2726
13.0k
        }
2727
95.0k
    } else {
2728
41.3k
        h1 = 0; /* avoid warning */
2729
41.3k
        if (atom_type == JS_ATOM_TYPE_SYMBOL) {
2730
42
            h = JS_ATOM_HASH_SYMBOL;
2731
41.3k
        } else {
2732
41.3k
            h = JS_ATOM_HASH_PRIVATE;
2733
41.3k
            atom_type = JS_ATOM_TYPE_SYMBOL;
2734
41.3k
        }
2735
41.3k
    }
2736
2737
86.4k
    if (rt->atom_free_index == 0) {
2738
        /* allow new atom entries */
2739
17
        uint32_t new_size, start;
2740
17
        JSAtomStruct **new_array;
2741
2742
        /* alloc new with size progression 3/2:
2743
           4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066 1599 2398 3597 5395 8092
2744
           preallocating space for predefined atoms (at least 195).
2745
         */
2746
17
        new_size = max_int(211, rt->atom_size * 3 / 2);
2747
17
        if (new_size > JS_ATOM_MAX)
2748
0
            goto fail;
2749
        /* XXX: should use realloc2 to use slack space */
2750
17
        new_array = js_realloc_rt(rt, rt->atom_array, sizeof(*new_array) * new_size);
2751
17
        if (!new_array)
2752
0
            goto fail;
2753
        /* Note: the atom 0 is not used */
2754
17
        start = rt->atom_size;
2755
17
        if (start == 0) {
2756
            /* JS_ATOM_NULL entry */
2757
3
            p = js_mallocz_rt(rt, sizeof(JSAtomStruct));
2758
3
            if (!p) {
2759
0
                js_free_rt(rt, new_array);
2760
0
                goto fail;
2761
0
            }
2762
3
            p->header.ref_count = 1;  /* not refcounted */
2763
3
            p->atom_type = JS_ATOM_TYPE_SYMBOL;
2764
#ifdef DUMP_LEAKS
2765
            list_add_tail(&p->link, &rt->string_list);
2766
#endif
2767
3
            new_array[0] = p;
2768
3
            rt->atom_count++;
2769
3
            start = 1;
2770
3
        }
2771
17
        rt->atom_size = new_size;
2772
17
        rt->atom_array = new_array;
2773
17
        rt->atom_free_index = start;
2774
9.48k
        for(i = start; i < new_size; i++) {
2775
9.47k
            uint32_t next;
2776
9.47k
            if (i == (new_size - 1))
2777
17
                next = 0;
2778
9.45k
            else
2779
9.45k
                next = i + 1;
2780
9.47k
            rt->atom_array[i] = atom_set_free(next);
2781
9.47k
        }
2782
17
    }
2783
2784
86.4k
    if (str) {
2785
86.4k
        if (str->atom_type == 0) {
2786
45.0k
            p = str;
2787
45.0k
            p->atom_type = atom_type;
2788
45.0k
        } else {
2789
41.3k
            p = js_malloc_rt(rt, sizeof(JSString) +
2790
41.3k
                             (str->len << str->is_wide_char) +
2791
41.3k
                             1 - str->is_wide_char);
2792
41.3k
            if (unlikely(!p))
2793
0
                goto fail;
2794
41.3k
            p->header.ref_count = 1;
2795
41.3k
            p->is_wide_char = str->is_wide_char;
2796
41.3k
            p->len = str->len;
2797
#ifdef DUMP_LEAKS
2798
            list_add_tail(&p->link, &rt->string_list);
2799
#endif
2800
41.3k
            memcpy(p->u.str8, str->u.str8, (str->len << str->is_wide_char) +
2801
41.3k
                   1 - str->is_wide_char);
2802
41.3k
            js_free_string(rt, str);
2803
41.3k
        }
2804
86.4k
    } else {
2805
0
        p = js_malloc_rt(rt, sizeof(JSAtomStruct)); /* empty wide string */
2806
0
        if (!p)
2807
0
            return JS_ATOM_NULL;
2808
0
        p->header.ref_count = 1;
2809
0
        p->is_wide_char = 1;    /* Hack to represent NULL as a JSString */
2810
0
        p->len = 0;
2811
#ifdef DUMP_LEAKS
2812
        list_add_tail(&p->link, &rt->string_list);
2813
#endif
2814
0
    }
2815
2816
    /* use an already free entry */
2817
86.4k
    i = rt->atom_free_index;
2818
86.4k
    rt->atom_free_index = atom_get_free(rt->atom_array[i]);
2819
86.4k
    rt->atom_array[i] = p;
2820
2821
86.4k
    p->hash = h;
2822
86.4k
    p->hash_next = i;   /* atom_index */
2823
86.4k
    p->atom_type = atom_type;
2824
2825
86.4k
    rt->atom_count++;
2826
2827
86.4k
    if (atom_type != JS_ATOM_TYPE_SYMBOL) {
2828
45.0k
        p->hash_next = rt->atom_hash[h1];
2829
45.0k
        rt->atom_hash[h1] = i;
2830
45.0k
        if (unlikely(rt->atom_count >= rt->atom_count_resize))
2831
5
            JS_ResizeAtomHash(rt, rt->atom_hash_size * 2);
2832
45.0k
    }
2833
2834
    //    JS_DumpAtoms(rt);
2835
86.4k
    return i;
2836
2837
0
 fail:
2838
0
    i = JS_ATOM_NULL;
2839
50.0k
 done:
2840
50.0k
    if (str)
2841
50.0k
        js_free_string(rt, str);
2842
50.0k
    return i;
2843
0
}
2844
2845
/* only works with zero terminated 8 bit strings */
2846
static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
2847
                               int atom_type)
2848
672
{
2849
672
    JSString *p;
2850
672
    p = js_alloc_string_rt(rt, len, 0);
2851
672
    if (!p)
2852
0
        return JS_ATOM_NULL;
2853
672
    memcpy(p->u.str8, str, len);
2854
672
    p->u.str8[len] = '\0';
2855
672
    return __JS_NewAtom(rt, p, atom_type);
2856
672
}
2857
2858
static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
2859
                            int atom_type)
2860
736k
{
2861
736k
    uint32_t h, h1, i;
2862
736k
    JSAtomStruct *p;
2863
2864
736k
    h = hash_string8((const uint8_t *)str, len, JS_ATOM_TYPE_STRING);
2865
736k
    h &= JS_ATOM_HASH_MASK;
2866
736k
    h1 = h & (rt->atom_hash_size - 1);
2867
736k
    i = rt->atom_hash[h1];
2868
869k
    while (i != 0) {
2869
823k
        p = rt->atom_array[i];
2870
823k
        if (p->hash == h &&
2871
823k
            p->atom_type == JS_ATOM_TYPE_STRING &&
2872
823k
            p->len == len &&
2873
823k
            p->is_wide_char == 0 &&
2874
823k
            memcmp(p->u.str8, str, len) == 0) {
2875
691k
            if (!__JS_AtomIsConst(i))
2876
476k
                p->header.ref_count++;
2877
691k
            return i;
2878
691k
        }
2879
132k
        i = p->hash_next;
2880
132k
    }
2881
45.8k
    return JS_ATOM_NULL;
2882
736k
}
2883
2884
static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p)
2885
77.5k
{
2886
#if 0   /* JS_ATOM_NULL is not refcounted: __JS_AtomIsConst() includes 0 */
2887
    if (unlikely(i == JS_ATOM_NULL)) {
2888
        p->header.ref_count = INT32_MAX / 2;
2889
        return;
2890
    }
2891
#endif
2892
77.5k
    uint32_t i = p->hash_next;  /* atom_index */
2893
77.5k
    if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
2894
43.7k
        JSAtomStruct *p0, *p1;
2895
43.7k
        uint32_t h0;
2896
2897
43.7k
        h0 = p->hash & (rt->atom_hash_size - 1);
2898
43.7k
        i = rt->atom_hash[h0];
2899
43.7k
        p1 = rt->atom_array[i];
2900
43.7k
        if (p1 == p) {
2901
43.6k
            rt->atom_hash[h0] = p1->hash_next;
2902
43.6k
        } else {
2903
81
            for(;;) {
2904
81
                assert(i != 0);
2905
81
                p0 = p1;
2906
81
                i = p1->hash_next;
2907
81
                p1 = rt->atom_array[i];
2908
81
                if (p1 == p) {
2909
62
                    p0->hash_next = p1->hash_next;
2910
62
                    break;
2911
62
                }
2912
81
            }
2913
62
        }
2914
43.7k
    }
2915
    /* insert in free atom list */
2916
77.5k
    rt->atom_array[i] = atom_set_free(rt->atom_free_index);
2917
77.5k
    rt->atom_free_index = i;
2918
    /* free the string structure */
2919
#ifdef DUMP_LEAKS
2920
    list_del(&p->link);
2921
#endif
2922
77.5k
    js_free_rt(rt, p);
2923
77.5k
    rt->atom_count--;
2924
77.5k
    assert(rt->atom_count >= 0);
2925
77.5k
}
2926
2927
static void __JS_FreeAtom(JSRuntime *rt, uint32_t i)
2928
4.72M
{
2929
4.72M
    JSAtomStruct *p;
2930
2931
4.72M
    p = rt->atom_array[i];
2932
4.72M
    if (--p->header.ref_count > 0)
2933
4.67M
        return;
2934
43.7k
    JS_FreeAtomStruct(rt, p);
2935
43.7k
}
2936
2937
/* Warning: 'p' is freed */
2938
static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p)
2939
95.1k
{
2940
95.1k
    JSRuntime *rt = ctx->rt;
2941
95.1k
    uint32_t n;
2942
95.1k
    if (is_num_string(&n, p)) {
2943
42
        if (n <= JS_ATOM_MAX_INT) {
2944
40
            js_free_string(rt, p);
2945
40
            return __JS_AtomFromUInt32(n);
2946
40
        }
2947
42
    }
2948
    /* XXX: should generate an exception */
2949
95.1k
    return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING);
2950
95.1k
}
2951
2952
JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len)
2953
736k
{
2954
736k
    JSValue val;
2955
2956
736k
    if (len == 0 || !is_digit(*str)) {
2957
736k
        JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);
2958
736k
        if (atom)
2959
691k
            return atom;
2960
736k
    }
2961
45.8k
    val = JS_NewStringLen(ctx, str, len);
2962
45.8k
    if (JS_IsException(val))
2963
0
        return JS_ATOM_NULL;
2964
45.8k
    return JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(val));
2965
45.8k
}
2966
2967
JSAtom JS_NewAtom(JSContext *ctx, const char *str)
2968
54.8k
{
2969
54.8k
    return JS_NewAtomLen(ctx, str, strlen(str));
2970
54.8k
}
2971
2972
JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
2973
0
{
2974
0
    if (n <= JS_ATOM_MAX_INT) {
2975
0
        return __JS_AtomFromUInt32(n);
2976
0
    } else {
2977
0
        char buf[11];
2978
0
        JSValue val;
2979
0
        snprintf(buf, sizeof(buf), "%u", n);
2980
0
        val = JS_NewString(ctx, buf);
2981
0
        if (JS_IsException(val))
2982
0
            return JS_ATOM_NULL;
2983
0
        return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
2984
0
                            JS_ATOM_TYPE_STRING);
2985
0
    }
2986
0
}
2987
2988
static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n)
2989
0
{
2990
0
    if ((uint64_t)n <= JS_ATOM_MAX_INT) {
2991
0
        return __JS_AtomFromUInt32((uint32_t)n);
2992
0
    } else {
2993
0
        char buf[24];
2994
0
        JSValue val;
2995
0
        snprintf(buf, sizeof(buf), "%" PRId64 , n);
2996
0
        val = JS_NewString(ctx, buf);
2997
0
        if (JS_IsException(val))
2998
0
            return JS_ATOM_NULL;
2999
0
        return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
3000
0
                            JS_ATOM_TYPE_STRING);
3001
0
    }
3002
0
}
3003
3004
/* 'p' is freed */
3005
static JSValue JS_NewSymbol(JSContext *ctx, JSString *p, int atom_type)
3006
41.3k
{
3007
41.3k
    JSRuntime *rt = ctx->rt;
3008
41.3k
    JSAtom atom;
3009
41.3k
    atom = __JS_NewAtom(rt, p, atom_type);
3010
41.3k
    if (atom == JS_ATOM_NULL)
3011
0
        return JS_ThrowOutOfMemory(ctx);
3012
41.3k
    return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]);
3013
41.3k
}
3014
3015
/* descr must be a non-numeric string atom */
3016
static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,
3017
                                    int atom_type)
3018
41.3k
{
3019
41.3k
    JSRuntime *rt = ctx->rt;
3020
41.3k
    JSString *p;
3021
3022
41.3k
    assert(!__JS_AtomIsTaggedInt(descr));
3023
41.3k
    assert(descr < rt->atom_size);
3024
41.3k
    p = rt->atom_array[descr];
3025
41.3k
    JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
3026
41.3k
    return JS_NewSymbol(ctx, p, atom_type);
3027
41.3k
}
3028
3029
#define ATOM_GET_STR_BUF_SIZE 64
3030
3031
/* Should only be used for debug. */
3032
static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,
3033
                                   JSAtom atom)
3034
122k
{
3035
122k
    if (__JS_AtomIsTaggedInt(atom)) {
3036
0
        snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom));
3037
122k
    } else {
3038
122k
        JSAtomStruct *p;
3039
122k
        assert(atom < rt->atom_size);
3040
122k
        if (atom == JS_ATOM_NULL) {
3041
0
            snprintf(buf, buf_size, "<null>");
3042
122k
        } else {
3043
122k
            int i, c;
3044
122k
            char *q;
3045
122k
            JSString *str;
3046
3047
122k
            q = buf;
3048
122k
            p = rt->atom_array[atom];
3049
122k
            assert(!atom_is_free(p));
3050
122k
            str = p;
3051
122k
            if (str) {
3052
122k
                if (!str->is_wide_char) {
3053
                    /* special case ASCII strings */
3054
122k
                    c = 0;
3055
1.10M
                    for(i = 0; i < str->len; i++) {
3056
984k
                        c |= str->u.str8[i];
3057
984k
                    }
3058
122k
                    if (c < 0x80)
3059
122k
                        return (const char *)str->u.str8;
3060
122k
                }
3061
0
                for(i = 0; i < str->len; i++) {
3062
0
                    if (str->is_wide_char)
3063
0
                        c = str->u.str16[i];
3064
0
                    else
3065
0
                        c = str->u.str8[i];
3066
0
                    if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX)
3067
0
                        break;
3068
0
                    if (c < 128) {
3069
0
                        *q++ = c;
3070
0
                    } else {
3071
0
                        q += unicode_to_utf8((uint8_t *)q, c);
3072
0
                    }
3073
0
                }
3074
0
            }
3075
0
            *q = '\0';
3076
0
        }
3077
122k
    }
3078
0
    return buf;
3079
122k
}
3080
3081
static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom)
3082
122k
{
3083
122k
    return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom);
3084
122k
}
3085
3086
static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string)
3087
1.79M
{
3088
1.79M
    char buf[ATOM_GET_STR_BUF_SIZE];
3089
3090
1.79M
    if (__JS_AtomIsTaggedInt(atom)) {
3091
30
        snprintf(buf, sizeof(buf), "%u", __JS_AtomToUInt32(atom));
3092
30
        return JS_NewString(ctx, buf);
3093
1.79M
    } else {
3094
1.79M
        JSRuntime *rt = ctx->rt;
3095
1.79M
        JSAtomStruct *p;
3096
1.79M
        assert(atom < rt->atom_size);
3097
1.79M
        p = rt->atom_array[atom];
3098
1.79M
        if (p->atom_type == JS_ATOM_TYPE_STRING) {
3099
1.79M
            goto ret_string;
3100
1.79M
        } else if (force_string) {
3101
0
            if (p->len == 0 && p->is_wide_char != 0) {
3102
                /* no description string */
3103
0
                p = rt->atom_array[JS_ATOM_empty_string];
3104
0
            }
3105
1.79M
        ret_string:
3106
1.79M
            return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
3107
28
        } else {
3108
28
            return JS_DupValue(ctx, JS_MKPTR(JS_TAG_SYMBOL, p));
3109
28
        }
3110
1.79M
    }
3111
1.79M
}
3112
3113
JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom)
3114
450k
{
3115
450k
    return __JS_AtomToValue(ctx, atom, FALSE);
3116
450k
}
3117
3118
JSValue JS_AtomToString(JSContext *ctx, JSAtom atom)
3119
1.34M
{
3120
1.34M
    return __JS_AtomToValue(ctx, atom, TRUE);
3121
1.34M
}
3122
3123
/* return TRUE if the atom is an array index (i.e. 0 <= index <=
3124
   2^32-2 and return its value */
3125
static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom)
3126
38.1M
{
3127
38.1M
    if (__JS_AtomIsTaggedInt(atom)) {
3128
38.1M
        *pval = __JS_AtomToUInt32(atom);
3129
38.1M
        return TRUE;
3130
38.1M
    } else {
3131
317
        JSRuntime *rt = ctx->rt;
3132
317
        JSAtomStruct *p;
3133
317
        uint32_t val;
3134
3135
317
        assert(atom < rt->atom_size);
3136
317
        p = rt->atom_array[atom];
3137
317
        if (p->atom_type == JS_ATOM_TYPE_STRING &&
3138
317
            is_num_string(&val, p) && val != -1) {
3139
0
            *pval = val;
3140
0
            return TRUE;
3141
317
        } else {
3142
317
            *pval = 0;
3143
317
            return FALSE;
3144
317
        }
3145
317
    }
3146
38.1M
}
3147
3148
/* This test must be fast if atom is not a numeric index (e.g. a
3149
   method name). Return JS_UNDEFINED if not a numeric
3150
   index. JS_EXCEPTION can also be returned. */
3151
static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
3152
0
{
3153
0
    JSRuntime *rt = ctx->rt;
3154
0
    JSAtomStruct *p1;
3155
0
    JSString *p;
3156
0
    int c, len, ret;
3157
0
    JSValue num, str;
3158
3159
0
    if (__JS_AtomIsTaggedInt(atom))
3160
0
        return JS_NewInt32(ctx, __JS_AtomToUInt32(atom));
3161
0
    assert(atom < rt->atom_size);
3162
0
    p1 = rt->atom_array[atom];
3163
0
    if (p1->atom_type != JS_ATOM_TYPE_STRING)
3164
0
        return JS_UNDEFINED;
3165
0
    p = p1;
3166
0
    len = p->len;
3167
0
    if (p->is_wide_char) {
3168
0
        const uint16_t *r = p->u.str16, *r_end = p->u.str16 + len;
3169
0
        if (r >= r_end)
3170
0
            return JS_UNDEFINED;
3171
0
        c = *r;
3172
0
        if (c == '-') {
3173
0
            if (r >= r_end)
3174
0
                return JS_UNDEFINED;
3175
0
            r++;
3176
0
            c = *r;
3177
            /* -0 case is specific */
3178
0
            if (c == '0' && len == 2)
3179
0
                goto minus_zero;
3180
0
        }
3181
        /* XXX: should test NaN, but the tests do not check it */
3182
0
        if (!is_num(c)) {
3183
            /* XXX: String should be normalized, therefore 8-bit only */
3184
0
            const uint16_t nfinity16[7] = { 'n', 'f', 'i', 'n', 'i', 't', 'y' };
3185
0
            if (!(c =='I' && (r_end - r) == 8 &&
3186
0
                  !memcmp(r + 1, nfinity16, sizeof(nfinity16))))
3187
0
                return JS_UNDEFINED;
3188
0
        }
3189
0
    } else {
3190
0
        const uint8_t *r = p->u.str8, *r_end = p->u.str8 + len;
3191
0
        if (r >= r_end)
3192
0
            return JS_UNDEFINED;
3193
0
        c = *r;
3194
0
        if (c == '-') {
3195
0
            if (r >= r_end)
3196
0
                return JS_UNDEFINED;
3197
0
            r++;
3198
0
            c = *r;
3199
            /* -0 case is specific */
3200
0
            if (c == '0' && len == 2) {
3201
0
            minus_zero:
3202
0
                return __JS_NewFloat64(ctx, -0.0);
3203
0
            }
3204
0
        }
3205
0
        if (!is_num(c)) {
3206
0
            if (!(c =='I' && (r_end - r) == 8 &&
3207
0
                  !memcmp(r + 1, "nfinity", 7)))
3208
0
                return JS_UNDEFINED;
3209
0
        }
3210
0
    }
3211
    /* XXX: bignum: would be better to only accept integer to avoid
3212
       relying on current floating point precision */
3213
    /* this is ECMA CanonicalNumericIndexString primitive */
3214
0
    num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p));
3215
0
    if (JS_IsException(num))
3216
0
        return num;
3217
0
    str = JS_ToString(ctx, num);
3218
0
    if (JS_IsException(str)) {
3219
0
        JS_FreeValue(ctx, num);
3220
0
        return str;
3221
0
    }
3222
0
    ret = js_string_compare(ctx, p, JS_VALUE_GET_STRING(str));
3223
0
    JS_FreeValue(ctx, str);
3224
0
    if (ret == 0) {
3225
0
        return num;
3226
0
    } else {
3227
0
        JS_FreeValue(ctx, num);
3228
0
        return JS_UNDEFINED;
3229
0
    }
3230
0
}
3231
3232
/* return -1 if exception or TRUE/FALSE */
3233
static int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom)
3234
0
{
3235
0
    JSValue num;
3236
0
    num = JS_AtomIsNumericIndex1(ctx, atom);
3237
0
    if (likely(JS_IsUndefined(num)))
3238
0
        return FALSE;
3239
0
    if (JS_IsException(num))
3240
0
        return -1;
3241
0
    JS_FreeValue(ctx, num);
3242
0
    return TRUE;
3243
0
}
3244
3245
void JS_FreeAtom(JSContext *ctx, JSAtom v)
3246
3.49M
{
3247
3.49M
    if (!__JS_AtomIsConst(v))
3248
1.21M
        __JS_FreeAtom(ctx->rt, v);
3249
3.49M
}
3250
3251
void JS_FreeAtomRT(JSRuntime *rt, JSAtom v)
3252
7.23M
{
3253
7.23M
    if (!__JS_AtomIsConst(v))
3254
3.50M
        __JS_FreeAtom(rt, v);
3255
7.23M
}
3256
3257
/* return TRUE if 'v' is a symbol with a string description */
3258
static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)
3259
46.8k
{
3260
46.8k
    JSRuntime *rt;
3261
46.8k
    JSAtomStruct *p;
3262
3263
46.8k
    rt = ctx->rt;
3264
46.8k
    if (__JS_AtomIsTaggedInt(v))
3265
0
        return FALSE;
3266
46.8k
    p = rt->atom_array[v];
3267
46.8k
    return (((p->atom_type == JS_ATOM_TYPE_SYMBOL &&
3268
46.8k
              p->hash == JS_ATOM_HASH_SYMBOL) ||
3269
46.8k
             p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL) &&
3270
46.8k
            !(p->len == 0 && p->is_wide_char != 0));
3271
46.8k
}
3272
3273
static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom)
3274
0
{
3275
0
    char buf[ATOM_GET_STR_BUF_SIZE];
3276
0
    const char *p;
3277
0
    int i;
3278
0
3279
0
    /* XXX: should handle embedded null characters */
3280
0
    /* XXX: should move encoding code to JS_AtomGetStr */
3281
0
    p = JS_AtomGetStr(ctx, buf, sizeof(buf), atom);
3282
0
    for (i = 0; p[i]; i++) {
3283
0
        int c = (unsigned char)p[i];
3284
0
        if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
3285
0
              (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0)))
3286
0
            break;
3287
0
    }
3288
0
    if (i > 0 && p[i] == '\0') {
3289
0
        printf("%s", p);
3290
0
    } else {
3291
0
        putchar('"');
3292
0
        printf("%.*s", i, p);
3293
0
        for (; p[i]; i++) {
3294
0
            int c = (unsigned char)p[i];
3295
0
            if (c == '\"' || c == '\\') {
3296
0
                putchar('\\');
3297
0
                putchar(c);
3298
0
            } else if (c >= ' ' && c <= 126) {
3299
0
                putchar(c);
3300
0
            } else if (c == '\n') {
3301
0
                putchar('\\');
3302
0
                putchar('n');
3303
0
            } else {
3304
0
                printf("\\u%04x", c);
3305
0
            }
3306
0
        }
3307
0
        putchar('\"');
3308
0
    }
3309
0
}
3310
3311
/* free with JS_FreeCString() */
3312
const char *JS_AtomToCString(JSContext *ctx, JSAtom atom)
3313
163k
{
3314
163k
    JSValue str;
3315
163k
    const char *cstr;
3316
3317
163k
    str = JS_AtomToString(ctx, atom);
3318
163k
    if (JS_IsException(str))
3319
0
        return NULL;
3320
163k
    cstr = JS_ToCString(ctx, str);
3321
163k
    JS_FreeValue(ctx, str);
3322
163k
    return cstr;
3323
163k
}
3324
3325
/* return a string atom containing name concatenated with str1 */
3326
static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1)
3327
76
{
3328
76
    JSValue str;
3329
76
    JSAtom atom;
3330
76
    const char *cstr;
3331
76
    char *cstr2;
3332
76
    size_t len, len1;
3333
    
3334
76
    str = JS_AtomToString(ctx, name);
3335
76
    if (JS_IsException(str))
3336
0
        return JS_ATOM_NULL;
3337
76
    cstr = JS_ToCStringLen(ctx, &len, str);
3338
76
    if (!cstr)
3339
0
        goto fail;
3340
76
    len1 = strlen(str1);
3341
76
    cstr2 = js_malloc(ctx, len + len1 + 1);
3342
76
    if (!cstr2)
3343
0
        goto fail;
3344
76
    memcpy(cstr2, cstr, len);
3345
76
    memcpy(cstr2 + len, str1, len1);
3346
76
    cstr2[len + len1] = '\0';
3347
76
    atom = JS_NewAtomLen(ctx, cstr2, len + len1);
3348
76
    js_free(ctx, cstr2);
3349
76
    JS_FreeCString(ctx, cstr);
3350
76
    JS_FreeValue(ctx, str);
3351
76
    return atom;
3352
0
 fail:
3353
0
    JS_FreeCString(ctx, cstr);
3354
0
    JS_FreeValue(ctx, str);
3355
0
    return JS_ATOM_NULL;
3356
76
}
3357
3358
static JSAtom js_atom_concat_num(JSContext *ctx, JSAtom name, uint32_t n)
3359
76
{
3360
76
    char buf[16];
3361
76
    snprintf(buf, sizeof(buf), "%u", n);
3362
76
    return js_atom_concat_str(ctx, name, buf);
3363
76
}
3364
3365
static inline BOOL JS_IsEmptyString(JSValueConst v)
3366
2
{
3367
2
    return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0;
3368
2
}
3369
3370
/* JSClass support */
3371
3372
/* a new class ID is allocated if *pclass_id != 0 */
3373
JSClassID JS_NewClassID(JSClassID *pclass_id)
3374
0
{
3375
0
    JSClassID class_id;
3376
    /* XXX: make it thread safe */
3377
0
    class_id = *pclass_id;
3378
0
    if (class_id == 0) {
3379
0
        class_id = js_class_id_alloc++;
3380
0
        *pclass_id = class_id;
3381
0
    }
3382
0
    return class_id;
3383
0
}
3384
3385
BOOL JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id)
3386
4
{
3387
4
    return (class_id < rt->class_count &&
3388
4
            rt->class_array[class_id].class_id != 0);
3389
4
}
3390
3391
/* create a new object internal class. Return -1 if error, 0 if
3392
   OK. The finalizer can be NULL if none is needed. */
3393
static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
3394
                        const JSClassDef *class_def, JSAtom name)
3395
161
{
3396
161
    int new_size, i;
3397
161
    JSClass *cl, *new_class_array;
3398
161
    struct list_head *el;
3399
3400
161
    if (class_id >= (1 << 16))
3401
0
        return -1;
3402
161
    if (class_id < rt->class_count &&
3403
161
        rt->class_array[class_id].class_id != 0)
3404
0
        return -1;
3405
3406
161
    if (class_id >= rt->class_count) {
3407
3
        new_size = max_int(JS_CLASS_INIT_COUNT,
3408
3
                           max_int(class_id + 1, rt->class_count * 3 / 2));
3409
3410
        /* reallocate the context class prototype array, if any */
3411
3
        list_for_each(el, &rt->context_list) {
3412
0
            JSContext *ctx = list_entry(el, JSContext, link);
3413
0
            JSValue *new_tab;
3414
0
            new_tab = js_realloc_rt(rt, ctx->class_proto,
3415
0
                                    sizeof(ctx->class_proto[0]) * new_size);
3416
0
            if (!new_tab)
3417
0
                return -1;
3418
0
            for(i = rt->class_count; i < new_size; i++)
3419
0
                new_tab[i] = JS_NULL;
3420
0
            ctx->class_proto = new_tab;
3421
0
        }
3422
        /* reallocate the class array */
3423
3
        new_class_array = js_realloc_rt(rt, rt->class_array,
3424
3
                                        sizeof(JSClass) * new_size);
3425
3
        if (!new_class_array)
3426
0
            return -1;
3427
3
        memset(new_class_array + rt->class_count, 0,
3428
3
               (new_size - rt->class_count) * sizeof(JSClass));
3429
3
        rt->class_array = new_class_array;
3430
3
        rt->class_count = new_size;
3431
3
    }
3432
161
    cl = &rt->class_array[class_id];
3433
161
    cl->class_id = class_id;
3434
161
    cl->class_name = JS_DupAtomRT(rt, name);
3435
161
    cl->finalizer = class_def->finalizer;
3436
161
    cl->gc_mark = class_def->gc_mark;
3437
161
    cl->call = class_def->call;
3438
161
    cl->exotic = class_def->exotic;
3439
161
    return 0;
3440
161
}
3441
3442
int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def)
3443
0
{
3444
0
    int ret, len;
3445
0
    JSAtom name;
3446
3447
0
    len = strlen(class_def->class_name);
3448
0
    name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
3449
0
    if (name == JS_ATOM_NULL) {
3450
0
        name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
3451
0
        if (name == JS_ATOM_NULL)
3452
0
            return -1;
3453
0
    }
3454
0
    ret = JS_NewClass1(rt, class_id, class_def, name);
3455
0
    JS_FreeAtomRT(rt, name);
3456
0
    return ret;
3457
0
}
3458
3459
static JSValue js_new_string8(JSContext *ctx, const uint8_t *buf, int len)
3460
858k
{
3461
858k
    JSString *str;
3462
3463
858k
    if (len <= 0) {
3464
0
        return JS_AtomToString(ctx, JS_ATOM_empty_string);
3465
0
    }
3466
858k
    str = js_alloc_string(ctx, len, 0);
3467
858k
    if (!str)
3468
0
        return JS_EXCEPTION;
3469
858k
    memcpy(str->u.str8, buf, len);
3470
858k
    str->u.str8[len] = '\0';
3471
858k
    return JS_MKPTR(JS_TAG_STRING, str);
3472
858k
}
3473
3474
static JSValue js_new_string16(JSContext *ctx, const uint16_t *buf, int len)
3475
141
{
3476
141
    JSString *str;
3477
141
    str = js_alloc_string(ctx, len, 1);
3478
141
    if (!str)
3479
0
        return JS_EXCEPTION;
3480
141
    memcpy(str->u.str16, buf, len * 2);
3481
141
    return JS_MKPTR(JS_TAG_STRING, str);
3482
141
}
3483
3484
static JSValue js_new_string_char(JSContext *ctx, uint16_t c)
3485
396k
{
3486
396k
    if (c < 0x100) {
3487
396k
        uint8_t ch8 = c;
3488
396k
        return js_new_string8(ctx, &ch8, 1);
3489
396k
    } else {
3490
141
        uint16_t ch16 = c;
3491
141
        return js_new_string16(ctx, &ch16, 1);
3492
141
    }
3493
396k
}
3494
3495
static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end)
3496
100k
{
3497
100k
    int len = end - start;
3498
100k
    if (start == 0 && end == p->len) {
3499
0
        return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
3500
0
    }
3501
100k
    if (p->is_wide_char && len > 0) {
3502
0
        JSString *str;
3503
0
        int i;
3504
0
        uint16_t c = 0;
3505
0
        for (i = start; i < end; i++) {
3506
0
            c |= p->u.str16[i];
3507
0
        }
3508
0
        if (c > 0xFF)
3509
0
            return js_new_string16(ctx, p->u.str16 + start, len);
3510
3511
0
        str = js_alloc_string(ctx, len, 0);
3512
0
        if (!str)
3513
0
            return JS_EXCEPTION;
3514
0
        for (i = 0; i < len; i++) {
3515
0
            str->u.str8[i] = p->u.str16[start + i];
3516
0
        }
3517
0
        str->u.str8[len] = '\0';
3518
0
        return JS_MKPTR(JS_TAG_STRING, str);
3519
100k
    } else {
3520
100k
        return js_new_string8(ctx, p->u.str8 + start, len);
3521
100k
    }
3522
100k
}
3523
3524
typedef struct StringBuffer {
3525
    JSContext *ctx;
3526
    JSString *str;
3527
    int len;
3528
    int size;
3529
    int is_wide_char;
3530
    int error_status;
3531
} StringBuffer;
3532
3533
/* It is valid to call string_buffer_end() and all string_buffer functions even
3534
   if string_buffer_init() or another string_buffer function returns an error.
3535
   If the error_status is set, string_buffer_end() returns JS_EXCEPTION.
3536
 */
3537
static int string_buffer_init2(JSContext *ctx, StringBuffer *s, int size,
3538
                               int is_wide)
3539
231k
{
3540
231k
    s->ctx = ctx;
3541
231k
    s->size = size;
3542
231k
    s->len = 0;
3543
231k
    s->is_wide_char = is_wide;
3544
231k
    s->error_status = 0;
3545
231k
    s->str = js_alloc_string(ctx, size, is_wide);
3546
231k
    if (unlikely(!s->str)) {
3547
0
        s->size = 0;
3548
0
        return s->error_status = -1;
3549
0
    }
3550
#ifdef DUMP_LEAKS
3551
    /* the StringBuffer may reallocate the JSString, only link it at the end */
3552
    list_del(&s->str->link);
3553
#endif
3554
231k
    return 0;
3555
231k
}
3556
3557
static inline int string_buffer_init(JSContext *ctx, StringBuffer *s, int size)
3558
5.26k
{
3559
5.26k
    return string_buffer_init2(ctx, s, size, 0);
3560
5.26k
}
3561
3562
static void string_buffer_free(StringBuffer *s)
3563
6
{
3564
6
    js_free(s->ctx, s->str);
3565
6
    s->str = NULL;
3566
6
}
3567
3568
static int string_buffer_set_error(StringBuffer *s)
3569
0
{
3570
0
    js_free(s->ctx, s->str);
3571
0
    s->str = NULL;
3572
0
    s->size = 0;
3573
0
    s->len = 0;
3574
0
    return s->error_status = -1;
3575
0
}
3576
3577
static no_inline int string_buffer_widen(StringBuffer *s, int size)
3578
1.78k
{
3579
1.78k
    JSString *str;
3580
1.78k
    size_t slack;
3581
1.78k
    int i;
3582
3583
1.78k
    if (s->error_status)
3584
0
        return -1;
3585
3586
1.78k
    str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack);
3587
1.78k
    if (!str)
3588
0
        return string_buffer_set_error(s);
3589
1.78k
    size += slack >> 1;
3590
618k
    for(i = s->len; i-- > 0;) {
3591
616k
        str->u.str16[i] = str->u.str8[i];
3592
616k
    }
3593
1.78k
    s->is_wide_char = 1;
3594
1.78k
    s->size = size;
3595
1.78k
    s->str = str;
3596
1.78k
    return 0;
3597
1.78k
}
3598
3599
static no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c)
3600
1.12k
{
3601
1.12k
    JSString *new_str;
3602
1.12k
    int new_size;
3603
1.12k
    size_t new_size_bytes, slack;
3604
3605
1.12k
    if (s->error_status)
3606
0
        return -1;
3607
3608
1.12k
    if (new_len > JS_STRING_LEN_MAX) {
3609
0
        JS_ThrowInternalError(s->ctx, "string too long");
3610
0
        return string_buffer_set_error(s);
3611
0
    }
3612
1.12k
    new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX);
3613
1.12k
    if (!s->is_wide_char && c >= 0x100) {
3614
2
        return string_buffer_widen(s, new_size);
3615
2
    }
3616
1.11k
    new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char;
3617
1.11k
    new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack);
3618
1.11k
    if (!new_str)
3619
0
        return string_buffer_set_error(s);
3620
1.11k
    new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX);
3621
1.11k
    s->size = new_size;
3622
1.11k
    s->str = new_str;
3623
1.11k
    return 0;
3624
1.11k
}
3625
3626
static no_inline int string_buffer_putc_slow(StringBuffer *s, uint32_t c)
3627
2.82k
{
3628
2.82k
    if (unlikely(s->len >= s->size)) {
3629
1.04k
        if (string_buffer_realloc(s, s->len + 1, c))
3630
0
            return -1;
3631
1.04k
    }
3632
2.82k
    if (s->is_wide_char) {
3633
145
        s->str->u.str16[s->len++] = c;
3634
2.67k
    } else if (c < 0x100) {
3635
899
        s->str->u.str8[s->len++] = c;
3636
1.77k
    } else {
3637
1.77k
        if (string_buffer_widen(s, s->size))
3638
0
            return -1;
3639
1.77k
        s->str->u.str16[s->len++] = c;
3640
1.77k
    }
3641
2.82k
    return 0;
3642
2.82k
}
3643
3644
/* 0 <= c <= 0xff */
3645
static int string_buffer_putc8(StringBuffer *s, uint32_t c)
3646
2.44M
{
3647
2.44M
    if (unlikely(s->len >= s->size)) {
3648
62
        if (string_buffer_realloc(s, s->len + 1, c))
3649
0
            return -1;
3650
62
    }
3651
2.44M
    if (s->is_wide_char) {
3652
2.31M
        s->str->u.str16[s->len++] = c;
3653
2.31M
    } else {
3654
126k
        s->str->u.str8[s->len++] = c;
3655
126k
    }
3656
2.44M
    return 0;
3657
2.44M
}
3658
3659
/* 0 <= c <= 0xffff */
3660
static int string_buffer_putc16(StringBuffer *s, uint32_t c)
3661
1.37M
{
3662
1.37M
    if (likely(s->len < s->size)) {
3663
1.37M
        if (s->is_wide_char) {
3664
1.04M
            s->str->u.str16[s->len++] = c;
3665
1.04M
            return 0;
3666
1.04M
        } else if (c < 0x100) {
3667
331k
            s->str->u.str8[s->len++] = c;
3668
331k
            return 0;
3669
331k
        }
3670
1.37M
    }
3671
2.82k
    return string_buffer_putc_slow(s, c);
3672
1.37M
}
3673
3674
/* 0 <= c <= 0x10ffff */
3675
static int string_buffer_putc(StringBuffer *s, uint32_t c)
3676
1.02M
{
3677
1.02M
    if (unlikely(c >= 0x10000)) {
3678
        /* surrogate pair */
3679
10
        c -= 0x10000;
3680
10
        if (string_buffer_putc16(s, (c >> 10) + 0xd800))
3681
0
            return -1;
3682
10
        c = (c & 0x3ff) + 0xdc00;
3683
10
    }
3684
1.02M
    return string_buffer_putc16(s, c);
3685
1.02M
}
3686
3687
52.7k
static int string_get(const JSString *p, int idx) {
3688
52.7k
    return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx];
3689
52.7k
}
3690
3691
static int string_getc(const JSString *p, int *pidx)
3692
53.0k
{
3693
53.0k
    int idx, c, c1;
3694
53.0k
    idx = *pidx;
3695
53.0k
    if (p->is_wide_char) {
3696
52.7k
        c = p->u.str16[idx++];
3697
52.7k
        if (c >= 0xd800 && c < 0xdc00 && idx < p->len) {
3698
0
            c1 = p->u.str16[idx];
3699
0
            if (c1 >= 0xdc00 && c1 < 0xe000) {
3700
0
                c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
3701
0
                idx++;
3702
0
            }
3703
0
        }
3704
52.7k
    } else {
3705
359
        c = p->u.str8[idx++];
3706
359
    }
3707
53.0k
    *pidx = idx;
3708
53.0k
    return c;
3709
53.0k
}
3710
3711
static int string_buffer_write8(StringBuffer *s, const uint8_t *p, int len)
3712
832k
{
3713
832k
    int i;
3714
3715
832k
    if (s->len + len > s->size) {
3716
12
        if (string_buffer_realloc(s, s->len + len, 0))
3717
0
            return -1;
3718
12
    }
3719
832k
    if (s->is_wide_char) {
3720
61.5k
        for (i = 0; i < len; i++) {
3721
30.7k
            s->str->u.str16[s->len + i] = p[i];
3722
30.7k
        }
3723
30.7k
        s->len += len;
3724
801k
    } else {
3725
801k
        memcpy(&s->str->u.str8[s->len], p, len);
3726
801k
        s->len += len;
3727
801k
    }
3728
832k
    return 0;
3729
832k
}
3730
3731
static int string_buffer_write16(StringBuffer *s, const uint16_t *p, int len)
3732
4
{
3733
4
    int c = 0, i;
3734
3735
131k
    for (i = 0; i < len; i++) {
3736
131k
        c |= p[i];
3737
131k
    }
3738
4
    if (s->len + len > s->size) {
3739
2
        if (string_buffer_realloc(s, s->len + len, c))
3740
0
            return -1;
3741
2
    } else if (!s->is_wide_char && c >= 0x100) {
3742
1
        if (string_buffer_widen(s, s->size))
3743
0
            return -1;
3744
1
    }
3745
4
    if (s->is_wide_char) {
3746
4
        memcpy(&s->str->u.str16[s->len], p, len << 1);
3747
4
        s->len += len;
3748
4
    } else {
3749
0
        for (i = 0; i < len; i++) {
3750
0
            s->str->u.str8[s->len + i] = p[i];
3751
0
        }
3752
0
        s->len += len;
3753
0
    }
3754
4
    return 0;
3755
4
}
3756
3757
/* appending an ASCII string */
3758
static int string_buffer_puts8(StringBuffer *s, const char *str)
3759
0
{
3760
0
    return string_buffer_write8(s, (const uint8_t *)str, strlen(str));
3761
0
}
3762
3763
static int string_buffer_concat(StringBuffer *s, const JSString *p,
3764
                                uint32_t from, uint32_t to)
3765
378k
{
3766
378k
    if (to <= from)
3767
3
        return 0;
3768
378k
    if (p->is_wide_char)
3769
4
        return string_buffer_write16(s, p->u.str16 + from, to - from);
3770
378k
    else
3771
378k
        return string_buffer_write8(s, p->u.str8 + from, to - from);
3772
378k
}
3773
3774
static int string_buffer_concat_value(StringBuffer *s, JSValueConst v)
3775
0
{
3776
0
    JSString *p;
3777
0
    JSValue v1;
3778
0
    int res;
3779
3780
0
    if (s->error_status) {
3781
        /* prevent exception overload */
3782
0
        return -1;
3783
0
    }
3784
0
    if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
3785
0
        v1 = JS_ToString(s->ctx, v);
3786
0
        if (JS_IsException(v1))
3787
0
            return string_buffer_set_error(s);
3788
0
        p = JS_VALUE_GET_STRING(v1);
3789
0
        res = string_buffer_concat(s, p, 0, p->len);
3790
0
        JS_FreeValue(s->ctx, v1);
3791
0
        return res;
3792
0
    }
3793
0
    p = JS_VALUE_GET_STRING(v);
3794
0
    return string_buffer_concat(s, p, 0, p->len);
3795
0
}
3796
3797
static int string_buffer_concat_value_free(StringBuffer *s, JSValue v)
3798
152k
{
3799
152k
    JSString *p;
3800
152k
    int res;
3801
3802
152k
    if (s->error_status) {
3803
        /* prevent exception overload */
3804
0
        JS_FreeValue(s->ctx, v);
3805
0
        return -1;
3806
0
    }
3807
152k
    if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
3808
1
        v = JS_ToStringFree(s->ctx, v);
3809
1
        if (JS_IsException(v))
3810
0
            return string_buffer_set_error(s);
3811
1
    }
3812
152k
    p = JS_VALUE_GET_STRING(v);
3813
152k
    res = string_buffer_concat(s, p, 0, p->len);
3814
152k
    JS_FreeValue(s->ctx, v);
3815
152k
    return res;
3816
152k
}
3817
3818
static int string_buffer_fill(StringBuffer *s, int c, int count)
3819
0
{
3820
    /* XXX: optimize */
3821
0
    if (s->len + count > s->size) {
3822
0
        if (string_buffer_realloc(s, s->len + count, c))
3823
0
            return -1;
3824
0
    }
3825
0
    while (count-- > 0) {
3826
0
        if (string_buffer_putc16(s, c))
3827
0
            return -1;
3828
0
    }
3829
0
    return 0;
3830
0
}
3831
3832
static JSValue string_buffer_end(StringBuffer *s)
3833
231k
{
3834
231k
    JSString *str;
3835
231k
    str = s->str;
3836
231k
    if (s->error_status)
3837
0
        return JS_EXCEPTION;
3838
231k
    if (s->len == 0) {
3839
1.06k
        js_free(s->ctx, str);
3840
1.06k
        s->str = NULL;
3841
1.06k
        return JS_AtomToString(s->ctx, JS_ATOM_empty_string);
3842
1.06k
    }
3843
230k
    if (s->len < s->size) {
3844
        /* smaller size so js_realloc should not fail, but OK if it does */
3845
        /* XXX: should add some slack to avoid unnecessary calls */
3846
        /* XXX: might need to use malloc+free to ensure smaller size */
3847
4.19k
        str = js_realloc_rt(s->ctx->rt, str, sizeof(JSString) +
3848
4.19k
                            (s->len << s->is_wide_char) + 1 - s->is_wide_char);
3849
4.19k
        if (str == NULL)
3850
0
            str = s->str;
3851
4.19k
        s->str = str;
3852
4.19k
    }
3853
230k
    if (!s->is_wide_char)
3854
228k
        str->u.str8[s->len] = 0;
3855
#ifdef DUMP_LEAKS
3856
    list_add_tail(&str->link, &s->ctx->rt->string_list);
3857
#endif
3858
230k
    str->is_wide_char = s->is_wide_char;
3859
230k
    str->len = s->len;
3860
230k
    s->str = NULL;
3861
230k
    return JS_MKPTR(JS_TAG_STRING, str);
3862
231k
}
3863
3864
/* create a string from a UTF-8 buffer */
3865
JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)
3866
363k
{
3867
363k
    const uint8_t *p, *p_end, *p_start, *p_next;
3868
363k
    uint32_t c;
3869
363k
    StringBuffer b_s, *b = &b_s;
3870
363k
    size_t len1;
3871
    
3872
363k
    p_start = (const uint8_t *)buf;
3873
363k
    p_end = p_start + buf_len;
3874
363k
    p = p_start;
3875
9.33M
    while (p < p_end && *p < 128)
3876
8.97M
        p++;
3877
363k
    len1 = p - p_start;
3878
363k
    if (len1 > JS_STRING_LEN_MAX)
3879
0
        return JS_ThrowInternalError(ctx, "string too long");
3880
363k
    if (p == p_end) {
3881
        /* ASCII string */
3882
361k
        return js_new_string8(ctx, (const uint8_t *)buf, buf_len);
3883
361k
    } else {
3884
1.86k
        if (string_buffer_init(ctx, b, buf_len))
3885
0
            goto fail;
3886
1.86k
        string_buffer_write8(b, p_start, len1);
3887
2.64M
        while (p < p_end) {
3888
2.63M
            if (*p < 128) {
3889
2.28M
                string_buffer_putc8(b, *p++);
3890
2.28M
            } else {
3891
                /* parse utf-8 sequence, return 0xFFFFFFFF for error */
3892
355k
                c = unicode_from_utf8(p, p_end - p, &p_next);
3893
355k
                if (c < 0x10000) {
3894
4.72k
                    p = p_next;
3895
350k
                } else if (c <= 0x10FFFF) {
3896
124
                    p = p_next;
3897
                    /* surrogate pair */
3898
124
                    c -= 0x10000;
3899
124
                    string_buffer_putc16(b, (c >> 10) + 0xd800);
3900
124
                    c = (c & 0x3ff) + 0xdc00;
3901
350k
                } else {
3902
                    /* invalid char */
3903
350k
                    c = 0xfffd;
3904
                    /* skip the invalid chars */
3905
                    /* XXX: seems incorrect. Why not just use c = *p++; ? */
3906
408k
                    while (p < p_end && (*p >= 0x80 && *p < 0xc0))
3907
58.2k
                        p++;
3908
350k
                    if (p < p_end) {
3909
350k
                        p++;
3910
357k
                        while (p < p_end && (*p >= 0x80 && *p < 0xc0))
3911
6.81k
                            p++;
3912
350k
                    }
3913
350k
                }
3914
355k
                string_buffer_putc16(b, c);
3915
355k
            }
3916
2.63M
        }
3917
1.86k
    }
3918
1.86k
    return string_buffer_end(b);
3919
3920
0
 fail:
3921
0
    string_buffer_free(b);
3922
0
    return JS_EXCEPTION;
3923
363k
}
3924
3925
static JSValue JS_ConcatString3(JSContext *ctx, const char *str1,
3926
                                JSValue str2, const char *str3)
3927
225k
{
3928
225k
    StringBuffer b_s, *b = &b_s;
3929
225k
    int len1, len3;
3930
225k
    JSString *p;
3931
3932
225k
    if (unlikely(JS_VALUE_GET_TAG(str2) != JS_TAG_STRING)) {
3933
0
        str2 = JS_ToStringFree(ctx, str2);
3934
0
        if (JS_IsException(str2))
3935
0
            goto fail;
3936
0
    }
3937
225k
    p = JS_VALUE_GET_STRING(str2);
3938
225k
    len1 = strlen(str1);
3939
225k
    len3 = strlen(str3);
3940
3941
225k
    if (string_buffer_init2(ctx, b, len1 + p->len + len3, p->is_wide_char))
3942
0
        goto fail;
3943
3944
225k
    string_buffer_write8(b, (const uint8_t *)str1, len1);
3945
225k
    string_buffer_concat(b, p, 0, p->len);
3946
225k
    string_buffer_write8(b, (const uint8_t *)str3, len3);
3947
3948
225k
    JS_FreeValue(ctx, str2);
3949
225k
    return string_buffer_end(b);
3950
3951
0
 fail:
3952
0
    JS_FreeValue(ctx, str2);
3953
0
    return JS_EXCEPTION;
3954
225k
}
3955
3956
JSValue JS_NewString(JSContext *ctx, const char *str)
3957
317k
{
3958
317k
    return JS_NewStringLen(ctx, str, strlen(str));
3959
317k
}
3960
3961
JSValue JS_NewAtomString(JSContext *ctx, const char *str)
3962
24
{
3963
24
    JSAtom atom = JS_NewAtom(ctx, str);
3964
24
    if (atom == JS_ATOM_NULL)
3965
0
        return JS_EXCEPTION;
3966
24
    JSValue val = JS_AtomToString(ctx, atom);
3967
24
    JS_FreeAtom(ctx, atom);
3968
24
    return val;
3969
24
}
3970
3971
/* return (NULL, 0) if exception. */
3972
/* return pointer into a JSString with a live ref_count */
3973
/* cesu8 determines if non-BMP1 codepoints are encoded as 1 or 2 utf-8 sequences */
3974
const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, BOOL cesu8)
3975
400k
{
3976
400k
    JSValue val;
3977
400k
    JSString *str, *str_new;
3978
400k
    int pos, len, c, c1;
3979
400k
    uint8_t *q;
3980
3981
400k
    if (JS_VALUE_GET_TAG(val1) != JS_TAG_STRING) {
3982
2
        val = JS_ToString(ctx, val1);
3983
2
        if (JS_IsException(val))
3984
0
            goto fail;
3985
400k
    } else {
3986
400k
        val = JS_DupValue(ctx, val1);
3987
400k
    }
3988
3989
400k
    str = JS_VALUE_GET_STRING(val);
3990
400k
    len = str->len;
3991
400k
    if (!str->is_wide_char) {
3992
400k
        const uint8_t *src = str->u.str8;
3993
400k
        int count;
3994
3995
        /* count the number of non-ASCII characters */
3996
        /* Scanning the whole string is required for ASCII strings,
3997
           and computing the number of non-ASCII bytes is less expensive
3998
           than testing each byte, hence this method is faster for ASCII
3999
           strings, which is the most common case.
4000
         */
4001
400k
        count = 0;
4002
7.09M
        for (pos = 0; pos < len; pos++) {
4003
6.69M
            count += src[pos] >> 7;
4004
6.69M
        }
4005
400k
        if (count == 0) {
4006
400k
            if (plen)
4007
195k
                *plen = len;
4008
400k
            return (const char *)src;
4009
400k
        }
4010
0
        str_new = js_alloc_string(ctx, len + count, 0);
4011
0
        if (!str_new)
4012
0
            goto fail;
4013
0
        q = str_new->u.str8;
4014
0
        for (pos = 0; pos < len; pos++) {
4015
0
            c = src[pos];
4016
0
            if (c < 0x80) {
4017
0
                *q++ = c;
4018
0
            } else {
4019
0
                *q++ = (c >> 6) | 0xc0;
4020
0
                *q++ = (c & 0x3f) | 0x80;
4021
0
            }
4022
0
        }
4023
44
    } else {
4024
44
        const uint16_t *src = str->u.str16;
4025
        /* Allocate 3 bytes per 16 bit code point. Surrogate pairs may
4026
           produce 4 bytes but use 2 code points.
4027
         */
4028
44
        str_new = js_alloc_string(ctx, len * 3, 0);
4029
44
        if (!str_new)
4030
0
            goto fail;
4031
44
        q = str_new->u.str8;
4032
44
        pos = 0;
4033
3.21M
        while (pos < len) {
4034
3.21M
            c = src[pos++];
4035
3.21M
            if (c < 0x80) {
4036
2.86M
                *q++ = c;
4037
2.86M
            } else {
4038
354k
                if (c >= 0xd800 && c < 0xdc00) {
4039
134
                    if (pos < len && !cesu8) {
4040
134
                        c1 = src[pos];
4041
134
                        if (c1 >= 0xdc00 && c1 < 0xe000) {
4042
129
                            pos++;
4043
                            /* surrogate pair */
4044
129
                            c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
4045
129
                        } else {
4046
                            /* Keep unmatched surrogate code points */
4047
                            /* c = 0xfffd; */ /* error */
4048
5
                        }
4049
134
                    } else {
4050
                        /* Keep unmatched surrogate code points */
4051
                        /* c = 0xfffd; */ /* error */
4052
0
                    }
4053
134
                }
4054
354k
                q += unicode_to_utf8(q, c);
4055
354k
            }
4056
3.21M
        }
4057
44
    }
4058
4059
44
    *q = '\0';
4060
44
    str_new->len = q - str_new->u.str8;
4061
44
    JS_FreeValue(ctx, val);
4062
44
    if (plen)
4063
44
        *plen = str_new->len;
4064
44
    return (const char *)str_new->u.str8;
4065
0
 fail:
4066
0
    if (plen)
4067
0
        *plen = 0;
4068
0
    return NULL;
4069
400k
}
4070
4071
void JS_FreeCString(JSContext *ctx, const char *ptr)
4072
522k
{
4073
522k
    JSString *p;
4074
522k
    if (!ptr)
4075
122k
        return;
4076
    /* purposely removing constness */
4077
400k
    p = (JSString *)(void *)(ptr - offsetof(JSString, u));
4078
400k
    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
4079
400k
}
4080
4081
static int memcmp16_8(const uint16_t *src1, const uint8_t *src2, int len)
4082
0
{
4083
0
    int c, i;
4084
0
    for(i = 0; i < len; i++) {
4085
0
        c = src1[i] - src2[i];
4086
0
        if (c != 0)
4087
0
            return c;
4088
0
    }
4089
0
    return 0;
4090
0
}
4091
4092
static int memcmp16(const uint16_t *src1, const uint16_t *src2, int len)
4093
1.63k
{
4094
1.63k
    int c, i;
4095
10.5k
    for(i = 0; i < len; i++) {
4096
8.90k
        c = src1[i] - src2[i];
4097
8.90k
        if (c != 0)
4098
0
            return c;
4099
8.90k
    }
4100
1.63k
    return 0;
4101
1.63k
}
4102
4103
static int js_string_memcmp(const JSString *p1, const JSString *p2, int len)
4104
50.0k
{
4105
50.0k
    int res;
4106
4107
50.0k
    if (likely(!p1->is_wide_char)) {
4108
48.4k
        if (likely(!p2->is_wide_char))
4109
48.4k
            res = memcmp(p1->u.str8, p2->u.str8, len);
4110
0
        else
4111
0
            res = -memcmp16_8(p2->u.str16, p1->u.str8, len);
4112
48.4k
    } else {
4113
1.63k
        if (!p2->is_wide_char)
4114
0
            res = memcmp16_8(p1->u.str16, p2->u.str8, len);
4115
1.63k
        else
4116
1.63k
            res = memcmp16(p1->u.str16, p2->u.str16, len);
4117
1.63k
    }
4118
50.0k
    return res;
4119
50.0k
}
4120
4121
/* return < 0, 0 or > 0 */
4122
static int js_string_compare(JSContext *ctx,
4123
                             const JSString *p1, const JSString *p2)
4124
0
{
4125
0
    int res, len;
4126
0
    len = min_int(p1->len, p2->len);
4127
0
    res = js_string_memcmp(p1, p2, len);
4128
0
    if (res == 0) {
4129
0
        if (p1->len == p2->len)
4130
0
            res = 0;
4131
0
        else if (p1->len < p2->len)
4132
0
            res = -1;
4133
0
        else
4134
0
            res = 1;
4135
0
    }
4136
0
    return res;
4137
0
}
4138
4139
static void copy_str16(uint16_t *dst, const JSString *p, int offset, int len)
4140
0
{
4141
0
    if (p->is_wide_char) {
4142
0
        memcpy(dst, p->u.str16 + offset, len * 2);
4143
0
    } else {
4144
0
        const uint8_t *src1 = p->u.str8 + offset;
4145
0
        int i;
4146
4147
0
        for(i = 0; i < len; i++)
4148
0
            dst[i] = src1[i];
4149
0
    }
4150
0
}
4151
4152
static JSValue JS_ConcatString1(JSContext *ctx,
4153
                                const JSString *p1, const JSString *p2)
4154
71.9k
{
4155
71.9k
    JSString *p;
4156
71.9k
    uint32_t len;
4157
71.9k
    int is_wide_char;
4158
4159
71.9k
    len = p1->len + p2->len;
4160
71.9k
    if (len > JS_STRING_LEN_MAX)
4161
0
        return JS_ThrowInternalError(ctx, "string too long");
4162
71.9k
    is_wide_char = p1->is_wide_char | p2->is_wide_char;
4163
71.9k
    p = js_alloc_string(ctx, len, is_wide_char);
4164
71.9k
    if (!p)
4165
0
        return JS_EXCEPTION;
4166
71.9k
    if (!is_wide_char) {
4167
71.9k
        memcpy(p->u.str8, p1->u.str8, p1->len);
4168
71.9k
        memcpy(p->u.str8 + p1->len, p2->u.str8, p2->len);
4169
71.9k
        p->u.str8[len] = '\0';
4170
71.9k
    } else {
4171
0
        copy_str16(p->u.str16, p1, 0, p1->len);
4172
0
        copy_str16(p->u.str16 + p1->len, p2, 0, p2->len);
4173
0
    }
4174
71.9k
    return JS_MKPTR(JS_TAG_STRING, p);
4175
71.9k
}
4176
4177
/* op1 and op2 are converted to strings. For convience, op1 or op2 =
4178
   JS_EXCEPTION are accepted and return JS_EXCEPTION.  */
4179
static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2)
4180
71.9k
{
4181
71.9k
    JSValue ret;
4182
71.9k
    JSString *p1, *p2;
4183
4184
71.9k
    if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING)) {
4185
71.9k
        op1 = JS_ToStringFree(ctx, op1);
4186
71.9k
        if (JS_IsException(op1)) {
4187
0
            JS_FreeValue(ctx, op2);
4188
0
            return JS_EXCEPTION;
4189
0
        }
4190
71.9k
    }
4191
71.9k
    if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING)) {
4192
0
        op2 = JS_ToStringFree(ctx, op2);
4193
0
        if (JS_IsException(op2)) {
4194
0
            JS_FreeValue(ctx, op1);
4195
0
            return JS_EXCEPTION;
4196
0
        }
4197
0
    }
4198
71.9k
    p1 = JS_VALUE_GET_STRING(op1);
4199
71.9k
    p2 = JS_VALUE_GET_STRING(op2);
4200
4201
    /* XXX: could also check if p1 is empty */
4202
71.9k
    if (p2->len == 0) {
4203
0
        goto ret_op1;
4204
0
    }
4205
71.9k
    if (p1->header.ref_count == 1 && p1->is_wide_char == p2->is_wide_char
4206
71.9k
    &&  js_malloc_usable_size(ctx, p1) >= sizeof(*p1) + ((p1->len + p2->len) << p2->is_wide_char) + 1 - p1->is_wide_char) {
4207
        /* Concatenate in place in available space at the end of p1 */
4208
0
        if (p1->is_wide_char) {
4209
0
            memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1);
4210
0
            p1->len += p2->len;
4211
0
        } else {
4212
0
            memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len);
4213
0
            p1->len += p2->len;
4214
0
            p1->u.str8[p1->len] = '\0';
4215
0
        }
4216
0
    ret_op1:
4217
0
        JS_FreeValue(ctx, op2);
4218
0
        return op1;
4219
0
    }
4220
71.9k
    ret = JS_ConcatString1(ctx, p1, p2);
4221
71.9k
    JS_FreeValue(ctx, op1);
4222
71.9k
    JS_FreeValue(ctx, op2);
4223
71.9k
    return ret;
4224
71.9k
}
4225
4226
/* Shape support */
4227
4228
static inline size_t get_shape_size(size_t hash_size, size_t prop_size)
4229
1.26M
{
4230
1.26M
    return hash_size * sizeof(uint32_t) + sizeof(JSShape) +
4231
1.26M
        prop_size * sizeof(JSShapeProperty);
4232
1.26M
}
4233
4234
static inline JSShape *get_shape_from_alloc(void *sh_alloc, size_t hash_size)
4235
1.26M
{
4236
1.26M
    return (JSShape *)(void *)((uint32_t *)sh_alloc + hash_size);
4237
1.26M
}
4238
4239
static inline uint32_t *prop_hash_end(JSShape *sh)
4240
22.3M
{
4241
22.3M
    return (uint32_t *)sh;
4242
22.3M
}
4243
4244
static inline void *get_alloc_from_shape(JSShape *sh)
4245
1.91M
{
4246
1.91M
    return prop_hash_end(sh) - ((intptr_t)sh->prop_hash_mask + 1);
4247
1.91M
}
4248
4249
static inline JSShapeProperty *get_shape_prop(JSShape *sh)
4250
18.3M
{
4251
18.3M
    return sh->prop;
4252
18.3M
}
4253
4254
static int init_shape_hash(JSRuntime *rt)
4255
3
{
4256
3
    rt->shape_hash_bits = 4;   /* 16 shapes */
4257
3
    rt->shape_hash_size = 1 << rt->shape_hash_bits;
4258
3
    rt->shape_hash_count = 0;
4259
3
    rt->shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
4260
3
                                   rt->shape_hash_size);
4261
3
    if (!rt->shape_hash)
4262
0
        return -1;
4263
3
    return 0;
4264
3
}
4265
4266
/* same magic hash multiplier as the Linux kernel */
4267
static uint32_t shape_hash(uint32_t h, uint32_t val)
4268
16.0M
{
4269
16.0M
    return (h + val) * 0x9e370001;
4270
16.0M
}
4271
4272
/* truncate the shape hash to 'hash_bits' bits */
4273
static uint32_t get_shape_hash(uint32_t h, int hash_bits)
4274
12.4M
{
4275
12.4M
    return h >> (32 - hash_bits);
4276
12.4M
}
4277
4278
static uint32_t shape_initial_hash(JSObject *proto)
4279
1.86M
{
4280
1.86M
    uint32_t h;
4281
1.86M
    h = shape_hash(1, (uintptr_t)proto);
4282
1.86M
    if (sizeof(proto) > 4)
4283
1.86M
        h = shape_hash(h, (uint64_t)(uintptr_t)proto >> 32);
4284
1.86M
    return h;
4285
1.86M
}
4286
4287
static int resize_shape_hash(JSRuntime *rt, int new_shape_hash_bits)
4288
6
{
4289
6
    int new_shape_hash_size, i;
4290
6
    uint32_t h;
4291
6
    JSShape **new_shape_hash, *sh, *sh_next;
4292
4293
6
    new_shape_hash_size = 1 << new_shape_hash_bits;
4294
6
    new_shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
4295
6
                                   new_shape_hash_size);
4296
6
    if (!new_shape_hash)
4297
0
        return -1;
4298
230
    for(i = 0; i < rt->shape_hash_size; i++) {
4299
336
        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh_next) {
4300
112
            sh_next = sh->shape_hash_next;
4301
112
            h = get_shape_hash(sh->hash, new_shape_hash_bits);
4302
112
            sh->shape_hash_next = new_shape_hash[h];
4303
112
            new_shape_hash[h] = sh;
4304
112
        }
4305
224
    }
4306
6
    js_free_rt(rt, rt->shape_hash);
4307
6
    rt->shape_hash_bits = new_shape_hash_bits;
4308
6
    rt->shape_hash_size = new_shape_hash_size;
4309
6
    rt->shape_hash = new_shape_hash;
4310
6
    return 0;
4311
6
}
4312
4313
static void js_shape_hash_link(JSRuntime *rt, JSShape *sh)
4314
3.77M
{
4315
3.77M
    uint32_t h;
4316
3.77M
    h = get_shape_hash(sh->hash, rt->shape_hash_bits);
4317
3.77M
    sh->shape_hash_next = rt->shape_hash[h];
4318
3.77M
    rt->shape_hash[h] = sh;
4319
3.77M
    rt->shape_hash_count++;
4320
3.77M
}
4321
4322
static void js_shape_hash_unlink(JSRuntime *rt, JSShape *sh)
4323
3.77M
{
4324
3.77M
    uint32_t h;
4325
3.77M
    JSShape **psh;
4326
4327
3.77M
    h = get_shape_hash(sh->hash, rt->shape_hash_bits);
4328
3.77M
    psh = &rt->shape_hash[h];
4329
3.77M
    while (*psh != sh)
4330
6
        psh = &(*psh)->shape_hash_next;
4331
3.77M
    *psh = sh->shape_hash_next;
4332
3.77M
    rt->shape_hash_count--;
4333
3.77M
}
4334
4335
/* create a new empty shape with prototype 'proto' */
4336
static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto,
4337
                                        int hash_size, int prop_size)
4338
562k
{
4339
562k
    JSRuntime *rt = ctx->rt;
4340
562k
    void *sh_alloc;
4341
562k
    JSShape *sh;
4342
4343
    /* resize the shape hash table if necessary */
4344
562k
    if (2 * (rt->shape_hash_count + 1) > rt->shape_hash_size) {
4345
6
        resize_shape_hash(rt, rt->shape_hash_bits + 1);
4346
6
    }
4347
4348
562k
    sh_alloc = js_malloc(ctx, get_shape_size(hash_size, prop_size));
4349
562k
    if (!sh_alloc)
4350
5
        return NULL;
4351
562k
    sh = get_shape_from_alloc(sh_alloc, hash_size);
4352
562k
    sh->header.ref_count = 1;
4353
562k
    add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
4354
562k
    if (proto)
4355
562k
        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, proto));
4356
562k
    sh->proto = proto;
4357
562k
    memset(prop_hash_end(sh) - hash_size, 0, sizeof(prop_hash_end(sh)[0]) *
4358
562k
           hash_size);
4359
562k
    sh->prop_hash_mask = hash_size - 1;
4360
562k
    sh->prop_size = prop_size;
4361
562k
    sh->prop_count = 0;
4362
562k
    sh->deleted_prop_count = 0;
4363
    
4364
    /* insert in the hash table */
4365
562k
    sh->hash = shape_initial_hash(proto);
4366
562k
    sh->is_hashed = TRUE;
4367
562k
    sh->has_small_array_index = FALSE;
4368
562k
    js_shape_hash_link(ctx->rt, sh);
4369
562k
    return sh;
4370
562k
}
4371
4372
static JSShape *js_new_shape(JSContext *ctx, JSObject *proto)
4373
562k
{
4374
562k
    return js_new_shape2(ctx, proto, JS_PROP_INITIAL_HASH_SIZE,
4375
562k
                         JS_PROP_INITIAL_SIZE);
4376
562k
}
4377
4378
/* The shape is cloned. The new shape is not inserted in the shape
4379
   hash table */
4380
static JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1)
4381
656k
{
4382
656k
    JSShape *sh;
4383
656k
    void *sh_alloc, *sh_alloc1;
4384
656k
    size_t size;
4385
656k
    JSShapeProperty *pr;
4386
656k
    uint32_t i, hash_size;
4387
4388
656k
    hash_size = sh1->prop_hash_mask + 1;
4389
656k
    size = get_shape_size(hash_size, sh1->prop_size);
4390
656k
    sh_alloc = js_malloc(ctx, size);
4391
656k
    if (!sh_alloc)
4392
0
        return NULL;
4393
656k
    sh_alloc1 = get_alloc_from_shape(sh1);
4394
656k
    memcpy(sh_alloc, sh_alloc1, size);
4395
656k
    sh = get_shape_from_alloc(sh_alloc, hash_size);
4396
656k
    sh->header.ref_count = 1;
4397
656k
    add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
4398
656k
    sh->is_hashed = FALSE;
4399
656k
    if (sh->proto) {
4400
656k
        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
4401
656k
    }
4402
1.40M
    for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
4403
748k
        JS_DupAtom(ctx, pr->atom);
4404
748k
    }
4405
656k
    return sh;
4406
656k
}
4407
4408
static JSShape *js_dup_shape(JSShape *sh)
4409
1.81M
{
4410
1.81M
    sh->header.ref_count++;
4411
1.81M
    return sh;
4412
1.81M
}
4413
4414
static void js_free_shape0(JSRuntime *rt, JSShape *sh)
4415
1.21M
{
4416
1.21M
    uint32_t i;
4417
1.21M
    JSShapeProperty *pr;
4418
4419
1.21M
    assert(sh->header.ref_count == 0);
4420
1.21M
    if (sh->is_hashed)
4421
1.21M
        js_shape_hash_unlink(rt, sh);
4422
1.21M
    if (sh->proto != NULL) {
4423
1.21M
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
4424
1.21M
    }
4425
1.21M
    pr = get_shape_prop(sh);
4426
4.42M
    for(i = 0; i < sh->prop_count; i++) {
4427
3.20M
        JS_FreeAtomRT(rt, pr->atom);
4428
3.20M
        pr++;
4429
3.20M
    }
4430
1.21M
    remove_gc_object(&sh->header);
4431
1.21M
    js_free_rt(rt, get_alloc_from_shape(sh));
4432
1.21M
}
4433
4434
static void js_free_shape(JSRuntime *rt, JSShape *sh)
4435
2.75M
{
4436
2.75M
    if (unlikely(--sh->header.ref_count <= 0)) {
4437
1.21M
        js_free_shape0(rt, sh);
4438
1.21M
    }
4439
2.75M
}
4440
4441
static void js_free_shape_null(JSRuntime *rt, JSShape *sh)
4442
0
{
4443
0
    if (sh)
4444
0
        js_free_shape(rt, sh);
4445
0
}
4446
4447
/* make space to hold at least 'count' properties */
4448
static no_inline int resize_properties(JSContext *ctx, JSShape **psh,
4449
                                       JSObject *p, uint32_t count)
4450
42.9k
{
4451
42.9k
    JSShape *sh;
4452
42.9k
    uint32_t new_size, new_hash_size, new_hash_mask, i;
4453
42.9k
    JSShapeProperty *pr;
4454
42.9k
    void *sh_alloc;
4455
42.9k
    intptr_t h;
4456
4457
42.9k
    sh = *psh;
4458
42.9k
    new_size = max_int(count, sh->prop_size * 3 / 2);
4459
    /* Reallocate prop array first to avoid crash or size inconsistency
4460
       in case of memory allocation failure */
4461
42.9k
    if (p) {
4462
42.9k
        JSProperty *new_prop;
4463
42.9k
        new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
4464
42.9k
        if (unlikely(!new_prop))
4465
0
            return -1;
4466
42.9k
        p->prop = new_prop;
4467
42.9k
    }
4468
42.9k
    new_hash_size = sh->prop_hash_mask + 1;
4469
43.4k
    while (new_hash_size < new_size)
4470
490
        new_hash_size = 2 * new_hash_size;
4471
42.9k
    if (new_hash_size != (sh->prop_hash_mask + 1)) {
4472
490
        JSShape *old_sh;
4473
        /* resize the hash table and the properties */
4474
490
        old_sh = sh;
4475
490
        sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
4476
490
        if (!sh_alloc)
4477
0
            return -1;
4478
490
        sh = get_shape_from_alloc(sh_alloc, new_hash_size);
4479
490
        list_del(&old_sh->header.link);
4480
        /* copy all the fields and the properties */
4481
490
        memcpy(sh, old_sh,
4482
490
               sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count);
4483
490
        list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
4484
490
        new_hash_mask = new_hash_size - 1;
4485
490
        sh->prop_hash_mask = new_hash_mask;
4486
490
        memset(prop_hash_end(sh) - new_hash_size, 0,
4487
490
               sizeof(prop_hash_end(sh)[0]) * new_hash_size);
4488
2.16M
        for(i = 0, pr = sh->prop; i < sh->prop_count; i++, pr++) {
4489
2.16M
            if (pr->atom != JS_ATOM_NULL) {
4490
2.16M
                h = ((uintptr_t)pr->atom & new_hash_mask);
4491
2.16M
                pr->hash_next = prop_hash_end(sh)[-h - 1];
4492
2.16M
                prop_hash_end(sh)[-h - 1] = i + 1;
4493
2.16M
            }
4494
2.16M
        }
4495
490
        js_free(ctx, get_alloc_from_shape(old_sh));
4496
42.4k
    } else {
4497
        /* only resize the properties */
4498
42.4k
        list_del(&sh->header.link);
4499
42.4k
        sh_alloc = js_realloc(ctx, get_alloc_from_shape(sh),
4500
42.4k
                              get_shape_size(new_hash_size, new_size));
4501
42.4k
        if (unlikely(!sh_alloc)) {
4502
            /* insert again in the GC list */
4503
0
            list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
4504
0
            return -1;
4505
0
        }
4506
42.4k
        sh = get_shape_from_alloc(sh_alloc, new_hash_size);
4507
42.4k
        list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
4508
42.4k
    }
4509
42.9k
    *psh = sh;
4510
42.9k
    sh->prop_size = new_size;
4511
42.9k
    return 0;
4512
42.9k
}
4513
4514
/* remove the deleted properties. */
4515
static int compact_properties(JSContext *ctx, JSObject *p)
4516
0
{
4517
0
    JSShape *sh, *old_sh;
4518
0
    void *sh_alloc;
4519
0
    intptr_t h;
4520
0
    uint32_t new_hash_size, i, j, new_hash_mask, new_size;
4521
0
    JSShapeProperty *old_pr, *pr;
4522
0
    JSProperty *prop, *new_prop;
4523
    
4524
0
    sh = p->shape;
4525
0
    assert(!sh->is_hashed);
4526
4527
0
    new_size = max_int(JS_PROP_INITIAL_SIZE,
4528
0
                       sh->prop_count - sh->deleted_prop_count);
4529
0
    assert(new_size <= sh->prop_size);
4530
4531
0
    new_hash_size = sh->prop_hash_mask + 1;
4532
0
    while ((new_hash_size / 2) >= new_size)
4533
0
        new_hash_size = new_hash_size / 2;
4534
0
    new_hash_mask = new_hash_size - 1;
4535
4536
    /* resize the hash table and the properties */
4537
0
    old_sh = sh;
4538
0
    sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
4539
0
    if (!sh_alloc)
4540
0
        return -1;
4541
0
    sh = get_shape_from_alloc(sh_alloc, new_hash_size);
4542
0
    list_del(&old_sh->header.link);
4543
0
    memcpy(sh, old_sh, sizeof(JSShape));
4544
0
    list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
4545
    
4546
0
    memset(prop_hash_end(sh) - new_hash_size, 0,
4547
0
           sizeof(prop_hash_end(sh)[0]) * new_hash_size);
4548
4549
0
    j = 0;
4550
0
    old_pr = old_sh->prop;
4551
0
    pr = sh->prop;
4552
0
    prop = p->prop;
4553
0
    for(i = 0; i < sh->prop_count; i++) {
4554
0
        if (old_pr->atom != JS_ATOM_NULL) {
4555
0
            pr->atom = old_pr->atom;
4556
0
            pr->flags = old_pr->flags;
4557
0
            h = ((uintptr_t)old_pr->atom & new_hash_mask);
4558
0
            pr->hash_next = prop_hash_end(sh)[-h - 1];
4559
0
            prop_hash_end(sh)[-h - 1] = j + 1;
4560
0
            prop[j] = prop[i];
4561
0
            j++;
4562
0
            pr++;
4563
0
        }
4564
0
        old_pr++;
4565
0
    }
4566
0
    assert(j == (sh->prop_count - sh->deleted_prop_count));
4567
0
    sh->prop_hash_mask = new_hash_mask;
4568
0
    sh->prop_size = new_size;
4569
0
    sh->deleted_prop_count = 0;
4570
0
    sh->prop_count = j;
4571
4572
0
    p->shape = sh;
4573
0
    js_free(ctx, get_alloc_from_shape(old_sh));
4574
    
4575
    /* reduce the size of the object properties */
4576
0
    new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
4577
0
    if (new_prop)
4578
0
        p->prop = new_prop;
4579
0
    return 0;
4580
0
}
4581
4582
static int add_shape_property(JSContext *ctx, JSShape **psh,
4583
                              JSObject *p, JSAtom atom, int prop_flags)
4584
2.55M
{
4585
2.55M
    JSRuntime *rt = ctx->rt;
4586
2.55M
    JSShape *sh = *psh;
4587
2.55M
    JSShapeProperty *pr, *prop;
4588
2.55M
    uint32_t hash_mask, new_shape_hash = 0;
4589
2.55M
    intptr_t h;
4590
4591
    /* update the shape hash */
4592
2.55M
    if (sh->is_hashed) {
4593
2.55M
        js_shape_hash_unlink(rt, sh);
4594
2.55M
        new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags);
4595
2.55M
    }
4596
4597
2.55M
    if (unlikely(sh->prop_count >= sh->prop_size)) {
4598
42.9k
        if (resize_properties(ctx, psh, p, sh->prop_count + 1)) {
4599
            /* in case of error, reinsert in the hash table.
4600
               sh is still valid if resize_properties() failed */
4601
0
            if (sh->is_hashed)
4602
0
                js_shape_hash_link(rt, sh);
4603
0
            return -1;
4604
0
        }
4605
42.9k
        sh = *psh;
4606
42.9k
    }
4607
2.55M
    if (sh->is_hashed) {
4608
2.55M
        sh->hash = new_shape_hash;
4609
2.55M
        js_shape_hash_link(rt, sh);
4610
2.55M
    }
4611
    /* Initialize the new shape property.
4612
       The object property at p->prop[sh->prop_count] is uninitialized */
4613
2.55M
    prop = get_shape_prop(sh);
4614
2.55M
    pr = &prop[sh->prop_count++];
4615
2.55M
    pr->atom = JS_DupAtom(ctx, atom);
4616
2.55M
    pr->flags = prop_flags;
4617
2.55M
    sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom);
4618
    /* add in hash table */
4619
2.55M
    hash_mask = sh->prop_hash_mask;
4620
2.55M
    h = atom & hash_mask;
4621
2.55M
    pr->hash_next = prop_hash_end(sh)[-h - 1];
4622
2.55M
    prop_hash_end(sh)[-h - 1] = sh->prop_count;
4623
2.55M
    return 0;
4624
2.55M
}
4625
4626
/* find a hashed empty shape matching the prototype. Return NULL if
4627
   not found */
4628
static JSShape *find_hashed_shape_proto(JSRuntime *rt, JSObject *proto)
4629
1.29M
{
4630
1.29M
    JSShape *sh1;
4631
1.29M
    uint32_t h, h1;
4632
4633
1.29M
    h = shape_initial_hash(proto);
4634
1.29M
    h1 = get_shape_hash(h, rt->shape_hash_bits);
4635
1.29M
    for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
4636
737k
        if (sh1->hash == h &&
4637
737k
            sh1->proto == proto &&
4638
737k
            sh1->prop_count == 0) {
4639
737k
            return sh1;
4640
737k
        }
4641
737k
    }
4642
562k
    return NULL;
4643
1.29M
}
4644
4645
/* find a hashed shape matching sh + (prop, prop_flags). Return NULL if
4646
   not found */
4647
static JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh,
4648
                                       JSAtom atom, int prop_flags)
4649
3.58M
{
4650
3.58M
    JSShape *sh1;
4651
3.58M
    uint32_t h, h1, i, n;
4652
4653
3.58M
    h = sh->hash;
4654
3.58M
    h = shape_hash(h, atom);
4655
3.58M
    h = shape_hash(h, prop_flags);
4656
3.58M
    h1 = get_shape_hash(h, rt->shape_hash_bits);
4657
4.97M
    for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
4658
        /* we test the hash first so that the rest is done only if the
4659
           shapes really match */
4660
2.42M
        if (sh1->hash == h &&
4661
2.42M
            sh1->proto == sh->proto &&
4662
2.42M
            sh1->prop_count == ((n = sh->prop_count) + 1)) {
4663
3.95M
            for(i = 0; i < n; i++) {
4664
2.91M
                if (unlikely(sh1->prop[i].atom != sh->prop[i].atom) ||
4665
2.91M
                    unlikely(sh1->prop[i].flags != sh->prop[i].flags))
4666
0
                    goto next;
4667
2.91M
            }
4668
1.03M
            if (unlikely(sh1->prop[n].atom != atom) ||
4669
1.03M
                unlikely(sh1->prop[n].flags != prop_flags))
4670
0
                goto next;
4671
1.03M
            return sh1;
4672
1.03M
        }
4673
1.38M
    next: ;
4674
1.38M
    }
4675
2.55M
    return NULL;
4676
3.58M
}
4677
4678
static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
4679
0
{
4680
0
    char atom_buf[ATOM_GET_STR_BUF_SIZE];
4681
0
    int j;
4682
0
4683
0
    /* XXX: should output readable class prototype */
4684
0
    printf("%5d %3d%c %14p %5d %5d", i,
4685
0
           sh->header.ref_count, " *"[sh->is_hashed],
4686
0
           (void *)sh->proto, sh->prop_size, sh->prop_count);
4687
0
    for(j = 0; j < sh->prop_count; j++) {
4688
0
        printf(" %s", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf),
4689
0
                                      sh->prop[j].atom));
4690
0
    }
4691
0
    printf("\n");
4692
0
}
4693
4694
static __maybe_unused void JS_DumpShapes(JSRuntime *rt)
4695
0
{
4696
0
    int i;
4697
0
    JSShape *sh;
4698
0
    struct list_head *el;
4699
0
    JSObject *p;
4700
0
    JSGCObjectHeader *gp;
4701
0
    
4702
0
    printf("JSShapes: {\n");
4703
0
    printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS");
4704
0
    for(i = 0; i < rt->shape_hash_size; i++) {
4705
0
        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
4706
0
            JS_DumpShape(rt, i, sh);
4707
0
            assert(sh->is_hashed);
4708
0
        }
4709
0
    }
4710
0
    /* dump non-hashed shapes */
4711
0
    list_for_each(el, &rt->gc_obj_list) {
4712
0
        gp = list_entry(el, JSGCObjectHeader, link);
4713
0
        if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
4714
0
            p = (JSObject *)gp;
4715
0
            if (!p->shape->is_hashed) {
4716
0
                JS_DumpShape(rt, -1, p->shape);
4717
0
            }
4718
0
        }
4719
0
    }
4720
0
    printf("}\n");
4721
0
}
4722
4723
static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID class_id)
4724
1.34M
{
4725
1.34M
    JSObject *p;
4726
4727
1.34M
    js_trigger_gc(ctx->rt, sizeof(JSObject));
4728
1.34M
    p = js_malloc(ctx, sizeof(JSObject));
4729
1.34M
    if (unlikely(!p))
4730
0
        goto fail;
4731
1.34M
    p->class_id = class_id;
4732
1.34M
    p->extensible = TRUE;
4733
1.34M
    p->free_mark = 0;
4734
1.34M
    p->is_exotic = 0;
4735
1.34M
    p->fast_array = 0;
4736
1.34M
    p->is_constructor = 0;
4737
1.34M
    p->is_uncatchable_error = 0;
4738
1.34M
    p->tmp_mark = 0;
4739
1.34M
    p->is_HTMLDDA = 0;
4740
1.34M
    p->first_weak_ref = NULL;
4741
1.34M
    p->u.opaque = NULL;
4742
1.34M
    p->shape = sh;
4743
1.34M
    p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size);
4744
1.34M
    if (unlikely(!p->prop)) {
4745
4
        js_free(ctx, p);
4746
4
    fail:
4747
4
        js_free_shape(ctx->rt, sh);
4748
4
        return JS_EXCEPTION;
4749
4
    }
4750
4751
1.34M
    switch(class_id) {
4752
226k
    case JS_CLASS_OBJECT:
4753
226k
        break;
4754
164k
    case JS_CLASS_ARRAY:
4755
164k
        {
4756
164k
            JSProperty *pr;
4757
164k
            p->is_exotic = 1;
4758
164k
            p->fast_array = 1;
4759
164k
            p->u.array.u.values = NULL;
4760
164k
            p->u.array.count = 0;
4761
164k
            p->u.array.u1.size = 0;
4762
            /* the length property is always the first one */
4763
164k
            if (likely(sh == ctx->array_shape)) {
4764
41.5k
                pr = &p->prop[0];
4765
122k
            } else {
4766
                /* only used for the first array */
4767
                /* cannot fail */
4768
122k
                pr = add_property(ctx, p, JS_ATOM_length,
4769
122k
                                  JS_PROP_WRITABLE | JS_PROP_LENGTH);
4770
122k
            }
4771
164k
            pr->u.value = JS_NewInt32(ctx, 0);
4772
164k
        }
4773
164k
        break;
4774
198
    case JS_CLASS_C_FUNCTION:
4775
198
        p->prop[0].u.value = JS_UNDEFINED;
4776
198
        break;
4777
0
    case JS_CLASS_ARGUMENTS:
4778
0
    case JS_CLASS_UINT8C_ARRAY:
4779
0
    case JS_CLASS_INT8_ARRAY:
4780
0
    case JS_CLASS_UINT8_ARRAY:
4781
0
    case JS_CLASS_INT16_ARRAY:
4782
0
    case JS_CLASS_UINT16_ARRAY:
4783
0
    case JS_CLASS_INT32_ARRAY:
4784
0
    case JS_CLASS_UINT32_ARRAY:
4785
0
#ifdef CONFIG_BIGNUM
4786
0
    case JS_CLASS_BIG_INT64_ARRAY:
4787
0
    case JS_CLASS_BIG_UINT64_ARRAY:
4788
0
#endif
4789
0
    case JS_CLASS_FLOAT32_ARRAY:
4790
0
    case JS_CLASS_FLOAT64_ARRAY:
4791
0
        p->is_exotic = 1;
4792
0
        p->fast_array = 1;
4793
0
        p->u.array.u.ptr = NULL;
4794
0
        p->u.array.count = 0;
4795
0
        break;
4796
0
    case JS_CLASS_DATAVIEW:
4797
0
        p->u.array.u.ptr = NULL;
4798
0
        p->u.array.count = 0;
4799
0
        break;
4800
2
    case JS_CLASS_NUMBER:
4801
12
    case JS_CLASS_STRING:
4802
34
    case JS_CLASS_BOOLEAN:
4803
34
    case JS_CLASS_SYMBOL:
4804
34
    case JS_CLASS_DATE:
4805
34
#ifdef CONFIG_BIGNUM
4806
34
    case JS_CLASS_BIG_INT:
4807
34
    case JS_CLASS_BIG_FLOAT:
4808
34
    case JS_CLASS_BIG_DECIMAL:
4809
34
#endif
4810
34
        p->u.object_data = JS_UNDEFINED;
4811
34
        goto set_exotic;
4812
5
    case JS_CLASS_REGEXP:
4813
5
        p->u.regexp.pattern = NULL;
4814
5
        p->u.regexp.bytecode = NULL;
4815
5
        goto set_exotic;
4816
950k
    default:
4817
950k
    set_exotic:
4818
950k
        if (ctx->rt->class_array[class_id].exotic) {
4819
10
            p->is_exotic = 1;
4820
10
        }
4821
950k
        break;
4822
1.34M
    }
4823
1.34M
    p->header.ref_count = 1;
4824
1.34M
    add_gc_object(ctx->rt, &p->header, JS_GC_OBJ_TYPE_JS_OBJECT);
4825
1.34M
    return JS_MKPTR(JS_TAG_OBJECT, p);
4826
1.34M
}
4827
4828
static JSObject *get_proto_obj(JSValueConst proto_val)
4829
1.29M
{
4830
1.29M
    if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT)
4831
14
        return NULL;
4832
1.29M
    else
4833
1.29M
        return JS_VALUE_GET_OBJ(proto_val);
4834
1.29M
}
4835
4836
/* WARNING: proto must be an object or JS_NULL */
4837
JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto_val,
4838
                               JSClassID class_id)
4839
1.29M
{
4840
1.29M
    JSShape *sh;
4841
1.29M
    JSObject *proto;
4842
4843
1.29M
    proto = get_proto_obj(proto_val);
4844
1.29M
    sh = find_hashed_shape_proto(ctx->rt, proto);
4845
1.29M
    if (likely(sh)) {
4846
737k
        sh = js_dup_shape(sh);
4847
737k
    } else {
4848
562k
        sh = js_new_shape(ctx, proto);
4849
562k
        if (!sh)
4850
5
            return JS_EXCEPTION;
4851
562k
    }
4852
1.29M
    return JS_NewObjectFromShape(ctx, sh, class_id);
4853
1.29M
}
4854
4855
#if 0
4856
static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj)
4857
{
4858
    JSObject *p;
4859
4860
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
4861
        p = JS_VALUE_GET_OBJ(obj);
4862
        switch(p->class_id) {
4863
        case JS_CLASS_NUMBER:
4864
        case JS_CLASS_STRING:
4865
        case JS_CLASS_BOOLEAN:
4866
        case JS_CLASS_SYMBOL:
4867
        case JS_CLASS_DATE:
4868
#ifdef CONFIG_BIGNUM
4869
        case JS_CLASS_BIG_INT:
4870
        case JS_CLASS_BIG_FLOAT:
4871
        case JS_CLASS_BIG_DECIMAL:
4872
#endif
4873
            return JS_DupValue(ctx, p->u.object_data);
4874
        }
4875
    }
4876
    return JS_UNDEFINED;
4877
}
4878
#endif
4879
4880
static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val)
4881
34
{
4882
34
    JSObject *p;
4883
4884
34
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
4885
34
        p = JS_VALUE_GET_OBJ(obj);
4886
34
        switch(p->class_id) {
4887
2
        case JS_CLASS_NUMBER:
4888
12
        case JS_CLASS_STRING:
4889
34
        case JS_CLASS_BOOLEAN:
4890
34
        case JS_CLASS_SYMBOL:
4891
34
        case JS_CLASS_DATE:
4892
34
#ifdef CONFIG_BIGNUM
4893
34
        case JS_CLASS_BIG_INT:
4894
34
        case JS_CLASS_BIG_FLOAT:
4895
34
        case JS_CLASS_BIG_DECIMAL:
4896
34
#endif
4897
34
            JS_FreeValue(ctx, p->u.object_data);
4898
34
            p->u.object_data = val;
4899
34
            return 0;
4900
34
        }
4901
34
    }
4902
0
    JS_FreeValue(ctx, val);
4903
0
    if (!JS_IsException(obj))
4904
0
        JS_ThrowTypeError(ctx, "invalid object type");
4905
0
    return -1;
4906
34
}
4907
4908
JSValue JS_NewObjectClass(JSContext *ctx, int class_id)
4909
457k
{
4910
457k
    return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id);
4911
457k
}
4912
4913
JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto)
4914
82.4k
{
4915
82.4k
    return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT);
4916
82.4k
}
4917
4918
JSValue JS_NewArray(JSContext *ctx)
4919
41.5k
{
4920
41.5k
    return JS_NewObjectFromShape(ctx, js_dup_shape(ctx->array_shape),
4921
41.5k
                                 JS_CLASS_ARRAY);
4922
41.5k
}
4923
4924
JSValue JS_NewObject(JSContext *ctx)
4925
144k
{
4926
    /* inline JS_NewObjectClass(ctx, JS_CLASS_OBJECT); */
4927
144k
    return JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT);
4928
144k
}
4929
4930
static void js_function_set_properties(JSContext *ctx, JSValueConst func_obj,
4931
                                       JSAtom name, int len)
4932
703k
{
4933
    /* ES6 feature non compatible with ES5.1: length is configurable */
4934
703k
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, JS_NewInt32(ctx, len),
4935
703k
                           JS_PROP_CONFIGURABLE);
4936
703k
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name,
4937
703k
                           JS_AtomToString(ctx, name), JS_PROP_CONFIGURABLE);
4938
703k
}
4939
4940
static BOOL js_class_has_bytecode(JSClassID class_id)
4941
621k
{
4942
621k
    return (class_id == JS_CLASS_BYTECODE_FUNCTION ||
4943
621k
            class_id == JS_CLASS_GENERATOR_FUNCTION ||
4944
621k
            class_id == JS_CLASS_ASYNC_FUNCTION ||
4945
621k
            class_id == JS_CLASS_ASYNC_GENERATOR_FUNCTION);
4946
621k
}
4947
4948
/* return NULL without exception if not a function or no bytecode */
4949
static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val)
4950
122k
{
4951
122k
    JSObject *p;
4952
122k
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
4953
0
        return NULL;
4954
122k
    p = JS_VALUE_GET_OBJ(val);
4955
122k
    if (!js_class_has_bytecode(p->class_id))
4956
0
        return NULL;
4957
122k
    return p->u.func.function_bytecode;
4958
122k
}
4959
4960
static void js_method_set_home_object(JSContext *ctx, JSValueConst func_obj,
4961
                                      JSValueConst home_obj)
4962
129k
{
4963
129k
    JSObject *p, *p1;
4964
129k
    JSFunctionBytecode *b;
4965
4966
129k
    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
4967
0
        return;
4968
129k
    p = JS_VALUE_GET_OBJ(func_obj);
4969
129k
    if (!js_class_has_bytecode(p->class_id))
4970
0
        return;
4971
129k
    b = p->u.func.function_bytecode;
4972
129k
    if (b->need_home_object) {
4973
41.3k
        p1 = p->u.func.home_object;
4974
41.3k
        if (p1) {
4975
0
            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
4976
0
        }
4977
41.3k
        if (JS_VALUE_GET_TAG(home_obj) == JS_TAG_OBJECT)
4978
41.3k
            p1 = JS_VALUE_GET_OBJ(JS_DupValue(ctx, home_obj));
4979
0
        else
4980
0
            p1 = NULL;
4981
41.3k
        p->u.func.home_object = p1;
4982
41.3k
    }
4983
129k
}
4984
4985
static JSValue js_get_function_name(JSContext *ctx, JSAtom name)
4986
46.8k
{
4987
46.8k
    JSValue name_str;
4988
4989
46.8k
    name_str = JS_AtomToString(ctx, name);
4990
46.8k
    if (JS_AtomSymbolHasDescription(ctx, name)) {
4991
0
        name_str = JS_ConcatString3(ctx, "[", name_str, "]");
4992
0
    }
4993
46.8k
    return name_str;
4994
46.8k
}
4995
4996
/* Modify the name of a method according to the atom and
4997
   'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and
4998
   JS_PROP_HAS_SET. Also set the home object of the method.
4999
   Return < 0 if exception. */
5000
static int js_method_set_properties(JSContext *ctx, JSValueConst func_obj,
5001
                                    JSAtom name, int flags, JSValueConst home_obj)
5002
46.8k
{
5003
46.8k
    JSValue name_str;
5004
5005
46.8k
    name_str = js_get_function_name(ctx, name);
5006
46.8k
    if (flags & JS_PROP_HAS_GET) {
5007
0
        name_str = JS_ConcatString3(ctx, "get ", name_str, "");
5008
46.8k
    } else if (flags & JS_PROP_HAS_SET) {
5009
0
        name_str = JS_ConcatString3(ctx, "set ", name_str, "");
5010
0
    }
5011
46.8k
    if (JS_IsException(name_str))
5012
0
        return -1;
5013
46.8k
    if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name_str,
5014
46.8k
                               JS_PROP_CONFIGURABLE) < 0)
5015
0
        return -1;
5016
46.8k
    js_method_set_home_object(ctx, func_obj, home_obj);
5017
46.8k
    return 0;
5018
46.8k
}
5019
5020
/* Note: at least 'length' arguments will be readable in 'argv' */
5021
static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
5022
                                const char *name,
5023
                                int length, JSCFunctionEnum cproto, int magic,
5024
                                JSValueConst proto_val)
5025
198
{
5026
198
    JSValue func_obj;
5027
198
    JSObject *p;
5028
198
    JSAtom name_atom;
5029
    
5030
198
    func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION);
5031
198
    if (JS_IsException(func_obj))
5032
0
        return func_obj;
5033
198
    p = JS_VALUE_GET_OBJ(func_obj);
5034
198
    p->u.cfunc.realm = JS_DupContext(ctx);
5035
198
    p->u.cfunc.c_function.generic = func;
5036
198
    p->u.cfunc.length = length;
5037
198
    p->u.cfunc.cproto = cproto;
5038
198
    p->u.cfunc.magic = magic;
5039
198
    p->is_constructor = (cproto == JS_CFUNC_constructor ||
5040
198
                         cproto == JS_CFUNC_constructor_magic ||
5041
198
                         cproto == JS_CFUNC_constructor_or_func ||
5042
198
                         cproto == JS_CFUNC_constructor_or_func_magic);
5043
198
    if (!name)
5044
4
        name = "";
5045
198
    name_atom = JS_NewAtom(ctx, name);
5046
198
    js_function_set_properties(ctx, func_obj, name_atom, length);
5047
198
    JS_FreeAtom(ctx, name_atom);
5048
198
    return func_obj;
5049
198
}
5050
5051
/* Note: at least 'length' arguments will be readable in 'argv' */
5052
JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
5053
                         const char *name,
5054
                         int length, JSCFunctionEnum cproto, int magic)
5055
153
{
5056
153
    return JS_NewCFunction3(ctx, func, name, length, cproto, magic,
5057
153
                            ctx->function_proto);
5058
153
}
5059
5060
typedef struct JSCFunctionDataRecord {
5061
    JSCFunctionData *func;
5062
    uint8_t length;
5063
    uint8_t data_len;
5064
    uint16_t magic;
5065
    JSValue data[0];
5066
} JSCFunctionDataRecord;
5067
5068
static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val)
5069
81.9k
{
5070
81.9k
    JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
5071
81.9k
    int i;
5072
5073
81.9k
    if (s) {
5074
245k
        for(i = 0; i < s->data_len; i++) {
5075
163k
            JS_FreeValueRT(rt, s->data[i]);
5076
163k
        }
5077
81.9k
        js_free_rt(rt, s);
5078
81.9k
    }
5079
81.9k
}
5080
5081
static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
5082
                                    JS_MarkFunc *mark_func)
5083
10
{
5084
10
    JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
5085
10
    int i;
5086
5087
10
    if (s) {
5088
30
        for(i = 0; i < s->data_len; i++) {
5089
20
            JS_MarkValue(rt, s->data[i], mark_func);
5090
20
        }
5091
10
    }
5092
10
}
5093
5094
static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
5095
                                       JSValueConst this_val,
5096
                                       int argc, JSValueConst *argv, int flags)
5097
81.9k
{
5098
81.9k
    JSCFunctionDataRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA);
5099
81.9k
    JSValueConst *arg_buf;
5100
81.9k
    int i;
5101
5102
    /* XXX: could add the function on the stack for debug */
5103
81.9k
    if (unlikely(argc < s->length)) {
5104
0
        arg_buf = alloca(sizeof(arg_buf[0]) * s->length);
5105
0
        for(i = 0; i < argc; i++)
5106
0
            arg_buf[i] = argv[i];
5107
0
        for(i = argc; i < s->length; i++)
5108
0
            arg_buf[i] = JS_UNDEFINED;
5109
81.9k
    } else {
5110
81.9k
        arg_buf = argv;
5111
81.9k
    }
5112
5113
81.9k
    return s->func(ctx, this_val, argc, arg_buf, s->magic, s->data);
5114
81.9k
}
5115
5116
JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
5117
                            int length, int magic, int data_len,
5118
                            JSValueConst *data)
5119
81.9k
{
5120
81.9k
    JSCFunctionDataRecord *s;
5121
81.9k
    JSValue func_obj;
5122
81.9k
    int i;
5123
5124
81.9k
    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
5125
81.9k
                                      JS_CLASS_C_FUNCTION_DATA);
5126
81.9k
    if (JS_IsException(func_obj))
5127
0
        return func_obj;
5128
81.9k
    s = js_malloc(ctx, sizeof(*s) + data_len * sizeof(JSValue));
5129
81.9k
    if (!s) {
5130
0
        JS_FreeValue(ctx, func_obj);
5131
0
        return JS_EXCEPTION;
5132
0
    }
5133
81.9k
    s->func = func;
5134
81.9k
    s->length = length;
5135
81.9k
    s->data_len = data_len;
5136
81.9k
    s->magic = magic;
5137
245k
    for(i = 0; i < data_len; i++)
5138
163k
        s->data[i] = JS_DupValue(ctx, data[i]);
5139
81.9k
    JS_SetOpaque(func_obj, s);
5140
81.9k
    js_function_set_properties(ctx, func_obj,
5141
81.9k
                               JS_ATOM_empty_string, length);
5142
81.9k
    return func_obj;
5143
81.9k
}
5144
5145
static JSContext *js_autoinit_get_realm(JSProperty *pr)
5146
16.2k
{
5147
16.2k
    return (JSContext *)(pr->u.init.realm_and_id & ~3);
5148
16.2k
}
5149
5150
static JSAutoInitIDEnum js_autoinit_get_id(JSProperty *pr)
5151
31
{
5152
31
    return pr->u.init.realm_and_id & 3;
5153
31
}
5154
5155
static void js_autoinit_free(JSRuntime *rt, JSProperty *pr)
5156
812
{
5157
812
    JS_FreeContext(js_autoinit_get_realm(pr));
5158
812
}
5159
5160
static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr,
5161
                             JS_MarkFunc *mark_func)
5162
15.4k
{
5163
15.4k
    mark_func(rt, &js_autoinit_get_realm(pr)->header);
5164
15.4k
}
5165
5166
static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags)
5167
3.05M
{
5168
3.05M
    if (unlikely(prop_flags & JS_PROP_TMASK)) {
5169
783
        if ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
5170
0
            if (pr->u.getset.getter)
5171
0
                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
5172
0
            if (pr->u.getset.setter)
5173
0
                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
5174
783
        } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
5175
2
            free_var_ref(rt, pr->u.var_ref);
5176
781
        } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
5177
781
            js_autoinit_free(rt, pr);
5178
781
        }
5179
3.05M
    } else {
5180
3.05M
        JS_FreeValueRT(rt, pr->u.value);
5181
3.05M
    }
5182
3.05M
}
5183
5184
static force_inline JSShapeProperty *find_own_property1(JSObject *p,
5185
                                                        JSAtom atom)
5186
168k
{
5187
168k
    JSShape *sh;
5188
168k
    JSShapeProperty *pr, *prop;
5189
168k
    intptr_t h;
5190
168k
    sh = p->shape;
5191
168k
    h = (uintptr_t)atom & sh->prop_hash_mask;
5192
168k
    h = prop_hash_end(sh)[-h - 1];
5193
168k
    prop = get_shape_prop(sh);
5194
169k
    while (h) {
5195
44.6k
        pr = &prop[h - 1];
5196
44.6k
        if (likely(pr->atom == atom)) {
5197
43.1k
            return pr;
5198
43.1k
        }
5199
1.52k
        h = pr->hash_next;
5200
1.52k
    }
5201
124k
    return NULL;
5202
168k
}
5203
5204
static force_inline JSShapeProperty *find_own_property(JSProperty **ppr,
5205
                                                       JSObject *p,
5206
                                                       JSAtom atom)
5207
10.2M
{
5208
10.2M
    JSShape *sh;
5209
10.2M
    JSShapeProperty *pr, *prop;
5210
10.2M
    intptr_t h;
5211
10.2M
    sh = p->shape;
5212
10.2M
    h = (uintptr_t)atom & sh->prop_hash_mask;
5213
10.2M
    h = prop_hash_end(sh)[-h - 1];
5214
10.2M
    prop = get_shape_prop(sh);
5215
11.3M
    while (h) {
5216
3.96M
        pr = &prop[h - 1];
5217
3.96M
        if (likely(pr->atom == atom)) {
5218
2.78M
            *ppr = &p->prop[h - 1];
5219
            /* the compiler should be able to assume that pr != NULL here */
5220
2.78M
            return pr;
5221
2.78M
        }
5222
1.17M
        h = pr->hash_next;
5223
1.17M
    }
5224
7.43M
    *ppr = NULL;
5225
7.43M
    return NULL;
5226
10.2M
}
5227
5228
/* indicate that the object may be part of a function prototype cycle */
5229
static void set_cycle_flag(JSContext *ctx, JSValueConst obj)
5230
82.8k
{
5231
82.8k
}
5232
5233
static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref)
5234
8.24M
{
5235
8.24M
    if (var_ref) {
5236
8.24M
        assert(var_ref->header.ref_count > 0);
5237
8.24M
        if (--var_ref->header.ref_count == 0) {
5238
160k
            if (var_ref->is_detached) {
5239
160k
                JS_FreeValueRT(rt, var_ref->value);
5240
160k
                remove_gc_object(&var_ref->header);
5241
160k
            } else {
5242
60
                list_del(&var_ref->header.link); /* still on the stack */
5243
60
            }
5244
160k
            js_free_rt(rt, var_ref);
5245
160k
        }
5246
8.24M
    }
5247
8.24M
}
5248
5249
static void js_array_finalizer(JSRuntime *rt, JSValue val)
5250
164k
{
5251
164k
    JSObject *p = JS_VALUE_GET_OBJ(val);
5252
164k
    int i;
5253
5254
317k
    for(i = 0; i < p->u.array.count; i++) {
5255
152k
        JS_FreeValueRT(rt, p->u.array.u.values[i]);
5256
152k
    }
5257
164k
    js_free_rt(rt, p->u.array.u.values);
5258
164k
}
5259
5260
static void js_array_mark(JSRuntime *rt, JSValueConst val,
5261
                          JS_MarkFunc *mark_func)
5262
132
{
5263
132
    JSObject *p = JS_VALUE_GET_OBJ(val);
5264
132
    int i;
5265
5266
105k
    for(i = 0; i < p->u.array.count; i++) {
5267
105k
        JS_MarkValue(rt, p->u.array.u.values[i], mark_func);
5268
105k
    }
5269
132
}
5270
5271
static void js_object_data_finalizer(JSRuntime *rt, JSValue val)
5272
28
{
5273
28
    JSObject *p = JS_VALUE_GET_OBJ(val);
5274
28
    JS_FreeValueRT(rt, p->u.object_data);
5275
28
    p->u.object_data = JS_UNDEFINED;
5276
28
}
5277
5278
static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
5279
                                JS_MarkFunc *mark_func)
5280
138
{
5281
138
    JSObject *p = JS_VALUE_GET_OBJ(val);
5282
138
    JS_MarkValue(rt, p->u.object_data, mark_func);
5283
138
}
5284
5285
static void js_c_function_finalizer(JSRuntime *rt, JSValue val)
5286
0
{
5287
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5288
5289
0
    if (p->u.cfunc.realm)
5290
0
        JS_FreeContext(p->u.cfunc.realm);
5291
0
}
5292
5293
static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
5294
                               JS_MarkFunc *mark_func)
5295
4.42k
{
5296
4.42k
    JSObject *p = JS_VALUE_GET_OBJ(val);
5297
5298
4.42k
    if (p->u.cfunc.realm)
5299
4.42k
        mark_func(rt, &p->u.cfunc.realm->header);
5300
4.42k
}
5301
5302
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val)
5303
476k
{
5304
476k
    JSObject *p1, *p = JS_VALUE_GET_OBJ(val);
5305
476k
    JSFunctionBytecode *b;
5306
476k
    JSVarRef **var_refs;
5307
476k
    int i;
5308
5309
476k
    p1 = p->u.func.home_object;
5310
476k
    if (p1) {
5311
33.8k
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, p1));
5312
33.8k
    }
5313
476k
    b = p->u.func.function_bytecode;
5314
476k
    if (b) {
5315
476k
        var_refs = p->u.func.var_refs;
5316
476k
        if (var_refs) {
5317
8.42M
            for(i = 0; i < b->closure_var_count; i++)
5318
8.24M
                free_var_ref(rt, var_refs[i]);
5319
183k
            js_free_rt(rt, var_refs);
5320
183k
        }
5321
476k
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b));
5322
476k
    }
5323
476k
}
5324
5325
static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
5326
                                      JS_MarkFunc *mark_func)
5327
203k
{
5328
203k
    JSObject *p = JS_VALUE_GET_OBJ(val);
5329
203k
    JSVarRef **var_refs = p->u.func.var_refs;
5330
203k
    JSFunctionBytecode *b = p->u.func.function_bytecode;
5331
203k
    int i;
5332
5333
203k
    if (p->u.func.home_object) {
5334
67.7k
        JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object),
5335
67.7k
                     mark_func);
5336
67.7k
    }
5337
203k
    if (b) {
5338
203k
        if (var_refs) {
5339
5.21M
            for(i = 0; i < b->closure_var_count; i++) {
5340
5.01M
                JSVarRef *var_ref = var_refs[i];
5341
5.01M
                if (var_ref && var_ref->is_detached) {
5342
4.81M
                    mark_func(rt, &var_ref->header);
5343
4.81M
                }
5344
5.01M
            }
5345
202k
        }
5346
        /* must mark the function bytecode because template objects may be
5347
           part of a cycle */
5348
203k
        JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func);
5349
203k
    }
5350
203k
}
5351
5352
static void js_bound_function_finalizer(JSRuntime *rt, JSValue val)
5353
0
{
5354
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5355
0
    JSBoundFunction *bf = p->u.bound_function;
5356
0
    int i;
5357
5358
0
    JS_FreeValueRT(rt, bf->func_obj);
5359
0
    JS_FreeValueRT(rt, bf->this_val);
5360
0
    for(i = 0; i < bf->argc; i++) {
5361
0
        JS_FreeValueRT(rt, bf->argv[i]);
5362
0
    }
5363
0
    js_free_rt(rt, bf);
5364
0
}
5365
5366
static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
5367
                                JS_MarkFunc *mark_func)
5368
0
{
5369
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5370
0
    JSBoundFunction *bf = p->u.bound_function;
5371
0
    int i;
5372
5373
0
    JS_MarkValue(rt, bf->func_obj, mark_func);
5374
0
    JS_MarkValue(rt, bf->this_val, mark_func);
5375
0
    for(i = 0; i < bf->argc; i++)
5376
0
        JS_MarkValue(rt, bf->argv[i], mark_func);
5377
0
}
5378
5379
static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val)
5380
3
{
5381
3
    JSObject *p = JS_VALUE_GET_OBJ(val);
5382
3
    JSForInIterator *it = p->u.for_in_iterator;
5383
3
    JS_FreeValueRT(rt, it->obj);
5384
3
    js_free_rt(rt, it);
5385
3
}
5386
5387
static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
5388
                                JS_MarkFunc *mark_func)
5389
0
{
5390
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5391
0
    JSForInIterator *it = p->u.for_in_iterator;
5392
0
    JS_MarkValue(rt, it->obj, mark_func);
5393
0
}
5394
5395
static void free_object(JSRuntime *rt, JSObject *p)
5396
1.06M
{
5397
1.06M
    int i;
5398
1.06M
    JSClassFinalizer *finalizer;
5399
1.06M
    JSShape *sh;
5400
1.06M
    JSShapeProperty *pr;
5401
5402
1.06M
    p->free_mark = 1; /* used to tell the object is invalid when
5403
                         freeing cycles */
5404
    /* free all the fields */
5405
1.06M
    sh = p->shape;
5406
1.06M
    pr = get_shape_prop(sh);
5407
4.11M
    for(i = 0; i < sh->prop_count; i++) {
5408
3.05M
        free_property(rt, &p->prop[i], pr->flags);
5409
3.05M
        pr++;
5410
3.05M
    }
5411
1.06M
    js_free_rt(rt, p->prop);
5412
    /* as an optimization we destroy the shape immediately without
5413
       putting it in gc_zero_ref_count_list */
5414
1.06M
    js_free_shape(rt, sh);
5415
5416
    /* fail safe */
5417
1.06M
    p->shape = NULL;
5418
1.06M
    p->prop = NULL;
5419
5420
1.06M
    if (unlikely(p->first_weak_ref)) {
5421
0
        reset_weak_ref(rt, p);
5422
0
    }
5423
5424
1.06M
    finalizer = rt->class_array[p->class_id].finalizer;
5425
1.06M
    if (finalizer)
5426
723k
        (*finalizer)(rt, JS_MKPTR(JS_TAG_OBJECT, p));
5427
5428
    /* fail safe */
5429
1.06M
    p->class_id = 0;
5430
1.06M
    p->u.opaque = NULL;
5431
1.06M
    p->u.func.var_refs = NULL;
5432
1.06M
    p->u.func.home_object = NULL;
5433
5434
1.06M
    remove_gc_object(&p->header);
5435
1.06M
    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && p->header.ref_count != 0) {
5436
68.0k
        list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list);
5437
997k
    } else {
5438
997k
        js_free_rt(rt, p);
5439
997k
    }
5440
1.06M
}
5441
5442
static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp)
5443
1.11M
{
5444
1.11M
    switch(gp->gc_obj_type) {
5445
1.06M
    case JS_GC_OBJ_TYPE_JS_OBJECT:
5446
1.06M
        free_object(rt, (JSObject *)gp);
5447
1.06M
        break;
5448
45.6k
    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
5449
45.6k
        free_function_bytecode(rt, (JSFunctionBytecode *)gp);
5450
45.6k
        break;
5451
0
    default:
5452
0
        abort();
5453
1.11M
    }
5454
1.11M
}
5455
5456
static void free_zero_refcount(JSRuntime *rt)
5457
888k
{
5458
888k
    struct list_head *el;
5459
888k
    JSGCObjectHeader *p;
5460
    
5461
888k
    rt->gc_phase = JS_GC_PHASE_DECREF;
5462
1.86M
    for(;;) {
5463
1.86M
        el = rt->gc_zero_ref_count_list.next;
5464
1.86M
        if (el == &rt->gc_zero_ref_count_list)
5465
888k
            break;
5466
975k
        p = list_entry(el, JSGCObjectHeader, link);
5467
975k
        assert(p->ref_count == 0);
5468
975k
        free_gc_object(rt, p);
5469
975k
    }
5470
888k
    rt->gc_phase = JS_GC_PHASE_NONE;
5471
888k
}
5472
5473
/* called with the ref_count of 'v' reaches zero. */
5474
void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
5475
2.16M
{
5476
2.16M
    uint32_t tag = JS_VALUE_GET_TAG(v);
5477
5478
#ifdef DUMP_FREE
5479
    {
5480
        printf("Freeing ");
5481
        if (tag == JS_TAG_OBJECT) {
5482
            JS_DumpObject(rt, JS_VALUE_GET_OBJ(v));
5483
        } else {
5484
            JS_DumpValueShort(rt, v);
5485
            printf("\n");
5486
        }
5487
    }
5488
#endif
5489
5490
2.16M
    switch(tag) {
5491
1.02M
    case JS_TAG_STRING:
5492
1.02M
        {
5493
1.02M
            JSString *p = JS_VALUE_GET_STRING(v);
5494
1.02M
            if (p->atom_type) {
5495
4
                JS_FreeAtomStruct(rt, p);
5496
1.02M
            } else {
5497
#ifdef DUMP_LEAKS
5498
                list_del(&p->link);
5499
#endif
5500
1.02M
                js_free_rt(rt, p);
5501
1.02M
            }
5502
1.02M
        }
5503
1.02M
        break;
5504
1.06M
    case JS_TAG_OBJECT:
5505
1.11M
    case JS_TAG_FUNCTION_BYTECODE:
5506
1.11M
        {
5507
1.11M
            JSGCObjectHeader *p = JS_VALUE_GET_PTR(v);
5508
1.11M
            if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
5509
975k
                list_del(&p->link);
5510
975k
                list_add(&p->link, &rt->gc_zero_ref_count_list);
5511
975k
                if (rt->gc_phase == JS_GC_PHASE_NONE) {
5512
888k
                    free_zero_refcount(rt);
5513
888k
                }
5514
975k
            }
5515
1.11M
        }
5516
1.11M
        break;
5517
0
    case JS_TAG_MODULE:
5518
0
        abort(); /* never freed here */
5519
0
        break;
5520
0
#ifdef CONFIG_BIGNUM
5521
996
    case JS_TAG_BIG_INT:
5522
996
    case JS_TAG_BIG_FLOAT:
5523
996
        {
5524
996
            JSBigFloat *bf = JS_VALUE_GET_PTR(v);
5525
996
            bf_delete(&bf->num);
5526
996
            js_free_rt(rt, bf);
5527
996
        }
5528
996
        break;
5529
0
    case JS_TAG_BIG_DECIMAL:
5530
0
        {
5531
0
            JSBigDecimal *bf = JS_VALUE_GET_PTR(v);
5532
0
            bfdec_delete(&bf->num);
5533
0
            js_free_rt(rt, bf);
5534
0
        }
5535
0
        break;
5536
0
#endif
5537
33.8k
    case JS_TAG_SYMBOL:
5538
33.8k
        {
5539
33.8k
            JSAtomStruct *p = JS_VALUE_GET_PTR(v);
5540
33.8k
            JS_FreeAtomStruct(rt, p);
5541
33.8k
        }
5542
33.8k
        break;
5543
0
    default:
5544
0
        printf("__JS_FreeValue: unknown tag=%d\n", tag);
5545
0
        abort();
5546
2.16M
    }
5547
2.16M
}
5548
5549
void __JS_FreeValue(JSContext *ctx, JSValue v)
5550
1.23M
{
5551
1.23M
    __JS_FreeValueRT(ctx->rt, v);
5552
1.23M
}
5553
5554
/* garbage collection */
5555
5556
static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
5557
                          JSGCObjectTypeEnum type)
5558
2.79M
{
5559
2.79M
    h->mark = 0;
5560
2.79M
    h->gc_obj_type = type;
5561
2.79M
    list_add_tail(&h->link, &rt->gc_obj_list);
5562
2.79M
}
5563
5564
static void remove_gc_object(JSGCObjectHeader *h)
5565
2.48M
{
5566
2.48M
    list_del(&h->link);
5567
2.48M
}
5568
5569
void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
5570
7.18M
{
5571
7.18M
    if (JS_VALUE_HAS_REF_COUNT(val)) {
5572
4.96M
        switch(JS_VALUE_GET_TAG(val)) {
5573
1.68M
        case JS_TAG_OBJECT:
5574
1.88M
        case JS_TAG_FUNCTION_BYTECODE:
5575
1.88M
            mark_func(rt, JS_VALUE_GET_PTR(val));
5576
1.88M
            break;
5577
3.07M
        default:
5578
3.07M
            break;
5579
4.96M
        }
5580
4.96M
    }
5581
7.18M
}
5582
5583
static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
5584
                          JS_MarkFunc *mark_func)
5585
2.60M
{
5586
2.60M
    switch(gp->gc_obj_type) {
5587
2.27M
    case JS_GC_OBJ_TYPE_JS_OBJECT:
5588
2.27M
        {
5589
2.27M
            JSObject *p = (JSObject *)gp;
5590
2.27M
            JSShapeProperty *prs;
5591
2.27M
            JSShape *sh;
5592
2.27M
            int i;
5593
2.27M
            sh = p->shape;
5594
2.27M
            mark_func(rt, &sh->header);
5595
            /* mark all the fields */
5596
2.27M
            prs = get_shape_prop(sh);
5597
6.77M
            for(i = 0; i < sh->prop_count; i++) {
5598
4.49M
                JSProperty *pr = &p->prop[i];
5599
4.49M
                if (prs->atom != JS_ATOM_NULL) {
5600
4.49M
                    if (prs->flags & JS_PROP_TMASK) {
5601
17.0k
                        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
5602
1.56k
                            if (pr->u.getset.getter)
5603
1.56k
                                mark_func(rt, &pr->u.getset.getter->header);
5604
1.56k
                            if (pr->u.getset.setter)
5605
138
                                mark_func(rt, &pr->u.getset.setter->header);
5606
15.4k
                        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
5607
0
                            if (pr->u.var_ref->is_detached) {
5608
                                /* Note: the tag does not matter
5609
                                   provided it is a GC object */
5610
0
                                mark_func(rt, &pr->u.var_ref->header);
5611
0
                            }
5612
15.4k
                        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
5613
15.4k
                            js_autoinit_mark(rt, pr, mark_func);
5614
15.4k
                        }
5615
4.47M
                    } else {
5616
4.47M
                        JS_MarkValue(rt, pr->u.value, mark_func);
5617
4.47M
                    }
5618
4.49M
                }
5619
4.49M
                prs++;
5620
4.49M
            }
5621
5622
2.27M
            if (p->class_id != JS_CLASS_OBJECT) {
5623
2.20M
                JSClassGCMark *gc_mark;
5624
2.20M
                gc_mark = rt->class_array[p->class_id].gc_mark;
5625
2.20M
                if (gc_mark)
5626
2.20M
                    gc_mark(rt, JS_MKPTR(JS_TAG_OBJECT, p), mark_func);
5627
2.20M
            }
5628
2.27M
        }
5629
2.27M
        break;
5630
820
    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
5631
        /* the template objects can be part of a cycle */
5632
820
        {
5633
820
            JSFunctionBytecode *b = (JSFunctionBytecode *)gp;
5634
820
            int i;
5635
4.49k
            for(i = 0; i < b->cpool_count; i++) {
5636
3.67k
                JS_MarkValue(rt, b->cpool[i], mark_func);
5637
3.67k
            }
5638
820
            if (b->realm)
5639
820
                mark_func(rt, &b->realm->header);
5640
820
        }
5641
820
        break;
5642
321k
    case JS_GC_OBJ_TYPE_VAR_REF:
5643
321k
        {
5644
321k
            JSVarRef *var_ref = (JSVarRef *)gp;
5645
            /* only detached variable referenced are taken into account */
5646
321k
            assert(var_ref->is_detached);
5647
321k
            JS_MarkValue(rt, *var_ref->pvalue, mark_func);
5648
321k
        }
5649
0
        break;
5650
0
    case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
5651
0
        {
5652
0
            JSAsyncFunctionData *s = (JSAsyncFunctionData *)gp;
5653
0
            if (s->is_active)
5654
0
                async_func_mark(rt, &s->func_state, mark_func);
5655
0
            JS_MarkValue(rt, s->resolving_funcs[0], mark_func);
5656
0
            JS_MarkValue(rt, s->resolving_funcs[1], mark_func);
5657
0
        }
5658
0
        break;
5659
2.66k
    case JS_GC_OBJ_TYPE_SHAPE:
5660
2.66k
        {
5661
2.66k
            JSShape *sh = (JSShape *)gp;
5662
2.66k
            if (sh->proto != NULL) {
5663
2.49k
                mark_func(rt, &sh->proto->header);
5664
2.49k
            }
5665
2.66k
        }
5666
2.66k
        break;
5667
46
    case JS_GC_OBJ_TYPE_JS_CONTEXT:
5668
46
        {
5669
46
            JSContext *ctx = (JSContext *)gp;
5670
46
            JS_MarkContext(rt, ctx, mark_func);
5671
46
        }
5672
46
        break;
5673
0
    default:
5674
0
        abort();
5675
2.60M
    }
5676
2.60M
}
5677
5678
static void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p)
5679
4.50M
{
5680
4.50M
    assert(p->ref_count > 0);
5681
4.50M
    p->ref_count--;
5682
4.50M
    if (p->ref_count == 0 && p->mark == 1) {
5683
170k
        list_del(&p->link);
5684
170k
        list_add_tail(&p->link, &rt->tmp_obj_list);
5685
170k
    }
5686
4.50M
}
5687
5688
static void gc_decref(JSRuntime *rt)
5689
23
{
5690
23
    struct list_head *el, *el1;
5691
23
    JSGCObjectHeader *p;
5692
    
5693
23
    init_list_head(&rt->tmp_obj_list);
5694
5695
    /* decrement the refcount of all the children of all the GC
5696
       objects and move the GC objects with zero refcount to
5697
       tmp_obj_list */
5698
1.30M
    list_for_each_safe(el, el1, &rt->gc_obj_list) {
5699
1.30M
        p = list_entry(el, JSGCObjectHeader, link);
5700
1.30M
        assert(p->mark == 0);
5701
1.30M
        mark_children(rt, p, gc_decref_child);
5702
1.30M
        p->mark = 1;
5703
1.30M
        if (p->ref_count == 0) {
5704
464k
            list_del(&p->link);
5705
464k
            list_add_tail(&p->link, &rt->tmp_obj_list);
5706
464k
        }
5707
1.30M
    }
5708
23
}
5709
5710
static void gc_scan_incref_child(JSRuntime *rt, JSGCObjectHeader *p)
5711
1.69M
{
5712
1.69M
    p->ref_count++;
5713
1.69M
    if (p->ref_count == 1) {
5714
        /* ref_count was 0: remove from tmp_obj_list and add at the
5715
           end of gc_obj_list */
5716
340k
        list_del(&p->link);
5717
340k
        list_add_tail(&p->link, &rt->gc_obj_list);
5718
340k
        p->mark = 0; /* reset the mark for the next GC call */
5719
340k
    }
5720
1.69M
}
5721
5722
static void gc_scan_incref_child2(JSRuntime *rt, JSGCObjectHeader *p)
5723
2.81M
{
5724
2.81M
    p->ref_count++;
5725
2.81M
}
5726
5727
static void gc_scan(JSRuntime *rt)
5728
23
{
5729
23
    struct list_head *el;
5730
23
    JSGCObjectHeader *p;
5731
5732
    /* keep the objects with a refcount > 0 and their children. */
5733
1.00M
    list_for_each(el, &rt->gc_obj_list) {
5734
1.00M
        p = list_entry(el, JSGCObjectHeader, link);
5735
1.00M
        assert(p->ref_count > 0);
5736
1.00M
        p->mark = 0; /* reset the mark for the next GC call */
5737
1.00M
        mark_children(rt, p, gc_scan_incref_child);
5738
1.00M
    }
5739
    
5740
    /* restore the refcount of the objects to be deleted. */
5741
295k
    list_for_each(el, &rt->tmp_obj_list) {
5742
295k
        p = list_entry(el, JSGCObjectHeader, link);
5743
295k
        mark_children(rt, p, gc_scan_incref_child2);
5744
295k
    }
5745
23
}
5746
5747
static void gc_free_cycles(JSRuntime *rt)
5748
23
{
5749
23
    struct list_head *el, *el1;
5750
23
    JSGCObjectHeader *p;
5751
#ifdef DUMP_GC_FREE
5752
    BOOL header_done = FALSE;
5753
#endif
5754
5755
23
    rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES;
5756
5757
168k
    for(;;) {
5758
168k
        el = rt->tmp_obj_list.next;
5759
168k
        if (el == &rt->tmp_obj_list)
5760
23
            break;
5761
168k
        p = list_entry(el, JSGCObjectHeader, link);
5762
        /* Only need to free the GC object associated with JS
5763
           values. The rest will be automatically removed because they
5764
           must be referenced by them. */
5765
168k
        switch(p->gc_obj_type) {
5766
135k
        case JS_GC_OBJ_TYPE_JS_OBJECT:
5767
135k
        case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
5768
#ifdef DUMP_GC_FREE
5769
            if (!header_done) {
5770
                printf("Freeing cycles:\n");
5771
                JS_DumpObjectHeader(rt);
5772
                header_done = TRUE;
5773
            }
5774
            JS_DumpGCObject(rt, p);
5775
#endif
5776
135k
            free_gc_object(rt, p);
5777
135k
            break;
5778
33.5k
        default:
5779
33.5k
            list_del(&p->link);
5780
33.5k
            list_add_tail(&p->link, &rt->gc_zero_ref_count_list);
5781
33.5k
            break;
5782
168k
        }
5783
168k
    }
5784
23
    rt->gc_phase = JS_GC_PHASE_NONE;
5785
           
5786
68.0k
    list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) {
5787
68.0k
        p = list_entry(el, JSGCObjectHeader, link);
5788
68.0k
        assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT ||
5789
68.0k
               p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
5790
68.0k
        js_free_rt(rt, p);
5791
68.0k
    }
5792
5793
23
    init_list_head(&rt->gc_zero_ref_count_list);
5794
23
}
5795
5796
void JS_RunGC(JSRuntime *rt)
5797
23
{
5798
    /* decrement the reference of the children of each object. mark =
5799
       1 after this pass. */
5800
23
    gc_decref(rt);
5801
5802
    /* keep the GC objects with a non zero refcount and their childs */
5803
23
    gc_scan(rt);
5804
5805
    /* free the GC objects in a cycle */
5806
23
    gc_free_cycles(rt);
5807
23
}
5808
5809
/* Return false if not an object or if the object has already been
5810
   freed (zombie objects are visible in finalizers when freeing
5811
   cycles). */
5812
BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj)
5813
0
{
5814
0
    JSObject *p;
5815
0
    if (!JS_IsObject(obj))
5816
0
        return FALSE;
5817
0
    p = JS_VALUE_GET_OBJ(obj);
5818
0
    return !p->free_mark;
5819
0
}
5820
5821
/* Compute memory used by various object types */
5822
/* XXX: poor man's approach to handling multiply referenced objects */
5823
typedef struct JSMemoryUsage_helper {
5824
    double memory_used_count;
5825
    double str_count;
5826
    double str_size;
5827
    int64_t js_func_count;
5828
    double js_func_size;
5829
    int64_t js_func_code_size;
5830
    int64_t js_func_pc2line_count;
5831
    int64_t js_func_pc2line_size;
5832
} JSMemoryUsage_helper;
5833
5834
static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp);
5835
5836
static void compute_jsstring_size(JSString *str, JSMemoryUsage_helper *hp)
5837
0
{
5838
0
    if (!str->atom_type) {  /* atoms are handled separately */
5839
0
        double s_ref_count = str->header.ref_count;
5840
0
        hp->str_count += 1 / s_ref_count;
5841
0
        hp->str_size += ((sizeof(*str) + (str->len << str->is_wide_char) +
5842
0
                          1 - str->is_wide_char) / s_ref_count);
5843
0
    }
5844
0
}
5845
5846
static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *hp)
5847
0
{
5848
0
    int memory_used_count, js_func_size, i;
5849
5850
0
    memory_used_count = 0;
5851
0
    js_func_size = offsetof(JSFunctionBytecode, debug);
5852
0
    if (b->vardefs) {
5853
0
        js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs);
5854
0
    }
5855
0
    if (b->cpool) {
5856
0
        js_func_size += b->cpool_count * sizeof(*b->cpool);
5857
0
        for (i = 0; i < b->cpool_count; i++) {
5858
0
            JSValueConst val = b->cpool[i];
5859
0
            compute_value_size(val, hp);
5860
0
        }
5861
0
    }
5862
0
    if (b->closure_var) {
5863
0
        js_func_size += b->closure_var_count * sizeof(*b->closure_var);
5864
0
    }
5865
0
    if (!b->read_only_bytecode && b->byte_code_buf) {
5866
0
        hp->js_func_code_size += b->byte_code_len;
5867
0
    }
5868
0
    if (b->has_debug) {
5869
0
        js_func_size += sizeof(*b) - offsetof(JSFunctionBytecode, debug);
5870
0
        if (b->debug.source) {
5871
0
            memory_used_count++;
5872
0
            js_func_size += b->debug.source_len + 1;
5873
0
        }
5874
0
        if (b->debug.pc2line_len) {
5875
0
            memory_used_count++;
5876
0
            hp->js_func_pc2line_count += 1;
5877
0
            hp->js_func_pc2line_size += b->debug.pc2line_len;
5878
0
        }
5879
0
    }
5880
0
    hp->js_func_size += js_func_size;
5881
0
    hp->js_func_count += 1;
5882
0
    hp->memory_used_count += memory_used_count;
5883
0
}
5884
5885
static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp)
5886
0
{
5887
0
    switch(JS_VALUE_GET_TAG(val)) {
5888
0
    case JS_TAG_STRING:
5889
0
        compute_jsstring_size(JS_VALUE_GET_STRING(val), hp);
5890
0
        break;
5891
0
#ifdef CONFIG_BIGNUM
5892
0
    case JS_TAG_BIG_INT:
5893
0
    case JS_TAG_BIG_FLOAT:
5894
0
    case JS_TAG_BIG_DECIMAL:
5895
        /* should track JSBigFloat usage */
5896
0
        break;
5897
0
#endif
5898
0
    }
5899
0
}
5900
5901
void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
5902
0
{
5903
0
    struct list_head *el, *el1;
5904
0
    int i;
5905
0
    JSMemoryUsage_helper mem = { 0 }, *hp = &mem;
5906
5907
0
    memset(s, 0, sizeof(*s));
5908
0
    s->malloc_count = rt->malloc_state.malloc_count;
5909
0
    s->malloc_size = rt->malloc_state.malloc_size;
5910
0
    s->malloc_limit = rt->malloc_state.malloc_limit;
5911
5912
0
    s->memory_used_count = 2; /* rt + rt->class_array */
5913
0
    s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count;
5914
5915
0
    list_for_each(el, &rt->context_list) {
5916
0
        JSContext *ctx = list_entry(el, JSContext, link);
5917
0
        JSShape *sh = ctx->array_shape;
5918
0
        s->memory_used_count += 2; /* ctx + ctx->class_proto */
5919
0
        s->memory_used_size += sizeof(JSContext) +
5920
0
            sizeof(JSValue) * rt->class_count;
5921
0
        s->binary_object_count += ctx->binary_object_count;
5922
0
        s->binary_object_size += ctx->binary_object_size;
5923
5924
        /* the hashed shapes are counted separately */
5925
0
        if (sh && !sh->is_hashed) {
5926
0
            int hash_size = sh->prop_hash_mask + 1;
5927
0
            s->shape_count++;
5928
0
            s->shape_size += get_shape_size(hash_size, sh->prop_size);
5929
0
        }
5930
0
        list_for_each(el1, &ctx->loaded_modules) {
5931
0
            JSModuleDef *m = list_entry(el1, JSModuleDef, link);
5932
0
            s->memory_used_count += 1;
5933
0
            s->memory_used_size += sizeof(*m);
5934
0
            if (m->req_module_entries) {
5935
0
                s->memory_used_count += 1;
5936
0
                s->memory_used_size += m->req_module_entries_count * sizeof(*m->req_module_entries);
5937
0
            }
5938
0
            if (m->export_entries) {
5939
0
                s->memory_used_count += 1;
5940
0
                s->memory_used_size += m->export_entries_count * sizeof(*m->export_entries);
5941
0
                for (i = 0; i < m->export_entries_count; i++) {
5942
0
                    JSExportEntry *me = &m->export_entries[i];
5943
0
                    if (me->export_type == JS_EXPORT_TYPE_LOCAL && me->u.local.var_ref) {
5944
                        /* potential multiple count */
5945
0
                        s->memory_used_count += 1;
5946
0
                        compute_value_size(me->u.local.var_ref->value, hp);
5947
0
                    }
5948
0
                }
5949
0
            }
5950
0
            if (m->star_export_entries) {
5951
0
                s->memory_used_count += 1;
5952
0
                s->memory_used_size += m->star_export_entries_count * sizeof(*m->star_export_entries);
5953
0
            }
5954
0
            if (m->import_entries) {
5955
0
                s->memory_used_count += 1;
5956
0
                s->memory_used_size += m->import_entries_count * sizeof(*m->import_entries);
5957
0
            }
5958
0
            compute_value_size(m->module_ns, hp);
5959
0
            compute_value_size(m->func_obj, hp);
5960
0
        }
5961
0
    }
5962
5963
0
    list_for_each(el, &rt->gc_obj_list) {
5964
0
        JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
5965
0
        JSObject *p;
5966
0
        JSShape *sh;
5967
0
        JSShapeProperty *prs;
5968
5969
        /* XXX: could count the other GC object types too */
5970
0
        if (gp->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) {
5971
0
            compute_bytecode_size((JSFunctionBytecode *)gp, hp);
5972
0
            continue;
5973
0
        } else if (gp->gc_obj_type != JS_GC_OBJ_TYPE_JS_OBJECT) {
5974
0
            continue;
5975
0
        }
5976
0
        p = (JSObject *)gp;
5977
0
        sh = p->shape;
5978
0
        s->obj_count++;
5979
0
        if (p->prop) {
5980
0
            s->memory_used_count++;
5981
0
            s->prop_size += sh->prop_size * sizeof(*p->prop);
5982
0
            s->prop_count += sh->prop_count;
5983
0
            prs = get_shape_prop(sh);
5984
0
            for(i = 0; i < sh->prop_count; i++) {
5985
0
                JSProperty *pr = &p->prop[i];
5986
0
                if (prs->atom != JS_ATOM_NULL && !(prs->flags & JS_PROP_TMASK)) {
5987
0
                    compute_value_size(pr->u.value, hp);
5988
0
                }
5989
0
                prs++;
5990
0
            }
5991
0
        }
5992
        /* the hashed shapes are counted separately */
5993
0
        if (!sh->is_hashed) {
5994
0
            int hash_size = sh->prop_hash_mask + 1;
5995
0
            s->shape_count++;
5996
0
            s->shape_size += get_shape_size(hash_size, sh->prop_size);
5997
0
        }
5998
5999
0
        switch(p->class_id) {
6000
0
        case JS_CLASS_ARRAY:             /* u.array | length */
6001
0
        case JS_CLASS_ARGUMENTS:         /* u.array | length */
6002
0
            s->array_count++;
6003
0
            if (p->fast_array) {
6004
0
                s->fast_array_count++;
6005
0
                if (p->u.array.u.values) {
6006
0
                    s->memory_used_count++;
6007
0
                    s->memory_used_size += p->u.array.count *
6008
0
                        sizeof(*p->u.array.u.values);
6009
0
                    s->fast_array_elements += p->u.array.count;
6010
0
                    for (i = 0; i < p->u.array.count; i++) {
6011
0
                        compute_value_size(p->u.array.u.values[i], hp);
6012
0
                    }
6013
0
                }
6014
0
            }
6015
0
            break;
6016
0
        case JS_CLASS_NUMBER:            /* u.object_data */
6017
0
        case JS_CLASS_STRING:            /* u.object_data */
6018
0
        case JS_CLASS_BOOLEAN:           /* u.object_data */
6019
0
        case JS_CLASS_SYMBOL:            /* u.object_data */
6020
0
        case JS_CLASS_DATE:              /* u.object_data */
6021
0
#ifdef CONFIG_BIGNUM
6022
0
        case JS_CLASS_BIG_INT:           /* u.object_data */
6023
0
        case JS_CLASS_BIG_FLOAT:         /* u.object_data */
6024
0
        case JS_CLASS_BIG_DECIMAL:         /* u.object_data */
6025
0
#endif
6026
0
            compute_value_size(p->u.object_data, hp);
6027
0
            break;
6028
0
        case JS_CLASS_C_FUNCTION:        /* u.cfunc */
6029
0
            s->c_func_count++;
6030
0
            break;
6031
0
        case JS_CLASS_BYTECODE_FUNCTION: /* u.func */
6032
0
            {
6033
0
                JSFunctionBytecode *b = p->u.func.function_bytecode;
6034
0
                JSVarRef **var_refs = p->u.func.var_refs;
6035
                /* home_object: object will be accounted for in list scan */
6036
0
                if (var_refs) {
6037
0
                    s->memory_used_count++;
6038
0
                    s->js_func_size += b->closure_var_count * sizeof(*var_refs);
6039
0
                    for (i = 0; i < b->closure_var_count; i++) {
6040
0
                        if (var_refs[i]) {
6041
0
                            double ref_count = var_refs[i]->header.ref_count;
6042
0
                            s->memory_used_count += 1 / ref_count;
6043
0
                            s->js_func_size += sizeof(*var_refs[i]) / ref_count;
6044
                            /* handle non object closed values */
6045
0
                            if (var_refs[i]->pvalue == &var_refs[i]->value) {
6046
                                /* potential multiple count */
6047
0
                                compute_value_size(var_refs[i]->value, hp);
6048
0
                            }
6049
0
                        }
6050
0
                    }
6051
0
                }
6052
0
            }
6053
0
            break;
6054
0
        case JS_CLASS_BOUND_FUNCTION:    /* u.bound_function */
6055
0
            {
6056
0
                JSBoundFunction *bf = p->u.bound_function;
6057
                /* func_obj and this_val are objects */
6058
0
                for (i = 0; i < bf->argc; i++) {
6059
0
                    compute_value_size(bf->argv[i], hp);
6060
0
                }
6061
0
                s->memory_used_count += 1;
6062
0
                s->memory_used_size += sizeof(*bf) + bf->argc * sizeof(*bf->argv);
6063
0
            }
6064
0
            break;
6065
0
        case JS_CLASS_C_FUNCTION_DATA:   /* u.c_function_data_record */
6066
0
            {
6067
0
                JSCFunctionDataRecord *fd = p->u.c_function_data_record;
6068
0
                if (fd) {
6069
0
                    for (i = 0; i < fd->data_len; i++) {
6070
0
                        compute_value_size(fd->data[i], hp);
6071
0
                    }
6072
0
                    s->memory_used_count += 1;
6073
0
                    s->memory_used_size += sizeof(*fd) + fd->data_len * sizeof(*fd->data);
6074
0
                }
6075
0
            }
6076
0
            break;
6077
0
        case JS_CLASS_REGEXP:            /* u.regexp */
6078
0
            compute_jsstring_size(p->u.regexp.pattern, hp);
6079
0
            compute_jsstring_size(p->u.regexp.bytecode, hp);
6080
0
            break;
6081
6082
0
        case JS_CLASS_FOR_IN_ITERATOR:   /* u.for_in_iterator */
6083
0
            {
6084
0
                JSForInIterator *it = p->u.for_in_iterator;
6085
0
                if (it) {
6086
0
                    compute_value_size(it->obj, hp);
6087
0
                    s->memory_used_count += 1;
6088
0
                    s->memory_used_size += sizeof(*it);
6089
0
                }
6090
0
            }
6091
0
            break;
6092
0
        case JS_CLASS_ARRAY_BUFFER:      /* u.array_buffer */
6093
0
        case JS_CLASS_SHARED_ARRAY_BUFFER: /* u.array_buffer */
6094
0
            {
6095
0
                JSArrayBuffer *abuf = p->u.array_buffer;
6096
0
                if (abuf) {
6097
0
                    s->memory_used_count += 1;
6098
0
                    s->memory_used_size += sizeof(*abuf);
6099
0
                    if (abuf->data) {
6100
0
                        s->memory_used_count += 1;
6101
0
                        s->memory_used_size += abuf->byte_length;
6102
0
                    }
6103
0
                }
6104
0
            }
6105
0
            break;
6106
0
        case JS_CLASS_GENERATOR:         /* u.generator_data */
6107
0
        case JS_CLASS_UINT8C_ARRAY:      /* u.typed_array / u.array */
6108
0
        case JS_CLASS_INT8_ARRAY:        /* u.typed_array / u.array */
6109
0
        case JS_CLASS_UINT8_ARRAY:       /* u.typed_array / u.array */
6110
0
        case JS_CLASS_INT16_ARRAY:       /* u.typed_array / u.array */
6111
0
        case JS_CLASS_UINT16_ARRAY:      /* u.typed_array / u.array */
6112
0
        case JS_CLASS_INT32_ARRAY:       /* u.typed_array / u.array */
6113
0
        case JS_CLASS_UINT32_ARRAY:      /* u.typed_array / u.array */
6114
0
#ifdef CONFIG_BIGNUM
6115
0
        case JS_CLASS_BIG_INT64_ARRAY:   /* u.typed_array / u.array */
6116
0
        case JS_CLASS_BIG_UINT64_ARRAY:  /* u.typed_array / u.array */
6117
0
#endif
6118
0
        case JS_CLASS_FLOAT32_ARRAY:     /* u.typed_array / u.array */
6119
0
        case JS_CLASS_FLOAT64_ARRAY:     /* u.typed_array / u.array */
6120
0
        case JS_CLASS_DATAVIEW:          /* u.typed_array */
6121
0
#ifdef CONFIG_BIGNUM
6122
0
        case JS_CLASS_FLOAT_ENV:         /* u.float_env */
6123
0
#endif
6124
0
        case JS_CLASS_MAP:               /* u.map_state */
6125
0
        case JS_CLASS_SET:               /* u.map_state */
6126
0
        case JS_CLASS_WEAKMAP:           /* u.map_state */
6127
0
        case JS_CLASS_WEAKSET:           /* u.map_state */
6128
0
        case JS_CLASS_MAP_ITERATOR:      /* u.map_iterator_data */
6129
0
        case JS_CLASS_SET_ITERATOR:      /* u.map_iterator_data */
6130
0
        case JS_CLASS_ARRAY_ITERATOR:    /* u.array_iterator_data */
6131
0
        case JS_CLASS_STRING_ITERATOR:   /* u.array_iterator_data */
6132
0
        case JS_CLASS_PROXY:             /* u.proxy_data */
6133
0
        case JS_CLASS_PROMISE:           /* u.promise_data */
6134
0
        case JS_CLASS_PROMISE_RESOLVE_FUNCTION:  /* u.promise_function_data */
6135
0
        case JS_CLASS_PROMISE_REJECT_FUNCTION:   /* u.promise_function_data */
6136
0
        case JS_CLASS_ASYNC_FUNCTION_RESOLVE:    /* u.async_function_data */
6137
0
        case JS_CLASS_ASYNC_FUNCTION_REJECT:     /* u.async_function_data */
6138
0
        case JS_CLASS_ASYNC_FROM_SYNC_ITERATOR:  /* u.async_from_sync_iterator_data */
6139
0
        case JS_CLASS_ASYNC_GENERATOR:   /* u.async_generator_data */
6140
            /* TODO */
6141
0
        default:
6142
            /* XXX: class definition should have an opaque block size */
6143
0
            if (p->u.opaque) {
6144
0
                s->memory_used_count += 1;
6145
0
            }
6146
0
            break;
6147
0
        }
6148
0
    }
6149
0
    s->obj_size += s->obj_count * sizeof(JSObject);
6150
6151
    /* hashed shapes */
6152
0
    s->memory_used_count++; /* rt->shape_hash */
6153
0
    s->memory_used_size += sizeof(rt->shape_hash[0]) * rt->shape_hash_size;
6154
0
    for(i = 0; i < rt->shape_hash_size; i++) {
6155
0
        JSShape *sh;
6156
0
        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
6157
0
            int hash_size = sh->prop_hash_mask + 1;
6158
0
            s->shape_count++;
6159
0
            s->shape_size += get_shape_size(hash_size, sh->prop_size);
6160
0
        }
6161
0
    }
6162
6163
    /* atoms */
6164
0
    s->memory_used_count += 2; /* rt->atom_array, rt->atom_hash */
6165
0
    s->atom_count = rt->atom_count;
6166
0
    s->atom_size = sizeof(rt->atom_array[0]) * rt->atom_size +
6167
0
        sizeof(rt->atom_hash[0]) * rt->atom_hash_size;
6168
0
    for(i = 0; i < rt->atom_size; i++) {
6169
0
        JSAtomStruct *p = rt->atom_array[i];
6170
0
        if (!atom_is_free(p)) {
6171
0
            s->atom_size += (sizeof(*p) + (p->len << p->is_wide_char) +
6172
0
                             1 - p->is_wide_char);
6173
0
        }
6174
0
    }
6175
0
    s->str_count = round(mem.str_count);
6176
0
    s->str_size = round(mem.str_size);
6177
0
    s->js_func_count = mem.js_func_count;
6178
0
    s->js_func_size = round(mem.js_func_size);
6179
0
    s->js_func_code_size = mem.js_func_code_size;
6180
0
    s->js_func_pc2line_count = mem.js_func_pc2line_count;
6181
0
    s->js_func_pc2line_size = mem.js_func_pc2line_size;
6182
0
    s->memory_used_count += round(mem.memory_used_count) +
6183
0
        s->atom_count + s->str_count +
6184
0
        s->obj_count + s->shape_count +
6185
0
        s->js_func_count + s->js_func_pc2line_count;
6186
0
    s->memory_used_size += s->atom_size + s->str_size +
6187
0
        s->obj_size + s->prop_size + s->shape_size +
6188
0
        s->js_func_size + s->js_func_code_size + s->js_func_pc2line_size;
6189
0
}
6190
6191
void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
6192
0
{
6193
0
    fprintf(fp, "QuickJS memory usage -- "
6194
0
#ifdef CONFIG_BIGNUM
6195
0
            "BigNum "
6196
0
#endif
6197
0
            CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n",
6198
0
            (int)sizeof(void *) * 8, (int64_t)(ssize_t)s->malloc_limit);
6199
0
#if 1
6200
0
    if (rt) {
6201
0
        static const struct {
6202
0
            const char *name;
6203
0
            size_t size;
6204
0
        } object_types[] = {
6205
0
            { "JSRuntime", sizeof(JSRuntime) },
6206
0
            { "JSContext", sizeof(JSContext) },
6207
0
            { "JSObject", sizeof(JSObject) },
6208
0
            { "JSString", sizeof(JSString) },
6209
0
            { "JSFunctionBytecode", sizeof(JSFunctionBytecode) },
6210
0
        };
6211
0
        int i, usage_size_ok = 0;
6212
0
        for(i = 0; i < countof(object_types); i++) {
6213
0
            unsigned int size = object_types[i].size;
6214
0
            void *p = js_malloc_rt(rt, size);
6215
0
            if (p) {
6216
0
                unsigned int size1 = js_malloc_usable_size_rt(rt, p);
6217
0
                if (size1 >= size) {
6218
0
                    usage_size_ok = 1;
6219
0
                    fprintf(fp, "  %3u + %-2u  %s\n",
6220
0
                            size, size1 - size, object_types[i].name);
6221
0
                }
6222
0
                js_free_rt(rt, p);
6223
0
            }
6224
0
        }
6225
0
        if (!usage_size_ok) {
6226
0
            fprintf(fp, "  malloc_usable_size unavailable\n");
6227
0
        }
6228
0
        {
6229
0
            int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 };
6230
0
            int class_id;
6231
0
            struct list_head *el;
6232
0
            list_for_each(el, &rt->gc_obj_list) {
6233
0
                JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
6234
0
                JSObject *p;
6235
0
                if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
6236
0
                    p = (JSObject *)gp;
6237
0
                    obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++;
6238
0
                }
6239
0
            }
6240
0
            fprintf(fp, "\n" "JSObject classes\n");
6241
0
            if (obj_classes[0])
6242
0
                fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[0], 0, "none");
6243
0
            for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) {
6244
0
                if (obj_classes[class_id]) {
6245
0
                    char buf[ATOM_GET_STR_BUF_SIZE];
6246
0
                    fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[class_id], class_id,
6247
0
                            JS_AtomGetStrRT(rt, buf, sizeof(buf), js_std_class_def[class_id - 1].class_name));
6248
0
                }
6249
0
            }
6250
0
            if (obj_classes[JS_CLASS_INIT_COUNT])
6251
0
                fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other");
6252
0
        }
6253
0
        fprintf(fp, "\n");
6254
0
    }
6255
0
#endif
6256
0
    fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE");
6257
6258
0
    if (s->malloc_count) {
6259
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per block)\n",
6260
0
                "memory allocated", s->malloc_count, s->malloc_size,
6261
0
                (double)s->malloc_size / s->malloc_count);
6262
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%d overhead, %0.1f average slack)\n",
6263
0
                "memory used", s->memory_used_count, s->memory_used_size,
6264
0
                MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) /
6265
0
                                  s->memory_used_count));
6266
0
    }
6267
0
    if (s->atom_count) {
6268
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per atom)\n",
6269
0
                "atoms", s->atom_count, s->atom_size,
6270
0
                (double)s->atom_size / s->atom_count);
6271
0
    }
6272
0
    if (s->str_count) {
6273
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per string)\n",
6274
0
                "strings", s->str_count, s->str_size,
6275
0
                (double)s->str_size / s->str_count);
6276
0
    }
6277
0
    if (s->obj_count) {
6278
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
6279
0
                "objects", s->obj_count, s->obj_size,
6280
0
                (double)s->obj_size / s->obj_count);
6281
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
6282
0
                "  properties", s->prop_count, s->prop_size,
6283
0
                (double)s->prop_count / s->obj_count);
6284
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per shape)\n",
6285
0
                "  shapes", s->shape_count, s->shape_size,
6286
0
                (double)s->shape_size / s->shape_count);
6287
0
    }
6288
0
    if (s->js_func_count) {
6289
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
6290
0
                "bytecode functions", s->js_func_count, s->js_func_size);
6291
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
6292
0
                "  bytecode", s->js_func_count, s->js_func_code_size,
6293
0
                (double)s->js_func_code_size / s->js_func_count);
6294
0
        if (s->js_func_pc2line_count) {
6295
0
            fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
6296
0
                    "  pc2line", s->js_func_pc2line_count,
6297
0
                    s->js_func_pc2line_size,
6298
0
                    (double)s->js_func_pc2line_size / s->js_func_pc2line_count);
6299
0
        }
6300
0
    }
6301
0
    if (s->c_func_count) {
6302
0
        fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count);
6303
0
    }
6304
0
    if (s->array_count) {
6305
0
        fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count);
6306
0
        if (s->fast_array_count) {
6307
0
            fprintf(fp, "%-20s %8"PRId64"\n", "  fast arrays", s->fast_array_count);
6308
0
            fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per fast array)\n",
6309
0
                    "  elements", s->fast_array_elements,
6310
0
                    s->fast_array_elements * (int)sizeof(JSValue),
6311
0
                    (double)s->fast_array_elements / s->fast_array_count);
6312
0
        }
6313
0
    }
6314
0
    if (s->binary_object_count) {
6315
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
6316
0
                "binary objects", s->binary_object_count, s->binary_object_size);
6317
0
    }
6318
0
}
6319
6320
JSValue JS_GetGlobalObject(JSContext *ctx)
6321
2
{
6322
2
    return JS_DupValue(ctx, ctx->global_obj);
6323
2
}
6324
6325
/* WARNING: obj is freed */
6326
JSValue JS_Throw(JSContext *ctx, JSValue obj)
6327
122k
{
6328
122k
    JSRuntime *rt = ctx->rt;
6329
122k
    JS_FreeValue(ctx, rt->current_exception);
6330
122k
    rt->current_exception = obj;
6331
122k
    return JS_EXCEPTION;
6332
122k
}
6333
6334
/* return the pending exception (cannot be called twice). */
6335
JSValue JS_GetException(JSContext *ctx)
6336
2
{
6337
2
    JSValue val;
6338
2
    JSRuntime *rt = ctx->rt;
6339
2
    val = rt->current_exception;
6340
2
    rt->current_exception = JS_NULL;
6341
2
    return val;
6342
2
}
6343
6344
static void dbuf_put_leb128(DynBuf *s, uint32_t v)
6345
25.5k
{
6346
25.5k
    uint32_t a;
6347
29.3k
    for(;;) {
6348
29.3k
        a = v & 0x7f;
6349
29.3k
        v >>= 7;
6350
29.3k
        if (v != 0) {
6351
3.76k
            dbuf_putc(s, a | 0x80);
6352
25.5k
        } else {
6353
25.5k
            dbuf_putc(s, a);
6354
25.5k
            break;
6355
25.5k
        }
6356
29.3k
    }
6357
25.5k
}
6358
6359
static void dbuf_put_sleb128(DynBuf *s, int32_t v1)
6360
11.8k
{
6361
11.8k
    uint32_t v = v1;
6362
11.8k
    dbuf_put_leb128(s, (2 * v) ^ -(v >> 31));
6363
11.8k
}
6364
6365
static int get_leb128(uint32_t *pval, const uint8_t *buf,
6366
                      const uint8_t *buf_end)
6367
2.62M
{
6368
2.62M
    const uint8_t *ptr = buf;
6369
2.62M
    uint32_t v, a, i;
6370
2.62M
    v = 0;
6371
2.74M
    for(i = 0; i < 5; i++) {
6372
2.74M
        if (unlikely(ptr >= buf_end))
6373
0
            break;
6374
2.74M
        a = *ptr++;
6375
2.74M
        v |= (a & 0x7f) << (i * 7);
6376
2.74M
        if (!(a & 0x80)) {
6377
2.62M
            *pval = v;
6378
2.62M
            return ptr - buf;
6379
2.62M
        }
6380
2.74M
    }
6381
0
    *pval = 0;
6382
0
    return -1;
6383
2.62M
}
6384
6385
static int get_sleb128(int32_t *pval, const uint8_t *buf,
6386
                       const uint8_t *buf_end)
6387
1.31M
{
6388
1.31M
    int ret;
6389
1.31M
    uint32_t val;
6390
1.31M
    ret = get_leb128(&val, buf, buf_end);
6391
1.31M
    if (ret < 0) {
6392
0
        *pval = 0;
6393
0
        return -1;
6394
0
    }
6395
1.31M
    *pval = (val >> 1) ^ -(val & 1);
6396
1.31M
    return ret;
6397
1.31M
}
6398
6399
static int find_line_num(JSContext *ctx, JSFunctionBytecode *b,
6400
                         uint32_t pc_value)
6401
163k
{
6402
163k
    const uint8_t *p_end, *p;
6403
163k
    int new_line_num, line_num, pc, v, ret;
6404
163k
    unsigned int op;
6405
6406
163k
    if (!b->has_debug || !b->debug.pc2line_buf) {
6407
        /* function was stripped */
6408
40.9k
        return -1;
6409
40.9k
    }
6410
6411
122k
    p = b->debug.pc2line_buf;
6412
122k
    p_end = p + b->debug.pc2line_len;
6413
122k
    pc = 0;
6414
122k
    line_num = b->debug.line_num;
6415
6.96M
    while (p < p_end) {
6416
6.96M
        op = *p++;
6417
6.96M
        if (op == 0) {
6418
1.31M
            uint32_t val;
6419
1.31M
            ret = get_leb128(&val, p, p_end);
6420
1.31M
            if (ret < 0)
6421
0
                goto fail;
6422
1.31M
            pc += val;
6423
1.31M
            p += ret;
6424
1.31M
            ret = get_sleb128(&v, p, p_end);
6425
1.31M
            if (ret < 0) {
6426
0
            fail:
6427
                /* should never happen */
6428
0
                return b->debug.line_num;
6429
0
            }
6430
1.31M
            p += ret;
6431
1.31M
            new_line_num = line_num + v;
6432
5.65M
        } else {
6433
5.65M
            op -= PC2LINE_OP_FIRST;
6434
5.65M
            pc += (op / PC2LINE_RANGE);
6435
5.65M
            new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE;
6436
5.65M
        }
6437
6.96M
        if (pc_value < pc)
6438
122k
            return line_num;
6439
6.84M
        line_num = new_line_num;
6440
6.84M
    }
6441
1
    return line_num;
6442
122k
}
6443
6444
/* in order to avoid executing arbitrary code during the stack trace
6445
   generation, we only look at simple 'name' properties containing a
6446
   string. */
6447
static const char *get_func_name(JSContext *ctx, JSValueConst func)
6448
163k
{
6449
163k
    JSProperty *pr;
6450
163k
    JSShapeProperty *prs;
6451
163k
    JSValueConst val;
6452
    
6453
163k
    if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)
6454
0
        return NULL;
6455
163k
    prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name);
6456
163k
    if (!prs)
6457
122k
        return NULL;
6458
40.9k
    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
6459
0
        return NULL;
6460
40.9k
    val = pr->u.value;
6461
40.9k
    if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
6462
0
        return NULL;
6463
40.9k
    return JS_ToCString(ctx, val);
6464
40.9k
}
6465
6466
163k
#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)
6467
/* only taken into account if filename is provided */
6468
16
#define JS_BACKTRACE_FLAG_SINGLE_LEVEL     (1 << 1)
6469
6470
/* if filename != NULL, an additional level is added with the filename
6471
   and line number information (used for parse error). */
6472
static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
6473
                            const char *filename, int line_num,
6474
                            int backtrace_flags)
6475
122k
{
6476
122k
    JSStackFrame *sf;
6477
122k
    JSValue str;
6478
122k
    DynBuf dbuf;
6479
122k
    const char *func_name_str;
6480
122k
    const char *str1;
6481
122k
    JSObject *p;
6482
122k
    BOOL backtrace_barrier;
6483
    
6484
122k
    js_dbuf_init(ctx, &dbuf);
6485
122k
    if (filename) {
6486
16
        dbuf_printf(&dbuf, "    at %s", filename);
6487
16
        if (line_num != -1)
6488
16
            dbuf_printf(&dbuf, ":%d", line_num);
6489
16
        dbuf_putc(&dbuf, '\n');
6490
16
        str = JS_NewString(ctx, filename);
6491
16
        JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
6492
16
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6493
16
        JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
6494
16
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6495
16
        if (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL)
6496
0
            goto done;
6497
16
    }
6498
286k
    for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
6499
163k
        if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {
6500
0
            backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;
6501
0
            continue;
6502
0
        }
6503
163k
        func_name_str = get_func_name(ctx, sf->cur_func);
6504
163k
        if (!func_name_str || func_name_str[0] == '\0')
6505
122k
            str1 = "<anonymous>";
6506
40.9k
        else
6507
40.9k
            str1 = func_name_str;
6508
163k
        dbuf_printf(&dbuf, "    at %s", str1);
6509
163k
        JS_FreeCString(ctx, func_name_str);
6510
6511
163k
        p = JS_VALUE_GET_OBJ(sf->cur_func);
6512
163k
        backtrace_barrier = FALSE;
6513
163k
        if (js_class_has_bytecode(p->class_id)) {
6514
163k
            JSFunctionBytecode *b;
6515
163k
            const char *atom_str;
6516
163k
            int line_num1;
6517
6518
163k
            b = p->u.func.function_bytecode;
6519
163k
            backtrace_barrier = b->backtrace_barrier;
6520
163k
            if (b->has_debug) {
6521
163k
                line_num1 = find_line_num(ctx, b,
6522
163k
                                          sf->cur_pc - b->byte_code_buf - 1);
6523
163k
                atom_str = JS_AtomToCString(ctx, b->debug.filename);
6524
163k
                dbuf_printf(&dbuf, " (%s",
6525
163k
                            atom_str ? atom_str : "<null>");
6526
163k
                JS_FreeCString(ctx, atom_str);
6527
163k
                if (line_num1 != -1)
6528
122k
                    dbuf_printf(&dbuf, ":%d", line_num1);
6529
163k
                dbuf_putc(&dbuf, ')');
6530
163k
            }
6531
163k
        } else {
6532
0
            dbuf_printf(&dbuf, " (native)");
6533
0
        }
6534
163k
        dbuf_putc(&dbuf, '\n');
6535
        /* stop backtrace if JS_EVAL_FLAG_BACKTRACE_BARRIER was used */
6536
163k
        if (backtrace_barrier)
6537
0
            break;
6538
163k
    }
6539
122k
 done:
6540
122k
    dbuf_putc(&dbuf, '\0');
6541
122k
    if (dbuf_error(&dbuf))
6542
0
        str = JS_NULL;
6543
122k
    else
6544
122k
        str = JS_NewString(ctx, (char *)dbuf.buf);
6545
122k
    dbuf_free(&dbuf);
6546
122k
    JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str,
6547
122k
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6548
122k
}
6549
6550
/* Note: it is important that no exception is returned by this function */
6551
static BOOL is_backtrace_needed(JSContext *ctx, JSValueConst obj)
6552
163k
{
6553
163k
    JSObject *p;
6554
163k
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6555
6
        return FALSE;
6556
163k
    p = JS_VALUE_GET_OBJ(obj);
6557
163k
    if (p->class_id != JS_CLASS_ERROR)
6558
0
        return FALSE;
6559
163k
    if (find_own_property1(p, JS_ATOM_stack))
6560
40.9k
        return FALSE;
6561
122k
    return TRUE;
6562
163k
}
6563
6564
JSValue JS_NewError(JSContext *ctx)
6565
0
{
6566
0
    return JS_NewObjectClass(ctx, JS_CLASS_ERROR);
6567
0
}
6568
6569
static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num,
6570
                              const char *fmt, va_list ap, BOOL add_backtrace)
6571
122k
{
6572
122k
    char buf[256];
6573
122k
    JSValue obj, ret;
6574
6575
122k
    vsnprintf(buf, sizeof(buf), fmt, ap);
6576
122k
    obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num],
6577
122k
                                 JS_CLASS_ERROR);
6578
122k
    if (unlikely(JS_IsException(obj))) {
6579
        /* out of memory: throw JS_NULL to avoid recursing */
6580
8
        obj = JS_NULL;
6581
122k
    } else {
6582
122k
        JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,
6583
122k
                               JS_NewString(ctx, buf),
6584
122k
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6585
122k
    }
6586
122k
    if (add_backtrace) {
6587
0
        build_backtrace(ctx, obj, NULL, 0, 0);
6588
0
    }
6589
122k
    ret = JS_Throw(ctx, obj);
6590
122k
    return ret;
6591
122k
}
6592
6593
static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num,
6594
                             const char *fmt, va_list ap)
6595
122k
{
6596
122k
    JSRuntime *rt = ctx->rt;
6597
122k
    JSStackFrame *sf;
6598
122k
    BOOL add_backtrace;
6599
6600
    /* the backtrace is added later if called from a bytecode function */
6601
122k
    sf = rt->current_stack_frame;
6602
122k
    add_backtrace = !rt->in_out_of_memory &&
6603
122k
        (!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL));
6604
122k
    return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace);
6605
122k
}
6606
6607
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...)
6608
0
{
6609
0
    JSValue val;
6610
0
    va_list ap;
6611
6612
0
    va_start(ap, fmt);
6613
0
    val = JS_ThrowError(ctx, JS_SYNTAX_ERROR, fmt, ap);
6614
0
    va_end(ap);
6615
0
    return val;
6616
0
}
6617
6618
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...)
6619
1
{
6620
1
    JSValue val;
6621
1
    va_list ap;
6622
6623
1
    va_start(ap, fmt);
6624
1
    val = JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
6625
1
    va_end(ap);
6626
1
    return val;
6627
1
}
6628
6629
static int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...)
6630
0
{
6631
0
    va_list ap;
6632
6633
0
    if ((flags & JS_PROP_THROW) ||
6634
0
        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
6635
0
        va_start(ap, fmt);
6636
0
        JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
6637
0
        va_end(ap);
6638
0
        return -1;
6639
0
    } else {
6640
0
        return FALSE;
6641
0
    }
6642
0
}
6643
6644
/* never use it directly */
6645
static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
6646
0
{
6647
0
    char buf[ATOM_GET_STR_BUF_SIZE];
6648
0
    return JS_ThrowTypeError(ctx, fmt,
6649
0
                             JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
6650
0
}
6651
6652
/* never use it directly */
6653
static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
6654
0
{
6655
0
    char buf[ATOM_GET_STR_BUF_SIZE];
6656
0
    return JS_ThrowSyntaxError(ctx, fmt,
6657
0
                             JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
6658
0
}
6659
6660
/* %s is replaced by 'atom'. The macro is used so that gcc can check
6661
    the format string. */
6662
0
#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, "")
6663
0
#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, "")
6664
6665
static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)
6666
0
{
6667
0
    if ((flags & JS_PROP_THROW) ||
6668
0
        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
6669
0
        JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom);
6670
0
        return -1;
6671
0
    } else {
6672
0
        return FALSE;
6673
0
    }
6674
0
}
6675
6676
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...)
6677
122k
{
6678
122k
    JSValue val;
6679
122k
    va_list ap;
6680
6681
122k
    va_start(ap, fmt);
6682
122k
    val = JS_ThrowError(ctx, JS_REFERENCE_ERROR, fmt, ap);
6683
122k
    va_end(ap);
6684
122k
    return val;
6685
122k
}
6686
6687
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...)
6688
0
{
6689
0
    JSValue val;
6690
0
    va_list ap;
6691
6692
0
    va_start(ap, fmt);
6693
0
    val = JS_ThrowError(ctx, JS_RANGE_ERROR, fmt, ap);
6694
0
    va_end(ap);
6695
0
    return val;
6696
0
}
6697
6698
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...)
6699
18
{
6700
18
    JSValue val;
6701
18
    va_list ap;
6702
6703
18
    va_start(ap, fmt);
6704
18
    val = JS_ThrowError(ctx, JS_INTERNAL_ERROR, fmt, ap);
6705
18
    va_end(ap);
6706
18
    return val;
6707
18
}
6708
6709
JSValue JS_ThrowOutOfMemory(JSContext *ctx)
6710
26
{
6711
26
    JSRuntime *rt = ctx->rt;
6712
26
    if (!rt->in_out_of_memory) {
6713
18
        rt->in_out_of_memory = TRUE;
6714
18
        JS_ThrowInternalError(ctx, "out of memory");
6715
18
        rt->in_out_of_memory = FALSE;
6716
18
    }
6717
26
    return JS_EXCEPTION;
6718
26
}
6719
6720
static JSValue JS_ThrowStackOverflow(JSContext *ctx)
6721
0
{
6722
0
    return JS_ThrowInternalError(ctx, "stack overflow");
6723
0
}
6724
6725
static JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx)
6726
0
{
6727
0
    return JS_ThrowTypeError(ctx, "not an object");
6728
0
}
6729
6730
static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx)
6731
0
{
6732
0
    return JS_ThrowTypeError(ctx, "not a symbol");
6733
0
}
6734
6735
static JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name)
6736
122k
{
6737
122k
    char buf[ATOM_GET_STR_BUF_SIZE];
6738
122k
    return JS_ThrowReferenceError(ctx, "'%s' is not defined",
6739
122k
                                  JS_AtomGetStr(ctx, buf, sizeof(buf), name));
6740
122k
}
6741
6742
static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name)
6743
0
{
6744
0
    char buf[ATOM_GET_STR_BUF_SIZE];
6745
0
    return JS_ThrowReferenceError(ctx, "%s is not initialized",
6746
0
                                  name == JS_ATOM_NULL ? "lexical variable" :
6747
0
                                  JS_AtomGetStr(ctx, buf, sizeof(buf), name));
6748
0
}
6749
6750
static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx,
6751
                                                    JSFunctionBytecode *b,
6752
                                                    int idx, BOOL is_ref)
6753
0
{
6754
0
    JSAtom atom = JS_ATOM_NULL;
6755
0
    if (is_ref) {
6756
0
        atom = b->closure_var[idx].var_name;
6757
0
    } else {
6758
        /* not present if the function is stripped and contains no eval() */
6759
0
        if (b->vardefs)
6760
0
            atom = b->vardefs[b->arg_count + idx].var_name;
6761
0
    }
6762
0
    return JS_ThrowReferenceErrorUninitialized(ctx, atom);
6763
0
}
6764
6765
static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
6766
0
{
6767
0
    JSRuntime *rt = ctx->rt;
6768
0
    JSAtom name;
6769
0
    name = rt->class_array[class_id].class_name;
6770
0
    return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
6771
0
}
6772
6773
static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
6774
91
{
6775
91
    JSRuntime *rt = ctx->rt;
6776
91
    ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
6777
91
    if (rt->interrupt_handler) {
6778
91
        if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {
6779
            /* XXX: should set a specific flag to avoid catching */
6780
0
            JS_ThrowInternalError(ctx, "interrupted");
6781
0
            JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE);
6782
0
            return -1;
6783
0
        }
6784
91
    }
6785
91
    return 0;
6786
91
}
6787
6788
static inline __exception int js_poll_interrupts(JSContext *ctx)
6789
903k
{
6790
903k
    if (unlikely(--ctx->interrupt_counter <= 0)) {
6791
91
        return __js_poll_interrupts(ctx);
6792
902k
    } else {
6793
902k
        return 0;
6794
902k
    }
6795
903k
}
6796
6797
/* return -1 (exception) or TRUE/FALSE */
6798
static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj,
6799
                                   JSValueConst proto_val,
6800
                                   BOOL throw_flag)
6801
0
{
6802
0
    JSObject *proto, *p, *p1;
6803
0
    JSShape *sh;
6804
6805
0
    if (throw_flag) {
6806
0
        if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL ||
6807
0
            JS_VALUE_GET_TAG(obj) == JS_TAG_UNDEFINED)
6808
0
            goto not_obj;
6809
0
    } else {
6810
0
        if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6811
0
            goto not_obj;
6812
0
    }
6813
0
    p = JS_VALUE_GET_OBJ(obj);
6814
0
    if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) {
6815
0
        if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_NULL) {
6816
0
        not_obj:
6817
0
            JS_ThrowTypeErrorNotAnObject(ctx);
6818
0
            return -1;
6819
0
        }
6820
0
        proto = NULL;
6821
0
    } else {
6822
0
        proto = JS_VALUE_GET_OBJ(proto_val);
6823
0
    }
6824
6825
0
    if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6826
0
        return TRUE;
6827
6828
0
    if (unlikely(p->class_id == JS_CLASS_PROXY))
6829
0
        return js_proxy_setPrototypeOf(ctx, obj, proto_val, throw_flag);
6830
0
    sh = p->shape;
6831
0
    if (sh->proto == proto)
6832
0
        return TRUE;
6833
0
    if (!p->extensible) {
6834
0
        if (throw_flag) {
6835
0
            JS_ThrowTypeError(ctx, "object is not extensible");
6836
0
            return -1;
6837
0
        } else {
6838
0
            return FALSE;
6839
0
        }
6840
0
    }
6841
0
    if (proto) {
6842
        /* check if there is a cycle */
6843
0
        p1 = proto;
6844
0
        do {
6845
0
            if (p1 == p) {
6846
0
                if (throw_flag) {
6847
0
                    JS_ThrowTypeError(ctx, "circular prototype chain");
6848
0
                    return -1;
6849
0
                } else {
6850
0
                    return FALSE;
6851
0
                }
6852
0
            }
6853
            /* Note: for Proxy objects, proto is NULL */
6854
0
            p1 = p1->shape->proto;
6855
0
        } while (p1 != NULL);
6856
0
        JS_DupValue(ctx, proto_val);
6857
0
    }
6858
6859
0
    if (js_shape_prepare_update(ctx, p, NULL))
6860
0
        return -1;
6861
0
    sh = p->shape;
6862
0
    if (sh->proto)
6863
0
        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
6864
0
    sh->proto = proto;
6865
0
    return TRUE;
6866
0
}
6867
6868
/* return -1 (exception) or TRUE/FALSE */
6869
int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val)
6870
0
{
6871
0
    return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE);
6872
0
}
6873
6874
/* Only works for primitive types, otherwise return JS_NULL. */
6875
static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val)
6876
11
{
6877
11
    switch(JS_VALUE_GET_NORM_TAG(val)) {
6878
0
#ifdef CONFIG_BIGNUM
6879
0
    case JS_TAG_BIG_INT:
6880
0
        val = ctx->class_proto[JS_CLASS_BIG_INT];
6881
0
        break;
6882
0
    case JS_TAG_BIG_FLOAT:
6883
0
        val = ctx->class_proto[JS_CLASS_BIG_FLOAT];
6884
0
        break;
6885
0
    case JS_TAG_BIG_DECIMAL:
6886
0
        val = ctx->class_proto[JS_CLASS_BIG_DECIMAL];
6887
0
        break;
6888
0
#endif
6889
0
    case JS_TAG_INT:
6890
0
    case JS_TAG_FLOAT64:
6891
0
        val = ctx->class_proto[JS_CLASS_NUMBER];
6892
0
        break;
6893
0
    case JS_TAG_BOOL:
6894
0
        val = ctx->class_proto[JS_CLASS_BOOLEAN];
6895
0
        break;
6896
11
    case JS_TAG_STRING:
6897
11
        val = ctx->class_proto[JS_CLASS_STRING];
6898
11
        break;
6899
0
    case JS_TAG_SYMBOL:
6900
0
        val = ctx->class_proto[JS_CLASS_SYMBOL];
6901
0
        break;
6902
0
    case JS_TAG_OBJECT:
6903
0
    case JS_TAG_NULL:
6904
0
    case JS_TAG_UNDEFINED:
6905
0
    default:
6906
0
        val = JS_NULL;
6907
0
        break;
6908
11
    }
6909
11
    return val;
6910
11
}
6911
6912
/* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */
6913
JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj)
6914
9
{
6915
9
    JSValue val;
6916
9
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
6917
9
        JSObject *p;
6918
9
        p = JS_VALUE_GET_OBJ(obj);
6919
9
        if (unlikely(p->class_id == JS_CLASS_PROXY)) {
6920
0
            val = js_proxy_getPrototypeOf(ctx, obj);
6921
9
        } else {
6922
9
            p = p->shape->proto;
6923
9
            if (!p)
6924
3
                val = JS_NULL;
6925
6
            else
6926
6
                val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
6927
9
        }
6928
9
    } else {
6929
0
        val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj));
6930
0
    }
6931
9
    return val;
6932
9
}
6933
6934
static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj)
6935
9
{
6936
9
    JSValue obj1;
6937
9
    obj1 = JS_GetPrototype(ctx, obj);
6938
9
    JS_FreeValue(ctx, obj);
6939
9
    return obj1;
6940
9
}
6941
6942
/* return TRUE, FALSE or (-1) in case of exception */
6943
static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val,
6944
                                   JSValueConst obj)
6945
0
{
6946
0
    JSValue obj_proto;
6947
0
    JSObject *proto;
6948
0
    const JSObject *p, *proto1;
6949
0
    BOOL ret;
6950
6951
0
    if (!JS_IsFunction(ctx, obj))
6952
0
        return FALSE;
6953
0
    p = JS_VALUE_GET_OBJ(obj);
6954
0
    if (p->class_id == JS_CLASS_BOUND_FUNCTION) {
6955
0
        JSBoundFunction *s = p->u.bound_function;
6956
0
        return JS_IsInstanceOf(ctx, val, s->func_obj);
6957
0
    }
6958
6959
    /* Only explicitly boxed values are instances of constructors */
6960
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
6961
0
        return FALSE;
6962
0
    obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype);
6963
0
    if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) {
6964
0
        if (!JS_IsException(obj_proto))
6965
0
            JS_ThrowTypeError(ctx, "operand 'prototype' property is not an object");
6966
0
        ret = -1;
6967
0
        goto done;
6968
0
    }
6969
0
    proto = JS_VALUE_GET_OBJ(obj_proto);
6970
0
    p = JS_VALUE_GET_OBJ(val);
6971
0
    for(;;) {
6972
0
        proto1 = p->shape->proto;
6973
0
        if (!proto1) {
6974
            /* slow case if proxy in the prototype chain */
6975
0
            if (unlikely(p->class_id == JS_CLASS_PROXY)) {
6976
0
                JSValue obj1;
6977
0
                obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p));
6978
0
                for(;;) {
6979
0
                    obj1 = JS_GetPrototypeFree(ctx, obj1);
6980
0
                    if (JS_IsException(obj1)) {
6981
0
                        ret = -1;
6982
0
                        break;
6983
0
                    }
6984
0
                    if (JS_IsNull(obj1)) {
6985
0
                        ret = FALSE;
6986
0
                        break;
6987
0
                    }
6988
0
                    if (proto == JS_VALUE_GET_OBJ(obj1)) {
6989
0
                        JS_FreeValue(ctx, obj1);
6990
0
                        ret = TRUE;
6991
0
                        break;
6992
0
                    }
6993
                    /* must check for timeout to avoid infinite loop */
6994
0
                    if (js_poll_interrupts(ctx)) {
6995
0
                        JS_FreeValue(ctx, obj1);
6996
0
                        ret = -1;
6997
0
                        break;
6998
0
                    }
6999
0
                }
7000
0
            } else {
7001
0
                ret = FALSE;
7002
0
            }
7003
0
            break;
7004
0
        }
7005
0
        p = proto1;
7006
0
        if (proto == p) {
7007
0
            ret = TRUE;
7008
0
            break;
7009
0
        }
7010
0
    }
7011
0
done:
7012
0
    JS_FreeValue(ctx, obj_proto);
7013
0
    return ret;
7014
0
}
7015
7016
/* return TRUE, FALSE or (-1) in case of exception */
7017
int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj)
7018
0
{
7019
0
    JSValue method;
7020
7021
0
    if (!JS_IsObject(obj))
7022
0
        goto fail;
7023
0
    method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_hasInstance);
7024
0
    if (JS_IsException(method))
7025
0
        return -1;
7026
0
    if (!JS_IsNull(method) && !JS_IsUndefined(method)) {
7027
0
        JSValue ret;
7028
0
        ret = JS_CallFree(ctx, method, obj, 1, &val);
7029
0
        return JS_ToBoolFree(ctx, ret);
7030
0
    }
7031
7032
    /* legacy case */
7033
0
    if (!JS_IsFunction(ctx, obj)) {
7034
0
    fail:
7035
0
        JS_ThrowTypeError(ctx, "invalid 'instanceof' right operand");
7036
0
        return -1;
7037
0
    }
7038
0
    return JS_OrdinaryIsInstanceOf(ctx, val, obj);
7039
0
}
7040
7041
/* return the value associated to the autoinit property or an exception */
7042
typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
7043
7044
static JSAutoInitFunc *js_autoinit_func_table[] = {
7045
    js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */
7046
    js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */
7047
    JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */
7048
};
7049
7050
/* warning: 'prs' is reallocated after it */
7051
static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
7052
                               JSProperty *pr, JSShapeProperty *prs)
7053
31
{
7054
31
    JSValue val;
7055
31
    JSContext *realm;
7056
31
    JSAutoInitFunc *func;
7057
7058
31
    if (js_shape_prepare_update(ctx, p, &prs))
7059
0
        return -1;
7060
7061
31
    realm = js_autoinit_get_realm(pr);
7062
31
    func = js_autoinit_func_table[js_autoinit_get_id(pr)];
7063
    /* 'func' shall not modify the object properties 'pr' */
7064
31
    val = func(realm, p, prop, pr->u.init.opaque);
7065
31
    js_autoinit_free(ctx->rt, pr);
7066
31
    prs->flags &= ~JS_PROP_TMASK;
7067
31
    pr->u.value = JS_UNDEFINED;
7068
31
    if (JS_IsException(val))
7069
0
        return -1;
7070
31
    pr->u.value = val;
7071
31
    return 0;
7072
31
}
7073
7074
JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
7075
                               JSAtom prop, JSValueConst this_obj,
7076
                               BOOL throw_ref_error)
7077
2.91M
{
7078
2.91M
    JSObject *p;
7079
2.91M
    JSProperty *pr;
7080
2.91M
    JSShapeProperty *prs;
7081
2.91M
    uint32_t tag;
7082
7083
2.91M
    tag = JS_VALUE_GET_TAG(obj);
7084
2.91M
    if (unlikely(tag != JS_TAG_OBJECT)) {
7085
13
        switch(tag) {
7086
0
        case JS_TAG_NULL:
7087
0
            return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop);
7088
0
        case JS_TAG_UNDEFINED:
7089
0
            return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop);
7090
0
        case JS_TAG_EXCEPTION:
7091
0
            return JS_EXCEPTION;
7092
13
        case JS_TAG_STRING:
7093
13
            {
7094
13
                JSString *p1 = JS_VALUE_GET_STRING(obj);
7095
13
                if (__JS_AtomIsTaggedInt(prop)) {
7096
0
                    uint32_t idx, ch;
7097
0
                    idx = __JS_AtomToUInt32(prop);
7098
0
                    if (idx < p1->len) {
7099
0
                        if (p1->is_wide_char)
7100
0
                            ch = p1->u.str16[idx];
7101
0
                        else
7102
0
                            ch = p1->u.str8[idx];
7103
0
                        return js_new_string_char(ctx, ch);
7104
0
                    }
7105
13
                } else if (prop == JS_ATOM_length) {
7106
2
                    return JS_NewInt32(ctx, p1->len);
7107
2
                }
7108
13
            }
7109
11
            break;
7110
11
        default:
7111
0
            break;
7112
13
        }
7113
        /* cannot raise an exception */
7114
11
        p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));
7115
11
        if (!p)
7116
0
            return JS_UNDEFINED;
7117
2.91M
    } else {
7118
2.91M
        p = JS_VALUE_GET_OBJ(obj);
7119
2.91M
    }
7120
7121
4.14M
    for(;;) {
7122
4.14M
        prs = find_own_property(&pr, p, prop);
7123
4.14M
        if (prs) {
7124
            /* found */
7125
2.07M
            if (unlikely(prs->flags & JS_PROP_TMASK)) {
7126
31
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
7127
0
                    if (unlikely(!pr->u.getset.getter)) {
7128
0
                        return JS_UNDEFINED;
7129
0
                    } else {
7130
0
                        JSValue func = JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter);
7131
                        /* Note: the field could be removed in the getter */
7132
0
                        func = JS_DupValue(ctx, func);
7133
0
                        return JS_CallFree(ctx, func, this_obj, 0, NULL);
7134
0
                    }
7135
31
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
7136
0
                    JSValue val = *pr->u.var_ref->pvalue;
7137
0
                    if (unlikely(JS_IsUninitialized(val)))
7138
0
                        return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7139
0
                    return JS_DupValue(ctx, val);
7140
31
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
7141
                    /* Instantiate property and retry */
7142
31
                    if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
7143
0
                        return JS_EXCEPTION;
7144
31
                    continue;
7145
31
                }
7146
2.07M
            } else {
7147
2.07M
                return JS_DupValue(ctx, pr->u.value);
7148
2.07M
            }
7149
2.07M
        }
7150
2.06M
        if (unlikely(p->is_exotic)) {
7151
            /* exotic behaviors */
7152
343k
            if (p->fast_array) {
7153
28
                if (__JS_AtomIsTaggedInt(prop)) {
7154
2
                    uint32_t idx = __JS_AtomToUInt32(prop);
7155
2
                    if (idx < p->u.array.count) {
7156
                        /* we avoid duplicating the code */
7157
0
                        return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
7158
2
                    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
7159
2
                               p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
7160
0
                        return JS_UNDEFINED;
7161
0
                    }
7162
26
                } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
7163
26
                           p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
7164
0
                    int ret;
7165
0
                    ret = JS_AtomIsNumericIndex(ctx, prop);
7166
0
                    if (ret != 0) {
7167
0
                        if (ret < 0)
7168
0
                            return JS_EXCEPTION;
7169
0
                        return JS_UNDEFINED;
7170
0
                    }
7171
0
                }
7172
343k
            } else {
7173
343k
                const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7174
343k
                if (em) {
7175
343k
                    if (em->get_property) {
7176
0
                        JSValue obj1, retval;
7177
                        /* XXX: should pass throw_ref_error */
7178
                        /* Note: if 'p' is a prototype, it can be
7179
                           freed in the called function */
7180
0
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7181
0
                        retval = em->get_property(ctx, obj1, prop, this_obj);
7182
0
                        JS_FreeValue(ctx, obj1);
7183
0
                        return retval;
7184
0
                    }
7185
343k
                    if (em->get_own_property) {
7186
343k
                        JSPropertyDescriptor desc;
7187
343k
                        int ret;
7188
343k
                        JSValue obj1;
7189
7190
                        /* Note: if 'p' is a prototype, it can be
7191
                           freed in the called function */
7192
343k
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7193
343k
                        ret = em->get_own_property(ctx, &desc, obj1, prop);
7194
343k
                        JS_FreeValue(ctx, obj1);
7195
343k
                        if (ret < 0)
7196
0
                            return JS_EXCEPTION;
7197
343k
                        if (ret) {
7198
343k
                            if (desc.flags & JS_PROP_GETSET) {
7199
0
                                JS_FreeValue(ctx, desc.setter);
7200
0
                                return JS_CallFree(ctx, desc.getter, this_obj, 0, NULL);
7201
343k
                            } else {
7202
343k
                                return desc.value;
7203
343k
                            }
7204
343k
                        }
7205
343k
                    }
7206
343k
                }
7207
343k
            }
7208
343k
        }
7209
1.72M
        p = p->shape->proto;
7210
1.72M
        if (!p)
7211
492k
            break;
7212
1.72M
    }
7213
492k
    if (unlikely(throw_ref_error)) {
7214
122k
        return JS_ThrowReferenceErrorNotDefined(ctx, prop);
7215
369k
    } else {
7216
369k
        return JS_UNDEFINED;
7217
369k
    }
7218
492k
}
7219
7220
static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom)
7221
0
{
7222
0
    return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist",
7223
0
                                 atom);
7224
0
}
7225
7226
/* Private fields can be added even on non extensible objects or
7227
   Proxies */
7228
static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj,
7229
                                 JSValueConst name, JSValue val)
7230
2
{
7231
2
    JSObject *p;
7232
2
    JSShapeProperty *prs;
7233
2
    JSProperty *pr;
7234
2
    JSAtom prop;
7235
7236
2
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
7237
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7238
0
        goto fail;
7239
0
    }
7240
    /* safety check */
7241
2
    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
7242
0
        JS_ThrowTypeErrorNotASymbol(ctx);
7243
0
        goto fail;
7244
0
    }
7245
2
    prop = js_symbol_to_atom(ctx, (JSValue)name);
7246
2
    p = JS_VALUE_GET_OBJ(obj);
7247
2
    prs = find_own_property(&pr, p, prop);
7248
2
    if (prs) {
7249
0
        JS_ThrowTypeErrorAtom(ctx, "private class field '%s' already exists",
7250
0
                              prop);
7251
0
        goto fail;
7252
0
    }
7253
2
    pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
7254
2
    if (unlikely(!pr)) {
7255
0
    fail:
7256
0
        JS_FreeValue(ctx, val);
7257
0
        return -1;
7258
0
    }
7259
2
    pr->u.value = val;
7260
2
    return 0;
7261
2
}
7262
7263
static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj,
7264
                                  JSValueConst name)
7265
0
{
7266
0
    JSObject *p;
7267
0
    JSShapeProperty *prs;
7268
0
    JSProperty *pr;
7269
0
    JSAtom prop;
7270
7271
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7272
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
7273
    /* safety check */
7274
0
    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL))
7275
0
        return JS_ThrowTypeErrorNotASymbol(ctx);
7276
0
    prop = js_symbol_to_atom(ctx, (JSValue)name);
7277
0
    p = JS_VALUE_GET_OBJ(obj);
7278
0
    prs = find_own_property(&pr, p, prop);
7279
0
    if (!prs) {
7280
0
        JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
7281
0
        return JS_EXCEPTION;
7282
0
    }
7283
0
    return JS_DupValue(ctx, pr->u.value);
7284
0
}
7285
7286
static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj,
7287
                              JSValueConst name, JSValue val)
7288
0
{
7289
0
    JSObject *p;
7290
0
    JSShapeProperty *prs;
7291
0
    JSProperty *pr;
7292
0
    JSAtom prop;
7293
7294
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
7295
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7296
0
        goto fail;
7297
0
    }
7298
    /* safety check */
7299
0
    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
7300
0
        JS_ThrowTypeErrorNotASymbol(ctx);
7301
0
        goto fail;
7302
0
    }
7303
0
    prop = js_symbol_to_atom(ctx, (JSValue)name);
7304
0
    p = JS_VALUE_GET_OBJ(obj);
7305
0
    prs = find_own_property(&pr, p, prop);
7306
0
    if (!prs) {
7307
0
        JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
7308
0
    fail:
7309
0
        JS_FreeValue(ctx, val);
7310
0
        return -1;
7311
0
    }
7312
0
    set_value(ctx, &pr->u.value, val);
7313
0
    return 0;
7314
0
}
7315
7316
static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
7317
0
{
7318
0
    JSObject *p, *p1;
7319
0
    JSShapeProperty *prs;
7320
0
    JSProperty *pr;
7321
0
    JSValue brand;
7322
0
    JSAtom brand_atom;
7323
    
7324
0
    if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) {
7325
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7326
0
        return -1;
7327
0
    }
7328
0
    p = JS_VALUE_GET_OBJ(home_obj);
7329
0
    prs = find_own_property(&pr, p, JS_ATOM_Private_brand);
7330
0
    if (!prs) {
7331
0
        brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE);
7332
0
        if (JS_IsException(brand))
7333
0
            return -1;
7334
        /* if the brand is not present, add it */
7335
0
        pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E);
7336
0
        if (!pr) {
7337
0
            JS_FreeValue(ctx, brand);
7338
0
            return -1;
7339
0
        }
7340
0
        pr->u.value = JS_DupValue(ctx, brand);
7341
0
    } else {
7342
0
        brand = JS_DupValue(ctx, pr->u.value);
7343
0
    }
7344
0
    brand_atom = js_symbol_to_atom(ctx, brand);
7345
    
7346
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
7347
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7348
0
        JS_FreeAtom(ctx, brand_atom);
7349
0
        return -1;
7350
0
    }
7351
0
    p1 = JS_VALUE_GET_OBJ(obj);
7352
0
    pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E);
7353
0
    JS_FreeAtom(ctx, brand_atom);
7354
0
    if (!pr)
7355
0
        return -1;
7356
0
    pr->u.value = JS_UNDEFINED;
7357
0
    return 0;
7358
0
}
7359
7360
static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
7361
0
{
7362
0
    JSObject *p, *p1, *home_obj;
7363
0
    JSShapeProperty *prs;
7364
0
    JSProperty *pr;
7365
0
    JSValueConst brand;
7366
    
7367
    /* get the home object of 'func' */
7368
0
    if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) {
7369
0
    not_obj:
7370
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7371
0
        return -1;
7372
0
    }
7373
0
    p1 = JS_VALUE_GET_OBJ(func);
7374
0
    if (!js_class_has_bytecode(p1->class_id))
7375
0
        goto not_obj;
7376
0
    home_obj = p1->u.func.home_object;
7377
0
    if (!home_obj)
7378
0
        goto not_obj;
7379
0
    prs = find_own_property(&pr, home_obj, JS_ATOM_Private_brand);
7380
0
    if (!prs) {
7381
0
        JS_ThrowTypeError(ctx, "expecting <brand> private field");
7382
0
        return -1;
7383
0
    }
7384
0
    brand = pr->u.value;
7385
    /* safety check */
7386
0
    if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL))
7387
0
        goto not_obj;
7388
    
7389
    /* get the brand array of 'obj' */
7390
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7391
0
        goto not_obj;
7392
0
    p = JS_VALUE_GET_OBJ(obj);
7393
0
    prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand));
7394
0
    if (!prs) {
7395
0
        JS_ThrowTypeError(ctx, "invalid brand on object");
7396
0
        return -1;
7397
0
    }
7398
0
    return 0;
7399
0
}
7400
7401
static uint32_t js_string_obj_get_length(JSContext *ctx,
7402
                                         JSValueConst obj)
7403
22
{
7404
22
    JSObject *p;
7405
22
    JSString *p1;
7406
22
    uint32_t len = 0;
7407
7408
    /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
7409
22
    p = JS_VALUE_GET_OBJ(obj);
7410
22
    if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
7411
22
        p1 = JS_VALUE_GET_STRING(p->u.object_data);
7412
22
        len = p1->len;
7413
22
    }
7414
22
    return len;
7415
22
}
7416
7417
static int num_keys_cmp(const void *p1, const void *p2, void *opaque)
7418
17.8M
{
7419
17.8M
    JSContext *ctx = opaque;
7420
17.8M
    JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom;
7421
17.8M
    JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom;
7422
17.8M
    uint32_t v1, v2;
7423
17.8M
    BOOL atom1_is_integer, atom2_is_integer;
7424
7425
17.8M
    atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1);
7426
17.8M
    atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2);
7427
17.8M
    assert(atom1_is_integer && atom2_is_integer);
7428
17.8M
    if (v1 < v2)
7429
9.60M
        return -1;
7430
8.22M
    else if (v1 == v2)
7431
0
        return 0;
7432
8.22M
    else
7433
8.22M
        return 1;
7434
17.8M
}
7435
7436
static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
7437
35
{
7438
35
    uint32_t i;
7439
35
    if (tab) {
7440
1.60M
        for(i = 0; i < len; i++)
7441
1.60M
            JS_FreeAtom(ctx, tab[i].atom);
7442
35
        js_free(ctx, tab);
7443
35
    }
7444
35
}
7445
7446
/* return < 0 in case if exception, 0 if OK. ptab and its atoms must
7447
   be freed by the user. */
7448
static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
7449
                                                      JSPropertyEnum **ptab,
7450
                                                      uint32_t *plen,
7451
                                                      JSObject *p, int flags)
7452
35
{
7453
35
    int i, j;
7454
35
    JSShape *sh;
7455
35
    JSShapeProperty *prs;
7456
35
    JSPropertyEnum *tab_atom, *tab_exotic;
7457
35
    JSAtom atom;
7458
35
    uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count;
7459
35
    uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count;
7460
35
    BOOL is_enumerable, num_sorted;
7461
35
    uint32_t num_key;
7462
35
    JSAtomKindEnum kind;
7463
    
7464
    /* clear pointer for consistency in case of failure */
7465
35
    *ptab = NULL;
7466
35
    *plen = 0;
7467
7468
    /* compute the number of returned properties */
7469
35
    num_keys_count = 0;
7470
35
    str_keys_count = 0;
7471
35
    sym_keys_count = 0;
7472
35
    exotic_keys_count = 0;
7473
35
    exotic_count = 0;
7474
35
    tab_exotic = NULL;
7475
35
    sh = p->shape;
7476
1.25M
    for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
7477
1.25M
        atom = prs->atom;
7478
1.25M
        if (atom != JS_ATOM_NULL) {
7479
1.25M
            is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
7480
1.25M
            kind = JS_AtomGetKind(ctx, atom);
7481
1.25M
            if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
7482
1.25M
                ((flags >> kind) & 1) != 0) {
7483
                /* need to raise an exception in case of the module
7484
                   name space (implicit GetOwnProperty) */
7485
1.25M
                if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) &&
7486
1.25M
                    (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY))) {
7487
0
                    JSVarRef *var_ref = p->prop[i].u.var_ref;
7488
0
                    if (unlikely(JS_IsUninitialized(*var_ref->pvalue))) {
7489
0
                        JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7490
0
                        return -1;
7491
0
                    }
7492
0
                }
7493
1.25M
                if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
7494
1.25M
                    num_keys_count++;
7495
1.25M
                } else if (kind == JS_ATOM_KIND_STRING) {
7496
4
                    str_keys_count++;
7497
4
                } else {
7498
0
                    sym_keys_count++;
7499
0
                }
7500
1.25M
            }
7501
1.25M
        }
7502
1.25M
    }
7503
7504
35
    if (p->is_exotic) {
7505
11
        if (p->fast_array) {
7506
0
            if (flags & JS_GPN_STRING_MASK) {
7507
0
                num_keys_count += p->u.array.count;
7508
0
            }
7509
11
        } else if (p->class_id == JS_CLASS_STRING) {
7510
11
            if (flags & JS_GPN_STRING_MASK) {
7511
11
                num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7512
11
            }
7513
11
        } else {
7514
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7515
0
            if (em && em->get_own_property_names) {
7516
0
                if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count,
7517
0
                                               JS_MKPTR(JS_TAG_OBJECT, p)))
7518
0
                    return -1;
7519
0
                for(i = 0; i < exotic_count; i++) {
7520
0
                    atom = tab_exotic[i].atom;
7521
0
                    kind = JS_AtomGetKind(ctx, atom);
7522
0
                    if (((flags >> kind) & 1) != 0) {
7523
0
                        is_enumerable = FALSE;
7524
0
                        if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) {
7525
0
                            JSPropertyDescriptor desc;
7526
0
                            int res;
7527
                            /* set the "is_enumerable" field if necessary */
7528
0
                            res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
7529
0
                            if (res < 0) {
7530
0
                                js_free_prop_enum(ctx, tab_exotic, exotic_count);
7531
0
                                return -1;
7532
0
                            }
7533
0
                            if (res) {
7534
0
                                is_enumerable =
7535
0
                                    ((desc.flags & JS_PROP_ENUMERABLE) != 0);
7536
0
                                js_free_desc(ctx, &desc);
7537
0
                            }
7538
0
                            tab_exotic[i].is_enumerable = is_enumerable;
7539
0
                        }
7540
0
                        if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) {
7541
0
                            exotic_keys_count++;
7542
0
                        }
7543
0
                    }
7544
0
                }
7545
0
            }
7546
0
        }
7547
11
    }
7548
7549
    /* fill them */
7550
7551
35
    atom_count = num_keys_count + str_keys_count + sym_keys_count + exotic_keys_count;
7552
    /* avoid allocating 0 bytes */
7553
35
    tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));
7554
35
    if (!tab_atom) {
7555
0
        js_free_prop_enum(ctx, tab_exotic, exotic_count);
7556
0
        return -1;
7557
0
    }
7558
7559
35
    num_index = 0;
7560
35
    str_index = num_keys_count;
7561
35
    sym_index = str_index + str_keys_count;
7562
7563
35
    num_sorted = TRUE;
7564
35
    sh = p->shape;
7565
1.25M
    for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
7566
1.25M
        atom = prs->atom;
7567
1.25M
        if (atom != JS_ATOM_NULL) {
7568
1.25M
            is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
7569
1.25M
            kind = JS_AtomGetKind(ctx, atom);
7570
1.25M
            if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
7571
1.25M
                ((flags >> kind) & 1) != 0) {
7572
1.25M
                if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
7573
1.25M
                    j = num_index++;
7574
1.25M
                    num_sorted = FALSE;
7575
1.25M
                } else if (kind == JS_ATOM_KIND_STRING) {
7576
4
                    j = str_index++;
7577
4
                } else {
7578
0
                    j = sym_index++;
7579
0
                }
7580
1.25M
                tab_atom[j].atom = JS_DupAtom(ctx, atom);
7581
1.25M
                tab_atom[j].is_enumerable = is_enumerable;
7582
1.25M
            }
7583
1.25M
        }
7584
1.25M
    }
7585
7586
35
    if (p->is_exotic) {
7587
11
        int len;
7588
11
        if (p->fast_array) {
7589
0
            if (flags & JS_GPN_STRING_MASK) {
7590
0
                len = p->u.array.count;
7591
0
                goto add_array_keys;
7592
0
            }
7593
11
        } else if (p->class_id == JS_CLASS_STRING) {
7594
11
            if (flags & JS_GPN_STRING_MASK) {
7595
11
                len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7596
11
            add_array_keys:
7597
343k
                for(i = 0; i < len; i++) {
7598
343k
                    tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
7599
343k
                    if (tab_atom[num_index].atom == JS_ATOM_NULL) {
7600
0
                        js_free_prop_enum(ctx, tab_atom, num_index);
7601
0
                        return -1;
7602
0
                    }
7603
343k
                    tab_atom[num_index].is_enumerable = TRUE;
7604
343k
                    num_index++;
7605
343k
                }
7606
11
            }
7607
11
        } else {
7608
            /* Note: exotic keys are not reordered and comes after the object own properties. */
7609
0
            for(i = 0; i < exotic_count; i++) {
7610
0
                atom = tab_exotic[i].atom;
7611
0
                is_enumerable = tab_exotic[i].is_enumerable;
7612
0
                kind = JS_AtomGetKind(ctx, atom);
7613
0
                if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
7614
0
                    ((flags >> kind) & 1) != 0) {
7615
0
                    tab_atom[sym_index].atom = atom;
7616
0
                    tab_atom[sym_index].is_enumerable = is_enumerable;
7617
0
                    sym_index++;
7618
0
                } else {
7619
0
                    JS_FreeAtom(ctx, atom);
7620
0
                }
7621
0
            }
7622
0
            js_free(ctx, tab_exotic);
7623
0
        }
7624
11
    }
7625
7626
35
    assert(num_index == num_keys_count);
7627
35
    assert(str_index == num_keys_count + str_keys_count);
7628
35
    assert(sym_index == atom_count);
7629
7630
35
    if (num_keys_count != 0 && !num_sorted) {
7631
19
        rqsort(tab_atom, num_keys_count, sizeof(tab_atom[0]), num_keys_cmp,
7632
19
               ctx);
7633
19
    }
7634
35
    *ptab = tab_atom;
7635
35
    *plen = atom_count;
7636
35
    return 0;
7637
35
}
7638
7639
int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
7640
                           uint32_t *plen, JSValueConst obj, int flags)
7641
0
{
7642
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
7643
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7644
0
        return -1;
7645
0
    }
7646
0
    return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
7647
0
                                          JS_VALUE_GET_OBJ(obj), flags);
7648
0
}
7649
7650
/* Return -1 if exception,
7651
   FALSE if the property does not exist, TRUE if it exists. If TRUE is
7652
   returned, the property descriptor 'desc' is filled present. */
7653
static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
7654
                                     JSObject *p, JSAtom prop)
7655
1.25M
{
7656
1.25M
    JSShapeProperty *prs;
7657
1.25M
    JSProperty *pr;
7658
7659
1.25M
retry:
7660
1.25M
    prs = find_own_property(&pr, p, prop);
7661
1.25M
    if (prs) {
7662
38
        if (desc) {
7663
4
            desc->flags = prs->flags & JS_PROP_C_W_E;
7664
4
            desc->getter = JS_UNDEFINED;
7665
4
            desc->setter = JS_UNDEFINED;
7666
4
            desc->value = JS_UNDEFINED;
7667
4
            if (unlikely(prs->flags & JS_PROP_TMASK)) {
7668
0
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
7669
0
                    desc->flags |= JS_PROP_GETSET;
7670
0
                    if (pr->u.getset.getter)
7671
0
                        desc->getter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
7672
0
                    if (pr->u.getset.setter)
7673
0
                        desc->setter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
7674
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
7675
0
                    JSValue val = *pr->u.var_ref->pvalue;
7676
0
                    if (unlikely(JS_IsUninitialized(val))) {
7677
0
                        JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7678
0
                        return -1;
7679
0
                    }
7680
0
                    desc->value = JS_DupValue(ctx, val);
7681
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
7682
                    /* Instantiate property and retry */
7683
0
                    if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
7684
0
                        return -1;
7685
0
                    goto retry;
7686
0
                }
7687
4
            } else {
7688
4
                desc->value = JS_DupValue(ctx, pr->u.value);
7689
4
            }
7690
34
        } else {
7691
            /* for consistency, send the exception even if desc is NULL */
7692
34
            if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF)) {
7693
0
                if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) {
7694
0
                    JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7695
0
                    return -1;
7696
0
                }
7697
34
            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
7698
                /* nothing to do: delay instantiation until actual value and/or attributes are read */
7699
0
            }
7700
34
        }
7701
38
        return TRUE;
7702
38
    }
7703
1.25M
    if (p->is_exotic) {
7704
30
        if (p->fast_array) {
7705
            /* specific case for fast arrays */
7706
0
            if (__JS_AtomIsTaggedInt(prop)) {
7707
0
                uint32_t idx;
7708
0
                idx = __JS_AtomToUInt32(prop);
7709
0
                if (idx < p->u.array.count) {
7710
0
                    if (desc) {
7711
0
                        desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE |
7712
0
                            JS_PROP_CONFIGURABLE;
7713
0
                        desc->getter = JS_UNDEFINED;
7714
0
                        desc->setter = JS_UNDEFINED;
7715
0
                        desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
7716
0
                    }
7717
0
                    return TRUE;
7718
0
                }
7719
0
            }
7720
30
        } else {
7721
30
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7722
30
            if (em && em->get_own_property) {
7723
30
                return em->get_own_property(ctx, desc,
7724
30
                                            JS_MKPTR(JS_TAG_OBJECT, p), prop);
7725
30
            }
7726
30
        }
7727
30
    }
7728
1.25M
    return FALSE;
7729
1.25M
}
7730
7731
int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
7732
                      JSValueConst obj, JSAtom prop)
7733
0
{
7734
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
7735
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7736
0
        return -1;
7737
0
    }
7738
0
    return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop);
7739
0
}
7740
7741
/* return -1 if exception (Proxy object only) or TRUE/FALSE */
7742
int JS_IsExtensible(JSContext *ctx, JSValueConst obj)
7743
0
{
7744
0
    JSObject *p;
7745
7746
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7747
0
        return FALSE;
7748
0
    p = JS_VALUE_GET_OBJ(obj);
7749
0
    if (unlikely(p->class_id == JS_CLASS_PROXY))
7750
0
        return js_proxy_isExtensible(ctx, obj);
7751
0
    else
7752
0
        return p->extensible;
7753
0
}
7754
7755
/* return -1 if exception (Proxy object only) or TRUE/FALSE */
7756
int JS_PreventExtensions(JSContext *ctx, JSValueConst obj)
7757
2
{
7758
2
    JSObject *p;
7759
7760
2
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7761
0
        return FALSE;
7762
2
    p = JS_VALUE_GET_OBJ(obj);
7763
2
    if (unlikely(p->class_id == JS_CLASS_PROXY))
7764
0
        return js_proxy_preventExtensions(ctx, obj);
7765
2
    p->extensible = FALSE;
7766
2
    return TRUE;
7767
2
}
7768
7769
/* return -1 if exception otherwise TRUE or FALSE */
7770
int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop)
7771
285
{
7772
285
    JSObject *p;
7773
285
    int ret;
7774
285
    JSValue obj1;
7775
7776
285
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7777
0
        return FALSE;
7778
285
    p = JS_VALUE_GET_OBJ(obj);
7779
724
    for(;;) {
7780
724
        if (p->is_exotic) {
7781
30
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7782
30
            if (em && em->has_property) {
7783
                /* has_property can free the prototype */
7784
0
                obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7785
0
                ret = em->has_property(ctx, obj1, prop);
7786
0
                JS_FreeValue(ctx, obj1);
7787
0
                return ret;
7788
0
            }
7789
30
        }
7790
        /* JS_GetOwnPropertyInternal can free the prototype */
7791
724
        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7792
724
        ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop);
7793
724
        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7794
724
        if (ret != 0)
7795
64
            return ret;
7796
660
        if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
7797
660
            p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
7798
0
            ret = JS_AtomIsNumericIndex(ctx, prop);
7799
0
            if (ret != 0) {
7800
0
                if (ret < 0)
7801
0
                    return -1;
7802
0
                return FALSE;
7803
0
            }
7804
0
        }
7805
660
        p = p->shape->proto;
7806
660
        if (!p)
7807
221
            break;
7808
660
    }
7809
221
    return FALSE;
7810
285
}
7811
7812
/* val must be a symbol */
7813
static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val)
7814
2
{
7815
2
    JSAtomStruct *p = JS_VALUE_GET_PTR(val);
7816
2
    return js_get_atom_index(ctx->rt, p);
7817
2
}
7818
7819
/* return JS_ATOM_NULL in case of exception */
7820
JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
7821
200k
{
7822
200k
    JSAtom atom;
7823
200k
    uint32_t tag;
7824
200k
    tag = JS_VALUE_GET_TAG(val);
7825
200k
    if (tag == JS_TAG_INT &&
7826
200k
        (uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) {
7827
        /* fast path for integer values */
7828
153k
        atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val));
7829
153k
    } else if (tag == JS_TAG_SYMBOL) {
7830
0
        JSAtomStruct *p = JS_VALUE_GET_PTR(val);
7831
0
        atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p));
7832
46.9k
    } else {
7833
46.9k
        JSValue str;
7834
46.9k
        str = JS_ToPropertyKey(ctx, val);
7835
46.9k
        if (JS_IsException(str))
7836
0
            return JS_ATOM_NULL;
7837
46.9k
        if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) {
7838
0
            atom = js_symbol_to_atom(ctx, str);
7839
46.9k
        } else {
7840
46.9k
            atom = JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(str));
7841
46.9k
        }
7842
46.9k
    }
7843
200k
    return atom;
7844
200k
}
7845
7846
static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
7847
                                   JSValue prop)
7848
152k
{
7849
152k
    JSAtom atom;
7850
152k
    JSValue ret;
7851
7852
152k
    if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
7853
152k
               JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
7854
152k
        JSObject *p;
7855
152k
        uint32_t idx, len;
7856
        /* fast path for array access */
7857
152k
        p = JS_VALUE_GET_OBJ(this_obj);
7858
152k
        idx = JS_VALUE_GET_INT(prop);
7859
152k
        len = (uint32_t)p->u.array.count;
7860
152k
        if (unlikely(idx >= len))
7861
8
            goto slow_path;
7862
152k
        switch(p->class_id) {
7863
152k
        case JS_CLASS_ARRAY:
7864
152k
        case JS_CLASS_ARGUMENTS:
7865
152k
            return JS_DupValue(ctx, p->u.array.u.values[idx]);
7866
0
        case JS_CLASS_INT8_ARRAY:
7867
0
            return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]);
7868
0
        case JS_CLASS_UINT8C_ARRAY:
7869
0
        case JS_CLASS_UINT8_ARRAY:
7870
0
            return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]);
7871
0
        case JS_CLASS_INT16_ARRAY:
7872
0
            return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]);
7873
0
        case JS_CLASS_UINT16_ARRAY:
7874
0
            return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]);
7875
0
        case JS_CLASS_INT32_ARRAY:
7876
0
            return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]);
7877
0
        case JS_CLASS_UINT32_ARRAY:
7878
0
            return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]);
7879
0
#ifdef CONFIG_BIGNUM
7880
0
        case JS_CLASS_BIG_INT64_ARRAY:
7881
0
            return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
7882
0
        case JS_CLASS_BIG_UINT64_ARRAY:
7883
0
            return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
7884
0
#endif
7885
0
        case JS_CLASS_FLOAT32_ARRAY:
7886
0
            return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]);
7887
0
        case JS_CLASS_FLOAT64_ARRAY:
7888
0
            return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]);
7889
0
        default:
7890
0
            goto slow_path;
7891
152k
        }
7892
152k
    } else {
7893
8
    slow_path:
7894
8
        atom = JS_ValueToAtom(ctx, prop);
7895
8
        JS_FreeValue(ctx, prop);
7896
8
        if (unlikely(atom == JS_ATOM_NULL))
7897
0
            return JS_EXCEPTION;
7898
8
        ret = JS_GetProperty(ctx, this_obj, atom);
7899
8
        JS_FreeAtom(ctx, atom);
7900
8
        return ret;
7901
8
    }
7902
152k
}
7903
7904
JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
7905
                             uint32_t idx)
7906
152k
{
7907
152k
    return JS_GetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx));
7908
152k
}
7909
7910
/* Check if an object has a generalized numeric property. Return value:
7911
   -1 for exception,
7912
   TRUE if property exists, stored into *pval,
7913
   FALSE if proprty does not exist.
7914
 */
7915
static int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, JSValue *pval)
7916
0
{
7917
0
    JSValue val = JS_UNDEFINED;
7918
0
    JSAtom prop;
7919
0
    int present;
7920
7921
0
    if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) {
7922
        /* fast path */
7923
0
        present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx));
7924
0
        if (present > 0) {
7925
0
            val = JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
7926
0
            if (unlikely(JS_IsException(val)))
7927
0
                present = -1;
7928
0
        }
7929
0
    } else {
7930
0
        prop = JS_NewAtomInt64(ctx, idx);
7931
0
        present = -1;
7932
0
        if (likely(prop != JS_ATOM_NULL)) {
7933
0
            present = JS_HasProperty(ctx, obj, prop);
7934
0
            if (present > 0) {
7935
0
                val = JS_GetProperty(ctx, obj, prop);
7936
0
                if (unlikely(JS_IsException(val)))
7937
0
                    present = -1;
7938
0
            }
7939
0
            JS_FreeAtom(ctx, prop);
7940
0
        }
7941
0
    }
7942
0
    *pval = val;
7943
0
    return present;
7944
0
}
7945
7946
static JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx)
7947
0
{
7948
0
    JSAtom prop;
7949
0
    JSValue val;
7950
7951
0
    if ((uint64_t)idx <= INT32_MAX) {
7952
        /* fast path for fast arrays */
7953
0
        return JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
7954
0
    }
7955
0
    prop = JS_NewAtomInt64(ctx, idx);
7956
0
    if (prop == JS_ATOM_NULL)
7957
0
        return JS_EXCEPTION;
7958
7959
0
    val = JS_GetProperty(ctx, obj, prop);
7960
0
    JS_FreeAtom(ctx, prop);
7961
0
    return val;
7962
0
}
7963
7964
JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
7965
                          const char *prop)
7966
1
{
7967
1
    JSAtom atom;
7968
1
    JSValue ret;
7969
1
    atom = JS_NewAtom(ctx, prop);
7970
1
    ret = JS_GetProperty(ctx, this_obj, atom);
7971
1
    JS_FreeAtom(ctx, atom);
7972
1
    return ret;
7973
1
}
7974
7975
/* Note: the property value is not initialized. Return NULL if memory
7976
   error. */
7977
static JSProperty *add_property(JSContext *ctx,
7978
                                JSObject *p, JSAtom prop, int prop_flags)
7979
3.58M
{
7980
3.58M
    JSShape *sh, *new_sh;
7981
7982
3.58M
    sh = p->shape;
7983
3.58M
    if (sh->is_hashed) {
7984
        /* try to find an existing shape */
7985
3.58M
        new_sh = find_hashed_shape_prop(ctx->rt, sh, prop, prop_flags);
7986
3.58M
        if (new_sh) {
7987
            /* matching shape found: use it */
7988
            /*  the property array may need to be resized */
7989
1.03M
            if (new_sh->prop_size != sh->prop_size) {
7990
165k
                JSProperty *new_prop;
7991
165k
                new_prop = js_realloc(ctx, p->prop, sizeof(p->prop[0]) *
7992
165k
                                      new_sh->prop_size);
7993
165k
                if (!new_prop)
7994
0
                    return NULL;
7995
165k
                p->prop = new_prop;
7996
165k
            }
7997
1.03M
            p->shape = js_dup_shape(new_sh);
7998
1.03M
            js_free_shape(ctx->rt, sh);
7999
1.03M
            return &p->prop[new_sh->prop_count - 1];
8000
2.55M
        } else if (sh->header.ref_count != 1) {
8001
            /* if the shape is shared, clone it */
8002
655k
            new_sh = js_clone_shape(ctx, sh);
8003
655k
            if (!new_sh)
8004
0
                return NULL;
8005
            /* hash the cloned shape */
8006
655k
            new_sh->is_hashed = TRUE;
8007
655k
            js_shape_hash_link(ctx->rt, new_sh);
8008
655k
            js_free_shape(ctx->rt, p->shape);
8009
655k
            p->shape = new_sh;
8010
655k
        }
8011
3.58M
    }
8012
2.55M
    assert(p->shape->header.ref_count == 1);
8013
2.55M
    if (add_shape_property(ctx, &p->shape, p, prop, prop_flags))
8014
0
        return NULL;
8015
2.55M
    return &p->prop[p->shape->prop_count - 1];
8016
2.55M
}
8017
8018
/* can be called on Array or Arguments objects. return < 0 if
8019
   memory alloc error. */
8020
static no_inline __exception int convert_fast_array_to_array(JSContext *ctx,
8021
                                                             JSObject *p)
8022
606
{
8023
606
    JSProperty *pr;
8024
606
    JSShape *sh;
8025
606
    JSValue *tab;
8026
606
    uint32_t i, len, new_count;
8027
8028
606
    if (js_shape_prepare_update(ctx, p, NULL))
8029
0
        return -1;
8030
606
    len = p->u.array.count;
8031
    /* resize the properties once to simplify the error handling */
8032
606
    sh = p->shape;
8033
606
    new_count = sh->prop_count + len;
8034
606
    if (new_count > sh->prop_size) {
8035
0
        if (resize_properties(ctx, &p->shape, p, new_count))
8036
0
            return -1;
8037
0
    }
8038
8039
606
    tab = p->u.array.u.values;
8040
606
    for(i = 0; i < len; i++) {
8041
        /* add_property cannot fail here but
8042
           __JS_AtomFromUInt32(i) fails for i > INT32_MAX */
8043
0
        pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E);
8044
0
        pr->u.value = *tab++;
8045
0
    }
8046
606
    js_free(ctx, p->u.array.u.values);
8047
606
    p->u.array.count = 0;
8048
606
    p->u.array.u.values = NULL; /* fail safe */
8049
606
    p->u.array.u1.size = 0;
8050
606
    p->fast_array = 0;
8051
606
    return 0;
8052
606
}
8053
8054
static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom)
8055
0
{
8056
0
    JSShape *sh;
8057
0
    JSShapeProperty *pr, *lpr, *prop;
8058
0
    JSProperty *pr1;
8059
0
    uint32_t lpr_idx;
8060
0
    intptr_t h, h1;
8061
8062
0
 redo:
8063
0
    sh = p->shape;
8064
0
    h1 = atom & sh->prop_hash_mask;
8065
0
    h = prop_hash_end(sh)[-h1 - 1];
8066
0
    prop = get_shape_prop(sh);
8067
0
    lpr = NULL;
8068
0
    lpr_idx = 0;   /* prevent warning */
8069
0
    while (h != 0) {
8070
0
        pr = &prop[h - 1];
8071
0
        if (likely(pr->atom == atom)) {
8072
            /* found ! */
8073
0
            if (!(pr->flags & JS_PROP_CONFIGURABLE))
8074
0
                return FALSE;
8075
            /* realloc the shape if needed */
8076
0
            if (lpr)
8077
0
                lpr_idx = lpr - get_shape_prop(sh);
8078
0
            if (js_shape_prepare_update(ctx, p, &pr))
8079
0
                return -1;
8080
0
            sh = p->shape;
8081
            /* remove property */
8082
0
            if (lpr) {
8083
0
                lpr = get_shape_prop(sh) + lpr_idx;
8084
0
                lpr->hash_next = pr->hash_next;
8085
0
            } else {
8086
0
                prop_hash_end(sh)[-h1 - 1] = pr->hash_next;
8087
0
            }
8088
0
            sh->deleted_prop_count++;
8089
            /* free the entry */
8090
0
            pr1 = &p->prop[h - 1];
8091
0
            free_property(ctx->rt, pr1, pr->flags);
8092
0
            JS_FreeAtom(ctx, pr->atom);
8093
            /* put default values */
8094
0
            pr->flags = 0;
8095
0
            pr->atom = JS_ATOM_NULL;
8096
0
            pr1->u.value = JS_UNDEFINED;
8097
8098
            /* compact the properties if too many deleted properties */
8099
0
            if (sh->deleted_prop_count >= 8 &&
8100
0
                sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) {
8101
0
                compact_properties(ctx, p);
8102
0
            }
8103
0
            return TRUE;
8104
0
        }
8105
0
        lpr = pr;
8106
0
        h = pr->hash_next;
8107
0
    }
8108
8109
0
    if (p->is_exotic) {
8110
0
        if (p->fast_array) {
8111
0
            uint32_t idx;
8112
0
            if (JS_AtomIsArrayIndex(ctx, &idx, atom) &&
8113
0
                idx < p->u.array.count) {
8114
0
                if (p->class_id == JS_CLASS_ARRAY ||
8115
0
                    p->class_id == JS_CLASS_ARGUMENTS) {
8116
                    /* Special case deleting the last element of a fast Array */
8117
0
                    if (idx == p->u.array.count - 1) {
8118
0
                        JS_FreeValue(ctx, p->u.array.u.values[idx]);
8119
0
                        p->u.array.count = idx;
8120
0
                        return TRUE;
8121
0
                    }
8122
0
                    if (convert_fast_array_to_array(ctx, p))
8123
0
                        return -1;
8124
0
                    goto redo;
8125
0
                } else {
8126
0
                    return FALSE;
8127
0
                }
8128
0
            }
8129
0
        } else {
8130
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8131
0
            if (em && em->delete_property) {
8132
0
                return em->delete_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), atom);
8133
0
            }
8134
0
        }
8135
0
    }
8136
    /* not found */
8137
0
    return TRUE;
8138
0
}
8139
8140
static int call_setter(JSContext *ctx, JSObject *setter,
8141
                       JSValueConst this_obj, JSValue val, int flags)
8142
0
{
8143
0
    JSValue ret, func;
8144
0
    if (likely(setter)) {
8145
0
        func = JS_MKPTR(JS_TAG_OBJECT, setter);
8146
        /* Note: the field could be removed in the setter */
8147
0
        func = JS_DupValue(ctx, func);
8148
0
        ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst *)&val);
8149
0
        JS_FreeValue(ctx, val);
8150
0
        if (JS_IsException(ret))
8151
0
            return -1;
8152
0
        JS_FreeValue(ctx, ret);
8153
0
        return TRUE;
8154
0
    } else {
8155
0
        JS_FreeValue(ctx, val);
8156
0
        if ((flags & JS_PROP_THROW) ||
8157
0
            ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
8158
0
            JS_ThrowTypeError(ctx, "no setter for property");
8159
0
            return -1;
8160
0
        }
8161
0
        return FALSE;
8162
0
    }
8163
0
}
8164
8165
/* set the array length and remove the array elements if necessary. */
8166
static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
8167
                            int flags)
8168
81.9k
{
8169
81.9k
    uint32_t len, idx, cur_len;
8170
81.9k
    int i, ret;
8171
8172
    /* Note: this call can reallocate the properties of 'p' */
8173
81.9k
    ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE);
8174
81.9k
    if (ret)
8175
0
        return -1;
8176
    /* JS_ToArrayLengthFree() must be done before the read-only test */
8177
81.9k
    if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE)))
8178
0
        return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
8179
8180
81.9k
    if (likely(p->fast_array)) {
8181
81.9k
        uint32_t old_len = p->u.array.count;
8182
81.9k
        if (len < old_len) {
8183
0
            for(i = len; i < old_len; i++) {
8184
0
                JS_FreeValue(ctx, p->u.array.u.values[i]);
8185
0
            }
8186
0
            p->u.array.count = len;
8187
0
        }
8188
81.9k
        p->prop[0].u.value = JS_NewUint32(ctx, len);
8189
81.9k
    } else {
8190
        /* Note: length is always a uint32 because the object is an
8191
           array */
8192
0
        JS_ToUint32(ctx, &cur_len, p->prop[0].u.value);
8193
0
        if (len < cur_len) {
8194
0
            uint32_t d;
8195
0
            JSShape *sh;
8196
0
            JSShapeProperty *pr;
8197
8198
0
            d = cur_len - len;
8199
0
            sh = p->shape;
8200
0
            if (d <= sh->prop_count) {
8201
0
                JSAtom atom;
8202
8203
                /* faster to iterate */
8204
0
                while (cur_len > len) {
8205
0
                    atom = JS_NewAtomUInt32(ctx, cur_len - 1);
8206
0
                    ret = delete_property(ctx, p, atom);
8207
0
                    JS_FreeAtom(ctx, atom);
8208
0
                    if (unlikely(!ret)) {
8209
                        /* unlikely case: property is not
8210
                           configurable */
8211
0
                        break;
8212
0
                    }
8213
0
                    cur_len--;
8214
0
                }
8215
0
            } else {
8216
                /* faster to iterate thru all the properties. Need two
8217
                   passes in case one of the property is not
8218
                   configurable */
8219
0
                cur_len = len;
8220
0
                for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
8221
0
                    i++, pr++) {
8222
0
                    if (pr->atom != JS_ATOM_NULL &&
8223
0
                        JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
8224
0
                        if (idx >= cur_len &&
8225
0
                            !(pr->flags & JS_PROP_CONFIGURABLE)) {
8226
0
                            cur_len = idx + 1;
8227
0
                        }
8228
0
                    }
8229
0
                }
8230
8231
0
                for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
8232
0
                    i++, pr++) {
8233
0
                    if (pr->atom != JS_ATOM_NULL &&
8234
0
                        JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
8235
0
                        if (idx >= cur_len) {
8236
                            /* remove the property */
8237
0
                            delete_property(ctx, p, pr->atom);
8238
                            /* WARNING: the shape may have been modified */
8239
0
                            sh = p->shape;
8240
0
                            pr = get_shape_prop(sh) + i;
8241
0
                        }
8242
0
                    }
8243
0
                }
8244
0
            }
8245
0
        } else {
8246
0
            cur_len = len;
8247
0
        }
8248
0
        set_value(ctx, &p->prop[0].u.value, JS_NewUint32(ctx, cur_len));
8249
0
        if (unlikely(cur_len > len)) {
8250
0
            return JS_ThrowTypeErrorOrFalse(ctx, flags, "not configurable");
8251
0
        }
8252
0
    }
8253
81.9k
    return TRUE;
8254
81.9k
}
8255
8256
/* return -1 if exception */
8257
static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len)
8258
57
{
8259
57
    uint32_t new_size;
8260
57
    size_t slack;
8261
57
    JSValue *new_array_prop;
8262
    /* XXX: potential arithmetic overflow */
8263
57
    new_size = max_int(new_len, p->u.array.u1.size * 3 / 2);
8264
57
    new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack);
8265
57
    if (!new_array_prop)
8266
0
        return -1;
8267
57
    new_size += slack / sizeof(*new_array_prop);
8268
57
    p->u.array.u.values = new_array_prop;
8269
57
    p->u.array.u1.size = new_size;
8270
57
    return 0;
8271
57
}
8272
8273
/* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array =
8274
   TRUE and p->extensible = TRUE */
8275
static int add_fast_array_element(JSContext *ctx, JSObject *p,
8276
                                  JSValue val, int flags)
8277
152k
{
8278
152k
    uint32_t new_len, array_len;
8279
    /* extend the array by one */
8280
    /* XXX: convert to slow array if new_len > 2^31-1 elements */
8281
152k
    new_len = p->u.array.count + 1;
8282
    /* update the length if necessary. We assume that if the length is
8283
       not an integer, then if it >= 2^31.  */
8284
152k
    if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) {
8285
152k
        array_len = JS_VALUE_GET_INT(p->prop[0].u.value);
8286
152k
        if (new_len > array_len) {
8287
152k
            if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) {
8288
0
                JS_FreeValue(ctx, val);
8289
0
                return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
8290
0
            }
8291
152k
            p->prop[0].u.value = JS_NewInt32(ctx, new_len);
8292
152k
        }
8293
152k
    }
8294
152k
    if (unlikely(new_len > p->u.array.u1.size)) {
8295
57
        if (expand_fast_array(ctx, p, new_len)) {
8296
0
            JS_FreeValue(ctx, val);
8297
0
            return -1;
8298
0
        }
8299
57
    }
8300
152k
    p->u.array.u.values[new_len - 1] = val;
8301
152k
    p->u.array.count = new_len;
8302
152k
    return TRUE;
8303
152k
}
8304
8305
static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
8306
4
{
8307
4
    JS_FreeValue(ctx, desc->getter);
8308
4
    JS_FreeValue(ctx, desc->setter);
8309
4
    JS_FreeValue(ctx, desc->value);
8310
4
}
8311
8312
/* generic (and slower) version of JS_SetProperty() for
8313
 * Reflect.set(). 'obj' must be an object.  */
8314
static int JS_SetPropertyGeneric(JSContext *ctx,
8315
                                 JSValueConst obj, JSAtom prop,
8316
                                 JSValue val, JSValueConst this_obj,
8317
                                 int flags)
8318
0
{
8319
0
    int ret;
8320
0
    JSPropertyDescriptor desc;
8321
0
    JSValue obj1;
8322
0
    JSObject *p;
8323
    
8324
0
    obj1 = JS_DupValue(ctx, obj);
8325
0
    for(;;) {
8326
0
        p = JS_VALUE_GET_OBJ(obj1);
8327
0
        if (p->is_exotic) {
8328
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8329
0
            if (em && em->set_property) {
8330
0
                ret = em->set_property(ctx, obj1, prop,
8331
0
                                       val, this_obj, flags);
8332
0
                JS_FreeValue(ctx, obj1);
8333
0
                JS_FreeValue(ctx, val);
8334
0
                return ret;
8335
0
            }
8336
0
        }
8337
8338
0
        ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
8339
0
        if (ret < 0) {
8340
0
            JS_FreeValue(ctx, obj1);
8341
0
            JS_FreeValue(ctx, val);
8342
0
            return ret;
8343
0
        }
8344
0
        if (ret) {
8345
0
            if (desc.flags & JS_PROP_GETSET) {
8346
0
                JSObject *setter;
8347
0
                if (JS_IsUndefined(desc.setter))
8348
0
                    setter = NULL;
8349
0
                else
8350
0
                    setter = JS_VALUE_GET_OBJ(desc.setter);
8351
0
                ret = call_setter(ctx, setter, this_obj, val, flags);
8352
0
                JS_FreeValue(ctx, desc.getter);
8353
0
                JS_FreeValue(ctx, desc.setter);
8354
0
                JS_FreeValue(ctx, obj1);
8355
0
                return ret;
8356
0
            } else {
8357
0
                JS_FreeValue(ctx, desc.value);
8358
0
                if (!(desc.flags & JS_PROP_WRITABLE)) {
8359
0
                    JS_FreeValue(ctx, obj1);
8360
0
                    goto read_only_error;
8361
0
                }
8362
0
            }
8363
0
            break;
8364
0
        }
8365
        /* Note: at this point 'obj1' cannot be a proxy. XXX: may have
8366
           to check recursion */
8367
0
        obj1 = JS_GetPrototypeFree(ctx, obj1);
8368
0
        if (JS_IsNull(obj1))
8369
0
            break;
8370
0
    }
8371
0
    JS_FreeValue(ctx, obj1);
8372
8373
0
    if (!JS_IsObject(this_obj)) {
8374
0
        JS_FreeValue(ctx, val);
8375
0
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "receiver is not an object");
8376
0
    }
8377
    
8378
0
    p = JS_VALUE_GET_OBJ(this_obj);
8379
8380
    /* modify the property in this_obj if it already exists */
8381
0
    ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
8382
0
    if (ret < 0) {
8383
0
        JS_FreeValue(ctx, val);
8384
0
        return ret;
8385
0
    }
8386
0
    if (ret) {
8387
0
        if (desc.flags & JS_PROP_GETSET) {
8388
0
            JS_FreeValue(ctx, desc.getter);
8389
0
            JS_FreeValue(ctx, desc.setter);
8390
0
            JS_FreeValue(ctx, val);
8391
0
            return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden");
8392
0
        } else {
8393
0
            JS_FreeValue(ctx, desc.value);
8394
0
            if (!(desc.flags & JS_PROP_WRITABLE) ||
8395
0
                p->class_id == JS_CLASS_MODULE_NS) {
8396
0
            read_only_error:
8397
0
                JS_FreeValue(ctx, val);
8398
0
                return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
8399
0
            }
8400
0
        }
8401
0
        ret = JS_DefineProperty(ctx, this_obj, prop, val,
8402
0
                                JS_UNDEFINED, JS_UNDEFINED,
8403
0
                                JS_PROP_HAS_VALUE);
8404
0
        JS_FreeValue(ctx, val);
8405
0
        return ret;
8406
0
    }
8407
8408
0
    ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,
8409
0
                            flags |
8410
0
                            JS_PROP_HAS_VALUE |
8411
0
                            JS_PROP_HAS_ENUMERABLE |
8412
0
                            JS_PROP_HAS_WRITABLE |
8413
0
                            JS_PROP_HAS_CONFIGURABLE |
8414
0
                            JS_PROP_C_W_E);
8415
0
    JS_FreeValue(ctx, val);
8416
0
    return ret;
8417
0
}
8418
8419
/* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is
8420
   freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD,
8421
   JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set,
8422
   the new property is not added and an error is raised. */
8423
int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj,
8424
                           JSAtom prop, JSValue val, int flags)
8425
83.2k
{
8426
83.2k
    JSObject *p, *p1;
8427
83.2k
    JSShapeProperty *prs;
8428
83.2k
    JSProperty *pr;
8429
83.2k
    uint32_t tag;
8430
83.2k
    JSPropertyDescriptor desc;
8431
83.2k
    int ret;
8432
#if 0
8433
    printf("JS_SetPropertyInternal: "); print_atom(ctx, prop); printf("\n");
8434
#endif
8435
83.2k
    tag = JS_VALUE_GET_TAG(this_obj);
8436
83.2k
    if (unlikely(tag != JS_TAG_OBJECT)) {
8437
0
        switch(tag) {
8438
0
        case JS_TAG_NULL:
8439
0
            JS_FreeValue(ctx, val);
8440
0
            JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop);
8441
0
            return -1;
8442
0
        case JS_TAG_UNDEFINED:
8443
0
            JS_FreeValue(ctx, val);
8444
0
            JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop);
8445
0
            return -1;
8446
0
        default:
8447
            /* even on a primitive type we can have setters on the prototype */
8448
0
            p = NULL;
8449
0
            p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, this_obj));
8450
0
            goto prototype_lookup;
8451
0
        }
8452
0
    }
8453
83.2k
    p = JS_VALUE_GET_OBJ(this_obj);
8454
83.2k
retry:
8455
83.2k
    prs = find_own_property(&pr, p, prop);
8456
83.2k
    if (prs) {
8457
83.0k
        if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE |
8458
83.0k
                                  JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) {
8459
            /* fast case */
8460
1.11k
            set_value(ctx, &pr->u.value, val);
8461
1.11k
            return TRUE;
8462
81.9k
        } else if (prs->flags & JS_PROP_LENGTH) {
8463
81.9k
            assert(p->class_id == JS_CLASS_ARRAY);
8464
81.9k
            assert(prop == JS_ATOM_length);
8465
81.9k
            return set_array_length(ctx, p, val, flags);
8466
81.9k
        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
8467
0
            return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
8468
2
        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
8469
            /* JS_PROP_WRITABLE is always true for variable
8470
               references, but they are write protected in module name
8471
               spaces. */
8472
2
            if (p->class_id == JS_CLASS_MODULE_NS)
8473
0
                goto read_only_prop;
8474
2
            set_value(ctx, pr->u.var_ref->pvalue, val);
8475
2
            return TRUE;
8476
2
        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
8477
            /* Instantiate property and retry (potentially useless) */
8478
0
            if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) {
8479
0
                JS_FreeValue(ctx, val);
8480
0
                return -1;
8481
0
            }
8482
0
            goto retry;
8483
0
        } else {
8484
0
            goto read_only_prop;
8485
0
        }
8486
83.0k
    }
8487
8488
181
    p1 = p;
8489
200
    for(;;) {
8490
200
        if (p1->is_exotic) {
8491
0
            if (p1->fast_array) {
8492
0
                if (__JS_AtomIsTaggedInt(prop)) {
8493
0
                    uint32_t idx = __JS_AtomToUInt32(prop);
8494
0
                    if (idx < p1->u.array.count) {
8495
0
                        if (unlikely(p == p1))
8496
0
                            return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, flags);
8497
0
                        else
8498
0
                            break;
8499
0
                    } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&
8500
0
                               p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
8501
0
                        goto typed_array_oob;
8502
0
                    }
8503
0
                } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&
8504
0
                           p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
8505
0
                    ret = JS_AtomIsNumericIndex(ctx, prop);
8506
0
                    if (ret != 0) {
8507
0
                        if (ret < 0) {
8508
0
                            JS_FreeValue(ctx, val);
8509
0
                            return -1;
8510
0
                        }
8511
0
                    typed_array_oob:
8512
0
                        val = JS_ToNumberFree(ctx, val);
8513
0
                        JS_FreeValue(ctx, val);
8514
0
                        if (JS_IsException(val))
8515
0
                            return -1;
8516
0
                        return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
8517
0
                    }
8518
0
                }
8519
0
            } else {
8520
0
                const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic;
8521
0
                if (em) {
8522
0
                    JSValue obj1;
8523
0
                    if (em->set_property) {
8524
                        /* set_property can free the prototype */
8525
0
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
8526
0
                        ret = em->set_property(ctx, obj1, prop,
8527
0
                                               val, this_obj, flags);
8528
0
                        JS_FreeValue(ctx, obj1);
8529
0
                        JS_FreeValue(ctx, val);
8530
0
                        return ret;
8531
0
                    }
8532
0
                    if (em->get_own_property) {
8533
                        /* get_own_property can free the prototype */
8534
0
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
8535
0
                        ret = em->get_own_property(ctx, &desc,
8536
0
                                                   obj1, prop);
8537
0
                        JS_FreeValue(ctx, obj1);
8538
0
                        if (ret < 0) {
8539
0
                            JS_FreeValue(ctx, val);
8540
0
                            return ret;
8541
0
                        }
8542
0
                        if (ret) {
8543
0
                            if (desc.flags & JS_PROP_GETSET) {
8544
0
                                JSObject *setter;
8545
0
                                if (JS_IsUndefined(desc.setter))
8546
0
                                    setter = NULL;
8547
0
                                else
8548
0
                                    setter = JS_VALUE_GET_OBJ(desc.setter);
8549
0
                                ret = call_setter(ctx, setter, this_obj, val, flags);
8550
0
                                JS_FreeValue(ctx, desc.getter);
8551
0
                                JS_FreeValue(ctx, desc.setter);
8552
0
                                return ret;
8553
0
                            } else {
8554
0
                                JS_FreeValue(ctx, desc.value);
8555
0
                                if (!(desc.flags & JS_PROP_WRITABLE))
8556
0
                                    goto read_only_prop;
8557
0
                                if (likely(p == p1)) {
8558
0
                                    ret = JS_DefineProperty(ctx, this_obj, prop, val,
8559
0
                                                            JS_UNDEFINED, JS_UNDEFINED,
8560
0
                                                            JS_PROP_HAS_VALUE);
8561
0
                                    JS_FreeValue(ctx, val);
8562
0
                                    return ret;
8563
0
                                } else {
8564
0
                                    break;
8565
0
                                }
8566
0
                            }
8567
0
                        }
8568
0
                    }
8569
0
                }
8570
0
            }
8571
0
        }
8572
200
        p1 = p1->shape->proto;
8573
200
    prototype_lookup:
8574
200
        if (!p1)
8575
181
            break;
8576
8577
19
    retry2:
8578
19
        prs = find_own_property(&pr, p1, prop);
8579
19
        if (prs) {
8580
0
            if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
8581
0
                return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
8582
0
            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
8583
                /* Instantiate property and retry (potentially useless) */
8584
0
                if (JS_AutoInitProperty(ctx, p1, prop, pr, prs))
8585
0
                    return -1;
8586
0
                goto retry2;
8587
0
            } else if (!(prs->flags & JS_PROP_WRITABLE)) {
8588
0
            read_only_prop:
8589
0
                JS_FreeValue(ctx, val);
8590
0
                return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
8591
0
            }
8592
0
        }
8593
19
    }
8594
8595
181
    if (unlikely(flags & JS_PROP_NO_ADD)) {
8596
0
        JS_FreeValue(ctx, val);
8597
0
        JS_ThrowReferenceErrorNotDefined(ctx, prop);
8598
0
        return -1;
8599
0
    }
8600
8601
181
    if (unlikely(!p)) {
8602
0
        JS_FreeValue(ctx, val);
8603
0
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "not an object");
8604
0
    }
8605
8606
181
    if (unlikely(!p->extensible)) {
8607
0
        JS_FreeValue(ctx, val);
8608
0
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
8609
0
    }
8610
8611
181
    if (p->is_exotic) {
8612
0
        if (p->class_id == JS_CLASS_ARRAY && p->fast_array &&
8613
0
            __JS_AtomIsTaggedInt(prop)) {
8614
0
            uint32_t idx = __JS_AtomToUInt32(prop);
8615
0
            if (idx == p->u.array.count) {
8616
                /* fast case */
8617
0
                return add_fast_array_element(ctx, p, val, flags);
8618
0
            } else {
8619
0
                goto generic_create_prop;
8620
0
            }
8621
0
        } else {
8622
0
        generic_create_prop:
8623
0
            ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,
8624
0
                                    flags |
8625
0
                                    JS_PROP_HAS_VALUE |
8626
0
                                    JS_PROP_HAS_ENUMERABLE |
8627
0
                                    JS_PROP_HAS_WRITABLE |
8628
0
                                    JS_PROP_HAS_CONFIGURABLE |
8629
0
                                    JS_PROP_C_W_E);
8630
0
            JS_FreeValue(ctx, val);
8631
0
            return ret;
8632
0
        }
8633
0
    }
8634
8635
181
    pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
8636
181
    if (unlikely(!pr)) {
8637
0
        JS_FreeValue(ctx, val);
8638
0
        return -1;
8639
0
    }
8640
181
    pr->u.value = val;
8641
181
    return TRUE;
8642
181
}
8643
8644
/* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */
8645
static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
8646
                               JSValue prop, JSValue val, int flags)
8647
39
{
8648
39
    if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
8649
39
               JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
8650
0
        JSObject *p;
8651
0
        uint32_t idx;
8652
0
        double d;
8653
0
        int32_t v;
8654
8655
        /* fast path for array access */
8656
0
        p = JS_VALUE_GET_OBJ(this_obj);
8657
0
        idx = JS_VALUE_GET_INT(prop);
8658
0
        switch(p->class_id) {
8659
0
        case JS_CLASS_ARRAY:
8660
0
            if (unlikely(idx >= (uint32_t)p->u.array.count)) {
8661
0
                JSObject *p1;
8662
0
                JSShape *sh1;
8663
8664
                /* fast path to add an element to the array */
8665
0
                if (idx != (uint32_t)p->u.array.count ||
8666
0
                    !p->fast_array || !p->extensible)
8667
0
                    goto slow_path;
8668
                /* check if prototype chain has a numeric property */
8669
0
                p1 = p->shape->proto;
8670
0
                while (p1 != NULL) {
8671
0
                    sh1 = p1->shape;
8672
0
                    if (p1->class_id == JS_CLASS_ARRAY) {
8673
0
                        if (unlikely(!p1->fast_array))
8674
0
                            goto slow_path;
8675
0
                    } else if (p1->class_id == JS_CLASS_OBJECT) {
8676
0
                        if (unlikely(sh1->has_small_array_index))
8677
0
                            goto slow_path;
8678
0
                    } else {
8679
0
                        goto slow_path;
8680
0
                    }
8681
0
                    p1 = sh1->proto;
8682
0
                }
8683
                /* add element */
8684
0
                return add_fast_array_element(ctx, p, val, flags);
8685
0
            }
8686
0
            set_value(ctx, &p->u.array.u.values[idx], val);
8687
0
            break;
8688
0
        case JS_CLASS_ARGUMENTS:
8689
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8690
0
                goto slow_path;
8691
0
            set_value(ctx, &p->u.array.u.values[idx], val);
8692
0
            break;
8693
0
        case JS_CLASS_UINT8C_ARRAY:
8694
0
            if (JS_ToUint8ClampFree(ctx, &v, val))
8695
0
                return -1;
8696
            /* Note: the conversion can detach the typed array, so the
8697
               array bound check must be done after */
8698
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8699
0
                goto ta_out_of_bound;
8700
0
            p->u.array.u.uint8_ptr[idx] = v;
8701
0
            break;
8702
0
        case JS_CLASS_INT8_ARRAY:
8703
0
        case JS_CLASS_UINT8_ARRAY:
8704
0
            if (JS_ToInt32Free(ctx, &v, val))
8705
0
                return -1;
8706
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8707
0
                goto ta_out_of_bound;
8708
0
            p->u.array.u.uint8_ptr[idx] = v;
8709
0
            break;
8710
0
        case JS_CLASS_INT16_ARRAY:
8711
0
        case JS_CLASS_UINT16_ARRAY:
8712
0
            if (JS_ToInt32Free(ctx, &v, val))
8713
0
                return -1;
8714
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8715
0
                goto ta_out_of_bound;
8716
0
            p->u.array.u.uint16_ptr[idx] = v;
8717
0
            break;
8718
0
        case JS_CLASS_INT32_ARRAY:
8719
0
        case JS_CLASS_UINT32_ARRAY:
8720
0
            if (JS_ToInt32Free(ctx, &v, val))
8721
0
                return -1;
8722
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8723
0
                goto ta_out_of_bound;
8724
0
            p->u.array.u.uint32_ptr[idx] = v;
8725
0
            break;
8726
0
#ifdef CONFIG_BIGNUM
8727
0
        case JS_CLASS_BIG_INT64_ARRAY:
8728
0
        case JS_CLASS_BIG_UINT64_ARRAY:
8729
            /* XXX: need specific conversion function */
8730
0
            {
8731
0
                int64_t v;
8732
0
                if (JS_ToBigInt64Free(ctx, &v, val))
8733
0
                    return -1;
8734
0
                if (unlikely(idx >= (uint32_t)p->u.array.count))
8735
0
                    goto ta_out_of_bound;
8736
0
                p->u.array.u.uint64_ptr[idx] = v;
8737
0
            }
8738
0
            break;
8739
0
#endif
8740
0
        case JS_CLASS_FLOAT32_ARRAY:
8741
0
            if (JS_ToFloat64Free(ctx, &d, val))
8742
0
                return -1;
8743
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
8744
0
                goto ta_out_of_bound;
8745
0
            p->u.array.u.float_ptr[idx] = d;
8746
0
            break;
8747
0
        case JS_CLASS_FLOAT64_ARRAY:
8748
0
            if (JS_ToFloat64Free(ctx, &d, val))
8749
0
                return -1;
8750
0
            if (unlikely(idx >= (uint32_t)p->u.array.count)) {
8751
0
            ta_out_of_bound:
8752
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
8753
0
            }
8754
0
            p->u.array.u.double_ptr[idx] = d;
8755
0
            break;
8756
0
        default:
8757
0
            goto slow_path;
8758
0
        }
8759
0
        return TRUE;
8760
39
    } else {
8761
39
        JSAtom atom;
8762
39
        int ret;
8763
39
    slow_path:
8764
39
        atom = JS_ValueToAtom(ctx, prop);
8765
39
        JS_FreeValue(ctx, prop);
8766
39
        if (unlikely(atom == JS_ATOM_NULL)) {
8767
0
            JS_FreeValue(ctx, val);
8768
0
            return -1;
8769
0
        }
8770
39
        ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags);
8771
39
        JS_FreeAtom(ctx, atom);
8772
39
        return ret;
8773
39
    }
8774
39
}
8775
8776
int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
8777
                         uint32_t idx, JSValue val)
8778
0
{
8779
0
    return JS_SetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx), val,
8780
0
                               JS_PROP_THROW);
8781
0
}
8782
8783
int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj,
8784
                        int64_t idx, JSValue val)
8785
0
{
8786
0
    JSAtom prop;
8787
0
    int res;
8788
8789
0
    if ((uint64_t)idx <= INT32_MAX) {
8790
        /* fast path for fast arrays */
8791
0
        return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val,
8792
0
                                   JS_PROP_THROW);
8793
0
    }
8794
0
    prop = JS_NewAtomInt64(ctx, idx);
8795
0
    if (prop == JS_ATOM_NULL) {
8796
0
        JS_FreeValue(ctx, val);
8797
0
        return -1;
8798
0
    }
8799
0
    res = JS_SetProperty(ctx, this_obj, prop, val);
8800
0
    JS_FreeAtom(ctx, prop);
8801
0
    return res;
8802
0
}
8803
8804
int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
8805
                      const char *prop, JSValue val)
8806
10
{
8807
10
    JSAtom atom;
8808
10
    int ret;
8809
10
    atom = JS_NewAtom(ctx, prop);
8810
10
    ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW);
8811
10
    JS_FreeAtom(ctx, atom);
8812
10
    return ret;
8813
10
}
8814
8815
/* compute the property flags. For each flag: (JS_PROP_HAS_x forces
8816
   it, otherwise def_flags is used)
8817
   Note: makes assumption about the bit pattern of the flags
8818
*/
8819
static int get_prop_flags(int flags, int def_flags)
8820
153k
{
8821
153k
    int mask;
8822
153k
    mask = (flags >> JS_PROP_HAS_SHIFT) & JS_PROP_C_W_E;
8823
153k
    return (flags & mask) | (def_flags & ~mask);
8824
153k
}
8825
8826
static int JS_CreateProperty(JSContext *ctx, JSObject *p,
8827
                             JSAtom prop, JSValueConst val,
8828
                             JSValueConst getter, JSValueConst setter,
8829
                             int flags)
8830
3.61M
{
8831
3.61M
    JSProperty *pr;
8832
3.61M
    int ret, prop_flags;
8833
8834
    /* add a new property or modify an existing exotic one */
8835
3.61M
    if (p->is_exotic) {
8836
153k
        if (p->class_id == JS_CLASS_ARRAY) {
8837
153k
            uint32_t idx, len;
8838
8839
153k
            if (p->fast_array) {
8840
153k
                if (__JS_AtomIsTaggedInt(prop)) {
8841
153k
                    idx = __JS_AtomToUInt32(prop);
8842
153k
                    if (idx == p->u.array.count) {
8843
153k
                        if (!p->extensible)
8844
0
                            goto not_extensible;
8845
153k
                        if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET))
8846
0
                            goto convert_to_array;
8847
153k
                        prop_flags = get_prop_flags(flags, 0);
8848
153k
                        if (prop_flags != JS_PROP_C_W_E)
8849
606
                            goto convert_to_array;
8850
152k
                        return add_fast_array_element(ctx, p,
8851
152k
                                                      JS_DupValue(ctx, val), flags);
8852
153k
                    } else {
8853
0
                        goto convert_to_array;
8854
0
                    }
8855
153k
                } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
8856
                    /* convert the fast array to normal array */
8857
606
                convert_to_array:
8858
606
                    if (convert_fast_array_to_array(ctx, p))
8859
0
                        return -1;
8860
606
                    goto generic_array;
8861
606
                }
8862
153k
            } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
8863
0
                JSProperty *plen;
8864
0
                JSShapeProperty *pslen;
8865
606
            generic_array:
8866
                /* update the length field */
8867
606
                plen = &p->prop[0];
8868
606
                JS_ToUint32(ctx, &len, plen->u.value);
8869
606
                if ((idx + 1) > len) {
8870
606
                    pslen = get_shape_prop(p->shape);
8871
606
                    if (unlikely(!(pslen->flags & JS_PROP_WRITABLE)))
8872
0
                        return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
8873
                    /* XXX: should update the length after defining
8874
                       the property */
8875
606
                    len = idx + 1;
8876
606
                    set_value(ctx, &plen->u.value, JS_NewUint32(ctx, len));
8877
606
                }
8878
606
            }
8879
153k
        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
8880
32
                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
8881
0
            ret = JS_AtomIsNumericIndex(ctx, prop);
8882
0
            if (ret != 0) {
8883
0
                if (ret < 0)
8884
0
                    return -1;
8885
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "cannot create numeric index in typed array");
8886
0
            }
8887
32
        } else if (!(flags & JS_PROP_NO_EXOTIC)) {
8888
16
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8889
16
            if (em) {
8890
16
                if (em->define_own_property) {
8891
16
                    return em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p),
8892
16
                                                   prop, val, getter, setter, flags);
8893
16
                }
8894
0
                ret = JS_IsExtensible(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
8895
0
                if (ret < 0)
8896
0
                    return -1;
8897
0
                if (!ret)
8898
0
                    goto not_extensible;
8899
0
            }
8900
16
        }
8901
153k
    }
8902
8903
3.46M
    if (!p->extensible) {
8904
0
    not_extensible:
8905
0
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
8906
0
    }
8907
8908
3.46M
    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
8909
68
        prop_flags = (flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
8910
68
            JS_PROP_GETSET;
8911
3.46M
    } else {
8912
3.46M
        prop_flags = flags & JS_PROP_C_W_E;
8913
3.46M
    }
8914
3.46M
    pr = add_property(ctx, p, prop, prop_flags);
8915
3.46M
    if (unlikely(!pr))
8916
0
        return -1;
8917
3.46M
    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
8918
68
        pr->u.getset.getter = NULL;
8919
68
        if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) {
8920
68
            pr->u.getset.getter =
8921
68
                JS_VALUE_GET_OBJ(JS_DupValue(ctx, getter));
8922
68
        }
8923
68
        pr->u.getset.setter = NULL;
8924
68
        if ((flags & JS_PROP_HAS_SET) && JS_IsFunction(ctx, setter)) {
8925
6
            pr->u.getset.setter =
8926
6
                JS_VALUE_GET_OBJ(JS_DupValue(ctx, setter));
8927
6
        }
8928
3.46M
    } else {
8929
3.46M
        if (flags & JS_PROP_HAS_VALUE) {
8930
3.46M
            pr->u.value = JS_DupValue(ctx, val);
8931
3.46M
        } else {
8932
0
            pr->u.value = JS_UNDEFINED;
8933
0
        }
8934
3.46M
    }
8935
3.46M
    return TRUE;
8936
3.46M
}
8937
8938
/* return FALSE if not OK */
8939
static BOOL check_define_prop_flags(int prop_flags, int flags)
8940
340k
{
8941
340k
    BOOL has_accessor, is_getset;
8942
8943
340k
    if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
8944
783
        if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) ==
8945
783
            (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) {
8946
0
            return FALSE;
8947
0
        }
8948
783
        if ((flags & JS_PROP_HAS_ENUMERABLE) &&
8949
783
            (flags & JS_PROP_ENUMERABLE) != (prop_flags & JS_PROP_ENUMERABLE))
8950
0
            return FALSE;
8951
783
    }
8952
340k
    if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
8953
340k
                 JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
8954
340k
        if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
8955
783
            has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0);
8956
783
            is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET);
8957
783
            if (has_accessor != is_getset)
8958
0
                return FALSE;
8959
783
            if (!has_accessor && !is_getset && !(prop_flags & JS_PROP_WRITABLE)) {
8960
                /* not writable: cannot set the writable bit */
8961
0
                if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
8962
0
                    (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE))
8963
0
                    return FALSE;
8964
0
            }
8965
783
        }
8966
340k
    }
8967
340k
    return TRUE;
8968
340k
}
8969
8970
/* ensure that the shape can be safely modified */
8971
static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
8972
                                   JSShapeProperty **pprs)
8973
1.24k
{
8974
1.24k
    JSShape *sh;
8975
1.24k
    uint32_t idx = 0;    /* prevent warning */
8976
8977
1.24k
    sh = p->shape;
8978
1.24k
    if (sh->is_hashed) {
8979
628
        if (sh->header.ref_count != 1) {
8980
306
            if (pprs)
8981
3
                idx = *pprs - get_shape_prop(sh);
8982
            /* clone the shape (the resulting one is no longer hashed) */
8983
306
            sh = js_clone_shape(ctx, sh);
8984
306
            if (!sh)
8985
0
                return -1;
8986
306
            js_free_shape(ctx->rt, p->shape);
8987
306
            p->shape = sh;
8988
306
            if (pprs)
8989
3
                *pprs = get_shape_prop(sh) + idx;
8990
322
        } else {
8991
322
            js_shape_hash_unlink(ctx->rt, sh);
8992
322
            sh->is_hashed = FALSE;
8993
322
        }
8994
628
    }
8995
1.24k
    return 0;
8996
1.24k
}
8997
8998
static int js_update_property_flags(JSContext *ctx, JSObject *p,
8999
                                    JSShapeProperty **pprs, int flags)
9000
679k
{
9001
679k
    if (flags != (*pprs)->flags) {
9002
610
        if (js_shape_prepare_update(ctx, p, pprs))
9003
0
            return -1;
9004
610
        (*pprs)->flags = flags;
9005
610
    }
9006
679k
    return 0;
9007
679k
}
9008
9009
/* allowed flags:
9010
   JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE
9011
   JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE,
9012
   JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE,
9013
   JS_PROP_THROW, JS_PROP_NO_EXOTIC.
9014
   If JS_PROP_THROW is set, return an exception instead of FALSE.
9015
   if JS_PROP_NO_EXOTIC is set, do not call the exotic
9016
   define_own_property callback.
9017
   return -1 (exception), FALSE or TRUE.
9018
*/
9019
int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
9020
                      JSAtom prop, JSValueConst val,
9021
                      JSValueConst getter, JSValueConst setter, int flags)
9022
3.95M
{
9023
3.95M
    JSObject *p;
9024
3.95M
    JSShapeProperty *prs;
9025
3.95M
    JSProperty *pr;
9026
3.95M
    int mask, res;
9027
9028
3.95M
    if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) {
9029
0
        JS_ThrowTypeErrorNotAnObject(ctx);
9030
0
        return -1;
9031
0
    }
9032
3.95M
    p = JS_VALUE_GET_OBJ(this_obj);
9033
9034
3.95M
 redo_prop_update:
9035
3.95M
    prs = find_own_property(&pr, p, prop);
9036
3.95M
    if (prs) {
9037
        /* the range of the Array length property is always tested before */
9038
340k
        if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) {
9039
0
            uint32_t array_length;
9040
0
            if (JS_ToArrayLengthFree(ctx, &array_length,
9041
0
                                     JS_DupValue(ctx, val), FALSE)) {
9042
0
                return -1;
9043
0
            }
9044
            /* this code relies on the fact that Uint32 are never allocated */
9045
0
            val = (JSValueConst)JS_NewUint32(ctx, array_length);
9046
            /* prs may have been modified */
9047
0
            prs = find_own_property(&pr, p, prop);
9048
0
            assert(prs != NULL);
9049
0
        }
9050
        /* property already exists */
9051
340k
        if (!check_define_prop_flags(prs->flags, flags)) {
9052
0
        not_configurable:
9053
0
            return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
9054
0
        }
9055
9056
340k
        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
9057
            /* Instantiate property and retry */
9058
0
            if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
9059
0
                return -1;
9060
0
            goto redo_prop_update;
9061
0
        }
9062
9063
340k
        if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
9064
340k
                     JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9065
340k
            if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9066
0
                JSObject *new_getter, *new_setter;
9067
9068
0
                if (JS_IsFunction(ctx, getter)) {
9069
0
                    new_getter = JS_VALUE_GET_OBJ(getter);
9070
0
                } else {
9071
0
                    new_getter = NULL;
9072
0
                }
9073
0
                if (JS_IsFunction(ctx, setter)) {
9074
0
                    new_setter = JS_VALUE_GET_OBJ(setter);
9075
0
                } else {
9076
0
                    new_setter = NULL;
9077
0
                }
9078
9079
0
                if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET) {
9080
0
                    if (js_shape_prepare_update(ctx, p, &prs))
9081
0
                        return -1;
9082
                    /* convert to getset */
9083
0
                    if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
9084
0
                        free_var_ref(ctx->rt, pr->u.var_ref);
9085
0
                    } else {
9086
0
                        JS_FreeValue(ctx, pr->u.value);
9087
0
                    }
9088
0
                    prs->flags = (prs->flags &
9089
0
                                  (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
9090
0
                        JS_PROP_GETSET;
9091
0
                    pr->u.getset.getter = NULL;
9092
0
                    pr->u.getset.setter = NULL;
9093
0
                } else {
9094
0
                    if (!(prs->flags & JS_PROP_CONFIGURABLE)) {
9095
0
                        if ((flags & JS_PROP_HAS_GET) &&
9096
0
                            new_getter != pr->u.getset.getter) {
9097
0
                            goto not_configurable;
9098
0
                        }
9099
0
                        if ((flags & JS_PROP_HAS_SET) &&
9100
0
                            new_setter != pr->u.getset.setter) {
9101
0
                            goto not_configurable;
9102
0
                        }
9103
0
                    }
9104
0
                }
9105
0
                if (flags & JS_PROP_HAS_GET) {
9106
0
                    if (pr->u.getset.getter)
9107
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
9108
0
                    if (new_getter)
9109
0
                        JS_DupValue(ctx, getter);
9110
0
                    pr->u.getset.getter = new_getter;
9111
0
                }
9112
0
                if (flags & JS_PROP_HAS_SET) {
9113
0
                    if (pr->u.getset.setter)
9114
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
9115
0
                    if (new_setter)
9116
0
                        JS_DupValue(ctx, setter);
9117
0
                    pr->u.getset.setter = new_setter;
9118
0
                }
9119
340k
            } else {
9120
340k
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
9121
                    /* convert to data descriptor */
9122
0
                    if (js_shape_prepare_update(ctx, p, &prs))
9123
0
                        return -1;
9124
0
                    if (pr->u.getset.getter)
9125
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
9126
0
                    if (pr->u.getset.setter)
9127
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
9128
0
                    prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
9129
0
                    pr->u.value = JS_UNDEFINED;
9130
340k
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
9131
                    /* Note: JS_PROP_VARREF is always writable */
9132
340k
                } else {
9133
340k
                    if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
9134
340k
                        (flags & JS_PROP_HAS_VALUE)) {
9135
0
                        if (!js_same_value(ctx, val, pr->u.value)) {
9136
0
                            goto not_configurable;
9137
0
                        } else {
9138
0
                            return TRUE;
9139
0
                        }
9140
0
                    }
9141
340k
                }
9142
340k
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
9143
0
                    if (flags & JS_PROP_HAS_VALUE) {
9144
0
                        if (p->class_id == JS_CLASS_MODULE_NS) {
9145
                            /* JS_PROP_WRITABLE is always true for variable
9146
                               references, but they are write protected in module name
9147
                               spaces. */
9148
0
                            if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue))
9149
0
                                goto not_configurable;
9150
0
                        }
9151
                        /* update the reference */
9152
0
                        set_value(ctx, pr->u.var_ref->pvalue,
9153
0
                                  JS_DupValue(ctx, val));
9154
0
                    }
9155
                    /* if writable is set to false, no longer a
9156
                       reference (for mapped arguments) */
9157
0
                    if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
9158
0
                        JSValue val1;
9159
0
                        if (js_shape_prepare_update(ctx, p, &prs))
9160
0
                            return -1;
9161
0
                        val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue);
9162
0
                        free_var_ref(ctx->rt, pr->u.var_ref);
9163
0
                        pr->u.value = val1;
9164
0
                        prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
9165
0
                    }
9166
340k
                } else if (prs->flags & JS_PROP_LENGTH) {
9167
0
                    if (flags & JS_PROP_HAS_VALUE) {
9168
                        /* Note: no JS code is executable because
9169
                           'val' is guaranted to be a Uint32 */
9170
0
                        res = set_array_length(ctx, p, JS_DupValue(ctx, val),
9171
0
                                               flags);
9172
0
                    } else {
9173
0
                        res = TRUE;
9174
0
                    }
9175
                    /* still need to reset the writable flag if
9176
                       needed.  The JS_PROP_LENGTH is kept because the
9177
                       Uint32 test is still done if the length
9178
                       property is read-only. */
9179
0
                    if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
9180
0
                        JS_PROP_HAS_WRITABLE) {
9181
0
                        prs = get_shape_prop(p->shape);
9182
0
                        if (js_update_property_flags(ctx, p, &prs,
9183
0
                                                     prs->flags & ~JS_PROP_WRITABLE))
9184
0
                            return -1;
9185
0
                    }
9186
0
                    return res;
9187
340k
                } else {
9188
340k
                    if (flags & JS_PROP_HAS_VALUE) {
9189
340k
                        JS_FreeValue(ctx, pr->u.value);
9190
340k
                        pr->u.value = JS_DupValue(ctx, val);
9191
340k
                    }
9192
340k
                    if (flags & JS_PROP_HAS_WRITABLE) {
9193
339k
                        if (js_update_property_flags(ctx, p, &prs,
9194
339k
                                                     (prs->flags & ~JS_PROP_WRITABLE) |
9195
339k
                                                     (flags & JS_PROP_WRITABLE)))
9196
0
                            return -1;
9197
339k
                    }
9198
340k
                }
9199
340k
            }
9200
340k
        }
9201
340k
        mask = 0;
9202
340k
        if (flags & JS_PROP_HAS_CONFIGURABLE)
9203
339k
            mask |= JS_PROP_CONFIGURABLE;
9204
340k
        if (flags & JS_PROP_HAS_ENUMERABLE)
9205
339k
            mask |= JS_PROP_ENUMERABLE;
9206
340k
        if (js_update_property_flags(ctx, p, &prs,
9207
340k
                                     (prs->flags & ~mask) | (flags & mask)))
9208
0
            return -1;
9209
340k
        return TRUE;
9210
340k
    }
9211
9212
    /* handle modification of fast array elements */
9213
3.61M
    if (p->fast_array) {
9214
153k
        uint32_t idx;
9215
153k
        uint32_t prop_flags;
9216
153k
        if (p->class_id == JS_CLASS_ARRAY) {
9217
153k
            if (__JS_AtomIsTaggedInt(prop)) {
9218
153k
                idx = __JS_AtomToUInt32(prop);
9219
153k
                if (idx < p->u.array.count) {
9220
0
                    prop_flags = get_prop_flags(flags, JS_PROP_C_W_E);
9221
0
                    if (prop_flags != JS_PROP_C_W_E)
9222
0
                        goto convert_to_slow_array;
9223
0
                    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9224
0
                    convert_to_slow_array:
9225
0
                        if (convert_fast_array_to_array(ctx, p))
9226
0
                            return -1;
9227
0
                        else
9228
0
                            goto redo_prop_update;
9229
0
                    }
9230
0
                    if (flags & JS_PROP_HAS_VALUE) {
9231
0
                        set_value(ctx, &p->u.array.u.values[idx], JS_DupValue(ctx, val));
9232
0
                    }
9233
0
                    return TRUE;
9234
0
                }
9235
153k
            }
9236
153k
        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
9237
0
                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
9238
0
            JSValue num;
9239
0
            int ret;
9240
9241
0
            if (!__JS_AtomIsTaggedInt(prop)) {
9242
                /* slow path with to handle all numeric indexes */
9243
0
                num = JS_AtomIsNumericIndex1(ctx, prop);
9244
0
                if (JS_IsUndefined(num))
9245
0
                    goto typed_array_done;
9246
0
                if (JS_IsException(num))
9247
0
                    return -1;
9248
0
                ret = JS_NumberIsInteger(ctx, num);
9249
0
                if (ret < 0) {
9250
0
                    JS_FreeValue(ctx, num);
9251
0
                    return -1;
9252
0
                }
9253
0
                if (!ret) {
9254
0
                    JS_FreeValue(ctx, num);
9255
0
                    return JS_ThrowTypeErrorOrFalse(ctx, flags, "non integer index in typed array");
9256
0
                }
9257
0
                ret = JS_NumberIsNegativeOrMinusZero(ctx, num);
9258
0
                JS_FreeValue(ctx, num);
9259
0
                if (ret) {
9260
0
                    return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array");
9261
0
                }
9262
0
                if (!__JS_AtomIsTaggedInt(prop))
9263
0
                    goto typed_array_oob;
9264
0
            }
9265
0
            idx = __JS_AtomToUInt32(prop);
9266
            /* if the typed array is detached, p->u.array.count = 0 */
9267
0
            if (idx >= typed_array_get_length(ctx, p)) {
9268
0
            typed_array_oob:
9269
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array");
9270
0
            }
9271
0
            prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
9272
0
            if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) ||
9273
0
                prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) {
9274
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags");
9275
0
            }
9276
0
            if (flags & JS_PROP_HAS_VALUE) {
9277
0
                return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), JS_DupValue(ctx, val), flags);
9278
0
            }
9279
0
            return TRUE;
9280
0
        typed_array_done: ;
9281
0
        }
9282
153k
    }
9283
9284
3.61M
    return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags);
9285
3.61M
}
9286
9287
static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj,
9288
                                     JSAtom prop, JSAutoInitIDEnum id,
9289
                                     void *opaque, int flags)
9290
1.48k
{
9291
1.48k
    JSObject *p;
9292
1.48k
    JSProperty *pr;
9293
9294
1.48k
    if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT)
9295
0
        return FALSE;
9296
9297
1.48k
    p = JS_VALUE_GET_OBJ(this_obj);
9298
9299
1.48k
    if (find_own_property(&pr, p, prop)) {
9300
        /* property already exists */
9301
0
        abort();
9302
0
        return FALSE;
9303
0
    }
9304
9305
    /* Specialized CreateProperty */
9306
1.48k
    pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT);
9307
1.48k
    if (unlikely(!pr))
9308
0
        return -1;
9309
1.48k
    pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx);
9310
1.48k
    assert((pr->u.init.realm_and_id & 3) == 0);
9311
1.48k
    assert(id <= 3);
9312
1.48k
    pr->u.init.realm_and_id |= id;
9313
1.48k
    pr->u.init.opaque = opaque;
9314
1.48k
    return TRUE;
9315
1.48k
}
9316
9317
/* shortcut to add or redefine a new property value */
9318
int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj,
9319
                           JSAtom prop, JSValue val, int flags)
9320
3.90M
{
9321
3.90M
    int ret;
9322
3.90M
    ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED,
9323
3.90M
                            flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE);
9324
3.90M
    JS_FreeValue(ctx, val);
9325
3.90M
    return ret;
9326
3.90M
}
9327
9328
int JS_DefinePropertyValueValue(JSContext *ctx, JSValueConst this_obj,
9329
                                JSValue prop, JSValue val, int flags)
9330
153k
{
9331
153k
    JSAtom atom;
9332
153k
    int ret;
9333
153k
    atom = JS_ValueToAtom(ctx, prop);
9334
153k
    JS_FreeValue(ctx, prop);
9335
153k
    if (unlikely(atom == JS_ATOM_NULL)) {
9336
0
        JS_FreeValue(ctx, val);
9337
0
        return -1;
9338
0
    }
9339
153k
    ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
9340
153k
    JS_FreeAtom(ctx, atom);
9341
153k
    return ret;
9342
153k
}
9343
9344
int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj,
9345
                                 uint32_t idx, JSValue val, int flags)
9346
53.3k
{
9347
53.3k
    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewUint32(ctx, idx),
9348
53.3k
                                       val, flags);
9349
53.3k
}
9350
9351
int JS_DefinePropertyValueInt64(JSContext *ctx, JSValueConst this_obj,
9352
                                int64_t idx, JSValue val, int flags)
9353
0
{
9354
0
    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),
9355
0
                                       val, flags);
9356
0
}
9357
9358
int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
9359
                              const char *prop, JSValue val, int flags)
9360
174
{
9361
174
    JSAtom atom;
9362
174
    int ret;
9363
174
    atom = JS_NewAtom(ctx, prop);
9364
174
    ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
9365
174
    JS_FreeAtom(ctx, atom);
9366
174
    return ret;
9367
174
}
9368
9369
/* shortcut to add getter & setter */
9370
int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,
9371
                            JSAtom prop, JSValue getter, JSValue setter,
9372
                            int flags)
9373
64
{
9374
64
    int ret;
9375
64
    ret = JS_DefineProperty(ctx, this_obj, prop, JS_UNDEFINED, getter, setter,
9376
64
                            flags | JS_PROP_HAS_GET | JS_PROP_HAS_SET |
9377
64
                            JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE);
9378
64
    JS_FreeValue(ctx, getter);
9379
64
    JS_FreeValue(ctx, setter);
9380
64
    return ret;
9381
64
}
9382
9383
static int JS_CreateDataPropertyUint32(JSContext *ctx, JSValueConst this_obj,
9384
                                       int64_t idx, JSValue val, int flags)
9385
100k
{
9386
100k
    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),
9387
100k
                                       val, flags | JS_PROP_CONFIGURABLE |
9388
100k
                                       JS_PROP_ENUMERABLE | JS_PROP_WRITABLE);
9389
100k
}
9390
9391
9392
/* return TRUE if 'obj' has a non empty 'name' string */
9393
static BOOL js_object_has_name(JSContext *ctx, JSValueConst obj)
9394
287k
{
9395
287k
    JSProperty *pr;
9396
287k
    JSShapeProperty *prs;
9397
287k
    JSValueConst val;
9398
287k
    JSString *p;
9399
    
9400
287k
    prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name);
9401
287k
    if (!prs)
9402
41.3k
        return FALSE;
9403
245k
    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
9404
0
        return TRUE;
9405
245k
    val = pr->u.value;
9406
245k
    if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
9407
0
        return TRUE;
9408
245k
    p = JS_VALUE_GET_STRING(val);
9409
245k
    return (p->len != 0);
9410
245k
}
9411
9412
static int JS_DefineObjectName(JSContext *ctx, JSValueConst obj,
9413
                               JSAtom name, int flags)
9414
287k
{
9415
287k
    if (name != JS_ATOM_NULL
9416
287k
    &&  JS_IsObject(obj)
9417
287k
    &&  !js_object_has_name(ctx, obj)
9418
287k
    &&  JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, JS_AtomToString(ctx, name), flags) < 0) {
9419
0
        return -1;
9420
0
    }
9421
287k
    return 0;
9422
287k
}
9423
9424
static int JS_DefineObjectNameComputed(JSContext *ctx, JSValueConst obj,
9425
                                       JSValueConst str, int flags)
9426
0
{
9427
0
    if (JS_IsObject(obj) &&
9428
0
        !js_object_has_name(ctx, obj)) {
9429
0
        JSAtom prop;
9430
0
        JSValue name_str;
9431
0
        prop = JS_ValueToAtom(ctx, str);
9432
0
        if (prop == JS_ATOM_NULL)
9433
0
            return -1;
9434
0
        name_str = js_get_function_name(ctx, prop);
9435
0
        JS_FreeAtom(ctx, prop);
9436
0
        if (JS_IsException(name_str))
9437
0
            return -1;
9438
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name_str, flags) < 0)
9439
0
            return -1;
9440
0
    }
9441
0
    return 0;
9442
0
}
9443
9444
1.60k
#define DEFINE_GLOBAL_LEX_VAR (1 << 7)
9445
1.97k
#define DEFINE_GLOBAL_FUNC_VAR (1 << 6)
9446
9447
static JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop)
9448
0
{
9449
0
    return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop);
9450
0
}
9451
9452
/* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */
9453
/* XXX: could support exotic global object. */
9454
static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags)
9455
1.19k
{
9456
1.19k
    JSObject *p;
9457
1.19k
    JSShapeProperty *prs;
9458
9459
1.19k
    p = JS_VALUE_GET_OBJ(ctx->global_obj);
9460
1.19k
    prs = find_own_property1(p, prop);
9461
    /* XXX: should handle JS_PROP_AUTOINIT */
9462
1.19k
    if (flags & DEFINE_GLOBAL_LEX_VAR) {
9463
0
        if (prs && !(prs->flags & JS_PROP_CONFIGURABLE))
9464
0
            goto fail_redeclaration;
9465
1.19k
    } else {
9466
1.19k
        if (!prs && !p->extensible)
9467
0
            goto define_error;
9468
1.19k
        if (flags & DEFINE_GLOBAL_FUNC_VAR) {
9469
784
            if (prs) {
9470
396
                if (!(prs->flags & JS_PROP_CONFIGURABLE) &&
9471
396
                    ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET ||
9472
396
                     ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) !=
9473
396
                      (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) {
9474
0
                define_error:
9475
0
                    JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'",
9476
0
                                          prop);
9477
0
                    return -1;
9478
0
                }
9479
396
            }
9480
784
        }
9481
1.19k
    }
9482
    /* check if there already is a lexical declaration */
9483
1.19k
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9484
1.19k
    prs = find_own_property1(p, prop);
9485
1.19k
    if (prs) {
9486
0
    fail_redeclaration:
9487
0
        JS_ThrowSyntaxErrorVarRedeclaration(ctx, prop);
9488
0
        return -1;
9489
0
    }
9490
1.19k
    return 0;
9491
1.19k
}
9492
9493
/* def_flags is (0, DEFINE_GLOBAL_LEX_VAR) |
9494
   JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE */
9495
/* XXX: could support exotic global object. */
9496
static int JS_DefineGlobalVar(JSContext *ctx, JSAtom prop, int def_flags)
9497
408
{
9498
408
    JSObject *p;
9499
408
    JSShapeProperty *prs;
9500
408
    JSProperty *pr;
9501
408
    JSValue val;
9502
408
    int flags;
9503
9504
408
    if (def_flags & DEFINE_GLOBAL_LEX_VAR) {
9505
0
        p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9506
0
        flags = JS_PROP_ENUMERABLE | (def_flags & JS_PROP_WRITABLE) |
9507
0
            JS_PROP_CONFIGURABLE;
9508
0
        val = JS_UNINITIALIZED;
9509
408
    } else {
9510
408
        p = JS_VALUE_GET_OBJ(ctx->global_obj);
9511
408
        flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
9512
408
            (def_flags & JS_PROP_CONFIGURABLE);
9513
408
        val = JS_UNDEFINED;
9514
408
    }
9515
408
    prs = find_own_property1(p, prop);
9516
408
    if (prs)
9517
406
        return 0;
9518
2
    if (!p->extensible)
9519
0
        return 0;
9520
2
    pr = add_property(ctx, p, prop, flags);
9521
2
    if (unlikely(!pr))
9522
0
        return -1;
9523
2
    pr->u.value = val;
9524
2
    return 0;
9525
2
}
9526
9527
/* 'def_flags' is 0 or JS_PROP_CONFIGURABLE. */
9528
/* XXX: could support exotic global object. */
9529
static int JS_DefineGlobalFunction(JSContext *ctx, JSAtom prop,
9530
                                   JSValueConst func, int def_flags)
9531
784
{
9532
9533
784
    JSObject *p;
9534
784
    JSShapeProperty *prs;
9535
784
    int flags;
9536
9537
784
    p = JS_VALUE_GET_OBJ(ctx->global_obj);
9538
784
    prs = find_own_property1(p, prop);
9539
784
    flags = JS_PROP_HAS_VALUE | JS_PROP_THROW;
9540
784
    if (!prs || (prs->flags & JS_PROP_CONFIGURABLE)) {
9541
1
        flags |= JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | def_flags |
9542
1
            JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE;
9543
1
    }
9544
784
    if (JS_DefineProperty(ctx, ctx->global_obj, prop, func,
9545
784
                          JS_UNDEFINED, JS_UNDEFINED, flags) < 0)
9546
0
        return -1;
9547
784
    return 0;
9548
784
}
9549
9550
static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop,
9551
                               BOOL throw_ref_error)
9552
327k
{
9553
327k
    JSObject *p;
9554
327k
    JSShapeProperty *prs;
9555
327k
    JSProperty *pr;
9556
9557
    /* no exotic behavior is possible in global_var_obj */
9558
327k
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9559
327k
    prs = find_own_property(&pr, p, prop);
9560
327k
    if (prs) {
9561
        /* XXX: should handle JS_PROP_TMASK properties */
9562
0
        if (unlikely(JS_IsUninitialized(pr->u.value)))
9563
0
            return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
9564
0
        return JS_DupValue(ctx, pr->u.value);
9565
0
    }
9566
327k
    return JS_GetPropertyInternal(ctx, ctx->global_obj, prop,
9567
327k
                                 ctx->global_obj, throw_ref_error);
9568
327k
}
9569
9570
/* construct a reference to a global variable */
9571
static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom prop, JSValue *sp)
9572
37
{
9573
37
    JSObject *p;
9574
37
    JSShapeProperty *prs;
9575
37
    JSProperty *pr;
9576
9577
    /* no exotic behavior is possible in global_var_obj */
9578
37
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9579
37
    prs = find_own_property(&pr, p, prop);
9580
37
    if (prs) {
9581
        /* XXX: should handle JS_PROP_AUTOINIT properties? */
9582
        /* XXX: conformance: do these tests in
9583
           OP_put_var_ref/OP_get_var_ref ? */
9584
0
        if (unlikely(JS_IsUninitialized(pr->u.value))) {
9585
0
            JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
9586
0
            return -1;
9587
0
        }
9588
0
        if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
9589
0
            return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
9590
0
        }
9591
0
        sp[0] = JS_DupValue(ctx, ctx->global_var_obj);
9592
37
    } else {
9593
37
        int ret;
9594
37
        ret = JS_HasProperty(ctx, ctx->global_obj, prop);
9595
37
        if (ret < 0)
9596
0
            return -1;
9597
37
        if (ret) {
9598
34
            sp[0] = JS_DupValue(ctx, ctx->global_obj);
9599
34
        } else {
9600
3
            sp[0] = JS_UNDEFINED;
9601
3
        }
9602
37
    }
9603
37
    sp[1] = JS_AtomToValue(ctx, prop);
9604
37
    return 0;
9605
37
}
9606
9607
/* use for strict variable access: test if the variable exists */
9608
static int JS_CheckGlobalVar(JSContext *ctx, JSAtom prop)
9609
0
{
9610
0
    JSObject *p;
9611
0
    JSShapeProperty *prs;
9612
0
    int ret;
9613
9614
    /* no exotic behavior is possible in global_var_obj */
9615
0
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9616
0
    prs = find_own_property1(p, prop);
9617
0
    if (prs) {
9618
0
        ret = TRUE;
9619
0
    } else {
9620
0
        ret = JS_HasProperty(ctx, ctx->global_obj, prop);
9621
0
        if (ret < 0)
9622
0
            return -1;
9623
0
    }
9624
0
    return ret;
9625
0
}
9626
9627
/* flag = 0: normal variable write
9628
   flag = 1: initialize lexical variable
9629
   flag = 2: normal variable write, strict check was done before
9630
*/
9631
static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val,
9632
                           int flag)
9633
1.08k
{
9634
1.08k
    JSObject *p;
9635
1.08k
    JSShapeProperty *prs;
9636
1.08k
    JSProperty *pr;
9637
1.08k
    int flags;
9638
9639
    /* no exotic behavior is possible in global_var_obj */
9640
1.08k
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
9641
1.08k
    prs = find_own_property(&pr, p, prop);
9642
1.08k
    if (prs) {
9643
        /* XXX: should handle JS_PROP_AUTOINIT properties? */
9644
0
        if (flag != 1) {
9645
0
            if (unlikely(JS_IsUninitialized(pr->u.value))) {
9646
0
                JS_FreeValue(ctx, val);
9647
0
                JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
9648
0
                return -1;
9649
0
            }
9650
0
            if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
9651
0
                JS_FreeValue(ctx, val);
9652
0
                return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
9653
0
            }
9654
0
        }
9655
0
        set_value(ctx, &pr->u.value, val);
9656
0
        return 0;
9657
0
    }
9658
1.08k
    flags = JS_PROP_THROW_STRICT;
9659
1.08k
    if (is_strict_mode(ctx)) 
9660
0
        flags |= JS_PROP_NO_ADD;
9661
1.08k
    return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags);
9662
1.08k
}
9663
9664
/* return -1, FALSE or TRUE. return FALSE if not configurable or
9665
   invalid object. return -1 in case of exception.
9666
   flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */
9667
int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags)
9668
0
{
9669
0
    JSValue obj1;
9670
0
    JSObject *p;
9671
0
    int res;
9672
    
9673
0
    obj1 = JS_ToObject(ctx, obj);
9674
0
    if (JS_IsException(obj1))
9675
0
        return -1;
9676
0
    p = JS_VALUE_GET_OBJ(obj1);
9677
0
    res = delete_property(ctx, p, prop);
9678
0
    JS_FreeValue(ctx, obj1);
9679
0
    if (res != FALSE)
9680
0
        return res;
9681
0
    if ((flags & JS_PROP_THROW) ||
9682
0
        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
9683
0
        JS_ThrowTypeError(ctx, "could not delete property");
9684
0
        return -1;
9685
0
    }
9686
0
    return FALSE;
9687
0
}
9688
9689
int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int flags)
9690
0
{
9691
0
    JSAtom prop;
9692
0
    int res;
9693
9694
0
    if ((uint64_t)idx <= JS_ATOM_MAX_INT) {
9695
        /* fast path for fast arrays */
9696
0
        return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags);
9697
0
    }
9698
0
    prop = JS_NewAtomInt64(ctx, idx);
9699
0
    if (prop == JS_ATOM_NULL)
9700
0
        return -1;
9701
0
    res = JS_DeleteProperty(ctx, obj, prop, flags);
9702
0
    JS_FreeAtom(ctx, prop);
9703
0
    return res;
9704
0
}
9705
9706
BOOL JS_IsFunction(JSContext *ctx, JSValueConst val)
9707
923k
{
9708
923k
    JSObject *p;
9709
923k
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9710
68
        return FALSE;
9711
923k
    p = JS_VALUE_GET_OBJ(val);
9712
923k
    switch(p->class_id) {
9713
40.9k
    case JS_CLASS_BYTECODE_FUNCTION:
9714
40.9k
        return TRUE;
9715
0
    case JS_CLASS_PROXY:
9716
0
        return p->u.proxy_data->is_func;
9717
882k
    default:
9718
882k
        return (ctx->rt->class_array[p->class_id].call != NULL);
9719
923k
    }
9720
923k
}
9721
9722
BOOL JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func, int magic)
9723
1
{
9724
1
    JSObject *p;
9725
1
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9726
0
        return FALSE;
9727
1
    p = JS_VALUE_GET_OBJ(val);
9728
1
    if (p->class_id == JS_CLASS_C_FUNCTION)
9729
1
        return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic);
9730
0
    else
9731
0
        return FALSE;
9732
1
}
9733
9734
BOOL JS_IsConstructor(JSContext *ctx, JSValueConst val)
9735
0
{
9736
0
    JSObject *p;
9737
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9738
0
        return FALSE;
9739
0
    p = JS_VALUE_GET_OBJ(val);
9740
0
    return p->is_constructor;
9741
0
}
9742
9743
BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, BOOL val)
9744
42.1k
{
9745
42.1k
    JSObject *p;
9746
42.1k
    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
9747
0
        return FALSE;
9748
42.1k
    p = JS_VALUE_GET_OBJ(func_obj);
9749
42.1k
    p->is_constructor = val;
9750
42.1k
    return TRUE;
9751
42.1k
}
9752
9753
BOOL JS_IsError(JSContext *ctx, JSValueConst val)
9754
2
{
9755
2
    JSObject *p;
9756
2
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9757
1
        return FALSE;
9758
1
    p = JS_VALUE_GET_OBJ(val);
9759
1
    return (p->class_id == JS_CLASS_ERROR);
9760
2
}
9761
9762
/* used to avoid catching interrupt exceptions */
9763
BOOL JS_IsUncatchableError(JSContext *ctx, JSValueConst val)
9764
163k
{
9765
163k
    JSObject *p;
9766
163k
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9767
6
        return FALSE;
9768
163k
    p = JS_VALUE_GET_OBJ(val);
9769
163k
    return p->class_id == JS_CLASS_ERROR && p->is_uncatchable_error;
9770
163k
}
9771
9772
void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag)
9773
0
{
9774
0
    JSObject *p;
9775
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9776
0
        return;
9777
0
    p = JS_VALUE_GET_OBJ(val);
9778
0
    if (p->class_id == JS_CLASS_ERROR)
9779
0
        p->is_uncatchable_error = flag;
9780
0
}
9781
9782
void JS_ResetUncatchableError(JSContext *ctx)
9783
0
{
9784
0
    JS_SetUncatchableError(ctx, ctx->rt->current_exception, FALSE);
9785
0
}
9786
9787
void JS_SetOpaque(JSValue obj, void *opaque)
9788
327k
{
9789
327k
   JSObject *p;
9790
327k
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
9791
327k
        p = JS_VALUE_GET_OBJ(obj);
9792
327k
        p->u.opaque = opaque;
9793
327k
    }
9794
327k
}
9795
9796
/* return NULL if not an object of class class_id */
9797
void *JS_GetOpaque(JSValueConst obj, JSClassID class_id)
9798
965k
{
9799
965k
    JSObject *p;
9800
965k
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
9801
0
        return NULL;
9802
965k
    p = JS_VALUE_GET_OBJ(obj);
9803
965k
    if (p->class_id != class_id)
9804
0
        return NULL;
9805
965k
    return p->u.opaque;
9806
965k
}
9807
9808
void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id)
9809
53.0k
{
9810
53.0k
    void *p = JS_GetOpaque(obj, class_id);
9811
53.0k
    if (unlikely(!p)) {
9812
0
        JS_ThrowTypeErrorInvalidClass(ctx, class_id);
9813
0
    }
9814
53.0k
    return p;
9815
53.0k
}
9816
9817
225k
#define HINT_STRING  0
9818
461k
#define HINT_NUMBER  1
9819
215k
#define HINT_NONE    2
9820
/* don't try Symbol.toPrimitive */
9821
451k
#define HINT_FORCE_ORDINARY (1 << 4)
9822
9823
static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)
9824
379k
{
9825
379k
    int i;
9826
379k
    BOOL force_ordinary;
9827
9828
379k
    JSAtom method_name;
9829
379k
    JSValue method, ret;
9830
379k
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
9831
153k
        return val;
9832
225k
    force_ordinary = hint & HINT_FORCE_ORDINARY;
9833
225k
    hint &= ~HINT_FORCE_ORDINARY;
9834
225k
    if (!force_ordinary) {
9835
225k
        method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive);
9836
225k
        if (JS_IsException(method))
9837
0
            goto exception;
9838
        /* ECMA says *If exoticToPrim is not undefined* but tests in
9839
           test262 use null as a non callable converter */
9840
225k
        if (!JS_IsUndefined(method) && !JS_IsNull(method)) {
9841
0
            JSAtom atom;
9842
0
            JSValue arg;
9843
0
            switch(hint) {
9844
0
            case HINT_STRING:
9845
0
                atom = JS_ATOM_string;
9846
0
                break;
9847
0
            case HINT_NUMBER:
9848
0
                atom = JS_ATOM_number;
9849
0
                break;
9850
0
            default:
9851
0
            case HINT_NONE:
9852
0
                atom = JS_ATOM_default;
9853
0
                break;
9854
0
            }
9855
0
            arg = JS_AtomToString(ctx, atom);
9856
0
            ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);
9857
0
            JS_FreeValue(ctx, arg);
9858
0
            if (JS_IsException(ret))
9859
0
                goto exception;
9860
0
            JS_FreeValue(ctx, val);
9861
0
            if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT)
9862
0
                return ret;
9863
0
            JS_FreeValue(ctx, ret);
9864
0
            return JS_ThrowTypeError(ctx, "toPrimitive");
9865
0
        }
9866
225k
    }
9867
225k
    if (hint != HINT_STRING)
9868
225k
        hint = HINT_NUMBER;
9869
451k
    for(i = 0; i < 2; i++) {
9870
451k
        if ((i ^ hint) == 0) {
9871
225k
            method_name = JS_ATOM_toString;
9872
225k
        } else {
9873
225k
            method_name = JS_ATOM_valueOf;
9874
225k
        }
9875
451k
        method = JS_GetProperty(ctx, val, method_name);
9876
451k
        if (JS_IsException(method))
9877
0
            goto exception;
9878
451k
        if (JS_IsFunction(ctx, method)) {
9879
451k
            ret = JS_CallFree(ctx, method, val, 0, NULL);
9880
451k
            if (JS_IsException(ret))
9881
0
                goto exception;
9882
451k
            if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
9883
225k
                JS_FreeValue(ctx, val);
9884
225k
                return ret;
9885
225k
            }
9886
225k
            JS_FreeValue(ctx, ret);
9887
225k
        } else {
9888
0
            JS_FreeValue(ctx, method);
9889
0
        }
9890
451k
    }
9891
0
    JS_ThrowTypeError(ctx, "toPrimitive");
9892
0
exception:
9893
0
    JS_FreeValue(ctx, val);
9894
0
    return JS_EXCEPTION;
9895
0
}
9896
9897
static JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint)
9898
8
{
9899
8
    return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint);
9900
8
}
9901
9902
void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj)
9903
0
{
9904
0
    JSObject *p;
9905
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
9906
0
        return;
9907
0
    p = JS_VALUE_GET_OBJ(obj);
9908
0
    p->is_HTMLDDA = TRUE;
9909
0
}
9910
9911
static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj)
9912
0
{
9913
0
    JSObject *p;
9914
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
9915
0
        return FALSE;
9916
0
    p = JS_VALUE_GET_OBJ(obj);
9917
0
    return p->is_HTMLDDA;
9918
0
}
9919
                         
9920
static int JS_ToBoolFree(JSContext *ctx, JSValue val)
9921
122k
{
9922
122k
    uint32_t tag = JS_VALUE_GET_TAG(val);
9923
122k
    switch(tag) {
9924
0
    case JS_TAG_INT:
9925
0
        return JS_VALUE_GET_INT(val) != 0;
9926
0
    case JS_TAG_BOOL:
9927
0
    case JS_TAG_NULL:
9928
0
    case JS_TAG_UNDEFINED:
9929
0
        return JS_VALUE_GET_INT(val);
9930
0
    case JS_TAG_EXCEPTION:
9931
0
        return -1;
9932
2
    case JS_TAG_STRING:
9933
2
        {
9934
2
            BOOL ret = JS_VALUE_GET_STRING(val)->len != 0;
9935
2
            JS_FreeValue(ctx, val);
9936
2
            return ret;
9937
0
        }
9938
0
#ifdef CONFIG_BIGNUM
9939
40.9k
    case JS_TAG_BIG_INT:
9940
40.9k
    case JS_TAG_BIG_FLOAT:
9941
40.9k
        {
9942
40.9k
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
9943
40.9k
            BOOL ret;
9944
40.9k
            ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
9945
40.9k
            JS_FreeValue(ctx, val);
9946
40.9k
            return ret;
9947
40.9k
        }
9948
0
    case JS_TAG_BIG_DECIMAL:
9949
0
        {
9950
0
            JSBigDecimal *p = JS_VALUE_GET_PTR(val);
9951
0
            BOOL ret;
9952
0
            ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
9953
0
            JS_FreeValue(ctx, val);
9954
0
            return ret;
9955
40.9k
        }
9956
0
#endif
9957
40.9k
    case JS_TAG_OBJECT:
9958
40.9k
        {
9959
40.9k
            JSObject *p = JS_VALUE_GET_OBJ(val);
9960
40.9k
            BOOL ret;
9961
40.9k
            ret = !p->is_HTMLDDA;
9962
40.9k
            JS_FreeValue(ctx, val);
9963
40.9k
            return ret;
9964
40.9k
        }
9965
0
        break;
9966
40.9k
    default:
9967
40.9k
        if (JS_TAG_IS_FLOAT64(tag)) {
9968
40.9k
            double d = JS_VALUE_GET_FLOAT64(val);
9969
40.9k
            return !isnan(d) && d != 0;
9970
40.9k
        } else {
9971
0
            JS_FreeValue(ctx, val);
9972
0
            return TRUE;
9973
0
        }
9974
122k
    }
9975
122k
}
9976
9977
int JS_ToBool(JSContext *ctx, JSValueConst val)
9978
0
{
9979
0
    return JS_ToBoolFree(ctx, JS_DupValue(ctx, val));
9980
0
}
9981
9982
static int skip_spaces(const char *pc)
9983
307k
{
9984
307k
    const uint8_t *p, *p_next, *p_start;
9985
307k
    uint32_t c;
9986
9987
307k
    p = p_start = (const uint8_t *)pc;
9988
307k
    for (;;) {
9989
307k
        c = *p;
9990
307k
        if (c < 128) {
9991
307k
            if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20)))
9992
307k
                break;
9993
0
            p++;
9994
0
        } else {
9995
0
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
9996
0
            if (!lre_is_space(c))
9997
0
                break;
9998
0
            p = p_next;
9999
0
        }
10000
307k
    }
10001
307k
    return p - p_start;
10002
307k
}
10003
10004
static inline int to_digit(int c)
10005
236k
{
10006
236k
    if (c >= '0' && c <= '9')
10007
14.1k
        return c - '0';
10008
221k
    else if (c >= 'A' && c <= 'Z')
10009
14
        return c - 'A' + 10;
10010
221k
    else if (c >= 'a' && c <= 'z')
10011
146k
        return c - 'a' + 10;
10012
75.0k
    else
10013
75.0k
        return 36;
10014
236k
}
10015
10016
/* XXX: remove */
10017
static double js_strtod(const char *p, int radix, BOOL is_float)
10018
3.03k
{
10019
3.03k
    double d;
10020
3.03k
    int c;
10021
    
10022
3.03k
    if (!is_float || radix != 10) {
10023
2.96k
        uint64_t n_max, n;
10024
2.96k
        int int_exp, is_neg;
10025
        
10026
2.96k
        is_neg = 0;
10027
2.96k
        if (*p == '-') {
10028
0
            is_neg = 1;
10029
0
            p++;
10030
0
        }
10031
10032
        /* skip leading zeros */
10033
3.64k
        while (*p == '0')
10034
688
            p++;
10035
2.96k
        n = 0;
10036
2.96k
        if (radix == 10)
10037
2.95k
            n_max = ((uint64_t)-1 - 9) / 10; /* most common case */
10038
4
        else
10039
4
            n_max = ((uint64_t)-1 - (radix - 1)) / radix;
10040
        /* XXX: could be more precise */
10041
2.96k
        int_exp = 0;
10042
6.45k
        while (*p != '\0') {
10043
3.49k
            c = to_digit((uint8_t)*p);
10044
3.49k
            if (c >= radix)
10045
0
                break;
10046
3.49k
            if (n <= n_max) {
10047
3.40k
                n = n * radix + c;
10048
3.40k
            } else {
10049
89
                int_exp++;
10050
89
            }
10051
3.49k
            p++;
10052
3.49k
        }
10053
2.96k
        d = n;
10054
2.96k
        if (int_exp != 0) {
10055
11
            d *= pow(radix, int_exp);
10056
11
        }
10057
2.96k
        if (is_neg)
10058
0
            d = -d;
10059
2.96k
    } else {
10060
76
        d = strtod(p, NULL);
10061
76
    }
10062
3.03k
    return d;
10063
3.03k
}
10064
10065
314k
#define ATOD_INT_ONLY        (1 << 0)
10066
/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
10067
157k
#define ATOD_ACCEPT_BIN_OCT  (1 << 2)
10068
/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
10069
4.04k
#define ATOD_ACCEPT_LEGACY_OCTAL  (1 << 4)
10070
/* accept _ between digits as a digit separator */
10071
162k
#define ATOD_ACCEPT_UNDERSCORES  (1 << 5)
10072
/* allow a suffix to override the type */
10073
8.07k
#define ATOD_ACCEPT_SUFFIX    (1 << 6) 
10074
/* default type */
10075
157k
#define ATOD_TYPE_MASK        (3 << 7)
10076
316k
#define ATOD_TYPE_FLOAT64     (0 << 7)
10077
2.00k
#define ATOD_TYPE_BIG_INT     (1 << 7)
10078
0
#define ATOD_TYPE_BIG_FLOAT   (2 << 7)
10079
0
#define ATOD_TYPE_BIG_DECIMAL (3 << 7)
10080
/* assume bigint mode: floats are parsed as integers if no decimal
10081
   point nor exponent */
10082
4.03k
#define ATOD_MODE_BIGINT      (1 << 9) 
10083
/* accept -0x1 */
10084
0
#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10)
10085
10086
#ifdef CONFIG_BIGNUM
10087
static JSValue js_string_to_bigint(JSContext *ctx, const char *buf,
10088
                                   int radix, int flags, slimb_t *pexponent)
10089
1.00k
{
10090
1.00k
    bf_t a_s, *a = &a_s;
10091
1.00k
    int ret;
10092
1.00k
    JSValue val;
10093
1.00k
    val = JS_NewBigInt(ctx);
10094
1.00k
    if (JS_IsException(val))
10095
0
        return val;
10096
1.00k
    a = JS_GetBigInt(val);
10097
1.00k
    ret = bf_atof(a, buf, NULL, radix, BF_PREC_INF, BF_RNDZ);
10098
1.00k
    if (ret & BF_ST_MEM_ERROR) {
10099
4
        JS_FreeValue(ctx, val);
10100
4
        return JS_ThrowOutOfMemory(ctx);
10101
4
    }
10102
996
    val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0);
10103
996
    return val;
10104
1.00k
}
10105
10106
static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf,
10107
                                     int radix, int flags, slimb_t *pexponent)
10108
0
{
10109
0
    bf_t *a;
10110
0
    int ret;
10111
0
    JSValue val;
10112
    
10113
0
    val = JS_NewBigFloat(ctx);
10114
0
    if (JS_IsException(val))
10115
0
        return val;
10116
0
    a = JS_GetBigFloat(val);
10117
0
    if (flags & ATOD_ACCEPT_SUFFIX) {
10118
        /* return the exponent to get infinite precision */
10119
0
        ret = bf_atof2(a, pexponent, buf, NULL, radix, BF_PREC_INF,
10120
0
                       BF_RNDZ | BF_ATOF_EXPONENT);
10121
0
    } else {
10122
0
        ret = bf_atof(a, buf, NULL, radix, ctx->fp_env.prec,
10123
0
                      ctx->fp_env.flags);
10124
0
    }
10125
0
    if (ret & BF_ST_MEM_ERROR) {
10126
0
        JS_FreeValue(ctx, val);
10127
0
        return JS_ThrowOutOfMemory(ctx);
10128
0
    }
10129
0
    return val;
10130
0
}
10131
10132
static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf,
10133
                                       int radix, int flags, slimb_t *pexponent)
10134
0
{
10135
0
    bfdec_t *a;
10136
0
    int ret;
10137
0
    JSValue val;
10138
    
10139
0
    val = JS_NewBigDecimal(ctx);
10140
0
    if (JS_IsException(val))
10141
0
        return val;
10142
0
    a = JS_GetBigDecimal(val);
10143
0
    ret = bfdec_atof(a, buf, NULL, BF_PREC_INF,
10144
0
                     BF_RNDZ | BF_ATOF_NO_NAN_INF);
10145
0
    if (ret & BF_ST_MEM_ERROR) {
10146
0
        JS_FreeValue(ctx, val);
10147
0
        return JS_ThrowOutOfMemory(ctx);
10148
0
    }
10149
0
    return val;
10150
0
}
10151
10152
#endif
10153
10154
/* return an exception in case of memory error. Return JS_NAN if
10155
   invalid syntax */
10156
#ifdef CONFIG_BIGNUM
10157
static JSValue js_atof2(JSContext *ctx, const char *str, const char **pp,
10158
                        int radix, int flags, slimb_t *pexponent)
10159
#else
10160
static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
10161
                       int radix, int flags)
10162
#endif
10163
157k
{
10164
157k
    const char *p, *p_start;
10165
157k
    int sep, is_neg;
10166
157k
    BOOL is_float, has_legacy_octal;
10167
157k
    int atod_type = flags & ATOD_TYPE_MASK;
10168
157k
    char buf1[64], *buf;
10169
157k
    int i, j, len;
10170
157k
    BOOL buf_allocated = FALSE;
10171
157k
    JSValue val;
10172
    
10173
    /* optional separator between digits */
10174
157k
    sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;
10175
157k
    has_legacy_octal = FALSE;
10176
    
10177
157k
    p = str;
10178
157k
    p_start = p;
10179
157k
    is_neg = 0;
10180
157k
    if (p[0] == '+') {
10181
0
        p++;
10182
0
        p_start++;
10183
0
        if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
10184
0
            goto no_radix_prefix;
10185
157k
    } else if (p[0] == '-') {
10186
0
        p++;
10187
0
        p_start++;
10188
0
        is_neg = 1;
10189
0
        if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
10190
0
            goto no_radix_prefix;
10191
0
    }
10192
157k
    if (p[0] == '0') {
10193
1.29k
        if ((p[1] == 'x' || p[1] == 'X') &&
10194
1.29k
            (radix == 0 || radix == 16)) {
10195
1
            p += 2;
10196
1
            radix = 16;
10197
1.29k
        } else if ((p[1] == 'o' || p[1] == 'O') &&
10198
1.29k
                   radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
10199
0
            p += 2;
10200
0
            radix = 8;
10201
1.29k
        } else if ((p[1] == 'b' || p[1] == 'B') &&
10202
1.29k
                   radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
10203
0
            p += 2;
10204
0
            radix = 2;
10205
1.29k
        } else if ((p[1] >= '0' && p[1] <= '9') &&
10206
1.29k
                   radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) {
10207
4
            int i;
10208
4
            has_legacy_octal = TRUE;
10209
4
            sep = 256;
10210
10
            for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++)
10211
6
                continue;
10212
4
            if (p[i] == '8' || p[i] == '9')
10213
0
                goto no_prefix;
10214
4
            p += 1;
10215
4
            radix = 8;
10216
1.29k
        } else {
10217
1.29k
            goto no_prefix;
10218
1.29k
        }
10219
        /* there must be a digit after the prefix */
10220
5
        if (to_digit((uint8_t)*p) >= radix)
10221
0
            goto fail;
10222
1.29k
    no_prefix: ;
10223
156k
    } else {
10224
156k
 no_radix_prefix:
10225
156k
        if (!(flags & ATOD_INT_ONLY) &&
10226
156k
            (atod_type == ATOD_TYPE_FLOAT64 ||
10227
156k
             atod_type == ATOD_TYPE_BIG_FLOAT) &&
10228
156k
            strstart(p, "Infinity", &p)) {
10229
0
#ifdef CONFIG_BIGNUM
10230
0
            if (atod_type == ATOD_TYPE_BIG_FLOAT) {
10231
0
                bf_t *a;
10232
0
                val = JS_NewBigFloat(ctx);
10233
0
                if (JS_IsException(val))
10234
0
                    goto done;
10235
0
                a = JS_GetBigFloat(val);
10236
0
                bf_set_inf(a, is_neg);
10237
0
            } else
10238
0
#endif
10239
0
            {
10240
0
                double d = 1.0 / 0.0;
10241
0
                if (is_neg)
10242
0
                    d = -d;
10243
0
                val = JS_NewFloat64(ctx, d);
10244
0
            }
10245
0
            goto done;
10246
0
        }
10247
156k
    }
10248
157k
    if (radix == 0)
10249
157k
        radix = 10;
10250
157k
    is_float = FALSE;
10251
157k
    p_start = p;
10252
232k
    while (to_digit((uint8_t)*p) < radix
10253
232k
           ||  (*p == sep && (radix != 10 ||
10254
0
                              p != p_start + 1 || p[-1] != '0') &&
10255
157k
                to_digit((uint8_t)p[1]) < radix)) {
10256
74.4k
        p++;
10257
74.4k
    }
10258
157k
    if (!(flags & ATOD_INT_ONLY)) {
10259
157k
        if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) {
10260
62
            is_float = TRUE;
10261
62
            p++;
10262
62
            if (*p == sep)
10263
0
                goto fail;
10264
144
            while (to_digit((uint8_t)*p) < radix ||
10265
144
                   (*p == sep && to_digit((uint8_t)p[1]) < radix))
10266
82
                p++;
10267
62
        }
10268
157k
        if (p > p_start &&
10269
157k
            (((*p == 'e' || *p == 'E') && radix == 10) ||
10270
4.03k
             ((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) {
10271
16
            const char *p1 = p + 1;
10272
16
            is_float = TRUE;
10273
16
            if (*p1 == '+') {
10274
0
                p1++;
10275
16
            } else if (*p1 == '-') {
10276
3
                p1++;
10277
3
            }
10278
16
            if (is_digit((uint8_t)*p1)) {
10279
16
                p = p1 + 1;
10280
60
                while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1])))
10281
44
                    p++;
10282
16
            }
10283
16
        }
10284
157k
    }
10285
157k
    if (p == p_start)
10286
153k
        goto fail;
10287
10288
4.03k
    buf = buf1;
10289
4.03k
    buf_allocated = FALSE;
10290
4.03k
    len = p - p_start;
10291
4.03k
    if (unlikely((len + 2) > sizeof(buf1))) {
10292
3
        buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */
10293
3
        if (!buf)
10294
0
            goto mem_error;
10295
3
        buf_allocated = TRUE;
10296
3
    }
10297
    /* remove the separators and the radix prefixes */
10298
4.03k
    j = 0;
10299
4.03k
    if (is_neg)
10300
0
        buf[j++] = '-';
10301
78.7k
    for (i = 0; i < len; i++) {
10302
74.6k
        if (p_start[i] != '_')
10303
74.6k
            buf[j++] = p_start[i];
10304
74.6k
    }
10305
4.03k
    buf[j] = '\0';
10306
10307
4.03k
#ifdef CONFIG_BIGNUM
10308
4.03k
    if (flags & ATOD_ACCEPT_SUFFIX) {
10309
4.03k
        if (*p == 'n') {
10310
1.00k
            p++;
10311
1.00k
            atod_type = ATOD_TYPE_BIG_INT;
10312
3.03k
        } else if (*p == 'l') {
10313
0
            p++;
10314
0
            atod_type = ATOD_TYPE_BIG_FLOAT;
10315
3.03k
        } else if (*p == 'm') {
10316
0
            p++;
10317
0
            atod_type = ATOD_TYPE_BIG_DECIMAL;
10318
3.03k
        } else {
10319
3.03k
            if (flags & ATOD_MODE_BIGINT) {
10320
0
                if (!is_float)
10321
0
                    atod_type = ATOD_TYPE_BIG_INT;
10322
0
                if (has_legacy_octal)
10323
0
                    goto fail;
10324
3.03k
            } else {
10325
3.03k
                if (is_float && radix != 10)
10326
0
                    goto fail;
10327
3.03k
            }
10328
3.03k
        }
10329
4.03k
    } else {
10330
0
        if (atod_type == ATOD_TYPE_FLOAT64) {
10331
0
            if (flags & ATOD_MODE_BIGINT) {
10332
0
                if (!is_float)
10333
0
                    atod_type = ATOD_TYPE_BIG_INT;
10334
0
                if (has_legacy_octal)
10335
0
                    goto fail;
10336
0
            } else {
10337
0
                if (is_float && radix != 10)
10338
0
                    goto fail;
10339
0
            }
10340
0
        }
10341
0
    }
10342
10343
4.03k
    switch(atod_type) {
10344
3.03k
    case ATOD_TYPE_FLOAT64:
10345
3.03k
        {
10346
3.03k
            double d;
10347
3.03k
            d = js_strtod(buf, radix, is_float);
10348
            /* return int or float64 */
10349
3.03k
            val = JS_NewFloat64(ctx, d);
10350
3.03k
        }
10351
3.03k
        break;
10352
1.00k
    case ATOD_TYPE_BIG_INT:
10353
1.00k
        if (has_legacy_octal || is_float)
10354
0
            goto fail;
10355
1.00k
        val = ctx->rt->bigint_ops.from_string(ctx, buf, radix, flags, NULL);
10356
1.00k
        break;
10357
0
    case ATOD_TYPE_BIG_FLOAT:
10358
0
        if (has_legacy_octal)
10359
0
            goto fail;
10360
0
        val = ctx->rt->bigfloat_ops.from_string(ctx, buf, radix, flags,
10361
0
                                                pexponent);
10362
0
        break;
10363
0
    case ATOD_TYPE_BIG_DECIMAL:
10364
0
        if (radix != 10)
10365
0
            goto fail;
10366
0
        val = ctx->rt->bigdecimal_ops.from_string(ctx, buf, radix, flags, NULL);
10367
0
        break;
10368
0
    default:
10369
0
        abort();
10370
4.03k
    }
10371
#else
10372
    {
10373
        double d;
10374
        (void)has_legacy_octal;
10375
        if (is_float && radix != 10)
10376
            goto fail;
10377
        d = js_strtod(buf, radix, is_float);
10378
        val = JS_NewFloat64(ctx, d);
10379
    }
10380
#endif
10381
    
10382
157k
done:
10383
157k
    if (buf_allocated)
10384
3
        js_free_rt(ctx->rt, buf);
10385
157k
    if (pp)
10386
157k
        *pp = p;
10387
157k
    return val;
10388
153k
 fail:
10389
153k
    val = JS_NAN;
10390
153k
    goto done;
10391
0
 mem_error:
10392
0
    val = JS_ThrowOutOfMemory(ctx);
10393
0
    goto done;
10394
4.03k
}
10395
10396
#ifdef CONFIG_BIGNUM
10397
static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
10398
                       int radix, int flags)
10399
153k
{
10400
153k
    return js_atof2(ctx, str, pp, radix, flags, NULL);
10401
153k
}
10402
#endif
10403
10404
typedef enum JSToNumberHintEnum {
10405
    TON_FLAG_NUMBER,
10406
    TON_FLAG_NUMERIC,
10407
} JSToNumberHintEnum;
10408
10409
static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
10410
                                   JSToNumberHintEnum flag)
10411
348k
{
10412
348k
    uint32_t tag;
10413
348k
    JSValue ret;
10414
10415
502k
 redo:
10416
502k
    tag = JS_VALUE_GET_NORM_TAG(val);
10417
502k
    switch(tag) {
10418
0
#ifdef CONFIG_BIGNUM
10419
0
    case JS_TAG_BIG_DECIMAL:
10420
0
        if (flag != TON_FLAG_NUMERIC) {
10421
0
            JS_FreeValue(ctx, val);
10422
0
            return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number");
10423
0
        }
10424
0
        ret = val;
10425
0
        break;
10426
2
    case JS_TAG_BIG_INT:
10427
2
        if (flag != TON_FLAG_NUMERIC) {
10428
0
            JS_FreeValue(ctx, val);
10429
0
            return JS_ThrowTypeError(ctx, "cannot convert bigint to number");
10430
0
        }
10431
2
        ret = val;
10432
2
        break;
10433
0
    case JS_TAG_BIG_FLOAT:
10434
0
        if (flag != TON_FLAG_NUMERIC) {
10435
0
            JS_FreeValue(ctx, val);
10436
0
            return JS_ThrowTypeError(ctx, "cannot convert bigfloat to number");
10437
0
        }
10438
0
        ret = val;
10439
0
        break;
10440
0
#endif
10441
81.9k
    case JS_TAG_FLOAT64:
10442
153k
    case JS_TAG_INT:
10443
153k
    case JS_TAG_EXCEPTION:
10444
153k
        ret = val;
10445
153k
        break;
10446
40.9k
    case JS_TAG_BOOL:
10447
40.9k
    case JS_TAG_NULL:
10448
40.9k
        ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
10449
40.9k
        break;
10450
30
    case JS_TAG_UNDEFINED:
10451
30
        ret = JS_NAN;
10452
30
        break;
10453
153k
    case JS_TAG_OBJECT:
10454
153k
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
10455
153k
        if (JS_IsException(val))
10456
0
            return JS_EXCEPTION;
10457
153k
        goto redo;
10458
153k
    case JS_TAG_STRING:
10459
153k
        {
10460
153k
            const char *str;
10461
153k
            const char *p;
10462
153k
            size_t len;
10463
            
10464
153k
            str = JS_ToCStringLen(ctx, &len, val);
10465
153k
            JS_FreeValue(ctx, val);
10466
153k
            if (!str)
10467
0
                return JS_EXCEPTION;
10468
153k
            p = str;
10469
153k
            p += skip_spaces(p);
10470
153k
            if ((p - str) == len) {
10471
0
                ret = JS_NewInt32(ctx, 0);
10472
153k
            } else {
10473
153k
                int flags = ATOD_ACCEPT_BIN_OCT;
10474
153k
                ret = js_atof(ctx, p, &p, 0, flags);
10475
153k
                if (!JS_IsException(ret)) {
10476
153k
                    p += skip_spaces(p);
10477
153k
                    if ((p - str) != len) {
10478
153k
                        JS_FreeValue(ctx, ret);
10479
153k
                        ret = JS_NAN;
10480
153k
                    }
10481
153k
                }
10482
153k
            }
10483
153k
            JS_FreeCString(ctx, str);
10484
153k
        }
10485
0
        break;
10486
0
    case JS_TAG_SYMBOL:
10487
0
        JS_FreeValue(ctx, val);
10488
0
        return JS_ThrowTypeError(ctx, "cannot convert symbol to number");
10489
0
    default:
10490
0
        JS_FreeValue(ctx, val);
10491
0
        ret = JS_NAN;
10492
0
        break;
10493
502k
    }
10494
348k
    return ret;
10495
502k
}
10496
10497
static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val)
10498
0
{
10499
0
    return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
10500
0
}
10501
10502
static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)
10503
348k
{
10504
348k
    return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
10505
348k
}
10506
10507
static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)
10508
0
{
10509
0
    return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
10510
0
}
10511
10512
static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
10513
                                          JSValue val)
10514
0
{
10515
0
    double d;
10516
0
    uint32_t tag;
10517
10518
0
    val = JS_ToNumberFree(ctx, val);
10519
0
    if (JS_IsException(val)) {
10520
0
        *pres = JS_FLOAT64_NAN;
10521
0
        return -1;
10522
0
    }
10523
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10524
0
    switch(tag) {
10525
0
    case JS_TAG_INT:
10526
0
        d = JS_VALUE_GET_INT(val);
10527
0
        break;
10528
0
    case JS_TAG_FLOAT64:
10529
0
        d = JS_VALUE_GET_FLOAT64(val);
10530
0
        break;
10531
0
#ifdef CONFIG_BIGNUM
10532
0
    case JS_TAG_BIG_INT:
10533
0
    case JS_TAG_BIG_FLOAT:
10534
0
        {
10535
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10536
            /* XXX: there can be a double rounding issue with some
10537
               primitives (such as JS_ToUint8ClampFree()), but it is
10538
               not critical to fix it. */
10539
0
            bf_get_float64(&p->num, &d, BF_RNDN);
10540
0
            JS_FreeValue(ctx, val);
10541
0
        }
10542
0
        break;
10543
0
#endif
10544
0
    default:
10545
0
        abort();
10546
0
    }
10547
0
    *pres = d;
10548
0
    return 0;
10549
0
}
10550
10551
static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val)
10552
225k
{
10553
225k
    uint32_t tag;
10554
10555
225k
    tag = JS_VALUE_GET_TAG(val);
10556
225k
    if (tag <= JS_TAG_NULL) {
10557
71.9k
        *pres = JS_VALUE_GET_INT(val);
10558
71.9k
        return 0;
10559
153k
    } else if (JS_TAG_IS_FLOAT64(tag)) {
10560
153k
        *pres = JS_VALUE_GET_FLOAT64(val);
10561
153k
        return 0;
10562
153k
    } else {
10563
0
        return __JS_ToFloat64Free(ctx, pres, val);
10564
0
    }
10565
225k
}
10566
10567
int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val)
10568
0
{
10569
0
    return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val));
10570
0
}
10571
10572
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
10573
0
{
10574
0
    return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
10575
0
}
10576
10577
/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
10578
static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
10579
0
{
10580
0
    uint32_t tag;
10581
0
    JSValue ret;
10582
10583
0
 redo:
10584
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10585
0
    switch(tag) {
10586
0
    case JS_TAG_INT:
10587
0
    case JS_TAG_BOOL:
10588
0
    case JS_TAG_NULL:
10589
0
    case JS_TAG_UNDEFINED:
10590
0
        ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
10591
0
        break;
10592
0
    case JS_TAG_FLOAT64:
10593
0
        {
10594
0
            double d = JS_VALUE_GET_FLOAT64(val);
10595
0
            if (isnan(d)) {
10596
0
                ret = JS_NewInt32(ctx, 0);
10597
0
            } else {
10598
                /* convert -0 to +0 */
10599
0
                d = trunc(d) + 0.0;
10600
0
                ret = JS_NewFloat64(ctx, d);
10601
0
            }
10602
0
        }
10603
0
        break;
10604
0
#ifdef CONFIG_BIGNUM
10605
0
    case JS_TAG_BIG_FLOAT:
10606
0
        {
10607
0
            bf_t a_s, *a, r_s, *r = &r_s;
10608
0
            BOOL is_nan;
10609
10610
0
            a = JS_ToBigFloat(ctx, &a_s, val);
10611
0
            if (!bf_is_finite(a)) {
10612
0
                is_nan = bf_is_nan(a);
10613
0
                if (is_nan)
10614
0
                    ret = JS_NewInt32(ctx, 0);
10615
0
                else
10616
0
                    ret = JS_DupValue(ctx, val);
10617
0
            } else {
10618
0
                ret = JS_NewBigInt(ctx);
10619
0
                if (!JS_IsException(ret)) {
10620
0
                    r = JS_GetBigInt(ret);
10621
0
                    bf_set(r, a);
10622
0
                    bf_rint(r, BF_RNDZ);
10623
0
                    ret = JS_CompactBigInt(ctx, ret);
10624
0
                }
10625
0
            }
10626
0
            if (a == &a_s)
10627
0
                bf_delete(a);
10628
0
            JS_FreeValue(ctx, val);
10629
0
        }
10630
0
        break;
10631
0
#endif
10632
0
    default:
10633
0
        val = JS_ToNumberFree(ctx, val);
10634
0
        if (JS_IsException(val))
10635
0
            return val;
10636
0
        goto redo;
10637
0
    }
10638
0
    return ret;
10639
0
}
10640
10641
/* Note: the integer value is satured to 32 bits */
10642
static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val)
10643
0
{
10644
0
    uint32_t tag;
10645
0
    int ret;
10646
10647
0
 redo:
10648
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10649
0
    switch(tag) {
10650
0
    case JS_TAG_INT:
10651
0
    case JS_TAG_BOOL:
10652
0
    case JS_TAG_NULL:
10653
0
    case JS_TAG_UNDEFINED:
10654
0
        ret = JS_VALUE_GET_INT(val);
10655
0
        break;
10656
0
    case JS_TAG_EXCEPTION:
10657
0
        *pres = 0;
10658
0
        return -1;
10659
0
    case JS_TAG_FLOAT64:
10660
0
        {
10661
0
            double d = JS_VALUE_GET_FLOAT64(val);
10662
0
            if (isnan(d)) {
10663
0
                ret = 0;
10664
0
            } else {
10665
0
                if (d < INT32_MIN)
10666
0
                    ret = INT32_MIN;
10667
0
                else if (d > INT32_MAX)
10668
0
                    ret = INT32_MAX;
10669
0
                else
10670
0
                    ret = (int)d;
10671
0
            }
10672
0
        }
10673
0
        break;
10674
0
#ifdef CONFIG_BIGNUM
10675
0
    case JS_TAG_BIG_FLOAT:
10676
0
        {
10677
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10678
0
            bf_get_int32(&ret, &p->num, 0);
10679
0
            JS_FreeValue(ctx, val);
10680
0
        }
10681
0
        break;
10682
0
#endif
10683
0
    default:
10684
0
        val = JS_ToNumberFree(ctx, val);
10685
0
        if (JS_IsException(val)) {
10686
0
            *pres = 0;
10687
0
            return -1;
10688
0
        }
10689
0
        goto redo;
10690
0
    }
10691
0
    *pres = ret;
10692
0
    return 0;
10693
0
}
10694
10695
int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val)
10696
0
{
10697
0
    return JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
10698
0
}
10699
10700
int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val,
10701
                    int min, int max, int min_offset)
10702
0
{
10703
0
    int res = JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
10704
0
    if (res == 0) {
10705
0
        if (*pres < min) {
10706
0
            *pres += min_offset;
10707
0
            if (*pres < min)
10708
0
                *pres = min;
10709
0
        } else {
10710
0
            if (*pres > max)
10711
0
                *pres = max;
10712
0
        }
10713
0
    }
10714
0
    return res;
10715
0
}
10716
10717
static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val)
10718
9
{
10719
9
    uint32_t tag;
10720
10721
9
 redo:
10722
9
    tag = JS_VALUE_GET_NORM_TAG(val);
10723
9
    switch(tag) {
10724
9
    case JS_TAG_INT:
10725
9
    case JS_TAG_BOOL:
10726
9
    case JS_TAG_NULL:
10727
9
    case JS_TAG_UNDEFINED:
10728
9
        *pres = JS_VALUE_GET_INT(val);
10729
9
        return 0;
10730
0
    case JS_TAG_EXCEPTION:
10731
0
        *pres = 0;
10732
0
        return -1;
10733
0
    case JS_TAG_FLOAT64:
10734
0
        {
10735
0
            double d = JS_VALUE_GET_FLOAT64(val);
10736
0
            if (isnan(d)) {
10737
0
                *pres = 0;
10738
0
            } else {
10739
0
                if (d < INT64_MIN)
10740
0
                    *pres = INT64_MIN;
10741
0
                else if (d > INT64_MAX)
10742
0
                    *pres = INT64_MAX;
10743
0
                else
10744
0
                    *pres = (int64_t)d;
10745
0
            }
10746
0
        }
10747
0
        return 0;
10748
0
#ifdef CONFIG_BIGNUM
10749
0
    case JS_TAG_BIG_FLOAT:
10750
0
        {
10751
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10752
0
            bf_get_int64(pres, &p->num, 0);
10753
0
            JS_FreeValue(ctx, val);
10754
0
        }
10755
0
        return 0;
10756
0
#endif
10757
0
    default:
10758
0
        val = JS_ToNumberFree(ctx, val);
10759
0
        if (JS_IsException(val)) {
10760
0
            *pres = 0;
10761
0
            return -1;
10762
0
        }
10763
0
        goto redo;
10764
9
    }
10765
9
}
10766
10767
int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val)
10768
0
{
10769
0
    return JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
10770
0
}
10771
10772
int JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValueConst val,
10773
                    int64_t min, int64_t max, int64_t neg_offset)
10774
9
{
10775
9
    int res = JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
10776
9
    if (res == 0) {
10777
9
        if (*pres < 0)
10778
0
            *pres += neg_offset;
10779
9
        if (*pres < min)
10780
0
            *pres = min;
10781
9
        else if (*pres > max)
10782
0
            *pres = max;
10783
9
    }
10784
9
    return res;
10785
9
}
10786
10787
/* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0)
10788
   in case of exception */
10789
static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
10790
0
{
10791
0
    uint32_t tag;
10792
0
    int64_t ret;
10793
10794
0
 redo:
10795
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10796
0
    switch(tag) {
10797
0
    case JS_TAG_INT:
10798
0
    case JS_TAG_BOOL:
10799
0
    case JS_TAG_NULL:
10800
0
    case JS_TAG_UNDEFINED:
10801
0
        ret = JS_VALUE_GET_INT(val);
10802
0
        break;
10803
0
    case JS_TAG_FLOAT64:
10804
0
        {
10805
0
            JSFloat64Union u;
10806
0
            double d;
10807
0
            int e;
10808
0
            d = JS_VALUE_GET_FLOAT64(val);
10809
0
            u.d = d;
10810
            /* we avoid doing fmod(x, 2^64) */
10811
0
            e = (u.u64 >> 52) & 0x7ff;
10812
0
            if (likely(e <= (1023 + 62))) {
10813
                /* fast case */
10814
0
                ret = (int64_t)d;
10815
0
            } else if (e <= (1023 + 62 + 53)) {
10816
0
                uint64_t v;
10817
                /* remainder modulo 2^64 */
10818
0
                v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
10819
0
                ret = v << ((e - 1023) - 52);
10820
                /* take the sign into account */
10821
0
                if (u.u64 >> 63)
10822
0
                    ret = -ret;
10823
0
            } else {
10824
0
                ret = 0; /* also handles NaN and +inf */
10825
0
            }
10826
0
        }
10827
0
        break;
10828
0
#ifdef CONFIG_BIGNUM
10829
0
    case JS_TAG_BIG_FLOAT:
10830
0
        {
10831
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10832
0
            bf_get_int64(&ret, &p->num, BF_GET_INT_MOD);
10833
0
            JS_FreeValue(ctx, val);
10834
0
        }
10835
0
        break;
10836
0
#endif
10837
0
    default:
10838
0
        val = JS_ToNumberFree(ctx, val);
10839
0
        if (JS_IsException(val)) {
10840
0
            *pres = 0;
10841
0
            return -1;
10842
0
        }
10843
0
        goto redo;
10844
0
    }
10845
0
    *pres = ret;
10846
0
    return 0;
10847
0
}
10848
10849
int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
10850
0
{
10851
0
    return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val));
10852
0
}
10853
10854
int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val)
10855
0
{
10856
0
    if (JS_IsBigInt(ctx, val))
10857
0
        return JS_ToBigInt64(ctx, pres, val);
10858
0
    else
10859
0
        return JS_ToInt64(ctx, pres, val);
10860
0
}
10861
10862
/* return (<0, 0) in case of exception */
10863
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)
10864
82.6k
{
10865
82.6k
    uint32_t tag;
10866
82.6k
    int32_t ret;
10867
10868
82.6k
 redo:
10869
82.6k
    tag = JS_VALUE_GET_NORM_TAG(val);
10870
82.6k
    switch(tag) {
10871
41.6k
    case JS_TAG_INT:
10872
41.6k
    case JS_TAG_BOOL:
10873
41.6k
    case JS_TAG_NULL:
10874
41.6k
    case JS_TAG_UNDEFINED:
10875
41.6k
        ret = JS_VALUE_GET_INT(val);
10876
41.6k
        break;
10877
41.0k
    case JS_TAG_FLOAT64:
10878
41.0k
        {
10879
41.0k
            JSFloat64Union u;
10880
41.0k
            double d;
10881
41.0k
            int e;
10882
41.0k
            d = JS_VALUE_GET_FLOAT64(val);
10883
41.0k
            u.d = d;
10884
            /* we avoid doing fmod(x, 2^32) */
10885
41.0k
            e = (u.u64 >> 52) & 0x7ff;
10886
41.0k
            if (likely(e <= (1023 + 30))) {
10887
                /* fast case */
10888
0
                ret = (int32_t)d;
10889
41.0k
            } else if (e <= (1023 + 30 + 53)) {
10890
0
                uint64_t v;
10891
                /* remainder modulo 2^32 */
10892
0
                v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
10893
0
                v = v << ((e - 1023) - 52 + 32);
10894
0
                ret = v >> 32;
10895
                /* take the sign into account */
10896
0
                if (u.u64 >> 63)
10897
0
                    ret = -ret;
10898
41.0k
            } else {
10899
41.0k
                ret = 0; /* also handles NaN and +inf */
10900
41.0k
            }
10901
41.0k
        }
10902
41.0k
        break;
10903
0
#ifdef CONFIG_BIGNUM
10904
0
    case JS_TAG_BIG_FLOAT:
10905
0
        {
10906
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10907
0
            bf_get_int32(&ret, &p->num, BF_GET_INT_MOD);
10908
0
            JS_FreeValue(ctx, val);
10909
0
        }
10910
0
        break;
10911
0
#endif
10912
0
    default:
10913
0
        val = JS_ToNumberFree(ctx, val);
10914
0
        if (JS_IsException(val)) {
10915
0
            *pres = 0;
10916
0
            return -1;
10917
0
        }
10918
0
        goto redo;
10919
82.6k
    }
10920
82.6k
    *pres = ret;
10921
82.6k
    return 0;
10922
82.6k
}
10923
10924
int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val)
10925
608
{
10926
608
    return JS_ToInt32Free(ctx, pres, JS_DupValue(ctx, val));
10927
608
}
10928
10929
static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val)
10930
2
{
10931
2
    return JS_ToInt32Free(ctx, (int32_t *)pres, val);
10932
2
}
10933
10934
static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
10935
0
{
10936
0
    uint32_t tag;
10937
0
    int res;
10938
10939
0
 redo:
10940
0
    tag = JS_VALUE_GET_NORM_TAG(val);
10941
0
    switch(tag) {
10942
0
    case JS_TAG_INT:
10943
0
    case JS_TAG_BOOL:
10944
0
    case JS_TAG_NULL:
10945
0
    case JS_TAG_UNDEFINED:
10946
0
        res = JS_VALUE_GET_INT(val);
10947
0
#ifdef CONFIG_BIGNUM
10948
0
    int_clamp:
10949
0
#endif
10950
0
        res = max_int(0, min_int(255, res));
10951
0
        break;
10952
0
    case JS_TAG_FLOAT64:
10953
0
        {
10954
0
            double d = JS_VALUE_GET_FLOAT64(val);
10955
0
            if (isnan(d)) {
10956
0
                res = 0;
10957
0
            } else {
10958
0
                if (d < 0)
10959
0
                    res = 0;
10960
0
                else if (d > 255)
10961
0
                    res = 255;
10962
0
                else
10963
0
                    res = lrint(d);
10964
0
            }
10965
0
        }
10966
0
        break;
10967
0
#ifdef CONFIG_BIGNUM
10968
0
    case JS_TAG_BIG_FLOAT:
10969
0
        {
10970
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
10971
0
            bf_t r_s, *r = &r_s;
10972
0
            bf_init(ctx->bf_ctx, r);
10973
0
            bf_set(r, &p->num);
10974
0
            bf_rint(r, BF_RNDN);
10975
0
            bf_get_int32(&res, r, 0);
10976
0
            bf_delete(r);
10977
0
            JS_FreeValue(ctx, val);
10978
0
        }
10979
0
        goto int_clamp;
10980
0
#endif
10981
0
    default:
10982
0
        val = JS_ToNumberFree(ctx, val);
10983
0
        if (JS_IsException(val)) {
10984
0
            *pres = 0;
10985
0
            return -1;
10986
0
        }
10987
0
        goto redo;
10988
0
    }
10989
0
    *pres = res;
10990
0
    return 0;
10991
0
}
10992
10993
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
10994
                                            JSValue val, BOOL is_array_ctor)
10995
163k
{
10996
163k
    uint32_t tag, len;
10997
10998
163k
    tag = JS_VALUE_GET_TAG(val);
10999
163k
    switch(tag) {
11000
163k
    case JS_TAG_INT:
11001
163k
    case JS_TAG_BOOL:
11002
163k
    case JS_TAG_NULL:
11003
163k
        {
11004
163k
            int v;
11005
163k
            v = JS_VALUE_GET_INT(val);
11006
163k
            if (v < 0)
11007
0
                goto fail;
11008
163k
            len = v;
11009
163k
        }
11010
0
        break;
11011
0
#ifdef CONFIG_BIGNUM
11012
0
    case JS_TAG_BIG_INT:
11013
0
    case JS_TAG_BIG_FLOAT:
11014
0
        {
11015
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11016
0
            bf_t a;
11017
0
            BOOL res;
11018
0
            bf_get_int32((int32_t *)&len, &p->num, BF_GET_INT_MOD);
11019
0
            bf_init(ctx->bf_ctx, &a);
11020
0
            bf_set_ui(&a, len);
11021
0
            res = bf_cmp_eq(&a, &p->num);
11022
0
            bf_delete(&a);
11023
0
            JS_FreeValue(ctx, val);
11024
0
            if (!res)
11025
0
                goto fail;
11026
0
        }
11027
0
        break;
11028
0
#endif
11029
0
    default:
11030
0
        if (JS_TAG_IS_FLOAT64(tag)) {
11031
0
            double d;
11032
0
            d = JS_VALUE_GET_FLOAT64(val);
11033
0
            len = (uint32_t)d;
11034
0
            if (len != d)
11035
0
                goto fail;
11036
0
        } else {
11037
0
            uint32_t len1;
11038
11039
0
            if (is_array_ctor) {
11040
0
                val = JS_ToNumberFree(ctx, val);
11041
0
                if (JS_IsException(val))
11042
0
                    return -1;
11043
                /* cannot recurse because val is a number */
11044
0
                if (JS_ToArrayLengthFree(ctx, &len, val, TRUE))
11045
0
                    return -1;
11046
0
            } else {
11047
                /* legacy behavior: must do the conversion twice and compare */
11048
0
                if (JS_ToUint32(ctx, &len, val)) {
11049
0
                    JS_FreeValue(ctx, val);
11050
0
                    return -1;
11051
0
                }
11052
0
                val = JS_ToNumberFree(ctx, val);
11053
0
                if (JS_IsException(val))
11054
0
                    return -1;
11055
                /* cannot recurse because val is a number */
11056
0
                if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE))
11057
0
                    return -1;
11058
0
                if (len1 != len) {
11059
0
                fail:
11060
0
                    JS_ThrowRangeError(ctx, "invalid array length");
11061
0
                    return -1;
11062
0
                }
11063
0
            }
11064
0
        }
11065
0
        break;
11066
163k
    }
11067
163k
    *plen = len;
11068
163k
    return 0;
11069
163k
}
11070
11071
1.00k
#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
11072
11073
static BOOL is_safe_integer(double d)
11074
0
{
11075
0
    return isfinite(d) && floor(d) == d &&
11076
0
        fabs(d) <= (double)MAX_SAFE_INTEGER;
11077
0
}
11078
11079
int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
11080
0
{
11081
0
    int64_t v;
11082
0
    if (JS_ToInt64Sat(ctx, &v, val))
11083
0
        return -1;
11084
0
    if (v < 0 || v > MAX_SAFE_INTEGER) {
11085
0
        JS_ThrowRangeError(ctx, "invalid array index");
11086
0
        *plen = 0;
11087
0
        return -1;
11088
0
    }
11089
0
    *plen = v;
11090
0
    return 0;
11091
0
}
11092
11093
/* convert a value to a length between 0 and MAX_SAFE_INTEGER.
11094
   return -1 for exception */
11095
static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
11096
                                       JSValue val)
11097
9
{
11098
9
    int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0);
11099
9
    JS_FreeValue(ctx, val);
11100
9
    return res;
11101
9
}
11102
11103
/* Note: can return an exception */
11104
static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)
11105
0
{
11106
0
    double d;
11107
0
    if (!JS_IsNumber(val))
11108
0
        return FALSE;
11109
0
    if (unlikely(JS_ToFloat64(ctx, &d, val)))
11110
0
        return -1;
11111
0
    return isfinite(d) && floor(d) == d;
11112
0
}
11113
11114
static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val)
11115
0
{
11116
0
    uint32_t tag;
11117
11118
0
    tag = JS_VALUE_GET_NORM_TAG(val);
11119
0
    switch(tag) {
11120
0
    case JS_TAG_INT:
11121
0
        {
11122
0
            int v;
11123
0
            v = JS_VALUE_GET_INT(val);
11124
0
            return (v < 0);
11125
0
        }
11126
0
    case JS_TAG_FLOAT64:
11127
0
        {
11128
0
            JSFloat64Union u;
11129
0
            u.d = JS_VALUE_GET_FLOAT64(val);
11130
0
            return (u.u64 >> 63);
11131
0
        }
11132
0
#ifdef CONFIG_BIGNUM
11133
0
    case JS_TAG_BIG_INT:
11134
0
        {
11135
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11136
            /* Note: integer zeros are not necessarily positive */
11137
0
            return p->num.sign && !bf_is_zero(&p->num);
11138
0
        }
11139
0
    case JS_TAG_BIG_FLOAT:
11140
0
        {
11141
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11142
0
            return p->num.sign;
11143
0
        }
11144
0
        break;
11145
0
    case JS_TAG_BIG_DECIMAL:
11146
0
        {
11147
0
            JSBigDecimal *p = JS_VALUE_GET_PTR(val);
11148
0
            return p->num.sign;
11149
0
        }
11150
0
        break;
11151
0
#endif
11152
0
    default:
11153
0
        return FALSE;
11154
0
    }
11155
0
}
11156
11157
#ifdef CONFIG_BIGNUM
11158
11159
static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)
11160
34
{
11161
34
    JSValue ret;
11162
34
    bf_t a_s, *a;
11163
34
    char *str;
11164
34
    int saved_sign;
11165
11166
34
    a = JS_ToBigInt(ctx, &a_s, val);
11167
34
    if (!a)
11168
0
        return JS_EXCEPTION;
11169
34
    saved_sign = a->sign;
11170
34
    if (a->expn == BF_EXP_ZERO)
11171
0
        a->sign = 0;
11172
34
    str = bf_ftoa(NULL, a, radix, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC |
11173
34
                  BF_FTOA_JS_QUIRKS);
11174
34
    a->sign = saved_sign;
11175
34
    JS_FreeBigInt(ctx, a, &a_s);
11176
34
    if (!str)
11177
0
        return JS_ThrowOutOfMemory(ctx);
11178
34
    ret = JS_NewString(ctx, str);
11179
34
    bf_free(ctx->bf_ctx, str);
11180
34
    return ret;
11181
34
}
11182
11183
static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val)
11184
34
{
11185
34
    return js_bigint_to_string1(ctx, val, 10);
11186
34
}
11187
11188
static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix,
11189
                       limb_t prec, bf_flags_t flags)
11190
0
{
11191
0
    JSValue val, ret;
11192
0
    bf_t a_s, *a;
11193
0
    char *str;
11194
0
    int saved_sign;
11195
11196
0
    val = JS_ToNumeric(ctx, val1);
11197
0
    if (JS_IsException(val))
11198
0
        return val;
11199
0
    a = JS_ToBigFloat(ctx, &a_s, val);
11200
0
    saved_sign = a->sign;
11201
0
    if (a->expn == BF_EXP_ZERO)
11202
0
        a->sign = 0;
11203
0
    flags |= BF_FTOA_JS_QUIRKS;
11204
0
    if ((flags & BF_FTOA_FORMAT_MASK) == BF_FTOA_FORMAT_FREE_MIN) {
11205
        /* Note: for floating point numbers with a radix which is not
11206
           a power of two, the current precision is used to compute
11207
           the number of digits. */
11208
0
        if ((radix & (radix - 1)) != 0) {
11209
0
            bf_t r_s, *r = &r_s;
11210
0
            int prec, flags1;
11211
            /* must round first */
11212
0
            if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
11213
0
                prec = ctx->fp_env.prec;
11214
0
                flags1 = ctx->fp_env.flags &
11215
0
                    (BF_FLAG_SUBNORMAL | (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT));
11216
0
            } else {
11217
0
                prec = 53;
11218
0
                flags1 = bf_set_exp_bits(11) | BF_FLAG_SUBNORMAL;
11219
0
            }
11220
0
            bf_init(ctx->bf_ctx, r);
11221
0
            bf_set(r, a);
11222
0
            bf_round(r, prec, flags1 | BF_RNDN);
11223
0
            str = bf_ftoa(NULL, r, radix, prec, flags1 | flags);
11224
0
            bf_delete(r);
11225
0
        } else {
11226
0
            str = bf_ftoa(NULL, a, radix, BF_PREC_INF, flags);
11227
0
        }
11228
0
    } else {
11229
0
        str = bf_ftoa(NULL, a, radix, prec, flags);
11230
0
    }
11231
0
    a->sign = saved_sign;
11232
0
    if (a == &a_s)
11233
0
        bf_delete(a);
11234
0
    JS_FreeValue(ctx, val);
11235
0
    if (!str)
11236
0
        return JS_ThrowOutOfMemory(ctx);
11237
0
    ret = JS_NewString(ctx, str);
11238
0
    bf_free(ctx->bf_ctx, str);
11239
0
    return ret;
11240
0
}
11241
11242
static JSValue js_bigfloat_to_string(JSContext *ctx, JSValueConst val)
11243
0
{
11244
0
    return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
11245
0
}
11246
11247
static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val,
11248
                                        limb_t prec, int flags)
11249
0
{
11250
0
    JSValue ret;
11251
0
    bfdec_t *a;
11252
0
    char *str;
11253
0
    int saved_sign;
11254
11255
0
    a = JS_ToBigDecimal(ctx, val);
11256
0
    saved_sign = a->sign;
11257
0
    if (a->expn == BF_EXP_ZERO)
11258
0
        a->sign = 0;
11259
0
    str = bfdec_ftoa(NULL, a, prec, flags | BF_FTOA_JS_QUIRKS);
11260
0
    a->sign = saved_sign;
11261
0
    if (!str)
11262
0
        return JS_ThrowOutOfMemory(ctx);
11263
0
    ret = JS_NewString(ctx, str);
11264
0
    bf_free(ctx->bf_ctx, str);
11265
0
    return ret;
11266
0
}
11267
11268
static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
11269
0
{
11270
0
    return js_bigdecimal_to_string1(ctx, val, 0,
11271
0
                                    BF_RNDZ | BF_FTOA_FORMAT_FREE);
11272
0
}
11273
11274
#endif /* CONFIG_BIGNUM */
11275
11276
/* 2 <= base <= 36 */
11277
static char *i64toa(char *buf_end, int64_t n, unsigned int base)
11278
0
{
11279
0
    char *q = buf_end;
11280
0
    int digit, is_neg;
11281
11282
0
    is_neg = 0;
11283
0
    if (n < 0) {
11284
0
        is_neg = 1;
11285
0
        n = -n;
11286
0
    }
11287
0
    *--q = '\0';
11288
0
    do {
11289
0
        digit = (uint64_t)n % base;
11290
0
        n = (uint64_t)n / base;
11291
0
        if (digit < 10)
11292
0
            digit += '0';
11293
0
        else
11294
0
            digit += 'a' - 10;
11295
0
        *--q = digit;
11296
0
    } while (n != 0);
11297
0
    if (is_neg)
11298
0
        *--q = '-';
11299
0
    return q;
11300
0
}
11301
11302
/* buf1 contains the printf result */
11303
static void js_ecvt1(double d, int n_digits, int *decpt, int *sign, char *buf,
11304
                     int rounding_mode, char *buf1, int buf1_size)
11305
5
{
11306
5
    if (rounding_mode != FE_TONEAREST)
11307
0
        fesetround(rounding_mode);
11308
5
    snprintf(buf1, buf1_size, "%+.*e", n_digits - 1, d);
11309
5
    if (rounding_mode != FE_TONEAREST)
11310
0
        fesetround(FE_TONEAREST);
11311
5
    *sign = (buf1[0] == '-');
11312
    /* mantissa */
11313
5
    buf[0] = buf1[1];
11314
5
    if (n_digits > 1)
11315
5
        memcpy(buf + 1, buf1 + 3, n_digits - 1);
11316
5
    buf[n_digits] = '\0';
11317
    /* exponent */
11318
5
    *decpt = atoi(buf1 + n_digits + 2 + (n_digits > 1)) + 1;
11319
5
}
11320
11321
/* maximum buffer size for js_dtoa */
11322
0
#define JS_DTOA_BUF_SIZE 128
11323
11324
/* needed because ecvt usually limits the number of digits to
11325
   17. Return the number of digits. */
11326
static int js_ecvt(double d, int n_digits, int *decpt, int *sign, char *buf,
11327
                   BOOL is_fixed)
11328
1
{
11329
1
    int rounding_mode;
11330
1
    char buf_tmp[JS_DTOA_BUF_SIZE];
11331
11332
1
    if (!is_fixed) {
11333
1
        unsigned int n_digits_min, n_digits_max;
11334
        /* find the minimum amount of digits (XXX: inefficient but simple) */
11335
1
        n_digits_min = 1;
11336
1
        n_digits_max = 17;
11337
5
        while (n_digits_min < n_digits_max) {
11338
4
            n_digits = (n_digits_min + n_digits_max) / 2;
11339
4
            js_ecvt1(d, n_digits, decpt, sign, buf, FE_TONEAREST,
11340
4
                     buf_tmp, sizeof(buf_tmp));
11341
4
            if (strtod(buf_tmp, NULL) == d) {
11342
                /* no need to keep the trailing zeros */
11343
1
                while (n_digits >= 2 && buf[n_digits - 1] == '0')
11344
0
                    n_digits--;
11345
1
                n_digits_max = n_digits;
11346
3
            } else {
11347
3
                n_digits_min = n_digits + 1;
11348
3
            }
11349
4
        }
11350
1
        n_digits = n_digits_max;
11351
1
        rounding_mode = FE_TONEAREST;
11352
1
    } else {
11353
0
        rounding_mode = FE_TONEAREST;
11354
0
#ifdef CONFIG_PRINTF_RNDN
11355
0
        {
11356
0
            char buf1[JS_DTOA_BUF_SIZE], buf2[JS_DTOA_BUF_SIZE];
11357
0
            int decpt1, sign1, decpt2, sign2;
11358
            /* The JS rounding is specified as round to nearest ties away
11359
               from zero (RNDNA), but in printf the "ties" case is not
11360
               specified (for example it is RNDN for glibc, RNDNA for
11361
               Windows), so we must round manually. */
11362
0
            js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_TONEAREST,
11363
0
                     buf_tmp, sizeof(buf_tmp));
11364
            /* XXX: could use 2 digits to reduce the average running time */
11365
0
            if (buf1[n_digits] == '5') {
11366
0
                js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_DOWNWARD,
11367
0
                         buf_tmp, sizeof(buf_tmp));
11368
0
                js_ecvt1(d, n_digits + 1, &decpt2, &sign2, buf2, FE_UPWARD,
11369
0
                         buf_tmp, sizeof(buf_tmp));
11370
0
                if (memcmp(buf1, buf2, n_digits + 1) == 0 && decpt1 == decpt2) {
11371
                    /* exact result: round away from zero */
11372
0
                    if (sign1)
11373
0
                        rounding_mode = FE_DOWNWARD;
11374
0
                    else
11375
0
                        rounding_mode = FE_UPWARD;
11376
0
                }
11377
0
            }
11378
0
        }
11379
0
#endif /* CONFIG_PRINTF_RNDN */
11380
0
    }
11381
1
    js_ecvt1(d, n_digits, decpt, sign, buf, rounding_mode,
11382
1
             buf_tmp, sizeof(buf_tmp));
11383
1
    return n_digits;
11384
1
}
11385
11386
static int js_fcvt1(char *buf, int buf_size, double d, int n_digits,
11387
                    int rounding_mode)
11388
0
{
11389
0
    int n;
11390
0
    if (rounding_mode != FE_TONEAREST)
11391
0
        fesetround(rounding_mode);
11392
0
    n = snprintf(buf, buf_size, "%.*f", n_digits, d);
11393
0
    if (rounding_mode != FE_TONEAREST)
11394
0
        fesetround(FE_TONEAREST);
11395
0
    assert(n < buf_size);
11396
0
    return n;
11397
0
}
11398
11399
static void js_fcvt(char *buf, int buf_size, double d, int n_digits)
11400
0
{
11401
0
    int rounding_mode;
11402
0
    rounding_mode = FE_TONEAREST;
11403
0
#ifdef CONFIG_PRINTF_RNDN
11404
0
    {
11405
0
        int n1, n2;
11406
0
        char buf1[JS_DTOA_BUF_SIZE];
11407
0
        char buf2[JS_DTOA_BUF_SIZE];
11408
11409
        /* The JS rounding is specified as round to nearest ties away from
11410
           zero (RNDNA), but in printf the "ties" case is not specified
11411
           (for example it is RNDN for glibc, RNDNA for Windows), so we
11412
           must round manually. */
11413
0
        n1 = js_fcvt1(buf1, sizeof(buf1), d, n_digits + 1, FE_TONEAREST);
11414
0
        rounding_mode = FE_TONEAREST;
11415
        /* XXX: could use 2 digits to reduce the average running time */
11416
0
        if (buf1[n1 - 1] == '5') {
11417
0
            n1 = js_fcvt1(buf1, sizeof(buf1), d, n_digits + 1, FE_DOWNWARD);
11418
0
            n2 = js_fcvt1(buf2, sizeof(buf2), d, n_digits + 1, FE_UPWARD);
11419
0
            if (n1 == n2 && memcmp(buf1, buf2, n1) == 0) {
11420
                /* exact result: round away from zero */
11421
0
                if (buf1[0] == '-')
11422
0
                    rounding_mode = FE_DOWNWARD;
11423
0
                else
11424
0
                    rounding_mode = FE_UPWARD;
11425
0
            }
11426
0
        }
11427
0
    }
11428
0
#endif /* CONFIG_PRINTF_RNDN */
11429
0
    js_fcvt1(buf, buf_size, d, n_digits, rounding_mode);
11430
0
}
11431
11432
/* radix != 10 is only supported with flags = JS_DTOA_VAR_FORMAT */
11433
/* use as many digits as necessary */
11434
71.9k
#define JS_DTOA_VAR_FORMAT   (0 << 0)
11435
/* use n_digits significant digits (1 <= n_digits <= 101) */
11436
1
#define JS_DTOA_FIXED_FORMAT (1 << 0)
11437
/* force fractional format: [-]dd.dd with n_digits fractional digits */
11438
0
#define JS_DTOA_FRAC_FORMAT  (2 << 0)
11439
/* force exponential notation either in fixed or variable format */
11440
1
#define JS_DTOA_FORCE_EXP    (1 << 2)
11441
11442
/* XXX: slow and maybe not fully correct. Use libbf when it is fast enough.
11443
   XXX: radix != 10 is only supported for small integers
11444
*/
11445
static void js_dtoa1(char *buf, double d, int radix, int n_digits, int flags)
11446
71.9k
{
11447
71.9k
    char *q;
11448
11449
71.9k
    if (!isfinite(d)) {
11450
71.9k
        if (isnan(d)) {
11451
71.9k
            strcpy(buf, "NaN");
11452
71.9k
        } else {
11453
0
            q = buf;
11454
0
            if (d < 0)
11455
0
                *q++ = '-';
11456
0
            strcpy(q, "Infinity");
11457
0
        }
11458
71.9k
    } else if (flags == JS_DTOA_VAR_FORMAT) {
11459
1
        int64_t i64;
11460
1
        char buf1[70], *ptr;
11461
1
        i64 = (int64_t)d;
11462
1
        if (d != i64 || i64 > MAX_SAFE_INTEGER || i64 < -MAX_SAFE_INTEGER)
11463
1
            goto generic_conv;
11464
        /* fast path for integers */
11465
0
        ptr = i64toa(buf1 + sizeof(buf1), i64, radix);
11466
0
        strcpy(buf, ptr);
11467
0
    } else {
11468
0
        if (d == 0.0)
11469
0
            d = 0.0; /* convert -0 to 0 */
11470
0
        if (flags == JS_DTOA_FRAC_FORMAT) {
11471
0
            js_fcvt(buf, JS_DTOA_BUF_SIZE, d, n_digits);
11472
0
        } else {
11473
0
            char buf1[JS_DTOA_BUF_SIZE];
11474
0
            int sign, decpt, k, n, i, p, n_max;
11475
0
            BOOL is_fixed;
11476
1
        generic_conv:
11477
1
            is_fixed = ((flags & 3) == JS_DTOA_FIXED_FORMAT);
11478
1
            if (is_fixed) {
11479
0
                n_max = n_digits;
11480
1
            } else {
11481
1
                n_max = 21;
11482
1
            }
11483
            /* the number has k digits (k >= 1) */
11484
1
            k = js_ecvt(d, n_digits, &decpt, &sign, buf1, is_fixed);
11485
1
            n = decpt; /* d=10^(n-k)*(buf1) i.e. d= < x.yyyy 10^(n-1) */
11486
1
            q = buf;
11487
1
            if (sign)
11488
0
                *q++ = '-';
11489
1
            if (flags & JS_DTOA_FORCE_EXP)
11490
0
                goto force_exp;
11491
1
            if (n >= 1 && n <= n_max) {
11492
1
                if (k <= n) {
11493
1
                    memcpy(q, buf1, k);
11494
1
                    q += k;
11495
4
                    for(i = 0; i < (n - k); i++)
11496
3
                        *q++ = '0';
11497
1
                    *q = '\0';
11498
1
                } else {
11499
                    /* k > n */
11500
0
                    memcpy(q, buf1, n);
11501
0
                    q += n;
11502
0
                    *q++ = '.';
11503
0
                    for(i = 0; i < (k - n); i++)
11504
0
                        *q++ = buf1[n + i];
11505
0
                    *q = '\0';
11506
0
                }
11507
1
            } else if (n >= -5 && n <= 0) {
11508
0
                *q++ = '0';
11509
0
                *q++ = '.';
11510
0
                for(i = 0; i < -n; i++)
11511
0
                    *q++ = '0';
11512
0
                memcpy(q, buf1, k);
11513
0
                q += k;
11514
0
                *q = '\0';
11515
0
            } else {
11516
0
            force_exp:
11517
                /* exponential notation */
11518
0
                *q++ = buf1[0];
11519
0
                if (k > 1) {
11520
0
                    *q++ = '.';
11521
0
                    for(i = 1; i < k; i++)
11522
0
                        *q++ = buf1[i];
11523
0
                }
11524
0
                *q++ = 'e';
11525
0
                p = n - 1;
11526
0
                if (p >= 0)
11527
0
                    *q++ = '+';
11528
0
                sprintf(q, "%d", p);
11529
0
            }
11530
1
        }
11531
0
    }
11532
71.9k
}
11533
11534
static JSValue js_dtoa(JSContext *ctx,
11535
                       double d, int radix, int n_digits, int flags)
11536
71.9k
{
11537
71.9k
    char buf[JS_DTOA_BUF_SIZE];
11538
71.9k
    js_dtoa1(buf, d, radix, n_digits, flags);
11539
71.9k
    return JS_NewString(ctx, buf);
11540
71.9k
}
11541
11542
JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey)
11543
118k
{
11544
118k
    uint32_t tag;
11545
118k
    const char *str;
11546
118k
    char buf[32];
11547
11548
118k
    tag = JS_VALUE_GET_NORM_TAG(val);
11549
118k
    switch(tag) {
11550
46.9k
    case JS_TAG_STRING:
11551
46.9k
        return JS_DupValue(ctx, val);
11552
0
    case JS_TAG_INT:
11553
0
        snprintf(buf, sizeof(buf), "%d", JS_VALUE_GET_INT(val));
11554
0
        str = buf;
11555
0
        goto new_string;
11556
0
    case JS_TAG_BOOL:
11557
0
        return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
11558
0
                          JS_ATOM_true : JS_ATOM_false);
11559
1
    case JS_TAG_NULL:
11560
1
        return JS_AtomToString(ctx, JS_ATOM_null);
11561
6
    case JS_TAG_UNDEFINED:
11562
6
        return JS_AtomToString(ctx, JS_ATOM_undefined);
11563
0
    case JS_TAG_EXCEPTION:
11564
0
        return JS_EXCEPTION;
11565
8
    case JS_TAG_OBJECT:
11566
8
        {
11567
8
            JSValue val1, ret;
11568
8
            val1 = JS_ToPrimitive(ctx, val, HINT_STRING);
11569
8
            if (JS_IsException(val1))
11570
0
                return val1;
11571
8
            ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey);
11572
8
            JS_FreeValue(ctx, val1);
11573
8
            return ret;
11574
8
        }
11575
0
        break;
11576
0
    case JS_TAG_FUNCTION_BYTECODE:
11577
0
        str = "[function bytecode]";
11578
0
        goto new_string;
11579
0
    case JS_TAG_SYMBOL:
11580
0
        if (is_ToPropertyKey) {
11581
0
            return JS_DupValue(ctx, val);
11582
0
        } else {
11583
0
            return JS_ThrowTypeError(ctx, "cannot convert symbol to string");
11584
0
        }
11585
71.9k
    case JS_TAG_FLOAT64:
11586
71.9k
        return js_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0,
11587
71.9k
                       JS_DTOA_VAR_FORMAT);
11588
0
#ifdef CONFIG_BIGNUM
11589
34
    case JS_TAG_BIG_INT:
11590
34
        return ctx->rt->bigint_ops.to_string(ctx, val);
11591
0
    case JS_TAG_BIG_FLOAT:
11592
0
        return ctx->rt->bigfloat_ops.to_string(ctx, val);
11593
0
    case JS_TAG_BIG_DECIMAL:
11594
0
        return ctx->rt->bigdecimal_ops.to_string(ctx, val);
11595
0
#endif
11596
0
    default:
11597
0
        str = "[unsupported type]";
11598
0
    new_string:
11599
0
        return JS_NewString(ctx, str);
11600
118k
    }
11601
118k
}
11602
11603
JSValue JS_ToString(JSContext *ctx, JSValueConst val)
11604
71.9k
{
11605
71.9k
    return JS_ToStringInternal(ctx, val, FALSE);
11606
71.9k
}
11607
11608
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val)
11609
71.9k
{
11610
71.9k
    JSValue ret;
11611
71.9k
    ret = JS_ToString(ctx, val);
11612
71.9k
    JS_FreeValue(ctx, val);
11613
71.9k
    return ret;
11614
71.9k
}
11615
11616
static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val)
11617
0
{
11618
0
    if (JS_IsUndefined(val) || JS_IsNull(val))
11619
0
        return JS_ToStringFree(ctx, val);
11620
0
    return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL);
11621
0
}
11622
11623
JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val)
11624
46.9k
{
11625
46.9k
    return JS_ToStringInternal(ctx, val, TRUE);
11626
46.9k
}
11627
11628
static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val)
11629
3
{
11630
3
    uint32_t tag = JS_VALUE_GET_TAG(val);
11631
3
    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
11632
0
        return JS_ThrowTypeError(ctx, "null or undefined are forbidden");
11633
3
    return JS_ToString(ctx, val);
11634
3
}
11635
11636
static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
11637
0
{
11638
0
    JSValue val;
11639
0
    JSString *p;
11640
0
    int i;
11641
0
    uint32_t c;
11642
0
    StringBuffer b_s, *b = &b_s;
11643
0
    char buf[16];
11644
11645
0
    val = JS_ToStringCheckObject(ctx, val1);
11646
0
    if (JS_IsException(val))
11647
0
        return val;
11648
0
    p = JS_VALUE_GET_STRING(val);
11649
11650
0
    if (string_buffer_init(ctx, b, p->len + 2))
11651
0
        goto fail;
11652
11653
0
    if (string_buffer_putc8(b, '\"'))
11654
0
        goto fail;
11655
0
    for(i = 0; i < p->len; ) {
11656
0
        c = string_getc(p, &i);
11657
0
        switch(c) {
11658
0
        case '\t':
11659
0
            c = 't';
11660
0
            goto quote;
11661
0
        case '\r':
11662
0
            c = 'r';
11663
0
            goto quote;
11664
0
        case '\n':
11665
0
            c = 'n';
11666
0
            goto quote;
11667
0
        case '\b':
11668
0
            c = 'b';
11669
0
            goto quote;
11670
0
        case '\f':
11671
0
            c = 'f';
11672
0
            goto quote;
11673
0
        case '\"':
11674
0
        case '\\':
11675
0
        quote:
11676
0
            if (string_buffer_putc8(b, '\\'))
11677
0
                goto fail;
11678
0
            if (string_buffer_putc8(b, c))
11679
0
                goto fail;
11680
0
            break;
11681
0
        default:
11682
0
            if (c < 32 || (c >= 0xd800 && c < 0xe000)) {
11683
0
                snprintf(buf, sizeof(buf), "\\u%04x", c);
11684
0
                if (string_buffer_puts8(b, buf))
11685
0
                    goto fail;
11686
0
            } else {
11687
0
                if (string_buffer_putc(b, c))
11688
0
                    goto fail;
11689
0
            }
11690
0
            break;
11691
0
        }
11692
0
    }
11693
0
    if (string_buffer_putc8(b, '\"'))
11694
0
        goto fail;
11695
0
    JS_FreeValue(ctx, val);
11696
0
    return string_buffer_end(b);
11697
0
 fail:
11698
0
    JS_FreeValue(ctx, val);
11699
0
    string_buffer_free(b);
11700
0
    return JS_EXCEPTION;
11701
0
}
11702
11703
static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
11704
0
{
11705
0
    printf("%14s %4s %4s %14s %10s %s\n",
11706
0
           "ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS");
11707
0
}
11708
11709
/* for debug only: dump an object without side effect */
11710
static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
11711
0
{
11712
0
    uint32_t i;
11713
0
    char atom_buf[ATOM_GET_STR_BUF_SIZE];
11714
0
    JSShape *sh;
11715
0
    JSShapeProperty *prs;
11716
0
    JSProperty *pr;
11717
0
    BOOL is_first = TRUE;
11718
0
11719
0
    /* XXX: should encode atoms with special characters */
11720
0
    sh = p->shape; /* the shape can be NULL while freeing an object */
11721
0
    printf("%14p %4d ",
11722
0
           (void *)p,
11723
0
           p->header.ref_count);
11724
0
    if (sh) {
11725
0
        printf("%3d%c %14p ",
11726
0
               sh->header.ref_count,
11727
0
               " *"[sh->is_hashed],
11728
0
               (void *)sh->proto);
11729
0
    } else {
11730
0
        printf("%3s  %14s ", "-", "-");
11731
0
    }
11732
0
    printf("%10s ",
11733
0
           JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), rt->class_array[p->class_id].class_name));
11734
0
    if (p->is_exotic && p->fast_array) {
11735
0
        printf("[ ");
11736
0
        for(i = 0; i < p->u.array.count; i++) {
11737
0
            if (i != 0)
11738
0
                printf(", ");
11739
0
            switch (p->class_id) {
11740
0
            case JS_CLASS_ARRAY:
11741
0
            case JS_CLASS_ARGUMENTS:
11742
0
                JS_DumpValueShort(rt, p->u.array.u.values[i]);
11743
0
                break;
11744
0
            case JS_CLASS_UINT8C_ARRAY:
11745
0
            case JS_CLASS_INT8_ARRAY:
11746
0
            case JS_CLASS_UINT8_ARRAY:
11747
0
            case JS_CLASS_INT16_ARRAY:
11748
0
            case JS_CLASS_UINT16_ARRAY:
11749
0
            case JS_CLASS_INT32_ARRAY:
11750
0
            case JS_CLASS_UINT32_ARRAY:
11751
0
#ifdef CONFIG_BIGNUM
11752
0
            case JS_CLASS_BIG_INT64_ARRAY:
11753
0
            case JS_CLASS_BIG_UINT64_ARRAY:
11754
0
#endif
11755
0
            case JS_CLASS_FLOAT32_ARRAY:
11756
0
            case JS_CLASS_FLOAT64_ARRAY:
11757
0
                {
11758
0
                    int size = 1 << typed_array_size_log2(p->class_id);
11759
0
                    const uint8_t *b = p->u.array.u.uint8_ptr + i * size;
11760
0
                    while (size-- > 0)
11761
0
                        printf("%02X", *b++);
11762
0
                }
11763
0
                break;
11764
0
            }
11765
0
        }
11766
0
        printf(" ] ");
11767
0
    }
11768
0
11769
0
    if (sh) {
11770
0
        printf("{ ");
11771
0
        for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
11772
0
            if (prs->atom != JS_ATOM_NULL) {
11773
0
                pr = &p->prop[i];
11774
0
                if (!is_first)
11775
0
                    printf(", ");
11776
0
                printf("%s: ",
11777
0
                       JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), prs->atom));
11778
0
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
11779
0
                    printf("[getset %p %p]", (void *)pr->u.getset.getter,
11780
0
                           (void *)pr->u.getset.setter);
11781
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
11782
0
                    printf("[varref %p]", (void *)pr->u.var_ref);
11783
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
11784
0
                    printf("[autoinit %p %d %p]",
11785
0
                           (void *)js_autoinit_get_realm(pr),
11786
0
                           js_autoinit_get_id(pr),
11787
0
                           (void *)pr->u.init.opaque);
11788
0
                } else {
11789
0
                    JS_DumpValueShort(rt, pr->u.value);
11790
0
                }
11791
0
                is_first = FALSE;
11792
0
            }
11793
0
        }
11794
0
        printf(" }");
11795
0
    }
11796
0
    
11797
0
    if (js_class_has_bytecode(p->class_id)) {
11798
0
        JSFunctionBytecode *b = p->u.func.function_bytecode;
11799
0
        JSVarRef **var_refs;
11800
0
        if (b->closure_var_count) {
11801
0
            var_refs = p->u.func.var_refs;
11802
0
            printf(" Closure:");
11803
0
            for(i = 0; i < b->closure_var_count; i++) {
11804
0
                printf(" ");
11805
0
                JS_DumpValueShort(rt, var_refs[i]->value);
11806
0
            }
11807
0
            if (p->u.func.home_object) {
11808
0
                printf(" HomeObject: ");
11809
0
                JS_DumpValueShort(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));
11810
0
            }
11811
0
        }
11812
0
    }
11813
0
    printf("\n");
11814
0
}
11815
11816
static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
11817
0
{
11818
0
    if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
11819
0
        JS_DumpObject(rt, (JSObject *)p);
11820
0
    } else {
11821
0
        printf("%14p %4d ",
11822
0
               (void *)p,
11823
0
               p->ref_count);
11824
0
        switch(p->gc_obj_type) {
11825
0
        case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
11826
0
            printf("[function bytecode]");
11827
0
            break;
11828
0
        case JS_GC_OBJ_TYPE_SHAPE:
11829
0
            printf("[shape]");
11830
0
            break;
11831
0
        case JS_GC_OBJ_TYPE_VAR_REF:
11832
0
            printf("[var_ref]");
11833
0
            break;
11834
0
        case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
11835
0
            printf("[async_function]");
11836
0
            break;
11837
0
        case JS_GC_OBJ_TYPE_JS_CONTEXT:
11838
0
            printf("[js_context]");
11839
0
            break;
11840
0
        default:
11841
0
            printf("[unknown %d]", p->gc_obj_type);
11842
0
            break;
11843
0
        }
11844
0
        printf("\n");
11845
0
    }
11846
0
}
11847
11848
static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
11849
                                                      JSValueConst val)
11850
0
{
11851
0
    uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
11852
0
    const char *str;
11853
0
11854
0
    switch(tag) {
11855
0
    case JS_TAG_INT:
11856
0
        printf("%d", JS_VALUE_GET_INT(val));
11857
0
        break;
11858
0
    case JS_TAG_BOOL:
11859
0
        if (JS_VALUE_GET_BOOL(val))
11860
0
            str = "true";
11861
0
        else
11862
0
            str = "false";
11863
0
        goto print_str;
11864
0
    case JS_TAG_NULL:
11865
0
        str = "null";
11866
0
        goto print_str;
11867
0
    case JS_TAG_EXCEPTION:
11868
0
        str = "exception";
11869
0
        goto print_str;
11870
0
    case JS_TAG_UNINITIALIZED:
11871
0
        str = "uninitialized";
11872
0
        goto print_str;
11873
0
    case JS_TAG_UNDEFINED:
11874
0
        str = "undefined";
11875
0
    print_str:
11876
0
        printf("%s", str);
11877
0
        break;
11878
0
    case JS_TAG_FLOAT64:
11879
0
        printf("%.14g", JS_VALUE_GET_FLOAT64(val));
11880
0
        break;
11881
0
#ifdef CONFIG_BIGNUM
11882
0
    case JS_TAG_BIG_INT:
11883
0
        {
11884
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11885
0
            char *str;
11886
0
            str = bf_ftoa(NULL, &p->num, 10, 0,
11887
0
                          BF_RNDZ | BF_FTOA_FORMAT_FRAC);
11888
0
            printf("%sn", str);
11889
0
            bf_realloc(&rt->bf_ctx, str, 0);
11890
0
        }
11891
0
        break;
11892
0
    case JS_TAG_BIG_FLOAT:
11893
0
        {
11894
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
11895
0
            char *str;
11896
0
            str = bf_ftoa(NULL, &p->num, 16, BF_PREC_INF,
11897
0
                          BF_RNDZ | BF_FTOA_FORMAT_FREE | BF_FTOA_ADD_PREFIX);
11898
0
            printf("%sl", str);
11899
0
            bf_free(&rt->bf_ctx, str);
11900
0
        }
11901
0
        break;
11902
0
    case JS_TAG_BIG_DECIMAL:
11903
0
        {
11904
0
            JSBigDecimal *p = JS_VALUE_GET_PTR(val);
11905
0
            char *str;
11906
0
            str = bfdec_ftoa(NULL, &p->num, BF_PREC_INF,
11907
0
                             BF_RNDZ | BF_FTOA_FORMAT_FREE);
11908
0
            printf("%sm", str);
11909
0
            bf_free(&rt->bf_ctx, str);
11910
0
        }
11911
0
        break;
11912
0
#endif
11913
0
    case JS_TAG_STRING:
11914
0
        {
11915
0
            JSString *p;
11916
0
            p = JS_VALUE_GET_STRING(val);
11917
0
            JS_DumpString(rt, p);
11918
0
        }
11919
0
        break;
11920
0
    case JS_TAG_FUNCTION_BYTECODE:
11921
0
        {
11922
0
            JSFunctionBytecode *b = JS_VALUE_GET_PTR(val);
11923
0
            char buf[ATOM_GET_STR_BUF_SIZE];
11924
0
            printf("[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
11925
0
        }
11926
0
        break;
11927
0
    case JS_TAG_OBJECT:
11928
0
        {
11929
0
            JSObject *p = JS_VALUE_GET_OBJ(val);
11930
0
            JSAtom atom = rt->class_array[p->class_id].class_name;
11931
0
            char atom_buf[ATOM_GET_STR_BUF_SIZE];
11932
0
            printf("[%s %p]",
11933
0
                   JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), atom), (void *)p);
11934
0
        }
11935
0
        break;
11936
0
    case JS_TAG_SYMBOL:
11937
0
        {
11938
0
            JSAtomStruct *p = JS_VALUE_GET_PTR(val);
11939
0
            char atom_buf[ATOM_GET_STR_BUF_SIZE];
11940
0
            printf("Symbol(%s)",
11941
0
                   JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), js_get_atom_index(rt, p)));
11942
0
        }
11943
0
        break;
11944
0
    case JS_TAG_MODULE:
11945
0
        printf("[module]");
11946
0
        break;
11947
0
    default:
11948
0
        printf("[unknown tag %d]", tag);
11949
0
        break;
11950
0
    }
11951
0
}
11952
11953
static __maybe_unused void JS_DumpValue(JSContext *ctx,
11954
                                                 JSValueConst val)
11955
0
{
11956
0
    JS_DumpValueShort(ctx->rt, val);
11957
0
}
11958
11959
static __maybe_unused void JS_PrintValue(JSContext *ctx,
11960
                                                  const char *str,
11961
                                                  JSValueConst val)
11962
0
{
11963
0
    printf("%s=", str);
11964
0
    JS_DumpValueShort(ctx->rt, val);
11965
0
    printf("\n");
11966
0
}
11967
11968
/* return -1 if exception (proxy case) or TRUE/FALSE */
11969
int JS_IsArray(JSContext *ctx, JSValueConst val)
11970
143k
{
11971
143k
    JSObject *p;
11972
143k
    if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
11973
143k
        p = JS_VALUE_GET_OBJ(val);
11974
143k
        if (unlikely(p->class_id == JS_CLASS_PROXY))
11975
0
            return js_proxy_isArray(ctx, val);
11976
143k
        else
11977
143k
            return p->class_id == JS_CLASS_ARRAY;
11978
143k
    } else {
11979
0
        return FALSE;
11980
0
    }
11981
143k
}
11982
11983
static double js_pow(double a, double b)
11984
0
{
11985
0
    if (unlikely(!isfinite(b)) && fabs(a) == 1) {
11986
        /* not compatible with IEEE 754 */
11987
0
        return JS_FLOAT64_NAN;
11988
0
    } else {
11989
0
        return pow(a, b);
11990
0
    }
11991
0
}
11992
11993
#ifdef CONFIG_BIGNUM
11994
11995
JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v)
11996
0
{
11997
0
    JSValue val;
11998
0
    bf_t *a;
11999
0
    val = JS_NewBigInt(ctx);
12000
0
    if (JS_IsException(val))
12001
0
        return val;
12002
0
    a = JS_GetBigInt(val);
12003
0
    if (bf_set_si(a, v)) {
12004
0
        JS_FreeValue(ctx, val);
12005
0
        return JS_ThrowOutOfMemory(ctx);
12006
0
    }
12007
0
    return val;
12008
0
}
12009
12010
JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
12011
0
{
12012
0
    if (is_math_mode(ctx) &&
12013
0
        v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
12014
0
        return JS_NewInt64(ctx, v);
12015
0
    } else {
12016
0
        return JS_NewBigInt64_1(ctx, v);
12017
0
    }
12018
0
}
12019
12020
JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
12021
0
{
12022
0
    JSValue val;
12023
0
    if (is_math_mode(ctx) && v <= MAX_SAFE_INTEGER) {
12024
0
        val = JS_NewInt64(ctx, v);
12025
0
    } else {
12026
0
        bf_t *a;
12027
0
        val = JS_NewBigInt(ctx);
12028
0
        if (JS_IsException(val))
12029
0
            return val;
12030
0
        a = JS_GetBigInt(val);
12031
0
        if (bf_set_ui(a, v)) {
12032
0
            JS_FreeValue(ctx, val);
12033
0
            return JS_ThrowOutOfMemory(ctx);
12034
0
        }
12035
0
    }
12036
0
    return val;
12037
0
}
12038
12039
/* if the returned bigfloat is allocated it is equal to
12040
   'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return
12041
   NULL in case of error. */
12042
static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val)
12043
0
{
12044
0
    uint32_t tag;
12045
0
    bf_t *r;
12046
0
    JSBigFloat *p;
12047
12048
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12049
0
    switch(tag) {
12050
0
    case JS_TAG_INT:
12051
0
    case JS_TAG_BOOL:
12052
0
    case JS_TAG_NULL:
12053
0
        r = buf;
12054
0
        bf_init(ctx->bf_ctx, r);
12055
0
        if (bf_set_si(r, JS_VALUE_GET_INT(val)))
12056
0
            goto fail;
12057
0
        break;
12058
0
    case JS_TAG_FLOAT64:
12059
0
        r = buf;
12060
0
        bf_init(ctx->bf_ctx, r);
12061
0
        if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) {
12062
0
        fail:
12063
0
            bf_delete(r);
12064
0
            return NULL;
12065
0
        }
12066
0
        break;
12067
0
    case JS_TAG_BIG_INT:
12068
0
    case JS_TAG_BIG_FLOAT:
12069
0
        p = JS_VALUE_GET_PTR(val);
12070
0
        r = &p->num;
12071
0
        break;
12072
0
    case JS_TAG_UNDEFINED:
12073
0
    default:
12074
0
        r = buf;
12075
0
        bf_init(ctx->bf_ctx, r);
12076
0
        bf_set_nan(r);
12077
0
        break;
12078
0
    }
12079
0
    return r;
12080
0
}
12081
12082
/* return NULL if invalid type */
12083
static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val)
12084
0
{
12085
0
    uint32_t tag;
12086
0
    JSBigDecimal *p;
12087
0
    bfdec_t *r;
12088
    
12089
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12090
0
    switch(tag) {
12091
0
    case JS_TAG_BIG_DECIMAL:
12092
0
        p = JS_VALUE_GET_PTR(val);
12093
0
        r = &p->num;
12094
0
        break;
12095
0
    default:
12096
0
        JS_ThrowTypeError(ctx, "bigdecimal expected");
12097
0
        r = NULL;
12098
0
        break;
12099
0
    }
12100
0
    return r;
12101
0
}
12102
12103
/* return NaN if bad bigint literal */
12104
static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
12105
0
{
12106
0
    const char *str, *p;
12107
0
    size_t len;
12108
0
    int flags;
12109
    
12110
0
    str = JS_ToCStringLen(ctx, &len, val);
12111
0
    JS_FreeValue(ctx, val);
12112
0
    if (!str)
12113
0
        return JS_EXCEPTION;
12114
0
    p = str;
12115
0
    p += skip_spaces(p);
12116
0
    if ((p - str) == len) {
12117
0
        val = JS_NewBigInt64(ctx, 0);
12118
0
    } else {
12119
0
        flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
12120
0
        if (is_math_mode(ctx))
12121
0
            flags |= ATOD_MODE_BIGINT;
12122
0
        val = js_atof(ctx, p, &p, 0, flags);
12123
0
        p += skip_spaces(p);
12124
0
        if (!JS_IsException(val)) {
12125
0
            if ((p - str) != len) {
12126
0
                JS_FreeValue(ctx, val);
12127
0
                val = JS_NAN;
12128
0
            }
12129
0
        }
12130
0
    }
12131
0
    JS_FreeCString(ctx, str);
12132
0
    return val;
12133
0
}
12134
12135
static JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val)
12136
0
{
12137
0
    val = JS_StringToBigInt(ctx, val);
12138
0
    if (JS_VALUE_IS_NAN(val))
12139
0
        return JS_ThrowSyntaxError(ctx, "invalid bigint literal");
12140
0
    return val;
12141
0
}
12142
12143
/* if the returned bigfloat is allocated it is equal to
12144
   'buf'. Otherwise it is a pointer to the bigfloat in 'val'. */
12145
static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
12146
36
{
12147
36
    uint32_t tag;
12148
36
    bf_t *r;
12149
36
    JSBigFloat *p;
12150
12151
36
 redo:
12152
36
    tag = JS_VALUE_GET_NORM_TAG(val);
12153
36
    switch(tag) {
12154
0
    case JS_TAG_INT:
12155
0
    case JS_TAG_NULL:
12156
0
    case JS_TAG_UNDEFINED:
12157
0
        if (!is_math_mode(ctx))
12158
0
            goto fail;
12159
        /* fall tru */
12160
0
    case JS_TAG_BOOL:
12161
0
        r = buf;
12162
0
        bf_init(ctx->bf_ctx, r);
12163
0
        bf_set_si(r, JS_VALUE_GET_INT(val));
12164
0
        break;
12165
0
    case JS_TAG_FLOAT64:
12166
0
        {
12167
0
            double d = JS_VALUE_GET_FLOAT64(val);
12168
0
            if (!is_math_mode(ctx))
12169
0
                goto fail;
12170
0
            if (!isfinite(d))
12171
0
                goto fail;
12172
0
            r = buf;
12173
0
            bf_init(ctx->bf_ctx, r);
12174
0
            d = trunc(d);
12175
0
            bf_set_float64(r, d);
12176
0
        }
12177
0
        break;
12178
36
    case JS_TAG_BIG_INT:
12179
36
        p = JS_VALUE_GET_PTR(val);
12180
36
        r = &p->num;
12181
36
        break;
12182
0
    case JS_TAG_BIG_FLOAT:
12183
0
        if (!is_math_mode(ctx))
12184
0
            goto fail;
12185
0
        p = JS_VALUE_GET_PTR(val);
12186
0
        if (!bf_is_finite(&p->num))
12187
0
            goto fail;
12188
0
        r = buf;
12189
0
        bf_init(ctx->bf_ctx, r);
12190
0
        bf_set(r, &p->num);
12191
0
        bf_rint(r, BF_RNDZ);
12192
0
        JS_FreeValue(ctx, val);
12193
0
        break;
12194
0
    case JS_TAG_STRING:
12195
0
        val = JS_StringToBigIntErr(ctx, val);
12196
0
        if (JS_IsException(val))
12197
0
            return NULL;
12198
0
        goto redo;
12199
0
    case JS_TAG_OBJECT:
12200
0
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
12201
0
        if (JS_IsException(val))
12202
0
            return NULL;
12203
0
        goto redo;
12204
0
    default:
12205
0
    fail:
12206
0
        JS_FreeValue(ctx, val);
12207
0
        JS_ThrowTypeError(ctx, "cannot convert to bigint");
12208
0
        return NULL;
12209
36
    }
12210
36
    return r;
12211
36
}
12212
12213
static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val)
12214
36
{
12215
36
    return JS_ToBigIntFree(ctx, buf, JS_DupValue(ctx, val));
12216
36
}
12217
12218
static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val)
12219
0
{
12220
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {
12221
0
        return val;
12222
0
    } else {
12223
0
        bf_t a_s, *a, *r;
12224
0
        int ret;
12225
0
        JSValue res; 
12226
12227
0
        res = JS_NewBigInt(ctx);
12228
0
        if (JS_IsException(res))
12229
0
            return JS_EXCEPTION;
12230
0
        a = JS_ToBigIntFree(ctx, &a_s, val);
12231
0
        if (!a) {
12232
0
            JS_FreeValue(ctx, res);
12233
0
            return JS_EXCEPTION;
12234
0
        }
12235
0
        r = JS_GetBigInt(res);
12236
0
        ret = bf_set(r, a);
12237
0
        JS_FreeBigInt(ctx, a, &a_s);
12238
0
        if (ret) {
12239
0
            JS_FreeValue(ctx, res);
12240
0
            return JS_ThrowOutOfMemory(ctx);
12241
0
        }
12242
0
        return JS_CompactBigInt(ctx, res);
12243
0
    }
12244
0
}
12245
12246
/* free the bf_t allocated by JS_ToBigInt */
12247
static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf)
12248
36
{
12249
36
    if (a == buf) {
12250
0
        bf_delete(a);
12251
36
    } else {
12252
36
        JSBigFloat *p = (JSBigFloat *)((uint8_t *)a -
12253
36
                                       offsetof(JSBigFloat, num));
12254
36
        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_FLOAT, p));
12255
36
    }
12256
36
}
12257
12258
/* XXX: merge with JS_ToInt64Free with a specific flag */
12259
static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
12260
0
{
12261
0
    bf_t a_s, *a;
12262
12263
0
    a = JS_ToBigIntFree(ctx, &a_s, val);
12264
0
    if (!a) {
12265
0
        *pres = 0;
12266
0
        return -1;
12267
0
    }
12268
0
    bf_get_int64(pres, a, BF_GET_INT_MOD);
12269
0
    JS_FreeBigInt(ctx, a, &a_s);
12270
0
    return 0;
12271
0
}
12272
12273
int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
12274
0
{
12275
0
    return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val));
12276
0
}
12277
12278
static JSBigFloat *js_new_bf(JSContext *ctx)
12279
22
{
12280
22
    JSBigFloat *p;
12281
22
    p = js_malloc(ctx, sizeof(*p));
12282
22
    if (!p)
12283
0
        return NULL;
12284
22
    p->header.ref_count = 1;
12285
22
    bf_init(ctx->bf_ctx, &p->num);
12286
22
    return p;
12287
22
}
12288
12289
static JSValue JS_NewBigFloat(JSContext *ctx)
12290
0
{
12291
0
    JSBigFloat *p;
12292
0
    p = js_malloc(ctx, sizeof(*p));
12293
0
    if (!p)
12294
0
        return JS_EXCEPTION;
12295
0
    p->header.ref_count = 1;
12296
0
    bf_init(ctx->bf_ctx, &p->num);
12297
0
    return JS_MKPTR(JS_TAG_BIG_FLOAT, p);
12298
0
}
12299
12300
static JSValue JS_NewBigDecimal(JSContext *ctx)
12301
0
{
12302
0
    JSBigDecimal *p;
12303
0
    p = js_malloc(ctx, sizeof(*p));
12304
0
    if (!p)
12305
0
        return JS_EXCEPTION;
12306
0
    p->header.ref_count = 1;
12307
0
    bfdec_init(ctx->bf_ctx, &p->num);
12308
0
    return JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
12309
0
}
12310
12311
static JSValue JS_NewBigInt(JSContext *ctx)
12312
1.00k
{
12313
1.00k
    JSBigFloat *p;
12314
1.00k
    p = js_malloc(ctx, sizeof(*p));
12315
1.00k
    if (!p)
12316
0
        return JS_EXCEPTION;
12317
1.00k
    p->header.ref_count = 1;
12318
1.00k
    bf_init(ctx->bf_ctx, &p->num);
12319
1.00k
    return JS_MKPTR(JS_TAG_BIG_INT, p);
12320
1.00k
}
12321
12322
static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
12323
                                 BOOL convert_to_safe_integer)
12324
997
{
12325
997
    int64_t v;
12326
997
    bf_t *a;
12327
    
12328
997
    if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT)
12329
0
        return val; /* fail safe */
12330
997
    a = JS_GetBigInt(val);
12331
997
    if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 &&
12332
997
        v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
12333
0
        JS_FreeValue(ctx, val);
12334
0
        return JS_NewInt64(ctx, v);
12335
997
    } else if (a->expn == BF_EXP_ZERO && a->sign) {
12336
0
        JSBigFloat *p = JS_VALUE_GET_PTR(val);
12337
0
        assert(p->header.ref_count == 1);
12338
0
        a->sign = 0;
12339
0
    }
12340
997
    return val;
12341
997
}
12342
12343
/* Convert the big int to a safe integer if in math mode. normalize
12344
   the zero representation. Could also be used to convert the bigint
12345
   to a short bigint value. The reference count of the value must be
12346
   1. Cannot fail */
12347
static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
12348
1
{
12349
1
    return JS_CompactBigInt1(ctx, val, is_math_mode(ctx));
12350
1
}
12351
12352
/* must be kept in sync with JSOverloadableOperatorEnum */
12353
/* XXX: use atoms ? */
12354
static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = {
12355
    "+",
12356
    "-",
12357
    "*",
12358
    "/",
12359
    "%",
12360
    "**",
12361
    "|",
12362
    "&",
12363
    "^",
12364
    "<<",
12365
    ">>",
12366
    ">>>",
12367
    "==",
12368
    "<",
12369
    "pos",
12370
    "neg",
12371
    "++",
12372
    "--",
12373
    "~",
12374
};
12375
12376
static int get_ovop_from_opcode(OPCodeEnum op)
12377
0
{
12378
0
    switch(op) {
12379
0
    case OP_add:
12380
0
        return JS_OVOP_ADD;
12381
0
    case OP_sub:
12382
0
        return JS_OVOP_SUB;
12383
0
    case OP_mul:
12384
0
        return JS_OVOP_MUL;
12385
0
    case OP_div:
12386
0
        return JS_OVOP_DIV;
12387
0
    case OP_mod:
12388
0
    case OP_math_mod:
12389
0
        return JS_OVOP_MOD;
12390
0
    case OP_pow:
12391
0
        return JS_OVOP_POW;
12392
0
    case OP_or:
12393
0
        return JS_OVOP_OR;
12394
0
    case OP_and:
12395
0
        return JS_OVOP_AND;
12396
0
    case OP_xor:
12397
0
        return JS_OVOP_XOR;
12398
0
    case OP_shl:
12399
0
        return JS_OVOP_SHL;
12400
0
    case OP_sar:
12401
0
        return JS_OVOP_SAR;
12402
0
    case OP_shr:
12403
0
        return JS_OVOP_SHR;
12404
0
    case OP_eq:
12405
0
    case OP_neq:
12406
0
        return JS_OVOP_EQ;
12407
0
    case OP_lt:
12408
0
    case OP_lte:
12409
0
    case OP_gt:
12410
0
    case OP_gte:
12411
0
        return JS_OVOP_LESS;
12412
0
    case OP_plus:
12413
0
        return JS_OVOP_POS;
12414
0
    case OP_neg:
12415
0
        return JS_OVOP_NEG;
12416
0
    case OP_inc:
12417
0
        return JS_OVOP_INC;
12418
0
    case OP_dec:
12419
0
        return JS_OVOP_DEC;
12420
0
    default:
12421
0
        abort();
12422
0
    }
12423
0
}
12424
12425
/* return NULL if not present */
12426
static JSObject *find_binary_op(JSBinaryOperatorDef *def,
12427
                                uint32_t operator_index,
12428
                                JSOverloadableOperatorEnum op)
12429
0
{
12430
0
    JSBinaryOperatorDefEntry *ent;
12431
0
    int i;
12432
0
    for(i = 0; i < def->count; i++) {
12433
0
        ent = &def->tab[i];
12434
0
        if (ent->operator_index == operator_index)
12435
0
            return ent->ops[op];
12436
0
    }
12437
0
    return NULL;
12438
0
}
12439
12440
/* return -1 if exception, 0 if no operator overloading, 1 if
12441
   overloaded operator called */
12442
static __exception int js_call_binary_op_fallback(JSContext *ctx,
12443
                                                  JSValue *pret,
12444
                                                  JSValueConst op1,
12445
                                                  JSValueConst op2,
12446
                                                  OPCodeEnum op,
12447
                                                  BOOL is_numeric,
12448
                                                  int hint)
12449
184k
{
12450
184k
    JSValue opset1_obj, opset2_obj, method, ret, new_op1, new_op2;
12451
184k
    JSOperatorSetData *opset1, *opset2;
12452
184k
    JSOverloadableOperatorEnum ovop;
12453
184k
    JSObject *p;
12454
184k
    JSValueConst args[2];
12455
    
12456
184k
    if (!ctx->allow_operator_overloading)
12457
184k
        return 0;
12458
    
12459
0
    opset2_obj = JS_UNDEFINED;
12460
0
    opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
12461
0
    if (JS_IsException(opset1_obj))
12462
0
        goto exception;
12463
0
    if (JS_IsUndefined(opset1_obj))
12464
0
        return 0;
12465
0
    opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
12466
0
    if (!opset1)
12467
0
        goto exception;
12468
12469
0
    opset2_obj = JS_GetProperty(ctx, op2, JS_ATOM_Symbol_operatorSet);
12470
0
    if (JS_IsException(opset2_obj))
12471
0
        goto exception;
12472
0
    if (JS_IsUndefined(opset2_obj)) {
12473
0
        JS_FreeValue(ctx, opset1_obj);
12474
0
        return 0;
12475
0
    }
12476
0
    opset2 = JS_GetOpaque2(ctx, opset2_obj, JS_CLASS_OPERATOR_SET);
12477
0
    if (!opset2)
12478
0
        goto exception;
12479
12480
0
    if (opset1->is_primitive && opset2->is_primitive) {
12481
0
        JS_FreeValue(ctx, opset1_obj);
12482
0
        JS_FreeValue(ctx, opset2_obj);
12483
0
        return 0;
12484
0
    }
12485
12486
0
    ovop = get_ovop_from_opcode(op);
12487
    
12488
0
    if (opset1->operator_counter == opset2->operator_counter) {
12489
0
        p = opset1->self_ops[ovop];
12490
0
    } else if (opset1->operator_counter > opset2->operator_counter) {
12491
0
        p = find_binary_op(&opset1->left, opset2->operator_counter, ovop);
12492
0
    } else {
12493
0
        p = find_binary_op(&opset2->right, opset1->operator_counter, ovop);
12494
0
    }
12495
0
    if (!p) {
12496
0
        JS_ThrowTypeError(ctx, "operator %s: no function defined",
12497
0
                          js_overloadable_operator_names[ovop]);
12498
0
        goto exception;
12499
0
    }
12500
12501
0
    if (opset1->is_primitive) {
12502
0
        if (is_numeric) {
12503
0
            new_op1 = JS_ToNumeric(ctx, op1);
12504
0
        } else {
12505
0
            new_op1 = JS_ToPrimitive(ctx, op1, hint);
12506
0
        }
12507
0
        if (JS_IsException(new_op1))
12508
0
            goto exception;
12509
0
    } else {
12510
0
        new_op1 = JS_DupValue(ctx, op1);
12511
0
    }
12512
    
12513
0
    if (opset2->is_primitive) {
12514
0
        if (is_numeric) {
12515
0
            new_op2 = JS_ToNumeric(ctx, op2);
12516
0
        } else {
12517
0
            new_op2 = JS_ToPrimitive(ctx, op2, hint);
12518
0
        }
12519
0
        if (JS_IsException(new_op2)) {
12520
0
            JS_FreeValue(ctx, new_op1);
12521
0
            goto exception;
12522
0
        }
12523
0
    } else {
12524
0
        new_op2 = JS_DupValue(ctx, op2);
12525
0
    }
12526
12527
    /* XXX: could apply JS_ToPrimitive() if primitive type so that the
12528
       operator function does not get a value object */
12529
    
12530
0
    method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12531
0
    if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) {
12532
0
        args[0] = new_op2;
12533
0
        args[1] = new_op1;
12534
0
    } else {
12535
0
        args[0] = new_op1;
12536
0
        args[1] = new_op2;
12537
0
    }
12538
0
    ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
12539
0
    JS_FreeValue(ctx, new_op1);
12540
0
    JS_FreeValue(ctx, new_op2);
12541
0
    if (JS_IsException(ret))
12542
0
        goto exception;
12543
0
    if (ovop == JS_OVOP_EQ) {
12544
0
        BOOL res = JS_ToBoolFree(ctx, ret);
12545
0
        if (op == OP_neq)
12546
0
            res ^= 1;
12547
0
        ret = JS_NewBool(ctx, res);
12548
0
    } else if (ovop == JS_OVOP_LESS) {
12549
0
        if (JS_IsUndefined(ret)) {
12550
0
            ret = JS_FALSE;
12551
0
        } else {
12552
0
            BOOL res = JS_ToBoolFree(ctx, ret);
12553
0
            if (op == OP_lte || op == OP_gte)
12554
0
                res ^= 1;
12555
0
            ret = JS_NewBool(ctx, res);
12556
0
        }
12557
0
    }
12558
0
    JS_FreeValue(ctx, opset1_obj);
12559
0
    JS_FreeValue(ctx, opset2_obj);
12560
0
    *pret = ret;
12561
0
    return 1;
12562
0
 exception:
12563
0
    JS_FreeValue(ctx, opset1_obj);
12564
0
    JS_FreeValue(ctx, opset2_obj);
12565
0
    *pret = JS_UNDEFINED;
12566
0
    return -1;
12567
0
}
12568
12569
/* try to call the operation on the operatorSet field of 'obj'. Only
12570
   used for "/" and "**" on the BigInt prototype in math mode */
12571
static __exception int js_call_binary_op_simple(JSContext *ctx,
12572
                                                JSValue *pret,
12573
                                                JSValueConst obj,
12574
                                                JSValueConst op1,
12575
                                                JSValueConst op2,
12576
                                                OPCodeEnum op)
12577
0
{
12578
0
    JSValue opset1_obj, method, ret, new_op1, new_op2;
12579
0
    JSOperatorSetData *opset1;
12580
0
    JSOverloadableOperatorEnum ovop;
12581
0
    JSObject *p;
12582
0
    JSValueConst args[2];
12583
12584
0
    opset1_obj = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
12585
0
    if (JS_IsException(opset1_obj))
12586
0
        goto exception;
12587
0
    if (JS_IsUndefined(opset1_obj))
12588
0
        return 0;
12589
0
    opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
12590
0
    if (!opset1)
12591
0
        goto exception;
12592
0
    ovop = get_ovop_from_opcode(op);
12593
12594
0
    p = opset1->self_ops[ovop];
12595
0
    if (!p) {
12596
0
        JS_FreeValue(ctx, opset1_obj);
12597
0
        return 0;
12598
0
    }
12599
12600
0
    new_op1 = JS_ToNumeric(ctx, op1);
12601
0
    if (JS_IsException(new_op1))
12602
0
        goto exception;
12603
0
    new_op2 = JS_ToNumeric(ctx, op2);
12604
0
    if (JS_IsException(new_op2)) {
12605
0
        JS_FreeValue(ctx, new_op1);
12606
0
        goto exception;
12607
0
    }
12608
12609
0
    method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12610
0
    args[0] = new_op1;
12611
0
    args[1] = new_op2;
12612
0
    ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
12613
0
    JS_FreeValue(ctx, new_op1);
12614
0
    JS_FreeValue(ctx, new_op2);
12615
0
    if (JS_IsException(ret))
12616
0
        goto exception;
12617
0
    JS_FreeValue(ctx, opset1_obj);
12618
0
    *pret = ret;
12619
0
    return 1;
12620
0
 exception:
12621
0
    JS_FreeValue(ctx, opset1_obj);
12622
0
    *pret = JS_UNDEFINED;
12623
0
    return -1;
12624
0
}
12625
12626
/* return -1 if exception, 0 if no operator overloading, 1 if
12627
   overloaded operator called */
12628
static __exception int js_call_unary_op_fallback(JSContext *ctx,
12629
                                                 JSValue *pret,
12630
                                                 JSValueConst op1,
12631
                                                 OPCodeEnum op)
12632
40.9k
{
12633
40.9k
    JSValue opset1_obj, method, ret;
12634
40.9k
    JSOperatorSetData *opset1;
12635
40.9k
    JSOverloadableOperatorEnum ovop;
12636
40.9k
    JSObject *p;
12637
12638
40.9k
    if (!ctx->allow_operator_overloading)
12639
40.9k
        return 0;
12640
    
12641
0
    opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
12642
0
    if (JS_IsException(opset1_obj))
12643
0
        goto exception;
12644
0
    if (JS_IsUndefined(opset1_obj))
12645
0
        return 0;
12646
0
    opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
12647
0
    if (!opset1)
12648
0
        goto exception;
12649
0
    if (opset1->is_primitive) {
12650
0
        JS_FreeValue(ctx, opset1_obj);
12651
0
        return 0;
12652
0
    }
12653
12654
0
    ovop = get_ovop_from_opcode(op);
12655
12656
0
    p = opset1->self_ops[ovop];
12657
0
    if (!p) {
12658
0
        JS_ThrowTypeError(ctx, "no overloaded operator %s",
12659
0
                          js_overloadable_operator_names[ovop]);
12660
0
        goto exception;
12661
0
    }
12662
0
    method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12663
0
    ret = JS_CallFree(ctx, method, JS_UNDEFINED, 1, &op1);
12664
0
    if (JS_IsException(ret))
12665
0
        goto exception;
12666
0
    JS_FreeValue(ctx, opset1_obj);
12667
0
    *pret = ret;
12668
0
    return 1;
12669
0
 exception:
12670
0
    JS_FreeValue(ctx, opset1_obj);
12671
0
    *pret = JS_UNDEFINED;
12672
0
    return -1;
12673
0
}
12674
12675
static JSValue throw_bf_exception(JSContext *ctx, int status)
12676
0
{
12677
0
    const char *str;
12678
0
    if (status & BF_ST_MEM_ERROR)
12679
0
        return JS_ThrowOutOfMemory(ctx);
12680
0
    if (status & BF_ST_DIVIDE_ZERO) {
12681
0
        str = "division by zero";
12682
0
    } else if (status & BF_ST_INVALID_OP) {
12683
0
        str = "invalid operation";
12684
0
    } else {
12685
0
        str = "integer overflow";
12686
0
    }
12687
0
    return JS_ThrowRangeError(ctx, "%s", str);
12688
0
}
12689
12690
static int js_unary_arith_bigint(JSContext *ctx,
12691
                                 JSValue *pres, OPCodeEnum op, JSValue op1)
12692
0
{
12693
0
    bf_t a_s, *r, *a;
12694
0
    int ret, v;
12695
0
    JSValue res;
12696
    
12697
0
    if (op == OP_plus && !is_math_mode(ctx)) {
12698
0
        JS_ThrowTypeError(ctx, "bigint argument with unary +");
12699
0
        JS_FreeValue(ctx, op1);
12700
0
        return -1;
12701
0
    }
12702
0
    res = JS_NewBigInt(ctx);
12703
0
    if (JS_IsException(res)) {
12704
0
        JS_FreeValue(ctx, op1);
12705
0
        return -1;
12706
0
    }
12707
0
    r = JS_GetBigInt(res);
12708
0
    a = JS_ToBigInt(ctx, &a_s, op1);
12709
0
    ret = 0;
12710
0
    switch(op) {
12711
0
    case OP_inc:
12712
0
    case OP_dec:
12713
0
        v = 2 * (op - OP_dec) - 1;
12714
0
        ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
12715
0
        break;
12716
0
    case OP_plus:
12717
0
        ret = bf_set(r, a);
12718
0
        break;
12719
0
    case OP_neg:
12720
0
        ret = bf_set(r, a);
12721
0
        bf_neg(r);
12722
0
        break;
12723
0
    case OP_not:
12724
0
        ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ);
12725
0
        bf_neg(r);
12726
0
        break;
12727
0
    default:
12728
0
        abort();
12729
0
    }
12730
0
    JS_FreeBigInt(ctx, a, &a_s);
12731
0
    JS_FreeValue(ctx, op1);
12732
0
    if (unlikely(ret)) {
12733
0
        JS_FreeValue(ctx, res);
12734
0
        throw_bf_exception(ctx, ret);
12735
0
        return -1;
12736
0
    }
12737
0
    res = JS_CompactBigInt(ctx, res);
12738
0
    *pres = res;
12739
0
    return 0;
12740
0
}
12741
12742
static int js_unary_arith_bigfloat(JSContext *ctx,
12743
                                   JSValue *pres, OPCodeEnum op, JSValue op1)
12744
0
{
12745
0
    bf_t a_s, *r, *a;
12746
0
    int ret, v;
12747
0
    JSValue res;
12748
    
12749
0
    if (op == OP_plus && !is_math_mode(ctx)) {
12750
0
        JS_ThrowTypeError(ctx, "bigfloat argument with unary +");
12751
0
        JS_FreeValue(ctx, op1);
12752
0
        return -1;
12753
0
    }
12754
12755
0
    res = JS_NewBigFloat(ctx);
12756
0
    if (JS_IsException(res)) {
12757
0
        JS_FreeValue(ctx, op1);
12758
0
        return -1;
12759
0
    }
12760
0
    r = JS_GetBigFloat(res);
12761
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
12762
0
    ret = 0;
12763
0
    switch(op) {
12764
0
    case OP_inc:
12765
0
    case OP_dec:
12766
0
        v = 2 * (op - OP_dec) - 1;
12767
0
        ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags);
12768
0
        break;
12769
0
    case OP_plus:
12770
0
        ret = bf_set(r, a);
12771
0
        break;
12772
0
    case OP_neg:
12773
0
        ret = bf_set(r, a);
12774
0
        bf_neg(r);
12775
0
        break;
12776
0
    default:
12777
0
        abort();
12778
0
    }
12779
0
    if (a == &a_s)
12780
0
        bf_delete(a);
12781
0
    JS_FreeValue(ctx, op1);
12782
0
    if (unlikely(ret & BF_ST_MEM_ERROR)) {
12783
0
        JS_FreeValue(ctx, res);
12784
0
        throw_bf_exception(ctx, ret);
12785
0
        return -1;
12786
0
    }
12787
0
    *pres = res;
12788
0
    return 0;
12789
0
}
12790
12791
static int js_unary_arith_bigdecimal(JSContext *ctx,
12792
                                     JSValue *pres, OPCodeEnum op, JSValue op1)
12793
0
{
12794
0
    bfdec_t *r, *a;
12795
0
    int ret, v;
12796
0
    JSValue res;
12797
    
12798
0
    if (op == OP_plus && !is_math_mode(ctx)) {
12799
0
        JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");
12800
0
        JS_FreeValue(ctx, op1);
12801
0
        return -1;
12802
0
    }
12803
12804
0
    res = JS_NewBigDecimal(ctx);
12805
0
    if (JS_IsException(res)) {
12806
0
        JS_FreeValue(ctx, op1);
12807
0
        return -1;
12808
0
    }
12809
0
    r = JS_GetBigDecimal(res);
12810
0
    a = JS_ToBigDecimal(ctx, op1);
12811
0
    ret = 0;
12812
0
    switch(op) {
12813
0
    case OP_inc:
12814
0
    case OP_dec:
12815
0
        v = 2 * (op - OP_dec) - 1;
12816
0
        ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
12817
0
        break;
12818
0
    case OP_plus:
12819
0
        ret = bfdec_set(r, a);
12820
0
        break;
12821
0
    case OP_neg:
12822
0
        ret = bfdec_set(r, a);
12823
0
        bfdec_neg(r);
12824
0
        break;
12825
0
    default:
12826
0
        abort();
12827
0
    }
12828
0
    JS_FreeValue(ctx, op1);
12829
0
    if (unlikely(ret)) {
12830
0
        JS_FreeValue(ctx, res);
12831
0
        throw_bf_exception(ctx, ret);
12832
0
        return -1;
12833
0
    }
12834
0
    *pres = res;
12835
0
    return 0;
12836
0
}
12837
12838
static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
12839
                                                     JSValue *sp,
12840
                                                     OPCodeEnum op)
12841
40.9k
{
12842
40.9k
    JSValue op1, val;
12843
40.9k
    int v, ret;
12844
40.9k
    uint32_t tag;
12845
12846
40.9k
    op1 = sp[-1];
12847
    /* fast path for float64 */
12848
40.9k
    if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
12849
0
        goto handle_float64;
12850
40.9k
    if (JS_IsObject(op1)) {
12851
40.9k
        ret = js_call_unary_op_fallback(ctx, &val, op1, op);
12852
40.9k
        if (ret < 0)
12853
0
            return -1;
12854
40.9k
        if (ret) {
12855
0
            JS_FreeValue(ctx, op1);
12856
0
            sp[-1] = val;
12857
0
            return 0;
12858
0
        }
12859
40.9k
    }
12860
12861
40.9k
    op1 = JS_ToNumericFree(ctx, op1);
12862
40.9k
    if (JS_IsException(op1))
12863
0
        goto exception;
12864
40.9k
    tag = JS_VALUE_GET_TAG(op1);
12865
40.9k
    switch(tag) {
12866
0
    case JS_TAG_INT:
12867
0
        {
12868
0
            int64_t v64;
12869
0
            v64 = JS_VALUE_GET_INT(op1);
12870
0
            switch(op) {
12871
0
            case OP_inc:
12872
0
            case OP_dec:
12873
0
                v = 2 * (op - OP_dec) - 1;
12874
0
                v64 += v;
12875
0
                break;
12876
0
            case OP_plus:
12877
0
                break;
12878
0
            case OP_neg:
12879
0
                if (v64 == 0) {
12880
0
                    sp[-1] = __JS_NewFloat64(ctx, -0.0);
12881
0
                    return 0;
12882
0
                } else {
12883
0
                    v64 = -v64;
12884
0
                }
12885
0
                break;
12886
0
            default:
12887
0
                abort();
12888
0
            }
12889
0
            sp[-1] = JS_NewInt64(ctx, v64);
12890
0
        }
12891
0
        break;
12892
0
    case JS_TAG_BIG_INT:
12893
0
    handle_bigint:
12894
0
        if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1))
12895
0
            goto exception;
12896
0
        break;
12897
0
    case JS_TAG_BIG_FLOAT:
12898
0
        if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1))
12899
0
            goto exception;
12900
0
        break;
12901
0
    case JS_TAG_BIG_DECIMAL:
12902
0
        if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1))
12903
0
            goto exception;
12904
0
        break;
12905
40.9k
    default:
12906
40.9k
    handle_float64:
12907
40.9k
        {
12908
40.9k
            double d;
12909
40.9k
            if (is_math_mode(ctx))
12910
0
                goto handle_bigint;
12911
40.9k
            d = JS_VALUE_GET_FLOAT64(op1);
12912
40.9k
            switch(op) {
12913
40.9k
            case OP_inc:
12914
40.9k
            case OP_dec:
12915
40.9k
                v = 2 * (op - OP_dec) - 1;
12916
40.9k
                d += v;
12917
40.9k
                break;
12918
0
            case OP_plus:
12919
0
                break;
12920
11
            case OP_neg:
12921
11
                d = -d;
12922
11
                break;
12923
0
            default:
12924
0
                abort();
12925
40.9k
            }
12926
40.9k
            sp[-1] = __JS_NewFloat64(ctx, d);
12927
40.9k
        }
12928
0
        break;
12929
40.9k
    }
12930
40.9k
    return 0;
12931
0
 exception:
12932
0
    sp[-1] = JS_UNDEFINED;
12933
0
    return -1;
12934
40.9k
}
12935
12936
static __exception int js_post_inc_slow(JSContext *ctx,
12937
                                        JSValue *sp, OPCodeEnum op)
12938
0
{
12939
0
    JSValue op1;
12940
12941
    /* XXX: allow custom operators */
12942
0
    op1 = sp[-1];
12943
0
    op1 = JS_ToNumericFree(ctx, op1);
12944
0
    if (JS_IsException(op1)) {
12945
0
        sp[-1] = JS_UNDEFINED;
12946
0
        return -1;
12947
0
    }
12948
0
    sp[-1] = op1;
12949
0
    sp[0] = JS_DupValue(ctx, op1);
12950
0
    return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec);
12951
0
}
12952
12953
static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
12954
7
{
12955
7
    JSValue op1, val;
12956
7
    int ret;
12957
    
12958
7
    op1 = sp[-1];
12959
7
    if (JS_IsObject(op1)) {
12960
1
        ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not);
12961
1
        if (ret < 0)
12962
0
            return -1;
12963
1
        if (ret) {
12964
0
            JS_FreeValue(ctx, op1);
12965
0
            sp[-1] = val;
12966
0
            return 0;
12967
0
        }
12968
1
    }
12969
12970
7
    op1 = JS_ToNumericFree(ctx, op1);
12971
7
    if (JS_IsException(op1))
12972
0
        goto exception;
12973
7
    if (is_math_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
12974
0
        if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1))
12975
0
            goto exception;
12976
7
    } else {
12977
7
        int32_t v1;
12978
7
        if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
12979
0
            goto exception;
12980
7
        sp[-1] = JS_NewInt32(ctx, ~v1);
12981
7
    }
12982
7
    return 0;
12983
0
 exception:
12984
0
    sp[-1] = JS_UNDEFINED;
12985
0
    return -1;
12986
7
}
12987
12988
static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
12989
                                    JSValue *pres, JSValue op1, JSValue op2)
12990
0
{
12991
0
    bf_t a_s, b_s, *r, *a, *b;
12992
0
    int ret;
12993
0
    JSValue res;
12994
    
12995
0
    res = JS_NewBigFloat(ctx);
12996
0
    if (JS_IsException(res)) {
12997
0
        JS_FreeValue(ctx, op1);
12998
0
        JS_FreeValue(ctx, op2);
12999
0
        return -1;
13000
0
    }
13001
0
    r = JS_GetBigFloat(res);
13002
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
13003
0
    b = JS_ToBigFloat(ctx, &b_s, op2);
13004
0
    bf_init(ctx->bf_ctx, r);
13005
0
    switch(op) {
13006
0
    case OP_add:
13007
0
        ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
13008
0
        break;
13009
0
    case OP_sub:
13010
0
        ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
13011
0
        break;
13012
0
    case OP_mul:
13013
0
        ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
13014
0
        break;
13015
0
    case OP_div:
13016
0
        ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
13017
0
        break;
13018
0
    case OP_math_mod:
13019
        /* Euclidian remainder */
13020
0
        ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
13021
0
                     BF_DIVREM_EUCLIDIAN);
13022
0
        break;
13023
0
    case OP_mod:
13024
0
        ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
13025
0
                     BF_RNDZ);
13026
0
        break;
13027
0
    case OP_pow:
13028
0
        ret = bf_pow(r, a, b, ctx->fp_env.prec,
13029
0
                     ctx->fp_env.flags | BF_POW_JS_QUIRKS);
13030
0
        break;
13031
0
    default:
13032
0
        abort();
13033
0
    }
13034
0
    if (a == &a_s)
13035
0
        bf_delete(a);
13036
0
    if (b == &b_s)
13037
0
        bf_delete(b);
13038
0
    JS_FreeValue(ctx, op1);
13039
0
    JS_FreeValue(ctx, op2);
13040
0
    if (unlikely(ret & BF_ST_MEM_ERROR)) {
13041
0
        JS_FreeValue(ctx, res);
13042
0
        throw_bf_exception(ctx, ret);
13043
0
        return -1;
13044
0
    }
13045
0
    *pres = res;
13046
0
    return 0;
13047
0
}
13048
13049
static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
13050
                                  JSValue *pres, JSValue op1, JSValue op2)
13051
1
{
13052
1
    bf_t a_s, b_s, *r, *a, *b;
13053
1
    int ret;
13054
1
    JSValue res;
13055
    
13056
1
    res = JS_NewBigInt(ctx);
13057
1
    if (JS_IsException(res))
13058
0
        goto fail;
13059
1
    a = JS_ToBigInt(ctx, &a_s, op1);
13060
1
    if (!a)
13061
0
        goto fail;
13062
1
    b = JS_ToBigInt(ctx, &b_s, op2);
13063
1
    if (!b) {
13064
0
        JS_FreeBigInt(ctx, a, &a_s);
13065
0
        goto fail;
13066
0
    }
13067
1
    r = JS_GetBigInt(res);
13068
1
    ret = 0;
13069
1
    switch(op) {
13070
0
    case OP_add:
13071
0
        ret = bf_add(r, a, b, BF_PREC_INF, BF_RNDZ);
13072
0
        break;
13073
0
    case OP_sub:
13074
0
        ret = bf_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
13075
0
        break;
13076
0
    case OP_mul:
13077
0
        ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
13078
0
        break;
13079
0
    case OP_div:
13080
0
        if (!is_math_mode(ctx)) {
13081
0
            bf_t rem_s, *rem = &rem_s;
13082
0
            bf_init(ctx->bf_ctx, rem);
13083
0
            ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ,
13084
0
                            BF_RNDZ);
13085
0
            bf_delete(rem);
13086
0
        } else {
13087
0
            goto math_mode_div_pow;
13088
0
        }
13089
0
        break;
13090
0
    case OP_math_mod:
13091
        /* Euclidian remainder */
13092
0
        ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
13093
0
                     BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP;
13094
0
        break;
13095
0
    case OP_mod:
13096
0
        ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
13097
0
                     BF_RNDZ) & BF_ST_INVALID_OP;
13098
0
        break;
13099
1
    case OP_pow:
13100
1
        if (b->sign) {
13101
0
            if (!is_math_mode(ctx)) {
13102
0
                ret = BF_ST_INVALID_OP;
13103
0
            } else {
13104
0
            math_mode_div_pow:
13105
0
                JS_FreeValue(ctx, res);
13106
0
                ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op);
13107
0
                if (ret != 0) {
13108
0
                    JS_FreeBigInt(ctx, a, &a_s);
13109
0
                    JS_FreeBigInt(ctx, b, &b_s);
13110
0
                    JS_FreeValue(ctx, op1);
13111
0
                    JS_FreeValue(ctx, op2);
13112
0
                    if (ret < 0) {
13113
0
                        return -1;
13114
0
                    } else {
13115
0
                        *pres = res;
13116
0
                        return 0;
13117
0
                    }
13118
0
                }
13119
                /* if no BigInt power operator defined, return a
13120
                   bigfloat */
13121
0
                res = JS_NewBigFloat(ctx);
13122
0
                if (JS_IsException(res)) {
13123
0
                    JS_FreeBigInt(ctx, a, &a_s);
13124
0
                    JS_FreeBigInt(ctx, b, &b_s);
13125
0
                    goto fail;
13126
0
                }
13127
0
                r = JS_GetBigFloat(res);
13128
0
                if (op == OP_div) {
13129
0
                    ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags) & BF_ST_MEM_ERROR;
13130
0
                } else {
13131
0
                    ret = bf_pow(r, a, b, ctx->fp_env.prec,
13132
0
                                 ctx->fp_env.flags | BF_POW_JS_QUIRKS) & BF_ST_MEM_ERROR;
13133
0
                }
13134
0
                JS_FreeBigInt(ctx, a, &a_s);
13135
0
                JS_FreeBigInt(ctx, b, &b_s);
13136
0
                JS_FreeValue(ctx, op1);
13137
0
                JS_FreeValue(ctx, op2);
13138
0
                if (unlikely(ret)) {
13139
0
                    JS_FreeValue(ctx, res);
13140
0
                    throw_bf_exception(ctx, ret);
13141
0
                    return -1;
13142
0
                }
13143
0
                *pres = res;
13144
0
                return 0;
13145
0
            }
13146
1
        } else {
13147
1
            ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS);
13148
1
        }
13149
1
        break;
13150
13151
        /* logical operations */
13152
1
    case OP_shl:
13153
0
    case OP_sar:
13154
0
        {
13155
0
            slimb_t v2;
13156
#if LIMB_BITS == 32
13157
            bf_get_int32(&v2, b, 0);
13158
            if (v2 == INT32_MIN)
13159
                v2 = INT32_MIN + 1;
13160
#else
13161
0
            bf_get_int64(&v2, b, 0);
13162
0
            if (v2 == INT64_MIN)
13163
0
                v2 = INT64_MIN + 1;
13164
0
#endif
13165
0
            if (op == OP_sar)
13166
0
                v2 = -v2;
13167
0
            ret = bf_set(r, a);
13168
0
            ret |= bf_mul_2exp(r, v2, BF_PREC_INF, BF_RNDZ);
13169
0
            if (v2 < 0) {
13170
0
                ret |= bf_rint(r, BF_RNDD) & (BF_ST_OVERFLOW | BF_ST_MEM_ERROR);
13171
0
            }
13172
0
        }
13173
0
        break;
13174
0
    case OP_and:
13175
0
        ret = bf_logic_and(r, a, b);
13176
0
        break;
13177
0
    case OP_or:
13178
0
        ret = bf_logic_or(r, a, b);
13179
0
        break;
13180
0
    case OP_xor:
13181
0
        ret = bf_logic_xor(r, a, b);
13182
0
        break;
13183
0
    default:
13184
0
        abort();
13185
1
    }
13186
1
    JS_FreeBigInt(ctx, a, &a_s);
13187
1
    JS_FreeBigInt(ctx, b, &b_s);
13188
1
    JS_FreeValue(ctx, op1);
13189
1
    JS_FreeValue(ctx, op2);
13190
1
    if (unlikely(ret)) {
13191
0
        JS_FreeValue(ctx, res);
13192
0
        throw_bf_exception(ctx, ret);
13193
0
        return -1;
13194
0
    }
13195
1
    *pres = JS_CompactBigInt(ctx, res);
13196
1
    return 0;
13197
0
 fail:
13198
0
    JS_FreeValue(ctx, res);
13199
0
    JS_FreeValue(ctx, op1);
13200
0
    JS_FreeValue(ctx, op2);
13201
0
    return -1;
13202
1
}
13203
13204
/* b must be a positive integer */
13205
static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b)
13206
0
{
13207
0
    bfdec_t b1;
13208
0
    int32_t b2;
13209
0
    int ret;
13210
13211
0
    bfdec_init(b->ctx, &b1);
13212
0
    ret = bfdec_set(&b1, b);
13213
0
    if (ret) {
13214
0
        bfdec_delete(&b1);
13215
0
        return ret;
13216
0
    }
13217
0
    ret = bfdec_rint(&b1, BF_RNDZ);
13218
0
    if (ret) {
13219
0
        bfdec_delete(&b1);
13220
0
        return BF_ST_INVALID_OP; /* must be an integer */
13221
0
    }
13222
0
    ret = bfdec_get_int32(&b2, &b1);
13223
0
    bfdec_delete(&b1);
13224
0
    if (ret)
13225
0
        return ret; /* overflow */
13226
0
    if (b2 < 0)
13227
0
        return BF_ST_INVALID_OP; /* must be positive */
13228
0
    return bfdec_pow_ui(r, a, b2);
13229
0
}
13230
13231
static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
13232
                                      JSValue *pres, JSValue op1, JSValue op2)
13233
0
{
13234
0
    bfdec_t *r, *a, *b;
13235
0
    int ret;
13236
0
    JSValue res;
13237
13238
0
    res = JS_NewBigDecimal(ctx);
13239
0
    if (JS_IsException(res))
13240
0
        goto fail;
13241
0
    r = JS_GetBigDecimal(res);
13242
    
13243
0
    a = JS_ToBigDecimal(ctx, op1);
13244
0
    if (!a)
13245
0
        goto fail;
13246
0
    b = JS_ToBigDecimal(ctx, op2);
13247
0
    if (!b)
13248
0
        goto fail;
13249
0
    switch(op) {
13250
0
    case OP_add:
13251
0
        ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ);
13252
0
        break;
13253
0
    case OP_sub:
13254
0
        ret = bfdec_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
13255
0
        break;
13256
0
    case OP_mul:
13257
0
        ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
13258
0
        break;
13259
0
    case OP_div:
13260
0
        ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ);
13261
0
        break;
13262
0
    case OP_math_mod:
13263
        /* Euclidian remainder */
13264
0
        ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN);
13265
0
        break;
13266
0
    case OP_mod:
13267
0
        ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ);
13268
0
        break;
13269
0
    case OP_pow:
13270
0
        ret = js_bfdec_pow(r, a, b);
13271
0
        break;
13272
0
    default:
13273
0
        abort();
13274
0
    }
13275
0
    JS_FreeValue(ctx, op1);
13276
0
    JS_FreeValue(ctx, op2);
13277
0
    if (unlikely(ret)) {
13278
0
        JS_FreeValue(ctx, res);
13279
0
        throw_bf_exception(ctx, ret);
13280
0
        return -1;
13281
0
    }
13282
0
    *pres = res;
13283
0
    return 0;
13284
0
 fail:
13285
0
    JS_FreeValue(ctx, res);
13286
0
    JS_FreeValue(ctx, op1);
13287
0
    JS_FreeValue(ctx, op2);
13288
0
    return -1;
13289
0
}
13290
13291
static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
13292
                                                      OPCodeEnum op)
13293
112k
{
13294
112k
    JSValue op1, op2, res;
13295
112k
    uint32_t tag1, tag2;
13296
112k
    int ret;
13297
112k
    double d1, d2;
13298
13299
112k
    op1 = sp[-2];
13300
112k
    op2 = sp[-1];
13301
112k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13302
112k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13303
    /* fast path for float operations */
13304
112k
    if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
13305
0
        d1 = JS_VALUE_GET_FLOAT64(op1);
13306
0
        d2 = JS_VALUE_GET_FLOAT64(op2);
13307
0
        goto handle_float64;
13308
0
    }
13309
13310
    /* try to call an overloaded operator */
13311
112k
    if ((tag1 == JS_TAG_OBJECT &&
13312
112k
         (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
13313
112k
        (tag2 == JS_TAG_OBJECT &&
13314
112k
         (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
13315
112k
        ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
13316
112k
        if (ret != 0) {
13317
0
            JS_FreeValue(ctx, op1);
13318
0
            JS_FreeValue(ctx, op2);
13319
0
            if (ret < 0) {
13320
0
                goto exception;
13321
0
            } else {
13322
0
                sp[-2] = res;
13323
0
                return 0;
13324
0
            }
13325
0
        }
13326
112k
    }
13327
13328
112k
    op1 = JS_ToNumericFree(ctx, op1);
13329
112k
    if (JS_IsException(op1)) {
13330
0
        JS_FreeValue(ctx, op2);
13331
0
        goto exception;
13332
0
    }
13333
112k
    op2 = JS_ToNumericFree(ctx, op2);
13334
112k
    if (JS_IsException(op2)) {
13335
0
        JS_FreeValue(ctx, op1);
13336
0
        goto exception;
13337
0
    }
13338
112k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13339
112k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13340
13341
112k
    if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
13342
0
        int32_t v1, v2;
13343
0
        int64_t v;
13344
0
        v1 = JS_VALUE_GET_INT(op1);
13345
0
        v2 = JS_VALUE_GET_INT(op2);
13346
0
        switch(op) {
13347
0
        case OP_sub:
13348
0
            v = (int64_t)v1 - (int64_t)v2;
13349
0
            break;
13350
0
        case OP_mul:
13351
0
            v = (int64_t)v1 * (int64_t)v2;
13352
0
            if (is_math_mode(ctx) &&
13353
0
                (v < -MAX_SAFE_INTEGER || v > MAX_SAFE_INTEGER))
13354
0
                goto handle_bigint;
13355
0
            if (v == 0 && (v1 | v2) < 0) {
13356
0
                sp[-2] = __JS_NewFloat64(ctx, -0.0);
13357
0
                return 0;
13358
0
            }
13359
0
            break;
13360
0
        case OP_div:
13361
0
            if (is_math_mode(ctx))
13362
0
                goto handle_bigint;
13363
0
            sp[-2] = __JS_NewFloat64(ctx, (double)v1 / (double)v2);
13364
0
            return 0;
13365
0
        case OP_math_mod:
13366
0
            if (unlikely(v2 == 0)) {
13367
0
                throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO);
13368
0
                goto exception;
13369
0
            }
13370
0
            v = (int64_t)v1 % (int64_t)v2;
13371
0
            if (v < 0) {
13372
0
                if (v2 < 0)
13373
0
                    v -= v2;
13374
0
                else
13375
0
                    v += v2;
13376
0
            }
13377
0
            break;
13378
0
        case OP_mod:
13379
0
            if (v1 < 0 || v2 <= 0) {
13380
0
                sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));
13381
0
                return 0;
13382
0
            } else {
13383
0
                v = (int64_t)v1 % (int64_t)v2;
13384
0
            }
13385
0
            break;
13386
0
        case OP_pow:
13387
0
            if (!is_math_mode(ctx)) {
13388
0
                sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));
13389
0
                return 0;
13390
0
            } else {
13391
0
                goto handle_bigint;
13392
0
            }
13393
0
            break;
13394
0
        default:
13395
0
            abort();
13396
0
        }
13397
0
        sp[-2] = JS_NewInt64(ctx, v);
13398
112k
    } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
13399
0
        if (ctx->rt->bigdecimal_ops.binary_arith(ctx, op, sp - 2, op1, op2))
13400
0
            goto exception;
13401
112k
    } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
13402
0
        if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2))
13403
0
            goto exception;
13404
112k
    } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
13405
1
    handle_bigint:
13406
1
        if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
13407
0
            goto exception;
13408
112k
    } else {
13409
112k
        double dr;
13410
        /* float64 result */
13411
112k
        if (JS_ToFloat64Free(ctx, &d1, op1)) {
13412
0
            JS_FreeValue(ctx, op2);
13413
0
            goto exception;
13414
0
        }
13415
112k
        if (JS_ToFloat64Free(ctx, &d2, op2))
13416
0
            goto exception;
13417
112k
    handle_float64:
13418
112k
        if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
13419
0
            goto handle_bigint;
13420
112k
        switch(op) {
13421
40.9k
        case OP_sub:
13422
40.9k
            dr = d1 - d2;
13423
40.9k
            break;
13424
71.9k
        case OP_mul:
13425
71.9k
            dr = d1 * d2;
13426
71.9k
            break;
13427
10
        case OP_div:
13428
10
            dr = d1 / d2;
13429
10
            break;
13430
0
        case OP_mod:
13431
0
            dr = fmod(d1, d2);
13432
0
            break;
13433
0
        case OP_math_mod:
13434
0
            d2 = fabs(d2);
13435
0
            dr = fmod(d1, d2);
13436
            /* XXX: loss of accuracy if dr < 0 */
13437
0
            if (dr < 0)
13438
0
                dr += d2;
13439
0
            break;
13440
0
        case OP_pow:
13441
0
            dr = js_pow(d1, d2);
13442
0
            break;
13443
0
        default:
13444
0
            abort();
13445
112k
        }
13446
112k
        sp[-2] = __JS_NewFloat64(ctx, dr);
13447
112k
    }
13448
112k
    return 0;
13449
0
 exception:
13450
0
    sp[-2] = JS_UNDEFINED;
13451
0
    sp[-1] = JS_UNDEFINED;
13452
0
    return -1;
13453
112k
}
13454
13455
static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
13456
71.9k
{
13457
71.9k
    JSValue op1, op2, res;
13458
71.9k
    uint32_t tag1, tag2;
13459
71.9k
    int ret;
13460
13461
71.9k
    op1 = sp[-2];
13462
71.9k
    op2 = sp[-1];
13463
13464
71.9k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13465
71.9k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13466
    /* fast path for float64 */
13467
71.9k
    if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
13468
0
        double d1, d2;
13469
0
        d1 = JS_VALUE_GET_FLOAT64(op1);
13470
0
        d2 = JS_VALUE_GET_FLOAT64(op2);
13471
0
        sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
13472
0
        return 0;
13473
0
    }
13474
13475
71.9k
    if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
13476
        /* try to call an overloaded operator */
13477
71.9k
        if ((tag1 == JS_TAG_OBJECT &&
13478
71.9k
             (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED &&
13479
3
              tag2 != JS_TAG_STRING)) ||
13480
71.9k
            (tag2 == JS_TAG_OBJECT &&
13481
71.9k
             (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED &&
13482
71.9k
              tag1 != JS_TAG_STRING))) {
13483
71.9k
            ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add,
13484
71.9k
                                             FALSE, HINT_NONE);
13485
71.9k
            if (ret != 0) {
13486
0
                JS_FreeValue(ctx, op1);
13487
0
                JS_FreeValue(ctx, op2);
13488
0
                if (ret < 0) {
13489
0
                    goto exception;
13490
0
                } else {
13491
0
                    sp[-2] = res;
13492
0
                    return 0;
13493
0
                }
13494
0
            }
13495
71.9k
        }
13496
13497
71.9k
        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
13498
71.9k
        if (JS_IsException(op1)) {
13499
0
            JS_FreeValue(ctx, op2);
13500
0
            goto exception;
13501
0
        }
13502
13503
71.9k
        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
13504
71.9k
        if (JS_IsException(op2)) {
13505
0
            JS_FreeValue(ctx, op1);
13506
0
            goto exception;
13507
0
        }
13508
71.9k
        tag1 = JS_VALUE_GET_NORM_TAG(op1);
13509
71.9k
        tag2 = JS_VALUE_GET_NORM_TAG(op2);
13510
71.9k
    }
13511
13512
71.9k
    if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
13513
71.9k
        sp[-2] = JS_ConcatString(ctx, op1, op2);
13514
71.9k
        if (JS_IsException(sp[-2]))
13515
0
            goto exception;
13516
71.9k
        return 0;
13517
71.9k
    }
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
        v = (int64_t)v1 + (int64_t)v2;
13538
0
        sp[-2] = JS_NewInt64(ctx, v);
13539
0
    } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
13540
0
        if (ctx->rt->bigdecimal_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
13541
0
            goto exception;
13542
0
    } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
13543
0
        if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
13544
0
            goto exception;
13545
0
    } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
13546
0
    handle_bigint:
13547
0
        if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
13548
0
            goto exception;
13549
0
    } else {
13550
0
        double d1, d2;
13551
        /* float64 result */
13552
0
        if (JS_ToFloat64Free(ctx, &d1, op1)) {
13553
0
            JS_FreeValue(ctx, op2);
13554
0
            goto exception;
13555
0
        }
13556
0
        if (JS_ToFloat64Free(ctx, &d2, op2))
13557
0
            goto exception;
13558
0
        if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
13559
0
            goto handle_bigint;
13560
0
        sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
13561
0
    }
13562
0
    return 0;
13563
0
 exception:
13564
0
    sp[-2] = JS_UNDEFINED;
13565
0
    sp[-1] = JS_UNDEFINED;
13566
0
    return -1;
13567
0
}
13568
13569
static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
13570
                                                      JSValue *sp,
13571
                                                      OPCodeEnum op)
13572
41.0k
{
13573
41.0k
    JSValue op1, op2, res;
13574
41.0k
    int ret;
13575
41.0k
    uint32_t tag1, tag2;
13576
41.0k
    uint32_t v1, v2, r;
13577
13578
41.0k
    op1 = sp[-2];
13579
41.0k
    op2 = sp[-1];
13580
41.0k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13581
41.0k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13582
13583
    /* try to call an overloaded operator */
13584
41.0k
    if ((tag1 == JS_TAG_OBJECT &&
13585
41.0k
         (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
13586
41.0k
        (tag2 == JS_TAG_OBJECT &&
13587
41.0k
         (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
13588
28
        ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
13589
28
        if (ret != 0) {
13590
0
            JS_FreeValue(ctx, op1);
13591
0
            JS_FreeValue(ctx, op2);
13592
0
            if (ret < 0) {
13593
0
                goto exception;
13594
0
            } else {
13595
0
                sp[-2] = res;
13596
0
                return 0;
13597
0
            }
13598
0
        }
13599
28
    }
13600
13601
41.0k
    op1 = JS_ToNumericFree(ctx, op1);
13602
41.0k
    if (JS_IsException(op1)) {
13603
0
        JS_FreeValue(ctx, op2);
13604
0
        goto exception;
13605
0
    }
13606
41.0k
    op2 = JS_ToNumericFree(ctx, op2);
13607
41.0k
    if (JS_IsException(op2)) {
13608
0
        JS_FreeValue(ctx, op1);
13609
0
        goto exception;
13610
0
    }
13611
13612
41.0k
    if (is_math_mode(ctx))
13613
0
        goto bigint_op;
13614
13615
41.0k
    tag1 = JS_VALUE_GET_TAG(op1);
13616
41.0k
    tag2 = JS_VALUE_GET_TAG(op2);
13617
41.0k
    if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
13618
0
        if (tag1 != tag2) {
13619
0
            JS_FreeValue(ctx, op1);
13620
0
            JS_FreeValue(ctx, op2);
13621
0
            JS_ThrowTypeError(ctx, "both operands must be bigint");
13622
0
            goto exception;
13623
0
        } else {
13624
0
        bigint_op:
13625
0
            if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
13626
0
                goto exception;
13627
0
        }
13628
41.0k
    } else {
13629
41.0k
        if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
13630
0
            JS_FreeValue(ctx, op2);
13631
0
            goto exception;
13632
0
        }
13633
41.0k
        if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
13634
0
            goto exception;
13635
41.0k
        switch(op) {
13636
0
        case OP_shl:
13637
0
            r = v1 << (v2 & 0x1f);
13638
0
            break;
13639
0
        case OP_sar:
13640
0
            r = (int)v1 >> (v2 & 0x1f);
13641
0
            break;
13642
41.0k
        case OP_and:
13643
41.0k
            r = v1 & v2;
13644
41.0k
            break;
13645
0
        case OP_or:
13646
0
            r = v1 | v2;
13647
0
            break;
13648
0
        case OP_xor:
13649
0
            r = v1 ^ v2;
13650
0
            break;
13651
0
        default:
13652
0
            abort();
13653
41.0k
        }
13654
41.0k
        sp[-2] = JS_NewInt32(ctx, r);
13655
41.0k
    }
13656
41.0k
    return 0;
13657
0
 exception:
13658
0
    sp[-2] = JS_UNDEFINED;
13659
0
    sp[-1] = JS_UNDEFINED;
13660
0
    return -1;
13661
41.0k
}
13662
13663
/* Note: also used for bigint */
13664
static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op,
13665
                               JSValue op1, JSValue op2)
13666
0
{
13667
0
    bf_t a_s, b_s, *a, *b;
13668
0
    int res;
13669
    
13670
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
13671
0
    if (!a) {
13672
0
        JS_FreeValue(ctx, op2);
13673
0
        return -1;
13674
0
    }
13675
0
    b = JS_ToBigFloat(ctx, &b_s, op2);
13676
0
    if (!b) {
13677
0
        if (a == &a_s)
13678
0
            bf_delete(a);
13679
0
        JS_FreeValue(ctx, op1);
13680
0
        return -1;
13681
0
    }
13682
0
    switch(op) {
13683
0
    case OP_lt:
13684
0
        res = bf_cmp_lt(a, b); /* if NaN return false */
13685
0
        break;
13686
0
    case OP_lte:
13687
0
        res = bf_cmp_le(a, b); /* if NaN return false */
13688
0
        break;
13689
0
    case OP_gt:
13690
0
        res = bf_cmp_lt(b, a); /* if NaN return false */
13691
0
        break;
13692
0
    case OP_gte:
13693
0
        res = bf_cmp_le(b, a); /* if NaN return false */
13694
0
        break;
13695
0
    case OP_eq:
13696
0
        res = bf_cmp_eq(a, b); /* if NaN return false */
13697
0
        break;
13698
0
    default:
13699
0
        abort();
13700
0
    }
13701
0
    if (a == &a_s)
13702
0
        bf_delete(a);
13703
0
    if (b == &b_s)
13704
0
        bf_delete(b);
13705
0
    JS_FreeValue(ctx, op1);
13706
0
    JS_FreeValue(ctx, op2);
13707
0
    return res;
13708
0
}
13709
13710
static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op,
13711
                                 JSValue op1, JSValue op2)
13712
0
{
13713
0
    bfdec_t *a, *b;
13714
0
    int res;
13715
13716
    /* Note: binary floats are converted to bigdecimal with
13717
       toString(). It is not mathematically correct but is consistent
13718
       with the BigDecimal() constructor behavior */
13719
0
    op1 = JS_ToBigDecimalFree(ctx, op1, TRUE);
13720
0
    if (JS_IsException(op1)) {
13721
0
        JS_FreeValue(ctx, op2);
13722
0
        return -1;
13723
0
    }
13724
0
    op2 = JS_ToBigDecimalFree(ctx, op2, TRUE);
13725
0
    if (JS_IsException(op2)) {
13726
0
        JS_FreeValue(ctx, op1);
13727
0
        return -1;
13728
0
    }
13729
0
    a = JS_ToBigDecimal(ctx, op1);
13730
0
    b = JS_ToBigDecimal(ctx, op2);
13731
    
13732
0
    switch(op) {
13733
0
    case OP_lt:
13734
0
        res = bfdec_cmp_lt(a, b); /* if NaN return false */
13735
0
        break;
13736
0
    case OP_lte:
13737
0
        res = bfdec_cmp_le(a, b); /* if NaN return false */
13738
0
        break;
13739
0
    case OP_gt:
13740
0
        res = bfdec_cmp_lt(b, a); /* if NaN return false */
13741
0
        break;
13742
0
    case OP_gte:
13743
0
        res = bfdec_cmp_le(b, a); /* if NaN return false */
13744
0
        break;
13745
0
    case OP_eq:
13746
0
        res = bfdec_cmp_eq(a, b); /* if NaN return false */
13747
0
        break;
13748
0
    default:
13749
0
        abort();
13750
0
    }
13751
0
    JS_FreeValue(ctx, op1);
13752
0
    JS_FreeValue(ctx, op2);
13753
0
    return res;
13754
0
}
13755
13756
static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
13757
                                        OPCodeEnum op)
13758
40.9k
{
13759
40.9k
    JSValue op1, op2, ret;
13760
40.9k
    int res;
13761
40.9k
    uint32_t tag1, tag2;
13762
13763
40.9k
    op1 = sp[-2];
13764
40.9k
    op2 = sp[-1];
13765
40.9k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13766
40.9k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13767
    /* try to call an overloaded operator */
13768
40.9k
    if ((tag1 == JS_TAG_OBJECT &&
13769
40.9k
         (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
13770
40.9k
        (tag2 == JS_TAG_OBJECT &&
13771
40.9k
         (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
13772
0
        res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op,
13773
0
                                         FALSE, HINT_NUMBER);
13774
0
        if (res != 0) {
13775
0
            JS_FreeValue(ctx, op1);
13776
0
            JS_FreeValue(ctx, op2);
13777
0
            if (res < 0) {
13778
0
                goto exception;
13779
0
            } else {
13780
0
                sp[-2] = ret;
13781
0
                return 0;
13782
0
            }
13783
0
        }
13784
0
    }
13785
40.9k
    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
13786
40.9k
    if (JS_IsException(op1)) {
13787
0
        JS_FreeValue(ctx, op2);
13788
0
        goto exception;
13789
0
    }
13790
40.9k
    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
13791
40.9k
    if (JS_IsException(op2)) {
13792
0
        JS_FreeValue(ctx, op1);
13793
0
        goto exception;
13794
0
    }
13795
40.9k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13796
40.9k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13797
13798
40.9k
    if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
13799
0
        JSString *p1, *p2;
13800
0
        p1 = JS_VALUE_GET_STRING(op1);
13801
0
        p2 = JS_VALUE_GET_STRING(op2);
13802
0
        res = js_string_compare(ctx, p1, p2);
13803
0
        switch(op) {
13804
0
        case OP_lt:
13805
0
            res = (res < 0);
13806
0
            break;
13807
0
        case OP_lte:
13808
0
            res = (res <= 0);
13809
0
            break;
13810
0
        case OP_gt:
13811
0
            res = (res > 0);
13812
0
            break;
13813
0
        default:
13814
0
        case OP_gte:
13815
0
            res = (res >= 0);
13816
0
            break;
13817
0
        }
13818
0
        JS_FreeValue(ctx, op1);
13819
0
        JS_FreeValue(ctx, op2);
13820
40.9k
    } else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) &&
13821
40.9k
               (tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) {
13822
        /* fast path for float64/int */
13823
40.9k
        goto float64_compare;
13824
40.9k
    } else {
13825
1
        if (((tag1 == JS_TAG_BIG_INT && tag2 == JS_TAG_STRING) ||
13826
1
             (tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING)) &&
13827
1
            !is_math_mode(ctx)) {
13828
0
            if (tag1 == JS_TAG_STRING) {
13829
0
                op1 = JS_StringToBigInt(ctx, op1);
13830
0
                if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
13831
0
                    goto invalid_bigint_string;
13832
0
            }
13833
0
            if (tag2 == JS_TAG_STRING) {
13834
0
                op2 = JS_StringToBigInt(ctx, op2);
13835
0
                if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) {
13836
0
                invalid_bigint_string:
13837
0
                    JS_FreeValue(ctx, op1);
13838
0
                    JS_FreeValue(ctx, op2);
13839
0
                    res = FALSE;
13840
0
                    goto done;
13841
0
                }
13842
0
            }
13843
1
        } else {
13844
1
            op1 = JS_ToNumericFree(ctx, op1);
13845
1
            if (JS_IsException(op1)) {
13846
0
                JS_FreeValue(ctx, op2);
13847
0
                goto exception;
13848
0
            }
13849
1
            op2 = JS_ToNumericFree(ctx, op2);
13850
1
            if (JS_IsException(op2)) {
13851
0
                JS_FreeValue(ctx, op1);
13852
0
                goto exception;
13853
0
            }
13854
1
        }
13855
13856
1
        tag1 = JS_VALUE_GET_NORM_TAG(op1);
13857
1
        tag2 = JS_VALUE_GET_NORM_TAG(op2);
13858
13859
1
        if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
13860
0
            res = ctx->rt->bigdecimal_ops.compare(ctx, op, op1, op2);
13861
0
            if (res < 0)
13862
0
                goto exception;
13863
1
        } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
13864
0
            res = ctx->rt->bigfloat_ops.compare(ctx, op, op1, op2);
13865
0
            if (res < 0)
13866
0
                goto exception;
13867
1
        } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
13868
0
            res = ctx->rt->bigint_ops.compare(ctx, op, op1, op2);
13869
0
            if (res < 0)
13870
0
                goto exception;
13871
1
        } else {
13872
1
            double d1, d2;
13873
13874
40.9k
        float64_compare:
13875
            /* can use floating point comparison */
13876
40.9k
            if (tag1 == JS_TAG_FLOAT64) {
13877
40.9k
                d1 = JS_VALUE_GET_FLOAT64(op1);
13878
40.9k
            } else {
13879
2
                d1 = JS_VALUE_GET_INT(op1);
13880
2
            }
13881
40.9k
            if (tag2 == JS_TAG_FLOAT64) {
13882
1
                d2 = JS_VALUE_GET_FLOAT64(op2);
13883
40.9k
            } else {
13884
40.9k
                d2 = JS_VALUE_GET_INT(op2);
13885
40.9k
            }
13886
40.9k
            switch(op) {
13887
3
            case OP_lt:
13888
3
                res = (d1 < d2); /* if NaN return false */
13889
3
                break;
13890
0
            case OP_lte:
13891
0
                res = (d1 <= d2); /* if NaN return false */
13892
0
                break;
13893
40.9k
            case OP_gt:
13894
40.9k
                res = (d1 > d2); /* if NaN return false */
13895
40.9k
                break;
13896
0
            default:
13897
0
            case OP_gte:
13898
0
                res = (d1 >= d2); /* if NaN return false */
13899
0
                break;
13900
40.9k
            }
13901
40.9k
        }
13902
1
    }
13903
40.9k
 done:
13904
40.9k
    sp[-2] = JS_NewBool(ctx, res);
13905
40.9k
    return 0;
13906
0
 exception:
13907
0
    sp[-2] = JS_UNDEFINED;
13908
0
    sp[-1] = JS_UNDEFINED;
13909
0
    return -1;
13910
40.9k
}
13911
13912
static BOOL tag_is_number(uint32_t tag)
13913
6
{
13914
6
    return (tag == JS_TAG_INT || tag == JS_TAG_BIG_INT ||
13915
6
            tag == JS_TAG_FLOAT64 || tag == JS_TAG_BIG_FLOAT ||
13916
6
            tag == JS_TAG_BIG_DECIMAL);
13917
6
}
13918
13919
static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
13920
                                            BOOL is_neq)
13921
2
{
13922
2
    JSValue op1, op2, ret;
13923
2
    int res;
13924
2
    uint32_t tag1, tag2;
13925
13926
2
    op1 = sp[-2];
13927
2
    op2 = sp[-1];
13928
4
 redo:
13929
4
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
13930
4
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
13931
4
    if (tag_is_number(tag1) && tag_is_number(tag2)) {
13932
2
        if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
13933
2
            res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
13934
2
        } else if ((tag1 == JS_TAG_FLOAT64 &&
13935
0
                    (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) ||
13936
0
                   (tag2 == JS_TAG_FLOAT64 &&
13937
0
                    (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) {
13938
0
            double d1, d2;
13939
0
            if (tag1 == JS_TAG_FLOAT64) {
13940
0
                d1 = JS_VALUE_GET_FLOAT64(op1);
13941
0
            } else {
13942
0
                d1 = JS_VALUE_GET_INT(op1);
13943
0
            }
13944
0
            if (tag2 == JS_TAG_FLOAT64) {
13945
0
                d2 = JS_VALUE_GET_FLOAT64(op2);
13946
0
            } else {
13947
0
                d2 = JS_VALUE_GET_INT(op2);
13948
0
            }
13949
0
            res = (d1 == d2);
13950
0
        } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
13951
0
            res = ctx->rt->bigdecimal_ops.compare(ctx, OP_eq, op1, op2);
13952
0
            if (res < 0)
13953
0
                goto exception;
13954
0
        } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
13955
0
            res = ctx->rt->bigfloat_ops.compare(ctx, OP_eq, op1, op2);
13956
0
            if (res < 0)
13957
0
                goto exception;
13958
0
        } else {
13959
0
            res = ctx->rt->bigint_ops.compare(ctx, OP_eq, op1, op2);
13960
0
            if (res < 0)
13961
0
                goto exception;
13962
0
        }
13963
2
    } else if (tag1 == tag2) {
13964
0
        if (tag1 == JS_TAG_OBJECT) {
13965
            /* try the fallback operator */
13966
0
            res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
13967
0
                                             is_neq ? OP_neq : OP_eq,
13968
0
                                             FALSE, HINT_NONE);
13969
0
            if (res != 0) {
13970
0
                JS_FreeValue(ctx, op1);
13971
0
                JS_FreeValue(ctx, op2);
13972
0
                if (res < 0) {
13973
0
                    goto exception;
13974
0
                } else {
13975
0
                    sp[-2] = ret;
13976
0
                    return 0;
13977
0
                }
13978
0
            }
13979
0
        }
13980
0
        res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
13981
2
    } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
13982
2
               (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
13983
0
        res = TRUE;
13984
2
    } else if ((tag1 == JS_TAG_STRING && tag_is_number(tag2)) ||
13985
2
               (tag2 == JS_TAG_STRING && tag_is_number(tag1))) {
13986
13987
0
        if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) &&
13988
0
            !is_math_mode(ctx)) {
13989
0
            if (tag1 == JS_TAG_STRING) {
13990
0
                op1 = JS_StringToBigInt(ctx, op1);
13991
0
                if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
13992
0
                    goto invalid_bigint_string;
13993
0
            }
13994
0
            if (tag2 == JS_TAG_STRING) {
13995
0
                op2 = JS_StringToBigInt(ctx, op2);
13996
0
                if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) {
13997
0
                invalid_bigint_string:
13998
0
                    JS_FreeValue(ctx, op1);
13999
0
                    JS_FreeValue(ctx, op2);
14000
0
                    res = FALSE;
14001
0
                    goto done;
14002
0
                }
14003
0
            }
14004
0
        } else {
14005
0
            op1 = JS_ToNumericFree(ctx, op1);
14006
0
            if (JS_IsException(op1)) {
14007
0
                JS_FreeValue(ctx, op2);
14008
0
                goto exception;
14009
0
            }
14010
0
            op2 = JS_ToNumericFree(ctx, op2);
14011
0
            if (JS_IsException(op2)) {
14012
0
                JS_FreeValue(ctx, op1);
14013
0
                goto exception;
14014
0
            }
14015
0
        }
14016
0
        res = js_strict_eq(ctx, op1, op2);
14017
2
    } else if (tag1 == JS_TAG_BOOL) {
14018
2
        op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
14019
2
        goto redo;
14020
2
    } else if (tag2 == JS_TAG_BOOL) {
14021
0
        op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
14022
0
        goto redo;
14023
0
    } else if ((tag1 == JS_TAG_OBJECT &&
14024
0
                (tag_is_number(tag2) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) ||
14025
0
               (tag2 == JS_TAG_OBJECT &&
14026
0
                (tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) {
14027
14028
        /* try the fallback operator */
14029
0
        res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
14030
0
                                         is_neq ? OP_neq : OP_eq,
14031
0
                                         FALSE, HINT_NONE);
14032
0
        if (res != 0) {
14033
0
            JS_FreeValue(ctx, op1);
14034
0
            JS_FreeValue(ctx, op2);
14035
0
            if (res < 0) {
14036
0
                goto exception;
14037
0
            } else {
14038
0
                sp[-2] = ret;
14039
0
                return 0;
14040
0
            }
14041
0
        }
14042
14043
0
        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
14044
0
        if (JS_IsException(op1)) {
14045
0
            JS_FreeValue(ctx, op2);
14046
0
            goto exception;
14047
0
        }
14048
0
        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
14049
0
        if (JS_IsException(op2)) {
14050
0
            JS_FreeValue(ctx, op1);
14051
0
            goto exception;
14052
0
        }
14053
0
        goto redo;
14054
0
    } else {
14055
        /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
14056
0
        if ((JS_IsHTMLDDA(ctx, op1) &&
14057
0
             (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
14058
0
            (JS_IsHTMLDDA(ctx, op2) &&
14059
0
             (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
14060
0
            res = TRUE;
14061
0
        } else {
14062
0
            res = FALSE;
14063
0
        }
14064
0
        JS_FreeValue(ctx, op1);
14065
0
        JS_FreeValue(ctx, op2);
14066
0
    }
14067
2
 done:
14068
2
    sp[-2] = JS_NewBool(ctx, res ^ is_neq);
14069
2
    return 0;
14070
0
 exception:
14071
0
    sp[-2] = JS_UNDEFINED;
14072
0
    sp[-1] = JS_UNDEFINED;
14073
0
    return -1;
14074
4
}
14075
14076
static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
14077
0
{
14078
0
    JSValue op1, op2;
14079
0
    uint32_t v1, v2, r;
14080
14081
0
    op1 = sp[-2];
14082
0
    op2 = sp[-1];
14083
0
    op1 = JS_ToNumericFree(ctx, op1);
14084
0
    if (JS_IsException(op1)) {
14085
0
        JS_FreeValue(ctx, op2);
14086
0
        goto exception;
14087
0
    }
14088
0
    op2 = JS_ToNumericFree(ctx, op2);
14089
0
    if (JS_IsException(op2)) {
14090
0
        JS_FreeValue(ctx, op1);
14091
0
        goto exception;
14092
0
    }
14093
    /* XXX: could forbid >>> in bignum mode */
14094
0
    if (!is_math_mode(ctx) &&
14095
0
        (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||
14096
0
         JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT)) {
14097
0
        JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>");
14098
0
        JS_FreeValue(ctx, op1);
14099
0
        JS_FreeValue(ctx, op2);
14100
0
        goto exception;
14101
0
    }
14102
    /* cannot give an exception */
14103
0
    JS_ToUint32Free(ctx, &v1, op1);
14104
0
    JS_ToUint32Free(ctx, &v2, op2);
14105
0
    r = v1 >> (v2 & 0x1f);
14106
0
    sp[-2] = JS_NewUint32(ctx, r);
14107
0
    return 0;
14108
0
 exception:
14109
0
    sp[-2] = JS_UNDEFINED;
14110
0
    sp[-1] = JS_UNDEFINED;
14111
0
    return -1;
14112
0
}
14113
14114
static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
14115
                                       int64_t exponent)
14116
0
{
14117
0
    bf_t r_s, *r = &r_s;
14118
0
    double d;
14119
0
    int ret;
14120
    
14121
    /* always convert to Float64 */
14122
0
    bf_init(ctx->bf_ctx, r);
14123
0
    ret = bf_mul_pow_radix(r, a, 10, exponent,
14124
0
                           53, bf_set_exp_bits(11) | BF_RNDN |
14125
0
                           BF_FLAG_SUBNORMAL);
14126
0
    bf_get_float64(r, &d, BF_RNDN);
14127
0
    bf_delete(r);
14128
0
    if (ret & BF_ST_MEM_ERROR)
14129
0
        return JS_ThrowOutOfMemory(ctx);
14130
0
    else
14131
0
        return __JS_NewFloat64(ctx, d);
14132
0
}
14133
14134
static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
14135
0
{
14136
0
    bf_t a_s, *a, *r;
14137
0
    JSValue op1, op2, res;
14138
0
    int64_t e;
14139
0
    int ret;
14140
14141
0
    res = JS_NewBigFloat(ctx);
14142
0
    if (JS_IsException(res))
14143
0
        return -1;
14144
0
    r = JS_GetBigFloat(res);
14145
0
    op1 = sp[-2];
14146
0
    op2 = sp[-1];
14147
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
14148
0
    if (!a)
14149
0
        return -1;
14150
0
    if (JS_IsBigInt(ctx, op2)) {
14151
0
        ret = JS_ToBigInt64(ctx, &e, op2);
14152
0
    } else {
14153
0
        ret = JS_ToInt64(ctx, &e, op2);
14154
0
    }
14155
0
    if (ret) {
14156
0
        if (a == &a_s)
14157
0
            bf_delete(a);
14158
0
        JS_FreeValue(ctx, res);
14159
0
        return -1;
14160
0
    }
14161
14162
0
    bf_mul_pow_radix(r, a, 10, e, ctx->fp_env.prec, ctx->fp_env.flags);
14163
0
    if (a == &a_s)
14164
0
        bf_delete(a);
14165
0
    JS_FreeValue(ctx, op1);
14166
0
    JS_FreeValue(ctx, op2);
14167
0
    sp[-2] = res;
14168
0
    return 0;
14169
0
}
14170
14171
#else /* !CONFIG_BIGNUM */
14172
14173
static JSValue JS_ThrowUnsupportedBigint(JSContext *ctx)
14174
{
14175
    return JS_ThrowTypeError(ctx, "bigint is not supported");
14176
}
14177
14178
JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
14179
{
14180
    return JS_ThrowUnsupportedBigint(ctx);
14181
}
14182
14183
JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
14184
{
14185
    return JS_ThrowUnsupportedBigint(ctx);
14186
}
14187
14188
int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
14189
{
14190
    JS_ThrowUnsupportedBigint(ctx);
14191
    *pres = 0;
14192
    return -1;
14193
}
14194
14195
static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
14196
                                                     JSValue *sp,
14197
                                                     OPCodeEnum op)
14198
{
14199
    JSValue op1;
14200
    double d;
14201
14202
    op1 = sp[-1];
14203
    if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) {
14204
        sp[-1] = JS_UNDEFINED;
14205
        return -1;
14206
    }
14207
    switch(op) {
14208
    case OP_inc:
14209
        d++;
14210
        break;
14211
    case OP_dec:
14212
        d--;
14213
        break;
14214
    case OP_plus:
14215
        break;
14216
    case OP_neg:
14217
        d = -d;
14218
        break;
14219
    default:
14220
        abort();
14221
    }
14222
    sp[-1] = JS_NewFloat64(ctx, d);
14223
    return 0;
14224
}
14225
14226
/* specific case necessary for correct return value semantics */
14227
static __exception int js_post_inc_slow(JSContext *ctx,
14228
                                        JSValue *sp, OPCodeEnum op)
14229
{
14230
    JSValue op1;
14231
    double d, r;
14232
14233
    op1 = sp[-1];
14234
    if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) {
14235
        sp[-1] = JS_UNDEFINED;
14236
        return -1;
14237
    }
14238
    r = d + 2 * (op - OP_post_dec) - 1;
14239
    sp[0] = JS_NewFloat64(ctx, r);
14240
    sp[-1] = JS_NewFloat64(ctx, d);
14241
    return 0;
14242
}
14243
14244
static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
14245
                                                      OPCodeEnum op)
14246
{
14247
    JSValue op1, op2;
14248
    double d1, d2, r;
14249
14250
    op1 = sp[-2];
14251
    op2 = sp[-1];
14252
    if (unlikely(JS_ToFloat64Free(ctx, &d1, op1))) {
14253
        JS_FreeValue(ctx, op2);
14254
        goto exception;
14255
    }
14256
    if (unlikely(JS_ToFloat64Free(ctx, &d2, op2))) {
14257
        goto exception;
14258
    }
14259
    switch(op) {
14260
    case OP_sub:
14261
        r = d1 - d2;
14262
        break;
14263
    case OP_mul:
14264
        r = d1 * d2;
14265
        break;
14266
    case OP_div:
14267
        r = d1 / d2;
14268
        break;
14269
    case OP_mod:
14270
        r = fmod(d1, d2);
14271
        break;
14272
    case OP_pow:
14273
        r = js_pow(d1, d2);
14274
        break;
14275
    default:
14276
        abort();
14277
    }
14278
    sp[-2] = JS_NewFloat64(ctx, r);
14279
    return 0;
14280
 exception:
14281
    sp[-2] = JS_UNDEFINED;
14282
    sp[-1] = JS_UNDEFINED;
14283
    return -1;
14284
}
14285
14286
static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
14287
{
14288
    JSValue op1, op2;
14289
    uint32_t tag1, tag2;
14290
14291
    op1 = sp[-2];
14292
    op2 = sp[-1];
14293
    tag1 = JS_VALUE_GET_TAG(op1);
14294
    tag2 = JS_VALUE_GET_TAG(op2);
14295
    if ((tag1 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag1)) &&
14296
        (tag2 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag2))) {
14297
        goto add_numbers;
14298
    } else {
14299
        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
14300
        if (JS_IsException(op1)) {
14301
            JS_FreeValue(ctx, op2);
14302
            goto exception;
14303
        }
14304
        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
14305
        if (JS_IsException(op2)) {
14306
            JS_FreeValue(ctx, op1);
14307
            goto exception;
14308
        }
14309
        tag1 = JS_VALUE_GET_TAG(op1);
14310
        tag2 = JS_VALUE_GET_TAG(op2);
14311
        if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
14312
            sp[-2] = JS_ConcatString(ctx, op1, op2);
14313
            if (JS_IsException(sp[-2]))
14314
                goto exception;
14315
        } else {
14316
            double d1, d2;
14317
        add_numbers:
14318
            if (JS_ToFloat64Free(ctx, &d1, op1)) {
14319
                JS_FreeValue(ctx, op2);
14320
                goto exception;
14321
            }
14322
            if (JS_ToFloat64Free(ctx, &d2, op2))
14323
                goto exception;
14324
            sp[-2] = JS_NewFloat64(ctx, d1 + d2);
14325
        }
14326
    }
14327
    return 0;
14328
 exception:
14329
    sp[-2] = JS_UNDEFINED;
14330
    sp[-1] = JS_UNDEFINED;
14331
    return -1;
14332
}
14333
14334
static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
14335
                                                      JSValue *sp,
14336
                                                      OPCodeEnum op)
14337
{
14338
    JSValue op1, op2;
14339
    uint32_t v1, v2, r;
14340
14341
    op1 = sp[-2];
14342
    op2 = sp[-1];
14343
    if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
14344
        JS_FreeValue(ctx, op2);
14345
        goto exception;
14346
    }
14347
    if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
14348
        goto exception;
14349
    switch(op) {
14350
    case OP_shl:
14351
        r = v1 << (v2 & 0x1f);
14352
        break;
14353
    case OP_sar:
14354
        r = (int)v1 >> (v2 & 0x1f);
14355
        break;
14356
    case OP_and:
14357
        r = v1 & v2;
14358
        break;
14359
    case OP_or:
14360
        r = v1 | v2;
14361
        break;
14362
    case OP_xor:
14363
        r = v1 ^ v2;
14364
        break;
14365
    default:
14366
        abort();
14367
    }
14368
    sp[-2] = JS_NewInt32(ctx, r);
14369
    return 0;
14370
 exception:
14371
    sp[-2] = JS_UNDEFINED;
14372
    sp[-1] = JS_UNDEFINED;
14373
    return -1;
14374
}
14375
14376
static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
14377
{
14378
    int32_t v1;
14379
14380
    if (unlikely(JS_ToInt32Free(ctx, &v1, sp[-1]))) {
14381
        sp[-1] = JS_UNDEFINED;
14382
        return -1;
14383
    }
14384
    sp[-1] = JS_NewInt32(ctx, ~v1);
14385
    return 0;
14386
}
14387
14388
static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
14389
                                        OPCodeEnum op)
14390
{
14391
    JSValue op1, op2;
14392
    int res;
14393
14394
    op1 = sp[-2];
14395
    op2 = sp[-1];
14396
    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
14397
    if (JS_IsException(op1)) {
14398
        JS_FreeValue(ctx, op2);
14399
        goto exception;
14400
    }
14401
    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
14402
    if (JS_IsException(op2)) {
14403
        JS_FreeValue(ctx, op1);
14404
        goto exception;
14405
    }
14406
    if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING &&
14407
        JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
14408
        JSString *p1, *p2;
14409
        p1 = JS_VALUE_GET_STRING(op1);
14410
        p2 = JS_VALUE_GET_STRING(op2);
14411
        res = js_string_compare(ctx, p1, p2);
14412
        JS_FreeValue(ctx, op1);
14413
        JS_FreeValue(ctx, op2);
14414
        switch(op) {
14415
        case OP_lt:
14416
            res = (res < 0);
14417
            break;
14418
        case OP_lte:
14419
            res = (res <= 0);
14420
            break;
14421
        case OP_gt:
14422
            res = (res > 0);
14423
            break;
14424
        default:
14425
        case OP_gte:
14426
            res = (res >= 0);
14427
            break;
14428
        }
14429
    } else {
14430
        double d1, d2;
14431
        if (JS_ToFloat64Free(ctx, &d1, op1)) {
14432
            JS_FreeValue(ctx, op2);
14433
            goto exception;
14434
        }
14435
        if (JS_ToFloat64Free(ctx, &d2, op2))
14436
            goto exception;
14437
        switch(op) {
14438
        case OP_lt:
14439
            res = (d1 < d2); /* if NaN return false */
14440
            break;
14441
        case OP_lte:
14442
            res = (d1 <= d2); /* if NaN return false */
14443
            break;
14444
        case OP_gt:
14445
            res = (d1 > d2); /* if NaN return false */
14446
            break;
14447
        default:
14448
        case OP_gte:
14449
            res = (d1 >= d2); /* if NaN return false */
14450
            break;
14451
        }
14452
    }
14453
    sp[-2] = JS_NewBool(ctx, res);
14454
    return 0;
14455
 exception:
14456
    sp[-2] = JS_UNDEFINED;
14457
    sp[-1] = JS_UNDEFINED;
14458
    return -1;
14459
}
14460
14461
static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
14462
                                            BOOL is_neq)
14463
{
14464
    JSValue op1, op2;
14465
    int tag1, tag2;
14466
    BOOL res;
14467
14468
    op1 = sp[-2];
14469
    op2 = sp[-1];
14470
 redo:
14471
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14472
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14473
    if (tag1 == tag2 ||
14474
        (tag1 == JS_TAG_INT && tag2 == JS_TAG_FLOAT64) ||
14475
        (tag2 == JS_TAG_INT && tag1 == JS_TAG_FLOAT64)) {
14476
        res = js_strict_eq(ctx, op1, op2);
14477
    } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
14478
               (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
14479
        res = TRUE;
14480
    } else if ((tag1 == JS_TAG_STRING && (tag2 == JS_TAG_INT ||
14481
                                   tag2 == JS_TAG_FLOAT64)) ||
14482
        (tag2 == JS_TAG_STRING && (tag1 == JS_TAG_INT ||
14483
                                   tag1 == JS_TAG_FLOAT64))) {
14484
        double d1;
14485
        double d2;
14486
        if (JS_ToFloat64Free(ctx, &d1, op1)) {
14487
            JS_FreeValue(ctx, op2);
14488
            goto exception;
14489
        }
14490
        if (JS_ToFloat64Free(ctx, &d2, op2))
14491
            goto exception;
14492
        res = (d1 == d2);
14493
    } else if (tag1 == JS_TAG_BOOL) {
14494
        op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
14495
        goto redo;
14496
    } else if (tag2 == JS_TAG_BOOL) {
14497
        op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
14498
        goto redo;
14499
    } else if (tag1 == JS_TAG_OBJECT &&
14500
               (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64 || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) {
14501
        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
14502
        if (JS_IsException(op1)) {
14503
            JS_FreeValue(ctx, op2);
14504
            goto exception;
14505
        }
14506
        goto redo;
14507
    } else if (tag2 == JS_TAG_OBJECT &&
14508
               (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64 || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL)) {
14509
        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
14510
        if (JS_IsException(op2)) {
14511
            JS_FreeValue(ctx, op1);
14512
            goto exception;
14513
        }
14514
        goto redo;
14515
    } else {
14516
        /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
14517
        if ((JS_IsHTMLDDA(ctx, op1) &&
14518
             (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
14519
            (JS_IsHTMLDDA(ctx, op2) &&
14520
             (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
14521
            res = TRUE;
14522
        } else {
14523
            res = FALSE;
14524
        }
14525
        JS_FreeValue(ctx, op1);
14526
        JS_FreeValue(ctx, op2);
14527
    }
14528
    sp[-2] = JS_NewBool(ctx, res ^ is_neq);
14529
    return 0;
14530
 exception:
14531
    sp[-2] = JS_UNDEFINED;
14532
    sp[-1] = JS_UNDEFINED;
14533
    return -1;
14534
}
14535
14536
static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
14537
{
14538
    JSValue op1, op2;
14539
    uint32_t v1, v2, r;
14540
14541
    op1 = sp[-2];
14542
    op2 = sp[-1];
14543
    if (unlikely(JS_ToUint32Free(ctx, &v1, op1))) {
14544
        JS_FreeValue(ctx, op2);
14545
        goto exception;
14546
    }
14547
    if (unlikely(JS_ToUint32Free(ctx, &v2, op2)))
14548
        goto exception;
14549
    r = v1 >> (v2 & 0x1f);
14550
    sp[-2] = JS_NewUint32(ctx, r);
14551
    return 0;
14552
 exception:
14553
    sp[-2] = JS_UNDEFINED;
14554
    sp[-1] = JS_UNDEFINED;
14555
    return -1;
14556
}
14557
14558
#endif /* !CONFIG_BIGNUM */
14559
14560
/* XXX: Should take JSValueConst arguments */
14561
static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
14562
                          JSStrictEqModeEnum eq_mode)
14563
40.9k
{
14564
40.9k
    BOOL res;
14565
40.9k
    int tag1, tag2;
14566
40.9k
    double d1, d2;
14567
14568
40.9k
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14569
40.9k
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14570
40.9k
    switch(tag1) {
14571
0
    case JS_TAG_BOOL:
14572
0
        if (tag1 != tag2) {
14573
0
            res = FALSE;
14574
0
        } else {
14575
0
            res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
14576
0
            goto done_no_free;
14577
0
        }
14578
0
        break;
14579
0
    case JS_TAG_NULL:
14580
0
    case JS_TAG_UNDEFINED:
14581
0
        res = (tag1 == tag2);
14582
0
        break;
14583
0
    case JS_TAG_STRING:
14584
0
        {
14585
0
            JSString *p1, *p2;
14586
0
            if (tag1 != tag2) {
14587
0
                res = FALSE;
14588
0
            } else {
14589
0
                p1 = JS_VALUE_GET_STRING(op1);
14590
0
                p2 = JS_VALUE_GET_STRING(op2);
14591
0
                res = (js_string_compare(ctx, p1, p2) == 0);
14592
0
            }
14593
0
        }
14594
0
        break;
14595
0
    case JS_TAG_SYMBOL:
14596
0
        {
14597
0
            JSAtomStruct *p1, *p2;
14598
0
            if (tag1 != tag2) {
14599
0
                res = FALSE;
14600
0
            } else {
14601
0
                p1 = JS_VALUE_GET_PTR(op1);
14602
0
                p2 = JS_VALUE_GET_PTR(op2);
14603
0
                res = (p1 == p2);
14604
0
            }
14605
0
        }
14606
0
        break;
14607
40.9k
    case JS_TAG_OBJECT:
14608
40.9k
        if (tag1 != tag2)
14609
0
            res = FALSE;
14610
40.9k
        else
14611
40.9k
            res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2);
14612
40.9k
        break;
14613
0
    case JS_TAG_INT:
14614
0
        d1 = JS_VALUE_GET_INT(op1);
14615
0
        if (tag2 == JS_TAG_INT) {
14616
0
            d2 = JS_VALUE_GET_INT(op2);
14617
0
            goto number_test;
14618
0
        } else if (tag2 == JS_TAG_FLOAT64) {
14619
0
            d2 = JS_VALUE_GET_FLOAT64(op2);
14620
0
            goto number_test;
14621
0
        } else {
14622
0
            res = FALSE;
14623
0
        }
14624
0
        break;
14625
0
    case JS_TAG_FLOAT64:
14626
0
        d1 = JS_VALUE_GET_FLOAT64(op1);
14627
0
        if (tag2 == JS_TAG_FLOAT64) {
14628
0
            d2 = JS_VALUE_GET_FLOAT64(op2);
14629
0
        } else if (tag2 == JS_TAG_INT) {
14630
0
            d2 = JS_VALUE_GET_INT(op2);
14631
0
        } else {
14632
0
            res = FALSE;
14633
0
            break;
14634
0
        }
14635
0
    number_test:
14636
0
        if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
14637
0
            JSFloat64Union u1, u2;
14638
            /* NaN is not always normalized, so this test is necessary */
14639
0
            if (isnan(d1) || isnan(d2)) {
14640
0
                res = isnan(d1) == isnan(d2);
14641
0
            } else if (eq_mode == JS_EQ_SAME_VALUE_ZERO) {
14642
0
                res = (d1 == d2); /* +0 == -0 */
14643
0
            } else {
14644
0
                u1.d = d1;
14645
0
                u2.d = d2;
14646
0
                res = (u1.u64 == u2.u64); /* +0 != -0 */
14647
0
            }
14648
0
        } else {
14649
0
            res = (d1 == d2); /* if NaN return false and +0 == -0 */
14650
0
        }
14651
0
        goto done_no_free;
14652
0
#ifdef CONFIG_BIGNUM
14653
0
    case JS_TAG_BIG_INT:
14654
0
        {
14655
0
            bf_t a_s, *a, b_s, *b;
14656
0
            if (tag1 != tag2) {
14657
0
                res = FALSE;
14658
0
                break;
14659
0
            }
14660
0
            a = JS_ToBigFloat(ctx, &a_s, op1);
14661
0
            b = JS_ToBigFloat(ctx, &b_s, op2);
14662
0
            res = bf_cmp_eq(a, b);
14663
0
            if (a == &a_s)
14664
0
                bf_delete(a);
14665
0
            if (b == &b_s)
14666
0
                bf_delete(b);
14667
0
        }
14668
0
        break;
14669
0
    case JS_TAG_BIG_FLOAT:
14670
0
        {
14671
0
            JSBigFloat *p1, *p2;
14672
0
            const bf_t *a, *b;
14673
0
            if (tag1 != tag2) {
14674
0
                res = FALSE;
14675
0
                break;
14676
0
            }
14677
0
            p1 = JS_VALUE_GET_PTR(op1);
14678
0
            p2 = JS_VALUE_GET_PTR(op2);
14679
0
            a = &p1->num;
14680
0
            b = &p2->num;
14681
0
            if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
14682
0
                if (eq_mode == JS_EQ_SAME_VALUE_ZERO &&
14683
0
                           a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO) {
14684
0
                    res = TRUE;
14685
0
                } else {
14686
0
                    res = (bf_cmp_full(a, b) == 0);
14687
0
                }
14688
0
            } else {
14689
0
                res = bf_cmp_eq(a, b);
14690
0
            }
14691
0
        }
14692
0
        break;
14693
0
    case JS_TAG_BIG_DECIMAL:
14694
0
        {
14695
0
            JSBigDecimal *p1, *p2;
14696
0
            const bfdec_t *a, *b;
14697
0
            if (tag1 != tag2) {
14698
0
                res = FALSE;
14699
0
                break;
14700
0
            }
14701
0
            p1 = JS_VALUE_GET_PTR(op1);
14702
0
            p2 = JS_VALUE_GET_PTR(op2);
14703
0
            a = &p1->num;
14704
0
            b = &p2->num;
14705
0
            res = bfdec_cmp_eq(a, b);
14706
0
        }
14707
0
        break;
14708
0
#endif
14709
0
    default:
14710
0
        res = FALSE;
14711
0
        break;
14712
40.9k
    }
14713
40.9k
    JS_FreeValue(ctx, op1);
14714
40.9k
    JS_FreeValue(ctx, op2);
14715
40.9k
 done_no_free:
14716
40.9k
    return res;
14717
40.9k
}
14718
14719
static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2)
14720
0
{
14721
0
    return js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
14722
0
}
14723
14724
static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2)
14725
40.9k
{
14726
40.9k
    return js_strict_eq2(ctx,
14727
40.9k
                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
14728
40.9k
                         JS_EQ_SAME_VALUE);
14729
40.9k
}
14730
14731
static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
14732
0
{
14733
0
    return js_strict_eq2(ctx,
14734
0
                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
14735
0
                         JS_EQ_SAME_VALUE_ZERO);
14736
0
}
14737
14738
static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp,
14739
                                       BOOL is_neq)
14740
0
{
14741
0
    BOOL res;
14742
0
    res = js_strict_eq(ctx, sp[-2], sp[-1]);
14743
0
    sp[-2] = JS_NewBool(ctx, res ^ is_neq);
14744
0
    return 0;
14745
0
}
14746
14747
static __exception int js_operator_in(JSContext *ctx, JSValue *sp)
14748
0
{
14749
0
    JSValue op1, op2;
14750
0
    JSAtom atom;
14751
0
    int ret;
14752
14753
0
    op1 = sp[-2];
14754
0
    op2 = sp[-1];
14755
14756
0
    if (JS_VALUE_GET_TAG(op2) != JS_TAG_OBJECT) {
14757
0
        JS_ThrowTypeError(ctx, "invalid 'in' operand");
14758
0
        return -1;
14759
0
    }
14760
0
    atom = JS_ValueToAtom(ctx, op1);
14761
0
    if (unlikely(atom == JS_ATOM_NULL))
14762
0
        return -1;
14763
0
    ret = JS_HasProperty(ctx, op2, atom);
14764
0
    JS_FreeAtom(ctx, atom);
14765
0
    if (ret < 0)
14766
0
        return -1;
14767
0
    JS_FreeValue(ctx, op1);
14768
0
    JS_FreeValue(ctx, op2);
14769
0
    sp[-2] = JS_NewBool(ctx, ret);
14770
0
    return 0;
14771
0
}
14772
14773
static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj,
14774
                                         JSAtom atom)
14775
0
{
14776
0
    JSValue arr, val;
14777
0
    int ret;
14778
14779
0
    arr = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_unscopables);
14780
0
    if (JS_IsException(arr))
14781
0
        return -1;
14782
0
    ret = 0;
14783
0
    if (JS_IsObject(arr)) {
14784
0
        val = JS_GetProperty(ctx, arr, atom);
14785
0
        ret = JS_ToBoolFree(ctx, val);
14786
0
    }
14787
0
    JS_FreeValue(ctx, arr);
14788
0
    return ret;
14789
0
}
14790
14791
static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp)
14792
0
{
14793
0
    JSValue op1, op2;
14794
0
    BOOL ret;
14795
14796
0
    op1 = sp[-2];
14797
0
    op2 = sp[-1];
14798
0
    ret = JS_IsInstanceOf(ctx, op1, op2);
14799
0
    if (ret < 0)
14800
0
        return ret;
14801
0
    JS_FreeValue(ctx, op1);
14802
0
    JS_FreeValue(ctx, op2);
14803
0
    sp[-2] = JS_NewBool(ctx, ret);
14804
0
    return 0;
14805
0
}
14806
14807
static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1)
14808
0
{
14809
0
    JSAtom atom;
14810
0
    uint32_t tag;
14811
14812
0
    tag = JS_VALUE_GET_NORM_TAG(op1);
14813
0
    switch(tag) {
14814
0
#ifdef CONFIG_BIGNUM
14815
0
    case JS_TAG_BIG_INT:
14816
0
        atom = JS_ATOM_bigint;
14817
0
        break;
14818
0
    case JS_TAG_BIG_FLOAT:
14819
0
        atom = JS_ATOM_bigfloat;
14820
0
        break;
14821
0
    case JS_TAG_BIG_DECIMAL:
14822
0
        atom = JS_ATOM_bigdecimal;
14823
0
        break;
14824
0
#endif
14825
0
    case JS_TAG_INT:
14826
0
    case JS_TAG_FLOAT64:
14827
0
        atom = JS_ATOM_number;
14828
0
        break;
14829
0
    case JS_TAG_UNDEFINED:
14830
0
        atom = JS_ATOM_undefined;
14831
0
        break;
14832
0
    case JS_TAG_BOOL:
14833
0
        atom = JS_ATOM_boolean;
14834
0
        break;
14835
0
    case JS_TAG_STRING:
14836
0
        atom = JS_ATOM_string;
14837
0
        break;
14838
0
    case JS_TAG_OBJECT:
14839
0
        {
14840
0
            JSObject *p;
14841
0
            p = JS_VALUE_GET_OBJ(op1);
14842
0
            if (unlikely(p->is_HTMLDDA)) 
14843
0
                atom = JS_ATOM_undefined;
14844
0
            else if (JS_IsFunction(ctx, op1))
14845
0
                atom = JS_ATOM_function;
14846
0
            else
14847
0
                goto obj_type;
14848
0
        }
14849
0
        break;
14850
0
    case JS_TAG_NULL:
14851
0
    obj_type:
14852
0
        atom = JS_ATOM_object;
14853
0
        break;
14854
0
    case JS_TAG_SYMBOL:
14855
0
        atom = JS_ATOM_symbol;
14856
0
        break;
14857
0
    default:
14858
0
        atom = JS_ATOM_unknown;
14859
0
        break;
14860
0
    }
14861
0
    return atom;
14862
0
}
14863
14864
static __exception int js_operator_delete(JSContext *ctx, JSValue *sp)
14865
0
{
14866
0
    JSValue op1, op2;
14867
0
    JSAtom atom;
14868
0
    int ret;
14869
14870
0
    op1 = sp[-2];
14871
0
    op2 = sp[-1];
14872
0
    atom = JS_ValueToAtom(ctx, op2);
14873
0
    if (unlikely(atom == JS_ATOM_NULL))
14874
0
        return -1;
14875
0
    ret = JS_DeleteProperty(ctx, op1, atom, JS_PROP_THROW_STRICT);
14876
0
    JS_FreeAtom(ctx, atom);
14877
0
    if (unlikely(ret < 0))
14878
0
        return -1;
14879
0
    JS_FreeValue(ctx, op1);
14880
0
    JS_FreeValue(ctx, op2);
14881
0
    sp[-2] = JS_NewBool(ctx, ret);
14882
0
    return 0;
14883
0
}
14884
14885
static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val,
14886
                                   int argc, JSValueConst *argv)
14887
0
{
14888
0
    return JS_ThrowTypeError(ctx, "invalid property access");
14889
0
}
14890
14891
/* XXX: not 100% compatible, but mozilla seems to use a similar
14892
   implementation to ensure that caller in non strict mode does not
14893
   throw (ES5 compatibility) */
14894
static JSValue js_function_proto_caller(JSContext *ctx, JSValueConst this_val,
14895
                                        int argc, JSValueConst *argv)
14896
0
{
14897
0
    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
14898
0
    if (!b || (b->js_mode & JS_MODE_STRICT) || !b->has_prototype) {
14899
0
        return js_throw_type_error(ctx, this_val, 0, NULL);
14900
0
    }
14901
0
    return JS_UNDEFINED;
14902
0
}
14903
14904
static JSValue js_function_proto_fileName(JSContext *ctx,
14905
                                          JSValueConst this_val)
14906
0
{
14907
0
    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
14908
0
    if (b && b->has_debug) {
14909
0
        return JS_AtomToString(ctx, b->debug.filename);
14910
0
    }
14911
0
    return JS_UNDEFINED;
14912
0
}
14913
14914
static JSValue js_function_proto_lineNumber(JSContext *ctx,
14915
                                            JSValueConst this_val)
14916
0
{
14917
0
    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
14918
0
    if (b && b->has_debug) {
14919
0
        return JS_NewInt32(ctx, b->debug.line_num);
14920
0
    }
14921
0
    return JS_UNDEFINED;
14922
0
}
14923
14924
static int js_arguments_define_own_property(JSContext *ctx,
14925
                                            JSValueConst this_obj,
14926
                                            JSAtom prop, JSValueConst val,
14927
                                            JSValueConst getter, JSValueConst setter, int flags)
14928
0
{
14929
0
    JSObject *p;
14930
0
    uint32_t idx;
14931
0
    p = JS_VALUE_GET_OBJ(this_obj);
14932
    /* convert to normal array when redefining an existing numeric field */
14933
0
    if (p->fast_array && JS_AtomIsArrayIndex(ctx, &idx, prop) &&
14934
0
        idx < p->u.array.count) {
14935
0
        if (convert_fast_array_to_array(ctx, p))
14936
0
            return -1;
14937
0
    }
14938
    /* run the default define own property */
14939
0
    return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
14940
0
                             flags | JS_PROP_NO_EXOTIC);
14941
0
}
14942
14943
static const JSClassExoticMethods js_arguments_exotic_methods = {
14944
    .define_own_property = js_arguments_define_own_property,
14945
};
14946
14947
static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv)
14948
0
{
14949
0
    JSValue val, *tab;
14950
0
    JSProperty *pr;
14951
0
    JSObject *p;
14952
0
    int i;
14953
14954
0
    val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
14955
0
                                 JS_CLASS_ARGUMENTS);
14956
0
    if (JS_IsException(val))
14957
0
        return val;
14958
0
    p = JS_VALUE_GET_OBJ(val);
14959
14960
    /* add the length field (cannot fail) */
14961
0
    pr = add_property(ctx, p, JS_ATOM_length,
14962
0
                      JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
14963
0
    pr->u.value = JS_NewInt32(ctx, argc);
14964
14965
    /* initialize the fast array part */
14966
0
    tab = NULL;
14967
0
    if (argc > 0) {
14968
0
        tab = js_malloc(ctx, sizeof(tab[0]) * argc);
14969
0
        if (!tab) {
14970
0
            JS_FreeValue(ctx, val);
14971
0
            return JS_EXCEPTION;
14972
0
        }
14973
0
        for(i = 0; i < argc; i++) {
14974
0
            tab[i] = JS_DupValue(ctx, argv[i]);
14975
0
        }
14976
0
    }
14977
0
    p->u.array.u.values = tab;
14978
0
    p->u.array.count = argc;
14979
14980
0
    JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator,
14981
0
                           JS_DupValue(ctx, ctx->array_proto_values),
14982
0
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
14983
    /* add callee property to throw a TypeError in strict mode */
14984
0
    JS_DefineProperty(ctx, val, JS_ATOM_callee, JS_UNDEFINED,
14985
0
                      ctx->throw_type_error, ctx->throw_type_error,
14986
0
                      JS_PROP_HAS_GET | JS_PROP_HAS_SET);
14987
0
    return val;
14988
0
}
14989
14990
1.76k
#define GLOBAL_VAR_OFFSET 0x40000000
14991
9.85k
#define ARGUMENT_VAR_OFFSET 0x20000000
14992
14993
/* legacy arguments object: add references to the function arguments */
14994
static JSValue js_build_mapped_arguments(JSContext *ctx, int argc,
14995
                                         JSValueConst *argv,
14996
                                         JSStackFrame *sf, int arg_count)
14997
0
{
14998
0
    JSValue val;
14999
0
    JSProperty *pr;
15000
0
    JSObject *p;
15001
0
    int i;
15002
15003
0
    val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
15004
0
                                 JS_CLASS_MAPPED_ARGUMENTS);
15005
0
    if (JS_IsException(val))
15006
0
        return val;
15007
0
    p = JS_VALUE_GET_OBJ(val);
15008
15009
    /* add the length field (cannot fail) */
15010
0
    pr = add_property(ctx, p, JS_ATOM_length,
15011
0
                      JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
15012
0
    pr->u.value = JS_NewInt32(ctx, argc);
15013
15014
0
    for(i = 0; i < arg_count; i++) {
15015
0
        JSVarRef *var_ref;
15016
0
        var_ref = get_var_ref(ctx, sf, i, TRUE);
15017
0
        if (!var_ref)
15018
0
            goto fail;
15019
0
        pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF);
15020
0
        if (!pr) {
15021
0
            free_var_ref(ctx->rt, var_ref);
15022
0
            goto fail;
15023
0
        }
15024
0
        pr->u.var_ref = var_ref;
15025
0
    }
15026
15027
    /* the arguments not mapped to the arguments of the function can
15028
       be normal properties */
15029
0
    for(i = arg_count; i < argc; i++) {
15030
0
        if (JS_DefinePropertyValueUint32(ctx, val, i,
15031
0
                                         JS_DupValue(ctx, argv[i]),
15032
0
                                         JS_PROP_C_W_E) < 0)
15033
0
            goto fail;
15034
0
    }
15035
15036
0
    JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator,
15037
0
                           JS_DupValue(ctx, ctx->array_proto_values),
15038
0
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
15039
    /* callee returns this function in non strict mode */
15040
0
    JS_DefinePropertyValue(ctx, val, JS_ATOM_callee,
15041
0
                           JS_DupValue(ctx, ctx->rt->current_stack_frame->cur_func),
15042
0
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
15043
0
    return val;
15044
0
 fail:
15045
0
    JS_FreeValue(ctx, val);
15046
0
    return JS_EXCEPTION;
15047
0
}
15048
15049
static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *argv)
15050
0
{
15051
0
    JSValue val;
15052
0
    int i, ret;
15053
15054
0
    val = JS_NewArray(ctx);
15055
0
    if (JS_IsException(val))
15056
0
        return val;
15057
0
    for (i = first; i < argc; i++) {
15058
0
        ret = JS_DefinePropertyValueUint32(ctx, val, i - first,
15059
0
                                           JS_DupValue(ctx, argv[i]),
15060
0
                                           JS_PROP_C_W_E);
15061
0
        if (ret < 0) {
15062
0
            JS_FreeValue(ctx, val);
15063
0
            return JS_EXCEPTION;
15064
0
        }
15065
0
    }
15066
0
    return val;
15067
0
}
15068
15069
static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
15070
3
{
15071
3
    JSObject *p;
15072
3
    JSPropertyEnum *tab_atom;
15073
3
    int i;
15074
3
    JSValue enum_obj, obj1;
15075
3
    JSForInIterator *it;
15076
3
    uint32_t tag, tab_atom_count;
15077
15078
3
    tag = JS_VALUE_GET_TAG(obj);
15079
3
    if (tag != JS_TAG_OBJECT && tag != JS_TAG_NULL && tag != JS_TAG_UNDEFINED) {
15080
3
        obj = JS_ToObjectFree(ctx, obj);
15081
3
    }
15082
15083
3
    it = js_malloc(ctx, sizeof(*it));
15084
3
    if (!it) {
15085
0
        JS_FreeValue(ctx, obj);
15086
0
        return JS_EXCEPTION;
15087
0
    }
15088
3
    enum_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_FOR_IN_ITERATOR);
15089
3
    if (JS_IsException(enum_obj)) {
15090
0
        js_free(ctx, it);
15091
0
        JS_FreeValue(ctx, obj);
15092
0
        return JS_EXCEPTION;
15093
0
    }
15094
3
    it->is_array = FALSE;
15095
3
    it->obj = obj;
15096
3
    it->idx = 0;
15097
3
    p = JS_VALUE_GET_OBJ(enum_obj);
15098
3
    p->u.for_in_iterator = it;
15099
15100
3
    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
15101
0
        return enum_obj;
15102
15103
    /* fast path: assume no enumerable properties in the prototype chain */
15104
3
    obj1 = JS_DupValue(ctx, obj);
15105
9
    for(;;) {
15106
9
        obj1 = JS_GetPrototypeFree(ctx, obj1);
15107
9
        if (JS_IsNull(obj1))
15108
3
            break;
15109
6
        if (JS_IsException(obj1))
15110
0
            goto fail;
15111
6
        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
15112
6
                                           JS_VALUE_GET_OBJ(obj1),
15113
6
                                           JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
15114
0
            JS_FreeValue(ctx, obj1);
15115
0
            goto fail;
15116
0
        }
15117
6
        js_free_prop_enum(ctx, tab_atom, tab_atom_count);
15118
6
        if (tab_atom_count != 0) {
15119
0
            JS_FreeValue(ctx, obj1);
15120
0
            goto slow_path;
15121
0
        }
15122
        /* must check for timeout to avoid infinite loop */
15123
6
        if (js_poll_interrupts(ctx)) {
15124
0
            JS_FreeValue(ctx, obj1);
15125
0
            goto fail;
15126
0
        }
15127
6
    }
15128
15129
3
    p = JS_VALUE_GET_OBJ(obj);
15130
15131
3
    if (p->fast_array) {
15132
0
        JSShape *sh;
15133
0
        JSShapeProperty *prs;
15134
        /* check that there are no enumerable normal fields */
15135
0
        sh = p->shape;
15136
0
        for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
15137
0
            if (prs->flags & JS_PROP_ENUMERABLE)
15138
0
                goto normal_case;
15139
0
        }
15140
        /* for fast arrays, we only store the number of elements */
15141
0
        it->is_array = TRUE;
15142
0
        it->array_length = p->u.array.count;
15143
3
    } else {
15144
3
    normal_case:
15145
3
        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
15146
3
                                   JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY))
15147
0
            goto fail;
15148
165
        for(i = 0; i < tab_atom_count; i++) {
15149
162
            JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0);
15150
162
        }
15151
3
        js_free_prop_enum(ctx, tab_atom, tab_atom_count);
15152
3
    }
15153
3
    return enum_obj;
15154
15155
0
 slow_path:
15156
    /* non enumerable properties hide the enumerables ones in the
15157
       prototype chain */
15158
0
    obj1 = JS_DupValue(ctx, obj);
15159
0
    for(;;) {
15160
0
        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
15161
0
                                           JS_VALUE_GET_OBJ(obj1),
15162
0
                                           JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
15163
0
            JS_FreeValue(ctx, obj1);
15164
0
            goto fail;
15165
0
        }
15166
0
        for(i = 0; i < tab_atom_count; i++) {
15167
0
            JS_DefinePropertyValue(ctx, enum_obj, tab_atom[i].atom, JS_NULL,
15168
0
                                   (tab_atom[i].is_enumerable ?
15169
0
                                    JS_PROP_ENUMERABLE : 0));
15170
0
        }
15171
0
        js_free_prop_enum(ctx, tab_atom, tab_atom_count);
15172
0
        obj1 = JS_GetPrototypeFree(ctx, obj1);
15173
0
        if (JS_IsNull(obj1))
15174
0
            break;
15175
0
        if (JS_IsException(obj1))
15176
0
            goto fail;
15177
        /* must check for timeout to avoid infinite loop */
15178
0
        if (js_poll_interrupts(ctx)) {
15179
0
            JS_FreeValue(ctx, obj1);
15180
0
            goto fail;
15181
0
        }
15182
0
    }
15183
0
    return enum_obj;
15184
15185
0
 fail:
15186
0
    JS_FreeValue(ctx, enum_obj);
15187
0
    return JS_EXCEPTION;
15188
0
}
15189
15190
/* obj -> enum_obj */
15191
static __exception int js_for_in_start(JSContext *ctx, JSValue *sp)
15192
3
{
15193
3
    sp[-1] = build_for_in_iterator(ctx, sp[-1]);
15194
3
    if (JS_IsException(sp[-1]))
15195
0
        return -1;
15196
3
    return 0;
15197
3
}
15198
15199
/* enum_obj -> enum_obj value done */
15200
static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
15201
31
{
15202
31
    JSValueConst enum_obj;
15203
31
    JSObject *p;
15204
31
    JSAtom prop;
15205
31
    JSForInIterator *it;
15206
31
    int ret;
15207
15208
31
    enum_obj = sp[-1];
15209
    /* fail safe */
15210
31
    if (JS_VALUE_GET_TAG(enum_obj) != JS_TAG_OBJECT)
15211
0
        goto done;
15212
31
    p = JS_VALUE_GET_OBJ(enum_obj);
15213
31
    if (p->class_id != JS_CLASS_FOR_IN_ITERATOR)
15214
0
        goto done;
15215
31
    it = p->u.for_in_iterator;
15216
15217
31
    for(;;) {
15218
31
        if (it->is_array) {
15219
0
            if (it->idx >= it->array_length)
15220
0
                goto done;
15221
0
            prop = __JS_AtomFromUInt32(it->idx);
15222
0
            it->idx++;
15223
31
        } else {
15224
31
            JSShape *sh = p->shape;
15225
31
            JSShapeProperty *prs;
15226
31
            if (it->idx >= sh->prop_count)
15227
1
                goto done;
15228
30
            prs = get_shape_prop(sh) + it->idx;
15229
30
            prop = prs->atom;
15230
30
            it->idx++;
15231
30
            if (prop == JS_ATOM_NULL || !(prs->flags & JS_PROP_ENUMERABLE))
15232
0
                continue;
15233
30
        }
15234
        /* check if the property was deleted */
15235
30
        ret = JS_HasProperty(ctx, it->obj, prop);
15236
30
        if (ret < 0)
15237
0
            return ret;
15238
30
        if (ret)
15239
30
            break;
15240
30
    }
15241
    /* return the property */
15242
30
    sp[0] = JS_AtomToValue(ctx, prop);
15243
30
    sp[1] = JS_FALSE;
15244
30
    return 0;
15245
1
 done:
15246
    /* return the end */
15247
1
    sp[0] = JS_UNDEFINED;
15248
1
    sp[1] = JS_TRUE;
15249
1
    return 0;
15250
31
}
15251
15252
static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj,
15253
                               JSValueConst method)
15254
3
{
15255
3
    JSValue enum_obj;
15256
15257
3
    enum_obj = JS_Call(ctx, method, obj, 0, NULL);
15258
3
    if (JS_IsException(enum_obj))
15259
0
        return enum_obj;
15260
3
    if (!JS_IsObject(enum_obj)) {
15261
0
        JS_FreeValue(ctx, enum_obj);
15262
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
15263
0
    }
15264
3
    return enum_obj;
15265
3
}
15266
15267
static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, BOOL is_async)
15268
3
{
15269
3
    JSValue method, ret, sync_iter;
15270
15271
3
    if (is_async) {
15272
0
        method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_asyncIterator);
15273
0
        if (JS_IsException(method))
15274
0
            return method;
15275
0
        if (JS_IsUndefined(method) || JS_IsNull(method)) {
15276
0
            method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
15277
0
            if (JS_IsException(method))
15278
0
                return method;
15279
0
            sync_iter = JS_GetIterator2(ctx, obj, method);
15280
0
            JS_FreeValue(ctx, method);
15281
0
            if (JS_IsException(sync_iter))
15282
0
                return sync_iter;
15283
0
            ret = JS_CreateAsyncFromSyncIterator(ctx, sync_iter);
15284
0
            JS_FreeValue(ctx, sync_iter);
15285
0
            return ret;
15286
0
        }
15287
3
    } else {
15288
3
        method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
15289
3
        if (JS_IsException(method))
15290
0
            return method;
15291
3
    }
15292
3
    if (!JS_IsFunction(ctx, method)) {
15293
0
        JS_FreeValue(ctx, method);
15294
0
        return JS_ThrowTypeError(ctx, "value is not iterable");
15295
0
    }
15296
3
    ret = JS_GetIterator2(ctx, obj, method);
15297
3
    JS_FreeValue(ctx, method);
15298
3
    return ret;
15299
3
}
15300
15301
/* return *pdone = 2 if the iterator object is not parsed */
15302
static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj,
15303
                                JSValueConst method,
15304
                                int argc, JSValueConst *argv, int *pdone)
15305
53.0k
{
15306
53.0k
    JSValue obj;
15307
15308
    /* fast path for the built-in iterators (avoid creating the
15309
       intermediate result object) */
15310
53.0k
    if (JS_IsObject(method)) {
15311
53.0k
        JSObject *p = JS_VALUE_GET_OBJ(method);
15312
53.0k
        if (p->class_id == JS_CLASS_C_FUNCTION &&
15313
53.0k
            p->u.cfunc.cproto == JS_CFUNC_iterator_next) {
15314
53.0k
            JSCFunctionType func;
15315
53.0k
            JSValueConst args[1];
15316
15317
            /* in case the function expects one argument */
15318
53.0k
            if (argc == 0) {
15319
53.0k
                args[0] = JS_UNDEFINED;
15320
53.0k
                argv = args;
15321
53.0k
            }
15322
53.0k
            func = p->u.cfunc.c_function;
15323
53.0k
            return func.iterator_next(ctx, enum_obj, argc, argv,
15324
53.0k
                                      pdone, p->u.cfunc.magic);
15325
53.0k
        }
15326
53.0k
    }
15327
0
    obj = JS_Call(ctx, method, enum_obj, argc, argv);
15328
0
    if (JS_IsException(obj))
15329
0
        goto fail;
15330
0
    if (!JS_IsObject(obj)) {
15331
0
        JS_FreeValue(ctx, obj);
15332
0
        JS_ThrowTypeError(ctx, "iterator must return an object");
15333
0
        goto fail;
15334
0
    }
15335
0
    *pdone = 2;
15336
0
    return obj;
15337
0
 fail:
15338
0
    *pdone = FALSE;
15339
0
    return JS_EXCEPTION;
15340
0
}
15341
15342
static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj,
15343
                               JSValueConst method,
15344
                               int argc, JSValueConst *argv, BOOL *pdone)
15345
53.0k
{
15346
53.0k
    JSValue obj, value, done_val;
15347
53.0k
    int done;
15348
15349
53.0k
    obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done);
15350
53.0k
    if (JS_IsException(obj))
15351
0
        goto fail;
15352
53.0k
    if (done != 2) {
15353
53.0k
        *pdone = done;
15354
53.0k
        return obj;
15355
53.0k
    } else {
15356
0
        done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
15357
0
        if (JS_IsException(done_val))
15358
0
            goto fail;
15359
0
        *pdone = JS_ToBoolFree(ctx, done_val);
15360
0
        value = JS_UNDEFINED;
15361
0
        if (!*pdone) {
15362
0
            value = JS_GetProperty(ctx, obj, JS_ATOM_value);
15363
0
        }
15364
0
        JS_FreeValue(ctx, obj);
15365
0
        return value;
15366
0
    }
15367
0
 fail:
15368
0
    JS_FreeValue(ctx, obj);
15369
0
    *pdone = FALSE;
15370
0
    return JS_EXCEPTION;
15371
53.0k
}
15372
15373
/* return < 0 in case of exception */
15374
static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
15375
                            BOOL is_exception_pending)
15376
1
{
15377
1
    JSValue method, ret, ex_obj;
15378
1
    int res;
15379
15380
1
    if (is_exception_pending) {
15381
1
        ex_obj = ctx->rt->current_exception;
15382
1
        ctx->rt->current_exception = JS_NULL;
15383
1
        res = -1;
15384
1
    } else {
15385
0
        ex_obj = JS_UNDEFINED;
15386
0
        res = 0;
15387
0
    }
15388
1
    method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return);
15389
1
    if (JS_IsException(method)) {
15390
0
        res = -1;
15391
0
        goto done;
15392
0
    }
15393
1
    if (JS_IsUndefined(method) || JS_IsNull(method)) {
15394
1
        goto done;
15395
1
    }
15396
0
    ret = JS_CallFree(ctx, method, enum_obj, 0, NULL);
15397
0
    if (!is_exception_pending) {
15398
0
        if (JS_IsException(ret)) {
15399
0
            res = -1;
15400
0
        } else if (!JS_IsObject(ret)) {
15401
0
            JS_ThrowTypeErrorNotAnObject(ctx);
15402
0
            res = -1;
15403
0
        }
15404
0
    }
15405
0
    JS_FreeValue(ctx, ret);
15406
1
 done:
15407
1
    if (is_exception_pending) {
15408
1
        JS_Throw(ctx, ex_obj);
15409
1
    }
15410
1
    return res;
15411
0
}
15412
15413
/* obj -> enum_rec (3 slots) */
15414
static __exception int js_for_of_start(JSContext *ctx, JSValue *sp,
15415
                                       BOOL is_async)
15416
2
{
15417
2
    JSValue op1, obj, method;
15418
2
    op1 = sp[-1];
15419
2
    obj = JS_GetIterator(ctx, op1, is_async);
15420
2
    if (JS_IsException(obj))
15421
0
        return -1;
15422
2
    JS_FreeValue(ctx, op1);
15423
2
    sp[-1] = obj;
15424
2
    method = JS_GetProperty(ctx, obj, JS_ATOM_next);
15425
2
    if (JS_IsException(method))
15426
0
        return -1;
15427
2
    sp[0] = method;
15428
2
    return 0;
15429
2
}
15430
15431
/* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset'
15432
   objs. If 'done' is true or in case of exception, 'enum_rec' is set
15433
   to undefined. If 'done' is true, 'value' is always set to
15434
   undefined. */
15435
static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
15436
360
{
15437
360
    JSValue value = JS_UNDEFINED;
15438
360
    int done = 1;
15439
15440
360
    if (likely(!JS_IsUndefined(sp[offset]))) {
15441
360
        value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done);
15442
360
        if (JS_IsException(value))
15443
0
            done = -1;
15444
360
        if (done) {
15445
            /* value is JS_UNDEFINED or JS_EXCEPTION */
15446
            /* replace the iteration object with undefined */
15447
1
            JS_FreeValue(ctx, sp[offset]);
15448
1
            sp[offset] = JS_UNDEFINED;
15449
1
            if (done < 0) {
15450
0
                return -1;
15451
1
            } else {
15452
1
                JS_FreeValue(ctx, value);
15453
1
                value = JS_UNDEFINED;
15454
1
            }
15455
1
        }
15456
360
    }
15457
360
    sp[0] = value;
15458
360
    sp[1] = JS_NewBool(ctx, done);
15459
360
    return 0;
15460
360
}
15461
15462
static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj,
15463
                                           BOOL *pdone)
15464
0
{
15465
0
    JSValue done_val, value;
15466
0
    BOOL done;
15467
0
    done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
15468
0
    if (JS_IsException(done_val))
15469
0
        goto fail;
15470
0
    done = JS_ToBoolFree(ctx, done_val);
15471
0
    value = JS_GetProperty(ctx, obj, JS_ATOM_value);
15472
0
    if (JS_IsException(value))
15473
0
        goto fail;
15474
0
    *pdone = done;
15475
0
    return value;
15476
0
 fail:
15477
0
    *pdone = FALSE;
15478
0
    return JS_EXCEPTION;
15479
0
}
15480
15481
static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)
15482
0
{
15483
0
    JSValue obj, value;
15484
0
    BOOL done;
15485
0
    obj = sp[-1];
15486
0
    if (!JS_IsObject(obj)) {
15487
0
        JS_ThrowTypeError(ctx, "iterator must return an object");
15488
0
        return -1;
15489
0
    }
15490
0
    value = JS_IteratorGetCompleteValue(ctx, obj, &done);
15491
0
    if (JS_IsException(value))
15492
0
        return -1;
15493
0
    JS_FreeValue(ctx, obj);
15494
0
    sp[-1] = value;
15495
0
    sp[0] = JS_NewBool(ctx, done);
15496
0
    return 0;
15497
0
}
15498
15499
static JSValue js_create_iterator_result(JSContext *ctx,
15500
                                         JSValue val,
15501
                                         BOOL done)
15502
0
{
15503
0
    JSValue obj;
15504
0
    obj = JS_NewObject(ctx);
15505
0
    if (JS_IsException(obj)) {
15506
0
        JS_FreeValue(ctx, val);
15507
0
        return obj;
15508
0
    }
15509
0
    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_value,
15510
0
                               val, JS_PROP_C_W_E) < 0) {
15511
0
        goto fail;
15512
0
    }
15513
0
    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done,
15514
0
                               JS_NewBool(ctx, done), JS_PROP_C_W_E) < 0) {
15515
0
    fail:
15516
0
        JS_FreeValue(ctx, obj);
15517
0
        return JS_EXCEPTION;
15518
0
    }
15519
0
    return obj;
15520
0
}
15521
15522
static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
15523
                                      int argc, JSValueConst *argv,
15524
                                      BOOL *pdone, int magic);
15525
15526
static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
15527
                                        int argc, JSValueConst *argv, int magic);
15528
15529
static BOOL js_is_fast_array(JSContext *ctx, JSValueConst obj)
15530
0
{
15531
    /* Try and handle fast arrays explicitly */
15532
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
15533
0
        JSObject *p = JS_VALUE_GET_OBJ(obj);
15534
0
        if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
15535
0
            return TRUE;
15536
0
        }
15537
0
    }
15538
0
    return FALSE;
15539
0
}
15540
15541
/* Access an Array's internal JSValue array if available */
15542
static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
15543
                              JSValue **arrpp, uint32_t *countp)
15544
0
{
15545
    /* Try and handle fast arrays explicitly */
15546
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
15547
0
        JSObject *p = JS_VALUE_GET_OBJ(obj);
15548
0
        if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
15549
0
            *countp = p->u.array.count;
15550
0
            *arrpp = p->u.array.u.values;
15551
0
            return TRUE;
15552
0
        }
15553
0
    }
15554
0
    return FALSE;
15555
0
}
15556
15557
static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp)
15558
1
{
15559
1
    JSValue iterator, enumobj, method, value;
15560
1
    int is_array_iterator;
15561
1
    JSValue *arrp;
15562
1
    uint32_t i, count32, pos;
15563
    
15564
1
    if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) {
15565
0
        JS_ThrowInternalError(ctx, "invalid index for append");
15566
0
        return -1;
15567
0
    }
15568
15569
1
    pos = JS_VALUE_GET_INT(sp[-2]);
15570
15571
    /* XXX: further optimisations:
15572
       - use ctx->array_proto_values?
15573
       - check if array_iterator_prototype next method is built-in and
15574
         avoid constructing actual iterator object?
15575
       - build this into js_for_of_start and use in all `for (x of o)` loops
15576
     */
15577
1
    iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator);
15578
1
    if (JS_IsException(iterator))
15579
0
        return -1;
15580
1
    is_array_iterator = JS_IsCFunction(ctx, iterator,
15581
1
                                       (JSCFunction *)js_create_array_iterator,
15582
1
                                       JS_ITERATOR_KIND_VALUE);
15583
1
    JS_FreeValue(ctx, iterator);
15584
15585
1
    enumobj = JS_GetIterator(ctx, sp[-1], FALSE);
15586
1
    if (JS_IsException(enumobj))
15587
0
        return -1;
15588
1
    method = JS_GetProperty(ctx, enumobj, JS_ATOM_next);
15589
1
    if (JS_IsException(method)) {
15590
0
        JS_FreeValue(ctx, enumobj);
15591
0
        return -1;
15592
0
    }
15593
1
    if (is_array_iterator
15594
1
    &&  JS_IsCFunction(ctx, method, (JSCFunction *)js_array_iterator_next, 0)
15595
1
    &&  js_get_fast_array(ctx, sp[-1], &arrp, &count32)) {
15596
0
        uint32_t len;
15597
0
        if (js_get_length32(ctx, &len, sp[-1]))
15598
0
            goto exception;
15599
        /* if len > count32, the elements >= count32 might be read in
15600
           the prototypes and might have side effects */
15601
0
        if (len != count32)
15602
0
            goto general_case;
15603
        /* Handle fast arrays explicitly */
15604
0
        for (i = 0; i < count32; i++) {
15605
0
            if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++,
15606
0
                                             JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0)
15607
0
                goto exception;
15608
0
        }
15609
1
    } else {
15610
1
    general_case:
15611
52.7k
        for (;;) {
15612
52.7k
            BOOL done;
15613
52.7k
            value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done);
15614
52.7k
            if (JS_IsException(value))
15615
0
                goto exception;
15616
52.7k
            if (done) {
15617
                /* value is JS_UNDEFINED */
15618
1
                break;
15619
1
            }
15620
52.7k
            if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0)
15621
0
                goto exception;
15622
52.7k
        }
15623
1
    }
15624
    /* Note: could raise an error if too many elements */
15625
1
    sp[-2] = JS_NewInt32(ctx, pos);
15626
1
    JS_FreeValue(ctx, enumobj);
15627
1
    JS_FreeValue(ctx, method);
15628
1
    return 0;
15629
15630
0
exception:
15631
0
    JS_IteratorClose(ctx, enumobj, TRUE);
15632
0
    JS_FreeValue(ctx, enumobj);
15633
0
    JS_FreeValue(ctx, method);
15634
0
    return -1;
15635
1
}
15636
15637
static __exception int JS_CopyDataProperties(JSContext *ctx,
15638
                                             JSValueConst target,
15639
                                             JSValueConst source,
15640
                                             JSValueConst excluded,
15641
                                             BOOL setprop)
15642
24
{
15643
24
    JSPropertyEnum *tab_atom;
15644
24
    JSValue val;
15645
24
    uint32_t i, tab_atom_count;
15646
24
    JSObject *p;
15647
24
    JSObject *pexcl = NULL;
15648
24
    int ret, gpn_flags;
15649
24
    JSPropertyDescriptor desc;
15650
24
    BOOL is_enumerable;
15651
    
15652
24
    if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT)
15653
0
        return 0;
15654
15655
24
    if (JS_VALUE_GET_TAG(excluded) == JS_TAG_OBJECT)
15656
19
        pexcl = JS_VALUE_GET_OBJ(excluded);
15657
15658
24
    p = JS_VALUE_GET_OBJ(source);
15659
15660
24
    gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY;
15661
24
    if (p->is_exotic) {
15662
5
        const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
15663
        /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it
15664
           introduces a visible change */
15665
5
        if (em && em->get_own_property_names) {
15666
0
            gpn_flags &= ~JS_GPN_ENUM_ONLY;
15667
0
        }
15668
5
    }
15669
24
    if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
15670
24
                                       gpn_flags))
15671
0
        return -1;
15672
    
15673
1.60M
    for (i = 0; i < tab_atom_count; i++) {
15674
1.60M
        if (pexcl) {
15675
1.25M
            ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom);
15676
1.25M
            if (ret) {
15677
0
                if (ret < 0)
15678
0
                    goto exception;
15679
0
                continue;
15680
0
            }
15681
1.25M
        }
15682
1.60M
        if (!(gpn_flags & JS_GPN_ENUM_ONLY)) {
15683
            /* test if the property is enumerable */
15684
0
            ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom);
15685
0
            if (ret < 0)
15686
0
                goto exception;
15687
0
            if (!ret)
15688
0
                continue;
15689
0
            is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0;
15690
0
            js_free_desc(ctx, &desc);
15691
0
            if (!is_enumerable)
15692
0
                continue;
15693
0
        }
15694
1.60M
        val = JS_GetProperty(ctx, source, tab_atom[i].atom);
15695
1.60M
        if (JS_IsException(val))
15696
0
            goto exception;
15697
1.60M
        if (setprop)
15698
0
            ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val);
15699
1.60M
        else
15700
1.60M
            ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val,
15701
1.60M
                                         JS_PROP_C_W_E);
15702
1.60M
        if (ret < 0)
15703
0
            goto exception;
15704
1.60M
    }
15705
24
    js_free_prop_enum(ctx, tab_atom, tab_atom_count);
15706
24
    return 0;
15707
0
 exception:
15708
0
    js_free_prop_enum(ctx, tab_atom, tab_atom_count);
15709
0
    return -1;
15710
24
}
15711
15712
/* only valid inside C functions */
15713
static JSValueConst JS_GetActiveFunction(JSContext *ctx)
15714
0
{
15715
0
    return ctx->rt->current_stack_frame->cur_func;
15716
0
}
15717
15718
static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
15719
                             int var_idx, BOOL is_arg)
15720
394k
{
15721
394k
    JSVarRef *var_ref;
15722
394k
    struct list_head *el;
15723
15724
1.77M
    list_for_each(el, &sf->var_ref_list) {
15725
1.77M
        var_ref = list_entry(el, JSVarRef, header.link);
15726
1.77M
        if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) {
15727
204k
            var_ref->header.ref_count++;
15728
204k
            return var_ref;
15729
204k
        }
15730
1.77M
    }
15731
    /* create a new one */
15732
189k
    var_ref = js_malloc(ctx, sizeof(JSVarRef));
15733
189k
    if (!var_ref)
15734
1
        return NULL;
15735
189k
    var_ref->header.ref_count = 1;
15736
189k
    var_ref->is_detached = FALSE;
15737
189k
    var_ref->is_arg = is_arg;
15738
189k
    var_ref->var_idx = var_idx;
15739
189k
    list_add_tail(&var_ref->header.link, &sf->var_ref_list);
15740
189k
    if (is_arg)
15741
40.9k
        var_ref->pvalue = &sf->arg_buf[var_idx];
15742
148k
    else
15743
148k
        var_ref->pvalue = &sf->var_buf[var_idx];
15744
189k
    var_ref->value = JS_UNDEFINED;
15745
189k
    return var_ref;
15746
189k
}
15747
15748
static JSValue js_closure2(JSContext *ctx, JSValue func_obj,
15749
                           JSFunctionBytecode *b,
15750
                           JSVarRef **cur_var_refs,
15751
                           JSStackFrame *sf)
15752
499k
{
15753
499k
    JSObject *p;
15754
499k
    JSVarRef **var_refs;
15755
499k
    int i;
15756
15757
499k
    p = JS_VALUE_GET_OBJ(func_obj);
15758
499k
    p->u.func.function_bytecode = b;
15759
499k
    p->u.func.home_object = NULL;
15760
499k
    p->u.func.var_refs = NULL;
15761
499k
    if (b->closure_var_count) {
15762
205k
        var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
15763
205k
        if (!var_refs)
15764
1
            goto fail;
15765
205k
        p->u.func.var_refs = var_refs;
15766
8.99M
        for(i = 0; i < b->closure_var_count; i++) {
15767
8.79M
            JSClosureVar *cv = &b->closure_var[i];
15768
8.79M
            JSVarRef *var_ref;
15769
8.79M
            if (cv->is_local) {
15770
                /* reuse the existing variable reference if it already exists */
15771
394k
                var_ref = get_var_ref(ctx, sf, cv->var_idx, cv->is_arg);
15772
394k
                if (!var_ref)
15773
1
                    goto fail;
15774
8.39M
            } else {
15775
8.39M
                var_ref = cur_var_refs[cv->var_idx];
15776
8.39M
                var_ref->header.ref_count++;
15777
8.39M
            }
15778
8.79M
            var_refs[i] = var_ref;
15779
8.79M
        }
15780
205k
    }
15781
499k
    return func_obj;
15782
2
 fail:
15783
    /* bfunc is freed when func_obj is freed */
15784
2
    JS_FreeValue(ctx, func_obj);
15785
2
    return JS_EXCEPTION;
15786
499k
}
15787
15788
static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque)
15789
0
{
15790
0
    JSValue obj, this_val;
15791
0
    int ret;
15792
15793
0
    this_val = JS_MKPTR(JS_TAG_OBJECT, p);
15794
0
    obj = JS_NewObject(ctx);
15795
0
    if (JS_IsException(obj))
15796
0
        return JS_EXCEPTION;
15797
0
    set_cycle_flag(ctx, obj);
15798
0
    set_cycle_flag(ctx, this_val);
15799
0
    ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor,
15800
0
                                 JS_DupValue(ctx, this_val),
15801
0
                                 JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
15802
0
    if (ret < 0) {
15803
0
        JS_FreeValue(ctx, obj);
15804
0
        return JS_EXCEPTION;
15805
0
    }
15806
0
    return obj;
15807
0
}
15808
15809
static const uint16_t func_kind_to_class_id[] = {
15810
    [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION,
15811
    [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION,
15812
    [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION,
15813
    [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION,
15814
};
15815
15816
static JSValue js_closure(JSContext *ctx, JSValue bfunc,
15817
                          JSVarRef **cur_var_refs,
15818
                          JSStackFrame *sf)
15819
457k
{
15820
457k
    JSFunctionBytecode *b;
15821
457k
    JSValue func_obj;
15822
457k
    JSAtom name_atom;
15823
15824
457k
    b = JS_VALUE_GET_PTR(bfunc);
15825
457k
    func_obj = JS_NewObjectClass(ctx, func_kind_to_class_id[b->func_kind]);
15826
457k
    if (JS_IsException(func_obj)) {
15827
0
        JS_FreeValue(ctx, bfunc);
15828
0
        return JS_EXCEPTION;
15829
0
    }
15830
457k
    func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf);
15831
457k
    if (JS_IsException(func_obj)) {
15832
        /* bfunc has been freed */
15833
2
        goto fail;
15834
2
    }
15835
457k
    name_atom = b->func_name;
15836
457k
    if (name_atom == JS_ATOM_NULL)
15837
375k
        name_atom = JS_ATOM_empty_string;
15838
457k
    js_function_set_properties(ctx, func_obj, name_atom,
15839
457k
                               b->defined_arg_count);
15840
15841
457k
    if (b->func_kind & JS_FUNC_GENERATOR) {
15842
41.0k
        JSValue proto;
15843
41.0k
        int proto_class_id;
15844
        /* generators have a prototype field which is used as
15845
           prototype for the generator object */
15846
41.0k
        if (b->func_kind == JS_FUNC_ASYNC_GENERATOR)
15847
0
            proto_class_id = JS_CLASS_ASYNC_GENERATOR;
15848
41.0k
        else
15849
41.0k
            proto_class_id = JS_CLASS_GENERATOR;
15850
41.0k
        proto = JS_NewObjectProto(ctx, ctx->class_proto[proto_class_id]);
15851
41.0k
        if (JS_IsException(proto))
15852
0
            goto fail;
15853
41.0k
        JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, proto,
15854
41.0k
                               JS_PROP_WRITABLE);
15855
416k
    } else if (b->has_prototype) {
15856
        /* add the 'prototype' property: delay instantiation to avoid
15857
           creating cycles for every javascript function. The prototype
15858
           object is created on the fly when first accessed */
15859
782
        JS_SetConstructorBit(ctx, func_obj, TRUE);
15860
782
        JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype,
15861
782
                                  JS_AUTOINIT_ID_PROTOTYPE, NULL,
15862
782
                                  JS_PROP_WRITABLE);
15863
782
    }
15864
457k
    return func_obj;
15865
2
 fail:
15866
    /* bfunc is freed when func_obj is freed */
15867
2
    JS_FreeValue(ctx, func_obj);
15868
2
    return JS_EXCEPTION;
15869
457k
}
15870
15871
41.4k
#define JS_DEFINE_CLASS_HAS_HERITAGE     (1 << 0)
15872
15873
static int js_op_define_class(JSContext *ctx, JSValue *sp,
15874
                              JSAtom class_name, int class_flags,
15875
                              JSVarRef **cur_var_refs,
15876
                              JSStackFrame *sf, BOOL is_computed_name)
15877
41.3k
{
15878
41.3k
    JSValue bfunc, parent_class, proto = JS_UNDEFINED;
15879
41.3k
    JSValue ctor = JS_UNDEFINED, parent_proto = JS_UNDEFINED;
15880
41.3k
    JSFunctionBytecode *b;
15881
15882
41.3k
    parent_class = sp[-2];
15883
41.3k
    bfunc = sp[-1];
15884
15885
41.3k
    if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) {
15886
0
        if (JS_IsNull(parent_class)) {
15887
0
            parent_proto = JS_NULL;
15888
0
            parent_class = JS_DupValue(ctx, ctx->function_proto);
15889
0
        } else {
15890
0
            if (!JS_IsConstructor(ctx, parent_class)) {
15891
0
                JS_ThrowTypeError(ctx, "parent class must be constructor");
15892
0
                goto fail;
15893
0
            }
15894
0
            parent_proto = JS_GetProperty(ctx, parent_class, JS_ATOM_prototype);
15895
0
            if (JS_IsException(parent_proto))
15896
0
                goto fail;
15897
0
            if (!JS_IsNull(parent_proto) && !JS_IsObject(parent_proto)) {
15898
0
                JS_ThrowTypeError(ctx, "parent prototype must be an object or null");
15899
0
                goto fail;
15900
0
            }
15901
0
        }
15902
41.3k
    } else {
15903
        /* parent_class is JS_UNDEFINED in this case */
15904
41.3k
        parent_proto = JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]);
15905
41.3k
        parent_class = JS_DupValue(ctx, ctx->function_proto);
15906
41.3k
    }
15907
41.3k
    proto = JS_NewObjectProto(ctx, parent_proto);
15908
41.3k
    if (JS_IsException(proto))
15909
0
        goto fail;
15910
15911
41.3k
    b = JS_VALUE_GET_PTR(bfunc);
15912
41.3k
    assert(b->func_kind == JS_FUNC_NORMAL);
15913
41.3k
    ctor = JS_NewObjectProtoClass(ctx, parent_class,
15914
41.3k
                                  JS_CLASS_BYTECODE_FUNCTION);
15915
41.3k
    if (JS_IsException(ctor))
15916
0
        goto fail;
15917
41.3k
    ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf);
15918
41.3k
    bfunc = JS_UNDEFINED;
15919
41.3k
    if (JS_IsException(ctor))
15920
0
        goto fail;
15921
41.3k
    js_method_set_home_object(ctx, ctor, proto);
15922
41.3k
    JS_SetConstructorBit(ctx, ctor, TRUE);
15923
15924
41.3k
    JS_DefinePropertyValue(ctx, ctor, JS_ATOM_length,
15925
41.3k
                           JS_NewInt32(ctx, b->defined_arg_count),
15926
41.3k
                           JS_PROP_CONFIGURABLE);
15927
15928
41.3k
    if (is_computed_name) {
15929
0
        if (JS_DefineObjectNameComputed(ctx, ctor, sp[-3],
15930
0
                                        JS_PROP_CONFIGURABLE) < 0)
15931
0
            goto fail;
15932
41.3k
    } else {
15933
41.3k
        if (JS_DefineObjectName(ctx, ctor, class_name, JS_PROP_CONFIGURABLE) < 0)
15934
0
            goto fail;
15935
41.3k
    }
15936
15937
    /* the constructor property must be first. It can be overriden by
15938
       computed property names */
15939
41.3k
    if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
15940
41.3k
                               JS_DupValue(ctx, ctor),
15941
41.3k
                               JS_PROP_CONFIGURABLE |
15942
41.3k
                               JS_PROP_WRITABLE | JS_PROP_THROW) < 0)
15943
0
        goto fail;
15944
    /* set the prototype property */
15945
41.3k
    if (JS_DefinePropertyValue(ctx, ctor, JS_ATOM_prototype,
15946
41.3k
                               JS_DupValue(ctx, proto), JS_PROP_THROW) < 0)
15947
0
        goto fail;
15948
41.3k
    set_cycle_flag(ctx, ctor);
15949
41.3k
    set_cycle_flag(ctx, proto);
15950
15951
41.3k
    JS_FreeValue(ctx, parent_proto);
15952
41.3k
    JS_FreeValue(ctx, parent_class);
15953
15954
41.3k
    sp[-2] = ctor;
15955
41.3k
    sp[-1] = proto;
15956
41.3k
    return 0;
15957
0
 fail:
15958
0
    JS_FreeValue(ctx, parent_class);
15959
0
    JS_FreeValue(ctx, parent_proto);
15960
0
    JS_FreeValue(ctx, bfunc);
15961
0
    JS_FreeValue(ctx, proto);
15962
0
    JS_FreeValue(ctx, ctor);
15963
0
    sp[-2] = JS_UNDEFINED;
15964
0
    sp[-1] = JS_UNDEFINED;
15965
0
    return -1;
15966
41.3k
}
15967
15968
static void close_var_refs(JSRuntime *rt, JSStackFrame *sf)
15969
40.9k
{
15970
40.9k
    struct list_head *el, *el1;
15971
40.9k
    JSVarRef *var_ref;
15972
40.9k
    int var_idx;
15973
15974
40.9k
    list_for_each_safe(el, el1, &sf->var_ref_list) {
15975
40.9k
        var_ref = list_entry(el, JSVarRef, header.link);
15976
40.9k
        var_idx = var_ref->var_idx;
15977
40.9k
        if (var_ref->is_arg)
15978
40.9k
            var_ref->value = JS_DupValueRT(rt, sf->arg_buf[var_idx]);
15979
4
        else
15980
4
            var_ref->value = JS_DupValueRT(rt, sf->var_buf[var_idx]);
15981
40.9k
        var_ref->pvalue = &var_ref->value;
15982
        /* the reference is no longer to a local variable */
15983
40.9k
        var_ref->is_detached = TRUE;
15984
40.9k
        add_gc_object(rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
15985
40.9k
    }
15986
40.9k
}
15987
15988
static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_arg)
15989
148k
{
15990
148k
    struct list_head *el, *el1;
15991
148k
    JSVarRef *var_ref;
15992
148k
    int var_idx = idx;
15993
15994
1.47M
    list_for_each_safe(el, el1, &sf->var_ref_list) {
15995
1.47M
        var_ref = list_entry(el, JSVarRef, header.link);
15996
1.47M
        if (var_idx == var_ref->var_idx && var_ref->is_arg == is_arg) {
15997
148k
            var_ref->value = JS_DupValue(ctx, sf->var_buf[var_idx]);
15998
148k
            var_ref->pvalue = &var_ref->value;
15999
148k
            list_del(&var_ref->header.link);
16000
            /* the reference is no longer to a local variable */
16001
148k
            var_ref->is_detached = TRUE;
16002
148k
            add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
16003
148k
        }
16004
1.47M
    }
16005
148k
}
16006
16007
574k
#define JS_CALL_FLAG_COPY_ARGV   (1 << 1)
16008
0
#define JS_CALL_FLAG_GENERATOR   (1 << 2)
16009
16010
static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
16011
                                  JSValueConst this_obj,
16012
                                  int argc, JSValueConst *argv, int flags)
16013
574k
{
16014
574k
    JSRuntime *rt = ctx->rt;
16015
574k
    JSCFunctionType func;
16016
574k
    JSObject *p;
16017
574k
    JSStackFrame sf_s, *sf = &sf_s, *prev_sf;
16018
574k
    JSValue ret_val;
16019
574k
    JSValueConst *arg_buf;
16020
574k
    int arg_count, i;
16021
574k
    JSCFunctionEnum cproto;
16022
16023
574k
    p = JS_VALUE_GET_OBJ(func_obj);
16024
574k
    cproto = p->u.cfunc.cproto;
16025
574k
    arg_count = p->u.cfunc.length;
16026
16027
    /* better to always check stack overflow */
16028
574k
    if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count))
16029
0
        return JS_ThrowStackOverflow(ctx);
16030
16031
574k
    prev_sf = rt->current_stack_frame;
16032
574k
    sf->prev_frame = prev_sf;
16033
574k
    rt->current_stack_frame = sf;
16034
574k
    ctx = p->u.cfunc.realm; /* change the current realm */
16035
    
16036
574k
#ifdef CONFIG_BIGNUM
16037
    /* we only propagate the bignum mode as some runtime functions
16038
       test it */
16039
574k
    if (prev_sf)
16040
574k
        sf->js_mode = prev_sf->js_mode & JS_MODE_MATH;
16041
1
    else
16042
1
        sf->js_mode = 0;
16043
#else
16044
    sf->js_mode = 0;
16045
#endif
16046
574k
    sf->cur_func = (JSValue)func_obj;
16047
574k
    sf->arg_count = argc;
16048
574k
    arg_buf = argv;
16049
16050
574k
    if (unlikely(argc < arg_count)) {
16051
        /* ensure that at least argc_count arguments are readable */
16052
40.9k
        arg_buf = alloca(sizeof(arg_buf[0]) * arg_count);
16053
40.9k
        for(i = 0; i < argc; i++)
16054
7
            arg_buf[i] = argv[i];
16055
81.9k
        for(i = argc; i < arg_count; i++)
16056
40.9k
            arg_buf[i] = JS_UNDEFINED;
16057
40.9k
        sf->arg_count = arg_count;
16058
40.9k
    }
16059
574k
    sf->arg_buf = (JSValue*)arg_buf;
16060
16061
574k
    func = p->u.cfunc.c_function;
16062
574k
    switch(cproto) {
16063
0
    case JS_CFUNC_constructor:
16064
122k
    case JS_CFUNC_constructor_or_func:
16065
122k
        if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
16066
40.9k
            if (cproto == JS_CFUNC_constructor) {
16067
0
            not_a_constructor:
16068
0
                ret_val = JS_ThrowTypeError(ctx, "must be called with new");
16069
0
                break;
16070
40.9k
            } else {
16071
40.9k
                this_obj = JS_UNDEFINED;
16072
40.9k
            }
16073
40.9k
        }
16074
        /* here this_obj is new_target */
16075
        /* fall thru */
16076
574k
    case JS_CFUNC_generic:
16077
574k
        ret_val = func.generic(ctx, this_obj, argc, arg_buf);
16078
574k
        break;
16079
0
    case JS_CFUNC_constructor_magic:
16080
0
    case JS_CFUNC_constructor_or_func_magic:
16081
0
        if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
16082
0
            if (cproto == JS_CFUNC_constructor_magic) {
16083
0
                goto not_a_constructor;
16084
0
            } else {
16085
0
                this_obj = JS_UNDEFINED;
16086
0
            }
16087
0
        }
16088
        /* fall thru */
16089
18
    case JS_CFUNC_generic_magic:
16090
18
        ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf,
16091
18
                                     p->u.cfunc.magic);
16092
18
        break;
16093
0
    case JS_CFUNC_getter:
16094
0
        ret_val = func.getter(ctx, this_obj);
16095
0
        break;
16096
0
    case JS_CFUNC_setter:
16097
0
        ret_val = func.setter(ctx, this_obj, arg_buf[0]);
16098
0
        break;
16099
0
    case JS_CFUNC_getter_magic:
16100
0
        ret_val = func.getter_magic(ctx, this_obj, p->u.cfunc.magic);
16101
0
        break;
16102
0
    case JS_CFUNC_setter_magic:
16103
0
        ret_val = func.setter_magic(ctx, this_obj, arg_buf[0], p->u.cfunc.magic);
16104
0
        break;
16105
0
    case JS_CFUNC_f_f:
16106
0
        {
16107
0
            double d1;
16108
16109
0
            if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
16110
0
                ret_val = JS_EXCEPTION;
16111
0
                break;
16112
0
            }
16113
0
            ret_val = JS_NewFloat64(ctx, func.f_f(d1));
16114
0
        }
16115
0
        break;
16116
0
    case JS_CFUNC_f_f_f:
16117
0
        {
16118
0
            double d1, d2;
16119
16120
0
            if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
16121
0
                ret_val = JS_EXCEPTION;
16122
0
                break;
16123
0
            }
16124
0
            if (unlikely(JS_ToFloat64(ctx, &d2, arg_buf[1]))) {
16125
0
                ret_val = JS_EXCEPTION;
16126
0
                break;
16127
0
            }
16128
0
            ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2));
16129
0
        }
16130
0
        break;
16131
0
    case JS_CFUNC_iterator_next:
16132
0
        {
16133
0
            int done;
16134
0
            ret_val = func.iterator_next(ctx, this_obj, argc, arg_buf,
16135
0
                                         &done, p->u.cfunc.magic);
16136
0
            if (!JS_IsException(ret_val) && done != 2) {
16137
0
                ret_val = js_create_iterator_result(ctx, ret_val, done);
16138
0
            }
16139
0
        }
16140
0
        break;
16141
0
    default:
16142
0
        abort();
16143
574k
    }
16144
16145
574k
    rt->current_stack_frame = sf->prev_frame;
16146
574k
    return ret_val;
16147
574k
}
16148
16149
static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
16150
                                      JSValueConst this_obj,
16151
                                      int argc, JSValueConst *argv, int flags)
16152
0
{
16153
0
    JSObject *p;
16154
0
    JSBoundFunction *bf;
16155
0
    JSValueConst *arg_buf, new_target;
16156
0
    int arg_count, i;
16157
16158
0
    p = JS_VALUE_GET_OBJ(func_obj);
16159
0
    bf = p->u.bound_function;
16160
0
    arg_count = bf->argc + argc;
16161
0
    if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count))
16162
0
        return JS_ThrowStackOverflow(ctx);
16163
0
    arg_buf = alloca(sizeof(JSValue) * arg_count);
16164
0
    for(i = 0; i < bf->argc; i++) {
16165
0
        arg_buf[i] = bf->argv[i];
16166
0
    }
16167
0
    for(i = 0; i < argc; i++) {
16168
0
        arg_buf[bf->argc + i] = argv[i];
16169
0
    }
16170
0
    if (flags & JS_CALL_FLAG_CONSTRUCTOR) {
16171
0
        new_target = this_obj;
16172
0
        if (js_same_value(ctx, func_obj, new_target))
16173
0
            new_target = bf->func_obj;
16174
0
        return JS_CallConstructor2(ctx, bf->func_obj, new_target,
16175
0
                                   arg_count, arg_buf);
16176
0
    } else {
16177
0
        return JS_Call(ctx, bf->func_obj, bf->this_val,
16178
0
                       arg_count, arg_buf);
16179
0
    }
16180
0
}
16181
16182
/* argument of OP_special_object */
16183
typedef enum {
16184
    OP_SPECIAL_OBJECT_ARGUMENTS,
16185
    OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS,
16186
    OP_SPECIAL_OBJECT_THIS_FUNC,
16187
    OP_SPECIAL_OBJECT_NEW_TARGET,
16188
    OP_SPECIAL_OBJECT_HOME_OBJECT,
16189
    OP_SPECIAL_OBJECT_VAR_OBJECT,
16190
    OP_SPECIAL_OBJECT_IMPORT_META,
16191
} OPSpecialObjectEnum;
16192
16193
0
#define FUNC_RET_AWAIT      0
16194
0
#define FUNC_RET_YIELD      1
16195
0
#define FUNC_RET_YIELD_STAR 2
16196
16197
/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
16198
static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
16199
                               JSValueConst this_obj, JSValueConst new_target,
16200
                               int argc, JSValue *argv, int flags)
16201
656k
{
16202
656k
    JSRuntime *rt = caller_ctx->rt;
16203
656k
    JSContext *ctx;
16204
656k
    JSObject *p;
16205
656k
    JSFunctionBytecode *b;
16206
656k
    JSStackFrame sf_s, *sf = &sf_s;
16207
656k
    const uint8_t *pc;
16208
656k
    int opcode, arg_allocated_size, i;
16209
656k
    JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval;
16210
656k
    JSVarRef **var_refs;
16211
656k
    size_t alloca_size;
16212
16213
#if !DIRECT_DISPATCH
16214
#define SWITCH(pc)      switch (opcode = *pc++)
16215
#define CASE(op)        case op
16216
#define DEFAULT         default
16217
#define BREAK           break
16218
#else
16219
656k
    static const void * const dispatch_table[256] = {
16220
161M
#define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id,
16221
656k
#if SHORT_OPCODES
16222
656k
#define def(id, size, n_pop, n_push, f)
16223
#else                                                     
16224
#define def(id, size, n_pop, n_push, f) && case_default,
16225
#endif
16226
656k
#include "quickjs-opcode.h"
16227
656k
        [ OP_COUNT ... 255 ] = &&case_default
16228
656k
    };
16229
7.28M
#define SWITCH(pc)      goto *dispatch_table[opcode = *pc++];
16230
8.18M
#define CASE(op)        case_ ## op
16231
656k
#define DEFAULT         case_default
16232
7.08M
#define BREAK           SWITCH(pc)
16233
656k
#endif
16234
16235
656k
    if (js_poll_interrupts(caller_ctx))
16236
0
        return JS_EXCEPTION;
16237
656k
    if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) {
16238
0
        if (flags & JS_CALL_FLAG_GENERATOR) {
16239
0
            JSAsyncFunctionState *s = JS_VALUE_GET_PTR(func_obj);
16240
            /* func_obj get contains a pointer to JSFuncAsyncState */
16241
            /* the stack frame is already allocated */
16242
0
            sf = &s->frame;
16243
0
            p = JS_VALUE_GET_OBJ(sf->cur_func);
16244
0
            b = p->u.func.function_bytecode;
16245
0
            ctx = b->realm;
16246
0
            var_refs = p->u.func.var_refs;
16247
0
            local_buf = arg_buf = sf->arg_buf;
16248
0
            var_buf = sf->var_buf;
16249
0
            stack_buf = sf->var_buf + b->var_count;
16250
0
            sp = sf->cur_sp;
16251
0
            sf->cur_sp = NULL; /* cur_sp is NULL if the function is running */
16252
0
            pc = sf->cur_pc;
16253
0
            sf->prev_frame = rt->current_stack_frame;
16254
0
            rt->current_stack_frame = sf;
16255
0
            if (s->throw_flag)
16256
0
                goto exception;
16257
0
            else
16258
0
                goto restart;
16259
0
        } else {
16260
0
            goto not_a_function;
16261
0
        }
16262
0
    }
16263
656k
    p = JS_VALUE_GET_OBJ(func_obj);
16264
656k
    if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
16265
574k
        JSClassCall *call_func;
16266
574k
        call_func = rt->class_array[p->class_id].call;
16267
574k
        if (!call_func) {
16268
1
        not_a_function:
16269
1
            return JS_ThrowTypeError(caller_ctx, "not a function");
16270
1
        }
16271
574k
        return call_func(caller_ctx, func_obj, this_obj, argc,
16272
574k
                         (JSValueConst *)argv, flags);
16273
574k
    }
16274
81.9k
    b = p->u.func.function_bytecode;
16275
16276
81.9k
    if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) {
16277
41.0k
        arg_allocated_size = b->arg_count;
16278
41.0k
    } else {
16279
40.9k
        arg_allocated_size = 0;
16280
40.9k
    }
16281
16282
81.9k
    alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count +
16283
81.9k
                                     b->stack_size);
16284
81.9k
    if (js_check_stack_overflow(rt, alloca_size))
16285
0
        return JS_ThrowStackOverflow(caller_ctx);
16286
16287
81.9k
    sf->js_mode = b->js_mode;
16288
81.9k
    arg_buf = argv;
16289
81.9k
    sf->arg_count = argc;
16290
81.9k
    sf->cur_func = (JSValue)func_obj;
16291
81.9k
    init_list_head(&sf->var_ref_list);
16292
81.9k
    var_refs = p->u.func.var_refs;
16293
16294
81.9k
    local_buf = alloca(alloca_size);
16295
81.9k
    if (unlikely(arg_allocated_size)) {
16296
0
        int n = min_int(argc, b->arg_count);
16297
0
        arg_buf = local_buf;
16298
0
        for(i = 0; i < n; i++)
16299
0
            arg_buf[i] = JS_DupValue(caller_ctx, argv[i]);
16300
0
        for(; i < b->arg_count; i++)
16301
0
            arg_buf[i] = JS_UNDEFINED;
16302
0
        sf->arg_count = b->arg_count;
16303
0
    }
16304
81.9k
    var_buf = local_buf + arg_allocated_size;
16305
81.9k
    sf->var_buf = var_buf;
16306
81.9k
    sf->arg_buf = arg_buf;
16307
16308
123k
    for(i = 0; i < b->var_count; i++)
16309
81.9k
        var_buf[i] = JS_UNDEFINED;
16310
16311
81.9k
    stack_buf = var_buf + b->var_count;
16312
81.9k
    sp = stack_buf;
16313
81.9k
    pc = b->byte_code_buf;
16314
81.9k
    sf->prev_frame = rt->current_stack_frame;
16315
81.9k
    rt->current_stack_frame = sf;
16316
81.9k
    ctx = b->realm; /* set the current realm */
16317
    
16318
204k
 restart:
16319
204k
    for(;;) {
16320
204k
        int call_argc;
16321
204k
        JSValue *call_argv;
16322
16323
204k
        SWITCH(pc) {
16324
204k
        CASE(OP_push_i32):
16325
40.9k
            *sp++ = JS_NewInt32(ctx, get_u32(pc));
16326
40.9k
            pc += 4;
16327
40.9k
            BREAK;
16328
40.9k
        CASE(OP_push_const):
16329
0
            *sp++ = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
16330
0
            pc += 4;
16331
0
            BREAK;
16332
0
#if SHORT_OPCODES
16333
0
        CASE(OP_push_minus1):
16334
82.0k
        CASE(OP_push_0):
16335
82.0k
        CASE(OP_push_1):
16336
82.0k
        CASE(OP_push_2):
16337
82.0k
        CASE(OP_push_3):
16338
82.0k
        CASE(OP_push_4):
16339
82.0k
        CASE(OP_push_5):
16340
194k
        CASE(OP_push_6):
16341
194k
        CASE(OP_push_7):
16342
194k
            *sp++ = JS_NewInt32(ctx, opcode - OP_push_0);
16343
194k
            BREAK;
16344
194k
        CASE(OP_push_i8):
16345
9
            *sp++ = JS_NewInt32(ctx, get_i8(pc));
16346
9
            pc += 1;
16347
9
            BREAK;
16348
29
        CASE(OP_push_i16):
16349
29
            *sp++ = JS_NewInt32(ctx, get_i16(pc));
16350
29
            pc += 2;
16351
29
            BREAK;
16352
246k
        CASE(OP_push_const8):
16353
246k
            *sp++ = JS_DupValue(ctx, b->cpool[*pc++]);
16354
246k
            BREAK;
16355
416k
        CASE(OP_fclosure8):
16356
416k
            *sp++ = js_closure(ctx, JS_DupValue(ctx, b->cpool[*pc++]), var_refs, sf);
16357
416k
            if (unlikely(JS_IsException(sp[-1])))
16358
2
                goto exception;
16359
416k
            BREAK;
16360
416k
        CASE(OP_push_empty_string):
16361
0
            *sp++ = JS_AtomToString(ctx, JS_ATOM_empty_string);
16362
0
            BREAK;
16363
0
        CASE(OP_get_length):
16364
0
            {
16365
0
                JSValue val;
16366
16367
0
                val = JS_GetProperty(ctx, sp[-1], JS_ATOM_length);
16368
0
                if (unlikely(JS_IsException(val)))
16369
0
                    goto exception;
16370
0
                JS_FreeValue(ctx, sp[-1]);
16371
0
                sp[-1] = val;
16372
0
            }
16373
0
            BREAK;
16374
0
#endif
16375
368k
        CASE(OP_push_atom_value):
16376
368k
            *sp++ = JS_AtomToValue(ctx, get_u32(pc));
16377
368k
            pc += 4;
16378
368k
            BREAK;
16379
368k
        CASE(OP_undefined):
16380
41.3k
            *sp++ = JS_UNDEFINED;
16381
41.3k
            BREAK;
16382
41.3k
        CASE(OP_null):
16383
5
            *sp++ = JS_NULL;
16384
5
            BREAK;
16385
8
        CASE(OP_push_this):
16386
            /* OP_push_this is only called at the start of a function */
16387
8
            {
16388
8
                JSValue val;
16389
8
                if (!(b->js_mode & JS_MODE_STRICT)) {
16390
0
                    uint32_t tag = JS_VALUE_GET_TAG(this_obj);
16391
0
                    if (likely(tag == JS_TAG_OBJECT))
16392
0
                        goto normal_this;
16393
0
                    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) {
16394
0
                        val = JS_DupValue(ctx, ctx->global_obj);
16395
0
                    } else {
16396
0
                        val = JS_ToObject(ctx, this_obj);
16397
0
                        if (JS_IsException(val))
16398
0
                            goto exception;
16399
0
                    }
16400
8
                } else {
16401
8
                normal_this:
16402
8
                    val = JS_DupValue(ctx, this_obj);
16403
8
                }
16404
8
                *sp++ = val;
16405
8
            }
16406
8
            BREAK;
16407
8
        CASE(OP_push_false):
16408
0
            *sp++ = JS_FALSE;
16409
0
            BREAK;
16410
0
        CASE(OP_push_true):
16411
0
            *sp++ = JS_TRUE;
16412
0
            BREAK;
16413
143k
        CASE(OP_object):
16414
143k
            *sp++ = JS_NewObject(ctx);
16415
143k
            if (unlikely(JS_IsException(sp[-1])))
16416
0
                goto exception;
16417
143k
            BREAK;
16418
143k
        CASE(OP_special_object):
16419
3
            {
16420
3
                int arg = *pc++;
16421
3
                switch(arg) {
16422
0
                case OP_SPECIAL_OBJECT_ARGUMENTS:
16423
0
                    *sp++ = js_build_arguments(ctx, argc, (JSValueConst *)argv);
16424
0
                    if (unlikely(JS_IsException(sp[-1])))
16425
0
                        goto exception;
16426
0
                    break;
16427
0
                case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS:
16428
0
                    *sp++ = js_build_mapped_arguments(ctx, argc, (JSValueConst *)argv,
16429
0
                                                      sf, min_int(argc, b->arg_count));
16430
0
                    if (unlikely(JS_IsException(sp[-1])))
16431
0
                        goto exception;
16432
0
                    break;
16433
0
                case OP_SPECIAL_OBJECT_THIS_FUNC:
16434
0
                    *sp++ = JS_DupValue(ctx, sf->cur_func);
16435
0
                    break;
16436
2
                case OP_SPECIAL_OBJECT_NEW_TARGET:
16437
2
                    *sp++ = JS_DupValue(ctx, new_target);
16438
2
                    break;
16439
1
                case OP_SPECIAL_OBJECT_HOME_OBJECT:
16440
1
                    {
16441
1
                        JSObject *p1;
16442
1
                        p1 = p->u.func.home_object;
16443
1
                        if (unlikely(!p1))
16444
0
                            *sp++ = JS_UNDEFINED;
16445
1
                        else
16446
1
                            *sp++ = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
16447
1
                    }
16448
1
                    break;
16449
0
                case OP_SPECIAL_OBJECT_VAR_OBJECT:
16450
0
                    *sp++ = JS_NewObjectProto(ctx, JS_NULL);
16451
0
                    if (unlikely(JS_IsException(sp[-1])))
16452
0
                        goto exception;
16453
0
                    break;
16454
0
                case OP_SPECIAL_OBJECT_IMPORT_META:
16455
0
                    *sp++ = js_import_meta(ctx);
16456
0
                    if (unlikely(JS_IsException(sp[-1])))
16457
0
                        goto exception;
16458
0
                    break;
16459
0
                default:
16460
0
                    abort();
16461
3
                }
16462
3
            }
16463
3
            BREAK;
16464
3
        CASE(OP_rest):
16465
0
            {
16466
0
                int first = get_u16(pc);
16467
0
                pc += 2;
16468
0
                *sp++ = js_build_rest(ctx, first, argc, (JSValueConst *)argv);
16469
0
                if (unlikely(JS_IsException(sp[-1])))
16470
0
                    goto exception;
16471
0
            }
16472
0
            BREAK;
16473
16474
656k
        CASE(OP_drop):
16475
656k
            JS_FreeValue(ctx, sp[-1]);
16476
656k
            sp--;
16477
656k
            BREAK;
16478
656k
        CASE(OP_nip):
16479
0
            JS_FreeValue(ctx, sp[-2]);
16480
0
            sp[-2] = sp[-1];
16481
0
            sp--;
16482
0
            BREAK;
16483
0
        CASE(OP_nip1): /* a b c -> b c */
16484
0
            JS_FreeValue(ctx, sp[-3]);
16485
0
            sp[-3] = sp[-2];
16486
0
            sp[-2] = sp[-1];
16487
0
            sp--;
16488
0
            BREAK;
16489
164k
        CASE(OP_dup):
16490
164k
            sp[0] = JS_DupValue(ctx, sp[-1]);
16491
164k
            sp++;
16492
164k
            BREAK;
16493
164k
        CASE(OP_dup2): /* a b -> a b a b */
16494
0
            sp[0] = JS_DupValue(ctx, sp[-2]);
16495
0
            sp[1] = JS_DupValue(ctx, sp[-1]);
16496
0
            sp += 2;
16497
0
            BREAK;
16498
0
        CASE(OP_dup3): /* a b c -> a b c a b c */
16499
0
            sp[0] = JS_DupValue(ctx, sp[-3]);
16500
0
            sp[1] = JS_DupValue(ctx, sp[-2]);
16501
0
            sp[2] = JS_DupValue(ctx, sp[-1]);
16502
0
            sp += 3;
16503
0
            BREAK;
16504
1
        CASE(OP_dup1): /* a b -> a a b */
16505
1
            sp[0] = sp[-1];
16506
1
            sp[-1] = JS_DupValue(ctx, sp[-2]);
16507
1
            sp++;
16508
1
            BREAK;
16509
1
        CASE(OP_insert2): /* obj a -> a obj a (dup_x1) */
16510
0
            sp[0] = sp[-1];
16511
0
            sp[-1] = sp[-2];
16512
0
            sp[-2] = JS_DupValue(ctx, sp[0]);
16513
0
            sp++;
16514
0
            BREAK;
16515
20
        CASE(OP_insert3): /* obj prop a -> a obj prop a (dup_x2) */
16516
20
            sp[0] = sp[-1];
16517
20
            sp[-1] = sp[-2];
16518
20
            sp[-2] = sp[-3];
16519
20
            sp[-3] = JS_DupValue(ctx, sp[0]);
16520
20
            sp++;
16521
20
            BREAK;
16522
20
        CASE(OP_insert4): /* this obj prop a -> a this obj prop a */
16523
0
            sp[0] = sp[-1];
16524
0
            sp[-1] = sp[-2];
16525
0
            sp[-2] = sp[-3];
16526
0
            sp[-3] = sp[-4];
16527
0
            sp[-4] = JS_DupValue(ctx, sp[0]);
16528
0
            sp++;
16529
0
            BREAK;
16530
0
        CASE(OP_perm3): /* obj a b -> a obj b (213) */
16531
0
            {
16532
0
                JSValue tmp;
16533
0
                tmp = sp[-2];
16534
0
                sp[-2] = sp[-3];
16535
0
                sp[-3] = tmp;
16536
0
            }
16537
0
            BREAK;
16538
0
        CASE(OP_rot3l): /* x a b -> a b x (231) */
16539
0
            {
16540
0
                JSValue tmp;
16541
0
                tmp = sp[-3];
16542
0
                sp[-3] = sp[-2];
16543
0
                sp[-2] = sp[-1];
16544
0
                sp[-1] = tmp;
16545
0
            }
16546
0
            BREAK;
16547
0
        CASE(OP_rot4l): /* x a b c -> a b c x */
16548
0
            {
16549
0
                JSValue tmp;
16550
0
                tmp = sp[-4];
16551
0
                sp[-4] = sp[-3];
16552
0
                sp[-3] = sp[-2];
16553
0
                sp[-2] = sp[-1];
16554
0
                sp[-1] = tmp;
16555
0
            }
16556
0
            BREAK;
16557
0
        CASE(OP_rot5l): /* x a b c d -> a b c d x */
16558
0
            {
16559
0
                JSValue tmp;
16560
0
                tmp = sp[-5];
16561
0
                sp[-5] = sp[-4];
16562
0
                sp[-4] = sp[-3];
16563
0
                sp[-3] = sp[-2];
16564
0
                sp[-2] = sp[-1];
16565
0
                sp[-1] = tmp;
16566
0
            }
16567
0
            BREAK;
16568
0
        CASE(OP_rot3r): /* a b x -> x a b (312) */
16569
0
            {
16570
0
                JSValue tmp;
16571
0
                tmp = sp[-1];
16572
0
                sp[-1] = sp[-2];
16573
0
                sp[-2] = sp[-3];
16574
0
                sp[-3] = tmp;
16575
0
            }
16576
0
            BREAK;
16577
0
        CASE(OP_perm4): /* obj prop a b -> a obj prop b */
16578
0
            {
16579
0
                JSValue tmp;
16580
0
                tmp = sp[-2];
16581
0
                sp[-2] = sp[-3];
16582
0
                sp[-3] = sp[-4];
16583
0
                sp[-4] = tmp;
16584
0
            }
16585
0
            BREAK;
16586
0
        CASE(OP_perm5): /* this obj prop a b -> a this obj prop b */
16587
0
            {
16588
0
                JSValue tmp;
16589
0
                tmp = sp[-2];
16590
0
                sp[-2] = sp[-3];
16591
0
                sp[-3] = sp[-4];
16592
0
                sp[-4] = sp[-5];
16593
0
                sp[-5] = tmp;
16594
0
            }
16595
0
            BREAK;
16596
20
        CASE(OP_swap): /* a b -> b a */
16597
20
            {
16598
20
                JSValue tmp;
16599
20
                tmp = sp[-2];
16600
20
                sp[-2] = sp[-1];
16601
20
                sp[-1] = tmp;
16602
20
            }
16603
20
            BREAK;
16604
20
        CASE(OP_swap2): /* a b c d -> c d a b */
16605
0
            {
16606
0
                JSValue tmp1, tmp2;
16607
0
                tmp1 = sp[-4];
16608
0
                tmp2 = sp[-3];
16609
0
                sp[-4] = sp[-2];
16610
0
                sp[-3] = sp[-1];
16611
0
                sp[-2] = tmp1;
16612
0
                sp[-1] = tmp2;
16613
0
            }
16614
0
            BREAK;
16615
16616
296
        CASE(OP_fclosure):
16617
296
            {
16618
296
                JSValue bfunc = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
16619
296
                pc += 4;
16620
296
                *sp++ = js_closure(ctx, bfunc, var_refs, sf);
16621
296
                if (unlikely(JS_IsException(sp[-1])))
16622
0
                    goto exception;
16623
296
            }
16624
296
            BREAK;
16625
296
#if SHORT_OPCODES
16626
296
        CASE(OP_call0):
16627
81.9k
        CASE(OP_call1):
16628
81.9k
        CASE(OP_call2):
16629
81.9k
        CASE(OP_call3):
16630
81.9k
            call_argc = opcode - OP_call0;
16631
81.9k
            goto has_call_argc;
16632
0
#endif
16633
0
        CASE(OP_call):
16634
0
        CASE(OP_tail_call):
16635
0
            {
16636
0
                call_argc = get_u16(pc);
16637
0
                pc += 2;
16638
0
                goto has_call_argc;
16639
81.9k
            has_call_argc:
16640
81.9k
                call_argv = sp - call_argc;
16641
81.9k
                sf->cur_pc = pc;
16642
81.9k
                ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
16643
81.9k
                                          JS_UNDEFINED, call_argc, call_argv, 0);
16644
81.9k
                if (unlikely(JS_IsException(ret_val)))
16645
2
                    goto exception;
16646
81.9k
                if (opcode == OP_tail_call)
16647
0
                    goto done;
16648
245k
                for(i = -1; i < call_argc; i++)
16649
163k
                    JS_FreeValue(ctx, call_argv[i]);
16650
81.9k
                sp -= call_argc + 1;
16651
81.9k
                *sp++ = ret_val;
16652
81.9k
            }
16653
81.9k
            BREAK;
16654
81.9k
        CASE(OP_call_constructor):
16655
81.9k
            {
16656
81.9k
                call_argc = get_u16(pc);
16657
81.9k
                pc += 2;
16658
81.9k
                call_argv = sp - call_argc;
16659
81.9k
                sf->cur_pc = pc;
16660
81.9k
                ret_val = JS_CallConstructorInternal(ctx, call_argv[-2],
16661
81.9k
                                                     call_argv[-1],
16662
81.9k
                                                     call_argc, call_argv, 0);
16663
81.9k
                if (unlikely(JS_IsException(ret_val)))
16664
0
                    goto exception;
16665
286k
                for(i = -2; i < call_argc; i++)
16666
204k
                    JS_FreeValue(ctx, call_argv[i]);
16667
81.9k
                sp -= call_argc + 2;
16668
81.9k
                *sp++ = ret_val;
16669
81.9k
            }
16670
81.9k
            BREAK;
16671
81.9k
        CASE(OP_call_method):
16672
8
        CASE(OP_tail_call_method):
16673
8
            {
16674
8
                call_argc = get_u16(pc);
16675
8
                pc += 2;
16676
8
                call_argv = sp - call_argc;
16677
8
                sf->cur_pc = pc;
16678
8
                ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2],
16679
8
                                          JS_UNDEFINED, call_argc, call_argv, 0);
16680
8
                if (unlikely(JS_IsException(ret_val)))
16681
0
                    goto exception;
16682
8
                if (opcode == OP_tail_call_method)
16683
0
                    goto done;
16684
31
                for(i = -2; i < call_argc; i++)
16685
23
                    JS_FreeValue(ctx, call_argv[i]);
16686
8
                sp -= call_argc + 2;
16687
8
                *sp++ = ret_val;
16688
8
            }
16689
8
            BREAK;
16690
40.9k
        CASE(OP_array_from):
16691
40.9k
            {
16692
40.9k
                int i, ret;
16693
16694
40.9k
                call_argc = get_u16(pc);
16695
40.9k
                pc += 2;
16696
40.9k
                ret_val = JS_NewArray(ctx);
16697
40.9k
                if (unlikely(JS_IsException(ret_val)))
16698
0
                    goto exception;
16699
40.9k
                call_argv = sp - call_argc;
16700
40.9k
                for(i = 0; i < call_argc; i++) {
16701
1
                    ret = JS_DefinePropertyValue(ctx, ret_val, __JS_AtomFromUInt32(i), call_argv[i],
16702
1
                                                 JS_PROP_C_W_E | JS_PROP_THROW);
16703
1
                    call_argv[i] = JS_UNDEFINED;
16704
1
                    if (ret < 0) {
16705
0
                        JS_FreeValue(ctx, ret_val);
16706
0
                        goto exception;
16707
0
                    }
16708
1
                }
16709
40.9k
                sp -= call_argc;
16710
40.9k
                *sp++ = ret_val;
16711
40.9k
            }
16712
40.9k
            BREAK;
16713
16714
40.9k
        CASE(OP_apply):
16715
0
            {
16716
0
                int magic;
16717
0
                magic = get_u16(pc);
16718
0
                pc += 2;
16719
16720
0
                ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic);
16721
0
                if (unlikely(JS_IsException(ret_val)))
16722
0
                    goto exception;
16723
0
                JS_FreeValue(ctx, sp[-3]);
16724
0
                JS_FreeValue(ctx, sp[-2]);
16725
0
                JS_FreeValue(ctx, sp[-1]);
16726
0
                sp -= 3;
16727
0
                *sp++ = ret_val;
16728
0
            }
16729
0
            BREAK;
16730
40.9k
        CASE(OP_return):
16731
40.9k
            ret_val = *--sp;
16732
40.9k
            goto done;
16733
4
        CASE(OP_return_undef):
16734
4
            ret_val = JS_UNDEFINED;
16735
4
            goto done;
16736
16737
0
        CASE(OP_check_ctor_return):
16738
            /* return TRUE if 'this' should be returned */
16739
0
            if (!JS_IsObject(sp[-1])) {
16740
0
                if (!JS_IsUndefined(sp[-1])) {
16741
0
                    JS_ThrowTypeError(caller_ctx, "derived class constructor must return an object or undefined");
16742
0
                    goto exception;
16743
0
                }
16744
0
                sp[0] = JS_TRUE;
16745
0
            } else {
16746
0
                sp[0] = JS_FALSE;
16747
0
            }
16748
0
            sp++;
16749
0
            BREAK;
16750
1
        CASE(OP_check_ctor):
16751
1
            if (JS_IsUndefined(new_target)) {
16752
0
                JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'");
16753
0
                goto exception;
16754
0
            }
16755
1
            BREAK;
16756
1
        CASE(OP_check_brand):
16757
0
            if (JS_CheckBrand(ctx, sp[-2], sp[-1]) < 0)
16758
0
                goto exception;
16759
0
            BREAK;
16760
0
        CASE(OP_add_brand):
16761
0
            if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0)
16762
0
                goto exception;
16763
0
            JS_FreeValue(ctx, sp[-2]);
16764
0
            JS_FreeValue(ctx, sp[-1]);
16765
0
            sp -= 2;
16766
0
            BREAK;
16767
            
16768
2
        CASE(OP_throw):
16769
2
            JS_Throw(ctx, *--sp);
16770
2
            goto exception;
16771
16772
0
        CASE(OP_throw_error):
16773
0
#define JS_THROW_VAR_RO             0
16774
0
#define JS_THROW_VAR_REDECL         1
16775
0
#define JS_THROW_VAR_UNINITIALIZED  2
16776
0
#define JS_THROW_ERROR_DELETE_SUPER   3
16777
370
#define JS_THROW_ERROR_ITERATOR_THROW 4
16778
0
            {
16779
0
                JSAtom atom;
16780
0
                int type;
16781
0
                atom = get_u32(pc);
16782
0
                type = pc[4];
16783
0
                pc += 5;
16784
0
                if (type == JS_THROW_VAR_RO)
16785
0
                    JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, atom);
16786
0
                else
16787
0
                if (type == JS_THROW_VAR_REDECL)
16788
0
                    JS_ThrowSyntaxErrorVarRedeclaration(ctx, atom);
16789
0
                else
16790
0
                if (type == JS_THROW_VAR_UNINITIALIZED)
16791
0
                    JS_ThrowReferenceErrorUninitialized(ctx, atom);
16792
0
                else
16793
0
                if (type == JS_THROW_ERROR_DELETE_SUPER)
16794
0
                    JS_ThrowReferenceError(ctx, "unsupported reference to 'super'");
16795
0
                else
16796
0
                if (type == JS_THROW_ERROR_ITERATOR_THROW)
16797
0
                    JS_ThrowTypeError(ctx, "iterator does not have a throw method");
16798
0
                else
16799
0
                    JS_ThrowInternalError(ctx, "invalid throw var type %d", type);
16800
0
            }
16801
0
            goto exception;
16802
16803
40.9k
        CASE(OP_eval):
16804
40.9k
            {
16805
40.9k
                JSValueConst obj;
16806
40.9k
                int scope_idx;
16807
40.9k
                call_argc = get_u16(pc);
16808
40.9k
                scope_idx = get_u16(pc + 2) - 1;
16809
40.9k
                pc += 4;
16810
40.9k
                call_argv = sp - call_argc;
16811
40.9k
                sf->cur_pc = pc;
16812
40.9k
                if (js_same_value(ctx, call_argv[-1], ctx->eval_obj)) {
16813
40.9k
                    if (call_argc >= 1)
16814
40.9k
                        obj = call_argv[0];
16815
0
                    else
16816
0
                        obj = JS_UNDEFINED;
16817
40.9k
                    ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
16818
40.9k
                                            JS_EVAL_TYPE_DIRECT, scope_idx);
16819
40.9k
                } else {
16820
0
                    ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
16821
0
                                              JS_UNDEFINED, call_argc, call_argv, 0);
16822
0
                }
16823
40.9k
                if (unlikely(JS_IsException(ret_val)))
16824
40.9k
                    goto exception;
16825
0
                for(i = -1; i < call_argc; i++)
16826
0
                    JS_FreeValue(ctx, call_argv[i]);
16827
0
                sp -= call_argc + 1;
16828
0
                *sp++ = ret_val;
16829
0
            }
16830
0
            BREAK;
16831
            /* could merge with OP_apply */
16832
0
        CASE(OP_apply_eval):
16833
0
            {
16834
0
                int scope_idx;
16835
0
                uint32_t len;
16836
0
                JSValue *tab;
16837
0
                JSValueConst obj;
16838
16839
0
                scope_idx = get_u16(pc) - 1;
16840
0
                pc += 2;
16841
0
                tab = build_arg_list(ctx, &len, sp[-1]);
16842
0
                if (!tab)
16843
0
                    goto exception;
16844
0
                if (js_same_value(ctx, sp[-2], ctx->eval_obj)) {
16845
0
                    if (len >= 1)
16846
0
                        obj = tab[0];
16847
0
                    else
16848
0
                        obj = JS_UNDEFINED;
16849
0
                    ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
16850
0
                                            JS_EVAL_TYPE_DIRECT, scope_idx);
16851
0
                } else {
16852
0
                    ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len,
16853
0
                                      (JSValueConst *)tab);
16854
0
                }
16855
0
                free_arg_list(ctx, tab, len);
16856
0
                if (unlikely(JS_IsException(ret_val)))
16857
0
                    goto exception;
16858
0
                JS_FreeValue(ctx, sp[-2]);
16859
0
                JS_FreeValue(ctx, sp[-1]);
16860
0
                sp -= 2;
16861
0
                *sp++ = ret_val;
16862
0
            }
16863
0
            BREAK;
16864
16865
5
        CASE(OP_regexp):
16866
5
            {
16867
5
                sp[-2] = js_regexp_constructor_internal(ctx, JS_UNDEFINED,
16868
5
                                                        sp[-2], sp[-1]);
16869
5
                sp--;
16870
5
            }
16871
5
            BREAK;
16872
16873
5
        CASE(OP_get_super):
16874
0
            {
16875
0
                JSValue proto;
16876
0
                proto = JS_GetPrototype(ctx, sp[-1]);
16877
0
                if (JS_IsException(proto))
16878
0
                    goto exception;
16879
0
                JS_FreeValue(ctx, sp[-1]);
16880
0
                sp[-1] = proto;
16881
0
            }
16882
0
            BREAK;
16883
16884
81.9k
        CASE(OP_import):
16885
81.9k
            {
16886
81.9k
                JSValue val;
16887
81.9k
                val = js_dynamic_import(ctx, sp[-1]);
16888
81.9k
                if (JS_IsException(val))
16889
0
                    goto exception;
16890
81.9k
                JS_FreeValue(ctx, sp[-1]);
16891
81.9k
                sp[-1] = val;
16892
81.9k
            }
16893
81.9k
            BREAK;
16894
16895
81.9k
        CASE(OP_check_var):
16896
0
            {
16897
0
                int ret;
16898
0
                JSAtom atom;
16899
0
                atom = get_u32(pc);
16900
0
                pc += 4;
16901
16902
0
                ret = JS_CheckGlobalVar(ctx, atom);
16903
0
                if (ret < 0)
16904
0
                    goto exception;
16905
0
                *sp++ = JS_NewBool(ctx, ret);
16906
0
            }
16907
0
            BREAK;
16908
16909
0
        CASE(OP_get_var_undef):
16910
327k
        CASE(OP_get_var):
16911
327k
            {
16912
327k
                JSValue val;
16913
327k
                JSAtom atom;
16914
327k
                atom = get_u32(pc);
16915
327k
                pc += 4;
16916
16917
327k
                val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef);
16918
327k
                if (unlikely(JS_IsException(val)))
16919
122k
                    goto exception;
16920
204k
                *sp++ = val;
16921
204k
            }
16922
204k
            BREAK;
16923
16924
204k
        CASE(OP_put_var):
16925
1.08k
        CASE(OP_put_var_init):
16926
1.08k
            {
16927
1.08k
                int ret;
16928
1.08k
                JSAtom atom;
16929
1.08k
                atom = get_u32(pc);
16930
1.08k
                pc += 4;
16931
16932
1.08k
                ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var);
16933
1.08k
                sp--;
16934
1.08k
                if (unlikely(ret < 0))
16935
0
                    goto exception;
16936
1.08k
            }
16937
1.08k
            BREAK;
16938
16939
1.08k
        CASE(OP_put_var_strict):
16940
0
            {
16941
0
                int ret;
16942
0
                JSAtom atom;
16943
0
                atom = get_u32(pc);
16944
0
                pc += 4;
16945
16946
                /* sp[-2] is JS_TRUE or JS_FALSE */
16947
0
                if (unlikely(!JS_VALUE_GET_INT(sp[-2]))) {
16948
0
                    JS_ThrowReferenceErrorNotDefined(ctx, atom);
16949
0
                    goto exception;
16950
0
                }
16951
0
                ret = JS_SetGlobalVar(ctx, atom, sp[-1], 2);
16952
0
                sp -= 2;
16953
0
                if (unlikely(ret < 0))
16954
0
                    goto exception;
16955
0
            }
16956
0
            BREAK;
16957
16958
1.19k
        CASE(OP_check_define_var):
16959
1.19k
            {
16960
1.19k
                JSAtom atom;
16961
1.19k
                int flags;
16962
1.19k
                atom = get_u32(pc);
16963
1.19k
                flags = pc[4];
16964
1.19k
                pc += 5;
16965
1.19k
                if (JS_CheckDefineGlobalVar(ctx, atom, flags))
16966
0
                    goto exception;
16967
1.19k
            }
16968
1.19k
            BREAK;
16969
1.19k
        CASE(OP_define_var):
16970
408
            {
16971
408
                JSAtom atom;
16972
408
                int flags;
16973
408
                atom = get_u32(pc);
16974
408
                flags = pc[4];
16975
408
                pc += 5;
16976
408
                if (JS_DefineGlobalVar(ctx, atom, flags))
16977
0
                    goto exception;
16978
408
            }
16979
408
            BREAK;
16980
784
        CASE(OP_define_func):
16981
784
            {
16982
784
                JSAtom atom;
16983
784
                int flags;
16984
784
                atom = get_u32(pc);
16985
784
                flags = pc[4];
16986
784
                pc += 5;
16987
784
                if (JS_DefineGlobalFunction(ctx, atom, sp[-1], flags))
16988
0
                    goto exception;
16989
784
                JS_FreeValue(ctx, sp[-1]);
16990
784
                sp--;
16991
784
            }
16992
784
            BREAK;
16993
16994
784
        CASE(OP_get_loc):
16995
0
            {
16996
0
                int idx;
16997
0
                idx = get_u16(pc);
16998
0
                pc += 2;
16999
0
                sp[0] = JS_DupValue(ctx, var_buf[idx]);
17000
0
                sp++;
17001
0
            }
17002
0
            BREAK;
17003
0
        CASE(OP_put_loc):
17004
0
            {
17005
0
                int idx;
17006
0
                idx = get_u16(pc);
17007
0
                pc += 2;
17008
0
                set_value(ctx, &var_buf[idx], sp[-1]);
17009
0
                sp--;
17010
0
            }
17011
0
            BREAK;
17012
0
        CASE(OP_set_loc):
17013
0
            {
17014
0
                int idx;
17015
0
                idx = get_u16(pc);
17016
0
                pc += 2;
17017
0
                set_value(ctx, &var_buf[idx], JS_DupValue(ctx, sp[-1]));
17018
0
            }
17019
0
            BREAK;
17020
0
        CASE(OP_get_arg):
17021
0
            {
17022
0
                int idx;
17023
0
                idx = get_u16(pc);
17024
0
                pc += 2;
17025
0
                sp[0] = JS_DupValue(ctx, arg_buf[idx]);
17026
0
                sp++;
17027
0
            }
17028
0
            BREAK;
17029
0
        CASE(OP_put_arg):
17030
0
            {
17031
0
                int idx;
17032
0
                idx = get_u16(pc);
17033
0
                pc += 2;
17034
0
                set_value(ctx, &arg_buf[idx], sp[-1]);
17035
0
                sp--;
17036
0
            }
17037
0
            BREAK;
17038
0
        CASE(OP_set_arg):
17039
0
            {
17040
0
                int idx;
17041
0
                idx = get_u16(pc);
17042
0
                pc += 2;
17043
0
                set_value(ctx, &arg_buf[idx], JS_DupValue(ctx, sp[-1]));
17044
0
            }
17045
0
            BREAK;
17046
17047
0
#if SHORT_OPCODES
17048
164k
        CASE(OP_get_loc8): *sp++ = JS_DupValue(ctx, var_buf[*pc++]); BREAK;
17049
434k
        CASE(OP_put_loc8): set_value(ctx, &var_buf[*pc++], *--sp); BREAK;
17050
434k
        CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], JS_DupValue(ctx, sp[-1])); BREAK;
17051
17052
245k
        CASE(OP_get_loc0): *sp++ = JS_DupValue(ctx, var_buf[0]); BREAK;
17053
245k
        CASE(OP_get_loc1): *sp++ = JS_DupValue(ctx, var_buf[1]); BREAK;
17054
40
        CASE(OP_get_loc2): *sp++ = JS_DupValue(ctx, var_buf[2]); BREAK;
17055
40
        CASE(OP_get_loc3): *sp++ = JS_DupValue(ctx, var_buf[3]); BREAK;
17056
164k
        CASE(OP_put_loc0): set_value(ctx, &var_buf[0], *--sp); BREAK;
17057
164k
        CASE(OP_put_loc1): set_value(ctx, &var_buf[1], *--sp); BREAK;
17058
41.3k
        CASE(OP_put_loc2): set_value(ctx, &var_buf[2], *--sp); BREAK;
17059
41.3k
        CASE(OP_put_loc3): set_value(ctx, &var_buf[3], *--sp); BREAK;
17060
409k
        CASE(OP_set_loc0): set_value(ctx, &var_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;
17061
409k
        CASE(OP_set_loc1): set_value(ctx, &var_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;
17062
41.3k
        CASE(OP_set_loc2): set_value(ctx, &var_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;
17063
0
        CASE(OP_set_loc3): set_value(ctx, &var_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;
17064
0
        CASE(OP_get_arg0): *sp++ = JS_DupValue(ctx, arg_buf[0]); BREAK;
17065
0
        CASE(OP_get_arg1): *sp++ = JS_DupValue(ctx, arg_buf[1]); BREAK;
17066
0
        CASE(OP_get_arg2): *sp++ = JS_DupValue(ctx, arg_buf[2]); BREAK;
17067
0
        CASE(OP_get_arg3): *sp++ = JS_DupValue(ctx, arg_buf[3]); BREAK;
17068
0
        CASE(OP_put_arg0): set_value(ctx, &arg_buf[0], *--sp); BREAK;
17069
0
        CASE(OP_put_arg1): set_value(ctx, &arg_buf[1], *--sp); BREAK;
17070
0
        CASE(OP_put_arg2): set_value(ctx, &arg_buf[2], *--sp); BREAK;
17071
0
        CASE(OP_put_arg3): set_value(ctx, &arg_buf[3], *--sp); BREAK;
17072
0
        CASE(OP_set_arg0): set_value(ctx, &arg_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;
17073
0
        CASE(OP_set_arg1): set_value(ctx, &arg_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;
17074
0
        CASE(OP_set_arg2): set_value(ctx, &arg_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;
17075
0
        CASE(OP_set_arg3): set_value(ctx, &arg_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;
17076
40.9k
        CASE(OP_get_var_ref0): *sp++ = JS_DupValue(ctx, *var_refs[0]->pvalue); BREAK;
17077
40.9k
        CASE(OP_get_var_ref1): *sp++ = JS_DupValue(ctx, *var_refs[1]->pvalue); BREAK;
17078
0
        CASE(OP_get_var_ref2): *sp++ = JS_DupValue(ctx, *var_refs[2]->pvalue); BREAK;
17079
0
        CASE(OP_get_var_ref3): *sp++ = JS_DupValue(ctx, *var_refs[3]->pvalue); BREAK;
17080
40.9k
        CASE(OP_put_var_ref0): set_value(ctx, var_refs[0]->pvalue, *--sp); BREAK;
17081
122k
        CASE(OP_put_var_ref1): set_value(ctx, var_refs[1]->pvalue, *--sp); BREAK;
17082
122k
        CASE(OP_put_var_ref2): set_value(ctx, var_refs[2]->pvalue, *--sp); BREAK;
17083
0
        CASE(OP_put_var_ref3): set_value(ctx, var_refs[3]->pvalue, *--sp); BREAK;
17084
0
        CASE(OP_set_var_ref0): set_value(ctx, var_refs[0]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17085
0
        CASE(OP_set_var_ref1): set_value(ctx, var_refs[1]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17086
0
        CASE(OP_set_var_ref2): set_value(ctx, var_refs[2]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17087
0
        CASE(OP_set_var_ref3): set_value(ctx, var_refs[3]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17088
0
#endif
17089
17090
163k
        CASE(OP_get_var_ref):
17091
163k
            {
17092
163k
                int idx;
17093
163k
                JSValue val;
17094
163k
                idx = get_u16(pc);
17095
163k
                pc += 2;
17096
163k
                val = *var_refs[idx]->pvalue;
17097
163k
                sp[0] = JS_DupValue(ctx, val);
17098
163k
                sp++;
17099
163k
            }
17100
163k
            BREAK;
17101
450k
        CASE(OP_put_var_ref):
17102
450k
            {
17103
450k
                int idx;
17104
450k
                idx = get_u16(pc);
17105
450k
                pc += 2;
17106
450k
                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
17107
450k
                sp--;
17108
450k
            }
17109
450k
            BREAK;
17110
450k
        CASE(OP_set_var_ref):
17111
0
            {
17112
0
                int idx;
17113
0
                idx = get_u16(pc);
17114
0
                pc += 2;
17115
0
                set_value(ctx, var_refs[idx]->pvalue, JS_DupValue(ctx, sp[-1]));
17116
0
            }
17117
0
            BREAK;
17118
5
        CASE(OP_get_var_ref_check):
17119
5
            {
17120
5
                int idx;
17121
5
                JSValue val;
17122
5
                idx = get_u16(pc);
17123
5
                pc += 2;
17124
5
                val = *var_refs[idx]->pvalue;
17125
5
                if (unlikely(JS_IsUninitialized(val))) {
17126
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
17127
0
                    goto exception;
17128
0
                }
17129
5
                sp[0] = JS_DupValue(ctx, val);
17130
5
                sp++;
17131
5
            }
17132
5
            BREAK;
17133
5
        CASE(OP_put_var_ref_check):
17134
0
            {
17135
0
                int idx;
17136
0
                idx = get_u16(pc);
17137
0
                pc += 2;
17138
0
                if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) {
17139
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
17140
0
                    goto exception;
17141
0
                }
17142
0
                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
17143
0
                sp--;
17144
0
            }
17145
0
            BREAK;
17146
0
        CASE(OP_put_var_ref_check_init):
17147
0
            {
17148
0
                int idx;
17149
0
                idx = get_u16(pc);
17150
0
                pc += 2;
17151
0
                if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) {
17152
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
17153
0
                    goto exception;
17154
0
                }
17155
0
                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
17156
0
                sp--;
17157
0
            }
17158
0
            BREAK;
17159
190k
        CASE(OP_set_loc_uninitialized):
17160
190k
            {
17161
190k
                int idx;
17162
190k
                idx = get_u16(pc);
17163
190k
                pc += 2;
17164
190k
                set_value(ctx, &var_buf[idx], JS_UNINITIALIZED);
17165
190k
            }
17166
190k
            BREAK;
17167
190k
        CASE(OP_get_loc_check):
17168
81.9k
            {
17169
81.9k
                int idx;
17170
81.9k
                idx = get_u16(pc);
17171
81.9k
                pc += 2;
17172
81.9k
                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
17173
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
17174
0
                    goto exception;
17175
0
                }
17176
81.9k
                sp[0] = JS_DupValue(ctx, var_buf[idx]);
17177
81.9k
                sp++;
17178
81.9k
            }
17179
81.9k
            BREAK;
17180
81.9k
        CASE(OP_put_loc_check):
17181
40.9k
            {
17182
40.9k
                int idx;
17183
40.9k
                idx = get_u16(pc);
17184
40.9k
                pc += 2;
17185
40.9k
                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
17186
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
17187
0
                    goto exception;
17188
0
                }
17189
40.9k
                set_value(ctx, &var_buf[idx], sp[-1]);
17190
40.9k
                sp--;
17191
40.9k
            }
17192
40.9k
            BREAK;
17193
40.9k
        CASE(OP_put_loc_check_init):
17194
0
            {
17195
0
                int idx;
17196
0
                idx = get_u16(pc);
17197
0
                pc += 2;
17198
0
                if (unlikely(!JS_IsUninitialized(var_buf[idx]))) {
17199
0
                    JS_ThrowReferenceError(ctx, "'this' can be initialized only once");
17200
0
                    goto exception;
17201
0
                }
17202
0
                set_value(ctx, &var_buf[idx], sp[-1]);
17203
0
                sp--;
17204
0
            }
17205
0
            BREAK;
17206
148k
        CASE(OP_close_loc):
17207
148k
            {
17208
148k
                int idx;
17209
148k
                idx = get_u16(pc);
17210
148k
                pc += 2;
17211
148k
                close_lexical_var(ctx, sf, idx, FALSE);
17212
148k
            }
17213
148k
            BREAK;
17214
17215
148k
        CASE(OP_make_loc_ref):
17216
2
        CASE(OP_make_arg_ref):
17217
2
        CASE(OP_make_var_ref_ref):
17218
2
            {
17219
2
                JSVarRef *var_ref;
17220
2
                JSProperty *pr;
17221
2
                JSAtom atom;
17222
2
                int idx;
17223
2
                atom = get_u32(pc);
17224
2
                idx = get_u16(pc + 4);
17225
2
                pc += 6;
17226
2
                *sp++ = JS_NewObjectProto(ctx, JS_NULL);
17227
2
                if (unlikely(JS_IsException(sp[-1])))
17228
0
                    goto exception;
17229
2
                if (opcode == OP_make_var_ref_ref) {
17230
0
                    var_ref = var_refs[idx];
17231
0
                    var_ref->header.ref_count++;
17232
2
                } else {
17233
2
                    var_ref = get_var_ref(ctx, sf, idx, opcode == OP_make_arg_ref);
17234
2
                    if (!var_ref)
17235
0
                        goto exception;
17236
2
                }
17237
2
                pr = add_property(ctx, JS_VALUE_GET_OBJ(sp[-1]), atom,
17238
2
                                  JS_PROP_WRITABLE | JS_PROP_VARREF);
17239
2
                if (!pr) {
17240
0
                    free_var_ref(rt, var_ref);
17241
0
                    goto exception;
17242
0
                }
17243
2
                pr->u.var_ref = var_ref;
17244
2
                *sp++ = JS_AtomToValue(ctx, atom);
17245
2
            }
17246
2
            BREAK;
17247
37
        CASE(OP_make_var_ref):
17248
37
            {
17249
37
                JSAtom atom;
17250
37
                atom = get_u32(pc);
17251
37
                pc += 4;
17252
17253
37
                if (JS_GetGlobalVarRef(ctx, atom, sp))
17254
0
                    goto exception;
17255
37
                sp += 2;
17256
37
            }
17257
37
            BREAK;
17258
17259
37
        CASE(OP_goto):
17260
0
            pc += (int32_t)get_u32(pc);
17261
0
            if (unlikely(js_poll_interrupts(ctx)))
17262
0
                goto exception;
17263
0
            BREAK;
17264
0
#if SHORT_OPCODES
17265
40.9k
        CASE(OP_goto16):
17266
40.9k
            pc += (int16_t)get_u16(pc);
17267
40.9k
            if (unlikely(js_poll_interrupts(ctx)))
17268
0
                goto exception;
17269
40.9k
            BREAK;
17270
81.9k
        CASE(OP_goto8):
17271
81.9k
            pc += (int8_t)pc[0];
17272
81.9k
            if (unlikely(js_poll_interrupts(ctx)))
17273
0
                goto exception;
17274
81.9k
            BREAK;
17275
81.9k
#endif
17276
81.9k
        CASE(OP_if_true):
17277
40.9k
            {
17278
40.9k
                int res;
17279
40.9k
                JSValue op1;
17280
17281
40.9k
                op1 = sp[-1];
17282
40.9k
                pc += 4;
17283
40.9k
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17284
0
                    res = JS_VALUE_GET_INT(op1);
17285
40.9k
                } else {
17286
40.9k
                    res = JS_ToBoolFree(ctx, op1);
17287
40.9k
                }
17288
40.9k
                sp--;
17289
40.9k
                if (res) {
17290
40.9k
                    pc += (int32_t)get_u32(pc - 4) - 4;
17291
40.9k
                }
17292
40.9k
                if (unlikely(js_poll_interrupts(ctx)))
17293
0
                    goto exception;
17294
40.9k
            }
17295
40.9k
            BREAK;
17296
40.9k
        CASE(OP_if_false):
17297
361
            {
17298
361
                int res;
17299
361
                JSValue op1;
17300
17301
361
                op1 = sp[-1];
17302
361
                pc += 4;
17303
361
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17304
361
                    res = JS_VALUE_GET_INT(op1);
17305
361
                } else {
17306
0
                    res = JS_ToBoolFree(ctx, op1);
17307
0
                }
17308
361
                sp--;
17309
361
                if (!res) {
17310
360
                    pc += (int32_t)get_u32(pc - 4) - 4;
17311
360
                }
17312
361
                if (unlikely(js_poll_interrupts(ctx)))
17313
0
                    goto exception;
17314
361
            }
17315
361
            BREAK;
17316
361
#if SHORT_OPCODES
17317
361
        CASE(OP_if_true8):
17318
1
            {
17319
1
                int res;
17320
1
                JSValue op1;
17321
17322
1
                op1 = sp[-1];
17323
1
                pc += 1;
17324
1
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17325
1
                    res = JS_VALUE_GET_INT(op1);
17326
1
                } else {
17327
0
                    res = JS_ToBoolFree(ctx, op1);
17328
0
                }
17329
1
                sp--;
17330
1
                if (res) {
17331
1
                    pc += (int8_t)pc[-1] - 1;
17332
1
                }
17333
1
                if (unlikely(js_poll_interrupts(ctx)))
17334
0
                    goto exception;
17335
1
            }
17336
1
            BREAK;
17337
35
        CASE(OP_if_false8):
17338
35
            {
17339
35
                int res;
17340
35
                JSValue op1;
17341
17342
35
                op1 = sp[-1];
17343
35
                pc += 1;
17344
35
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17345
34
                    res = JS_VALUE_GET_INT(op1);
17346
34
                } else {
17347
1
                    res = JS_ToBoolFree(ctx, op1);
17348
1
                }
17349
35
                sp--;
17350
35
                if (!res) {
17351
31
                    pc += (int8_t)pc[-1] - 1;
17352
31
                }
17353
35
                if (unlikely(js_poll_interrupts(ctx)))
17354
0
                    goto exception;
17355
35
            }
17356
35
            BREAK;
17357
35
#endif
17358
245k
        CASE(OP_catch):
17359
245k
            {
17360
245k
                int32_t diff;
17361
245k
                diff = get_u32(pc);
17362
245k
                sp[0] = JS_NewCatchOffset(ctx, pc + diff - b->byte_code_buf);
17363
245k
                sp++;
17364
245k
                pc += 4;
17365
245k
            }
17366
245k
            BREAK;
17367
245k
        CASE(OP_gosub):
17368
0
            {
17369
0
                int32_t diff;
17370
0
                diff = get_u32(pc);
17371
                /* XXX: should have a different tag to avoid security flaw */
17372
0
                sp[0] = JS_NewInt32(ctx, pc + 4 - b->byte_code_buf);
17373
0
                sp++;
17374
0
                pc += diff;
17375
0
            }
17376
0
            BREAK;
17377
0
        CASE(OP_ret):
17378
0
            {
17379
0
                JSValue op1;
17380
0
                uint32_t pos;
17381
0
                op1 = sp[-1];
17382
0
                if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_INT))
17383
0
                    goto ret_fail;
17384
0
                pos = JS_VALUE_GET_INT(op1);
17385
0
                if (unlikely(pos >= b->byte_code_len)) {
17386
0
                ret_fail:
17387
0
                    JS_ThrowInternalError(ctx, "invalid ret value");
17388
0
                    goto exception;
17389
0
                }
17390
0
                sp--;
17391
0
                pc = b->byte_code_buf + pos;
17392
0
            }
17393
0
            BREAK;
17394
17395
3
        CASE(OP_for_in_start):
17396
3
            if (js_for_in_start(ctx, sp))
17397
0
                goto exception;
17398
3
            BREAK;
17399
31
        CASE(OP_for_in_next):
17400
31
            if (js_for_in_next(ctx, sp))
17401
0
                goto exception;
17402
31
            sp += 2;
17403
31
            BREAK;
17404
31
        CASE(OP_for_of_start):
17405
2
            if (js_for_of_start(ctx, sp, FALSE))
17406
0
                goto exception;
17407
2
            sp += 1;
17408
2
            *sp++ = JS_NewCatchOffset(ctx, 0);
17409
2
            BREAK;
17410
360
        CASE(OP_for_of_next):
17411
360
            {
17412
360
                int offset = -3 - pc[0];
17413
360
                pc += 1;
17414
360
                if (js_for_of_next(ctx, sp, offset))
17415
0
                    goto exception;
17416
360
                sp += 2;
17417
360
            }
17418
360
            BREAK;
17419
360
        CASE(OP_for_await_of_start):
17420
0
            if (js_for_of_start(ctx, sp, TRUE))
17421
0
                goto exception;
17422
0
            sp += 1;
17423
0
            *sp++ = JS_NewCatchOffset(ctx, 0);
17424
0
            BREAK;
17425
0
        CASE(OP_iterator_get_value_done):
17426
0
            if (js_iterator_get_value_done(ctx, sp))
17427
0
                goto exception;
17428
0
            sp += 1;
17429
0
            BREAK;
17430
0
        CASE(OP_iterator_check_object):
17431
0
            if (unlikely(!JS_IsObject(sp[-1]))) {
17432
0
                JS_ThrowTypeError(ctx, "iterator must return an object");
17433
0
                goto exception;
17434
0
            }
17435
0
            BREAK;
17436
17437
1
        CASE(OP_iterator_close):
17438
            /* iter_obj next catch_offset -> */
17439
1
            sp--; /* drop the catch offset to avoid getting caught by exception */
17440
1
            JS_FreeValue(ctx, sp[-1]); /* drop the next method */
17441
1
            sp--;
17442
1
            if (!JS_IsUndefined(sp[-1])) {
17443
0
                if (JS_IteratorClose(ctx, sp[-1], FALSE))
17444
0
                    goto exception;
17445
0
                JS_FreeValue(ctx, sp[-1]);
17446
0
            }
17447
1
            sp--;
17448
1
            BREAK;
17449
1
        CASE(OP_iterator_close_return):
17450
0
            {
17451
0
                JSValue ret_val;
17452
                /* iter_obj next catch_offset ... ret_val ->
17453
                   ret_eval iter_obj next catch_offset */
17454
0
                ret_val = *--sp;
17455
0
                while (sp > stack_buf &&
17456
0
                       JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) {
17457
0
                    JS_FreeValue(ctx, *--sp);
17458
0
                }
17459
0
                if (unlikely(sp < stack_buf + 3)) {
17460
0
                    JS_ThrowInternalError(ctx, "iterator_close_return");
17461
0
                    JS_FreeValue(ctx, ret_val);
17462
0
                    goto exception;
17463
0
                }
17464
0
                sp[0] = sp[-1];
17465
0
                sp[-1] = sp[-2];
17466
0
                sp[-2] = sp[-3];
17467
0
                sp[-3] = ret_val;
17468
0
                sp++;
17469
0
            }
17470
0
            BREAK;
17471
17472
0
        CASE(OP_iterator_next):
17473
            /* stack: iter_obj next catch_offset val */
17474
0
            {
17475
0
                JSValue ret;
17476
0
                ret = JS_Call(ctx, sp[-3], sp[-4],
17477
0
                              1, (JSValueConst *)(sp - 1));
17478
0
                if (JS_IsException(ret))
17479
0
                    goto exception;
17480
0
                JS_FreeValue(ctx, sp[-1]);
17481
0
                sp[-1] = ret;
17482
0
            }
17483
0
            BREAK;
17484
17485
0
        CASE(OP_iterator_call):
17486
            /* stack: iter_obj next catch_offset val */
17487
0
            {
17488
0
                JSValue method, ret;
17489
0
                BOOL ret_flag;
17490
0
                int flags;
17491
0
                flags = *pc++;
17492
0
                method = JS_GetProperty(ctx, sp[-4], (flags & 1) ?
17493
0
                                        JS_ATOM_throw : JS_ATOM_return);
17494
0
                if (JS_IsException(method))
17495
0
                    goto exception;
17496
0
                if (JS_IsUndefined(method) || JS_IsNull(method)) {
17497
0
                    ret_flag = TRUE;
17498
0
                } else {
17499
0
                    if (flags & 2) {
17500
                        /* no argument */
17501
0
                        ret = JS_CallFree(ctx, method, sp[-4],
17502
0
                                          0, NULL);
17503
0
                    } else {
17504
0
                        ret = JS_CallFree(ctx, method, sp[-4],
17505
0
                                          1, (JSValueConst *)(sp - 1));
17506
0
                    }
17507
0
                    if (JS_IsException(ret))
17508
0
                        goto exception;
17509
0
                    JS_FreeValue(ctx, sp[-1]);
17510
0
                    sp[-1] = ret;
17511
0
                    ret_flag = FALSE;
17512
0
                }
17513
0
                sp[0] = JS_NewBool(ctx, ret_flag);
17514
0
                sp += 1;
17515
0
            }
17516
0
            BREAK;
17517
17518
81.9k
        CASE(OP_lnot):
17519
81.9k
            {
17520
81.9k
                int res;
17521
81.9k
                JSValue op1;
17522
17523
81.9k
                op1 = sp[-1];
17524
81.9k
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17525
18
                    res = JS_VALUE_GET_INT(op1) != 0;
17526
81.9k
                } else {
17527
81.9k
                    res = JS_ToBoolFree(ctx, op1);
17528
81.9k
                }
17529
81.9k
                sp[-1] = JS_NewBool(ctx, !res);
17530
81.9k
            }
17531
81.9k
            BREAK;
17532
17533
81.9k
        CASE(OP_get_field):
17534
29
            {
17535
29
                JSValue val;
17536
29
                JSAtom atom;
17537
29
                atom = get_u32(pc);
17538
29
                pc += 4;
17539
17540
29
                val = JS_GetProperty(ctx, sp[-1], atom);
17541
29
                if (unlikely(JS_IsException(val)))
17542
0
                    goto exception;
17543
29
                JS_FreeValue(ctx, sp[-1]);
17544
29
                sp[-1] = val;
17545
29
            }
17546
29
            BREAK;
17547
17548
29
        CASE(OP_get_field2):
17549
7
            {
17550
7
                JSValue val;
17551
7
                JSAtom atom;
17552
7
                atom = get_u32(pc);
17553
7
                pc += 4;
17554
17555
7
                val = JS_GetProperty(ctx, sp[-1], atom);
17556
7
                if (unlikely(JS_IsException(val)))
17557
0
                    goto exception;
17558
7
                *sp++ = val;
17559
7
            }
17560
7
            BREAK;
17561
17562
7
        CASE(OP_put_field):
17563
1
            {
17564
1
                int ret;
17565
1
                JSAtom atom;
17566
1
                atom = get_u32(pc);
17567
1
                pc += 4;
17568
17569
1
                ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1],
17570
1
                                             JS_PROP_THROW_STRICT);
17571
1
                JS_FreeValue(ctx, sp[-2]);
17572
1
                sp -= 2;
17573
1
                if (unlikely(ret < 0))
17574
0
                    goto exception;
17575
1
            }
17576
1
            BREAK;
17577
17578
41.3k
        CASE(OP_private_symbol):
17579
41.3k
            {
17580
41.3k
                JSAtom atom;
17581
41.3k
                JSValue val;
17582
                
17583
41.3k
                atom = get_u32(pc);
17584
41.3k
                pc += 4;
17585
41.3k
                val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE);
17586
41.3k
                if (JS_IsException(val))
17587
0
                    goto exception;
17588
41.3k
                *sp++ = val;
17589
41.3k
            }
17590
41.3k
            BREAK;
17591
            
17592
41.3k
        CASE(OP_get_private_field):
17593
0
            {
17594
0
                JSValue val;
17595
17596
0
                val = JS_GetPrivateField(ctx, sp[-2], sp[-1]);
17597
0
                JS_FreeValue(ctx, sp[-1]);
17598
0
                JS_FreeValue(ctx, sp[-2]);
17599
0
                sp[-2] = val;
17600
0
                sp--;
17601
0
                if (unlikely(JS_IsException(val)))
17602
0
                    goto exception;
17603
0
            }
17604
0
            BREAK;
17605
17606
0
        CASE(OP_put_private_field):
17607
0
            {
17608
0
                int ret;
17609
0
                ret = JS_SetPrivateField(ctx, sp[-3], sp[-1], sp[-2]);
17610
0
                JS_FreeValue(ctx, sp[-3]);
17611
0
                JS_FreeValue(ctx, sp[-1]);
17612
0
                sp -= 3;
17613
0
                if (unlikely(ret < 0))
17614
0
                    goto exception;
17615
0
            }
17616
0
            BREAK;
17617
17618
2
        CASE(OP_define_private_field):
17619
2
            {
17620
2
                int ret;
17621
2
                ret = JS_DefinePrivateField(ctx, sp[-3], sp[-2], sp[-1]);
17622
2
                JS_FreeValue(ctx, sp[-2]);
17623
2
                sp -= 2;
17624
2
                if (unlikely(ret < 0))
17625
0
                    goto exception;
17626
2
            }
17627
2
            BREAK;
17628
17629
2
        CASE(OP_define_field):
17630
0
            {
17631
0
                int ret;
17632
0
                JSAtom atom;
17633
0
                atom = get_u32(pc);
17634
0
                pc += 4;
17635
17636
0
                ret = JS_DefinePropertyValue(ctx, sp[-2], atom, sp[-1],
17637
0
                                             JS_PROP_C_W_E | JS_PROP_THROW);
17638
0
                sp--;
17639
0
                if (unlikely(ret < 0))
17640
0
                    goto exception;
17641
0
            }
17642
0
            BREAK;
17643
17644
245k
        CASE(OP_set_name):
17645
245k
            {
17646
245k
                int ret;
17647
245k
                JSAtom atom;
17648
245k
                atom = get_u32(pc);
17649
245k
                pc += 4;
17650
17651
245k
                ret = JS_DefineObjectName(ctx, sp[-1], atom, JS_PROP_CONFIGURABLE);
17652
245k
                if (unlikely(ret < 0))
17653
0
                    goto exception;
17654
245k
            }
17655
245k
            BREAK;
17656
245k
        CASE(OP_set_name_computed):
17657
0
            {
17658
0
                int ret;
17659
0
                ret = JS_DefineObjectNameComputed(ctx, sp[-1], sp[-2], JS_PROP_CONFIGURABLE);
17660
0
                if (unlikely(ret < 0))
17661
0
                    goto exception;
17662
0
            }
17663
0
            BREAK;
17664
0
        CASE(OP_set_proto):
17665
0
            {
17666
0
                JSValue proto;
17667
0
                proto = sp[-1];
17668
0
                if (JS_IsObject(proto) || JS_IsNull(proto)) {
17669
0
                    if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0)
17670
0
                        goto exception;
17671
0
                }
17672
0
                JS_FreeValue(ctx, proto);
17673
0
                sp--;
17674
0
            }
17675
0
            BREAK;
17676
41.3k
        CASE(OP_set_home_object):
17677
41.3k
            js_method_set_home_object(ctx, sp[-1], sp[-2]);
17678
41.3k
            BREAK;
17679
41.3k
        CASE(OP_define_method):
17680
46.8k
        CASE(OP_define_method_computed):
17681
46.8k
            {
17682
46.8k
                JSValue getter, setter, value;
17683
46.8k
                JSValueConst obj;
17684
46.8k
                JSAtom atom;
17685
46.8k
                int flags, ret, op_flags;
17686
46.8k
                BOOL is_computed;
17687
47.0k
#define OP_DEFINE_METHOD_METHOD 0
17688
46.8k
#define OP_DEFINE_METHOD_GETTER 1
17689
46.8k
#define OP_DEFINE_METHOD_SETTER 2
17690
46.8k
#define OP_DEFINE_METHOD_ENUMERABLE 4
17691
17692
46.8k
                is_computed = (opcode == OP_define_method_computed);
17693
46.8k
                if (is_computed) {
17694
46.8k
                    atom = JS_ValueToAtom(ctx, sp[-2]);
17695
46.8k
                    if (unlikely(atom == JS_ATOM_NULL))
17696
0
                        goto exception;
17697
46.8k
                    opcode += OP_define_method - OP_define_method_computed;
17698
46.8k
                } else {
17699
0
                    atom = get_u32(pc);
17700
0
                    pc += 4;
17701
0
                }
17702
46.8k
                op_flags = *pc++;
17703
17704
46.8k
                obj = sp[-2 - is_computed];
17705
46.8k
                flags = JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE |
17706
46.8k
                    JS_PROP_HAS_ENUMERABLE | JS_PROP_THROW;
17707
46.8k
                if (op_flags & OP_DEFINE_METHOD_ENUMERABLE)
17708
0
                    flags |= JS_PROP_ENUMERABLE;
17709
46.8k
                op_flags &= 3;
17710
46.8k
                value = JS_UNDEFINED;
17711
46.8k
                getter = JS_UNDEFINED;
17712
46.8k
                setter = JS_UNDEFINED;
17713
46.8k
                if (op_flags == OP_DEFINE_METHOD_METHOD) {
17714
46.8k
                    value = sp[-1];
17715
46.8k
                    flags |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE;
17716
46.8k
                } else if (op_flags == OP_DEFINE_METHOD_GETTER) {
17717
0
                    getter = sp[-1];
17718
0
                    flags |= JS_PROP_HAS_GET;
17719
0
                } else {
17720
0
                    setter = sp[-1];
17721
0
                    flags |= JS_PROP_HAS_SET;
17722
0
                }
17723
46.8k
                ret = js_method_set_properties(ctx, sp[-1], atom, flags, obj);
17724
46.8k
                if (ret >= 0) {
17725
46.8k
                    ret = JS_DefineProperty(ctx, obj, atom, value,
17726
46.8k
                                            getter, setter, flags);
17727
46.8k
                }
17728
46.8k
                JS_FreeValue(ctx, sp[-1]);
17729
46.8k
                if (is_computed) {
17730
46.8k
                    JS_FreeAtom(ctx, atom);
17731
46.8k
                    JS_FreeValue(ctx, sp[-2]);
17732
46.8k
                }
17733
46.8k
                sp -= 1 + is_computed;
17734
46.8k
                if (unlikely(ret < 0))
17735
0
                    goto exception;
17736
46.8k
            }
17737
46.8k
            BREAK;
17738
17739
46.8k
        CASE(OP_define_class):
17740
41.3k
        CASE(OP_define_class_computed):
17741
41.3k
            {
17742
41.3k
                int class_flags;
17743
41.3k
                JSAtom atom;
17744
                
17745
41.3k
                atom = get_u32(pc);
17746
41.3k
                class_flags = pc[4];
17747
41.3k
                pc += 5;
17748
41.3k
                if (js_op_define_class(ctx, sp, atom, class_flags,
17749
41.3k
                                       var_refs, sf,
17750
41.3k
                                       (opcode == OP_define_class_computed)) < 0)
17751
0
                    goto exception;
17752
41.3k
            }
17753
41.3k
            BREAK;
17754
17755
41.3k
        CASE(OP_get_array_el):
17756
0
            {
17757
0
                JSValue val;
17758
17759
0
                val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
17760
0
                JS_FreeValue(ctx, sp[-2]);
17761
0
                sp[-2] = val;
17762
0
                sp--;
17763
0
                if (unlikely(JS_IsException(val)))
17764
0
                    goto exception;
17765
0
            }
17766
0
            BREAK;
17767
17768
0
        CASE(OP_get_array_el2):
17769
0
            {
17770
0
                JSValue val;
17771
17772
0
                val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
17773
0
                sp[-1] = val;
17774
0
                if (unlikely(JS_IsException(val)))
17775
0
                    goto exception;
17776
0
            }
17777
0
            BREAK;
17778
17779
0
        CASE(OP_get_ref_value):
17780
0
            {
17781
0
                JSValue val;
17782
0
                if (unlikely(JS_IsUndefined(sp[-2]))) {
17783
0
                    JSAtom atom = JS_ValueToAtom(ctx, sp[-1]);
17784
0
                    if (atom != JS_ATOM_NULL) {
17785
0
                        JS_ThrowReferenceErrorNotDefined(ctx, atom);
17786
0
                        JS_FreeAtom(ctx, atom);
17787
0
                    }
17788
0
                    goto exception;
17789
0
                }
17790
0
                val = JS_GetPropertyValue(ctx, sp[-2],
17791
0
                                          JS_DupValue(ctx, sp[-1]));
17792
0
                if (unlikely(JS_IsException(val)))
17793
0
                    goto exception;
17794
0
                sp[0] = val;
17795
0
                sp++;
17796
0
            }
17797
0
            BREAK;
17798
17799
0
        CASE(OP_get_super_value):
17800
0
            {
17801
0
                JSValue val;
17802
0
                JSAtom atom;
17803
0
                atom = JS_ValueToAtom(ctx, sp[-1]);
17804
0
                if (unlikely(atom == JS_ATOM_NULL))
17805
0
                    goto exception;
17806
0
                val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], FALSE);
17807
0
                JS_FreeAtom(ctx, atom);
17808
0
                if (unlikely(JS_IsException(val)))
17809
0
                    goto exception;
17810
0
                JS_FreeValue(ctx, sp[-1]);
17811
0
                JS_FreeValue(ctx, sp[-2]);
17812
0
                JS_FreeValue(ctx, sp[-3]);
17813
0
                sp[-3] = val;
17814
0
                sp -= 2;
17815
0
            }
17816
0
            BREAK;
17817
17818
0
        CASE(OP_put_array_el):
17819
0
            {
17820
0
                int ret;
17821
17822
0
                ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
17823
0
                JS_FreeValue(ctx, sp[-3]);
17824
0
                sp -= 3;
17825
0
                if (unlikely(ret < 0))
17826
0
                    goto exception;
17827
0
            }
17828
0
            BREAK;
17829
17830
39
        CASE(OP_put_ref_value):
17831
39
            {
17832
39
                int ret, flags;
17833
39
                flags = JS_PROP_THROW_STRICT;
17834
39
                if (unlikely(JS_IsUndefined(sp[-3]))) {
17835
3
                    if (is_strict_mode(ctx)) {
17836
0
                        JSAtom atom = JS_ValueToAtom(ctx, sp[-2]);
17837
0
                        if (atom != JS_ATOM_NULL) {
17838
0
                            JS_ThrowReferenceErrorNotDefined(ctx, atom);
17839
0
                            JS_FreeAtom(ctx, atom);
17840
0
                        }
17841
0
                        goto exception;
17842
3
                    } else {
17843
3
                        sp[-3] = JS_DupValue(ctx, ctx->global_obj);
17844
3
                    }
17845
36
                } else {
17846
36
                    if (is_strict_mode(ctx))
17847
0
                        flags |= JS_PROP_NO_ADD;
17848
36
                }
17849
39
                ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], flags);
17850
39
                JS_FreeValue(ctx, sp[-3]);
17851
39
                sp -= 3;
17852
39
                if (unlikely(ret < 0))
17853
0
                    goto exception;
17854
39
            }
17855
39
            BREAK;
17856
17857
39
        CASE(OP_put_super_value):
17858
0
            {
17859
0
                int ret;
17860
0
                JSAtom atom;
17861
0
                if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) {
17862
0
                    JS_ThrowTypeErrorNotAnObject(ctx);
17863
0
                    goto exception;
17864
0
                }
17865
0
                atom = JS_ValueToAtom(ctx, sp[-2]);
17866
0
                if (unlikely(atom == JS_ATOM_NULL))
17867
0
                    goto exception;
17868
0
                ret = JS_SetPropertyGeneric(ctx, sp[-3], atom, sp[-1], sp[-4],
17869
0
                                            JS_PROP_THROW_STRICT);
17870
0
                JS_FreeAtom(ctx, atom);
17871
0
                JS_FreeValue(ctx, sp[-4]);
17872
0
                JS_FreeValue(ctx, sp[-3]);
17873
0
                JS_FreeValue(ctx, sp[-2]);
17874
0
                sp -= 4;
17875
0
                if (ret < 0)
17876
0
                    goto exception;
17877
0
            }
17878
0
            BREAK;
17879
17880
3
        CASE(OP_define_array_el):
17881
3
            {
17882
3
                int ret;
17883
3
                ret = JS_DefinePropertyValueValue(ctx, sp[-3], JS_DupValue(ctx, sp[-2]), sp[-1],
17884
3
                                                  JS_PROP_C_W_E | JS_PROP_THROW);
17885
3
                sp -= 1;
17886
3
                if (unlikely(ret < 0))
17887
0
                    goto exception;
17888
3
            }
17889
3
            BREAK;
17890
17891
3
        CASE(OP_append):    /* array pos enumobj -- array pos */
17892
1
            {
17893
1
                if (js_append_enumerate(ctx, sp))
17894
0
                    goto exception;
17895
1
                JS_FreeValue(ctx, *--sp);
17896
1
            }
17897
1
            BREAK;
17898
17899
24
        CASE(OP_copy_data_properties):    /* target source excludeList */
17900
24
            {
17901
                /* stack offsets (-1 based):
17902
                   2 bits for target,
17903
                   3 bits for source,
17904
                   2 bits for exclusionList */
17905
24
                int mask;
17906
17907
24
                mask = *pc++;
17908
24
                if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)],
17909
24
                                          sp[-1 - ((mask >> 2) & 7)],
17910
24
                                          sp[-1 - ((mask >> 5) & 7)], 0))
17911
0
                    goto exception;
17912
24
            }
17913
24
            BREAK;
17914
17915
72.0k
        CASE(OP_add):
17916
72.0k
            {
17917
72.0k
                JSValue op1, op2;
17918
72.0k
                op1 = sp[-2];
17919
72.0k
                op2 = sp[-1];
17920
72.0k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
17921
56
                    int64_t r;
17922
56
                    r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2);
17923
56
                    if (unlikely((int)r != r))
17924
0
                        goto add_slow;
17925
56
                    sp[-2] = JS_NewInt32(ctx, r);
17926
56
                    sp--;
17927
71.9k
                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
17928
0
                    sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) +
17929
0
                                             JS_VALUE_GET_FLOAT64(op2));
17930
0
                    sp--;
17931
71.9k
                } else {
17932
71.9k
                add_slow:
17933
71.9k
                    if (js_add_slow(ctx, sp))
17934
0
                        goto exception;
17935
71.9k
                    sp--;
17936
71.9k
                }
17937
72.0k
            }
17938
72.0k
            BREAK;
17939
72.0k
        CASE(OP_add_loc):
17940
0
            {
17941
0
                JSValue *pv;
17942
0
                int idx;
17943
0
                idx = *pc;
17944
0
                pc += 1;
17945
17946
0
                pv = &var_buf[idx];
17947
0
                if (likely(JS_VALUE_IS_BOTH_INT(*pv, sp[-1]))) {
17948
0
                    int64_t r;
17949
0
                    r = (int64_t)JS_VALUE_GET_INT(*pv) +
17950
0
                        JS_VALUE_GET_INT(sp[-1]);
17951
0
                    if (unlikely((int)r != r))
17952
0
                        goto add_loc_slow;
17953
0
                    *pv = JS_NewInt32(ctx, r);
17954
0
                    sp--;
17955
0
                } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) {
17956
0
                    JSValue op1;
17957
0
                    op1 = sp[-1];
17958
0
                    sp--;
17959
0
                    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
17960
0
                    if (JS_IsException(op1))
17961
0
                        goto exception;
17962
0
                    op1 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op1);
17963
0
                    if (JS_IsException(op1))
17964
0
                        goto exception;
17965
0
                    set_value(ctx, pv, op1);
17966
0
                } else {
17967
0
                    JSValue ops[2];
17968
0
                add_loc_slow:
17969
                    /* In case of exception, js_add_slow frees ops[0]
17970
                       and ops[1], so we must duplicate *pv */
17971
0
                    ops[0] = JS_DupValue(ctx, *pv);
17972
0
                    ops[1] = sp[-1];
17973
0
                    sp--;
17974
0
                    if (js_add_slow(ctx, ops + 2))
17975
0
                        goto exception;
17976
0
                    set_value(ctx, pv, ops[0]);
17977
0
                }
17978
0
            }
17979
0
            BREAK;
17980
40.9k
        CASE(OP_sub):
17981
40.9k
            {
17982
40.9k
                JSValue op1, op2;
17983
40.9k
                op1 = sp[-2];
17984
40.9k
                op2 = sp[-1];
17985
40.9k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
17986
0
                    int64_t r;
17987
0
                    r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2);
17988
0
                    if (unlikely((int)r != r))
17989
0
                        goto binary_arith_slow;
17990
0
                    sp[-2] = JS_NewInt32(ctx, r);
17991
0
                    sp--;
17992
40.9k
                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
17993
0
                    sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) -
17994
0
                                             JS_VALUE_GET_FLOAT64(op2));
17995
0
                    sp--;
17996
40.9k
                } else {
17997
40.9k
                    goto binary_arith_slow;
17998
40.9k
                }
17999
40.9k
            }
18000
0
            BREAK;
18001
71.9k
        CASE(OP_mul):
18002
71.9k
            {
18003
71.9k
                JSValue op1, op2;
18004
71.9k
                double d;
18005
71.9k
                op1 = sp[-2];
18006
71.9k
                op2 = sp[-1];
18007
71.9k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18008
5
                    int32_t v1, v2;
18009
5
                    int64_t r;
18010
5
                    v1 = JS_VALUE_GET_INT(op1);
18011
5
                    v2 = JS_VALUE_GET_INT(op2);
18012
5
                    r = (int64_t)v1 * v2;
18013
5
                    if (unlikely((int)r != r)) {
18014
0
#ifdef CONFIG_BIGNUM
18015
0
                        if (unlikely(sf->js_mode & JS_MODE_MATH) &&
18016
0
                            (r < -MAX_SAFE_INTEGER || r > MAX_SAFE_INTEGER))
18017
0
                            goto binary_arith_slow;
18018
0
#endif
18019
0
                        d = (double)r;
18020
0
                        goto mul_fp_res;
18021
0
                    }
18022
                    /* need to test zero case for -0 result */
18023
5
                    if (unlikely(r == 0 && (v1 | v2) < 0)) {
18024
0
                        d = -0.0;
18025
0
                        goto mul_fp_res;
18026
0
                    }
18027
5
                    sp[-2] = JS_NewInt32(ctx, r);
18028
5
                    sp--;
18029
71.9k
                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
18030
0
#ifdef CONFIG_BIGNUM
18031
0
                    if (unlikely(sf->js_mode & JS_MODE_MATH))
18032
0
                        goto binary_arith_slow;
18033
0
#endif
18034
0
                    d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);
18035
0
                mul_fp_res:
18036
0
                    sp[-2] = __JS_NewFloat64(ctx, d);
18037
0
                    sp--;
18038
71.9k
                } else {
18039
71.9k
                    goto binary_arith_slow;
18040
71.9k
                }
18041
71.9k
            }
18042
5
            BREAK;
18043
10
        CASE(OP_div):
18044
10
            {
18045
10
                JSValue op1, op2;
18046
10
                op1 = sp[-2];
18047
10
                op2 = sp[-1];
18048
10
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18049
0
                    int v1, v2;
18050
0
                    if (unlikely(sf->js_mode & JS_MODE_MATH))
18051
0
                        goto binary_arith_slow;
18052
0
                    v1 = JS_VALUE_GET_INT(op1);
18053
0
                    v2 = JS_VALUE_GET_INT(op2);
18054
0
                    sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
18055
0
                    sp--;
18056
10
                } else {
18057
10
                    goto binary_arith_slow;
18058
10
                }
18059
10
            }
18060
0
            BREAK;
18061
0
        CASE(OP_mod):
18062
0
#ifdef CONFIG_BIGNUM
18063
0
        CASE(OP_math_mod):
18064
0
#endif
18065
0
            {
18066
0
                JSValue op1, op2;
18067
0
                op1 = sp[-2];
18068
0
                op2 = sp[-1];
18069
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18070
0
                    int v1, v2, r;
18071
0
                    v1 = JS_VALUE_GET_INT(op1);
18072
0
                    v2 = JS_VALUE_GET_INT(op2);
18073
                    /* We must avoid v2 = 0, v1 = INT32_MIN and v2 =
18074
                       -1 and the cases where the result is -0. */
18075
0
                    if (unlikely(v1 < 0 || v2 <= 0))
18076
0
                        goto binary_arith_slow;
18077
0
                    r = v1 % v2;
18078
0
                    sp[-2] = JS_NewInt32(ctx, r);
18079
0
                    sp--;
18080
0
                } else {
18081
0
                    goto binary_arith_slow;
18082
0
                }
18083
0
            }
18084
0
            BREAK;
18085
1
        CASE(OP_pow):
18086
112k
        binary_arith_slow:
18087
112k
            if (js_binary_arith_slow(ctx, sp, opcode))
18088
0
                goto exception;
18089
112k
            sp--;
18090
112k
            BREAK;
18091
18092
112k
        CASE(OP_plus):
18093
0
            {
18094
0
                JSValue op1;
18095
0
                uint32_t tag;
18096
0
                op1 = sp[-1];
18097
0
                tag = JS_VALUE_GET_TAG(op1);
18098
0
                if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) {
18099
0
                } else {
18100
0
                    if (js_unary_arith_slow(ctx, sp, opcode))
18101
0
                        goto exception;
18102
0
                }
18103
0
            }
18104
0
            BREAK;
18105
40.9k
        CASE(OP_neg):
18106
40.9k
            {
18107
40.9k
                JSValue op1;
18108
40.9k
                uint32_t tag;
18109
40.9k
                int val;
18110
40.9k
                double d;
18111
40.9k
                op1 = sp[-1];
18112
40.9k
                tag = JS_VALUE_GET_TAG(op1);
18113
40.9k
                if (tag == JS_TAG_INT) {
18114
0
                    val = JS_VALUE_GET_INT(op1);
18115
                    /* Note: -0 cannot be expressed as integer */
18116
0
                    if (unlikely(val == 0)) {
18117
0
                        d = -0.0;
18118
0
                        goto neg_fp_res;
18119
0
                    }
18120
0
                    if (unlikely(val == INT32_MIN)) {
18121
0
                        d = -(double)val;
18122
0
                        goto neg_fp_res;
18123
0
                    }
18124
0
                    sp[-1] = JS_NewInt32(ctx, -val);
18125
40.9k
                } else if (JS_TAG_IS_FLOAT64(tag)) {
18126
40.9k
                    d = -JS_VALUE_GET_FLOAT64(op1);
18127
40.9k
                neg_fp_res:
18128
40.9k
                    sp[-1] = __JS_NewFloat64(ctx, d);
18129
40.9k
                } else {
18130
11
                    if (js_unary_arith_slow(ctx, sp, opcode))
18131
0
                        goto exception;
18132
11
                }
18133
40.9k
            }
18134
40.9k
            BREAK;
18135
40.9k
        CASE(OP_inc):
18136
40.9k
            {
18137
40.9k
                JSValue op1;
18138
40.9k
                int val;
18139
40.9k
                op1 = sp[-1];
18140
40.9k
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18141
2
                    val = JS_VALUE_GET_INT(op1);
18142
2
                    if (unlikely(val == INT32_MAX))
18143
0
                        goto inc_slow;
18144
2
                    sp[-1] = JS_NewInt32(ctx, val + 1);
18145
40.9k
                } else {
18146
40.9k
                inc_slow:
18147
40.9k
                    if (js_unary_arith_slow(ctx, sp, opcode))
18148
0
                        goto exception;
18149
40.9k
                }
18150
40.9k
            }
18151
40.9k
            BREAK;
18152
40.9k
        CASE(OP_dec):
18153
0
            {
18154
0
                JSValue op1;
18155
0
                int val;
18156
0
                op1 = sp[-1];
18157
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18158
0
                    val = JS_VALUE_GET_INT(op1);
18159
0
                    if (unlikely(val == INT32_MIN))
18160
0
                        goto dec_slow;
18161
0
                    sp[-1] = JS_NewInt32(ctx, val - 1);
18162
0
                } else {
18163
0
                dec_slow:
18164
0
                    if (js_unary_arith_slow(ctx, sp, opcode))
18165
0
                        goto exception;
18166
0
                }
18167
0
            }
18168
0
            BREAK;
18169
0
        CASE(OP_post_inc):
18170
0
        CASE(OP_post_dec):
18171
0
            if (js_post_inc_slow(ctx, sp, opcode))
18172
0
                goto exception;
18173
0
            sp++;
18174
0
            BREAK;
18175
0
        CASE(OP_inc_loc):
18176
0
            {
18177
0
                JSValue op1;
18178
0
                int val;
18179
0
                int idx;
18180
0
                idx = *pc;
18181
0
                pc += 1;
18182
18183
0
                op1 = var_buf[idx];
18184
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18185
0
                    val = JS_VALUE_GET_INT(op1);
18186
0
                    if (unlikely(val == INT32_MAX))
18187
0
                        goto inc_loc_slow;
18188
0
                    var_buf[idx] = JS_NewInt32(ctx, val + 1);
18189
0
                } else {
18190
0
                inc_loc_slow:
18191
                    /* must duplicate otherwise the variable value may
18192
                       be destroyed before JS code accesses it */
18193
0
                    op1 = JS_DupValue(ctx, op1);
18194
0
                    if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc))
18195
0
                        goto exception;
18196
0
                    set_value(ctx, &var_buf[idx], op1);
18197
0
                }
18198
0
            }
18199
0
            BREAK;
18200
0
        CASE(OP_dec_loc):
18201
0
            {
18202
0
                JSValue op1;
18203
0
                int val;
18204
0
                int idx;
18205
0
                idx = *pc;
18206
0
                pc += 1;
18207
18208
0
                op1 = var_buf[idx];
18209
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18210
0
                    val = JS_VALUE_GET_INT(op1);
18211
0
                    if (unlikely(val == INT32_MIN))
18212
0
                        goto dec_loc_slow;
18213
0
                    var_buf[idx] = JS_NewInt32(ctx, val - 1);
18214
0
                } else {
18215
0
                dec_loc_slow:
18216
                    /* must duplicate otherwise the variable value may
18217
                       be destroyed before JS code accesses it */
18218
0
                    op1 = JS_DupValue(ctx, op1);
18219
0
                    if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec))
18220
0
                        goto exception;
18221
0
                    set_value(ctx, &var_buf[idx], op1);
18222
0
                }
18223
0
            }
18224
0
            BREAK;
18225
7
        CASE(OP_not):
18226
7
            {
18227
7
                JSValue op1;
18228
7
                op1 = sp[-1];
18229
7
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18230
0
                    sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1));
18231
7
                } else {
18232
7
                    if (js_not_slow(ctx, sp))
18233
0
                        goto exception;
18234
7
                }
18235
7
            }
18236
7
            BREAK;
18237
18238
7
        CASE(OP_shl):
18239
0
            {
18240
0
                JSValue op1, op2;
18241
0
                op1 = sp[-2];
18242
0
                op2 = sp[-1];
18243
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18244
0
                    uint32_t v1, v2;
18245
0
                    v1 = JS_VALUE_GET_INT(op1);
18246
0
                    v2 = JS_VALUE_GET_INT(op2);
18247
0
#ifdef CONFIG_BIGNUM
18248
0
                    {
18249
0
                        int64_t r;
18250
0
                        if (unlikely(sf->js_mode & JS_MODE_MATH)) {
18251
0
                            if (v2 > 0x1f)
18252
0
                                goto shl_slow;
18253
0
                            r = (int64_t)v1 << v2;
18254
0
                            if ((int)r != r)
18255
0
                                goto shl_slow;
18256
0
                        } else {
18257
0
                            v2 &= 0x1f;
18258
0
                        }
18259
0
                    }
18260
#else
18261
                    v2 &= 0x1f;
18262
#endif
18263
0
                    sp[-2] = JS_NewInt32(ctx, v1 << v2);
18264
0
                    sp--;
18265
0
                } else {
18266
0
#ifdef CONFIG_BIGNUM
18267
0
                shl_slow:
18268
0
#endif
18269
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
18270
0
                        goto exception;
18271
0
                    sp--;
18272
0
                }
18273
0
            }
18274
0
            BREAK;
18275
0
        CASE(OP_shr):
18276
0
            {
18277
0
                JSValue op1, op2;
18278
0
                op1 = sp[-2];
18279
0
                op2 = sp[-1];
18280
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18281
0
                    uint32_t v2;
18282
0
                    v2 = JS_VALUE_GET_INT(op2);
18283
                    /* v1 >>> v2 retains its JS semantics if CONFIG_BIGNUM */
18284
0
                    v2 &= 0x1f;
18285
0
                    sp[-2] = JS_NewUint32(ctx,
18286
0
                                          (uint32_t)JS_VALUE_GET_INT(op1) >>
18287
0
                                          v2);
18288
0
                    sp--;
18289
0
                } else {
18290
0
                    if (js_shr_slow(ctx, sp))
18291
0
                        goto exception;
18292
0
                    sp--;
18293
0
                }
18294
0
            }
18295
0
            BREAK;
18296
0
        CASE(OP_sar):
18297
0
            {
18298
0
                JSValue op1, op2;
18299
0
                op1 = sp[-2];
18300
0
                op2 = sp[-1];
18301
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18302
0
                    uint32_t v2;
18303
0
                    v2 = JS_VALUE_GET_INT(op2);
18304
0
#ifdef CONFIG_BIGNUM
18305
0
                    if (unlikely(v2 > 0x1f)) {
18306
0
                        if (unlikely(sf->js_mode & JS_MODE_MATH))
18307
0
                            goto sar_slow;
18308
0
                        else
18309
0
                            v2 &= 0x1f;
18310
0
                    }
18311
#else
18312
                    v2 &= 0x1f;
18313
#endif
18314
0
                    sp[-2] = JS_NewInt32(ctx,
18315
0
                                          (int)JS_VALUE_GET_INT(op1) >> v2);
18316
0
                    sp--;
18317
0
                } else {
18318
0
#ifdef CONFIG_BIGNUM
18319
0
                sar_slow:
18320
0
#endif
18321
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
18322
0
                        goto exception;
18323
0
                    sp--;
18324
0
                }
18325
0
            }
18326
0
            BREAK;
18327
41.0k
        CASE(OP_and):
18328
41.0k
            {
18329
41.0k
                JSValue op1, op2;
18330
41.0k
                op1 = sp[-2];
18331
41.0k
                op2 = sp[-1];
18332
41.0k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18333
0
                    sp[-2] = JS_NewInt32(ctx,
18334
0
                                         JS_VALUE_GET_INT(op1) &
18335
0
                                         JS_VALUE_GET_INT(op2));
18336
0
                    sp--;
18337
41.0k
                } else {
18338
41.0k
                    if (js_binary_logic_slow(ctx, sp, opcode))
18339
0
                        goto exception;
18340
41.0k
                    sp--;
18341
41.0k
                }
18342
41.0k
            }
18343
41.0k
            BREAK;
18344
41.0k
        CASE(OP_or):
18345
0
            {
18346
0
                JSValue op1, op2;
18347
0
                op1 = sp[-2];
18348
0
                op2 = sp[-1];
18349
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18350
0
                    sp[-2] = JS_NewInt32(ctx,
18351
0
                                         JS_VALUE_GET_INT(op1) |
18352
0
                                         JS_VALUE_GET_INT(op2));
18353
0
                    sp--;
18354
0
                } else {
18355
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
18356
0
                        goto exception;
18357
0
                    sp--;
18358
0
                }
18359
0
            }
18360
0
            BREAK;
18361
0
        CASE(OP_xor):
18362
0
            {
18363
0
                JSValue op1, op2;
18364
0
                op1 = sp[-2];
18365
0
                op2 = sp[-1];
18366
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18367
0
                    sp[-2] = JS_NewInt32(ctx,
18368
0
                                         JS_VALUE_GET_INT(op1) ^
18369
0
                                         JS_VALUE_GET_INT(op2));
18370
0
                    sp--;
18371
0
                } else {
18372
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
18373
0
                        goto exception;
18374
0
                    sp--;
18375
0
                }
18376
0
            }
18377
0
            BREAK;
18378
18379
18380
0
#define OP_CMP(opcode, binary_op, slow_call)              \
18381
40.9k
            CASE(opcode):                                 \
18382
40.9k
                {                                         \
18383
40.9k
                JSValue op1, op2;                         \
18384
40.9k
                op1 = sp[-2];                             \
18385
40.9k
                op2 = sp[-1];                                   \
18386
40.9k
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {           \
18387
1
                    sp[-2] = JS_NewBool(ctx, JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \
18388
1
                    sp--;                                               \
18389
40.9k
                } else {                                                \
18390
40.9k
                    if (slow_call)                                      \
18391
40.9k
                        goto exception;                                 \
18392
40.9k
                    sp--;                                               \
18393
40.9k
                }                                                       \
18394
40.9k
                }                                                       \
18395
40.9k
            BREAK
18396
18397
8
            OP_CMP(OP_lt, <, js_relational_slow(ctx, sp, opcode));
18398
8
            OP_CMP(OP_lte, <=, js_relational_slow(ctx, sp, opcode));
18399
81.9k
            OP_CMP(OP_gt, >, js_relational_slow(ctx, sp, opcode));
18400
81.9k
            OP_CMP(OP_gte, >=, js_relational_slow(ctx, sp, opcode));
18401
4
            OP_CMP(OP_eq, ==, js_eq_slow(ctx, sp, 0));
18402
4
            OP_CMP(OP_neq, !=, js_eq_slow(ctx, sp, 1));
18403
0
            OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0));
18404
0
            OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1));
18405
18406
0
#ifdef CONFIG_BIGNUM
18407
0
        CASE(OP_mul_pow10):
18408
0
            if (rt->bigfloat_ops.mul_pow10(ctx, sp))
18409
0
                goto exception;
18410
0
            sp--;
18411
0
            BREAK;
18412
0
#endif
18413
0
        CASE(OP_in):
18414
0
            if (js_operator_in(ctx, sp))
18415
0
                goto exception;
18416
0
            sp--;
18417
0
            BREAK;
18418
0
        CASE(OP_instanceof):
18419
0
            if (js_operator_instanceof(ctx, sp))
18420
0
                goto exception;
18421
0
            sp--;
18422
0
            BREAK;
18423
0
        CASE(OP_typeof):
18424
0
            {
18425
0
                JSValue op1;
18426
0
                JSAtom atom;
18427
18428
0
                op1 = sp[-1];
18429
0
                atom = js_operator_typeof(ctx, op1);
18430
0
                JS_FreeValue(ctx, op1);
18431
0
                sp[-1] = JS_AtomToString(ctx, atom);
18432
0
            }
18433
0
            BREAK;
18434
0
        CASE(OP_delete):
18435
0
            if (js_operator_delete(ctx, sp))
18436
0
                goto exception;
18437
0
            sp--;
18438
0
            BREAK;
18439
0
        CASE(OP_delete_var):
18440
0
            {
18441
0
                JSAtom atom;
18442
0
                int ret;
18443
18444
0
                atom = get_u32(pc);
18445
0
                pc += 4;
18446
18447
0
                ret = JS_DeleteProperty(ctx, ctx->global_obj, atom, 0);
18448
0
                if (unlikely(ret < 0))
18449
0
                    goto exception;
18450
0
                *sp++ = JS_NewBool(ctx, ret);
18451
0
            }
18452
0
            BREAK;
18453
18454
47
        CASE(OP_to_object):
18455
47
            if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) {
18456
25
                ret_val = JS_ToObject(ctx, sp[-1]);
18457
25
                if (JS_IsException(ret_val))
18458
0
                    goto exception;
18459
25
                JS_FreeValue(ctx, sp[-1]);
18460
25
                sp[-1] = ret_val;
18461
25
            }
18462
47
            BREAK;
18463
18464
25.0k
        CASE(OP_to_propkey):
18465
25.0k
            switch (JS_VALUE_GET_TAG(sp[-1])) {
18466
0
            case JS_TAG_INT:
18467
25.0k
            case JS_TAG_STRING:
18468
25.0k
            case JS_TAG_SYMBOL:
18469
25.0k
                break;
18470
0
            default:
18471
0
                ret_val = JS_ToPropertyKey(ctx, sp[-1]);
18472
0
                if (JS_IsException(ret_val))
18473
0
                    goto exception;
18474
0
                JS_FreeValue(ctx, sp[-1]);
18475
0
                sp[-1] = ret_val;
18476
0
                break;
18477
25.0k
            }
18478
25.0k
            BREAK;
18479
18480
25.0k
        CASE(OP_to_propkey2):
18481
            /* must be tested first */
18482
0
            if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
18483
0
                JS_ThrowTypeError(ctx, "value has no property");
18484
0
                goto exception;
18485
0
            }
18486
0
            switch (JS_VALUE_GET_TAG(sp[-1])) {
18487
0
            case JS_TAG_INT:
18488
0
            case JS_TAG_STRING:
18489
0
            case JS_TAG_SYMBOL:
18490
0
                break;
18491
0
            default:
18492
0
                ret_val = JS_ToPropertyKey(ctx, sp[-1]);
18493
0
                if (JS_IsException(ret_val))
18494
0
                    goto exception;
18495
0
                JS_FreeValue(ctx, sp[-1]);
18496
0
                sp[-1] = ret_val;
18497
0
                break;
18498
0
            }
18499
0
            BREAK;
18500
#if 0
18501
        CASE(OP_to_string):
18502
            if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_STRING) {
18503
                ret_val = JS_ToString(ctx, sp[-1]);
18504
                if (JS_IsException(ret_val))
18505
                    goto exception;
18506
                JS_FreeValue(ctx, sp[-1]);
18507
                sp[-1] = ret_val;
18508
            }
18509
            BREAK;
18510
#endif
18511
118
        CASE(OP_with_get_var):
18512
118
        CASE(OP_with_put_var):
18513
118
        CASE(OP_with_delete_var):
18514
218
        CASE(OP_with_make_ref):
18515
218
        CASE(OP_with_get_ref):
18516
218
        CASE(OP_with_get_ref_undef):
18517
218
            {
18518
218
                JSAtom atom;
18519
218
                int32_t diff;
18520
218
                JSValue obj, val;
18521
218
                int ret, is_with;
18522
218
                atom = get_u32(pc);
18523
218
                diff = get_u32(pc + 4);
18524
218
                is_with = pc[8];
18525
218
                pc += 9;
18526
18527
218
                obj = sp[-1];
18528
218
                ret = JS_HasProperty(ctx, obj, atom);
18529
218
                if (unlikely(ret < 0))
18530
0
                    goto exception;
18531
218
                if (ret) {
18532
0
                    if (is_with) {
18533
0
                        ret = js_has_unscopable(ctx, obj, atom);
18534
0
                        if (unlikely(ret < 0))
18535
0
                            goto exception;
18536
0
                        if (ret)
18537
0
                            goto no_with;
18538
0
                    }
18539
0
                    switch (opcode) {
18540
0
                    case OP_with_get_var:
18541
0
                        val = JS_GetProperty(ctx, obj, atom);
18542
0
                        if (unlikely(JS_IsException(val)))
18543
0
                            goto exception;
18544
0
                        set_value(ctx, &sp[-1], val);
18545
0
                        break;
18546
0
                    case OP_with_put_var:
18547
                        /* XXX: check if strict mode */
18548
0
                        ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2],
18549
0
                                                     JS_PROP_THROW_STRICT);
18550
0
                        JS_FreeValue(ctx, sp[-1]);
18551
0
                        sp -= 2;
18552
0
                        if (unlikely(ret < 0))
18553
0
                            goto exception;
18554
0
                        break;
18555
0
                    case OP_with_delete_var:
18556
0
                        ret = JS_DeleteProperty(ctx, obj, atom, 0);
18557
0
                        if (unlikely(ret < 0))
18558
0
                            goto exception;
18559
0
                        JS_FreeValue(ctx, sp[-1]);
18560
0
                        sp[-1] = JS_NewBool(ctx, ret);
18561
0
                        break;
18562
0
                    case OP_with_make_ref:
18563
                        /* produce a pair object/propname on the stack */
18564
0
                        *sp++ = JS_AtomToValue(ctx, atom);
18565
0
                        break;
18566
0
                    case OP_with_get_ref:
18567
                        /* produce a pair object/method on the stack */
18568
0
                        val = JS_GetProperty(ctx, obj, atom);
18569
0
                        if (unlikely(JS_IsException(val)))
18570
0
                            goto exception;
18571
0
                        *sp++ = val;
18572
0
                        break;
18573
0
                    case OP_with_get_ref_undef:
18574
                        /* produce a pair undefined/function on the stack */
18575
0
                        val = JS_GetProperty(ctx, obj, atom);
18576
0
                        if (unlikely(JS_IsException(val)))
18577
0
                            goto exception;
18578
0
                        JS_FreeValue(ctx, sp[-1]);
18579
0
                        sp[-1] = JS_UNDEFINED;
18580
0
                        *sp++ = val;
18581
0
                        break;
18582
0
                    }
18583
0
                    pc += diff - 5;
18584
218
                } else {
18585
218
                no_with:
18586
                    /* if not jumping, drop the object argument */
18587
218
                    JS_FreeValue(ctx, sp[-1]);
18588
218
                    sp--;
18589
218
                }
18590
218
            }
18591
218
            BREAK;
18592
18593
218
        CASE(OP_await):
18594
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_AWAIT);
18595
0
            goto done_generator;
18596
0
        CASE(OP_yield):
18597
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD);
18598
0
            goto done_generator;
18599
0
        CASE(OP_yield_star):
18600
0
        CASE(OP_async_yield_star):
18601
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR);
18602
0
            goto done_generator;
18603
0
        CASE(OP_return_async):
18604
0
        CASE(OP_initial_yield):
18605
0
            ret_val = JS_UNDEFINED;
18606
0
            goto done_generator;
18607
18608
0
        CASE(OP_nop):
18609
0
            BREAK;
18610
0
        CASE(OP_is_undefined_or_null):
18611
0
            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED ||
18612
0
                JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
18613
0
                goto set_true;
18614
0
            } else {
18615
0
                goto free_and_set_false;
18616
0
            }
18617
0
#if SHORT_OPCODES
18618
1
        CASE(OP_is_undefined):
18619
1
            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED) {
18620
1
                goto set_true;
18621
1
            } else {
18622
0
                goto free_and_set_false;
18623
0
            }
18624
0
        CASE(OP_is_null):
18625
0
            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
18626
0
                goto set_true;
18627
0
            } else {
18628
0
                goto free_and_set_false;
18629
0
            }
18630
            /* XXX: could merge to a single opcode */
18631
0
        CASE(OP_typeof_is_undefined):
18632
            /* different from OP_is_undefined because of isHTMLDDA */
18633
0
            if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) {
18634
0
                goto free_and_set_true;
18635
0
            } else {
18636
0
                goto free_and_set_false;
18637
0
            }
18638
0
        CASE(OP_typeof_is_function):
18639
0
            if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) {
18640
0
                goto free_and_set_true;
18641
0
            } else {
18642
0
                goto free_and_set_false;
18643
0
            }
18644
0
        free_and_set_true:
18645
0
            JS_FreeValue(ctx, sp[-1]);
18646
0
#endif
18647
1
        set_true:
18648
1
            sp[-1] = JS_TRUE;
18649
1
            BREAK;
18650
1
        free_and_set_false:
18651
0
            JS_FreeValue(ctx, sp[-1]);
18652
0
            sp[-1] = JS_FALSE;
18653
0
            BREAK;
18654
0
        CASE(OP_invalid):
18655
0
        DEFAULT:
18656
0
            JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x",
18657
0
                                  (int)(pc - b->byte_code_buf - 1), opcode);
18658
0
            goto exception;
18659
0
        }
18660
0
    }
18661
163k
 exception:
18662
163k
    if (is_backtrace_needed(ctx, rt->current_exception)) {
18663
        /* add the backtrace information now (it is not done
18664
           before if the exception happens in a bytecode
18665
           operation */
18666
122k
        sf->cur_pc = pc;
18667
122k
        build_backtrace(ctx, rt->current_exception, NULL, 0, 0);
18668
122k
    }
18669
163k
    if (!JS_IsUncatchableError(ctx, rt->current_exception)) {
18670
368k
        while (sp > stack_buf) {
18671
327k
            JSValue val = *--sp;
18672
327k
            JS_FreeValue(ctx, val);
18673
327k
            if (JS_VALUE_GET_TAG(val) == JS_TAG_CATCH_OFFSET) {
18674
122k
                int pos = JS_VALUE_GET_INT(val);
18675
122k
                if (pos == 0) {
18676
                    /* enumerator: close it with a throw */
18677
1
                    JS_FreeValue(ctx, sp[-1]); /* drop the next method */
18678
1
                    sp--;
18679
1
                    JS_IteratorClose(ctx, sp[-1], TRUE);
18680
122k
                } else {
18681
122k
                    *sp++ = rt->current_exception;
18682
122k
                    rt->current_exception = JS_NULL;
18683
122k
                    pc = b->byte_code_buf + pos;
18684
122k
                    goto restart;
18685
122k
                }
18686
122k
            }
18687
327k
        }
18688
163k
    }
18689
40.9k
    ret_val = JS_EXCEPTION;
18690
    /* the local variables are freed by the caller in the generator
18691
       case. Hence the label 'done' should never be reached in a
18692
       generator function. */
18693
40.9k
    if (b->func_kind != JS_FUNC_NORMAL) {
18694
0
    done_generator:
18695
0
        sf->cur_pc = pc;
18696
0
        sf->cur_sp = sp;
18697
40.9k
    } else {
18698
81.9k
    done:
18699
81.9k
        if (unlikely(!list_empty(&sf->var_ref_list))) {
18700
            /* variable references reference the stack: must close them */
18701
40.9k
            close_var_refs(rt, sf);
18702
40.9k
        }
18703
        /* free the local variables and stack */
18704
123k
        for(pval = local_buf; pval < sp; pval++) {
18705
41.6k
            JS_FreeValue(ctx, *pval);
18706
41.6k
        }
18707
81.9k
    }
18708
81.9k
    rt->current_stack_frame = sf->prev_frame;
18709
81.9k
    return ret_val;
18710
40.9k
}
18711
18712
JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,
18713
                int argc, JSValueConst *argv)
18714
81.9k
{
18715
81.9k
    return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
18716
81.9k
                           argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
18717
81.9k
}
18718
18719
static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
18720
                           int argc, JSValueConst *argv)
18721
492k
{
18722
492k
    JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
18723
492k
                                  argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
18724
492k
    JS_FreeValue(ctx, func_obj);
18725
492k
    return res;
18726
492k
}
18727
18728
/* warning: the refcount of the context is not incremented. Return
18729
   NULL in case of exception (case of revoked proxy only) */
18730
static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj)
18731
0
{
18732
0
    JSObject *p;
18733
0
    JSContext *realm;
18734
    
18735
0
    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
18736
0
        return ctx;
18737
0
    p = JS_VALUE_GET_OBJ(func_obj);
18738
0
    switch(p->class_id) {
18739
0
    case JS_CLASS_C_FUNCTION:
18740
0
        realm = p->u.cfunc.realm;
18741
0
        break;
18742
0
    case JS_CLASS_BYTECODE_FUNCTION:
18743
0
    case JS_CLASS_GENERATOR_FUNCTION:
18744
0
    case JS_CLASS_ASYNC_FUNCTION:
18745
0
    case JS_CLASS_ASYNC_GENERATOR_FUNCTION:
18746
0
        {
18747
0
            JSFunctionBytecode *b;
18748
0
            b = p->u.func.function_bytecode;
18749
0
            realm = b->realm;
18750
0
        }
18751
0
        break;
18752
0
    case JS_CLASS_PROXY:
18753
0
        {
18754
0
            JSProxyData *s = p->u.opaque;
18755
0
            if (!s)
18756
0
                return ctx;
18757
0
            if (s->is_revoked) {
18758
0
                JS_ThrowTypeErrorRevokedProxy(ctx);
18759
0
                return NULL;
18760
0
            } else {
18761
0
                realm = JS_GetFunctionRealm(ctx, s->target);
18762
0
            }
18763
0
        }
18764
0
        break;
18765
0
    case JS_CLASS_BOUND_FUNCTION:
18766
0
        {
18767
0
            JSBoundFunction *bf = p->u.bound_function;
18768
0
            realm = JS_GetFunctionRealm(ctx, bf->func_obj);
18769
0
        }
18770
0
        break;
18771
0
    default:
18772
0
        realm = ctx;
18773
0
        break;
18774
0
    }
18775
0
    return realm;
18776
0
}
18777
18778
static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor,
18779
                                   int class_id)
18780
204k
{
18781
204k
    JSValue proto, obj;
18782
204k
    JSContext *realm;
18783
    
18784
204k
    if (JS_IsUndefined(ctor)) {
18785
122k
        proto = JS_DupValue(ctx, ctx->class_proto[class_id]);
18786
122k
    } else {
18787
81.9k
        proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
18788
81.9k
        if (JS_IsException(proto))
18789
0
            return proto;
18790
81.9k
        if (!JS_IsObject(proto)) {
18791
0
            JS_FreeValue(ctx, proto);
18792
0
            realm = JS_GetFunctionRealm(ctx, ctor);
18793
0
            if (!realm)
18794
0
                return JS_EXCEPTION;
18795
0
            proto = JS_DupValue(ctx, realm->class_proto[class_id]);
18796
0
        }
18797
81.9k
    }
18798
204k
    obj = JS_NewObjectProtoClass(ctx, proto, class_id);
18799
204k
    JS_FreeValue(ctx, proto);
18800
204k
    return obj;
18801
204k
}
18802
18803
/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
18804
static JSValue JS_CallConstructorInternal(JSContext *ctx,
18805
                                          JSValueConst func_obj,
18806
                                          JSValueConst new_target,
18807
                                          int argc, JSValue *argv, int flags)
18808
81.9k
{
18809
81.9k
    JSObject *p;
18810
81.9k
    JSFunctionBytecode *b;
18811
18812
81.9k
    if (js_poll_interrupts(ctx))
18813
0
        return JS_EXCEPTION;
18814
81.9k
    flags |= JS_CALL_FLAG_CONSTRUCTOR;
18815
81.9k
    if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT))
18816
0
        goto not_a_function;
18817
81.9k
    p = JS_VALUE_GET_OBJ(func_obj);
18818
81.9k
    if (unlikely(!p->is_constructor))
18819
0
        return JS_ThrowTypeError(ctx, "not a constructor");
18820
81.9k
    if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
18821
81.9k
        JSClassCall *call_func;
18822
81.9k
        call_func = ctx->rt->class_array[p->class_id].call;
18823
81.9k
        if (!call_func) {
18824
0
        not_a_function:
18825
0
            return JS_ThrowTypeError(ctx, "not a function");
18826
0
        }
18827
81.9k
        return call_func(ctx, func_obj, new_target, argc,
18828
81.9k
                         (JSValueConst *)argv, flags);
18829
81.9k
    }
18830
18831
1
    b = p->u.func.function_bytecode;
18832
1
    if (b->is_derived_class_constructor) {
18833
0
        return JS_CallInternal(ctx, func_obj, JS_UNDEFINED, new_target, argc, argv, flags);
18834
1
    } else {
18835
1
        JSValue obj, ret;
18836
        /* legacy constructor behavior */
18837
1
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
18838
1
        if (JS_IsException(obj))
18839
0
            return JS_EXCEPTION;
18840
1
        ret = JS_CallInternal(ctx, func_obj, obj, new_target, argc, argv, flags);
18841
1
        if (JS_VALUE_GET_TAG(ret) == JS_TAG_OBJECT ||
18842
1
            JS_IsException(ret)) {
18843
0
            JS_FreeValue(ctx, obj);
18844
0
            return ret;
18845
1
        } else {
18846
1
            JS_FreeValue(ctx, ret);
18847
1
            return obj;
18848
1
        }
18849
1
    }
18850
1
}
18851
18852
JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,
18853
                            JSValueConst new_target,
18854
                            int argc, JSValueConst *argv)
18855
0
{
18856
0
    return JS_CallConstructorInternal(ctx, func_obj, new_target,
18857
0
                                      argc, (JSValue *)argv,
18858
0
                                      JS_CALL_FLAG_COPY_ARGV);
18859
0
}
18860
18861
JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,
18862
                           int argc, JSValueConst *argv)
18863
0
{
18864
0
    return JS_CallConstructorInternal(ctx, func_obj, func_obj,
18865
0
                                      argc, (JSValue *)argv,
18866
0
                                      JS_CALL_FLAG_COPY_ARGV);
18867
0
}
18868
18869
JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom,
18870
                  int argc, JSValueConst *argv)
18871
0
{
18872
0
    JSValue func_obj;
18873
0
    func_obj = JS_GetProperty(ctx, this_val, atom);
18874
0
    if (JS_IsException(func_obj))
18875
0
        return func_obj;
18876
0
    return JS_CallFree(ctx, func_obj, this_val, argc, argv);
18877
0
}
18878
18879
static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
18880
                             int argc, JSValueConst *argv)
18881
0
{
18882
0
    JSValue res = JS_Invoke(ctx, this_val, atom, argc, argv);
18883
0
    JS_FreeValue(ctx, this_val);
18884
0
    return res;
18885
0
}
18886
18887
/* JSAsyncFunctionState (used by generator and async functions) */
18888
static __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s,
18889
                                       JSValueConst func_obj, JSValueConst this_obj,
18890
                                       int argc, JSValueConst *argv)
18891
0
{
18892
0
    JSObject *p;
18893
0
    JSFunctionBytecode *b;
18894
0
    JSStackFrame *sf;
18895
0
    int local_count, i, arg_buf_len, n;
18896
18897
0
    sf = &s->frame;
18898
0
    init_list_head(&sf->var_ref_list);
18899
0
    p = JS_VALUE_GET_OBJ(func_obj);
18900
0
    b = p->u.func.function_bytecode;
18901
0
    sf->js_mode = b->js_mode;
18902
0
    sf->cur_pc = b->byte_code_buf;
18903
0
    arg_buf_len = max_int(b->arg_count, argc);
18904
0
    local_count = arg_buf_len + b->var_count + b->stack_size;
18905
0
    sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1));
18906
0
    if (!sf->arg_buf)
18907
0
        return -1;
18908
0
    sf->cur_func = JS_DupValue(ctx, func_obj);
18909
0
    s->this_val = JS_DupValue(ctx, this_obj);
18910
0
    s->argc = argc;
18911
0
    sf->arg_count = arg_buf_len;
18912
0
    sf->var_buf = sf->arg_buf + arg_buf_len;
18913
0
    sf->cur_sp = sf->var_buf + b->var_count;
18914
0
    for(i = 0; i < argc; i++)
18915
0
        sf->arg_buf[i] = JS_DupValue(ctx, argv[i]);
18916
0
    n = arg_buf_len + b->var_count;
18917
0
    for(i = argc; i < n; i++)
18918
0
        sf->arg_buf[i] = JS_UNDEFINED;
18919
0
    return 0;
18920
0
}
18921
18922
static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
18923
                            JS_MarkFunc *mark_func)
18924
0
{
18925
0
    JSStackFrame *sf;
18926
0
    JSValue *sp;
18927
18928
0
    sf = &s->frame;
18929
0
    JS_MarkValue(rt, sf->cur_func, mark_func);
18930
0
    JS_MarkValue(rt, s->this_val, mark_func);
18931
0
    if (sf->cur_sp) {
18932
        /* if the function is running, cur_sp is not known so we
18933
           cannot mark the stack. Marking the variables is not needed
18934
           because a running function cannot be part of a removable
18935
           cycle */
18936
0
        for(sp = sf->arg_buf; sp < sf->cur_sp; sp++)
18937
0
            JS_MarkValue(rt, *sp, mark_func);
18938
0
    }
18939
0
}
18940
18941
static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
18942
0
{
18943
0
    JSStackFrame *sf;
18944
0
    JSValue *sp;
18945
18946
0
    sf = &s->frame;
18947
18948
    /* close the closure variables. */
18949
0
    close_var_refs(rt, sf);
18950
    
18951
0
    if (sf->arg_buf) {
18952
        /* cannot free the function if it is running */
18953
0
        assert(sf->cur_sp != NULL);
18954
0
        for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) {
18955
0
            JS_FreeValueRT(rt, *sp);
18956
0
        }
18957
0
        js_free_rt(rt, sf->arg_buf);
18958
0
    }
18959
0
    JS_FreeValueRT(rt, sf->cur_func);
18960
0
    JS_FreeValueRT(rt, s->this_val);
18961
0
}
18962
18963
static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)
18964
0
{
18965
0
    JSValue func_obj;
18966
18967
0
    if (js_check_stack_overflow(ctx->rt, 0))
18968
0
        return JS_ThrowStackOverflow(ctx);
18969
18970
    /* the tag does not matter provided it is not an object */
18971
0
    func_obj = JS_MKPTR(JS_TAG_INT, s);
18972
0
    return JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,
18973
0
                           s->argc, s->frame.arg_buf, JS_CALL_FLAG_GENERATOR);
18974
0
}
18975
18976
18977
/* Generators */
18978
18979
typedef enum JSGeneratorStateEnum {
18980
    JS_GENERATOR_STATE_SUSPENDED_START,
18981
    JS_GENERATOR_STATE_SUSPENDED_YIELD,
18982
    JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
18983
    JS_GENERATOR_STATE_EXECUTING,
18984
    JS_GENERATOR_STATE_COMPLETED,
18985
} JSGeneratorStateEnum;
18986
18987
typedef struct JSGeneratorData {
18988
    JSGeneratorStateEnum state;
18989
    JSAsyncFunctionState func_state;
18990
} JSGeneratorData;
18991
18992
static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s)
18993
0
{
18994
0
    if (s->state == JS_GENERATOR_STATE_COMPLETED)
18995
0
        return;
18996
0
    async_func_free(rt, &s->func_state);
18997
0
    s->state = JS_GENERATOR_STATE_COMPLETED;
18998
0
}
18999
19000
static void js_generator_finalizer(JSRuntime *rt, JSValue obj)
19001
0
{
19002
0
    JSGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_GENERATOR);
19003
19004
0
    if (s) {
19005
0
        free_generator_stack_rt(rt, s);
19006
0
        js_free_rt(rt, s);
19007
0
    }
19008
0
}
19009
19010
static void free_generator_stack(JSContext *ctx, JSGeneratorData *s)
19011
0
{
19012
0
    free_generator_stack_rt(ctx->rt, s);
19013
0
}
19014
19015
static void js_generator_mark(JSRuntime *rt, JSValueConst val,
19016
                              JS_MarkFunc *mark_func)
19017
0
{
19018
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
19019
0
    JSGeneratorData *s = p->u.generator_data;
19020
19021
0
    if (!s || s->state == JS_GENERATOR_STATE_COMPLETED)
19022
0
        return;
19023
0
    async_func_mark(rt, &s->func_state, mark_func);
19024
0
}
19025
19026
/* XXX: use enum */
19027
0
#define GEN_MAGIC_NEXT   0
19028
0
#define GEN_MAGIC_RETURN 1
19029
0
#define GEN_MAGIC_THROW  2
19030
19031
static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
19032
                                 int argc, JSValueConst *argv,
19033
                                 BOOL *pdone, int magic)
19034
0
{
19035
0
    JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR);
19036
0
    JSStackFrame *sf;
19037
0
    JSValue ret, func_ret;
19038
19039
0
    *pdone = TRUE;
19040
0
    if (!s)
19041
0
        return JS_ThrowTypeError(ctx, "not a generator");
19042
0
    sf = &s->func_state.frame;
19043
0
    switch(s->state) {
19044
0
    default:
19045
0
    case JS_GENERATOR_STATE_SUSPENDED_START:
19046
0
        if (magic == GEN_MAGIC_NEXT) {
19047
0
            goto exec_no_arg;
19048
0
        } else {
19049
0
            free_generator_stack(ctx, s);
19050
0
            goto done;
19051
0
        }
19052
0
        break;
19053
0
    case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
19054
0
    case JS_GENERATOR_STATE_SUSPENDED_YIELD:
19055
        /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
19056
0
        ret = JS_DupValue(ctx, argv[0]);
19057
0
        if (magic == GEN_MAGIC_THROW &&
19058
0
            s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {
19059
0
            JS_Throw(ctx, ret);
19060
0
            s->func_state.throw_flag = TRUE;
19061
0
        } else {
19062
0
            sf->cur_sp[-1] = ret;
19063
0
            sf->cur_sp[0] = JS_NewInt32(ctx, magic);
19064
0
            sf->cur_sp++;
19065
0
        exec_no_arg:
19066
0
            s->func_state.throw_flag = FALSE;
19067
0
        }
19068
0
        s->state = JS_GENERATOR_STATE_EXECUTING;
19069
0
        func_ret = async_func_resume(ctx, &s->func_state);
19070
0
        s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD;
19071
0
        if (JS_IsException(func_ret)) {
19072
            /* finalize the execution in case of exception */
19073
0
            free_generator_stack(ctx, s);
19074
0
            return func_ret;
19075
0
        }
19076
0
        if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
19077
            /* get the returned yield value at the top of the stack */
19078
0
            ret = sf->cur_sp[-1];
19079
0
            sf->cur_sp[-1] = JS_UNDEFINED;
19080
0
            if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) {
19081
0
                s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
19082
                /* return (value, done) object */
19083
0
                *pdone = 2;
19084
0
            } else {
19085
0
                *pdone = FALSE;
19086
0
            }
19087
0
        } else {
19088
            /* end of iterator */
19089
0
            ret = sf->cur_sp[-1];
19090
0
            sf->cur_sp[-1] = JS_UNDEFINED;
19091
0
            JS_FreeValue(ctx, func_ret);
19092
0
            free_generator_stack(ctx, s);
19093
0
        }
19094
0
        break;
19095
0
    case JS_GENERATOR_STATE_COMPLETED:
19096
0
    done:
19097
        /* execution is finished */
19098
0
        switch(magic) {
19099
0
        default:
19100
0
        case GEN_MAGIC_NEXT:
19101
0
            ret = JS_UNDEFINED;
19102
0
            break;
19103
0
        case GEN_MAGIC_RETURN:
19104
0
            ret = JS_DupValue(ctx, argv[0]);
19105
0
            break;
19106
0
        case GEN_MAGIC_THROW:
19107
0
            ret = JS_Throw(ctx, JS_DupValue(ctx, argv[0]));
19108
0
            break;
19109
0
        }
19110
0
        break;
19111
0
    case JS_GENERATOR_STATE_EXECUTING:
19112
0
        ret = JS_ThrowTypeError(ctx, "cannot invoke a running generator");
19113
0
        break;
19114
0
    }
19115
0
    return ret;
19116
0
}
19117
19118
static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
19119
                                          JSValueConst this_obj,
19120
                                          int argc, JSValueConst *argv,
19121
                                          int flags)
19122
0
{
19123
0
    JSValue obj, func_ret;
19124
0
    JSGeneratorData *s;
19125
19126
0
    s = js_mallocz(ctx, sizeof(*s));
19127
0
    if (!s)
19128
0
        return JS_EXCEPTION;
19129
0
    s->state = JS_GENERATOR_STATE_SUSPENDED_START;
19130
0
    if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
19131
0
        s->state = JS_GENERATOR_STATE_COMPLETED;
19132
0
        goto fail;
19133
0
    }
19134
19135
    /* execute the function up to 'OP_initial_yield' */
19136
0
    func_ret = async_func_resume(ctx, &s->func_state);
19137
0
    if (JS_IsException(func_ret))
19138
0
        goto fail;
19139
0
    JS_FreeValue(ctx, func_ret);
19140
19141
0
    obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR);
19142
0
    if (JS_IsException(obj))
19143
0
        goto fail;
19144
0
    JS_SetOpaque(obj, s);
19145
0
    return obj;
19146
0
 fail:
19147
0
    free_generator_stack_rt(ctx->rt, s);
19148
0
    js_free(ctx, s);
19149
0
    return JS_EXCEPTION;
19150
0
}
19151
19152
/* AsyncFunction */
19153
19154
static void js_async_function_terminate(JSRuntime *rt, JSAsyncFunctionData *s)
19155
0
{
19156
0
    if (s->is_active) {
19157
0
        async_func_free(rt, &s->func_state);
19158
0
        s->is_active = FALSE;
19159
0
    }
19160
0
}
19161
19162
static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s)
19163
0
{
19164
0
    js_async_function_terminate(rt, s);
19165
0
    JS_FreeValueRT(rt, s->resolving_funcs[0]);
19166
0
    JS_FreeValueRT(rt, s->resolving_funcs[1]);
19167
0
    remove_gc_object(&s->header);
19168
0
    js_free_rt(rt, s);
19169
0
}
19170
19171
static void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s)
19172
0
{
19173
0
    if (--s->header.ref_count == 0) {
19174
0
        js_async_function_free0(rt, s);
19175
0
    }
19176
0
}
19177
19178
static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val)
19179
0
{
19180
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
19181
0
    JSAsyncFunctionData *s = p->u.async_function_data;
19182
0
    if (s) {
19183
0
        js_async_function_free(rt, s);
19184
0
    }
19185
0
}
19186
19187
static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
19188
                                           JS_MarkFunc *mark_func)
19189
0
{
19190
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
19191
0
    JSAsyncFunctionData *s = p->u.async_function_data;
19192
0
    if (s) {
19193
0
        mark_func(rt, &s->header);
19194
0
    }
19195
0
}
19196
19197
static int js_async_function_resolve_create(JSContext *ctx,
19198
                                            JSAsyncFunctionData *s,
19199
                                            JSValue *resolving_funcs)
19200
0
{
19201
0
    int i;
19202
0
    JSObject *p;
19203
19204
0
    for(i = 0; i < 2; i++) {
19205
0
        resolving_funcs[i] =
19206
0
            JS_NewObjectProtoClass(ctx, ctx->function_proto,
19207
0
                                   JS_CLASS_ASYNC_FUNCTION_RESOLVE + i);
19208
0
        if (JS_IsException(resolving_funcs[i])) {
19209
0
            if (i == 1)
19210
0
                JS_FreeValue(ctx, resolving_funcs[0]);
19211
0
            return -1;
19212
0
        }
19213
0
        p = JS_VALUE_GET_OBJ(resolving_funcs[i]);
19214
0
        s->header.ref_count++;
19215
0
        p->u.async_function_data = s;
19216
0
    }
19217
0
    return 0;
19218
0
}
19219
19220
static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s)
19221
0
{
19222
0
    JSValue func_ret, ret2;
19223
19224
0
    func_ret = async_func_resume(ctx, &s->func_state);
19225
0
    if (JS_IsException(func_ret)) {
19226
0
        JSValue error;
19227
0
    fail:
19228
0
        error = JS_GetException(ctx);
19229
0
        ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED,
19230
0
                       1, (JSValueConst *)&error);
19231
0
        JS_FreeValue(ctx, error);
19232
0
        js_async_function_terminate(ctx->rt, s);
19233
0
        JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
19234
0
    } else {
19235
0
        JSValue value;
19236
0
        value = s->func_state.frame.cur_sp[-1];
19237
0
        s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
19238
0
        if (JS_IsUndefined(func_ret)) {
19239
            /* function returned */
19240
0
            ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,
19241
0
                           1, (JSValueConst *)&value);
19242
0
            JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
19243
0
            JS_FreeValue(ctx, value);
19244
0
            js_async_function_terminate(ctx->rt, s);
19245
0
        } else {
19246
0
            JSValue promise, resolving_funcs[2], resolving_funcs1[2];
19247
0
            int i, res;
19248
19249
            /* await */
19250
0
            JS_FreeValue(ctx, func_ret); /* not used */
19251
0
            promise = js_promise_resolve(ctx, ctx->promise_ctor,
19252
0
                                         1, (JSValueConst *)&value, 0);
19253
0
            JS_FreeValue(ctx, value);
19254
0
            if (JS_IsException(promise))
19255
0
                goto fail;
19256
0
            if (js_async_function_resolve_create(ctx, s, resolving_funcs)) {
19257
0
                JS_FreeValue(ctx, promise);
19258
0
                goto fail;
19259
0
            }
19260
19261
            /* Note: no need to create 'thrownawayCapability' as in
19262
               the spec */
19263
0
            for(i = 0; i < 2; i++)
19264
0
                resolving_funcs1[i] = JS_UNDEFINED;
19265
0
            res = perform_promise_then(ctx, promise,
19266
0
                                       (JSValueConst *)resolving_funcs,
19267
0
                                       (JSValueConst *)resolving_funcs1);
19268
0
            JS_FreeValue(ctx, promise);
19269
0
            for(i = 0; i < 2; i++)
19270
0
                JS_FreeValue(ctx, resolving_funcs[i]);
19271
0
            if (res)
19272
0
                goto fail;
19273
0
        }
19274
0
    }
19275
0
}
19276
19277
static JSValue js_async_function_resolve_call(JSContext *ctx,
19278
                                              JSValueConst func_obj,
19279
                                              JSValueConst this_obj,
19280
                                              int argc, JSValueConst *argv,
19281
                                              int flags)
19282
0
{
19283
0
    JSObject *p = JS_VALUE_GET_OBJ(func_obj);
19284
0
    JSAsyncFunctionData *s = p->u.async_function_data;
19285
0
    BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE;
19286
0
    JSValueConst arg;
19287
19288
0
    if (argc > 0)
19289
0
        arg = argv[0];
19290
0
    else
19291
0
        arg = JS_UNDEFINED;
19292
0
    s->func_state.throw_flag = is_reject;
19293
0
    if (is_reject) {
19294
0
        JS_Throw(ctx, JS_DupValue(ctx, arg));
19295
0
    } else {
19296
        /* return value of await */
19297
0
        s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg);
19298
0
    }
19299
0
    js_async_function_resume(ctx, s);
19300
0
    return JS_UNDEFINED;
19301
0
}
19302
19303
static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj,
19304
                                      JSValueConst this_obj,
19305
                                      int argc, JSValueConst *argv, int flags)
19306
0
{
19307
0
    JSValue promise;
19308
0
    JSAsyncFunctionData *s;
19309
19310
0
    s = js_mallocz(ctx, sizeof(*s));
19311
0
    if (!s)
19312
0
        return JS_EXCEPTION;
19313
0
    s->header.ref_count = 1;
19314
0
    add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
19315
0
    s->is_active = FALSE;
19316
0
    s->resolving_funcs[0] = JS_UNDEFINED;
19317
0
    s->resolving_funcs[1] = JS_UNDEFINED;
19318
19319
0
    promise = JS_NewPromiseCapability(ctx, s->resolving_funcs);
19320
0
    if (JS_IsException(promise))
19321
0
        goto fail;
19322
19323
0
    if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
19324
0
    fail:
19325
0
        JS_FreeValue(ctx, promise);
19326
0
        js_async_function_free(ctx->rt, s);
19327
0
        return JS_EXCEPTION;
19328
0
    }
19329
0
    s->is_active = TRUE;
19330
19331
0
    js_async_function_resume(ctx, s);
19332
19333
0
    js_async_function_free(ctx->rt, s);
19334
19335
0
    return promise;
19336
0
}
19337
19338
/* AsyncGenerator */
19339
19340
typedef enum JSAsyncGeneratorStateEnum {
19341
    JS_ASYNC_GENERATOR_STATE_SUSPENDED_START,
19342
    JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD,
19343
    JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
19344
    JS_ASYNC_GENERATOR_STATE_EXECUTING,
19345
    JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN,
19346
    JS_ASYNC_GENERATOR_STATE_COMPLETED,
19347
} JSAsyncGeneratorStateEnum;
19348
19349
typedef struct JSAsyncGeneratorRequest {
19350
    struct list_head link;
19351
    /* completion */
19352
    int completion_type; /* GEN_MAGIC_x */
19353
    JSValue result;
19354
    /* promise capability */
19355
    JSValue promise;
19356
    JSValue resolving_funcs[2];
19357
} JSAsyncGeneratorRequest;
19358
19359
typedef struct JSAsyncGeneratorData {
19360
    JSObject *generator; /* back pointer to the object (const) */
19361
    JSAsyncGeneratorStateEnum state;
19362
    JSAsyncFunctionState func_state;
19363
    struct list_head queue; /* list of JSAsyncGeneratorRequest.link */
19364
} JSAsyncGeneratorData;
19365
19366
static void js_async_generator_free(JSRuntime *rt,
19367
                                    JSAsyncGeneratorData *s)
19368
0
{
19369
0
    struct list_head *el, *el1;
19370
0
    JSAsyncGeneratorRequest *req;
19371
19372
0
    list_for_each_safe(el, el1, &s->queue) {
19373
0
        req = list_entry(el, JSAsyncGeneratorRequest, link);
19374
0
        JS_FreeValueRT(rt, req->result);
19375
0
        JS_FreeValueRT(rt, req->promise);
19376
0
        JS_FreeValueRT(rt, req->resolving_funcs[0]);
19377
0
        JS_FreeValueRT(rt, req->resolving_funcs[1]);
19378
0
        js_free_rt(rt, req);
19379
0
    }
19380
0
    if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
19381
0
        s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
19382
0
        async_func_free(rt, &s->func_state);
19383
0
    }
19384
0
    js_free_rt(rt, s);
19385
0
}
19386
19387
static void js_async_generator_finalizer(JSRuntime *rt, JSValue obj)
19388
0
{
19389
0
    JSAsyncGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_ASYNC_GENERATOR);
19390
19391
0
    if (s) {
19392
0
        js_async_generator_free(rt, s);
19393
0
    }
19394
0
}
19395
19396
static void js_async_generator_mark(JSRuntime *rt, JSValueConst val,
19397
                                    JS_MarkFunc *mark_func)
19398
0
{
19399
0
    JSAsyncGeneratorData *s = JS_GetOpaque(val, JS_CLASS_ASYNC_GENERATOR);
19400
0
    struct list_head *el;
19401
0
    JSAsyncGeneratorRequest *req;
19402
0
    if (s) {
19403
0
        list_for_each(el, &s->queue) {
19404
0
            req = list_entry(el, JSAsyncGeneratorRequest, link);
19405
0
            JS_MarkValue(rt, req->result, mark_func);
19406
0
            JS_MarkValue(rt, req->promise, mark_func);
19407
0
            JS_MarkValue(rt, req->resolving_funcs[0], mark_func);
19408
0
            JS_MarkValue(rt, req->resolving_funcs[1], mark_func);
19409
0
        }
19410
0
        if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
19411
0
            s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
19412
0
            async_func_mark(rt, &s->func_state, mark_func);
19413
0
        }
19414
0
    }
19415
0
}
19416
19417
static JSValue js_async_generator_resolve_function(JSContext *ctx,
19418
                                          JSValueConst this_obj,
19419
                                          int argc, JSValueConst *argv,
19420
                                          int magic, JSValue *func_data);
19421
19422
static int js_async_generator_resolve_function_create(JSContext *ctx,
19423
                                                      JSValueConst generator,
19424
                                                      JSValue *resolving_funcs,
19425
                                                      BOOL is_resume_next)
19426
0
{
19427
0
    int i;
19428
0
    JSValue func;
19429
19430
0
    for(i = 0; i < 2; i++) {
19431
0
        func = JS_NewCFunctionData(ctx, js_async_generator_resolve_function, 1,
19432
0
                                   i + is_resume_next * 2, 1, &generator);
19433
0
        if (JS_IsException(func)) {
19434
0
            if (i == 1)
19435
0
                JS_FreeValue(ctx, resolving_funcs[0]);
19436
0
            return -1;
19437
0
        }
19438
0
        resolving_funcs[i] = func;
19439
0
    }
19440
0
    return 0;
19441
0
}
19442
19443
static int js_async_generator_await(JSContext *ctx,
19444
                                    JSAsyncGeneratorData *s,
19445
                                    JSValueConst value)
19446
0
{
19447
0
    JSValue promise, resolving_funcs[2], resolving_funcs1[2];
19448
0
    int i, res;
19449
19450
0
    promise = js_promise_resolve(ctx, ctx->promise_ctor,
19451
0
                                 1, &value, 0);
19452
0
    if (JS_IsException(promise))
19453
0
        goto fail;
19454
19455
0
    if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator),
19456
0
                                                   resolving_funcs, FALSE)) {
19457
0
        JS_FreeValue(ctx, promise);
19458
0
        goto fail;
19459
0
    }
19460
19461
    /* Note: no need to create 'thrownawayCapability' as in
19462
       the spec */
19463
0
    for(i = 0; i < 2; i++)
19464
0
        resolving_funcs1[i] = JS_UNDEFINED;
19465
0
    res = perform_promise_then(ctx, promise,
19466
0
                               (JSValueConst *)resolving_funcs,
19467
0
                               (JSValueConst *)resolving_funcs1);
19468
0
    JS_FreeValue(ctx, promise);
19469
0
    for(i = 0; i < 2; i++)
19470
0
        JS_FreeValue(ctx, resolving_funcs[i]);
19471
0
    if (res)
19472
0
        goto fail;
19473
0
    return 0;
19474
0
 fail:
19475
0
    return -1;
19476
0
}
19477
19478
static void js_async_generator_resolve_or_reject(JSContext *ctx,
19479
                                                 JSAsyncGeneratorData *s,
19480
                                                 JSValueConst result,
19481
                                                 int is_reject)
19482
0
{
19483
0
    JSAsyncGeneratorRequest *next;
19484
0
    JSValue ret;
19485
19486
0
    next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
19487
0
    list_del(&next->link);
19488
0
    ret = JS_Call(ctx, next->resolving_funcs[is_reject], JS_UNDEFINED, 1,
19489
0
                  &result);
19490
0
    JS_FreeValue(ctx, ret);
19491
0
    JS_FreeValue(ctx, next->result);
19492
0
    JS_FreeValue(ctx, next->promise);
19493
0
    JS_FreeValue(ctx, next->resolving_funcs[0]);
19494
0
    JS_FreeValue(ctx, next->resolving_funcs[1]);
19495
0
    js_free(ctx, next);
19496
0
}
19497
19498
static void js_async_generator_resolve(JSContext *ctx,
19499
                                       JSAsyncGeneratorData *s,
19500
                                       JSValueConst value,
19501
                                       BOOL done)
19502
0
{
19503
0
    JSValue result;
19504
0
    result = js_create_iterator_result(ctx, JS_DupValue(ctx, value), done);
19505
    /* XXX: better exception handling ? */
19506
0
    js_async_generator_resolve_or_reject(ctx, s, result, 0);
19507
0
    JS_FreeValue(ctx, result);
19508
0
 }
19509
19510
static void js_async_generator_reject(JSContext *ctx,
19511
                                       JSAsyncGeneratorData *s,
19512
                                       JSValueConst exception)
19513
0
{
19514
0
    js_async_generator_resolve_or_reject(ctx, s, exception, 1);
19515
0
}
19516
19517
static void js_async_generator_complete(JSContext *ctx,
19518
                                        JSAsyncGeneratorData *s)
19519
0
{
19520
0
    if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) {
19521
0
        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
19522
0
        async_func_free(ctx->rt, &s->func_state);
19523
0
    }
19524
0
}
19525
19526
static int js_async_generator_completed_return(JSContext *ctx,
19527
                                               JSAsyncGeneratorData *s,
19528
                                               JSValueConst value)
19529
0
{
19530
0
    JSValue promise, resolving_funcs[2], resolving_funcs1[2];
19531
0
    int res;
19532
19533
0
    promise = js_promise_resolve(ctx, ctx->promise_ctor,
19534
0
                                 1, (JSValueConst *)&value, 0);
19535
0
    if (JS_IsException(promise))
19536
0
        return -1;
19537
0
    if (js_async_generator_resolve_function_create(ctx,
19538
0
                                                   JS_MKPTR(JS_TAG_OBJECT, s->generator),
19539
0
                                                   resolving_funcs1,
19540
0
                                                   TRUE)) {
19541
0
        JS_FreeValue(ctx, promise);
19542
0
        return -1;
19543
0
    }
19544
0
    resolving_funcs[0] = JS_UNDEFINED;
19545
0
    resolving_funcs[1] = JS_UNDEFINED;
19546
0
    res = perform_promise_then(ctx, promise,
19547
0
                               (JSValueConst *)resolving_funcs1,
19548
0
                               (JSValueConst *)resolving_funcs);
19549
0
    JS_FreeValue(ctx, resolving_funcs1[0]);
19550
0
    JS_FreeValue(ctx, resolving_funcs1[1]);
19551
0
    JS_FreeValue(ctx, promise);
19552
0
    return res;
19553
0
}
19554
19555
static void js_async_generator_resume_next(JSContext *ctx,
19556
                                           JSAsyncGeneratorData *s)
19557
0
{
19558
0
    JSAsyncGeneratorRequest *next;
19559
0
    JSValue func_ret, value;
19560
19561
0
    for(;;) {
19562
0
        if (list_empty(&s->queue))
19563
0
            break;
19564
0
        next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
19565
0
        switch(s->state) {
19566
0
        case JS_ASYNC_GENERATOR_STATE_EXECUTING:
19567
            /* only happens when restarting execution after await() */
19568
0
            goto resume_exec;
19569
0
        case JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN:
19570
0
            goto done;
19571
0
        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_START:
19572
0
            if (next->completion_type == GEN_MAGIC_NEXT) {
19573
0
                goto exec_no_arg;
19574
0
            } else {
19575
0
                js_async_generator_complete(ctx, s);
19576
0
            }
19577
0
            break;
19578
0
        case JS_ASYNC_GENERATOR_STATE_COMPLETED:
19579
0
            if (next->completion_type == GEN_MAGIC_NEXT) {
19580
0
                js_async_generator_resolve(ctx, s, JS_UNDEFINED, TRUE);
19581
0
            } else if (next->completion_type == GEN_MAGIC_RETURN) {
19582
0
                s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN;
19583
0
                js_async_generator_completed_return(ctx, s, next->result);
19584
0
                goto done;
19585
0
            } else {
19586
0
                js_async_generator_reject(ctx, s, next->result);
19587
0
            }
19588
0
            goto done;
19589
0
        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD:
19590
0
        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
19591
0
            value = JS_DupValue(ctx, next->result);
19592
0
            if (next->completion_type == GEN_MAGIC_THROW &&
19593
0
                s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) {
19594
0
                JS_Throw(ctx, value);
19595
0
                s->func_state.throw_flag = TRUE;
19596
0
            } else {
19597
                /* 'yield' returns a value. 'yield *' also returns a value
19598
                   in case the 'throw' method is called */
19599
0
                s->func_state.frame.cur_sp[-1] = value;
19600
0
                s->func_state.frame.cur_sp[0] =
19601
0
                    JS_NewInt32(ctx, next->completion_type);
19602
0
                s->func_state.frame.cur_sp++;
19603
0
            exec_no_arg:
19604
0
                s->func_state.throw_flag = FALSE;
19605
0
            }
19606
0
            s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING;
19607
0
        resume_exec:
19608
0
            func_ret = async_func_resume(ctx, &s->func_state);
19609
0
            if (JS_IsException(func_ret)) {
19610
0
                value = JS_GetException(ctx);
19611
0
                js_async_generator_complete(ctx, s);
19612
0
                js_async_generator_reject(ctx, s, value);
19613
0
                JS_FreeValue(ctx, value);
19614
0
            } else if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
19615
0
                int func_ret_code;
19616
0
                value = s->func_state.frame.cur_sp[-1];
19617
0
                s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
19618
0
                func_ret_code = JS_VALUE_GET_INT(func_ret);
19619
0
                switch(func_ret_code) {
19620
0
                case FUNC_RET_YIELD:
19621
0
                case FUNC_RET_YIELD_STAR:
19622
0
                    if (func_ret_code == FUNC_RET_YIELD_STAR)
19623
0
                        s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
19624
0
                    else
19625
0
                        s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD;
19626
0
                    js_async_generator_resolve(ctx, s, value, FALSE);
19627
0
                    JS_FreeValue(ctx, value);
19628
0
                    break;
19629
0
                case FUNC_RET_AWAIT:
19630
0
                    js_async_generator_await(ctx, s, value);
19631
0
                    JS_FreeValue(ctx, value);
19632
0
                    goto done;
19633
0
                default:
19634
0
                    abort();
19635
0
                }
19636
0
            } else {
19637
0
                assert(JS_IsUndefined(func_ret));
19638
                /* end of function */
19639
0
                value = s->func_state.frame.cur_sp[-1];
19640
0
                s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
19641
0
                js_async_generator_complete(ctx, s);
19642
0
                js_async_generator_resolve(ctx, s, value, TRUE);
19643
0
                JS_FreeValue(ctx, value);
19644
0
            }
19645
0
            break;
19646
0
        default:
19647
0
            abort();
19648
0
        }
19649
0
    }
19650
0
 done: ;
19651
0
}
19652
19653
static JSValue js_async_generator_resolve_function(JSContext *ctx,
19654
                                                   JSValueConst this_obj,
19655
                                                   int argc, JSValueConst *argv,
19656
                                                   int magic, JSValue *func_data)
19657
0
{
19658
0
    BOOL is_reject = magic & 1;
19659
0
    JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR);
19660
0
    JSValueConst arg = argv[0];
19661
19662
    /* XXX: what if s == NULL */
19663
19664
0
    if (magic >= 2) {
19665
        /* resume next case in AWAITING_RETURN state */
19666
0
        assert(s->state == JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN ||
19667
0
               s->state == JS_ASYNC_GENERATOR_STATE_COMPLETED);
19668
0
        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
19669
0
        if (is_reject) {
19670
0
            js_async_generator_reject(ctx, s, arg);
19671
0
        } else {
19672
0
            js_async_generator_resolve(ctx, s, arg, TRUE);
19673
0
        }
19674
0
    } else {
19675
        /* restart function execution after await() */
19676
0
        assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING);
19677
0
        s->func_state.throw_flag = is_reject;
19678
0
        if (is_reject) {
19679
0
            JS_Throw(ctx, JS_DupValue(ctx, arg));
19680
0
        } else {
19681
            /* return value of await */
19682
0
            s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg);
19683
0
        }
19684
0
        js_async_generator_resume_next(ctx, s);
19685
0
    }
19686
0
    return JS_UNDEFINED;
19687
0
}
19688
19689
/* magic = GEN_MAGIC_x */
19690
static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val,
19691
                                       int argc, JSValueConst *argv,
19692
                                       int magic)
19693
0
{
19694
0
    JSAsyncGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_GENERATOR);
19695
0
    JSValue promise, resolving_funcs[2];
19696
0
    JSAsyncGeneratorRequest *req;
19697
19698
0
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
19699
0
    if (JS_IsException(promise))
19700
0
        return JS_EXCEPTION;
19701
0
    if (!s) {
19702
0
        JSValue err, res2;
19703
0
        JS_ThrowTypeError(ctx, "not an AsyncGenerator object");
19704
0
        err = JS_GetException(ctx);
19705
0
        res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
19706
0
                       1, (JSValueConst *)&err);
19707
0
        JS_FreeValue(ctx, err);
19708
0
        JS_FreeValue(ctx, res2);
19709
0
        JS_FreeValue(ctx, resolving_funcs[0]);
19710
0
        JS_FreeValue(ctx, resolving_funcs[1]);
19711
0
        return promise;
19712
0
    }
19713
0
    req = js_mallocz(ctx, sizeof(*req));
19714
0
    if (!req)
19715
0
        goto fail;
19716
0
    req->completion_type = magic;
19717
0
    req->result = JS_DupValue(ctx, argv[0]);
19718
0
    req->promise = JS_DupValue(ctx, promise);
19719
0
    req->resolving_funcs[0] = resolving_funcs[0];
19720
0
    req->resolving_funcs[1] = resolving_funcs[1];
19721
0
    list_add_tail(&req->link, &s->queue);
19722
0
    if (s->state != JS_ASYNC_GENERATOR_STATE_EXECUTING) {
19723
0
        js_async_generator_resume_next(ctx, s);
19724
0
    }
19725
0
    return promise;
19726
0
 fail:
19727
0
    JS_FreeValue(ctx, resolving_funcs[0]);
19728
0
    JS_FreeValue(ctx, resolving_funcs[1]);
19729
0
    JS_FreeValue(ctx, promise);
19730
0
    return JS_EXCEPTION;
19731
0
}
19732
19733
static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst func_obj,
19734
                                                JSValueConst this_obj,
19735
                                                int argc, JSValueConst *argv,
19736
                                                int flags)
19737
0
{
19738
0
    JSValue obj, func_ret;
19739
0
    JSAsyncGeneratorData *s;
19740
19741
0
    s = js_mallocz(ctx, sizeof(*s));
19742
0
    if (!s)
19743
0
        return JS_EXCEPTION;
19744
0
    s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START;
19745
0
    init_list_head(&s->queue);
19746
0
    if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
19747
0
        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
19748
0
        goto fail;
19749
0
    }
19750
19751
    /* execute the function up to 'OP_initial_yield' (no yield nor
19752
       await are possible) */
19753
0
    func_ret = async_func_resume(ctx, &s->func_state);
19754
0
    if (JS_IsException(func_ret))
19755
0
        goto fail;
19756
0
    JS_FreeValue(ctx, func_ret);
19757
19758
0
    obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_ASYNC_GENERATOR);
19759
0
    if (JS_IsException(obj))
19760
0
        goto fail;
19761
0
    s->generator = JS_VALUE_GET_OBJ(obj);
19762
0
    JS_SetOpaque(obj, s);
19763
0
    return obj;
19764
0
 fail:
19765
0
    js_async_generator_free(ctx->rt, s);
19766
0
    return JS_EXCEPTION;
19767
0
}
19768
19769
/* JS parser */
19770
19771
enum {
19772
    TOK_NUMBER = -128,
19773
    TOK_STRING,
19774
    TOK_TEMPLATE,
19775
    TOK_IDENT,
19776
    TOK_REGEXP,
19777
    /* warning: order matters (see js_parse_assign_expr) */
19778
    TOK_MUL_ASSIGN,
19779
    TOK_DIV_ASSIGN,
19780
    TOK_MOD_ASSIGN,
19781
    TOK_PLUS_ASSIGN,
19782
    TOK_MINUS_ASSIGN,
19783
    TOK_SHL_ASSIGN,
19784
    TOK_SAR_ASSIGN,
19785
    TOK_SHR_ASSIGN,
19786
    TOK_AND_ASSIGN,
19787
    TOK_XOR_ASSIGN,
19788
    TOK_OR_ASSIGN,
19789
#ifdef CONFIG_BIGNUM
19790
    TOK_MATH_POW_ASSIGN,
19791
#endif
19792
    TOK_POW_ASSIGN,
19793
    TOK_LAND_ASSIGN,
19794
    TOK_LOR_ASSIGN,
19795
    TOK_DOUBLE_QUESTION_MARK_ASSIGN,
19796
    TOK_DEC,
19797
    TOK_INC,
19798
    TOK_SHL,
19799
    TOK_SAR,
19800
    TOK_SHR,
19801
    TOK_LT,
19802
    TOK_LTE,
19803
    TOK_GT,
19804
    TOK_GTE,
19805
    TOK_EQ,
19806
    TOK_STRICT_EQ,
19807
    TOK_NEQ,
19808
    TOK_STRICT_NEQ,
19809
    TOK_LAND,
19810
    TOK_LOR,
19811
#ifdef CONFIG_BIGNUM
19812
    TOK_MATH_POW,
19813
#endif
19814
    TOK_POW,
19815
    TOK_ARROW,
19816
    TOK_ELLIPSIS,
19817
    TOK_DOUBLE_QUESTION_MARK,
19818
    TOK_QUESTION_MARK_DOT,
19819
    TOK_ERROR,
19820
    TOK_PRIVATE_NAME,
19821
    TOK_EOF,
19822
    /* keywords: WARNING: same order as atoms */
19823
    TOK_NULL, /* must be first */
19824
    TOK_FALSE,
19825
    TOK_TRUE,
19826
    TOK_IF,
19827
    TOK_ELSE,
19828
    TOK_RETURN,
19829
    TOK_VAR,
19830
    TOK_THIS,
19831
    TOK_DELETE,
19832
    TOK_VOID,
19833
    TOK_TYPEOF,
19834
    TOK_NEW,
19835
    TOK_IN,
19836
    TOK_INSTANCEOF,
19837
    TOK_DO,
19838
    TOK_WHILE,
19839
    TOK_FOR,
19840
    TOK_BREAK,
19841
    TOK_CONTINUE,
19842
    TOK_SWITCH,
19843
    TOK_CASE,
19844
    TOK_DEFAULT,
19845
    TOK_THROW,
19846
    TOK_TRY,
19847
    TOK_CATCH,
19848
    TOK_FINALLY,
19849
    TOK_FUNCTION,
19850
    TOK_DEBUGGER,
19851
    TOK_WITH,
19852
    /* FutureReservedWord */
19853
    TOK_CLASS,
19854
    TOK_CONST,
19855
    TOK_ENUM,
19856
    TOK_EXPORT,
19857
    TOK_EXTENDS,
19858
    TOK_IMPORT,
19859
    TOK_SUPER,
19860
    /* FutureReservedWords when parsing strict mode code */
19861
    TOK_IMPLEMENTS,
19862
    TOK_INTERFACE,
19863
    TOK_LET,
19864
    TOK_PACKAGE,
19865
    TOK_PRIVATE,
19866
    TOK_PROTECTED,
19867
    TOK_PUBLIC,
19868
    TOK_STATIC,
19869
    TOK_YIELD,
19870
    TOK_AWAIT, /* must be last */
19871
    TOK_OF,     /* only used for js_parse_skip_parens_token() */
19872
};
19873
19874
1.74M
#define TOK_FIRST_KEYWORD   TOK_NULL
19875
859k
#define TOK_LAST_KEYWORD    TOK_AWAIT
19876
19877
/* unicode code points */
19878
#define CP_NBSP 0x00a0
19879
#define CP_BOM  0xfeff
19880
19881
2.83M
#define CP_LS   0x2028
19882
1.41M
#define CP_PS   0x2029
19883
19884
typedef struct BlockEnv {
19885
    struct BlockEnv *prev;
19886
    JSAtom label_name; /* JS_ATOM_NULL if none */
19887
    int label_break; /* -1 if none */
19888
    int label_cont; /* -1 if none */
19889
    int drop_count; /* number of stack elements to drop */
19890
    int label_finally; /* -1 if none */
19891
    int scope_level;
19892
    int has_iterator;
19893
} BlockEnv;
19894
19895
typedef struct JSGlobalVar {
19896
    int cpool_idx; /* if >= 0, index in the constant pool for hoisted
19897
                      function defintion*/
19898
    uint8_t force_init : 1; /* force initialization to undefined */
19899
    uint8_t is_lexical : 1; /* global let/const definition */
19900
    uint8_t is_const   : 1; /* const definition */
19901
    int scope_level;    /* scope of definition */
19902
    JSAtom var_name;  /* variable name */
19903
} JSGlobalVar;
19904
19905
typedef struct RelocEntry {
19906
    struct RelocEntry *next;
19907
    uint32_t addr; /* address to patch */
19908
    int size;   /* address size: 1, 2 or 4 bytes */
19909
} RelocEntry;
19910
19911
typedef struct JumpSlot {
19912
    int op;
19913
    int size;
19914
    int pos;
19915
    int label;
19916
} JumpSlot;
19917
19918
typedef struct LabelSlot {
19919
    int ref_count;
19920
    int pos;    /* phase 1 address, -1 means not resolved yet */
19921
    int pos2;   /* phase 2 address, -1 means not resolved yet */
19922
    int addr;   /* phase 3 address, -1 means not resolved yet */
19923
    RelocEntry *first_reloc;
19924
} LabelSlot;
19925
19926
typedef struct LineNumberSlot {
19927
    uint32_t pc;
19928
    int line_num;
19929
} LineNumberSlot;
19930
19931
typedef enum JSParseFunctionEnum {
19932
    JS_PARSE_FUNC_STATEMENT,
19933
    JS_PARSE_FUNC_VAR,
19934
    JS_PARSE_FUNC_EXPR,
19935
    JS_PARSE_FUNC_ARROW,
19936
    JS_PARSE_FUNC_GETTER,
19937
    JS_PARSE_FUNC_SETTER,
19938
    JS_PARSE_FUNC_METHOD,
19939
    JS_PARSE_FUNC_CLASS_CONSTRUCTOR,
19940
    JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR,
19941
} JSParseFunctionEnum;
19942
19943
typedef enum JSParseExportEnum {
19944
    JS_PARSE_EXPORT_NONE,
19945
    JS_PARSE_EXPORT_NAMED,
19946
    JS_PARSE_EXPORT_DEFAULT,
19947
} JSParseExportEnum;
19948
19949
typedef struct JSFunctionDef {
19950
    JSContext *ctx;
19951
    struct JSFunctionDef *parent;
19952
    int parent_cpool_idx; /* index in the constant pool of the parent
19953
                             or -1 if none */
19954
    int parent_scope_level; /* scope level in parent at point of definition */
19955
    struct list_head child_list; /* list of JSFunctionDef.link */
19956
    struct list_head link;
19957
19958
    BOOL is_eval; /* TRUE if eval code */
19959
    int eval_type; /* only valid if is_eval = TRUE */
19960
    BOOL is_global_var; /* TRUE if variables are not defined locally:
19961
                           eval global, eval module or non strict eval */
19962
    BOOL is_func_expr; /* TRUE if function expression */
19963
    BOOL has_home_object; /* TRUE if the home object is available */
19964
    BOOL has_prototype; /* true if a prototype field is necessary */
19965
    BOOL has_simple_parameter_list;
19966
    BOOL has_parameter_expressions; /* if true, an argument scope is created */
19967
    BOOL has_use_strict; /* to reject directive in special cases */
19968
    BOOL has_eval_call; /* true if the function contains a call to eval() */
19969
    BOOL has_arguments_binding; /* true if the 'arguments' binding is
19970
                                   available in the function */
19971
    BOOL has_this_binding; /* true if the 'this' and new.target binding are
19972
                              available in the function */
19973
    BOOL new_target_allowed; /* true if the 'new.target' does not
19974
                                throw a syntax error */
19975
    BOOL super_call_allowed; /* true if super() is allowed */
19976
    BOOL super_allowed; /* true if super. or super[] is allowed */
19977
    BOOL arguments_allowed; /* true if the 'arguments' identifier is allowed */
19978
    BOOL is_derived_class_constructor;
19979
    BOOL in_function_body;
19980
    BOOL backtrace_barrier;
19981
    JSFunctionKindEnum func_kind : 8;
19982
    JSParseFunctionEnum func_type : 8;
19983
    uint8_t js_mode; /* bitmap of JS_MODE_x */
19984
    JSAtom func_name; /* JS_ATOM_NULL if no name */
19985
19986
    JSVarDef *vars;
19987
    int var_size; /* allocated size for vars[] */
19988
    int var_count;
19989
    JSVarDef *args;
19990
    int arg_size; /* allocated size for args[] */
19991
    int arg_count; /* number of arguments */
19992
    int defined_arg_count;
19993
    int var_object_idx; /* -1 if none */
19994
    int arg_var_object_idx; /* -1 if none (var object for the argument scope) */
19995
    int arguments_var_idx; /* -1 if none */
19996
    int arguments_arg_idx; /* argument variable definition in argument scope, 
19997
                              -1 if none */
19998
    int func_var_idx; /* variable containing the current function (-1
19999
                         if none, only used if is_func_expr is true) */
20000
    int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */
20001
    int this_var_idx; /* variable containg the 'this' value, -1 if none */
20002
    int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */
20003
    int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */
20004
    int home_object_var_idx;
20005
    BOOL need_home_object;
20006
    
20007
    int scope_level;    /* index into fd->scopes if the current lexical scope */
20008
    int scope_first;    /* index into vd->vars of first lexically scoped variable */
20009
    int scope_size;     /* allocated size of fd->scopes array */
20010
    int scope_count;    /* number of entries used in the fd->scopes array */
20011
    JSVarScope *scopes;
20012
    JSVarScope def_scope_array[4];
20013
    int body_scope; /* scope of the body of the function or eval */
20014
20015
    int global_var_count;
20016
    int global_var_size;
20017
    JSGlobalVar *global_vars;
20018
20019
    DynBuf byte_code;
20020
    int last_opcode_pos; /* -1 if no last opcode */
20021
    int last_opcode_line_num;
20022
    BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */
20023
    
20024
    LabelSlot *label_slots;
20025
    int label_size; /* allocated size for label_slots[] */
20026
    int label_count;
20027
    BlockEnv *top_break; /* break/continue label stack */
20028
20029
    /* constant pool (strings, functions, numbers) */
20030
    JSValue *cpool;
20031
    int cpool_count;
20032
    int cpool_size;
20033
20034
    /* list of variables in the closure */
20035
    int closure_var_count;
20036
    int closure_var_size;
20037
    JSClosureVar *closure_var;
20038
20039
    JumpSlot *jump_slots;
20040
    int jump_size;
20041
    int jump_count;
20042
20043
    LineNumberSlot *line_number_slots;
20044
    int line_number_size;
20045
    int line_number_count;
20046
    int line_number_last;
20047
    int line_number_last_pc;
20048
20049
    /* pc2line table */
20050
    JSAtom filename;
20051
    int line_num;
20052
    DynBuf pc2line;
20053
20054
    char *source;  /* raw source, utf-8 encoded */
20055
    int source_len;
20056
20057
    JSModuleDef *module; /* != NULL when parsing a module */
20058
} JSFunctionDef;
20059
20060
typedef struct JSToken {
20061
    int val;
20062
    int line_num;   /* line number of token start */
20063
    const uint8_t *ptr;
20064
    union {
20065
        struct {
20066
            JSValue str;
20067
            int sep;
20068
        } str;
20069
        struct {
20070
            JSValue val;
20071
#ifdef CONFIG_BIGNUM
20072
            slimb_t exponent; /* may be != 0 only if val is a float */
20073
#endif
20074
        } num;
20075
        struct {
20076
            JSAtom atom;
20077
            BOOL has_escape;
20078
            BOOL is_reserved;
20079
        } ident;
20080
        struct {
20081
            JSValue body;
20082
            JSValue flags;
20083
        } regexp;
20084
    } u;
20085
} JSToken;
20086
20087
typedef struct JSParseState {
20088
    JSContext *ctx;
20089
    int last_line_num;  /* line number of last token */
20090
    int line_num;       /* line number of current offset */
20091
    const char *filename;
20092
    JSToken token;
20093
    BOOL got_lf; /* true if got line feed before the current token */
20094
    const uint8_t *last_ptr;
20095
    const uint8_t *buf_ptr;
20096
    const uint8_t *buf_end;
20097
20098
    /* current function code */
20099
    JSFunctionDef *cur_func;
20100
    BOOL is_module; /* parsing a module */
20101
    BOOL allow_html_comments;
20102
    BOOL ext_json; /* true if accepting JSON superset */
20103
} JSParseState;
20104
20105
typedef struct JSOpCode {
20106
#ifdef DUMP_BYTECODE
20107
    const char *name;
20108
#endif
20109
    uint8_t size; /* in bytes */
20110
    /* the opcodes remove n_pop items from the top of the stack, then
20111
       pushes n_push items */
20112
    uint8_t n_pop;
20113
    uint8_t n_push;
20114
    uint8_t fmt;
20115
} JSOpCode;
20116
20117
static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = {
20118
#define FMT(f)
20119
#ifdef DUMP_BYTECODE
20120
#define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f },
20121
#else
20122
#define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f },
20123
#endif
20124
#include "quickjs-opcode.h"
20125
#undef DEF
20126
#undef FMT
20127
};
20128
20129
#if SHORT_OPCODES
20130
/* After the final compilation pass, short opcodes are used. Their
20131
   opcodes overlap with the temporary opcodes which cannot appear in
20132
   the final bytecode. Their description is after the temporary
20133
   opcodes in opcode_info[]. */
20134
#define short_opcode_info(op)           \
20135
4.86M
    opcode_info[(op) >= OP_TEMP_START ? \
20136
4.86M
                (op) + (OP_TEMP_END - OP_TEMP_START) : (op)]
20137
#else
20138
#define short_opcode_info(op) opcode_info[op]
20139
#endif
20140
20141
static __exception int next_token(JSParseState *s);
20142
20143
static void free_token(JSParseState *s, JSToken *token)
20144
1.53M
{
20145
1.53M
    switch(token->val) {
20146
0
#ifdef CONFIG_BIGNUM
20147
4.03k
    case TOK_NUMBER:
20148
4.03k
        JS_FreeValue(s->ctx, token->u.num.val);
20149
4.03k
        break;
20150
0
#endif
20151
2.05k
    case TOK_STRING:
20152
2.78k
    case TOK_TEMPLATE:
20153
2.78k
        JS_FreeValue(s->ctx, token->u.str.str);
20154
2.78k
        break;
20155
67
    case TOK_REGEXP:
20156
67
        JS_FreeValue(s->ctx, token->u.regexp.body);
20157
67
        JS_FreeValue(s->ctx, token->u.regexp.flags);
20158
67
        break;
20159
665k
    case TOK_IDENT:
20160
665k
    case TOK_PRIVATE_NAME:
20161
665k
        JS_FreeAtom(s->ctx, token->u.ident.atom);
20162
665k
        break;
20163
864k
    default:
20164
864k
        if (token->val >= TOK_FIRST_KEYWORD &&
20165
864k
            token->val <= TOK_LAST_KEYWORD) {
20166
16.8k
            JS_FreeAtom(s->ctx, token->u.ident.atom);
20167
16.8k
        }
20168
864k
        break;
20169
1.53M
    }
20170
1.53M
}
20171
20172
static void __attribute((unused)) dump_token(JSParseState *s,
20173
                                             const JSToken *token)
20174
0
{
20175
0
    switch(token->val) {
20176
0
    case TOK_NUMBER:
20177
0
        {
20178
0
            double d;
20179
0
            JS_ToFloat64(s->ctx, &d, token->u.num.val);  /* no exception possible */
20180
0
            printf("number: %.14g\n", d);
20181
0
        }
20182
0
        break;
20183
0
    case TOK_IDENT:
20184
0
    dump_atom:
20185
0
        {
20186
0
            char buf[ATOM_GET_STR_BUF_SIZE];
20187
0
            printf("ident: '%s'\n",
20188
0
                   JS_AtomGetStr(s->ctx, buf, sizeof(buf), token->u.ident.atom));
20189
0
        }
20190
0
        break;
20191
0
    case TOK_STRING:
20192
0
        {
20193
0
            const char *str;
20194
0
            /* XXX: quote the string */
20195
0
            str = JS_ToCString(s->ctx, token->u.str.str);
20196
0
            printf("string: '%s'\n", str);
20197
0
            JS_FreeCString(s->ctx, str);
20198
0
        }
20199
0
        break;
20200
0
    case TOK_TEMPLATE:
20201
0
        {
20202
0
            const char *str;
20203
0
            str = JS_ToCString(s->ctx, token->u.str.str);
20204
0
            printf("template: `%s`\n", str);
20205
0
            JS_FreeCString(s->ctx, str);
20206
0
        }
20207
0
        break;
20208
0
    case TOK_REGEXP:
20209
0
        {
20210
0
            const char *str, *str2;
20211
0
            str = JS_ToCString(s->ctx, token->u.regexp.body);
20212
0
            str2 = JS_ToCString(s->ctx, token->u.regexp.flags);
20213
0
            printf("regexp: '%s' '%s'\n", str, str2);
20214
0
            JS_FreeCString(s->ctx, str);
20215
0
            JS_FreeCString(s->ctx, str2);
20216
0
        }
20217
0
        break;
20218
0
    case TOK_EOF:
20219
0
        printf("eof\n");
20220
0
        break;
20221
0
    default:
20222
0
        if (s->token.val >= TOK_NULL && s->token.val <= TOK_LAST_KEYWORD) {
20223
0
            goto dump_atom;
20224
0
        } else if (s->token.val >= 256) {
20225
0
            printf("token: %d\n", token->val);
20226
0
        } else {
20227
0
            printf("token: '%c'\n", token->val);
20228
0
        }
20229
0
        break;
20230
0
    }
20231
0
}
20232
20233
int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const char *fmt, ...)
20234
16
{
20235
16
    JSContext *ctx = s->ctx;
20236
16
    va_list ap;
20237
16
    int backtrace_flags;
20238
    
20239
16
    va_start(ap, fmt);
20240
16
    JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE);
20241
16
    va_end(ap);
20242
16
    backtrace_flags = 0;
20243
16
    if (s->cur_func && s->cur_func->backtrace_barrier)
20244
0
        backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
20245
16
    build_backtrace(ctx, ctx->rt->current_exception, s->filename, s->line_num,
20246
16
                    backtrace_flags);
20247
16
    return -1;
20248
16
}
20249
20250
static int js_parse_expect(JSParseState *s, int tok)
20251
61.8k
{
20252
61.8k
    if (s->token.val != tok) {
20253
        /* XXX: dump token correctly in all cases */
20254
1
        return js_parse_error(s, "expecting '%c'", tok);
20255
1
    }
20256
61.8k
    return next_token(s);
20257
61.8k
}
20258
20259
static int js_parse_expect_semi(JSParseState *s)
20260
110k
{
20261
110k
    if (s->token.val != ';') {
20262
        /* automatic insertion of ';' */
20263
110k
        if (s->token.val == TOK_EOF || s->token.val == '}' || s->got_lf) {
20264
110k
            return 0;
20265
110k
        }
20266
1
        return js_parse_error(s, "expecting '%c'", ';');
20267
110k
    }
20268
454
    return next_token(s);
20269
110k
}
20270
20271
static int js_parse_error_reserved_identifier(JSParseState *s)
20272
0
{
20273
0
    char buf1[ATOM_GET_STR_BUF_SIZE];
20274
0
    return js_parse_error(s, "'%s' is a reserved identifier",
20275
0
                          JS_AtomGetStr(s->ctx, buf1, sizeof(buf1),
20276
0
                                        s->token.u.ident.atom));
20277
0
}
20278
20279
static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
20280
723
{
20281
723
    uint32_t c;
20282
723
    StringBuffer b_s, *b = &b_s;
20283
20284
    /* p points to the first byte of the template part */
20285
723
    if (string_buffer_init(s->ctx, b, 32))
20286
0
        goto fail;
20287
361k
    for(;;) {
20288
361k
        if (p >= s->buf_end)
20289
0
            goto unexpected_eof;
20290
361k
        c = *p++;
20291
361k
        if (c == '`') {
20292
            /* template end part */
20293
723
            break;
20294
723
        }
20295
360k
        if (c == '$' && *p == '{') {
20296
            /* template start or middle part */
20297
0
            p++;
20298
0
            break;
20299
0
        }
20300
360k
        if (c == '\\') {
20301
4.72k
            if (string_buffer_putc8(b, c))
20302
0
                goto fail;
20303
4.72k
            if (p >= s->buf_end)
20304
0
                goto unexpected_eof;
20305
4.72k
            c = *p++;
20306
4.72k
        }
20307
        /* newline sequences are normalized as single '\n' bytes */
20308
360k
        if (c == '\r') {
20309
61.7k
            if (*p == '\n')
20310
240
                p++;
20311
61.7k
            c = '\n';
20312
61.7k
        }
20313
360k
        if (c == '\n') {
20314
66.1k
            s->line_num++;
20315
294k
        } else if (c >= 0x80) {
20316
461
            const uint8_t *p_next;
20317
461
            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
20318
461
            if (c > 0x10FFFF) {
20319
0
                js_parse_error(s, "invalid UTF-8 sequence");
20320
0
                goto fail;
20321
0
            }
20322
461
            p = p_next;
20323
461
        }
20324
360k
        if (string_buffer_putc(b, c))
20325
0
            goto fail;
20326
360k
    }
20327
723
    s->token.val = TOK_TEMPLATE;
20328
723
    s->token.u.str.sep = c;
20329
723
    s->token.u.str.str = string_buffer_end(b);
20330
723
    s->buf_ptr = p;
20331
723
    return 0;
20332
20333
0
 unexpected_eof:
20334
0
    js_parse_error(s, "unexpected end of string");
20335
0
 fail:
20336
0
    string_buffer_free(b);
20337
0
    return -1;
20338
0
}
20339
20340
static __exception int js_parse_string(JSParseState *s, int sep,
20341
                                       BOOL do_throw, const uint8_t *p,
20342
                                       JSToken *token, const uint8_t **pp)
20343
2.53k
{
20344
2.53k
    int ret;
20345
2.53k
    uint32_t c;
20346
2.53k
    StringBuffer b_s, *b = &b_s;
20347
20348
    /* string */
20349
2.53k
    if (string_buffer_init(s->ctx, b, 32))
20350
0
        goto fail;
20351
665k
    for(;;) {
20352
665k
        if (p >= s->buf_end)
20353
0
            goto invalid_char;
20354
665k
        c = *p;
20355
665k
        if (c < 0x20) {
20356
75.2k
            if (!s->cur_func) {
20357
0
                if (do_throw)
20358
0
                    js_parse_error(s, "invalid character in a JSON string");
20359
0
                goto fail;
20360
0
            }
20361
75.2k
            if (sep == '`') {
20362
64.5k
                if (c == '\r') {
20363
31.1k
                    if (p[1] == '\n')
20364
120
                        p++;
20365
31.1k
                    c = '\n';
20366
31.1k
                }
20367
                /* do not update s->line_num */
20368
64.5k
            } else if (c == '\n' || c == '\r')
20369
0
                goto invalid_char;
20370
75.2k
        }
20371
665k
        p++;
20372
665k
        if (c == sep)
20373
2.53k
            break;
20374
663k
        if (c == '$' && *p == '{' && sep == '`') {
20375
            /* template start or middle part */
20376
0
            p++;
20377
0
            break;
20378
0
        }
20379
663k
        if (c == '\\') {
20380
3.26k
            c = *p;
20381
            /* XXX: need a specific JSON case to avoid
20382
               accepting invalid escapes */
20383
3.26k
            switch(c) {
20384
166
            case '\0':
20385
166
                if (p >= s->buf_end)
20386
0
                    goto invalid_char;
20387
166
                p++;
20388
166
                break;
20389
0
            case '\'':
20390
1
            case '\"':
20391
1.09k
            case '\\':
20392
1.09k
                p++;
20393
1.09k
                break;
20394
0
            case '\r':  /* accept DOS and MAC newline sequences */
20395
0
                if (p[1] == '\n') {
20396
0
                    p++;
20397
0
                }
20398
                /* fall thru */
20399
0
            case '\n':
20400
                /* ignore escaped newline sequence */
20401
0
                p++;
20402
0
                if (sep != '`')
20403
0
                    s->line_num++;
20404
0
                continue;
20405
2.00k
            default:
20406
2.00k
                if (c >= '0' && c <= '9') {
20407
892
                    if (!s->cur_func)
20408
0
                        goto invalid_escape; /* JSON case */
20409
892
                    if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`')
20410
0
                        goto parse_escape;
20411
892
                    if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) {
20412
890
                        p++;
20413
890
                        c = '\0';
20414
890
                    } else {
20415
2
                        if (c >= '8' || sep == '`') {
20416
                            /* Note: according to ES2021, \8 and \9 are not
20417
                               accepted in strict mode or in templates. */
20418
2
                            goto invalid_escape;
20419
2
                        } else {
20420
0
                            if (do_throw)
20421
0
                                js_parse_error(s, "octal escape sequences are not allowed in strict mode");
20422
0
                        }
20423
0
                        goto fail;
20424
2
                    }
20425
1.11k
                } else if (c >= 0x80) {
20426
0
                    const uint8_t *p_next;
20427
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
20428
0
                    if (c > 0x10FFFF) {
20429
0
                        goto invalid_utf8;
20430
0
                    }
20431
0
                    p = p_next;
20432
                    /* LS or PS are skipped */
20433
0
                    if (c == CP_LS || c == CP_PS)
20434
0
                        continue;
20435
1.11k
                } else {
20436
1.11k
                parse_escape:
20437
1.11k
                    ret = lre_parse_escape(&p, TRUE);
20438
1.11k
                    if (ret == -1) {
20439
2
                    invalid_escape:
20440
2
                        if (do_throw)
20441
0
                            js_parse_error(s, "malformed escape sequence in string literal");
20442
2
                        goto fail;
20443
1.11k
                    } else if (ret < 0) {
20444
                        /* ignore the '\' (could output a warning) */
20445
1.10k
                        p++;
20446
1.10k
                    } else {
20447
10
                        c = ret;
20448
10
                    }
20449
1.11k
                }
20450
2.00k
                break;
20451
3.26k
            }
20452
659k
        } else if (c >= 0x80) {
20453
600
            const uint8_t *p_next;
20454
600
            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
20455
600
            if (c > 0x10FFFF)
20456
0
                goto invalid_utf8;
20457
600
            p = p_next;
20458
600
        }
20459
663k
        if (string_buffer_putc(b, c))
20460
0
            goto fail;
20461
663k
    }
20462
2.53k
    token->val = TOK_STRING;
20463
2.53k
    token->u.str.sep = c;
20464
2.53k
    token->u.str.str = string_buffer_end(b);
20465
2.53k
    *pp = p;
20466
2.53k
    return 0;
20467
20468
0
 invalid_utf8:
20469
0
    if (do_throw)
20470
0
        js_parse_error(s, "invalid UTF-8 sequence");
20471
0
    goto fail;
20472
0
 invalid_char:
20473
0
    if (do_throw)
20474
0
        js_parse_error(s, "unexpected end of string");
20475
2
 fail:
20476
2
    string_buffer_free(b);
20477
2
    return -1;
20478
0
}
20479
20480
1.03M
static inline BOOL token_is_pseudo_keyword(JSParseState *s, JSAtom atom) {
20481
1.03M
    return s->token.val == TOK_IDENT && s->token.u.ident.atom == atom &&
20482
1.03M
        !s->token.u.ident.has_escape;
20483
1.03M
}
20484
20485
static __exception int js_parse_regexp(JSParseState *s)
20486
67
{
20487
67
    const uint8_t *p;
20488
67
    BOOL in_class;
20489
67
    StringBuffer b_s, *b = &b_s;
20490
67
    StringBuffer b2_s, *b2 = &b2_s;
20491
67
    uint32_t c;
20492
20493
67
    p = s->buf_ptr;
20494
67
    p++;
20495
67
    in_class = FALSE;
20496
67
    if (string_buffer_init(s->ctx, b, 32))
20497
0
        return -1;
20498
67
    if (string_buffer_init(s->ctx, b2, 1))
20499
0
        goto fail;
20500
301
    for(;;) {
20501
301
        if (p >= s->buf_end) {
20502
0
        eof_error:
20503
0
            js_parse_error(s, "unexpected end of regexp");
20504
0
            goto fail;
20505
0
        }
20506
301
        c = *p++;
20507
301
        if (c == '\n' || c == '\r') {
20508
0
            goto eol_error;
20509
301
        } else if (c == '/') {
20510
67
            if (!in_class)
20511
67
                break;
20512
234
        } else if (c == '[') {
20513
2
            in_class = TRUE;
20514
232
        } else if (c == ']') {
20515
            /* XXX: incorrect as the first character in a class */
20516
2
            in_class = FALSE;
20517
230
        } else if (c == '\\') {
20518
40
            if (string_buffer_putc8(b, c))
20519
0
                goto fail;
20520
40
            c = *p++;
20521
40
            if (c == '\n' || c == '\r')
20522
0
                goto eol_error;
20523
40
            else if (c == '\0' && p >= s->buf_end)
20524
0
                goto eof_error;
20525
40
            else if (c >= 0x80) {
20526
0
                const uint8_t *p_next;
20527
0
                c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
20528
0
                if (c > 0x10FFFF) {
20529
0
                    goto invalid_utf8;
20530
0
                }
20531
0
                p = p_next;
20532
0
                if (c == CP_LS || c == CP_PS)
20533
0
                    goto eol_error;
20534
0
            }
20535
190
        } else if (c >= 0x80) {
20536
3
            const uint8_t *p_next;
20537
3
            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
20538
3
            if (c > 0x10FFFF) {
20539
0
            invalid_utf8:
20540
0
                js_parse_error(s, "invalid UTF-8 sequence");
20541
0
                goto fail;
20542
0
            }
20543
3
            p = p_next;
20544
            /* LS or PS are considered as line terminator */
20545
3
            if (c == CP_LS || c == CP_PS) {
20546
0
            eol_error:
20547
0
                js_parse_error(s, "unexpected line terminator in regexp");
20548
0
                goto fail;
20549
0
            }
20550
3
        }
20551
234
        if (string_buffer_putc(b, c))
20552
0
            goto fail;
20553
234
    }
20554
20555
    /* flags */
20556
71
    for(;;) {
20557
71
        const uint8_t *p_next = p;
20558
71
        c = *p_next++;
20559
71
        if (c >= 0x80) {
20560
0
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
20561
0
            if (c > 0x10FFFF) {
20562
0
                goto invalid_utf8;
20563
0
            }
20564
0
        }
20565
71
        if (!lre_js_is_ident_next(c))
20566
67
            break;
20567
4
        if (string_buffer_putc(b2, c))
20568
0
            goto fail;
20569
4
        p = p_next;
20570
4
    }
20571
20572
67
    s->token.val = TOK_REGEXP;
20573
67
    s->token.u.regexp.body = string_buffer_end(b);
20574
67
    s->token.u.regexp.flags = string_buffer_end(b2);
20575
67
    s->buf_ptr = p;
20576
67
    return 0;
20577
0
 fail:
20578
0
    string_buffer_free(b);
20579
0
    string_buffer_free(b2);
20580
0
    return -1;
20581
67
}
20582
20583
static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
20584
                                     char *static_buf)
20585
31
{
20586
31
    char *buf, *new_buf;
20587
31
    size_t size, new_size;
20588
    
20589
31
    buf = *pbuf;
20590
31
    size = *psize;
20591
31
    if (size >= (SIZE_MAX / 3) * 2)
20592
0
        new_size = SIZE_MAX;
20593
31
    else
20594
31
        new_size = size + (size >> 1);
20595
31
    if (buf == static_buf) {
20596
7
        new_buf = js_malloc(ctx, new_size);
20597
7
        if (!new_buf)
20598
0
            return -1;
20599
7
        memcpy(new_buf, buf, size);
20600
24
    } else {
20601
24
        new_buf = js_realloc(ctx, buf, new_size);
20602
24
        if (!new_buf)
20603
0
            return -1;
20604
24
    }
20605
31
    *pbuf = new_buf;
20606
31
    *psize = new_size;
20607
31
    return 0;
20608
31
}
20609
20610
/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
20611
static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
20612
                          BOOL *pident_has_escape, int c, BOOL is_private)
20613
681k
{
20614
681k
    const uint8_t *p, *p1;
20615
681k
    char ident_buf[128], *buf;
20616
681k
    size_t ident_size, ident_pos;
20617
681k
    JSAtom atom;
20618
    
20619
681k
    p = *pp;
20620
681k
    buf = ident_buf;
20621
681k
    ident_size = sizeof(ident_buf);
20622
681k
    ident_pos = 0;
20623
681k
    if (is_private)
20624
20
        buf[ident_pos++] = '#';
20625
2.43M
    for(;;) {
20626
2.43M
        p1 = p;
20627
        
20628
2.43M
        if (c < 128) {
20629
2.43M
            buf[ident_pos++] = c;
20630
2.43M
        } else {
20631
1.83k
            ident_pos += unicode_to_utf8((uint8_t*)buf + ident_pos, c);
20632
1.83k
        }
20633
2.43M
        c = *p1++;
20634
2.43M
        if (c == '\\' && *p1 == 'u') {
20635
0
            c = lre_parse_escape(&p1, TRUE);
20636
0
            *pident_has_escape = TRUE;
20637
2.43M
        } else if (c >= 128) {
20638
1.82k
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
20639
1.82k
        }
20640
2.43M
        if (!lre_js_is_ident_next(c))
20641
681k
            break;
20642
1.75M
        p = p1;
20643
1.75M
        if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
20644
31
            if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
20645
0
                atom = JS_ATOM_NULL;
20646
0
                goto done;
20647
0
            }
20648
31
        }
20649
1.75M
    }
20650
681k
    atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
20651
681k
 done:
20652
681k
    if (unlikely(buf != ident_buf))
20653
7
        js_free(s->ctx, buf);
20654
681k
    *pp = p;
20655
681k
    return atom;
20656
681k
}
20657
20658
20659
static __exception int next_token(JSParseState *s)
20660
1.53M
{
20661
1.53M
    const uint8_t *p;
20662
1.53M
    int c;
20663
1.53M
    BOOL ident_has_escape;
20664
1.53M
    JSAtom atom;
20665
    
20666
1.53M
    if (js_check_stack_overflow(s->ctx->rt, 0)) {
20667
0
        return js_parse_error(s, "stack overflow");
20668
0
    }
20669
    
20670
1.53M
    free_token(s, &s->token);
20671
20672
1.53M
    p = s->last_ptr = s->buf_ptr;
20673
1.53M
    s->got_lf = FALSE;
20674
1.53M
    s->last_line_num = s->token.line_num;
20675
2.00M
 redo:
20676
2.00M
    s->token.line_num = s->line_num;
20677
2.00M
    s->token.ptr = p;
20678
2.00M
    c = *p;
20679
2.00M
    switch(c) {
20680
41.3k
    case 0:
20681
41.3k
        if (p >= s->buf_end) {
20682
41.1k
            s->token.val = TOK_EOF;
20683
41.1k
        } else {
20684
207
            goto def_token;
20685
207
        }
20686
41.1k
        break;
20687
41.1k
    case '`':
20688
723
        if (js_parse_template_part(s, p + 1))
20689
0
            goto fail;
20690
723
        p = s->buf_ptr;
20691
723
        break;
20692
1.86k
    case '\'':
20693
2.05k
    case '\"':
20694
2.05k
        if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
20695
0
            goto fail;
20696
2.05k
        break;
20697
368k
    case '\r':  /* accept DOS and MAC newline sequences */
20698
368k
        if (p[1] == '\n') {
20699
759
            p++;
20700
759
        }
20701
        /* fall thru */
20702
449k
    case '\n':
20703
449k
        p++;
20704
449k
    line_terminator:
20705
449k
        s->got_lf = TRUE;
20706
449k
        s->line_num++;
20707
449k
        goto redo;
20708
2.95k
    case '\f':
20709
3.77k
    case '\v':
20710
12.1k
    case ' ':
20711
14.4k
    case '\t':
20712
14.4k
        p++;
20713
14.4k
        goto redo;
20714
8.89k
    case '/':
20715
8.89k
        if (p[1] == '*') {
20716
            /* comment */
20717
3
            p += 2;
20718
175k
            for(;;) {
20719
175k
                if (*p == '\0' && p >= s->buf_end) {
20720
0
                    js_parse_error(s, "unexpected end of comment");
20721
0
                    goto fail;
20722
0
                }
20723
175k
                if (p[0] == '*' && p[1] == '/') {
20724
3
                    p += 2;
20725
3
                    break;
20726
3
                }
20727
175k
                if (*p == '\n') {
20728
735
                    s->line_num++;
20729
735
                    s->got_lf = TRUE; /* considered as LF for ASI */
20730
735
                    p++;
20731
174k
                } else if (*p == '\r') {
20732
221
                    s->got_lf = TRUE; /* considered as LF for ASI */
20733
221
                    p++;
20734
174k
                } else if (*p >= 0x80) {
20735
113k
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
20736
113k
                    if (c == CP_LS || c == CP_PS) {
20737
0
                        s->got_lf = TRUE; /* considered as LF for ASI */
20738
113k
                    } else if (c == -1) {
20739
113k
                        p++; /* skip invalid UTF-8 */
20740
113k
                    }
20741
113k
                } else {
20742
61.2k
                    p++;
20743
61.2k
                }
20744
175k
            }
20745
3
            goto redo;
20746
8.89k
        } else if (p[1] == '/') {
20747
            /* line comment */
20748
8.06k
            p += 2;
20749
8.06k
        skip_line_comment:
20750
4.40M
            for(;;) {
20751
4.40M
                if (*p == '\0' && p >= s->buf_end)
20752
23
                    break;
20753
4.40M
                if (*p == '\r' || *p == '\n')
20754
8.04k
                    break;
20755
4.40M
                if (*p >= 0x80) {
20756
1.30M
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
20757
                    /* LS or PS are considered as line terminator */
20758
1.30M
                    if (c == CP_LS || c == CP_PS) {
20759
1
                        break;
20760
1.30M
                    } else if (c == -1) {
20761
1.29M
                        p++; /* skip invalid UTF-8 */
20762
1.29M
                    }
20763
3.09M
                } else {
20764
3.09M
                    p++;
20765
3.09M
                }
20766
4.40M
            }
20767
8.06k
            goto redo;
20768
8.06k
        } else if (p[1] == '=') {
20769
0
            p += 2;
20770
0
            s->token.val = TOK_DIV_ASSIGN;
20771
827
        } else {
20772
827
            p++;
20773
827
            s->token.val = c;
20774
827
        }
20775
827
        break;
20776
827
    case '\\':
20777
0
        if (p[1] == 'u') {
20778
0
            const uint8_t *p1 = p + 1;
20779
0
            int c1 = lre_parse_escape(&p1, TRUE);
20780
0
            if (c1 >= 0 && lre_js_is_ident_first(c1)) {
20781
0
                c = c1;
20782
0
                p = p1;
20783
0
                ident_has_escape = TRUE;
20784
0
                goto has_ident;
20785
0
            } else {
20786
                /* XXX: syntax error? */
20787
0
            }
20788
0
        }
20789
0
        goto def_token;
20790
236k
    case 'a': case 'b': case 'c': case 'd':
20791
254k
    case 'e': case 'f': case 'g': case 'h':
20792
483k
    case 'i': case 'j': case 'k': case 'l':
20793
503k
    case 'm': case 'n': case 'o': case 'p':
20794
512k
    case 'q': case 'r': case 's': case 't':
20795
554k
    case 'u': case 'v': case 'w': case 'x':
20796
555k
    case 'y': case 'z': 
20797
560k
    case 'A': case 'B': case 'C': case 'D':
20798
563k
    case 'E': case 'F': case 'G': case 'H':
20799
569k
    case 'I': case 'J': case 'K': case 'L':
20800
583k
    case 'M': case 'N': case 'O': case 'P':
20801
583k
    case 'Q': case 'R': case 'S': case 'T':
20802
639k
    case 'U': case 'V': case 'W': case 'X':
20803
681k
    case 'Y': case 'Z': 
20804
681k
    case '_':
20805
681k
    case '$':
20806
        /* identifier */
20807
681k
        p++;
20808
681k
        ident_has_escape = FALSE;
20809
681k
    has_ident:
20810
681k
        atom = parse_ident(s, &p, &ident_has_escape, c, FALSE);
20811
681k
        if (atom == JS_ATOM_NULL)
20812
0
            goto fail;
20813
681k
        s->token.u.ident.atom = atom;
20814
681k
        s->token.u.ident.has_escape = ident_has_escape;
20815
681k
        s->token.u.ident.is_reserved = FALSE;
20816
681k
        if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
20817
681k
            (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&
20818
665k
             (s->cur_func->js_mode & JS_MODE_STRICT)) ||
20819
681k
            (s->token.u.ident.atom == JS_ATOM_yield &&
20820
665k
             ((s->cur_func->func_kind & JS_FUNC_GENERATOR) ||
20821
383
              (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
20822
0
               !s->cur_func->in_function_body && s->cur_func->parent &&
20823
0
               (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||
20824
681k
            (s->token.u.ident.atom == JS_ATOM_await &&
20825
665k
             (s->is_module ||
20826
0
              (((s->cur_func->func_kind & JS_FUNC_ASYNC) ||
20827
0
                (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
20828
0
                 !s->cur_func->in_function_body && s->cur_func->parent &&
20829
16.8k
                 (s->cur_func->parent->func_kind & JS_FUNC_ASYNC))))))) {
20830
16.8k
                  if (ident_has_escape) {
20831
0
                      s->token.u.ident.is_reserved = TRUE;
20832
0
                      s->token.val = TOK_IDENT;
20833
16.8k
                  } else {
20834
                      /* The keywords atoms are pre allocated */
20835
16.8k
                      s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD;
20836
16.8k
                  }
20837
665k
        } else {
20838
665k
            s->token.val = TOK_IDENT;
20839
665k
        }
20840
681k
        break;
20841
20
    case '#':
20842
        /* private name */
20843
20
        {
20844
20
            const uint8_t *p1;
20845
20
            p++;
20846
20
            p1 = p;
20847
20
            c = *p1++;
20848
20
            if (c == '\\' && *p1 == 'u') {
20849
0
                c = lre_parse_escape(&p1, TRUE);
20850
20
            } else if (c >= 128) {
20851
0
                c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
20852
0
            }
20853
20
            if (!lre_js_is_ident_first(c)) {
20854
0
                js_parse_error(s, "invalid first character of private name");
20855
0
                goto fail;
20856
0
            }
20857
20
            p = p1;
20858
20
            ident_has_escape = FALSE; /* not used */
20859
20
            atom = parse_ident(s, &p, &ident_has_escape, c, TRUE);
20860
20
            if (atom == JS_ATOM_NULL)
20861
0
                goto fail;
20862
20
            s->token.u.ident.atom = atom;
20863
20
            s->token.val = TOK_PRIVATE_NAME;
20864
20
        }
20865
0
        break;
20866
4.99k
    case '.':
20867
4.99k
        if (p[1] == '.' && p[2] == '.') {
20868
53
            p += 3;
20869
53
            s->token.val = TOK_ELLIPSIS;
20870
53
            break;
20871
53
        }
20872
4.94k
        if (p[1] >= '0' && p[1] <= '9') {
20873
18
            goto parse_number;
20874
4.92k
        } else {
20875
4.92k
            goto def_token;
20876
4.92k
        }
20877
0
        break;
20878
1.29k
    case '0':
20879
        /* in strict mode, octal literals are not accepted */
20880
1.29k
        if (is_digit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) {
20881
0
            js_parse_error(s, "octal literals are deprecated in strict mode");
20882
0
            goto fail;
20883
0
        }
20884
1.29k
        goto parse_number;
20885
1.29k
    case '1': case '2': case '3': case '4':
20886
1.40k
    case '5': case '6': case '7': case '8':
20887
2.72k
    case '9': 
20888
        /* number */
20889
4.03k
    parse_number:
20890
4.03k
        {
20891
4.03k
            JSValue ret;
20892
4.03k
            const uint8_t *p1;
20893
4.03k
            int flags, radix;
20894
4.03k
            flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |
20895
4.03k
                ATOD_ACCEPT_UNDERSCORES;
20896
4.03k
#ifdef CONFIG_BIGNUM
20897
4.03k
            flags |= ATOD_ACCEPT_SUFFIX;
20898
4.03k
            if (s->cur_func->js_mode & JS_MODE_MATH) {
20899
0
                flags |= ATOD_MODE_BIGINT;
20900
0
                if (s->cur_func->js_mode & JS_MODE_MATH)
20901
0
                    flags |= ATOD_TYPE_BIG_FLOAT;
20902
0
            }
20903
4.03k
#endif
20904
4.03k
            radix = 0;
20905
4.03k
#ifdef CONFIG_BIGNUM
20906
4.03k
            s->token.u.num.exponent = 0;
20907
4.03k
            ret = js_atof2(s->ctx, (const char *)p, (const char **)&p, radix,
20908
4.03k
                           flags, &s->token.u.num.exponent);
20909
#else
20910
            ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
20911
                          flags);
20912
#endif
20913
4.03k
            if (JS_IsException(ret))
20914
4
                goto fail;
20915
            /* reject `10instanceof Number` */
20916
4.03k
            if (JS_VALUE_IS_NAN(ret) ||
20917
4.03k
                lre_js_is_ident_next(unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1))) {
20918
0
                JS_FreeValue(s->ctx, ret);
20919
0
                js_parse_error(s, "invalid number literal");
20920
0
                goto fail;
20921
0
            }
20922
4.03k
            s->token.val = TOK_NUMBER;
20923
4.03k
            s->token.u.num.val = ret;
20924
4.03k
        }
20925
0
        break;
20926
1.12k
    case '*':
20927
1.12k
        if (p[1] == '=') {
20928
4
            p += 2;
20929
4
            s->token.val = TOK_MUL_ASSIGN;
20930
1.12k
        } else if (p[1] == '*') {
20931
19
            if (p[2] == '=') {
20932
0
                p += 3;
20933
0
                s->token.val = TOK_POW_ASSIGN;
20934
19
            } else {
20935
19
                p += 2;
20936
19
                s->token.val = TOK_POW;
20937
19
            }
20938
1.10k
        } else {
20939
1.10k
            goto def_token;
20940
1.10k
        }
20941
23
        break;
20942
23
    case '%':
20943
9
        if (p[1] == '=') {
20944
0
            p += 2;
20945
0
            s->token.val = TOK_MOD_ASSIGN;
20946
9
        } else {
20947
9
            goto def_token;
20948
9
        }
20949
0
        break;
20950
1.99k
    case '+':
20951
1.99k
        if (p[1] == '=') {
20952
4
            p += 2;
20953
4
            s->token.val = TOK_PLUS_ASSIGN;
20954
1.98k
        } else if (p[1] == '+') {
20955
487
            p += 2;
20956
487
            s->token.val = TOK_INC;
20957
1.50k
        } else {
20958
1.50k
            goto def_token;
20959
1.50k
        }
20960
491
        break;
20961
491
    case '-':
20962
232
        if (p[1] == '=') {
20963
2
            p += 2;
20964
2
            s->token.val = TOK_MINUS_ASSIGN;
20965
230
        } else if (p[1] == '-') {
20966
7
            if (s->allow_html_comments &&
20967
7
                p[2] == '>' && s->last_line_num != s->line_num) {
20968
                /* Annex B: `-->` at beginning of line is an html comment end.
20969
                   It extends to the end of the line.
20970
                 */
20971
0
                goto skip_line_comment;
20972
0
            }
20973
7
            p += 2;
20974
7
            s->token.val = TOK_DEC;
20975
223
        } else {
20976
223
            goto def_token;
20977
223
        }
20978
9
        break;
20979
1.48k
    case '<':
20980
1.48k
        if (p[1] == '=') {
20981
8
            p += 2;
20982
8
            s->token.val = TOK_LTE;
20983
1.47k
        } else if (p[1] == '<') {
20984
0
            if (p[2] == '=') {
20985
0
                p += 3;
20986
0
                s->token.val = TOK_SHL_ASSIGN;
20987
0
            } else {
20988
0
                p += 2;
20989
0
                s->token.val = TOK_SHL;
20990
0
            }
20991
1.47k
        } else if (s->allow_html_comments &&
20992
1.47k
                   p[1] == '!' && p[2] == '-' && p[3] == '-') {
20993
            /* Annex B: handle `<!--` single line html comments */
20994
0
            goto skip_line_comment;
20995
1.47k
        } else {
20996
1.47k
            goto def_token;
20997
1.47k
        }
20998
8
        break;
20999
316
    case '>':
21000
316
        if (p[1] == '=') {
21001
14
            p += 2;
21002
14
            s->token.val = TOK_GTE;
21003
302
        } else if (p[1] == '>') {
21004
103
            if (p[2] == '>') {
21005
44
                if (p[3] == '=') {
21006
44
                    p += 4;
21007
44
                    s->token.val = TOK_SHR_ASSIGN;
21008
44
                } else {
21009
0
                    p += 3;
21010
0
                    s->token.val = TOK_SHR;
21011
0
                }
21012
59
            } else if (p[2] == '=') {
21013
4
                p += 3;
21014
4
                s->token.val = TOK_SAR_ASSIGN;
21015
55
            } else {
21016
55
                p += 2;
21017
55
                s->token.val = TOK_SAR;
21018
55
            }
21019
199
        } else {
21020
199
            goto def_token;
21021
199
        }
21022
117
        break;
21023
269k
    case '=':
21024
269k
        if (p[1] == '=') {
21025
147
            if (p[2] == '=') {
21026
16
                p += 3;
21027
16
                s->token.val = TOK_STRICT_EQ;
21028
131
            } else {
21029
131
                p += 2;
21030
131
                s->token.val = TOK_EQ;
21031
131
            }
21032
269k
        } else if (p[1] == '>') {
21033
1.44k
            p += 2;
21034
1.44k
            s->token.val = TOK_ARROW;
21035
268k
        } else {
21036
268k
            goto def_token;
21037
268k
        }
21038
1.58k
        break;
21039
1.58k
    case '!':
21040
796
        if (p[1] == '=') {
21041
14
            if (p[2] == '=') {
21042
2
                p += 3;
21043
2
                s->token.val = TOK_STRICT_NEQ;
21044
12
            } else {
21045
12
                p += 2;
21046
12
                s->token.val = TOK_NEQ;
21047
12
            }
21048
782
        } else {
21049
782
            goto def_token;
21050
782
        }
21051
14
        break;
21052
37
    case '&':
21053
37
        if (p[1] == '=') {
21054
0
            p += 2;
21055
0
            s->token.val = TOK_AND_ASSIGN;
21056
37
        } else if (p[1] == '&') {
21057
20
            if (p[2] == '=') {
21058
0
                p += 3;
21059
0
                s->token.val = TOK_LAND_ASSIGN;
21060
20
            } else {
21061
20
                p += 2;
21062
20
                s->token.val = TOK_LAND;
21063
20
            }
21064
20
        } else {
21065
17
            goto def_token;
21066
17
        }
21067
20
        break;
21068
20
#ifdef CONFIG_BIGNUM
21069
        /* in math mode, '^' is the power operator. '^^' is always the
21070
           xor operator and '**' is always the power operator */
21071
217
    case '^':
21072
217
        if (p[1] == '=') {
21073
48
            p += 2;
21074
48
            if (s->cur_func->js_mode & JS_MODE_MATH)
21075
0
                s->token.val = TOK_MATH_POW_ASSIGN;
21076
48
            else
21077
48
                s->token.val = TOK_XOR_ASSIGN;
21078
169
        } else if (p[1] == '^') {
21079
0
            if (p[2] == '=') {
21080
0
                p += 3;
21081
0
                s->token.val = TOK_XOR_ASSIGN;
21082
0
            } else {
21083
0
                p += 2;
21084
0
                s->token.val = '^';
21085
0
            }
21086
169
        } else {
21087
169
            p++;
21088
169
            if (s->cur_func->js_mode & JS_MODE_MATH)
21089
0
                s->token.val = TOK_MATH_POW;
21090
169
            else
21091
169
                s->token.val = '^';
21092
169
        }
21093
217
        break;
21094
#else
21095
    case '^':
21096
        if (p[1] == '=') {
21097
            p += 2;
21098
            s->token.val = TOK_XOR_ASSIGN;
21099
        } else {
21100
            goto def_token;
21101
        }
21102
        break;
21103
#endif
21104
3.01k
    case '|':
21105
3.01k
        if (p[1] == '=') {
21106
190
            p += 2;
21107
190
            s->token.val = TOK_OR_ASSIGN;
21108
2.82k
        } else if (p[1] == '|') {
21109
2.74k
            if (p[2] == '=') {
21110
2.43k
                p += 3;
21111
2.43k
                s->token.val = TOK_LOR_ASSIGN;
21112
2.43k
            } else {
21113
314
                p += 2;
21114
314
                s->token.val = TOK_LOR;
21115
314
            }
21116
2.74k
        } else {
21117
74
            goto def_token;
21118
74
        }
21119
2.93k
        break;
21120
2.93k
    case '?':
21121
229
        if (p[1] == '?') {
21122
3
            if (p[2] == '=') {
21123
2
                p += 3;
21124
2
                s->token.val = TOK_DOUBLE_QUESTION_MARK_ASSIGN;
21125
2
            } else {
21126
1
                p += 2;
21127
1
                s->token.val = TOK_DOUBLE_QUESTION_MARK;
21128
1
            }
21129
226
        } else if (p[1] == '.' && !(p[2] >= '0' && p[2] <= '9')) {
21130
2
            p += 2;
21131
2
            s->token.val = TOK_QUESTION_MARK_DOT;
21132
224
        } else {
21133
224
            goto def_token;
21134
224
        }
21135
5
        break;
21136
521k
    default:
21137
521k
        if (c >= 128) {
21138
            /* unicode value */
21139
26
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21140
26
            switch(c) {
21141
1
            case CP_PS:
21142
4
            case CP_LS:
21143
                /* XXX: should avoid incrementing line_number, but
21144
                   needed to handle HTML comments */
21145
4
                goto line_terminator; 
21146
22
            default:
21147
22
                if (lre_is_space(c)) {
21148
3
                    goto redo;
21149
19
                } else if (lre_js_is_ident_first(c)) {
21150
16
                    ident_has_escape = FALSE;
21151
16
                    goto has_ident;
21152
16
                } else {
21153
3
                    js_parse_error(s, "unexpected character");
21154
3
                    goto fail;
21155
3
                }
21156
26
            }
21157
26
        }
21158
800k
    def_token:
21159
800k
        s->token.val = c;
21160
800k
        p++;
21161
800k
        break;
21162
2.00M
    }
21163
1.53M
    s->buf_ptr = p;
21164
21165
    //    dump_token(s, &s->token);
21166
1.53M
    return 0;
21167
21168
7
 fail:
21169
7
    s->token.val = TOK_ERROR;
21170
7
    return -1;
21171
2.00M
}
21172
21173
/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
21174
static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
21175
0
{
21176
0
    const uint8_t *p;
21177
0
    char ident_buf[128], *buf;
21178
0
    size_t ident_size, ident_pos;
21179
0
    JSAtom atom;
21180
    
21181
0
    p = *pp;
21182
0
    buf = ident_buf;
21183
0
    ident_size = sizeof(ident_buf);
21184
0
    ident_pos = 0;
21185
0
    for(;;) {
21186
0
        buf[ident_pos++] = c;
21187
0
        c = *p;
21188
0
        if (c >= 128 ||
21189
0
            !((lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1))
21190
0
            break;
21191
0
        p++;
21192
0
        if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
21193
0
            if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
21194
0
                atom = JS_ATOM_NULL;
21195
0
                goto done;
21196
0
            }
21197
0
        }
21198
0
    }
21199
0
    atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
21200
0
 done:
21201
0
    if (unlikely(buf != ident_buf))
21202
0
        js_free(s->ctx, buf);
21203
0
    *pp = p;
21204
0
    return atom;
21205
0
}
21206
21207
static __exception int json_next_token(JSParseState *s)
21208
0
{
21209
0
    const uint8_t *p;
21210
0
    int c;
21211
0
    JSAtom atom;
21212
    
21213
0
    if (js_check_stack_overflow(s->ctx->rt, 0)) {
21214
0
        return js_parse_error(s, "stack overflow");
21215
0
    }
21216
    
21217
0
    free_token(s, &s->token);
21218
21219
0
    p = s->last_ptr = s->buf_ptr;
21220
0
    s->last_line_num = s->token.line_num;
21221
0
 redo:
21222
0
    s->token.line_num = s->line_num;
21223
0
    s->token.ptr = p;
21224
0
    c = *p;
21225
0
    switch(c) {
21226
0
    case 0:
21227
0
        if (p >= s->buf_end) {
21228
0
            s->token.val = TOK_EOF;
21229
0
        } else {
21230
0
            goto def_token;
21231
0
        }
21232
0
        break;
21233
0
    case '\'':
21234
0
        if (!s->ext_json) {
21235
            /* JSON does not accept single quoted strings */
21236
0
            goto def_token;
21237
0
        }
21238
        /* fall through */
21239
0
    case '\"':
21240
0
        if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
21241
0
            goto fail;
21242
0
        break;
21243
0
    case '\r':  /* accept DOS and MAC newline sequences */
21244
0
        if (p[1] == '\n') {
21245
0
            p++;
21246
0
        }
21247
        /* fall thru */
21248
0
    case '\n':
21249
0
        p++;
21250
0
        s->line_num++;
21251
0
        goto redo;
21252
0
    case '\f':
21253
0
    case '\v':
21254
0
        if (!s->ext_json) {
21255
            /* JSONWhitespace does not match <VT>, nor <FF> */
21256
0
            goto def_token;
21257
0
        }
21258
        /* fall through */
21259
0
    case ' ':
21260
0
    case '\t':
21261
0
        p++;
21262
0
        goto redo;
21263
0
    case '/':
21264
0
        if (!s->ext_json) {
21265
            /* JSON does not accept comments */
21266
0
            goto def_token;
21267
0
        }
21268
0
        if (p[1] == '*') {
21269
            /* comment */
21270
0
            p += 2;
21271
0
            for(;;) {
21272
0
                if (*p == '\0' && p >= s->buf_end) {
21273
0
                    js_parse_error(s, "unexpected end of comment");
21274
0
                    goto fail;
21275
0
                }
21276
0
                if (p[0] == '*' && p[1] == '/') {
21277
0
                    p += 2;
21278
0
                    break;
21279
0
                }
21280
0
                if (*p == '\n') {
21281
0
                    s->line_num++;
21282
0
                    p++;
21283
0
                } else if (*p == '\r') {
21284
0
                    p++;
21285
0
                } else if (*p >= 0x80) {
21286
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21287
0
                    if (c == -1) {
21288
0
                        p++; /* skip invalid UTF-8 */
21289
0
                    }
21290
0
                } else {
21291
0
                    p++;
21292
0
                }
21293
0
            }
21294
0
            goto redo;
21295
0
        } else if (p[1] == '/') {
21296
            /* line comment */
21297
0
            p += 2;
21298
0
            for(;;) {
21299
0
                if (*p == '\0' && p >= s->buf_end)
21300
0
                    break;
21301
0
                if (*p == '\r' || *p == '\n')
21302
0
                    break;
21303
0
                if (*p >= 0x80) {
21304
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21305
                    /* LS or PS are considered as line terminator */
21306
0
                    if (c == CP_LS || c == CP_PS) {
21307
0
                        break;
21308
0
                    } else if (c == -1) {
21309
0
                        p++; /* skip invalid UTF-8 */
21310
0
                    }
21311
0
                } else {
21312
0
                    p++;
21313
0
                }
21314
0
            }
21315
0
            goto redo;
21316
0
        } else {
21317
0
            goto def_token;
21318
0
        }
21319
0
        break;
21320
0
    case 'a': case 'b': case 'c': case 'd':
21321
0
    case 'e': case 'f': case 'g': case 'h':
21322
0
    case 'i': case 'j': case 'k': case 'l':
21323
0
    case 'm': case 'n': case 'o': case 'p':
21324
0
    case 'q': case 'r': case 's': case 't':
21325
0
    case 'u': case 'v': case 'w': case 'x':
21326
0
    case 'y': case 'z': 
21327
0
    case 'A': case 'B': case 'C': case 'D':
21328
0
    case 'E': case 'F': case 'G': case 'H':
21329
0
    case 'I': case 'J': case 'K': case 'L':
21330
0
    case 'M': case 'N': case 'O': case 'P':
21331
0
    case 'Q': case 'R': case 'S': case 'T':
21332
0
    case 'U': case 'V': case 'W': case 'X':
21333
0
    case 'Y': case 'Z': 
21334
0
    case '_':
21335
0
    case '$':
21336
        /* identifier : only pure ascii characters are accepted */
21337
0
        p++;
21338
0
        atom = json_parse_ident(s, &p, c);
21339
0
        if (atom == JS_ATOM_NULL)
21340
0
            goto fail;
21341
0
        s->token.u.ident.atom = atom;
21342
0
        s->token.u.ident.has_escape = FALSE;
21343
0
        s->token.u.ident.is_reserved = FALSE;
21344
0
        s->token.val = TOK_IDENT;
21345
0
        break;
21346
0
    case '+':
21347
0
        if (!s->ext_json || !is_digit(p[1]))
21348
0
            goto def_token;
21349
0
        goto parse_number;
21350
0
    case '0':
21351
0
        if (is_digit(p[1]))
21352
0
            goto def_token;
21353
0
        goto parse_number;
21354
0
    case '-':
21355
0
        if (!is_digit(p[1]))
21356
0
            goto def_token;
21357
0
        goto parse_number;
21358
0
    case '1': case '2': case '3': case '4':
21359
0
    case '5': case '6': case '7': case '8':
21360
0
    case '9': 
21361
        /* number */
21362
0
    parse_number:
21363
0
        {
21364
0
            JSValue ret;
21365
0
            int flags, radix;
21366
0
            if (!s->ext_json) {
21367
0
                flags = 0;
21368
0
                radix = 10;
21369
0
            } else {
21370
0
                flags = ATOD_ACCEPT_BIN_OCT;
21371
0
                radix = 0;
21372
0
            }
21373
0
            ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
21374
0
                          flags);
21375
0
            if (JS_IsException(ret))
21376
0
                goto fail;
21377
0
            s->token.val = TOK_NUMBER;
21378
0
            s->token.u.num.val = ret;
21379
0
        }
21380
0
        break;
21381
0
    default:
21382
0
        if (c >= 128) {
21383
0
            js_parse_error(s, "unexpected character");
21384
0
            goto fail;
21385
0
        }
21386
0
    def_token:
21387
0
        s->token.val = c;
21388
0
        p++;
21389
0
        break;
21390
0
    }
21391
0
    s->buf_ptr = p;
21392
21393
    //    dump_token(s, &s->token);
21394
0
    return 0;
21395
21396
0
 fail:
21397
0
    s->token.val = TOK_ERROR;
21398
0
    return -1;
21399
0
}
21400
21401
/* only used for ':' and '=>', 'let' or 'function' look-ahead. *pp is
21402
   only set if TOK_IMPORT is returned */
21403
/* XXX: handle all unicode cases */
21404
static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator)
21405
636k
{
21406
636k
    const uint8_t *p;
21407
636k
    uint32_t c;
21408
    
21409
    /* skip spaces and comments */
21410
636k
    p = *pp;
21411
853k
    for (;;) {
21412
853k
        switch(c = *p++) {
21413
212k
        case '\r':
21414
252k
        case '\n':
21415
252k
            if (no_line_terminator)
21416
37.9k
                return '\n';
21417
214k
            continue;
21418
214k
        case ' ':
21419
1.43k
        case '\t':
21420
1.46k
        case '\v':
21421
2.96k
        case '\f':
21422
2.96k
            continue;
21423
1.14k
        case '/':
21424
1.14k
            if (*p == '/') {
21425
1.08k
                if (no_line_terminator)
21426
1.00k
                    return '\n';
21427
153k
                while (*p && *p != '\r' && *p != '\n')
21428
153k
                    p++;
21429
79
                continue;
21430
1.08k
            }
21431
62
            if (*p == '*') {
21432
0
                while (*++p) {
21433
0
                    if ((*p == '\r' || *p == '\n') && no_line_terminator)
21434
0
                        return '\n';
21435
0
                    if (*p == '*' && p[1] == '/') {
21436
0
                        p += 2;
21437
0
                        break;
21438
0
                    }
21439
0
                }
21440
0
                continue;
21441
0
            }
21442
62
            break;
21443
208k
        case '=':
21444
208k
            if (*p == '>')
21445
366
                return TOK_ARROW;
21446
207k
            break;
21447
389k
        default:
21448
389k
            if (lre_js_is_ident_first(c)) {
21449
31.1k
                if (c == 'i') {
21450
20
                    if (p[0] == 'n' && !lre_js_is_ident_next(p[1])) {
21451
13
                        return TOK_IN;
21452
13
                    }
21453
7
                    if (p[0] == 'm' && p[1] == 'p' && p[2] == 'o' &&
21454
7
                        p[3] == 'r' && p[4] == 't' &&
21455
7
                        !lre_js_is_ident_next(p[5])) {
21456
0
                        *pp = p + 5;
21457
0
                        return TOK_IMPORT;
21458
0
                    }
21459
31.1k
                } else if (c == 'o' && *p == 'f' && !lre_js_is_ident_next(p[1])) {
21460
0
                    return TOK_OF;
21461
31.1k
                } else if (c == 'e' &&
21462
31.1k
                           p[0] == 'x' && p[1] == 'p' && p[2] == 'o' &&
21463
31.1k
                           p[3] == 'r' && p[4] == 't' &&
21464
31.1k
                           !lre_js_is_ident_next(p[5])) {
21465
0
                    *pp = p + 5;
21466
0
                    return TOK_EXPORT;
21467
31.1k
                } else if (c == 'f' && p[0] == 'u' && p[1] == 'n' &&
21468
31.1k
                         p[2] == 'c' && p[3] == 't' && p[4] == 'i' &&
21469
31.1k
                         p[5] == 'o' && p[6] == 'n' && !lre_js_is_ident_next(p[7])) {
21470
11.3k
                    return TOK_FUNCTION;
21471
11.3k
                }
21472
19.8k
                return TOK_IDENT;
21473
31.1k
            }
21474
358k
            break;
21475
853k
        }
21476
565k
        return c;
21477
853k
    }
21478
636k
}
21479
21480
static int peek_token(JSParseState *s, BOOL no_line_terminator)
21481
636k
{
21482
636k
    const uint8_t *p = s->buf_ptr;
21483
636k
    return simple_next_token(&p, no_line_terminator);
21484
636k
}
21485
21486
/* return true if 'input' contains the source of a module
21487
   (heuristic). 'input' must be a zero terminated.
21488
21489
   Heuristic: skip comments and expect 'import' keyword not followed
21490
   by '(' or '.' or export keyword.
21491
*/
21492
BOOL JS_DetectModule(const char *input, size_t input_len)
21493
0
{
21494
0
    const uint8_t *p = (const uint8_t *)input;
21495
0
    int tok;
21496
0
    switch(simple_next_token(&p, FALSE)) {
21497
0
    case TOK_IMPORT:
21498
0
        tok = simple_next_token(&p, FALSE);
21499
0
        return (tok != '.' && tok != '(');
21500
0
    case TOK_EXPORT:
21501
0
        return TRUE;
21502
0
    default:
21503
0
        return FALSE;
21504
0
    }
21505
0
}
21506
21507
598k
static inline int get_prev_opcode(JSFunctionDef *fd) {
21508
598k
    if (fd->last_opcode_pos < 0)
21509
2
        return OP_invalid;
21510
598k
    else
21511
598k
        return fd->byte_code.buf[fd->last_opcode_pos];
21512
598k
}
21513
21514
100k
static BOOL js_is_live_code(JSParseState *s) {
21515
100k
    switch (get_prev_opcode(s->cur_func)) {
21516
0
    case OP_tail_call:
21517
0
    case OP_tail_call_method:
21518
1
    case OP_return:
21519
1
    case OP_return_undef:
21520
1
    case OP_return_async:
21521
79
    case OP_throw:
21522
79
    case OP_throw_error:
21523
79
    case OP_goto:
21524
79
#if SHORT_OPCODES
21525
79
    case OP_goto8:
21526
79
    case OP_goto16:
21527
79
#endif
21528
79
    case OP_ret:
21529
79
        return FALSE;
21530
100k
    default:
21531
100k
        return TRUE;
21532
100k
    }
21533
100k
}
21534
21535
static void emit_u8(JSParseState *s, uint8_t val)
21536
7.42k
{
21537
7.42k
    dbuf_putc(&s->cur_func->byte_code, val);
21538
7.42k
}
21539
21540
static void emit_u16(JSParseState *s, uint16_t val)
21541
1.05M
{
21542
1.05M
    dbuf_put_u16(&s->cur_func->byte_code, val);
21543
1.05M
}
21544
21545
static void emit_u32(JSParseState *s, uint32_t val)
21546
1.62M
{
21547
1.62M
    dbuf_put_u32(&s->cur_func->byte_code, val);
21548
1.62M
}
21549
21550
static void emit_op(JSParseState *s, uint8_t val)
21551
2.54M
{
21552
2.54M
    JSFunctionDef *fd = s->cur_func;
21553
2.54M
    DynBuf *bc = &fd->byte_code;
21554
21555
    /* Use the line number of the last token used, not the next token,
21556
       nor the current offset in the source file.
21557
     */
21558
2.54M
    if (unlikely(fd->last_opcode_line_num != s->last_line_num)) {
21559
174k
        dbuf_putc(bc, OP_line_num);
21560
174k
        dbuf_put_u32(bc, s->last_line_num);
21561
174k
        fd->last_opcode_line_num = s->last_line_num;
21562
174k
    }
21563
2.54M
    fd->last_opcode_pos = bc->size;
21564
2.54M
    dbuf_putc(bc, val);
21565
2.54M
}
21566
21567
static void emit_atom(JSParseState *s, JSAtom name)
21568
319k
{
21569
319k
    emit_u32(s, JS_DupAtom(s->ctx, name));
21570
319k
}
21571
21572
static int update_label(JSFunctionDef *s, int label, int delta)
21573
1.43M
{
21574
1.43M
    LabelSlot *ls;
21575
21576
1.43M
    assert(label >= 0 && label < s->label_count);
21577
1.43M
    ls = &s->label_slots[label];
21578
1.43M
    ls->ref_count += delta;
21579
1.43M
    assert(ls->ref_count >= 0);
21580
1.43M
    return ls->ref_count;
21581
1.43M
}
21582
21583
static int new_label_fd(JSFunctionDef *fd, int label)
21584
705k
{
21585
705k
    LabelSlot *ls;
21586
21587
705k
    if (label < 0) {
21588
696k
        if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
21589
696k
                            sizeof(fd->label_slots[0]),
21590
696k
                            &fd->label_size, fd->label_count + 1))
21591
0
            return -1;
21592
696k
        label = fd->label_count++;
21593
696k
        ls = &fd->label_slots[label];
21594
696k
        ls->ref_count = 0;
21595
696k
        ls->pos = -1;
21596
696k
        ls->pos2 = -1;
21597
696k
        ls->addr = -1;
21598
696k
        ls->first_reloc = NULL;
21599
696k
    }
21600
705k
    return label;
21601
705k
}
21602
21603
static int new_label(JSParseState *s)
21604
353k
{
21605
353k
    return new_label_fd(s->cur_func, -1);
21606
353k
}
21607
21608
/* return the label ID offset */
21609
static int emit_label(JSParseState *s, int label)
21610
353k
{
21611
353k
    if (label >= 0) {
21612
353k
        emit_op(s, OP_label);
21613
353k
        emit_u32(s, label);
21614
353k
        s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
21615
353k
        return s->cur_func->byte_code.size - 4;
21616
353k
    } else {
21617
0
        return -1;
21618
0
    }
21619
353k
}
21620
21621
/* return label or -1 if dead code */
21622
static int emit_goto(JSParseState *s, int opcode, int label)
21623
88.3k
{
21624
88.3k
    if (js_is_live_code(s)) {
21625
88.2k
        if (label < 0)
21626
34.9k
            label = new_label(s);
21627
88.2k
        emit_op(s, opcode);
21628
88.2k
        emit_u32(s, label);
21629
88.2k
        s->cur_func->label_slots[label].ref_count++;
21630
88.2k
        return label;
21631
88.2k
    }
21632
73
    return -1;
21633
88.3k
}
21634
21635
/* return the constant pool index. 'val' is not duplicated. */
21636
static int cpool_add(JSParseState *s, JSValue val)
21637
13.9k
{
21638
13.9k
    JSFunctionDef *fd = s->cur_func;
21639
    
21640
13.9k
    if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]),
21641
13.9k
                        &fd->cpool_size, fd->cpool_count + 1))
21642
0
        return -1;
21643
13.9k
    fd->cpool[fd->cpool_count++] = val;
21644
13.9k
    return fd->cpool_count - 1;
21645
13.9k
}
21646
21647
static __exception int emit_push_const(JSParseState *s, JSValueConst val,
21648
                                       BOOL as_atom)
21649
3.50k
{
21650
3.50k
    int idx;
21651
21652
3.50k
    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING && as_atom) {
21653
2.20k
        JSAtom atom;
21654
        /* warning: JS_NewAtomStr frees the string value */
21655
2.20k
        JS_DupValue(s->ctx, val);
21656
2.20k
        atom = JS_NewAtomStr(s->ctx, JS_VALUE_GET_STRING(val));
21657
2.20k
        if (atom != JS_ATOM_NULL && !__JS_AtomIsTaggedInt(atom)) {
21658
2.20k
            emit_op(s, OP_push_atom_value);
21659
2.20k
            emit_u32(s, atom);
21660
2.20k
            return 0;
21661
2.20k
        }
21662
2.20k
    }
21663
21664
1.29k
    idx = cpool_add(s, JS_DupValue(s->ctx, val));
21665
1.29k
    if (idx < 0)
21666
0
        return -1;
21667
1.29k
    emit_op(s, OP_push_const);
21668
1.29k
    emit_u32(s, idx);
21669
1.29k
    return 0;
21670
1.29k
}
21671
21672
/* return the variable index or -1 if not found,
21673
   add ARGUMENT_VAR_OFFSET for argument variables */
21674
static int find_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21675
532k
{
21676
532k
    int i;
21677
565k
    for(i = fd->arg_count; i-- > 0;) {
21678
34.0k
        if (fd->args[i].var_name == name)
21679
686
            return i | ARGUMENT_VAR_OFFSET;
21680
34.0k
    }
21681
531k
    return -1;
21682
532k
}
21683
21684
static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21685
538k
{
21686
538k
    int i;
21687
4.84M
    for(i = fd->var_count; i-- > 0;) {
21688
4.31M
        if (fd->vars[i].var_name == name && fd->vars[i].scope_level == 0)
21689
6.31k
            return i;
21690
4.31M
    }
21691
532k
    return find_arg(ctx, fd, name);
21692
538k
}
21693
21694
/* find a variable declaration in a given scope */
21695
static int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd,
21696
                             JSAtom name, int scope_level)
21697
0
{
21698
0
    int scope_idx;
21699
0
    for(scope_idx = fd->scopes[scope_level].first; scope_idx >= 0;
21700
0
        scope_idx = fd->vars[scope_idx].scope_next) {
21701
0
        if (fd->vars[scope_idx].scope_level != scope_level)
21702
0
            break;
21703
0
        if (fd->vars[scope_idx].var_name == name)
21704
0
            return scope_idx;
21705
0
    }
21706
0
    return -1;
21707
0
}
21708
21709
/* return true if scope == parent_scope or if scope is a child of
21710
   parent_scope */
21711
static BOOL is_child_scope(JSContext *ctx, JSFunctionDef *fd,
21712
                           int scope, int parent_scope)
21713
467
{
21714
1.39k
    while (scope >= 0) {
21715
931
        if (scope == parent_scope)
21716
0
            return TRUE;
21717
931
        scope = fd->scopes[scope].parent;
21718
931
    }
21719
467
    return FALSE;
21720
467
}
21721
21722
/* find a 'var' declaration in the same scope or a child scope */
21723
static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd,
21724
                                   JSAtom name, int scope_level)
21725
1.33k
{
21726
1.33k
    int i;
21727
76.1k
    for(i = 0; i < fd->var_count; i++) {
21728
74.8k
        JSVarDef *vd = &fd->vars[i];
21729
74.8k
        if (vd->var_name == name && vd->scope_level == 0) {
21730
0
            if (is_child_scope(ctx, fd, vd->scope_next,
21731
0
                               scope_level))
21732
0
                return i;
21733
0
        }
21734
74.8k
    }
21735
1.33k
    return -1;
21736
1.33k
}
21737
21738
21739
static JSGlobalVar *find_global_var(JSFunctionDef *fd, JSAtom name)
21740
2.45k
{
21741
2.45k
    int i;
21742
44.6k
    for(i = 0; i < fd->global_var_count; i++) {
21743
44.2k
        JSGlobalVar *hf = &fd->global_vars[i];
21744
44.2k
        if (hf->var_name == name)
21745
2.03k
            return hf;
21746
44.2k
    }
21747
421
    return NULL;
21748
21749
2.45k
}
21750
21751
static JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name)
21752
541
{
21753
541
    JSGlobalVar *hf = find_global_var(fd, name);
21754
541
    if (hf && hf->is_lexical)
21755
0
        return hf;
21756
541
    else
21757
541
        return NULL;
21758
541
}
21759
21760
static int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
21761
                             int scope_idx, BOOL check_catch_var)
21762
6.88k
{
21763
11.3k
    while (scope_idx >= 0) {
21764
5.41k
        JSVarDef *vd = &fd->vars[scope_idx];
21765
5.41k
        if (vd->var_name == name &&
21766
5.41k
            (vd->is_lexical || (vd->var_kind == JS_VAR_CATCH &&
21767
154
                                check_catch_var)))
21768
936
            return scope_idx;
21769
4.47k
        scope_idx = vd->scope_next;
21770
4.47k
    }
21771
21772
5.94k
    if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_GLOBAL) {
21773
541
        if (find_lexical_global_var(fd, name))
21774
0
            return GLOBAL_VAR_OFFSET;
21775
541
    }
21776
5.94k
    return -1;
21777
5.94k
}
21778
21779
60.1k
static int push_scope(JSParseState *s) {
21780
60.1k
    if (s->cur_func) {
21781
60.1k
        JSFunctionDef *fd = s->cur_func;
21782
60.1k
        int scope = fd->scope_count;
21783
        /* XXX: should check for scope overflow */
21784
60.1k
        if ((fd->scope_count + 1) > fd->scope_size) {
21785
295
            int new_size;
21786
295
            size_t slack;
21787
295
            JSVarScope *new_buf;
21788
            /* XXX: potential arithmetic overflow */
21789
295
            new_size = max_int(fd->scope_count + 1, fd->scope_size * 3 / 2);
21790
295
            if (fd->scopes == fd->def_scope_array) {
21791
50
                new_buf = js_realloc2(s->ctx, NULL, new_size * sizeof(*fd->scopes), &slack);
21792
50
                if (!new_buf)
21793
0
                    return -1;
21794
50
                memcpy(new_buf, fd->scopes, fd->scope_count * sizeof(*fd->scopes));
21795
245
            } else {
21796
245
                new_buf = js_realloc2(s->ctx, fd->scopes, new_size * sizeof(*fd->scopes), &slack);
21797
245
                if (!new_buf)
21798
0
                    return -1;
21799
245
            }
21800
295
            new_size += slack / sizeof(*new_buf);
21801
295
            fd->scopes = new_buf;
21802
295
            fd->scope_size = new_size;
21803
295
        }
21804
60.1k
        fd->scope_count++;
21805
60.1k
        fd->scopes[scope].parent = fd->scope_level;
21806
60.1k
        fd->scopes[scope].first = fd->scope_first;
21807
60.1k
        emit_op(s, OP_enter_scope);
21808
60.1k
        emit_u16(s, scope);
21809
60.1k
        return fd->scope_level = scope;
21810
60.1k
    }
21811
0
    return 0;
21812
60.1k
}
21813
21814
static int get_first_lexical_var(JSFunctionDef *fd, int scope)
21815
6.40k
{
21816
17.2k
    while (scope >= 0) {
21817
11.9k
        int scope_idx = fd->scopes[scope].first;
21818
11.9k
        if (scope_idx >= 0)
21819
1.13k
            return scope_idx;
21820
10.8k
        scope = fd->scopes[scope].parent;
21821
10.8k
    }
21822
5.26k
    return -1;
21823
6.40k
}
21824
21825
6.40k
static void pop_scope(JSParseState *s) {
21826
6.40k
    if (s->cur_func) {
21827
        /* disable scoped variables */
21828
6.40k
        JSFunctionDef *fd = s->cur_func;
21829
6.40k
        int scope = fd->scope_level;
21830
6.40k
        emit_op(s, OP_leave_scope);
21831
6.40k
        emit_u16(s, scope);
21832
6.40k
        fd->scope_level = fd->scopes[scope].parent;
21833
6.40k
        fd->scope_first = get_first_lexical_var(fd, fd->scope_level);
21834
6.40k
    }
21835
6.40k
}
21836
21837
static void close_scopes(JSParseState *s, int scope, int scope_stop)
21838
543
{
21839
1.08k
    while (scope > scope_stop) {
21840
543
        emit_op(s, OP_leave_scope);
21841
543
        emit_u16(s, scope);
21842
543
        scope = s->cur_func->scopes[scope].parent;
21843
543
    }
21844
543
}
21845
21846
/* return the variable index or -1 if error */
21847
static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21848
43.6k
{
21849
43.6k
    JSVarDef *vd;
21850
21851
    /* the local variable indexes are currently stored on 16 bits */
21852
43.6k
    if (fd->var_count >= JS_MAX_LOCAL_VARS) {
21853
0
        JS_ThrowInternalError(ctx, "too many local variables");
21854
0
        return -1;
21855
0
    }
21856
43.6k
    if (js_resize_array(ctx, (void **)&fd->vars, sizeof(fd->vars[0]),
21857
43.6k
                        &fd->var_size, fd->var_count + 1))
21858
0
        return -1;
21859
43.6k
    vd = &fd->vars[fd->var_count++];
21860
43.6k
    memset(vd, 0, sizeof(*vd));
21861
43.6k
    vd->var_name = JS_DupAtom(ctx, name);
21862
43.6k
    vd->func_pool_idx = -1;
21863
43.6k
    return fd->var_count - 1;
21864
43.6k
}
21865
21866
static int add_scope_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
21867
                         JSVarKindEnum var_kind)
21868
2.23k
{
21869
2.23k
    int idx = add_var(ctx, fd, name);
21870
2.23k
    if (idx >= 0) {
21871
2.23k
        JSVarDef *vd = &fd->vars[idx];
21872
2.23k
        vd->var_kind = var_kind;
21873
2.23k
        vd->scope_level = fd->scope_level;
21874
2.23k
        vd->scope_next = fd->scope_first;
21875
2.23k
        fd->scopes[fd->scope_level].first = idx;
21876
2.23k
        fd->scope_first = idx;
21877
2.23k
    }
21878
2.23k
    return idx;
21879
2.23k
}
21880
21881
static int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21882
0
{
21883
0
    int idx = fd->func_var_idx;
21884
0
    if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) {
21885
0
        fd->func_var_idx = idx;
21886
0
        fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME;
21887
0
        if (fd->js_mode & JS_MODE_STRICT)
21888
0
            fd->vars[idx].is_const = TRUE;
21889
0
    }
21890
0
    return idx;
21891
0
}
21892
21893
static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd)
21894
1
{
21895
1
    int idx = fd->arguments_var_idx;
21896
1
    if (idx < 0 && (idx = add_var(ctx, fd, JS_ATOM_arguments)) >= 0) {
21897
1
        fd->arguments_var_idx = idx;
21898
1
    }
21899
1
    return idx;
21900
1
}
21901
21902
/* add an argument definition in the argument scope. Only needed when
21903
   "eval()" may be called in the argument scope. Return 0 if OK. */
21904
static int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd)
21905
0
{
21906
0
    int idx;
21907
0
    if (fd->arguments_arg_idx < 0) {
21908
0
        idx = find_var_in_scope(ctx, fd, JS_ATOM_arguments, ARG_SCOPE_INDEX);
21909
0
        if (idx < 0) {
21910
            /* XXX: the scope links are not fully updated. May be an
21911
               issue if there are child scopes of the argument
21912
               scope */
21913
0
            idx = add_var(ctx, fd, JS_ATOM_arguments);
21914
0
            if (idx < 0)
21915
0
                return -1;
21916
0
            fd->vars[idx].scope_next = fd->scopes[ARG_SCOPE_INDEX].first;
21917
0
            fd->scopes[ARG_SCOPE_INDEX].first = idx;
21918
0
            fd->vars[idx].scope_level = ARG_SCOPE_INDEX;
21919
0
            fd->vars[idx].is_lexical = TRUE;
21920
21921
0
            fd->arguments_arg_idx = idx;
21922
0
        }
21923
0
    }
21924
0
    return 0;
21925
0
}
21926
21927
static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
21928
1.44k
{
21929
1.44k
    JSVarDef *vd;
21930
21931
    /* the local variable indexes are currently stored on 16 bits */
21932
1.44k
    if (fd->arg_count >= JS_MAX_LOCAL_VARS) {
21933
0
        JS_ThrowInternalError(ctx, "too many arguments");
21934
0
        return -1;
21935
0
    }
21936
1.44k
    if (js_resize_array(ctx, (void **)&fd->args, sizeof(fd->args[0]),
21937
1.44k
                        &fd->arg_size, fd->arg_count + 1))
21938
0
        return -1;
21939
1.44k
    vd = &fd->args[fd->arg_count++];
21940
1.44k
    memset(vd, 0, sizeof(*vd));
21941
1.44k
    vd->var_name = JS_DupAtom(ctx, name);
21942
1.44k
    vd->func_pool_idx = -1;
21943
1.44k
    return fd->arg_count - 1;
21944
1.44k
}
21945
21946
/* add a global variable definition */
21947
static JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s,
21948
                                     JSAtom name)
21949
8.82k
{
21950
8.82k
    JSGlobalVar *hf;
21951
21952
8.82k
    if (js_resize_array(ctx, (void **)&s->global_vars,
21953
8.82k
                        sizeof(s->global_vars[0]),
21954
8.82k
                        &s->global_var_size, s->global_var_count + 1))
21955
0
        return NULL;
21956
8.82k
    hf = &s->global_vars[s->global_var_count++];
21957
8.82k
    hf->cpool_idx = -1;
21958
8.82k
    hf->force_init = FALSE;
21959
8.82k
    hf->is_lexical = FALSE;
21960
8.82k
    hf->is_const = FALSE;
21961
8.82k
    hf->scope_level = s->scope_level;
21962
8.82k
    hf->var_name = JS_DupAtom(ctx, name);
21963
8.82k
    return hf;
21964
8.82k
}
21965
21966
typedef enum {
21967
    JS_VAR_DEF_WITH,
21968
    JS_VAR_DEF_LET,
21969
    JS_VAR_DEF_CONST,
21970
    JS_VAR_DEF_FUNCTION_DECL, /* function declaration */
21971
    JS_VAR_DEF_NEW_FUNCTION_DECL, /* async/generator function declaration */
21972
    JS_VAR_DEF_CATCH,
21973
    JS_VAR_DEF_VAR,
21974
} JSVarDefEnum;
21975
21976
static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
21977
                      JSVarDefEnum var_def_type)
21978
7.29k
{
21979
7.29k
    JSContext *ctx = s->ctx;
21980
7.29k
    JSVarDef *vd;
21981
7.29k
    int idx;
21982
21983
7.29k
    switch (var_def_type) {
21984
853
    case JS_VAR_DEF_WITH:
21985
853
        idx = add_scope_var(ctx, fd, name, JS_VAR_NORMAL);
21986
853
        break;
21987
21988
608
    case JS_VAR_DEF_LET:
21989
857
    case JS_VAR_DEF_CONST:
21990
1.32k
    case JS_VAR_DEF_FUNCTION_DECL:
21991
1.33k
    case JS_VAR_DEF_NEW_FUNCTION_DECL:
21992
1.33k
        idx = find_lexical_decl(ctx, fd, name, fd->scope_first, TRUE);
21993
1.33k
        if (idx >= 0) {
21994
471
            if (idx < GLOBAL_VAR_OFFSET) {
21995
471
                if (fd->vars[idx].scope_level == fd->scope_level) {
21996
                    /* same scope: in non strict mode, functions
21997
                       can be redefined (annex B.3.3.4). */
21998
465
                    if (!(!(fd->js_mode & JS_MODE_STRICT) &&
21999
465
                          var_def_type == JS_VAR_DEF_FUNCTION_DECL &&
22000
465
                          fd->vars[idx].var_kind == JS_VAR_FUNCTION_DECL)) {
22001
0
                        goto redef_lex_error;
22002
0
                    }
22003
465
                } else if (fd->vars[idx].var_kind == JS_VAR_CATCH && (fd->vars[idx].scope_level + 2) == fd->scope_level) {
22004
0
                    goto redef_lex_error;
22005
0
                }
22006
471
            } else {
22007
0
                if (fd->scope_level == fd->body_scope) {
22008
0
                redef_lex_error:
22009
                    /* redefining a scoped var in the same scope: error */
22010
0
                    return js_parse_error(s, "invalid redefinition of lexical identifier");
22011
0
                }
22012
0
            }
22013
471
        }
22014
1.33k
        if (var_def_type != JS_VAR_DEF_FUNCTION_DECL &&
22015
1.33k
            var_def_type != JS_VAR_DEF_NEW_FUNCTION_DECL &&
22016
1.33k
            fd->scope_level == fd->body_scope &&
22017
1.33k
            find_arg(ctx, fd, name) >= 0) {
22018
            /* lexical variable redefines a parameter name */
22019
0
            return js_parse_error(s, "invalid redefinition of parameter name");
22020
0
        }
22021
22022
1.33k
        if (find_var_in_child_scope(ctx, fd, name, fd->scope_level) >= 0) {
22023
0
            return js_parse_error(s, "invalid redefinition of a variable");
22024
0
        }
22025
        
22026
1.33k
        if (fd->is_global_var) {
22027
622
            JSGlobalVar *hf;
22028
622
            hf = find_global_var(fd, name);
22029
622
            if (hf && is_child_scope(ctx, fd, hf->scope_level,
22030
467
                                     fd->scope_level)) {
22031
0
                return js_parse_error(s, "invalid redefinition of global identifier");
22032
0
            }
22033
622
        }
22034
        
22035
1.33k
        if (fd->is_eval &&
22036
1.33k
            (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
22037
622
             fd->eval_type == JS_EVAL_TYPE_MODULE) &&
22038
1.33k
            fd->scope_level == fd->body_scope) {
22039
0
            JSGlobalVar *hf;
22040
0
            hf = add_global_var(s->ctx, fd, name);
22041
0
            if (!hf)
22042
0
                return -1;
22043
0
            hf->is_lexical = TRUE;
22044
0
            hf->is_const = (var_def_type == JS_VAR_DEF_CONST);
22045
0
            idx = GLOBAL_VAR_OFFSET;
22046
1.33k
        } else {
22047
1.33k
            JSVarKindEnum var_kind;
22048
1.33k
            if (var_def_type == JS_VAR_DEF_FUNCTION_DECL)
22049
471
                var_kind = JS_VAR_FUNCTION_DECL;
22050
864
            else if (var_def_type == JS_VAR_DEF_NEW_FUNCTION_DECL)
22051
7
                var_kind = JS_VAR_NEW_FUNCTION_DECL;
22052
857
            else
22053
857
                var_kind = JS_VAR_NORMAL;
22054
1.33k
            idx = add_scope_var(ctx, fd, name, var_kind);
22055
1.33k
            if (idx >= 0) {
22056
1.33k
                vd = &fd->vars[idx];
22057
1.33k
                vd->is_lexical = 1;
22058
1.33k
                vd->is_const = (var_def_type == JS_VAR_DEF_CONST);
22059
1.33k
            }
22060
1.33k
        }
22061
1.33k
        break;
22062
22063
1.33k
    case JS_VAR_DEF_CATCH:
22064
29
        idx = add_scope_var(ctx, fd, name, JS_VAR_CATCH);
22065
29
        break;
22066
22067
5.08k
    case JS_VAR_DEF_VAR:
22068
5.08k
        if (find_lexical_decl(ctx, fd, name, fd->scope_first,
22069
5.08k
                              FALSE) >= 0) {
22070
0
       invalid_lexical_redefinition:
22071
            /* error to redefine a var that inside a lexical scope */
22072
0
            return js_parse_error(s, "invalid redefinition of lexical identifier");
22073
0
        }
22074
5.08k
        if (fd->is_global_var) {
22075
1.28k
            JSGlobalVar *hf;
22076
1.28k
            hf = find_global_var(fd, name);
22077
1.28k
            if (hf && hf->is_lexical && hf->scope_level == fd->scope_level &&
22078
1.28k
                fd->eval_type == JS_EVAL_TYPE_MODULE) {
22079
0
                goto invalid_lexical_redefinition;
22080
0
            }
22081
1.28k
            hf = add_global_var(s->ctx, fd, name);
22082
1.28k
            if (!hf)
22083
0
                return -1;
22084
1.28k
            idx = GLOBAL_VAR_OFFSET;
22085
3.79k
        } else {
22086
            /* if the variable already exists, don't add it again  */
22087
3.79k
            idx = find_var(ctx, fd, name);
22088
3.79k
            if (idx >= 0)
22089
3.75k
                break;
22090
43
            idx = add_var(ctx, fd, name);
22091
43
            if (idx >= 0) {
22092
43
                if (name == JS_ATOM_arguments && fd->has_arguments_binding)
22093
0
                    fd->arguments_var_idx = idx;
22094
43
                fd->vars[idx].scope_next = fd->scope_level;
22095
43
            }
22096
43
        }
22097
1.33k
        break;
22098
1.33k
    default:
22099
0
        abort();
22100
7.29k
    }
22101
7.29k
    return idx;
22102
7.29k
}
22103
22104
/* add a private field variable in the current scope */
22105
static int add_private_class_field(JSParseState *s, JSFunctionDef *fd,
22106
                                   JSAtom name, JSVarKindEnum var_kind)
22107
17
{
22108
17
    JSContext *ctx = s->ctx;
22109
17
    JSVarDef *vd;
22110
17
    int idx;
22111
22112
17
    idx = add_scope_var(ctx, fd, name, var_kind);
22113
17
    if (idx < 0)
22114
0
        return idx;
22115
17
    vd = &fd->vars[idx];
22116
17
    vd->is_lexical = 1;
22117
17
    vd->is_const = 1;
22118
17
    return idx;
22119
17
}
22120
22121
static __exception int js_parse_expr(JSParseState *s);
22122
static __exception int js_parse_function_decl(JSParseState *s,
22123
                                              JSParseFunctionEnum func_type,
22124
                                              JSFunctionKindEnum func_kind,
22125
                                              JSAtom func_name, const uint8_t *ptr,
22126
                                              int start_line);
22127
static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s);
22128
static __exception int js_parse_function_decl2(JSParseState *s,
22129
                                               JSParseFunctionEnum func_type,
22130
                                               JSFunctionKindEnum func_kind,
22131
                                               JSAtom func_name,
22132
                                               const uint8_t *ptr,
22133
                                               int function_line_num,
22134
                                               JSParseExportEnum export_flag,
22135
                                               JSFunctionDef **pfd);
22136
static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);
22137
static __exception int js_parse_assign_expr(JSParseState *s);
22138
static __exception int js_parse_unary(JSParseState *s, int parse_flags);
22139
static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
22140
                             JSAtom label_name,
22141
                             int label_break, int label_cont,
22142
                             int drop_count);
22143
static void pop_break_entry(JSFunctionDef *fd);
22144
static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
22145
                                       JSAtom local_name, JSAtom export_name,
22146
                                       JSExportTypeEnum export_type);
22147
22148
/* Note: all the fields are already sealed except length */
22149
static int seal_template_obj(JSContext *ctx, JSValueConst obj)
22150
606
{
22151
606
    JSObject *p;
22152
606
    JSShapeProperty *prs;
22153
22154
606
    p = JS_VALUE_GET_OBJ(obj);
22155
606
    prs = find_own_property1(p, JS_ATOM_length);
22156
606
    if (prs) {
22157
606
        if (js_update_property_flags(ctx, p, &prs,
22158
606
                                     prs->flags & ~(JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)))
22159
0
            return -1;
22160
606
    }
22161
606
    p->extensible = FALSE;
22162
606
    return 0;
22163
606
}
22164
22165
static __exception int js_parse_template(JSParseState *s, int call, int *argc)
22166
473
{
22167
473
    JSContext *ctx = s->ctx;
22168
473
    JSValue raw_array, template_object;
22169
473
    JSToken cooked;
22170
473
    int depth, ret;
22171
22172
473
    raw_array = JS_UNDEFINED; /* avoid warning */
22173
473
    template_object = JS_UNDEFINED; /* avoid warning */
22174
473
    if (call) {
22175
        /* Create a template object: an array of cooked strings */
22176
        /* Create an array of raw strings and store it to the raw property */
22177
303
        template_object = JS_NewArray(ctx);
22178
303
        if (JS_IsException(template_object))
22179
0
            return -1;
22180
        //        pool_idx = s->cur_func->cpool_count;
22181
303
        ret = emit_push_const(s, template_object, 0);
22182
303
        JS_FreeValue(ctx, template_object);
22183
303
        if (ret)
22184
0
            return -1;
22185
303
        raw_array = JS_NewArray(ctx);
22186
303
        if (JS_IsException(raw_array))
22187
0
            return -1;
22188
303
        if (JS_DefinePropertyValue(ctx, template_object, JS_ATOM_raw,
22189
303
                                   raw_array, JS_PROP_THROW) < 0) {
22190
0
            return -1;
22191
0
        }
22192
303
    }
22193
22194
473
    depth = 0;
22195
473
    while (s->token.val == TOK_TEMPLATE) {
22196
473
        const uint8_t *p = s->token.ptr + 1;
22197
473
        cooked = s->token;
22198
473
        if (call) {
22199
303
            if (JS_DefinePropertyValueUint32(ctx, raw_array, depth,
22200
303
                                             JS_DupValue(ctx, s->token.u.str.str),
22201
303
                                             JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
22202
0
                return -1;
22203
0
            }
22204
            /* re-parse the string with escape sequences but do not throw a
22205
               syntax error if it contains invalid sequences
22206
             */
22207
303
            if (js_parse_string(s, '`', FALSE, p, &cooked, &p)) {
22208
2
                cooked.u.str.str = JS_UNDEFINED;
22209
2
            }
22210
303
            if (JS_DefinePropertyValueUint32(ctx, template_object, depth,
22211
303
                                             cooked.u.str.str,
22212
303
                                             JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
22213
0
                return -1;
22214
0
            }
22215
303
        } else {
22216
170
            JSString *str;
22217
            /* re-parse the string with escape sequences and throw a
22218
               syntax error if it contains invalid sequences
22219
             */
22220
170
            JS_FreeValue(ctx, s->token.u.str.str);
22221
170
            s->token.u.str.str = JS_UNDEFINED;
22222
170
            if (js_parse_string(s, '`', TRUE, p, &cooked, &p))
22223
0
                return -1;
22224
170
            str = JS_VALUE_GET_STRING(cooked.u.str.str);
22225
170
            if (str->len != 0 || depth == 0) {
22226
170
                ret = emit_push_const(s, cooked.u.str.str, 1);
22227
170
                JS_FreeValue(s->ctx, cooked.u.str.str);
22228
170
                if (ret)
22229
0
                    return -1;
22230
170
                if (depth == 0) {
22231
170
                    if (s->token.u.str.sep == '`')
22232
170
                        goto done1;
22233
0
                    emit_op(s, OP_get_field2);
22234
0
                    emit_atom(s, JS_ATOM_concat);
22235
0
                }
22236
0
                depth++;
22237
0
            } else {
22238
0
                JS_FreeValue(s->ctx, cooked.u.str.str);
22239
0
            }
22240
170
        }
22241
303
        if (s->token.u.str.sep == '`')
22242
303
            goto done;
22243
0
        if (next_token(s))
22244
0
            return -1;
22245
0
        if (js_parse_expr(s))
22246
0
            return -1;
22247
0
        depth++;
22248
0
        if (s->token.val != '}') {
22249
0
            return js_parse_error(s, "expected '}' after template expression");
22250
0
        }
22251
        /* XXX: should convert to string at this stage? */
22252
0
        free_token(s, &s->token);
22253
        /* Resume TOK_TEMPLATE parsing (s->token.line_num and
22254
         * s->token.ptr are OK) */
22255
0
        s->got_lf = FALSE;
22256
0
        s->last_line_num = s->token.line_num;
22257
0
        if (js_parse_template_part(s, s->buf_ptr))
22258
0
            return -1;
22259
0
    }
22260
0
    return js_parse_expect(s, TOK_TEMPLATE);
22261
22262
303
 done:
22263
303
    if (call) {
22264
        /* Seal the objects */
22265
303
        seal_template_obj(ctx, raw_array);
22266
303
        seal_template_obj(ctx, template_object);
22267
303
        *argc = depth + 1;
22268
303
    } else {
22269
0
        emit_op(s, OP_call_method);
22270
0
        emit_u16(s, depth - 1);
22271
0
    }
22272
473
 done1:
22273
473
    return next_token(s);
22274
303
}
22275
22276
22277
266k
#define PROP_TYPE_IDENT 0
22278
129k
#define PROP_TYPE_VAR   1
22279
1.03k
#define PROP_TYPE_GET   2
22280
518
#define PROP_TYPE_SET   3
22281
131
#define PROP_TYPE_STAR  4
22282
131
#define PROP_TYPE_ASYNC 5
22283
131
#define PROP_TYPE_ASYNC_STAR 6
22284
22285
1.05k
#define PROP_TYPE_PRIVATE (1 << 4)
22286
22287
static BOOL token_is_ident(int tok)
22288
49.5k
{
22289
    /* Accept keywords and reserved words as property names */
22290
49.5k
    return (tok == TOK_IDENT ||
22291
49.5k
            (tok >= TOK_FIRST_KEYWORD &&
22292
338
             tok <= TOK_LAST_KEYWORD));
22293
49.5k
}
22294
22295
/* if the property is an expression, name = JS_ATOM_NULL */
22296
static int __exception js_parse_property_name(JSParseState *s,
22297
                                              JSAtom *pname,
22298
                                              BOOL allow_method, BOOL allow_var,
22299
                                              BOOL allow_private)
22300
44.6k
{
22301
44.6k
    int is_private = 0;
22302
44.6k
    BOOL is_non_reserved_ident;
22303
44.6k
    JSAtom name;
22304
44.6k
    int prop_type;
22305
    
22306
44.6k
    prop_type = PROP_TYPE_IDENT;
22307
44.6k
    if (allow_method) {
22308
2.00k
        if (token_is_pseudo_keyword(s, JS_ATOM_get)
22309
2.00k
        ||  token_is_pseudo_keyword(s, JS_ATOM_set)) {
22310
            /* get x(), set x() */
22311
0
            name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
22312
0
            if (next_token(s))
22313
0
                goto fail1;
22314
0
            if (s->token.val == ':' || s->token.val == ',' ||
22315
0
                s->token.val == '}' || s->token.val == '(') {
22316
0
                is_non_reserved_ident = TRUE;
22317
0
                goto ident_found;
22318
0
            }
22319
0
            prop_type = PROP_TYPE_GET + (name == JS_ATOM_set);
22320
0
            JS_FreeAtom(s->ctx, name);
22321
2.00k
        } else if (s->token.val == '*') {
22322
0
            if (next_token(s))
22323
0
                goto fail;
22324
0
            prop_type = PROP_TYPE_STAR;
22325
2.00k
        } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
22326
2.00k
                   peek_token(s, TRUE) != '\n') {
22327
0
            name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
22328
0
            if (next_token(s))
22329
0
                goto fail1;
22330
0
            if (s->token.val == ':' || s->token.val == ',' ||
22331
0
                s->token.val == '}' || s->token.val == '(') {
22332
0
                is_non_reserved_ident = TRUE;
22333
0
                goto ident_found;
22334
0
            }
22335
0
            JS_FreeAtom(s->ctx, name);
22336
0
            if (s->token.val == '*') {
22337
0
                if (next_token(s))
22338
0
                    goto fail;
22339
0
                prop_type = PROP_TYPE_ASYNC_STAR;
22340
0
            } else {
22341
0
                prop_type = PROP_TYPE_ASYNC;
22342
0
            }
22343
0
        }
22344
2.00k
    }
22345
22346
44.6k
    if (token_is_ident(s->token.val)) {
22347
        /* variable can only be a non-reserved identifier */
22348
44.3k
        is_non_reserved_ident =
22349
44.3k
            (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved);
22350
        /* keywords and reserved words have a valid atom */
22351
44.3k
        name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
22352
44.3k
        if (next_token(s))
22353
0
            goto fail1;
22354
44.3k
    ident_found:
22355
44.3k
        if (is_non_reserved_ident &&
22356
44.3k
            prop_type == PROP_TYPE_IDENT && allow_var) {
22357
44.1k
            if (!(s->token.val == ':' ||
22358
44.1k
                  (s->token.val == '(' && allow_method))) {
22359
41.8k
                prop_type = PROP_TYPE_VAR;
22360
41.8k
            }
22361
44.1k
        }
22362
44.3k
    } else if (s->token.val == TOK_STRING) {
22363
0
        name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
22364
0
        if (name == JS_ATOM_NULL)
22365
0
            goto fail;
22366
0
        if (next_token(s))
22367
0
            goto fail1;
22368
336
    } else if (s->token.val == TOK_NUMBER) {
22369
112
        JSValue val;
22370
112
        val = s->token.u.num.val;
22371
112
#ifdef CONFIG_BIGNUM
22372
112
        if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
22373
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
22374
0
            val = s->ctx->rt->bigfloat_ops.
22375
0
                mul_pow10_to_float64(s->ctx, &p->num,
22376
0
                                     s->token.u.num.exponent);
22377
0
            if (JS_IsException(val))
22378
0
                goto fail;
22379
0
            name = JS_ValueToAtom(s->ctx, val);
22380
0
            JS_FreeValue(s->ctx, val);
22381
0
        } else
22382
112
#endif
22383
112
        {
22384
112
            name = JS_ValueToAtom(s->ctx, val);
22385
112
        }
22386
112
        if (name == JS_ATOM_NULL)
22387
0
            goto fail;
22388
112
        if (next_token(s))
22389
0
            goto fail1;
22390
224
    } else if (s->token.val == '[') {
22391
207
        if (next_token(s))
22392
0
            goto fail;
22393
207
        if (js_parse_expr(s))
22394
0
            goto fail;
22395
207
        if (js_parse_expect(s, ']'))
22396
0
            goto fail;
22397
207
        name = JS_ATOM_NULL;
22398
207
    } else if (s->token.val == TOK_PRIVATE_NAME && allow_private) {
22399
17
        name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
22400
17
        if (next_token(s))
22401
0
            goto fail1;
22402
17
        is_private = PROP_TYPE_PRIVATE;
22403
17
    } else {
22404
0
        goto invalid_prop;
22405
0
    }
22406
44.6k
    if (prop_type != PROP_TYPE_IDENT && prop_type != PROP_TYPE_VAR &&
22407
44.6k
        s->token.val != '(') {
22408
0
        JS_FreeAtom(s->ctx, name);
22409
0
    invalid_prop:
22410
0
        js_parse_error(s, "invalid property name");
22411
0
        goto fail;
22412
0
    }
22413
44.6k
    *pname = name;
22414
44.6k
    return prop_type | is_private;
22415
0
 fail1:
22416
0
    JS_FreeAtom(s->ctx, name);
22417
0
 fail:
22418
0
    *pname = JS_ATOM_NULL;
22419
0
    return -1;
22420
0
}
22421
22422
typedef struct JSParsePos {
22423
    int last_line_num;
22424
    int line_num;
22425
    BOOL got_lf;
22426
    const uint8_t *ptr;
22427
} JSParsePos;
22428
22429
static int js_parse_get_pos(JSParseState *s, JSParsePos *sp)
22430
39.8k
{
22431
39.8k
    sp->last_line_num = s->last_line_num;
22432
39.8k
    sp->line_num = s->token.line_num;
22433
39.8k
    sp->ptr = s->token.ptr;
22434
39.8k
    sp->got_lf = s->got_lf;
22435
39.8k
    return 0;
22436
39.8k
}
22437
22438
static __exception int js_parse_seek_token(JSParseState *s, const JSParsePos *sp)
22439
39.8k
{
22440
39.8k
    s->token.line_num = sp->last_line_num;
22441
39.8k
    s->line_num = sp->line_num;
22442
39.8k
    s->buf_ptr = sp->ptr;
22443
39.8k
    s->got_lf = sp->got_lf;
22444
39.8k
    return next_token(s);
22445
39.8k
}
22446
22447
/* return TRUE if a regexp literal is allowed after this token */
22448
static BOOL is_regexp_allowed(int tok)
22449
170
{
22450
170
    switch (tok) {
22451
0
    case TOK_NUMBER:
22452
0
    case TOK_STRING:
22453
0
    case TOK_REGEXP:
22454
0
    case TOK_DEC:
22455
0
    case TOK_INC:
22456
0
    case TOK_NULL:
22457
0
    case TOK_FALSE:
22458
0
    case TOK_TRUE:
22459
0
    case TOK_THIS:
22460
0
    case ')':
22461
0
    case ']':
22462
0
    case '}': /* XXX: regexp may occur after */
22463
170
    case TOK_IDENT:
22464
170
        return FALSE;
22465
0
    default:
22466
0
        return TRUE;
22467
170
    }
22468
170
}
22469
22470
304
#define SKIP_HAS_SEMI       (1 << 0)
22471
24.7k
#define SKIP_HAS_ELLIPSIS   (1 << 1)
22472
14.8k
#define SKIP_HAS_ASSIGNMENT (1 << 2)
22473
22474
/* XXX: improve speed with early bailout */
22475
/* XXX: no longer works if regexps are present. Could use previous
22476
   regexp parsing heuristics to handle most cases */
22477
static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_terminator)
22478
39.6k
{
22479
39.6k
    char state[256];
22480
39.6k
    size_t level = 0;
22481
39.6k
    JSParsePos pos;
22482
39.6k
    int last_tok, tok = TOK_EOF;
22483
39.6k
    int c, tok_len, bits = 0;
22484
22485
    /* protect from underflow */
22486
39.6k
    state[level++] = 0;
22487
22488
39.6k
    js_parse_get_pos(s, &pos);
22489
39.6k
    last_tok = 0;
22490
184k
    for (;;) {
22491
184k
        switch(s->token.val) {
22492
12.8k
        case '(':
22493
32.2k
        case '[':
22494
39.9k
        case '{':
22495
39.9k
            if (level >= sizeof(state))
22496
0
                goto done;
22497
39.9k
            state[level++] = s->token.val;
22498
39.9k
            break;
22499
12.8k
        case ')':
22500
12.8k
            if (state[--level] != '(')
22501
0
                goto done;
22502
12.8k
            break;
22503
19.4k
        case ']':
22504
19.4k
            if (state[--level] != '[')
22505
0
                goto done;
22506
19.4k
            break;
22507
19.4k
        case '}':
22508
7.62k
            c = state[--level];
22509
7.62k
            if (c == '`') {
22510
                /* continue the parsing of the template */
22511
0
                free_token(s, &s->token);
22512
                /* Resume TOK_TEMPLATE parsing (s->token.line_num and
22513
                 * s->token.ptr are OK) */
22514
0
                s->got_lf = FALSE;
22515
0
                s->last_line_num = s->token.line_num;
22516
0
                if (js_parse_template_part(s, s->buf_ptr))
22517
0
                    goto done;
22518
0
                goto handle_template;
22519
7.62k
            } else if (c != '{') {
22520
0
                goto done;
22521
0
            }
22522
7.62k
            break;
22523
7.62k
        case TOK_TEMPLATE:
22524
248
        handle_template:
22525
248
            if (s->token.u.str.sep != '`') {
22526
                /* '${' inside the template : closing '}' and continue
22527
                   parsing the template */
22528
0
                if (level >= sizeof(state))
22529
0
                    goto done;
22530
0
                state[level++] = '`';
22531
0
            } 
22532
248
            break;
22533
248
        case TOK_EOF:
22534
0
            goto done;
22535
24
        case ';':
22536
24
            if (level == 2) {
22537
24
                bits |= SKIP_HAS_SEMI;
22538
24
            }
22539
24
            break;
22540
25
        case TOK_ELLIPSIS:
22541
25
            if (level == 2) {
22542
25
                bits |= SKIP_HAS_ELLIPSIS;
22543
25
            }
22544
25
            break;
22545
2.59k
        case '=':
22546
2.59k
            bits |= SKIP_HAS_ASSIGNMENT;
22547
2.59k
            break;
22548
            
22549
0
        case TOK_DIV_ASSIGN:
22550
0
            tok_len = 2;
22551
0
            goto parse_regexp;
22552
170
        case '/':
22553
170
            tok_len = 1;
22554
170
        parse_regexp:
22555
170
            if (is_regexp_allowed(last_tok)) {
22556
0
                s->buf_ptr -= tok_len;
22557
0
                if (js_parse_regexp(s)) {
22558
                    /* XXX: should clear the exception */
22559
0
                    goto done;
22560
0
                }
22561
0
            }
22562
170
            break;
22563
184k
        }
22564
        /* last_tok is only used to recognize regexps */
22565
184k
        if (s->token.val == TOK_IDENT &&
22566
184k
            (token_is_pseudo_keyword(s, JS_ATOM_of) ||
22567
57.8k
             token_is_pseudo_keyword(s, JS_ATOM_yield))) {
22568
2
            last_tok = TOK_OF;
22569
184k
        } else {
22570
184k
            last_tok = s->token.val;
22571
184k
        }
22572
184k
        if (next_token(s)) {
22573
            /* XXX: should clear the exception generated by next_token() */
22574
0
            break;
22575
0
        }
22576
184k
        if (level <= 1) {
22577
39.6k
            tok = s->token.val;
22578
39.6k
            if (token_is_pseudo_keyword(s, JS_ATOM_of))
22579
0
                tok = TOK_OF;
22580
39.6k
            if (no_line_terminator && s->last_line_num != s->token.line_num)
22581
6
                tok = '\n';
22582
39.6k
            break;
22583
39.6k
        }
22584
184k
    }
22585
39.6k
 done:
22586
39.6k
    if (pbits) {
22587
39.4k
        *pbits = bits;
22588
39.4k
    }
22589
39.6k
    if (js_parse_seek_token(s, &pos))
22590
0
        return -1;
22591
39.6k
    return tok;
22592
39.6k
}
22593
22594
static void set_object_name(JSParseState *s, JSAtom name)
22595
218k
{
22596
218k
    JSFunctionDef *fd = s->cur_func;
22597
218k
    int opcode;
22598
22599
218k
    opcode = get_prev_opcode(fd);
22600
218k
    if (opcode == OP_set_name) {
22601
        /* XXX: should free atom after OP_set_name? */
22602
310
        fd->byte_code.size = fd->last_opcode_pos;
22603
310
        fd->last_opcode_pos = -1;
22604
310
        emit_op(s, OP_set_name);
22605
310
        emit_atom(s, name);
22606
218k
    } else if (opcode == OP_set_class_name) {
22607
0
        int define_class_pos;
22608
0
        JSAtom atom;
22609
0
        define_class_pos = fd->last_opcode_pos + 1 -
22610
0
            get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
22611
0
        assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
22612
        /* for consistency we free the previous atom which is
22613
           JS_ATOM_empty_string */
22614
0
        atom = get_u32(fd->byte_code.buf + define_class_pos + 1);
22615
0
        JS_FreeAtom(s->ctx, atom);
22616
0
        put_u32(fd->byte_code.buf + define_class_pos + 1,
22617
0
                JS_DupAtom(s->ctx, name));
22618
0
        fd->last_opcode_pos = -1;
22619
0
    }
22620
218k
}
22621
22622
static void set_object_name_computed(JSParseState *s)
22623
93
{
22624
93
    JSFunctionDef *fd = s->cur_func;
22625
93
    int opcode;
22626
22627
93
    opcode = get_prev_opcode(fd);
22628
93
    if (opcode == OP_set_name) {
22629
        /* XXX: should free atom after OP_set_name? */
22630
0
        fd->byte_code.size = fd->last_opcode_pos;
22631
0
        fd->last_opcode_pos = -1;
22632
0
        emit_op(s, OP_set_name_computed);
22633
93
    } else if (opcode == OP_set_class_name) {
22634
0
        int define_class_pos;
22635
0
        define_class_pos = fd->last_opcode_pos + 1 -
22636
0
            get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
22637
0
        assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
22638
0
        fd->byte_code.buf[define_class_pos] = OP_define_class_computed;
22639
0
        fd->last_opcode_pos = -1;
22640
0
    }
22641
93
}
22642
22643
static __exception int js_parse_object_literal(JSParseState *s)
22644
937
{
22645
937
    JSAtom name = JS_ATOM_NULL;
22646
937
    const uint8_t *start_ptr;
22647
937
    int start_line, prop_type;
22648
937
    BOOL has_proto;
22649
22650
937
    if (next_token(s))
22651
0
        goto fail;
22652
    /* XXX: add an initial length that will be patched back */
22653
937
    emit_op(s, OP_object);
22654
937
    has_proto = FALSE;
22655
2.42k
    while (s->token.val != '}') {
22656
        /* specific case for getter/setter */
22657
1.49k
        start_ptr = s->token.ptr;
22658
1.49k
        start_line = s->token.line_num;
22659
22660
1.49k
        if (s->token.val == TOK_ELLIPSIS) {
22661
5
            if (next_token(s))
22662
0
                return -1;
22663
5
            if (js_parse_assign_expr(s))
22664
0
                return -1;
22665
5
            emit_op(s, OP_null);  /* dummy excludeList */
22666
5
            emit_op(s, OP_copy_data_properties);
22667
5
            emit_u8(s, 2 | (1 << 2) | (0 << 5));
22668
5
            emit_op(s, OP_drop); /* pop excludeList */
22669
5
            emit_op(s, OP_drop); /* pop src object */
22670
5
            goto next;
22671
5
        }
22672
22673
1.49k
        prop_type = js_parse_property_name(s, &name, TRUE, TRUE, FALSE);
22674
1.49k
        if (prop_type < 0)
22675
0
            goto fail;
22676
22677
1.49k
        if (prop_type == PROP_TYPE_VAR) {
22678
            /* shortcut for x: x */
22679
1.49k
            emit_op(s, OP_scope_get_var);
22680
1.49k
            emit_atom(s, name);
22681
1.49k
            emit_u16(s, s->cur_func->scope_level);
22682
1.49k
            emit_op(s, OP_define_field);
22683
1.49k
            emit_atom(s, name);
22684
1.49k
        } else if (s->token.val == '(') {
22685
0
            BOOL is_getset = (prop_type == PROP_TYPE_GET ||
22686
0
                              prop_type == PROP_TYPE_SET);
22687
0
            JSParseFunctionEnum func_type;
22688
0
            JSFunctionKindEnum func_kind;
22689
0
            int op_flags;
22690
22691
0
            func_kind = JS_FUNC_NORMAL;
22692
0
            if (is_getset) {
22693
0
                func_type = JS_PARSE_FUNC_GETTER + prop_type - PROP_TYPE_GET;
22694
0
            } else {
22695
0
                func_type = JS_PARSE_FUNC_METHOD;
22696
0
                if (prop_type == PROP_TYPE_STAR)
22697
0
                    func_kind = JS_FUNC_GENERATOR;
22698
0
                else if (prop_type == PROP_TYPE_ASYNC)
22699
0
                    func_kind = JS_FUNC_ASYNC;
22700
0
                else if (prop_type == PROP_TYPE_ASYNC_STAR)
22701
0
                    func_kind = JS_FUNC_ASYNC_GENERATOR;
22702
0
            }
22703
0
            if (js_parse_function_decl(s, func_type, func_kind, JS_ATOM_NULL,
22704
0
                                       start_ptr, start_line))
22705
0
                goto fail;
22706
0
            if (name == JS_ATOM_NULL) {
22707
0
                emit_op(s, OP_define_method_computed);
22708
0
            } else {
22709
0
                emit_op(s, OP_define_method);
22710
0
                emit_atom(s, name);
22711
0
            }
22712
0
            if (is_getset) {
22713
0
                op_flags = OP_DEFINE_METHOD_GETTER +
22714
0
                    prop_type - PROP_TYPE_GET;
22715
0
            } else {
22716
0
                op_flags = OP_DEFINE_METHOD_METHOD;
22717
0
            }
22718
0
            emit_u8(s, op_flags | OP_DEFINE_METHOD_ENUMERABLE);
22719
0
        } else {
22720
0
            if (js_parse_expect(s, ':'))
22721
0
                goto fail;
22722
0
            if (js_parse_assign_expr(s))
22723
0
                goto fail;
22724
0
            if (name == JS_ATOM_NULL) {
22725
0
                set_object_name_computed(s);
22726
0
                emit_op(s, OP_define_array_el);
22727
0
                emit_op(s, OP_drop);
22728
0
            } else if (name == JS_ATOM___proto__) {
22729
0
                if (has_proto) {
22730
0
                    js_parse_error(s, "duplicate __proto__ property name");
22731
0
                    goto fail;
22732
0
                }
22733
0
                emit_op(s, OP_set_proto);
22734
0
                has_proto = TRUE;
22735
0
            } else {
22736
0
                set_object_name(s, name);
22737
0
                emit_op(s, OP_define_field);
22738
0
                emit_atom(s, name);
22739
0
            }
22740
0
        }
22741
1.49k
        JS_FreeAtom(s->ctx, name);
22742
1.49k
    next:
22743
1.49k
        name = JS_ATOM_NULL;
22744
1.49k
        if (s->token.val != ',')
22745
7
            break;
22746
1.48k
        if (next_token(s))
22747
0
            goto fail;
22748
1.48k
    }
22749
937
    if (js_parse_expect(s, '}'))
22750
0
        goto fail;
22751
937
    return 0;
22752
0
 fail:
22753
0
    JS_FreeAtom(s->ctx, name);
22754
0
    return -1;
22755
937
}
22756
22757
/* allow the 'in' binary operator */
22758
141k
#define PF_IN_ACCEPTED  (1 << 0) 
22759
/* allow function calls parsing in js_parse_postfix_expr() */
22760
1.15M
#define PF_POSTFIX_CALL (1 << 1) 
22761
/* allow arrow functions parsing in js_parse_postfix_expr() */
22762
2.24M
#define PF_ARROW_FUNC   (1 << 2) 
22763
/* allow the exponentiation operator in js_parse_unary() */
22764
1.13M
#define PF_POW_ALLOWED  (1 << 3) 
22765
/* forbid the exponentiation operator in js_parse_unary() */
22766
574k
#define PF_POW_FORBIDDEN (1 << 4) 
22767
22768
static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
22769
22770
static __exception int js_parse_left_hand_side_expr(JSParseState *s)
22771
8.11k
{
22772
8.11k
    return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
22773
8.11k
}
22774
22775
/* XXX: could generate specific bytecode */
22776
static __exception int js_parse_class_default_ctor(JSParseState *s,
22777
                                                   BOOL has_super,
22778
                                                   JSFunctionDef **pfd)
22779
88
{
22780
88
    JSParsePos pos;
22781
88
    const char *str;
22782
88
    int ret, line_num;
22783
88
    JSParseFunctionEnum func_type;
22784
88
    const uint8_t *saved_buf_end;
22785
    
22786
88
    js_parse_get_pos(s, &pos);
22787
88
    if (has_super) {
22788
        /* spec change: no argument evaluation */
22789
0
        str = "(){super(...arguments);}";
22790
0
        func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
22791
88
    } else {
22792
88
        str = "(){}";
22793
88
        func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
22794
88
    }
22795
88
    line_num = s->token.line_num;
22796
88
    saved_buf_end = s->buf_end;
22797
88
    s->buf_ptr = (uint8_t *)str;
22798
88
    s->buf_end = (uint8_t *)(str + strlen(str));
22799
88
    ret = next_token(s);
22800
88
    if (!ret) {
22801
88
        ret = js_parse_function_decl2(s, func_type, JS_FUNC_NORMAL,
22802
88
                                      JS_ATOM_NULL, (uint8_t *)str,
22803
88
                                      line_num, JS_PARSE_EXPORT_NONE, pfd);
22804
88
    }
22805
88
    s->buf_end = saved_buf_end;
22806
88
    ret |= js_parse_seek_token(s, &pos);
22807
88
    return ret;
22808
88
}
22809
22810
/* find field in the current scope */
22811
static int find_private_class_field(JSContext *ctx, JSFunctionDef *fd,
22812
                                    JSAtom name, int scope_level)
22813
17
{
22814
17
    int idx;
22815
17
    idx = fd->scopes[scope_level].first;
22816
96
    while (idx != -1) {
22817
90
        if (fd->vars[idx].scope_level != scope_level)
22818
11
            break;
22819
79
        if (fd->vars[idx].var_name == name)
22820
0
            return idx;
22821
79
        idx = fd->vars[idx].scope_next;
22822
79
    }
22823
17
    return -1;
22824
17
}
22825
22826
/* initialize the class fields, called by the constructor. Note:
22827
   super() can be called in an arrow function, so <this> and
22828
   <class_fields_init> can be variable references */
22829
static void emit_class_field_init(JSParseState *s)
22830
88
{
22831
88
    int label_next;
22832
    
22833
88
    emit_op(s, OP_scope_get_var);
22834
88
    emit_atom(s, JS_ATOM_class_fields_init);
22835
88
    emit_u16(s, s->cur_func->scope_level);
22836
22837
    /* no need to call the class field initializer if not defined */
22838
88
    emit_op(s, OP_dup);
22839
88
    label_next = emit_goto(s, OP_if_false, -1);
22840
    
22841
88
    emit_op(s, OP_scope_get_var);
22842
88
    emit_atom(s, JS_ATOM_this);
22843
88
    emit_u16(s, 0);
22844
    
22845
88
    emit_op(s, OP_swap);
22846
    
22847
88
    emit_op(s, OP_call_method);
22848
88
    emit_u16(s, 0);
22849
22850
88
    emit_label(s, label_next);
22851
88
    emit_op(s, OP_drop);
22852
88
}
22853
22854
/* build a private setter function name from the private getter name */
22855
static JSAtom get_private_setter_name(JSContext *ctx, JSAtom name)
22856
0
{
22857
0
    return js_atom_concat_str(ctx, name, "<set>");
22858
0
}
22859
22860
typedef struct {
22861
    JSFunctionDef *fields_init_fd;
22862
    int computed_fields_count;
22863
    BOOL has_brand;
22864
    int brand_push_pos;
22865
} ClassFieldsDef;
22866
22867
static __exception int emit_class_init_start(JSParseState *s,
22868
                                             ClassFieldsDef *cf)
22869
88
{
22870
88
    int label_add_brand;
22871
    
22872
88
    cf->fields_init_fd = js_parse_function_class_fields_init(s);
22873
88
    if (!cf->fields_init_fd)
22874
0
        return -1;
22875
22876
88
    s->cur_func = cf->fields_init_fd;
22877
    
22878
    /* XXX: would be better to add the code only if needed, maybe in a
22879
       later pass */
22880
88
    emit_op(s, OP_push_false); /* will be patched later */
22881
88
    cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos;
22882
88
    label_add_brand = emit_goto(s, OP_if_false, -1);
22883
    
22884
88
    emit_op(s, OP_scope_get_var);
22885
88
    emit_atom(s, JS_ATOM_this);
22886
88
    emit_u16(s, 0);
22887
    
22888
88
    emit_op(s, OP_scope_get_var);
22889
88
    emit_atom(s, JS_ATOM_home_object);
22890
88
    emit_u16(s, 0);
22891
    
22892
88
    emit_op(s, OP_add_brand);
22893
    
22894
88
    emit_label(s, label_add_brand);
22895
22896
88
    s->cur_func = s->cur_func->parent;
22897
88
    return 0;
22898
88
}
22899
22900
static __exception int add_brand(JSParseState *s, ClassFieldsDef *cf)
22901
0
{
22902
0
    if (!cf->has_brand) {
22903
        /* define the brand field in 'this' of the initializer */
22904
0
        if (!cf->fields_init_fd) {
22905
0
            if (emit_class_init_start(s, cf))
22906
0
                return -1;
22907
0
        }
22908
        /* patch the start of the function to enable the OP_add_brand code */
22909
0
        cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true;
22910
        
22911
0
        cf->has_brand = TRUE;
22912
0
    }
22913
0
    return 0;
22914
0
}
22915
22916
static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf)
22917
88
{
22918
88
    int cpool_idx;
22919
        
22920
88
    s->cur_func = cf->fields_init_fd;
22921
88
    emit_op(s, OP_return_undef);
22922
88
    s->cur_func = s->cur_func->parent;
22923
    
22924
88
    cpool_idx = cpool_add(s, JS_NULL);
22925
88
    cf->fields_init_fd->parent_cpool_idx = cpool_idx;
22926
88
    emit_op(s, OP_fclosure);
22927
88
    emit_u32(s, cpool_idx);
22928
88
    emit_op(s, OP_set_home_object);
22929
88
}
22930
22931
22932
static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
22933
                                      JSParseExportEnum export_flag)
22934
88
{
22935
88
    JSContext *ctx = s->ctx;
22936
88
    JSFunctionDef *fd = s->cur_func;
22937
88
    JSAtom name = JS_ATOM_NULL, class_name = JS_ATOM_NULL, class_name1;
22938
88
    JSAtom class_var_name = JS_ATOM_NULL;
22939
88
    JSFunctionDef *method_fd, *ctor_fd;
22940
88
    int saved_js_mode, class_name_var_idx, prop_type, ctor_cpool_offset;
22941
88
    int class_flags = 0, i, define_class_offset;
22942
88
    BOOL is_static, is_private;
22943
88
    const uint8_t *class_start_ptr = s->token.ptr;
22944
88
    const uint8_t *start_ptr;
22945
88
    ClassFieldsDef class_fields[2];
22946
        
22947
    /* classes are parsed and executed in strict mode */
22948
88
    saved_js_mode = fd->js_mode;
22949
88
    fd->js_mode |= JS_MODE_STRICT;
22950
88
    if (next_token(s))
22951
0
        goto fail;
22952
88
    if (s->token.val == TOK_IDENT) {
22953
85
        if (s->token.u.ident.is_reserved) {
22954
0
            js_parse_error_reserved_identifier(s);
22955
0
            goto fail;
22956
0
        }
22957
85
        class_name = JS_DupAtom(ctx, s->token.u.ident.atom);
22958
85
        if (next_token(s))
22959
0
            goto fail;
22960
85
    } else if (!is_class_expr && export_flag != JS_PARSE_EXPORT_DEFAULT) {
22961
0
        js_parse_error(s, "class statement requires a name");
22962
0
        goto fail;
22963
0
    }
22964
88
    if (!is_class_expr) {
22965
5
        if (class_name == JS_ATOM_NULL)
22966
0
            class_var_name = JS_ATOM__default_; /* export default */
22967
5
        else
22968
5
            class_var_name = class_name;
22969
5
        class_var_name = JS_DupAtom(ctx, class_var_name);
22970
5
    }
22971
22972
88
    push_scope(s);
22973
22974
88
    if (s->token.val == TOK_EXTENDS) {
22975
0
        class_flags = JS_DEFINE_CLASS_HAS_HERITAGE;
22976
0
        if (next_token(s))
22977
0
            goto fail;
22978
0
        if (js_parse_left_hand_side_expr(s))
22979
0
            goto fail;
22980
88
    } else {
22981
88
        emit_op(s, OP_undefined);
22982
88
    }
22983
22984
    /* add a 'const' definition for the class name */
22985
88
    if (class_name != JS_ATOM_NULL) {
22986
85
        class_name_var_idx = define_var(s, fd, class_name, JS_VAR_DEF_CONST);
22987
85
        if (class_name_var_idx < 0)
22988
0
            goto fail;
22989
85
    }
22990
22991
88
    if (js_parse_expect(s, '{'))
22992
0
        goto fail;
22993
22994
    /* this scope contains the private fields */
22995
88
    push_scope(s);
22996
22997
88
    emit_op(s, OP_push_const);
22998
88
    ctor_cpool_offset = fd->byte_code.size;
22999
88
    emit_u32(s, 0); /* will be patched at the end of the class parsing */
23000
23001
88
    if (class_name == JS_ATOM_NULL) {
23002
3
        if (class_var_name != JS_ATOM_NULL)
23003
0
            class_name1 = JS_ATOM_default;
23004
3
        else
23005
3
            class_name1 = JS_ATOM_empty_string;
23006
85
    } else {
23007
85
        class_name1 = class_name;
23008
85
    }
23009
    
23010
88
    emit_op(s, OP_define_class);
23011
88
    emit_atom(s, class_name1);
23012
88
    emit_u8(s, class_flags);
23013
88
    define_class_offset = fd->last_opcode_pos;
23014
23015
264
    for(i = 0; i < 2; i++) {
23016
176
        ClassFieldsDef *cf = &class_fields[i];
23017
176
        cf->fields_init_fd = NULL;
23018
176
        cf->computed_fields_count = 0;
23019
176
        cf->has_brand = FALSE;
23020
176
    }
23021
    
23022
88
    ctor_fd = NULL;
23023
611
    while (s->token.val != '}') {
23024
523
        if (s->token.val == ';') {
23025
5
            if (next_token(s))
23026
0
                goto fail;
23027
5
            continue;
23028
5
        }
23029
518
        is_static = (s->token.val == TOK_STATIC);
23030
518
        prop_type = -1;
23031
518
        if (is_static) {
23032
0
            if (next_token(s))
23033
0
                goto fail;
23034
            /* allow "static" field name */
23035
0
            if (s->token.val == ';' || s->token.val == '=') {
23036
0
                is_static = FALSE;
23037
0
                name = JS_DupAtom(ctx, JS_ATOM_static);
23038
0
                prop_type = PROP_TYPE_IDENT;
23039
0
            }
23040
0
        }
23041
518
        if (is_static)
23042
0
            emit_op(s, OP_swap);
23043
518
        start_ptr = s->token.ptr;
23044
518
        if (prop_type < 0) {
23045
518
            prop_type = js_parse_property_name(s, &name, TRUE, FALSE, TRUE);
23046
518
            if (prop_type < 0)
23047
0
                goto fail;
23048
518
        }
23049
518
        is_private = prop_type & PROP_TYPE_PRIVATE;
23050
518
        prop_type &= ~PROP_TYPE_PRIVATE;
23051
        
23052
518
        if ((name == JS_ATOM_constructor && !is_static &&
23053
518
             prop_type != PROP_TYPE_IDENT) ||
23054
518
            (name == JS_ATOM_prototype && is_static) ||
23055
518
            name == JS_ATOM_hash_constructor) {
23056
0
            js_parse_error(s, "invalid method name");
23057
0
            goto fail;
23058
0
        }
23059
518
        if (prop_type == PROP_TYPE_GET || prop_type == PROP_TYPE_SET) {
23060
0
            BOOL is_set = prop_type - PROP_TYPE_GET;
23061
0
            JSFunctionDef *method_fd;
23062
23063
0
            if (is_private) {
23064
0
                int idx, var_kind;
23065
0
                idx = find_private_class_field(ctx, fd, name, fd->scope_level);
23066
0
                if (idx >= 0) {
23067
0
                    var_kind = fd->vars[idx].var_kind;
23068
0
                    if (var_kind == JS_VAR_PRIVATE_FIELD ||
23069
0
                        var_kind == JS_VAR_PRIVATE_METHOD ||
23070
0
                        var_kind == JS_VAR_PRIVATE_GETTER_SETTER ||
23071
0
                        var_kind == (JS_VAR_PRIVATE_GETTER + is_set)) {
23072
0
                        goto private_field_already_defined;
23073
0
                    }
23074
0
                    fd->vars[idx].var_kind = JS_VAR_PRIVATE_GETTER_SETTER;
23075
0
                } else {
23076
0
                    if (add_private_class_field(s, fd, name,
23077
0
                                                JS_VAR_PRIVATE_GETTER + is_set) < 0)
23078
0
                        goto fail;
23079
0
                }
23080
0
                if (add_brand(s, &class_fields[is_static]) < 0)
23081
0
                    goto fail;
23082
0
            }
23083
23084
0
            if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set,
23085
0
                                        JS_FUNC_NORMAL, JS_ATOM_NULL,
23086
0
                                        start_ptr, s->token.line_num,
23087
0
                                        JS_PARSE_EXPORT_NONE, &method_fd))
23088
0
                goto fail;
23089
0
            if (is_private) {
23090
0
                method_fd->need_home_object = TRUE; /* needed for brand check */
23091
0
                emit_op(s, OP_set_home_object);
23092
                /* XXX: missing function name */
23093
0
                emit_op(s, OP_scope_put_var_init);
23094
0
                if (is_set) {
23095
0
                    JSAtom setter_name;
23096
0
                    int ret;
23097
                    
23098
0
                    setter_name = get_private_setter_name(ctx, name);
23099
0
                    if (setter_name == JS_ATOM_NULL)
23100
0
                        goto fail;
23101
0
                    emit_atom(s, setter_name);
23102
0
                    ret = add_private_class_field(s, fd, setter_name,
23103
0
                                                  JS_VAR_PRIVATE_SETTER);
23104
0
                    JS_FreeAtom(ctx, setter_name);
23105
0
                    if (ret < 0)
23106
0
                        goto fail;
23107
0
                } else {
23108
0
                    emit_atom(s, name);
23109
0
                }
23110
0
                emit_u16(s, s->cur_func->scope_level);
23111
0
            } else {
23112
0
                if (name == JS_ATOM_NULL) {
23113
0
                    emit_op(s, OP_define_method_computed);
23114
0
                } else {
23115
0
                    emit_op(s, OP_define_method);
23116
0
                    emit_atom(s, name);
23117
0
                }
23118
0
                emit_u8(s, OP_DEFINE_METHOD_GETTER + is_set);
23119
0
            }
23120
518
        } else if (prop_type == PROP_TYPE_IDENT && s->token.val != '(') {
23121
387
            ClassFieldsDef *cf = &class_fields[is_static];
23122
387
            JSAtom field_var_name = JS_ATOM_NULL;
23123
            
23124
            /* class field */
23125
23126
            /* XXX: spec: not consistent with method name checks */
23127
387
            if (name == JS_ATOM_constructor || name == JS_ATOM_prototype) {
23128
0
                js_parse_error(s, "invalid field name");
23129
0
                goto fail;
23130
0
            }
23131
            
23132
387
            if (is_private) {
23133
17
                if (find_private_class_field(ctx, fd, name,
23134
17
                                             fd->scope_level) >= 0) {
23135
0
                    goto private_field_already_defined;
23136
0
                }
23137
17
                if (add_private_class_field(s, fd, name,
23138
17
                                            JS_VAR_PRIVATE_FIELD) < 0)
23139
0
                    goto fail;
23140
17
                emit_op(s, OP_private_symbol);
23141
17
                emit_atom(s, name);
23142
17
                emit_op(s, OP_scope_put_var_init);
23143
17
                emit_atom(s, name);
23144
17
                emit_u16(s, s->cur_func->scope_level);
23145
17
            }
23146
23147
387
            if (!cf->fields_init_fd) {
23148
88
                if (emit_class_init_start(s, cf))
23149
0
                    goto fail;
23150
88
            }
23151
387
            if (name == JS_ATOM_NULL ) {
23152
                /* save the computed field name into a variable */
23153
76
                field_var_name = js_atom_concat_num(ctx, JS_ATOM_computed_field + is_static, cf->computed_fields_count);
23154
76
                if (field_var_name == JS_ATOM_NULL)
23155
0
                    goto fail;
23156
76
                if (define_var(s, fd, field_var_name, JS_VAR_DEF_CONST) < 0) {
23157
0
                    JS_FreeAtom(ctx, field_var_name);
23158
0
                    goto fail;
23159
0
                }
23160
76
                emit_op(s, OP_to_propkey);
23161
76
                emit_op(s, OP_scope_put_var_init);
23162
76
                emit_atom(s, field_var_name);
23163
76
                emit_u16(s, s->cur_func->scope_level);
23164
76
            }
23165
387
            s->cur_func = cf->fields_init_fd;
23166
387
            emit_op(s, OP_scope_get_var);
23167
387
            emit_atom(s, JS_ATOM_this);
23168
387
            emit_u16(s, 0);
23169
23170
387
            if (name == JS_ATOM_NULL) {
23171
76
                emit_op(s, OP_scope_get_var);
23172
76
                emit_atom(s, field_var_name);
23173
76
                emit_u16(s, s->cur_func->scope_level);
23174
76
                cf->computed_fields_count++;
23175
76
                JS_FreeAtom(ctx, field_var_name);
23176
311
            } else if (is_private) {
23177
17
                emit_op(s, OP_scope_get_var);
23178
17
                emit_atom(s, name);
23179
17
                emit_u16(s, s->cur_func->scope_level);
23180
17
            }
23181
            
23182
387
            if (s->token.val == '=') {
23183
10
                if (next_token(s))
23184
0
                    goto fail;
23185
10
                if (js_parse_assign_expr(s))
23186
0
                    goto fail;
23187
377
            } else {
23188
377
                emit_op(s, OP_undefined);
23189
377
            }
23190
387
            if (is_private) {
23191
17
                set_object_name_computed(s);
23192
17
                emit_op(s, OP_define_private_field);
23193
370
            } else if (name == JS_ATOM_NULL) {
23194
76
                set_object_name_computed(s);
23195
76
                emit_op(s, OP_define_array_el);
23196
76
                emit_op(s, OP_drop);
23197
294
            } else {
23198
294
                set_object_name(s, name);
23199
294
                emit_op(s, OP_define_field);
23200
294
                emit_atom(s, name);
23201
294
            }
23202
387
            s->cur_func = s->cur_func->parent;
23203
387
            if (js_parse_expect_semi(s))
23204
0
                goto fail;
23205
387
        } else {
23206
131
            JSParseFunctionEnum func_type;
23207
131
            JSFunctionKindEnum func_kind;
23208
            
23209
131
            func_type = JS_PARSE_FUNC_METHOD;
23210
131
            func_kind = JS_FUNC_NORMAL;
23211
131
            if (prop_type == PROP_TYPE_STAR) {
23212
0
                func_kind = JS_FUNC_GENERATOR;
23213
131
            } else if (prop_type == PROP_TYPE_ASYNC) {
23214
0
                func_kind = JS_FUNC_ASYNC;
23215
131
            } else if (prop_type == PROP_TYPE_ASYNC_STAR) {
23216
0
                func_kind = JS_FUNC_ASYNC_GENERATOR;
23217
131
            } else if (name == JS_ATOM_constructor && !is_static) {
23218
0
                if (ctor_fd) {
23219
0
                    js_parse_error(s, "property constructor appears more than once");
23220
0
                    goto fail;
23221
0
                }
23222
0
                if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE)
23223
0
                    func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
23224
0
                else
23225
0
                    func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
23226
0
            }
23227
131
            if (is_private) {
23228
0
                if (add_brand(s, &class_fields[is_static]) < 0)
23229
0
                    goto fail;
23230
0
            }
23231
131
            if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, start_ptr, s->token.line_num, JS_PARSE_EXPORT_NONE, &method_fd))
23232
0
                goto fail;
23233
131
            if (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR ||
23234
131
                func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
23235
0
                ctor_fd = method_fd;
23236
131
            } else if (is_private) {
23237
0
                method_fd->need_home_object = TRUE; /* needed for brand check */
23238
0
                if (find_private_class_field(ctx, fd, name,
23239
0
                                             fd->scope_level) >= 0) {
23240
0
                private_field_already_defined:
23241
0
                    js_parse_error(s, "private class field is already defined");
23242
0
                    goto fail;
23243
0
                }
23244
0
                if (add_private_class_field(s, fd, name,
23245
0
                                            JS_VAR_PRIVATE_METHOD) < 0)
23246
0
                    goto fail;
23247
0
                emit_op(s, OP_set_home_object);
23248
0
                emit_op(s, OP_set_name);
23249
0
                emit_atom(s, name);
23250
0
                emit_op(s, OP_scope_put_var_init);
23251
0
                emit_atom(s, name);
23252
0
                emit_u16(s, s->cur_func->scope_level);
23253
131
            } else {
23254
131
                if (name == JS_ATOM_NULL) {
23255
131
                    emit_op(s, OP_define_method_computed);
23256
131
                } else {
23257
0
                    emit_op(s, OP_define_method);
23258
0
                    emit_atom(s, name);
23259
0
                }
23260
131
                emit_u8(s, OP_DEFINE_METHOD_METHOD);
23261
131
            }
23262
131
        }
23263
518
        if (is_static)
23264
0
            emit_op(s, OP_swap);
23265
518
        JS_FreeAtom(ctx, name);
23266
518
        name = JS_ATOM_NULL;
23267
518
    }
23268
23269
88
    if (s->token.val != '}') {
23270
0
        js_parse_error(s, "expecting '%c'", '}');
23271
0
        goto fail;
23272
0
    }
23273
23274
88
    if (!ctor_fd) {
23275
88
        if (js_parse_class_default_ctor(s, class_flags & JS_DEFINE_CLASS_HAS_HERITAGE, &ctor_fd))
23276
0
            goto fail;
23277
88
    }
23278
    /* patch the constant pool index for the constructor */
23279
88
    put_u32(fd->byte_code.buf + ctor_cpool_offset, ctor_fd->parent_cpool_idx);
23280
23281
    /* store the class source code in the constructor. */
23282
88
    if (!(fd->js_mode & JS_MODE_STRIP)) {
23283
88
        js_free(ctx, ctor_fd->source);
23284
88
        ctor_fd->source_len = s->buf_ptr - class_start_ptr;
23285
88
        ctor_fd->source = js_strndup(ctx, (const char *)class_start_ptr,
23286
88
                                     ctor_fd->source_len);
23287
88
        if (!ctor_fd->source)
23288
0
            goto fail;
23289
88
    }
23290
23291
    /* consume the '}' */
23292
88
    if (next_token(s))
23293
0
        goto fail;
23294
23295
    /* store the function to initialize the fields to that it can be
23296
       referenced by the constructor */
23297
88
    {
23298
88
        ClassFieldsDef *cf = &class_fields[0];
23299
88
        int var_idx;
23300
        
23301
88
        var_idx = define_var(s, fd, JS_ATOM_class_fields_init,
23302
88
                             JS_VAR_DEF_CONST);
23303
88
        if (var_idx < 0)
23304
0
            goto fail;
23305
88
        if (cf->fields_init_fd) {
23306
88
            emit_class_init_end(s, cf);
23307
88
        } else {
23308
0
            emit_op(s, OP_undefined);
23309
0
        }
23310
88
        emit_op(s, OP_scope_put_var_init);
23311
88
        emit_atom(s, JS_ATOM_class_fields_init);
23312
88
        emit_u16(s, s->cur_func->scope_level);
23313
88
    }
23314
23315
    /* drop the prototype */
23316
0
    emit_op(s, OP_drop);
23317
23318
    /* initialize the static fields */
23319
88
    if (class_fields[1].fields_init_fd != NULL) {
23320
0
        ClassFieldsDef *cf = &class_fields[1];
23321
0
        emit_op(s, OP_dup);
23322
0
        emit_class_init_end(s, cf);
23323
0
        emit_op(s, OP_call_method);
23324
0
        emit_u16(s, 0);
23325
0
        emit_op(s, OP_drop);
23326
0
    }
23327
    
23328
88
    if (class_name != JS_ATOM_NULL) {
23329
        /* store the class name in the scoped class name variable (it
23330
           is independent from the class statement variable
23331
           definition) */
23332
85
        emit_op(s, OP_dup);
23333
85
        emit_op(s, OP_scope_put_var_init);
23334
85
        emit_atom(s, class_name);
23335
85
        emit_u16(s, fd->scope_level);
23336
85
    }
23337
88
    pop_scope(s);
23338
88
    pop_scope(s);
23339
23340
    /* the class statements have a block level scope */
23341
88
    if (class_var_name != JS_ATOM_NULL) {
23342
5
        if (define_var(s, fd, class_var_name, JS_VAR_DEF_LET) < 0)
23343
0
            goto fail;
23344
5
        emit_op(s, OP_scope_put_var_init);
23345
5
        emit_atom(s, class_var_name);
23346
5
        emit_u16(s, fd->scope_level);
23347
83
    } else {
23348
83
        if (class_name == JS_ATOM_NULL) {
23349
            /* cannot use OP_set_name because the name of the class
23350
               must be defined before the static initializers are
23351
               executed */
23352
3
            emit_op(s, OP_set_class_name);
23353
3
            emit_u32(s, fd->last_opcode_pos + 1 - define_class_offset);
23354
3
        }
23355
83
    }
23356
23357
88
    if (export_flag != JS_PARSE_EXPORT_NONE) {
23358
0
        if (!add_export_entry(s, fd->module,
23359
0
                              class_var_name,
23360
0
                              export_flag == JS_PARSE_EXPORT_NAMED ? class_var_name : JS_ATOM_default,
23361
0
                              JS_EXPORT_TYPE_LOCAL))
23362
0
            goto fail;
23363
0
    }
23364
23365
88
    JS_FreeAtom(ctx, class_name);
23366
88
    JS_FreeAtom(ctx, class_var_name);
23367
88
    fd->js_mode = saved_js_mode;
23368
88
    return 0;
23369
0
 fail:
23370
0
    JS_FreeAtom(ctx, name);
23371
0
    JS_FreeAtom(ctx, class_name);
23372
0
    JS_FreeAtom(ctx, class_var_name);
23373
0
    fd->js_mode = saved_js_mode;
23374
0
    return -1;
23375
88
}
23376
23377
static __exception int js_parse_array_literal(JSParseState *s)
23378
1.29k
{
23379
1.29k
    uint32_t idx;
23380
1.29k
    BOOL need_length;
23381
23382
1.29k
    if (next_token(s))
23383
0
        return -1;
23384
    /* small regular arrays are created on the stack */
23385
1.29k
    idx = 0;
23386
1.30k
    while (s->token.val != ']' && idx < 32) {
23387
562
        if (s->token.val == ',' || s->token.val == TOK_ELLIPSIS)
23388
549
            break;
23389
13
        if (js_parse_assign_expr(s))
23390
0
            return -1;
23391
13
        idx++;
23392
        /* accept trailing comma */
23393
13
        if (s->token.val == ',') {
23394
3
            if (next_token(s))
23395
0
                return -1;
23396
3
        } else
23397
10
        if (s->token.val != ']')
23398
0
            goto done;
23399
13
    }
23400
1.29k
    emit_op(s, OP_array_from);
23401
1.29k
    emit_u16(s, idx);
23402
23403
    /* larger arrays and holes are handled with explicit indices */
23404
1.29k
    need_length = FALSE;
23405
1.83k
    while (s->token.val != ']' && idx < 0x7fffffff) {
23406
549
        if (s->token.val == TOK_ELLIPSIS)
23407
1
            break;
23408
548
        need_length = TRUE;
23409
548
        if (s->token.val != ',') {
23410
0
            if (js_parse_assign_expr(s))
23411
0
                return -1;
23412
0
            emit_op(s, OP_define_field);
23413
0
            emit_u32(s, __JS_AtomFromUInt32(idx));
23414
0
            need_length = FALSE;
23415
0
        }
23416
548
        idx++;
23417
        /* accept trailing comma */
23418
548
        if (s->token.val == ',') {
23419
548
            if (next_token(s))
23420
0
                return -1;
23421
548
        }
23422
548
    }
23423
1.29k
    if (s->token.val == ']') {
23424
1.29k
        if (need_length) {
23425
            /* Set the length: Cannot use OP_define_field because
23426
               length is not configurable */
23427
548
            emit_op(s, OP_dup);
23428
548
            emit_op(s, OP_push_i32);
23429
548
            emit_u32(s, idx);
23430
548
            emit_op(s, OP_put_field);
23431
548
            emit_atom(s, JS_ATOM_length);
23432
548
        }
23433
1.29k
        goto done;
23434
1.29k
    }
23435
23436
    /* huge arrays and spread elements require a dynamic index on the stack */
23437
1
    emit_op(s, OP_push_i32);
23438
1
    emit_u32(s, idx);
23439
23440
    /* stack has array, index */
23441
4
    while (s->token.val != ']') {
23442
3
        if (s->token.val == TOK_ELLIPSIS) {
23443
1
            if (next_token(s))
23444
0
                return -1;
23445
1
            if (js_parse_assign_expr(s))
23446
0
                return -1;
23447
1
#if 1
23448
1
            emit_op(s, OP_append);
23449
#else
23450
            int label_next, label_done;
23451
            label_next = new_label(s);
23452
            label_done = new_label(s);
23453
            /* enumerate object */
23454
            emit_op(s, OP_for_of_start);
23455
            emit_op(s, OP_rot5l);
23456
            emit_op(s, OP_rot5l);
23457
            emit_label(s, label_next);
23458
            /* on stack: enum_rec array idx */
23459
            emit_op(s, OP_for_of_next);
23460
            emit_u8(s, 2);
23461
            emit_goto(s, OP_if_true, label_done);
23462
            /* append element */
23463
            /* enum_rec array idx val -> enum_rec array new_idx */
23464
            emit_op(s, OP_define_array_el);
23465
            emit_op(s, OP_inc);
23466
            emit_goto(s, OP_goto, label_next);
23467
            emit_label(s, label_done);
23468
            /* close enumeration */
23469
            emit_op(s, OP_drop); /* drop undef val */
23470
            emit_op(s, OP_nip1); /* drop enum_rec */
23471
            emit_op(s, OP_nip1);
23472
            emit_op(s, OP_nip1);
23473
#endif
23474
2
        } else {
23475
2
            need_length = TRUE;
23476
2
            if (s->token.val != ',') {
23477
1
                if (js_parse_assign_expr(s))
23478
0
                    return -1;
23479
                /* a idx val */
23480
1
                emit_op(s, OP_define_array_el);
23481
1
                need_length = FALSE;
23482
1
            }
23483
2
            emit_op(s, OP_inc);
23484
2
        }
23485
3
        if (s->token.val != ',')
23486
0
            break;
23487
3
        if (next_token(s))
23488
0
            return -1;
23489
3
    }
23490
1
    if (need_length) {
23491
        /* Set the length: cannot use OP_define_field because
23492
           length is not configurable */
23493
1
        emit_op(s, OP_dup1);    /* array length - array array length */
23494
1
        emit_op(s, OP_put_field);
23495
1
        emit_atom(s, JS_ATOM_length);
23496
1
    } else {
23497
0
        emit_op(s, OP_drop);    /* array length - array */
23498
0
    }
23499
1.29k
done:
23500
1.29k
    return js_parse_expect(s, ']');
23501
1
}
23502
23503
/* XXX: remove */
23504
static BOOL has_with_scope(JSFunctionDef *s, int scope_level)
23505
9.59k
{
23506
    /* check if scope chain contains a with statement */
23507
24.3k
    while (s) {
23508
15.3k
        int scope_idx = s->scopes[scope_level].first;
23509
58.7k
        while (scope_idx >= 0) {
23510
43.9k
            JSVarDef *vd = &s->vars[scope_idx];
23511
23512
43.9k
            if (vd->var_name == JS_ATOM__with_)
23513
526
                return TRUE;
23514
43.4k
            scope_idx = vd->scope_next;
23515
43.4k
        }
23516
        /* check parent scopes */
23517
14.7k
        scope_level = s->parent_scope_level;
23518
14.7k
        s = s->parent;
23519
14.7k
    }
23520
9.07k
    return FALSE;
23521
9.59k
}
23522
23523
static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
23524
                                  JSAtom *pname, int *plabel, int *pdepth, BOOL keep,
23525
                                  int tok)
23526
265k
{
23527
265k
    JSFunctionDef *fd;
23528
265k
    int opcode, scope, label, depth;
23529
265k
    JSAtom name;
23530
23531
    /* we check the last opcode to get the lvalue type */
23532
265k
    fd = s->cur_func;
23533
265k
    scope = 0;
23534
265k
    name = JS_ATOM_NULL;
23535
265k
    label = -1;
23536
265k
    depth = 0;
23537
265k
    switch(opcode = get_prev_opcode(fd)) {
23538
265k
    case OP_scope_get_var:
23539
265k
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
23540
265k
        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
23541
265k
        if ((name == JS_ATOM_arguments || name == JS_ATOM_eval) &&
23542
265k
            (fd->js_mode & JS_MODE_STRICT)) {
23543
0
            return js_parse_error(s, "invalid lvalue in strict mode");
23544
0
        }
23545
265k
        if (name == JS_ATOM_this || name == JS_ATOM_new_target)
23546
0
            goto invalid_lvalue;
23547
265k
        depth = 2;  /* will generate OP_get_ref_value */
23548
265k
        break;
23549
465
    case OP_get_field:
23550
465
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
23551
465
        depth = 1;
23552
465
        break;
23553
0
    case OP_scope_get_private_field:
23554
0
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
23555
0
        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
23556
0
        depth = 1;
23557
0
        break;
23558
3
    case OP_get_array_el:
23559
3
        depth = 2;
23560
3
        break;
23561
0
    case OP_get_super_value:
23562
0
        depth = 3;
23563
0
        break;
23564
3
    default:
23565
3
    invalid_lvalue:
23566
3
        if (tok == TOK_FOR) {
23567
0
            return js_parse_error(s, "invalid for in/of left hand-side");
23568
3
        } else if (tok == TOK_INC || tok == TOK_DEC) {
23569
0
            return js_parse_error(s, "invalid increment/decrement operand");
23570
3
        } else if (tok == '[' || tok == '{') {
23571
0
            return js_parse_error(s, "invalid destructuring target");
23572
3
        } else {
23573
3
            return js_parse_error(s, "invalid assignment left-hand side");
23574
3
        }
23575
265k
    }
23576
    /* remove the last opcode */
23577
265k
    fd->byte_code.size = fd->last_opcode_pos;
23578
265k
    fd->last_opcode_pos = -1;
23579
23580
265k
    if (keep) {
23581
        /* get the value but keep the object/fields on the stack */
23582
3.20k
        switch(opcode) {
23583
3.20k
        case OP_scope_get_var:
23584
3.20k
            label = new_label(s);
23585
3.20k
            emit_op(s, OP_scope_make_ref);
23586
3.20k
            emit_atom(s, name);
23587
3.20k
            emit_u32(s, label);
23588
3.20k
            emit_u16(s, scope);
23589
3.20k
            update_label(fd, label, 1);
23590
3.20k
            emit_op(s, OP_get_ref_value);
23591
3.20k
            opcode = OP_get_ref_value;
23592
3.20k
            break;
23593
1
        case OP_get_field:
23594
1
            emit_op(s, OP_get_field2);
23595
1
            emit_atom(s, name);
23596
1
            break;
23597
0
        case OP_scope_get_private_field:
23598
0
            emit_op(s, OP_scope_get_private_field2);
23599
0
            emit_atom(s, name);
23600
0
            emit_u16(s, scope);
23601
0
            break;
23602
0
        case OP_get_array_el:
23603
            /* XXX: replace by a single opcode ? */
23604
0
            emit_op(s, OP_to_propkey2);
23605
0
            emit_op(s, OP_dup2);
23606
0
            emit_op(s, OP_get_array_el);
23607
0
            break;
23608
0
        case OP_get_super_value:
23609
0
            emit_op(s, OP_to_propkey);
23610
0
            emit_op(s, OP_dup3);
23611
0
            emit_op(s, OP_get_super_value);
23612
0
            break;
23613
0
        default:
23614
0
            abort();
23615
3.20k
        }
23616
262k
    } else {
23617
262k
        switch(opcode) {
23618
261k
        case OP_scope_get_var:
23619
261k
            label = new_label(s);
23620
261k
            emit_op(s, OP_scope_make_ref);
23621
261k
            emit_atom(s, name);
23622
261k
            emit_u32(s, label);
23623
261k
            emit_u16(s, scope);
23624
261k
            update_label(fd, label, 1);
23625
261k
            opcode = OP_get_ref_value;
23626
261k
            break;
23627
3
        case OP_get_array_el:
23628
3
            emit_op(s, OP_to_propkey2);
23629
3
            break;
23630
0
        case OP_get_super_value:
23631
0
            emit_op(s, OP_to_propkey);
23632
0
            break;
23633
262k
        }
23634
262k
    }
23635
23636
265k
    *popcode = opcode;
23637
265k
    *pscope = scope;
23638
    /* name has refcount for OP_get_field and OP_get_ref_value,
23639
       and JS_ATOM_NULL for other opcodes */
23640
265k
    *pname = name;
23641
265k
    *plabel = label;
23642
265k
    if (pdepth)
23643
50.6k
        *pdepth = depth;
23644
265k
    return 0;
23645
265k
}
23646
23647
typedef enum {
23648
    PUT_LVALUE_NOKEEP, /* [depth] v -> */
23649
    PUT_LVALUE_NOKEEP_DEPTH, /* [depth] v -> , keep depth (currently
23650
                                just disable optimizations) */
23651
    PUT_LVALUE_KEEP_TOP,  /* [depth] v -> v */
23652
    PUT_LVALUE_KEEP_SECOND, /* [depth] v0 v -> v0 */
23653
    PUT_LVALUE_NOKEEP_BOTTOM, /* v [depth] -> */
23654
} PutLValueEnum;
23655
23656
/* name has a live reference. 'is_let' is only used with opcode =
23657
   OP_scope_get_var which is never generated by get_lvalue(). */
23658
static void put_lvalue(JSParseState *s, int opcode, int scope,
23659
                       JSAtom name, int label, PutLValueEnum special,
23660
                       BOOL is_let)
23661
265k
{
23662
265k
    switch(opcode) {
23663
464
    case OP_get_field:
23664
464
    case OP_scope_get_private_field:
23665
        /* depth = 1 */
23666
464
        switch(special) {
23667
0
        case PUT_LVALUE_NOKEEP:
23668
0
        case PUT_LVALUE_NOKEEP_DEPTH:
23669
0
            break;
23670
463
        case PUT_LVALUE_KEEP_TOP:
23671
463
            emit_op(s, OP_insert2); /* obj v -> v obj v */
23672
463
            break;
23673
1
        case PUT_LVALUE_KEEP_SECOND:
23674
1
            emit_op(s, OP_perm3); /* obj v0 v -> v0 obj v */
23675
1
            break;
23676
0
        case PUT_LVALUE_NOKEEP_BOTTOM:
23677
0
            emit_op(s, OP_swap);
23678
0
            break;
23679
0
        default:
23680
0
            abort();
23681
464
        }
23682
464
        break;
23683
464
    case OP_get_array_el:
23684
265k
    case OP_get_ref_value:
23685
        /* depth = 2 */
23686
265k
        if (opcode == OP_get_ref_value) {
23687
265k
            JS_FreeAtom(s->ctx, name);
23688
265k
            emit_label(s, label);
23689
265k
        }
23690
265k
        switch(special) {
23691
902
        case PUT_LVALUE_NOKEEP:
23692
902
            emit_op(s, OP_nop); /* will trigger optimization */
23693
902
            break;
23694
50.6k
        case PUT_LVALUE_NOKEEP_DEPTH:
23695
50.6k
            break;
23696
212k
        case PUT_LVALUE_KEEP_TOP:
23697
212k
            emit_op(s, OP_insert3); /* obj prop v -> v obj prop v */
23698
212k
            break;
23699
477
        case PUT_LVALUE_KEEP_SECOND:
23700
477
            emit_op(s, OP_perm4); /* obj prop v0 v -> v0 obj prop v */
23701
477
            break;
23702
202
        case PUT_LVALUE_NOKEEP_BOTTOM:
23703
202
            emit_op(s, OP_rot3l);
23704
202
            break;
23705
0
        default:
23706
0
            abort();
23707
265k
        }
23708
265k
        break;
23709
265k
    case OP_get_super_value:
23710
        /* depth = 3 */
23711
0
        switch(special) {
23712
0
        case PUT_LVALUE_NOKEEP:
23713
0
        case PUT_LVALUE_NOKEEP_DEPTH:
23714
0
            break;
23715
0
        case PUT_LVALUE_KEEP_TOP:
23716
0
            emit_op(s, OP_insert4); /* this obj prop v -> v this obj prop v */
23717
0
            break;
23718
0
        case PUT_LVALUE_KEEP_SECOND:
23719
0
            emit_op(s, OP_perm5); /* this obj prop v0 v -> v0 this obj prop v */
23720
0
            break;
23721
0
        case PUT_LVALUE_NOKEEP_BOTTOM:
23722
0
            emit_op(s, OP_rot4l);
23723
0
            break;
23724
0
        default:
23725
0
            abort();
23726
0
        }
23727
0
        break;
23728
107
    default:
23729
107
        break;
23730
265k
    }
23731
    
23732
265k
    switch(opcode) {
23733
107
    case OP_scope_get_var:  /* val -- */
23734
107
        assert(special == PUT_LVALUE_NOKEEP ||
23735
107
               special == PUT_LVALUE_NOKEEP_DEPTH);
23736
107
        emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var);
23737
107
        emit_u32(s, name);  /* has refcount */
23738
107
        emit_u16(s, scope);
23739
107
        break;
23740
464
    case OP_get_field:
23741
464
        emit_op(s, OP_put_field);
23742
464
        emit_u32(s, name);  /* name has refcount */
23743
464
        break;
23744
0
    case OP_scope_get_private_field:
23745
0
        emit_op(s, OP_scope_put_private_field);
23746
0
        emit_u32(s, name);  /* name has refcount */
23747
0
        emit_u16(s, scope);
23748
0
        break;
23749
3
    case OP_get_array_el:
23750
3
        emit_op(s, OP_put_array_el);
23751
3
        break;
23752
265k
    case OP_get_ref_value:
23753
265k
        emit_op(s, OP_put_ref_value);
23754
265k
        break;
23755
0
    case OP_get_super_value:
23756
0
        emit_op(s, OP_put_super_value);
23757
0
        break;
23758
0
    default:
23759
0
        abort();
23760
265k
    }
23761
265k
}
23762
23763
static __exception int js_parse_expr_paren(JSParseState *s)
23764
2.00k
{
23765
2.00k
    if (js_parse_expect(s, '('))
23766
0
        return -1;
23767
2.00k
    if (js_parse_expr(s))
23768
0
        return -1;
23769
2.00k
    if (js_parse_expect(s, ')'))
23770
0
        return -1;
23771
2.00k
    return 0;
23772
2.00k
}
23773
23774
static int js_unsupported_keyword(JSParseState *s, JSAtom atom)
23775
0
{
23776
0
    char buf[ATOM_GET_STR_BUF_SIZE];
23777
0
    return js_parse_error(s, "unsupported keyword: %s",
23778
0
                          JS_AtomGetStr(s->ctx, buf, sizeof(buf), atom));
23779
0
}
23780
23781
static __exception int js_define_var(JSParseState *s, JSAtom name, int tok)
23782
1.53k
{
23783
1.53k
    JSFunctionDef *fd = s->cur_func;
23784
1.53k
    JSVarDefEnum var_def_type;
23785
    
23786
1.53k
    if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
23787
0
        return js_parse_error(s, "yield is a reserved identifier");
23788
0
    }
23789
1.53k
    if ((name == JS_ATOM_arguments || name == JS_ATOM_eval)
23790
1.53k
    &&  (fd->js_mode & JS_MODE_STRICT)) {
23791
0
        return js_parse_error(s, "invalid variable name in strict mode");
23792
0
    }
23793
1.53k
    if ((name == JS_ATOM_let || name == JS_ATOM_undefined)
23794
1.53k
    &&  (tok == TOK_LET || tok == TOK_CONST)) {
23795
0
        return js_parse_error(s, "invalid lexical variable name");
23796
0
    }
23797
1.53k
    switch(tok) {
23798
175
    case TOK_LET:
23799
175
        var_def_type = JS_VAR_DEF_LET;
23800
175
        break;
23801
0
    case TOK_CONST:
23802
0
        var_def_type = JS_VAR_DEF_CONST;
23803
0
        break;
23804
1.33k
    case TOK_VAR:
23805
1.33k
        var_def_type = JS_VAR_DEF_VAR;
23806
1.33k
        break;
23807
29
    case TOK_CATCH:
23808
29
        var_def_type = JS_VAR_DEF_CATCH;
23809
29
        break;
23810
0
    default:
23811
0
        abort();
23812
1.53k
    }
23813
1.53k
    if (define_var(s, fd, name, var_def_type) < 0)
23814
0
        return -1;
23815
1.53k
    return 0;
23816
1.53k
}
23817
23818
static void js_emit_spread_code(JSParseState *s, int depth)
23819
0
{
23820
0
    int label_rest_next, label_rest_done;
23821
23822
    /* XXX: could check if enum object is an actual array and optimize
23823
       slice extraction. enumeration record and target array are in a
23824
       different order from OP_append case. */
23825
    /* enum_rec xxx -- enum_rec xxx array 0 */
23826
0
    emit_op(s, OP_array_from);
23827
0
    emit_u16(s, 0);
23828
0
    emit_op(s, OP_push_i32);
23829
0
    emit_u32(s, 0);
23830
0
    emit_label(s, label_rest_next = new_label(s));
23831
0
    emit_op(s, OP_for_of_next);
23832
0
    emit_u8(s, 2 + depth);
23833
0
    label_rest_done = emit_goto(s, OP_if_true, -1);
23834
    /* array idx val -- array idx */
23835
0
    emit_op(s, OP_define_array_el);
23836
0
    emit_op(s, OP_inc);
23837
0
    emit_goto(s, OP_goto, label_rest_next);
23838
0
    emit_label(s, label_rest_done);
23839
    /* enum_rec xxx array idx undef -- enum_rec xxx array */
23840
0
    emit_op(s, OP_drop);
23841
0
    emit_op(s, OP_drop);
23842
0
}
23843
23844
static int js_parse_check_duplicate_parameter(JSParseState *s, JSAtom name)
23845
110
{
23846
    /* Check for duplicate parameter names */
23847
110
    JSFunctionDef *fd = s->cur_func;
23848
110
    int i;
23849
220
    for (i = 0; i < fd->arg_count; i++) {
23850
110
        if (fd->args[i].var_name == name)
23851
0
            goto duplicate;
23852
110
    }
23853
212
    for (i = 0; i < fd->var_count; i++) {
23854
102
        if (fd->vars[i].var_name == name)
23855
0
            goto duplicate;
23856
102
    }
23857
110
    return 0;
23858
23859
0
duplicate:
23860
0
    return js_parse_error(s, "duplicate parameter names not allowed in this context");
23861
110
}
23862
23863
static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg)
23864
39
{
23865
39
    JSAtom name;
23866
23867
39
    if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
23868
39
    ||  ((s->cur_func->js_mode & JS_MODE_STRICT) &&
23869
39
         (s->token.u.ident.atom == JS_ATOM_eval || s->token.u.ident.atom == JS_ATOM_arguments))) {
23870
0
        js_parse_error(s, "invalid destructuring target");
23871
0
        return JS_ATOM_NULL;
23872
0
    }
23873
39
    name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
23874
39
    if (is_arg && js_parse_check_duplicate_parameter(s, name))
23875
0
        goto fail;
23876
39
    if (next_token(s))
23877
0
        goto fail;
23878
23879
39
    return name;
23880
0
fail:
23881
0
    JS_FreeAtom(s->ctx, name);
23882
0
    return JS_ATOM_NULL;
23883
39
}
23884
23885
/* Return -1 if error, 0 if no initializer, 1 if an initializer is
23886
   present at the top level. */
23887
static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
23888
                                        int hasval, int has_ellipsis,
23889
                                        BOOL allow_initializer)
23890
24.6k
{
23891
24.6k
    int label_parse, label_assign, label_done, label_lvalue, depth_lvalue;
23892
24.6k
    int start_addr, assign_addr;
23893
24.6k
    JSAtom prop_name, var_name;
23894
24.6k
    int opcode, scope, tok1, skip_bits;
23895
24.6k
    BOOL has_initializer;
23896
    
23897
24.6k
    if (has_ellipsis < 0) {
23898
        /* pre-parse destructuration target for spread detection */
23899
42
        js_parse_skip_parens_token(s, &skip_bits, FALSE);
23900
42
        has_ellipsis = skip_bits & SKIP_HAS_ELLIPSIS;
23901
42
    }
23902
23903
24.6k
    label_parse = new_label(s);
23904
24.6k
    label_assign = new_label(s);
23905
23906
24.6k
    start_addr = s->cur_func->byte_code.size;
23907
24.6k
    if (hasval) {
23908
        /* consume value from the stack */
23909
74
        emit_op(s, OP_dup);
23910
74
        emit_op(s, OP_undefined);
23911
74
        emit_op(s, OP_strict_eq);
23912
74
        emit_goto(s, OP_if_true, label_parse);
23913
74
        emit_label(s, label_assign);
23914
24.6k
    } else {
23915
24.6k
        emit_goto(s, OP_goto, label_parse);
23916
24.6k
        emit_label(s, label_assign);
23917
        /* leave value on the stack */
23918
24.6k
        emit_op(s, OP_dup);
23919
24.6k
    }
23920
24.6k
    assign_addr = s->cur_func->byte_code.size;
23921
24.6k
    if (s->token.val == '{') {
23922
6.53k
        if (next_token(s))
23923
0
            return -1;
23924
        /* throw an exception if the value cannot be converted to an object */
23925
6.53k
        emit_op(s, OP_to_object);
23926
6.53k
        if (has_ellipsis) {
23927
            /* add excludeList on stack just below src object */
23928
19
            emit_op(s, OP_object);
23929
19
            emit_op(s, OP_swap);
23930
19
        }
23931
42.7k
        while (s->token.val != '}') {
23932
42.6k
            int prop_type;
23933
42.6k
            if (s->token.val == TOK_ELLIPSIS) {
23934
19
                if (!has_ellipsis) {
23935
0
                    JS_ThrowInternalError(s->ctx, "unexpected ellipsis token");
23936
0
                    return -1;
23937
0
                }
23938
19
                if (next_token(s))
23939
0
                    return -1;
23940
19
                if (tok) {
23941
0
                    var_name = js_parse_destructuring_var(s, tok, is_arg);
23942
0
                    if (var_name == JS_ATOM_NULL)
23943
0
                        return -1;
23944
0
                    opcode = OP_scope_get_var;
23945
0
                    scope = s->cur_func->scope_level;
23946
0
                    label_lvalue = -1;
23947
0
                    depth_lvalue = 0;
23948
19
                } else {
23949
19
                    if (js_parse_left_hand_side_expr(s))
23950
0
                        return -1;
23951
23952
19
                    if (get_lvalue(s, &opcode, &scope, &var_name,
23953
19
                                   &label_lvalue, &depth_lvalue, FALSE, '{'))
23954
0
                        return -1;
23955
19
                }
23956
19
                if (s->token.val != '}') {
23957
0
                    js_parse_error(s, "assignment rest property must be last");
23958
0
                    goto var_error;
23959
0
                }
23960
19
                emit_op(s, OP_object);  /* target */
23961
19
                emit_op(s, OP_copy_data_properties);
23962
19
                emit_u8(s, 0 | ((depth_lvalue + 1) << 2) | ((depth_lvalue + 2) << 5));
23963
19
                goto set_val;
23964
19
            }
23965
42.6k
            prop_type = js_parse_property_name(s, &prop_name, FALSE, TRUE, FALSE);
23966
42.6k
            if (prop_type < 0)
23967
0
                return -1;
23968
42.6k
            var_name = JS_ATOM_NULL;
23969
42.6k
            opcode = OP_scope_get_var;
23970
42.6k
            scope = s->cur_func->scope_level;
23971
42.6k
            label_lvalue = -1;
23972
42.6k
            depth_lvalue = 0;
23973
42.6k
            if (prop_type == PROP_TYPE_IDENT) {
23974
2.27k
                if (next_token(s))
23975
0
                    goto prop_error;
23976
2.27k
                if ((s->token.val == '[' || s->token.val == '{')
23977
2.27k
                    &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
23978
0
                         tok1 == '=' || tok1 == '}')) {
23979
0
                    if (prop_name == JS_ATOM_NULL) {
23980
                        /* computed property name on stack */
23981
0
                        if (has_ellipsis) {
23982
                            /* define the property in excludeList */
23983
0
                            emit_op(s, OP_to_propkey); /* avoid calling ToString twice */
23984
0
                            emit_op(s, OP_perm3); /* TOS: src excludeList prop */
23985
0
                            emit_op(s, OP_null); /* TOS: src excludeList prop null */
23986
0
                            emit_op(s, OP_define_array_el); /* TOS: src excludeList prop */
23987
0
                            emit_op(s, OP_perm3); /* TOS: excludeList src prop */
23988
0
                        }
23989
                        /* get the computed property from the source object */
23990
0
                        emit_op(s, OP_get_array_el2);
23991
0
                    } else {
23992
                        /* named property */
23993
0
                        if (has_ellipsis) {
23994
                            /* define the property in excludeList */
23995
0
                            emit_op(s, OP_swap); /* TOS: src excludeList */
23996
0
                            emit_op(s, OP_null); /* TOS: src excludeList null */
23997
0
                            emit_op(s, OP_define_field); /* TOS: src excludeList */
23998
0
                            emit_atom(s, prop_name);
23999
0
                            emit_op(s, OP_swap); /* TOS: excludeList src */
24000
0
                        }
24001
                        /* get the named property from the source object */
24002
0
                        emit_op(s, OP_get_field2);
24003
0
                        emit_u32(s, prop_name);
24004
0
                    }
24005
0
                    if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE) < 0)
24006
0
                        return -1;
24007
0
                    if (s->token.val == '}')
24008
0
                        break;
24009
                    /* accept a trailing comma before the '}' */
24010
0
                    if (js_parse_expect(s, ','))
24011
0
                        return -1;
24012
0
                    continue;
24013
0
                }
24014
2.27k
                if (prop_name == JS_ATOM_NULL) {
24015
0
                    emit_op(s, OP_to_propkey2);
24016
0
                    if (has_ellipsis) {
24017
                        /* define the property in excludeList */
24018
0
                        emit_op(s, OP_perm3);
24019
0
                        emit_op(s, OP_null);
24020
0
                        emit_op(s, OP_define_array_el);
24021
0
                        emit_op(s, OP_perm3);
24022
0
                    }
24023
                    /* source prop -- source source prop */
24024
0
                    emit_op(s, OP_dup1);
24025
2.27k
                } else {
24026
2.27k
                    if (has_ellipsis) {
24027
                        /* define the property in excludeList */
24028
0
                        emit_op(s, OP_swap);
24029
0
                        emit_op(s, OP_null);
24030
0
                        emit_op(s, OP_define_field);
24031
0
                        emit_atom(s, prop_name);
24032
0
                        emit_op(s, OP_swap);
24033
0
                    }
24034
                    /* source -- source source */
24035
2.27k
                    emit_op(s, OP_dup);
24036
2.27k
                }
24037
2.27k
                if (tok) {
24038
38
                    var_name = js_parse_destructuring_var(s, tok, is_arg);
24039
38
                    if (var_name == JS_ATOM_NULL)
24040
0
                        goto prop_error;
24041
2.23k
                } else {
24042
2.23k
                    if (js_parse_left_hand_side_expr(s))
24043
0
                        goto prop_error;
24044
42.5k
                lvalue:
24045
42.5k
                    if (get_lvalue(s, &opcode, &scope, &var_name,
24046
42.5k
                                   &label_lvalue, &depth_lvalue, FALSE, '{'))
24047
0
                        goto prop_error;
24048
                    /* swap ref and lvalue object if any */
24049
42.5k
                    if (prop_name == JS_ATOM_NULL) {
24050
0
                        switch(depth_lvalue) {
24051
0
                        case 1:
24052
                            /* source prop x -> x source prop */
24053
0
                            emit_op(s, OP_rot3r);
24054
0
                            break;
24055
0
                        case 2:
24056
                            /* source prop x y -> x y source prop */
24057
0
                            emit_op(s, OP_swap2);   /* t p2 s p1 */
24058
0
                            break;
24059
0
                        case 3:
24060
                            /* source prop x y z -> x y z source prop */
24061
0
                            emit_op(s, OP_rot5l);
24062
0
                            emit_op(s, OP_rot5l);
24063
0
                            break;
24064
0
                        }
24065
42.5k
                    } else {
24066
42.5k
                        switch(depth_lvalue) {
24067
0
                        case 1:
24068
                            /* source x -> x source */
24069
0
                            emit_op(s, OP_swap);
24070
0
                            break;
24071
42.5k
                        case 2:
24072
                            /* source x y -> x y source */
24073
42.5k
                            emit_op(s, OP_rot3l);
24074
42.5k
                            break;
24075
0
                        case 3:
24076
                            /* source x y z -> x y z source */
24077
0
                            emit_op(s, OP_rot4l);
24078
0
                            break;
24079
42.5k
                        }
24080
42.5k
                    }
24081
42.5k
                }
24082
42.6k
                if (prop_name == JS_ATOM_NULL) {
24083
                    /* computed property name on stack */
24084
                    /* XXX: should have OP_get_array_el2x with depth */
24085
                    /* source prop -- val */
24086
0
                    emit_op(s, OP_get_array_el);
24087
42.6k
                } else {
24088
                    /* named property */
24089
                    /* XXX: should have OP_get_field2x with depth */
24090
                    /* source -- val */
24091
42.6k
                    emit_op(s, OP_get_field);
24092
42.6k
                    emit_u32(s, prop_name);
24093
42.6k
                }
24094
42.6k
            } else {
24095
                /* prop_type = PROP_TYPE_VAR, cannot be a computed property */
24096
40.4k
                if (is_arg && js_parse_check_duplicate_parameter(s, prop_name))
24097
0
                    goto prop_error;
24098
40.4k
                if ((s->cur_func->js_mode & JS_MODE_STRICT) &&
24099
40.4k
                    (prop_name == JS_ATOM_eval || prop_name == JS_ATOM_arguments)) {
24100
0
                    js_parse_error(s, "invalid destructuring target");
24101
0
                    goto prop_error;
24102
0
                }
24103
40.4k
                if (has_ellipsis) {
24104
                    /* define the property in excludeList */
24105
0
                    emit_op(s, OP_swap);
24106
0
                    emit_op(s, OP_null);
24107
0
                    emit_op(s, OP_define_field);
24108
0
                    emit_atom(s, prop_name);
24109
0
                    emit_op(s, OP_swap);
24110
0
                }
24111
40.4k
                if (!tok || tok == TOK_VAR) {
24112
                    /* generate reference */
24113
                    /* source -- source source */
24114
40.3k
                    emit_op(s, OP_dup);
24115
40.3k
                    emit_op(s, OP_scope_get_var);
24116
40.3k
                    emit_atom(s, prop_name);
24117
40.3k
                    emit_u16(s, s->cur_func->scope_level);
24118
40.3k
                    goto lvalue;
24119
40.3k
                }
24120
68
                var_name = JS_DupAtom(s->ctx, prop_name);
24121
                /* source -- source val */
24122
68
                emit_op(s, OP_get_field2);
24123
68
                emit_u32(s, prop_name);
24124
68
            }
24125
42.6k
        set_val:
24126
42.6k
            if (tok) {
24127
118
                if (js_define_var(s, var_name, tok))
24128
0
                    goto var_error;
24129
118
                scope = s->cur_func->scope_level;
24130
118
            }
24131
42.6k
            if (s->token.val == '=') {  /* handle optional default value */
24132
2.04k
                int label_hasval;
24133
2.04k
                emit_op(s, OP_dup);
24134
2.04k
                emit_op(s, OP_undefined);
24135
2.04k
                emit_op(s, OP_strict_eq);
24136
2.04k
                label_hasval = emit_goto(s, OP_if_false, -1);
24137
2.04k
                if (next_token(s))
24138
0
                    goto var_error;
24139
2.04k
                emit_op(s, OP_drop);
24140
2.04k
                if (js_parse_assign_expr(s))
24141
0
                    goto var_error;
24142
2.04k
                if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
24143
2.04k
                    set_object_name(s, var_name);
24144
2.04k
                emit_label(s, label_hasval);
24145
2.04k
            }
24146
            /* store value into lvalue object */
24147
42.6k
            put_lvalue(s, opcode, scope, var_name, label_lvalue,
24148
42.6k
                       PUT_LVALUE_NOKEEP_DEPTH,
24149
42.6k
                       (tok == TOK_CONST || tok == TOK_LET));
24150
42.6k
            if (s->token.val == '}')
24151
6.50k
                break;
24152
            /* accept a trailing comma before the '}' */
24153
36.1k
            if (js_parse_expect(s, ','))
24154
0
                return -1;
24155
36.1k
        }
24156
        /* drop the source object */
24157
6.53k
        emit_op(s, OP_drop);
24158
6.53k
        if (has_ellipsis) {
24159
19
            emit_op(s, OP_drop); /* pop excludeList */
24160
19
        }
24161
6.53k
        if (next_token(s))
24162
0
            return -1;
24163
18.1k
    } else if (s->token.val == '[') {
24164
18.1k
        BOOL has_spread;
24165
18.1k
        int enum_depth;
24166
18.1k
        BlockEnv block_env;
24167
24168
18.1k
        if (next_token(s))
24169
0
            return -1;
24170
        /* the block environment is only needed in generators in case
24171
           'yield' triggers a 'return' */
24172
18.1k
        push_break_entry(s->cur_func, &block_env,
24173
18.1k
                         JS_ATOM_NULL, -1, -1, 2);
24174
18.1k
        block_env.has_iterator = TRUE;
24175
18.1k
        emit_op(s, OP_for_of_start);
24176
18.1k
        has_spread = FALSE;
24177
18.1k
        while (s->token.val != ']') {
24178
            /* get the next value */
24179
5.69k
            if (s->token.val == TOK_ELLIPSIS) {
24180
0
                if (next_token(s))
24181
0
                    return -1;
24182
0
                if (s->token.val == ',' || s->token.val == ']')
24183
0
                    return js_parse_error(s, "missing binding pattern...");
24184
0
                has_spread = TRUE;
24185
0
            }
24186
5.69k
            if (s->token.val == ',') {
24187
                /* do nothing, skip the value, has_spread is false */
24188
0
                emit_op(s, OP_for_of_next);
24189
0
                emit_u8(s, 0);
24190
0
                emit_op(s, OP_drop);
24191
0
                emit_op(s, OP_drop);
24192
5.69k
            } else if ((s->token.val == '[' || s->token.val == '{')
24193
5.69k
                   &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
24194
29
                        tok1 == '=' || tok1 == ']')) {
24195
29
                if (has_spread) {
24196
0
                    if (tok1 == '=')
24197
0
                        return js_parse_error(s, "rest element cannot have a default value");
24198
0
                    js_emit_spread_code(s, 0);
24199
29
                } else {
24200
29
                    emit_op(s, OP_for_of_next);
24201
29
                    emit_u8(s, 0);
24202
29
                    emit_op(s, OP_drop);
24203
29
                }
24204
29
                if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
24205
0
                    return -1;
24206
5.66k
            } else {
24207
5.66k
                var_name = JS_ATOM_NULL;
24208
5.66k
                enum_depth = 0;
24209
5.66k
                if (tok) {
24210
1
                    var_name = js_parse_destructuring_var(s, tok, is_arg);
24211
1
                    if (var_name == JS_ATOM_NULL)
24212
0
                        goto var_error;
24213
1
                    if (js_define_var(s, var_name, tok))
24214
0
                        goto var_error;
24215
1
                    opcode = OP_scope_get_var;
24216
1
                    scope = s->cur_func->scope_level;
24217
5.66k
                } else {
24218
5.66k
                    if (js_parse_left_hand_side_expr(s))
24219
0
                        return -1;
24220
5.66k
                    if (get_lvalue(s, &opcode, &scope, &var_name,
24221
5.66k
                                   &label_lvalue, &enum_depth, FALSE, '[')) {
24222
0
                        return -1;
24223
0
                    }
24224
5.66k
                }
24225
5.66k
                if (has_spread) {
24226
0
                    js_emit_spread_code(s, enum_depth);
24227
5.66k
                } else {
24228
5.66k
                    emit_op(s, OP_for_of_next);
24229
5.66k
                    emit_u8(s, enum_depth);
24230
5.66k
                    emit_op(s, OP_drop);
24231
5.66k
                }
24232
5.66k
                if (s->token.val == '=' && !has_spread) {
24233
                    /* handle optional default value */
24234
0
                    int label_hasval;
24235
0
                    emit_op(s, OP_dup);
24236
0
                    emit_op(s, OP_undefined);
24237
0
                    emit_op(s, OP_strict_eq);
24238
0
                    label_hasval = emit_goto(s, OP_if_false, -1);
24239
0
                    if (next_token(s))
24240
0
                        goto var_error;
24241
0
                    emit_op(s, OP_drop);
24242
0
                    if (js_parse_assign_expr(s))
24243
0
                        goto var_error;
24244
0
                    if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
24245
0
                        set_object_name(s, var_name);
24246
0
                    emit_label(s, label_hasval);
24247
0
                }
24248
                /* store value into lvalue object */
24249
5.66k
                put_lvalue(s, opcode, scope, var_name,
24250
5.66k
                           label_lvalue, PUT_LVALUE_NOKEEP_DEPTH,
24251
5.66k
                           (tok == TOK_CONST || tok == TOK_LET));
24252
5.66k
            }
24253
5.69k
            if (s->token.val == ']')
24254
5.69k
                break;
24255
0
            if (has_spread)
24256
0
                return js_parse_error(s, "rest element must be the last one");
24257
            /* accept a trailing comma before the ']' */
24258
0
            if (js_parse_expect(s, ','))
24259
0
                return -1;
24260
0
        }
24261
        /* close iterator object:
24262
           if completed, enum_obj has been replaced by undefined */
24263
18.1k
        emit_op(s, OP_iterator_close);
24264
18.1k
        pop_break_entry(s->cur_func);
24265
18.1k
        if (next_token(s))
24266
0
            return -1;
24267
18.1k
    } else {
24268
0
        return js_parse_error(s, "invalid assignment syntax");
24269
0
    }
24270
24.6k
    if (s->token.val == '=' && allow_initializer) {
24271
24.6k
        label_done = emit_goto(s, OP_goto, -1);
24272
24.6k
        if (next_token(s))
24273
0
            return -1;
24274
24.6k
        emit_label(s, label_parse);
24275
24.6k
        if (hasval)
24276
36
            emit_op(s, OP_drop);
24277
24.6k
        if (js_parse_assign_expr(s))
24278
0
            return -1;
24279
24.6k
        emit_goto(s, OP_goto, label_assign);
24280
24.6k
        emit_label(s, label_done);
24281
24.6k
        has_initializer = TRUE;
24282
24.6k
    } else {
24283
        /* normally hasval is true except if
24284
           js_parse_skip_parens_token() was wrong in the parsing */
24285
        //        assert(hasval);
24286
38
        if (!hasval) {
24287
0
            js_parse_error(s, "too complicated destructuring expression");
24288
0
            return -1;
24289
0
        }
24290
        /* remove test and decrement label ref count */
24291
38
        memset(s->cur_func->byte_code.buf + start_addr, OP_nop,
24292
38
               assign_addr - start_addr);
24293
38
        s->cur_func->label_slots[label_parse].ref_count--;
24294
38
        has_initializer = FALSE;
24295
38
    }
24296
24.6k
    return has_initializer;
24297
24298
0
 prop_error:
24299
0
    JS_FreeAtom(s->ctx, prop_name);
24300
0
 var_error:
24301
0
    JS_FreeAtom(s->ctx, var_name);
24302
0
    return -1;
24303
0
}
24304
24305
typedef enum FuncCallType {
24306
    FUNC_CALL_NORMAL,
24307
    FUNC_CALL_NEW,
24308
    FUNC_CALL_SUPER_CTOR,
24309
    FUNC_CALL_TEMPLATE,
24310
} FuncCallType;
24311
24312
static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
24313
                                int drop_count)
24314
2
{
24315
2
    int label_next, i;
24316
2
    if (*poptional_chaining_label < 0)
24317
2
        *poptional_chaining_label = new_label(s);
24318
   /* XXX: could be more efficient with a specific opcode */
24319
2
    emit_op(s, OP_dup);
24320
2
    emit_op(s, OP_is_undefined_or_null);
24321
2
    label_next = emit_goto(s, OP_if_false, -1);
24322
4
    for(i = 0; i < drop_count; i++)
24323
2
        emit_op(s, OP_drop);
24324
2
    emit_op(s, OP_undefined);
24325
2
    emit_goto(s, OP_goto, *poptional_chaining_label);
24326
2
    emit_label(s, label_next);
24327
2
}
24328
24329
/* allowed parse_flags: PF_POSTFIX_CALL, PF_ARROW_FUNC */
24330
static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
24331
575k
{
24332
575k
    FuncCallType call_type;
24333
575k
    int optional_chaining_label;
24334
575k
    BOOL accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0;
24335
    
24336
575k
    call_type = FUNC_CALL_NORMAL;
24337
575k
    switch(s->token.val) {
24338
3.58k
    case TOK_NUMBER:
24339
3.58k
        {
24340
3.58k
            JSValue val;
24341
3.58k
            val = s->token.u.num.val;
24342
24343
3.58k
            if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
24344
2.73k
                emit_op(s, OP_push_i32);
24345
2.73k
                emit_u32(s, JS_VALUE_GET_INT(val));
24346
2.73k
            } else
24347
856
#ifdef CONFIG_BIGNUM
24348
856
            if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
24349
0
                slimb_t e;
24350
0
                int ret;
24351
24352
                /* need a runtime conversion */
24353
                /* XXX: could add a cache and/or do it once at
24354
                   the start of the function */
24355
0
                if (emit_push_const(s, val, 0) < 0)
24356
0
                    return -1;
24357
0
                e = s->token.u.num.exponent;
24358
0
                if (e == (int32_t)e) {
24359
0
                    emit_op(s, OP_push_i32);
24360
0
                    emit_u32(s, e);
24361
0
                } else {
24362
0
                    val = JS_NewBigInt64_1(s->ctx, e);
24363
0
                    if (JS_IsException(val))
24364
0
                        return -1;
24365
0
                    ret = emit_push_const(s, val, 0);
24366
0
                    JS_FreeValue(s->ctx, val);
24367
0
                    if (ret < 0)
24368
0
                        return -1;
24369
0
                }
24370
0
                emit_op(s, OP_mul_pow10);
24371
0
            } else
24372
856
#endif
24373
856
            {
24374
856
                if (emit_push_const(s, val, 0) < 0)
24375
0
                    return -1;
24376
856
            }
24377
3.58k
        }
24378
3.58k
        if (next_token(s))
24379
0
            return -1;
24380
3.58k
        break;
24381
3.58k
    case TOK_TEMPLATE:
24382
170
        if (js_parse_template(s, 0, NULL))
24383
0
            return -1;
24384
170
        break;
24385
2.03k
    case TOK_STRING:
24386
2.03k
        if (emit_push_const(s, s->token.u.str.str, 1))
24387
0
            return -1;
24388
2.03k
        if (next_token(s))
24389
0
            return -1;
24390
2.03k
        break;
24391
        
24392
2.03k
    case TOK_DIV_ASSIGN:
24393
0
        s->buf_ptr -= 2;
24394
0
        goto parse_regexp;
24395
67
    case '/':
24396
67
        s->buf_ptr--;
24397
67
    parse_regexp:
24398
67
        {
24399
67
            JSValue str;
24400
67
            int ret, backtrace_flags;
24401
67
            if (!s->ctx->compile_regexp)
24402
0
                return js_parse_error(s, "RegExp are not supported");
24403
            /* the previous token is '/' or '/=', so no need to free */
24404
67
            if (js_parse_regexp(s))
24405
0
                return -1;
24406
67
            ret = emit_push_const(s, s->token.u.regexp.body, 0);
24407
67
            str = s->ctx->compile_regexp(s->ctx, s->token.u.regexp.body,
24408
67
                                         s->token.u.regexp.flags);
24409
67
            if (JS_IsException(str)) {
24410
                /* add the line number info */
24411
0
                backtrace_flags = 0;
24412
0
                if (s->cur_func && s->cur_func->backtrace_barrier)
24413
0
                    backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
24414
0
                build_backtrace(s->ctx, s->ctx->rt->current_exception,
24415
0
                                s->filename, s->token.line_num,
24416
0
                                backtrace_flags);
24417
0
                return -1;
24418
0
            }
24419
67
            ret = emit_push_const(s, str, 0);
24420
67
            JS_FreeValue(s->ctx, str);
24421
67
            if (ret)
24422
0
                return -1;
24423
            /* we use a specific opcode to be sure the correct
24424
               function is called (otherwise the bytecode would have
24425
               to be verified by the RegExp constructor) */
24426
67
            emit_op(s, OP_regexp);
24427
67
            if (next_token(s))
24428
0
                return -1;
24429
67
        }
24430
67
        break;
24431
431
    case '(':
24432
431
        if ((parse_flags & PF_ARROW_FUNC) &&
24433
431
            js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
24434
218
            if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
24435
218
                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
24436
218
                                       s->token.ptr, s->token.line_num))
24437
0
                return -1;
24438
218
        } else {
24439
213
            if (js_parse_expr_paren(s))
24440
0
                return -1;
24441
213
        }
24442
431
        break;
24443
431
    case TOK_FUNCTION:
24444
13
        if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
24445
13
                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
24446
13
                                   s->token.ptr, s->token.line_num))
24447
4
            return -1;
24448
9
        break;
24449
83
    case TOK_CLASS:
24450
83
        if (js_parse_class(s, TRUE, JS_PARSE_EXPORT_NONE))
24451
0
            return -1;
24452
83
        break;
24453
83
    case TOK_NULL:
24454
5
        if (next_token(s))
24455
0
            return -1;
24456
5
        emit_op(s, OP_null);
24457
5
        break;
24458
10
    case TOK_THIS:
24459
10
        if (next_token(s))
24460
0
            return -1;
24461
10
        emit_op(s, OP_scope_get_var);
24462
10
        emit_atom(s, JS_ATOM_this);
24463
10
        emit_u16(s, 0);
24464
10
        break;
24465
0
    case TOK_FALSE:
24466
0
        if (next_token(s))
24467
0
            return -1;
24468
0
        emit_op(s, OP_push_false);
24469
0
        break;
24470
0
    case TOK_TRUE:
24471
0
        if (next_token(s))
24472
0
            return -1;
24473
0
        emit_op(s, OP_push_true);
24474
0
        break;
24475
542k
    case TOK_IDENT:
24476
542k
        {
24477
542k
            JSAtom name;
24478
542k
            if (s->token.u.ident.is_reserved) {
24479
0
                return js_parse_error_reserved_identifier(s);
24480
0
            }
24481
542k
            if ((parse_flags & PF_ARROW_FUNC) &&
24482
542k
                peek_token(s, TRUE) == TOK_ARROW) {
24483
349
                if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
24484
349
                                           JS_FUNC_NORMAL, JS_ATOM_NULL,
24485
349
                                           s->token.ptr, s->token.line_num))
24486
2
                    return -1;
24487
542k
            } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
24488
542k
                       peek_token(s, TRUE) != '\n') {
24489
4
                const uint8_t *source_ptr;
24490
4
                int source_line_num;
24491
24492
4
                source_ptr = s->token.ptr;
24493
4
                source_line_num = s->token.line_num;
24494
4
                if (next_token(s))
24495
0
                    return -1;
24496
4
                if (s->token.val == TOK_FUNCTION) {
24497
0
                    if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
24498
0
                                               JS_FUNC_ASYNC, JS_ATOM_NULL,
24499
0
                                               source_ptr, source_line_num))
24500
0
                        return -1;
24501
4
                } else if ((parse_flags & PF_ARROW_FUNC) &&
24502
4
                           ((s->token.val == '(' &&
24503
4
                             js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||
24504
4
                            (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
24505
4
                             peek_token(s, TRUE) == TOK_ARROW))) {
24506
4
                    if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
24507
4
                                               JS_FUNC_ASYNC, JS_ATOM_NULL,
24508
4
                                               source_ptr, source_line_num))
24509
0
                        return -1;
24510
4
                } else {
24511
0
                    name = JS_DupAtom(s->ctx, JS_ATOM_async);
24512
0
                    goto do_get_var;
24513
0
                }
24514
542k
            } else {
24515
542k
                if (s->token.u.ident.atom == JS_ATOM_arguments &&
24516
542k
                    !s->cur_func->arguments_allowed) {
24517
0
                    js_parse_error(s, "'arguments' identifier is not allowed in class field initializer");
24518
0
                    return -1;
24519
0
                }
24520
542k
                name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
24521
542k
                if (next_token(s))  /* update line number before emitting code */
24522
2
                    return -1;
24523
542k
            do_get_var:
24524
542k
                emit_op(s, OP_scope_get_var);
24525
542k
                emit_u32(s, name);
24526
542k
                emit_u16(s, s->cur_func->scope_level);
24527
542k
            }
24528
542k
        }
24529
542k
        break;
24530
542k
    case '{':
24531
26.8k
    case '[':
24532
26.8k
        {
24533
26.8k
            int skip_bits;
24534
26.8k
            if (js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
24535
24.6k
                if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
24536
0
                    return -1;
24537
24.6k
            } else {
24538
2.22k
                if (s->token.val == '{') {
24539
937
                    if (js_parse_object_literal(s))
24540
0
                        return -1;
24541
1.29k
                } else {
24542
1.29k
                    if (js_parse_array_literal(s))
24543
0
                        return -1;
24544
1.29k
                }
24545
2.22k
            }
24546
26.8k
        }
24547
26.8k
        break;
24548
26.8k
    case TOK_NEW:
24549
14
        if (next_token(s))
24550
0
            return -1;
24551
14
        if (s->token.val == '.') {
24552
0
            if (next_token(s))
24553
0
                return -1;
24554
0
            if (!token_is_pseudo_keyword(s, JS_ATOM_target))
24555
0
                return js_parse_error(s, "expecting target");
24556
0
            if (!s->cur_func->new_target_allowed)
24557
0
                return js_parse_error(s, "new.target only allowed within functions");
24558
0
            if (next_token(s))
24559
0
                return -1;
24560
0
            emit_op(s, OP_scope_get_var);
24561
0
            emit_atom(s, JS_ATOM_new_target);
24562
0
            emit_u16(s, 0);
24563
14
        } else {
24564
14
            if (js_parse_postfix_expr(s, 0))
24565
0
                return -1;
24566
14
            accept_lparen = TRUE;
24567
14
            if (s->token.val != '(') {
24568
                /* new operator on an object */
24569
2
                emit_op(s, OP_dup);
24570
2
                emit_op(s, OP_call_constructor);
24571
2
                emit_u16(s, 0);
24572
12
            } else {
24573
12
                call_type = FUNC_CALL_NEW;
24574
12
            }
24575
14
        }
24576
14
        break;
24577
14
    case TOK_SUPER:
24578
0
        if (next_token(s))
24579
0
            return -1;
24580
0
        if (s->token.val == '(') {
24581
0
            if (!s->cur_func->super_call_allowed)
24582
0
                return js_parse_error(s, "super() is only valid in a derived class constructor");
24583
0
            call_type = FUNC_CALL_SUPER_CTOR;
24584
0
        } else if (s->token.val == '.' || s->token.val == '[') {
24585
0
            if (!s->cur_func->super_allowed)
24586
0
                return js_parse_error(s, "'super' is only valid in a method");
24587
0
            emit_op(s, OP_scope_get_var);
24588
0
            emit_atom(s, JS_ATOM_this);
24589
0
            emit_u16(s, 0);
24590
0
            emit_op(s, OP_scope_get_var);
24591
0
            emit_atom(s, JS_ATOM_home_object);
24592
0
            emit_u16(s, 0);
24593
0
            emit_op(s, OP_get_super);
24594
0
        } else {
24595
0
            return js_parse_error(s, "invalid use of 'super'");
24596
0
        }
24597
0
        break;
24598
31
    case TOK_IMPORT:
24599
31
        if (next_token(s))
24600
0
            return -1;
24601
31
        if (s->token.val == '.') {
24602
0
            if (next_token(s))
24603
0
                return -1;
24604
0
            if (!token_is_pseudo_keyword(s, JS_ATOM_meta))
24605
0
                return js_parse_error(s, "meta expected");
24606
0
            if (!s->is_module)
24607
0
                return js_parse_error(s, "import.meta only valid in module code");
24608
0
            if (next_token(s))
24609
0
                return -1;
24610
0
            emit_op(s, OP_special_object);
24611
0
            emit_u8(s, OP_SPECIAL_OBJECT_IMPORT_META);
24612
31
        } else {
24613
31
            if (js_parse_expect(s, '('))
24614
0
                return -1;
24615
31
            if (!accept_lparen)
24616
0
                return js_parse_error(s, "invalid use of 'import()'");
24617
31
            if (js_parse_assign_expr(s))
24618
0
                return -1;
24619
31
            if (js_parse_expect(s, ')'))
24620
0
                return -1;
24621
31
            emit_op(s, OP_import);
24622
31
        }
24623
31
        break;
24624
31
    default:
24625
8
        return js_parse_error(s, "unexpected token in expression: '%.*s'",
24626
8
                              (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
24627
575k
    }
24628
24629
575k
    optional_chaining_label = -1;
24630
590k
    for(;;) {
24631
590k
        JSFunctionDef *fd = s->cur_func;
24632
590k
        BOOL has_optional_chain = FALSE;
24633
        
24634
590k
        if (s->token.val == TOK_QUESTION_MARK_DOT) {
24635
            /* optional chaining */
24636
2
            if (next_token(s))
24637
0
                return -1;
24638
2
            has_optional_chain = TRUE;
24639
2
            if (s->token.val == '(' && accept_lparen) {
24640
2
                goto parse_func_call;
24641
2
            } else if (s->token.val == '[') {
24642
0
                goto parse_array_access;
24643
0
            } else {
24644
0
                goto parse_property;
24645
0
            }
24646
590k
        } else if (s->token.val == TOK_TEMPLATE &&
24647
590k
                   call_type == FUNC_CALL_NORMAL) {
24648
303
            if (optional_chaining_label >= 0) {
24649
0
                return js_parse_error(s, "template literal cannot appear in an optional chain");
24650
0
            }
24651
303
            call_type = FUNC_CALL_TEMPLATE;
24652
303
            goto parse_func_call2;
24653
590k
        } else if (s->token.val == '(' && accept_lparen) {
24654
9.42k
            int opcode, arg_count, drop_count;
24655
24656
            /* function call */
24657
9.42k
        parse_func_call:
24658
9.42k
            if (next_token(s))
24659
0
                return -1;
24660
24661
9.42k
            if (call_type == FUNC_CALL_NORMAL) {
24662
9.71k
            parse_func_call2:
24663
9.71k
                switch(opcode = get_prev_opcode(fd)) {
24664
75
                case OP_get_field:
24665
                    /* keep the object on the stack */
24666
75
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
24667
75
                    drop_count = 2;
24668
75
                    break;
24669
0
                case OP_scope_get_private_field:
24670
                    /* keep the object on the stack */
24671
0
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2;
24672
0
                    drop_count = 2;
24673
0
                    break;
24674
0
                case OP_get_array_el:
24675
                    /* keep the object on the stack */
24676
0
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
24677
0
                    drop_count = 2;
24678
0
                    break;
24679
9.62k
                case OP_scope_get_var:
24680
9.62k
                    {
24681
9.62k
                        JSAtom name;
24682
9.62k
                        int scope;
24683
9.62k
                        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
24684
9.62k
                        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
24685
9.62k
                        if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL && !has_optional_chain) {
24686
                            /* direct 'eval' */
24687
23
                            opcode = OP_eval;
24688
9.59k
                        } else {
24689
                            /* verify if function name resolves to a simple
24690
                               get_loc/get_arg: a function call inside a `with`
24691
                               statement can resolve to a method call of the
24692
                               `with` context object
24693
                             */
24694
                            /* XXX: always generate the OP_scope_get_ref
24695
                               and remove it in variable resolution
24696
                               pass ? */
24697
9.59k
                            if (has_with_scope(fd, scope)) {
24698
526
                                opcode = OP_scope_get_ref;
24699
526
                                fd->byte_code.buf[fd->last_opcode_pos] = opcode;
24700
526
                            }
24701
9.59k
                        }
24702
9.62k
                        drop_count = 1;
24703
9.62k
                    }
24704
9.62k
                    break;
24705
0
                case OP_get_super_value:
24706
0
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el;
24707
                    /* on stack: this func_obj */
24708
0
                    opcode = OP_get_array_el;
24709
0
                    drop_count = 2;
24710
0
                    break;
24711
20
                default:
24712
20
                    opcode = OP_invalid;
24713
20
                    drop_count = 1;
24714
20
                    break;
24715
9.71k
                }
24716
9.71k
                if (has_optional_chain) {
24717
2
                    optional_chain_test(s, &optional_chaining_label,
24718
2
                                        drop_count);
24719
2
                }
24720
9.71k
            } else {
24721
12
                opcode = OP_invalid;
24722
12
            }
24723
24724
9.72k
            if (call_type == FUNC_CALL_TEMPLATE) {
24725
303
                if (js_parse_template(s, 1, &arg_count))
24726
0
                    return -1;
24727
303
                goto emit_func_call;
24728
9.42k
            } else if (call_type == FUNC_CALL_SUPER_CTOR) {
24729
0
                emit_op(s, OP_scope_get_var);
24730
0
                emit_atom(s, JS_ATOM_this_active_func);
24731
0
                emit_u16(s, 0);
24732
24733
0
                emit_op(s, OP_get_super);
24734
24735
0
                emit_op(s, OP_scope_get_var);
24736
0
                emit_atom(s, JS_ATOM_new_target);
24737
0
                emit_u16(s, 0);
24738
9.42k
            } else if (call_type == FUNC_CALL_NEW) {
24739
12
                emit_op(s, OP_dup); /* new.target = function */
24740
12
            }
24741
24742
            /* parse arguments */
24743
9.42k
            arg_count = 0;
24744
9.42k
            while (s->token.val != ')') {
24745
927
                if (arg_count >= 65535) {
24746
0
                    return js_parse_error(s, "Too many call arguments");
24747
0
                }
24748
927
                if (s->token.val == TOK_ELLIPSIS)
24749
3
                    break;
24750
924
                if (js_parse_assign_expr(s))
24751
1
                    return -1;
24752
923
                arg_count++;
24753
923
                if (s->token.val == ')')
24754
919
                    break;
24755
                /* accept a trailing comma before the ')' */
24756
4
                if (js_parse_expect(s, ','))
24757
0
                    return -1;
24758
4
            }
24759
9.42k
            if (s->token.val == TOK_ELLIPSIS) {
24760
3
                emit_op(s, OP_array_from);
24761
3
                emit_u16(s, arg_count);
24762
3
                emit_op(s, OP_push_i32);
24763
3
                emit_u32(s, arg_count);
24764
24765
                /* on stack: array idx */
24766
5
                while (s->token.val != ')') {
24767
3
                    if (s->token.val == TOK_ELLIPSIS) {
24768
3
                        if (next_token(s))
24769
0
                            return -1;
24770
3
                        if (js_parse_assign_expr(s))
24771
0
                            return -1;
24772
3
#if 1
24773
                        /* XXX: could pass is_last indicator? */
24774
3
                        emit_op(s, OP_append);
24775
#else
24776
                        int label_next, label_done;
24777
                        label_next = new_label(s);
24778
                        label_done = new_label(s);
24779
                        /* push enumerate object below array/idx pair */
24780
                        emit_op(s, OP_for_of_start);
24781
                        emit_op(s, OP_rot5l);
24782
                        emit_op(s, OP_rot5l);
24783
                        emit_label(s, label_next);
24784
                        /* on stack: enum_rec array idx */
24785
                        emit_op(s, OP_for_of_next);
24786
                        emit_u8(s, 2);
24787
                        emit_goto(s, OP_if_true, label_done);
24788
                        /* append element */
24789
                        /* enum_rec array idx val -> enum_rec array new_idx */
24790
                        emit_op(s, OP_define_array_el);
24791
                        emit_op(s, OP_inc);
24792
                        emit_goto(s, OP_goto, label_next);
24793
                        emit_label(s, label_done);
24794
                        /* close enumeration, drop enum_rec and idx */
24795
                        emit_op(s, OP_drop); /* drop undef */
24796
                        emit_op(s, OP_nip1); /* drop enum_rec */
24797
                        emit_op(s, OP_nip1);
24798
                        emit_op(s, OP_nip1);
24799
#endif
24800
3
                    } else {
24801
0
                        if (js_parse_assign_expr(s))
24802
0
                            return -1;
24803
                        /* array idx val */
24804
0
                        emit_op(s, OP_define_array_el);
24805
0
                        emit_op(s, OP_inc);
24806
0
                    }
24807
3
                    if (s->token.val == ')')
24808
1
                        break;
24809
                    /* accept a trailing comma before the ')' */
24810
2
                    if (js_parse_expect(s, ','))
24811
0
                        return -1;
24812
2
                }
24813
3
                if (next_token(s))
24814
0
                    return -1;
24815
                /* drop the index */
24816
3
                emit_op(s, OP_drop);
24817
24818
                /* apply function call */
24819
3
                switch(opcode) {
24820
0
                case OP_get_field:
24821
0
                case OP_scope_get_private_field:
24822
0
                case OP_get_array_el:
24823
0
                case OP_scope_get_ref:
24824
                    /* obj func array -> func obj array */
24825
0
                    emit_op(s, OP_perm3);
24826
0
                    emit_op(s, OP_apply);
24827
0
                    emit_u16(s, call_type == FUNC_CALL_NEW);
24828
0
                    break;
24829
2
                case OP_eval:
24830
2
                    emit_op(s, OP_apply_eval);
24831
2
                    emit_u16(s, fd->scope_level);
24832
2
                    fd->has_eval_call = TRUE;
24833
2
                    break;
24834
1
                default:
24835
1
                    if (call_type == FUNC_CALL_SUPER_CTOR) {
24836
0
                        emit_op(s, OP_apply);
24837
0
                        emit_u16(s, 1);
24838
                        /* set the 'this' value */
24839
0
                        emit_op(s, OP_dup);
24840
0
                        emit_op(s, OP_scope_put_var_init);
24841
0
                        emit_atom(s, JS_ATOM_this);
24842
0
                        emit_u16(s, 0);
24843
24844
0
                        emit_class_field_init(s);
24845
1
                    } else if (call_type == FUNC_CALL_NEW) {
24846
                        /* obj func array -> func obj array */
24847
0
                        emit_op(s, OP_perm3);
24848
0
                        emit_op(s, OP_apply);
24849
0
                        emit_u16(s, 1);
24850
1
                    } else {
24851
                        /* func array -> func undef array */
24852
1
                        emit_op(s, OP_undefined);
24853
1
                        emit_op(s, OP_swap);
24854
1
                        emit_op(s, OP_apply);
24855
1
                        emit_u16(s, 0);
24856
1
                    }
24857
1
                    break;
24858
3
                }
24859
9.42k
            } else {
24860
9.42k
                if (next_token(s))
24861
0
                    return -1;
24862
9.72k
            emit_func_call:
24863
9.72k
                switch(opcode) {
24864
75
                case OP_get_field:
24865
75
                case OP_scope_get_private_field:
24866
75
                case OP_get_array_el:
24867
601
                case OP_scope_get_ref:
24868
601
                    emit_op(s, OP_call_method);
24869
601
                    emit_u16(s, arg_count);
24870
601
                    break;
24871
21
                case OP_eval:
24872
21
                    emit_op(s, OP_eval);
24873
21
                    emit_u16(s, arg_count);
24874
21
                    emit_u16(s, fd->scope_level);
24875
21
                    fd->has_eval_call = TRUE;
24876
21
                    break;
24877
9.10k
                default:
24878
9.10k
                    if (call_type == FUNC_CALL_SUPER_CTOR) {
24879
0
                        emit_op(s, OP_call_constructor);
24880
0
                        emit_u16(s, arg_count);
24881
24882
                        /* set the 'this' value */
24883
0
                        emit_op(s, OP_dup);
24884
0
                        emit_op(s, OP_scope_put_var_init);
24885
0
                        emit_atom(s, JS_ATOM_this);
24886
0
                        emit_u16(s, 0);
24887
24888
0
                        emit_class_field_init(s);
24889
9.10k
                    } else if (call_type == FUNC_CALL_NEW) {
24890
12
                        emit_op(s, OP_call_constructor);
24891
12
                        emit_u16(s, arg_count);
24892
9.09k
                    } else {
24893
9.09k
                        emit_op(s, OP_call);
24894
9.09k
                        emit_u16(s, arg_count);
24895
9.09k
                    }
24896
9.10k
                    break;
24897
9.72k
                }
24898
9.72k
            }
24899
9.72k
            call_type = FUNC_CALL_NORMAL;
24900
580k
        } else if (s->token.val == '.') {
24901
4.83k
            if (next_token(s))
24902
0
                return -1;
24903
4.83k
        parse_property:
24904
4.83k
            if (s->token.val == TOK_PRIVATE_NAME) {
24905
                /* private class field */
24906
0
                if (get_prev_opcode(fd) == OP_get_super) {
24907
0
                    return js_parse_error(s, "private class field forbidden after super");
24908
0
                }
24909
0
                if (has_optional_chain) {
24910
0
                    optional_chain_test(s, &optional_chaining_label, 1);
24911
0
                }
24912
0
                emit_op(s, OP_scope_get_private_field);
24913
0
                emit_atom(s, s->token.u.ident.atom);
24914
0
                emit_u16(s, s->cur_func->scope_level);
24915
4.83k
            } else {
24916
4.83k
                if (!token_is_ident(s->token.val)) {
24917
0
                    return js_parse_error(s, "expecting field name");
24918
0
                }
24919
4.83k
                if (get_prev_opcode(fd) == OP_get_super) {
24920
0
                    JSValue val;
24921
0
                    int ret;
24922
0
                    val = JS_AtomToValue(s->ctx, s->token.u.ident.atom);
24923
0
                    ret = emit_push_const(s, val, 1);
24924
0
                    JS_FreeValue(s->ctx, val);
24925
0
                    if (ret)
24926
0
                        return -1;
24927
0
                    emit_op(s, OP_get_super_value);
24928
4.83k
                } else {
24929
4.83k
                    if (has_optional_chain) {
24930
0
                        optional_chain_test(s, &optional_chaining_label, 1);
24931
0
                    }
24932
4.83k
                    emit_op(s, OP_get_field);
24933
4.83k
                    emit_atom(s, s->token.u.ident.atom);
24934
4.83k
                }
24935
4.83k
            }
24936
4.83k
            if (next_token(s))
24937
0
                return -1;
24938
575k
        } else if (s->token.val == '[') {
24939
100
            int prev_op;
24940
24941
100
        parse_array_access:
24942
100
            prev_op = get_prev_opcode(fd);
24943
100
            if (has_optional_chain) {
24944
0
                optional_chain_test(s, &optional_chaining_label, 1);
24945
0
            }
24946
100
            if (next_token(s))
24947
1
                return -1;
24948
99
            if (js_parse_expr(s))
24949
0
                return -1;
24950
99
            if (js_parse_expect(s, ']'))
24951
0
                return -1;
24952
99
            if (prev_op == OP_get_super) {
24953
0
                emit_op(s, OP_get_super_value);
24954
99
            } else {
24955
99
                emit_op(s, OP_get_array_el);
24956
99
            }
24957
575k
        } else {
24958
575k
            break;
24959
575k
        }
24960
590k
    }
24961
575k
    if (optional_chaining_label >= 0)
24962
2
        emit_label(s, optional_chaining_label);
24963
575k
    return 0;
24964
575k
}
24965
24966
static __exception int js_parse_delete(JSParseState *s)
24967
4
{
24968
4
    JSFunctionDef *fd = s->cur_func;
24969
4
    JSAtom name;
24970
4
    int opcode;
24971
24972
4
    if (next_token(s))
24973
0
        return -1;
24974
4
    if (js_parse_unary(s, PF_POW_FORBIDDEN))
24975
0
        return -1;
24976
4
    switch(opcode = get_prev_opcode(fd)) {
24977
0
    case OP_get_field:
24978
0
        {
24979
0
            JSValue val;
24980
0
            int ret;
24981
24982
0
            name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
24983
0
            fd->byte_code.size = fd->last_opcode_pos;
24984
0
            fd->last_opcode_pos = -1;
24985
0
            val = JS_AtomToValue(s->ctx, name);
24986
0
            ret = emit_push_const(s, val, 1);
24987
0
            JS_FreeValue(s->ctx, val);
24988
0
            JS_FreeAtom(s->ctx, name);
24989
0
            if (ret)
24990
0
                return ret;
24991
0
        }
24992
0
        goto do_delete;
24993
2
    case OP_get_array_el:
24994
2
        fd->byte_code.size = fd->last_opcode_pos;
24995
2
        fd->last_opcode_pos = -1;
24996
2
    do_delete:
24997
2
        emit_op(s, OP_delete);
24998
2
        break;
24999
0
    case OP_scope_get_var:
25000
        /* 'delete this': this is not a reference */
25001
0
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
25002
0
        if (name == JS_ATOM_this || name == JS_ATOM_new_target)
25003
0
            goto ret_true;
25004
0
        if (fd->js_mode & JS_MODE_STRICT) {
25005
0
            return js_parse_error(s, "cannot delete a direct reference in strict mode");
25006
0
        } else {
25007
0
            fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_delete_var;
25008
0
        }
25009
0
        break;
25010
0
    case OP_scope_get_private_field:
25011
0
        return js_parse_error(s, "cannot delete a private class field");
25012
0
    case OP_get_super_value:
25013
0
        emit_op(s, OP_throw_error);
25014
0
        emit_atom(s, JS_ATOM_NULL);
25015
0
        emit_u8(s, JS_THROW_ERROR_DELETE_SUPER);
25016
0
        break;
25017
2
    default:
25018
2
    ret_true:
25019
2
        emit_op(s, OP_drop);
25020
2
        emit_op(s, OP_push_true);
25021
2
        break;
25022
4
    }
25023
4
    return 0;
25024
4
}
25025
25026
/* allowed parse_flags: PF_ARROW_FUNC, PF_POW_ALLOWED, PF_POW_FORBIDDEN */
25027
static __exception int js_parse_unary(JSParseState *s, int parse_flags)
25028
571k
{
25029
571k
    int op;
25030
25031
571k
    switch(s->token.val) {
25032
662
    case '+':
25033
807
    case '-':
25034
1.58k
    case '!':
25035
2.59k
    case '~':
25036
3.21k
    case TOK_VOID:
25037
3.21k
        op = s->token.val;
25038
3.21k
        if (next_token(s))
25039
1
            return -1;
25040
3.21k
        if (js_parse_unary(s, PF_POW_FORBIDDEN))
25041
1
            return -1;
25042
3.21k
        switch(op) {
25043
143
        case '-':
25044
143
            emit_op(s, OP_neg);
25045
143
            break;
25046
662
        case '+':
25047
662
            emit_op(s, OP_plus);
25048
662
            break;
25049
782
        case '!':
25050
782
            emit_op(s, OP_lnot);
25051
782
            break;
25052
1.01k
        case '~':
25053
1.01k
            emit_op(s, OP_not);
25054
1.01k
            break;
25055
616
        case TOK_VOID:
25056
616
            emit_op(s, OP_drop);
25057
616
            emit_op(s, OP_undefined);
25058
616
            break;
25059
0
        default:
25060
0
            abort();
25061
3.21k
        }
25062
3.21k
        parse_flags = 0;
25063
3.21k
        break;
25064
0
    case TOK_DEC:
25065
13
    case TOK_INC:
25066
13
        {
25067
13
            int opcode, op, scope, label;
25068
13
            JSAtom name;
25069
13
            op = s->token.val;
25070
13
            if (next_token(s))
25071
0
                return -1;
25072
13
            if (js_parse_unary(s, 0))
25073
0
                return -1;
25074
13
            if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
25075
0
                return -1;
25076
13
            emit_op(s, OP_dec + op - TOK_DEC);
25077
13
            put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP,
25078
13
                       FALSE);
25079
13
        }
25080
0
        break;
25081
11
    case TOK_TYPEOF:
25082
11
        {
25083
11
            JSFunctionDef *fd;
25084
11
            if (next_token(s))
25085
0
                return -1;
25086
11
            if (js_parse_unary(s, PF_POW_FORBIDDEN))
25087
0
                return -1;
25088
            /* reference access should not return an exception, so we
25089
               patch the get_var */
25090
11
            fd = s->cur_func;
25091
11
            if (get_prev_opcode(fd) == OP_scope_get_var) {
25092
3
                fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef;
25093
3
            }
25094
11
            emit_op(s, OP_typeof);
25095
11
            parse_flags = 0;
25096
11
        }
25097
0
        break;
25098
4
    case TOK_DELETE:
25099
4
        if (js_parse_delete(s))
25100
0
            return -1;
25101
4
        parse_flags = 0;
25102
4
        break;
25103
0
    case TOK_AWAIT:
25104
0
        if (!(s->cur_func->func_kind & JS_FUNC_ASYNC))
25105
0
            return js_parse_error(s, "unexpected 'await' keyword");
25106
0
        if (!s->cur_func->in_function_body)
25107
0
            return js_parse_error(s, "await in default expression");
25108
0
        if (next_token(s))
25109
0
            return -1;
25110
0
        if (js_parse_unary(s, PF_POW_FORBIDDEN))
25111
0
            return -1;
25112
0
        emit_op(s, OP_await);
25113
0
        parse_flags = 0;
25114
0
        break;
25115
567k
    default:
25116
567k
        if (js_parse_postfix_expr(s, (parse_flags & PF_ARROW_FUNC) |
25117
567k
                                  PF_POSTFIX_CALL))
25118
18
            return -1;
25119
567k
        if (!s->got_lf &&
25120
567k
            (s->token.val == TOK_DEC || s->token.val == TOK_INC)) {
25121
478
            int opcode, op, scope, label;
25122
478
            JSAtom name;
25123
478
            op = s->token.val;
25124
478
            if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
25125
0
                return -1;
25126
478
            emit_op(s, OP_post_dec + op - TOK_DEC);
25127
478
            put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND,
25128
478
                       FALSE);
25129
478
            if (next_token(s))
25130
0
                return -1;        
25131
478
        }
25132
567k
        break;
25133
571k
    }
25134
571k
    if (parse_flags & (PF_POW_ALLOWED | PF_POW_FORBIDDEN)) {
25135
567k
#ifdef CONFIG_BIGNUM
25136
567k
        if (s->token.val == TOK_POW || s->token.val == TOK_MATH_POW) {
25137
            /* Extended exponentiation syntax rules: we extend the ES7
25138
               grammar in order to have more intuitive semantics:
25139
               -2**2 evaluates to -4. */
25140
19
            if (!(s->cur_func->js_mode & JS_MODE_MATH)) {
25141
19
                if (parse_flags & PF_POW_FORBIDDEN) {
25142
0
                    JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
25143
0
                    return -1;
25144
0
                }
25145
19
            }
25146
19
            if (next_token(s))
25147
0
                return -1;
25148
19
            if (js_parse_unary(s, PF_POW_ALLOWED))
25149
0
                return -1;
25150
19
            emit_op(s, OP_pow);
25151
19
        }
25152
#else
25153
        if (s->token.val == TOK_POW) {
25154
            /* Strict ES7 exponentiation syntax rules: To solve
25155
               conficting semantics between different implementations
25156
               regarding the precedence of prefix operators and the
25157
               postifx exponential, ES7 specifies that -2**2 is a
25158
               syntax error. */
25159
            if (parse_flags & PF_POW_FORBIDDEN) {
25160
                JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
25161
                return -1;
25162
            }
25163
            if (next_token(s))
25164
                return -1;
25165
            if (js_parse_unary(s, PF_POW_ALLOWED))
25166
                return -1;
25167
            emit_op(s, OP_pow);
25168
        }
25169
#endif
25170
567k
    }
25171
571k
    return 0;
25172
571k
}
25173
25174
/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
25175
static __exception int js_parse_expr_binary(JSParseState *s, int level,
25176
                                            int parse_flags)
25177
5.08M
{
25178
5.08M
    int op, opcode;
25179
25180
5.08M
    if (level == 0) {
25181
567k
        return js_parse_unary(s, (parse_flags & PF_ARROW_FUNC) |
25182
567k
                              PF_POW_ALLOWED);
25183
567k
    }
25184
4.52M
    if (js_parse_expr_binary(s, level - 1, parse_flags))
25185
156
        return -1;
25186
4.52M
    for(;;) {
25187
4.52M
        op = s->token.val;
25188
4.52M
        switch(level) {
25189
567k
        case 1:
25190
567k
            switch(op) {
25191
363
            case '*':
25192
363
                opcode = OP_mul;
25193
363
                break;
25194
577
            case '/':
25195
577
                opcode = OP_div;
25196
577
                break;
25197
7
            case '%':
25198
7
#ifdef CONFIG_BIGNUM
25199
7
                if (s->cur_func->js_mode & JS_MODE_MATH)
25200
0
                    opcode = OP_math_mod;
25201
7
                else
25202
7
#endif
25203
7
                    opcode = OP_mod;
25204
7
                break;
25205
566k
            default:
25206
566k
                return 0;
25207
567k
            }
25208
947
            break;
25209
566k
        case 2:
25210
566k
            switch(op) {
25211
823
            case '+':
25212
823
                opcode = OP_add;
25213
823
                break;
25214
78
            case '-':
25215
78
                opcode = OP_sub;
25216
78
                break;
25217
565k
            default:
25218
565k
                return 0;
25219
566k
            }
25220
901
            break;
25221
565k
        case 3:
25222
565k
            switch(op) {
25223
0
            case TOK_SHL:
25224
0
                opcode = OP_shl;
25225
0
                break;
25226
55
            case TOK_SAR:
25227
55
                opcode = OP_sar;
25228
55
                break;
25229
0
            case TOK_SHR:
25230
0
                opcode = OP_shr;
25231
0
                break;
25232
565k
            default:
25233
565k
                return 0;
25234
565k
            }
25235
55
            break;
25236
565k
        case 4:
25237
565k
            switch(op) {
25238
742
            case '<':
25239
742
                opcode = OP_lt;
25240
742
                break;
25241
199
            case '>':
25242
199
                opcode = OP_gt;
25243
199
                break;
25244
8
            case TOK_LTE:
25245
8
                opcode = OP_lte;
25246
8
                break;
25247
13
            case TOK_GTE:
25248
13
                opcode = OP_gte;
25249
13
                break;
25250
0
            case TOK_INSTANCEOF:
25251
0
                opcode = OP_instanceof;
25252
0
                break;
25253
24
            case TOK_IN:
25254
24
                if (parse_flags & PF_IN_ACCEPTED) {
25255
24
                    opcode = OP_in;
25256
24
                } else {
25257
0
                    return 0;
25258
0
                }
25259
24
                break;
25260
564k
            default:
25261
564k
                return 0;
25262
565k
            }
25263
986
            break;
25264
564k
        case 5:
25265
564k
            switch(op) {
25266
121
            case TOK_EQ:
25267
121
                opcode = OP_eq;
25268
121
                break;
25269
12
            case TOK_NEQ:
25270
12
                opcode = OP_neq;
25271
12
                break;
25272
12
            case TOK_STRICT_EQ:
25273
12
                opcode = OP_strict_eq;
25274
12
                break;
25275
2
            case TOK_STRICT_NEQ:
25276
2
                opcode = OP_strict_neq;
25277
2
                break;
25278
564k
            default:
25279
564k
                return 0;
25280
564k
            }
25281
147
            break;
25282
564k
        case 6:
25283
564k
            switch(op) {
25284
17
            case '&':
25285
17
                opcode = OP_and;
25286
17
                break;
25287
564k
            default:
25288
564k
                return 0;
25289
564k
            }
25290
17
            break;
25291
564k
        case 7:
25292
564k
            switch(op) {
25293
169
            case '^':
25294
169
                opcode = OP_xor;
25295
169
                break;
25296
564k
            default:
25297
564k
                return 0;
25298
564k
            }
25299
169
            break;
25300
564k
        case 8:
25301
564k
            switch(op) {
25302
43
            case '|':
25303
43
                opcode = OP_or;
25304
43
                break;
25305
564k
            default:
25306
564k
                return 0;
25307
564k
            }
25308
43
            break;
25309
43
        default:
25310
0
            abort();
25311
4.52M
        }
25312
3.26k
        if (next_token(s))
25313
2
            return -1;
25314
3.26k
        if (js_parse_expr_binary(s, level - 1, parse_flags & ~PF_ARROW_FUNC))
25315
4
            return -1;
25316
3.25k
        emit_op(s, opcode);
25317
3.25k
    }
25318
0
    return 0;
25319
4.52M
}
25320
25321
/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
25322
static __exception int js_parse_logical_and_or(JSParseState *s, int op,
25323
                                               int parse_flags)
25324
1.12M
{
25325
1.12M
    int label1;
25326
25327
1.12M
    if (op == TOK_LAND) {
25328
564k
        if (js_parse_expr_binary(s, 8, parse_flags))
25329
21
            return -1;
25330
564k
    } else {
25331
564k
        if (js_parse_logical_and_or(s, TOK_LAND, parse_flags))
25332
21
            return -1;
25333
564k
    }
25334
1.12M
    if (s->token.val == op) {
25335
222
        label1 = new_label(s);
25336
25337
305
        for(;;) {
25338
305
            if (next_token(s))
25339
0
                return -1;
25340
305
            emit_op(s, OP_dup);
25341
305
            emit_goto(s, op == TOK_LAND ? OP_if_false : OP_if_true, label1);
25342
305
            emit_op(s, OP_drop);
25343
25344
305
            if (op == TOK_LAND) {
25345
20
                if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
25346
0
                    return -1;
25347
285
            } else {
25348
285
                if (js_parse_logical_and_or(s, TOK_LAND,
25349
285
                                            parse_flags & ~PF_ARROW_FUNC))
25350
0
                    return -1;
25351
285
            }
25352
305
            if (s->token.val != op) {
25353
222
                if (s->token.val == TOK_DOUBLE_QUESTION_MARK)
25354
0
                    return js_parse_error(s, "cannot mix ?? with && or ||");
25355
222
                break;
25356
222
            }
25357
305
        }
25358
25359
222
        emit_label(s, label1);
25360
222
    }
25361
1.12M
    return 0;
25362
1.12M
}
25363
25364
static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
25365
564k
{
25366
564k
    int label1;
25367
    
25368
564k
    if (js_parse_logical_and_or(s, TOK_LOR, parse_flags))
25369
21
        return -1;
25370
564k
    if (s->token.val == TOK_DOUBLE_QUESTION_MARK) {
25371
1
        label1 = new_label(s);
25372
1
        for(;;) {
25373
1
            if (next_token(s))
25374
0
                return -1;
25375
            
25376
1
            emit_op(s, OP_dup);
25377
1
            emit_op(s, OP_is_undefined_or_null);
25378
1
            emit_goto(s, OP_if_false, label1);
25379
1
            emit_op(s, OP_drop);
25380
            
25381
1
            if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
25382
0
                return -1;
25383
1
            if (s->token.val != TOK_DOUBLE_QUESTION_MARK)
25384
1
                break;
25385
1
        }
25386
1
        emit_label(s, label1);
25387
1
    }
25388
564k
    return 0;
25389
564k
}
25390
25391
/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
25392
static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
25393
564k
{
25394
564k
    int label1, label2;
25395
25396
564k
    if (js_parse_coalesce_expr(s, parse_flags))
25397
21
        return -1;
25398
564k
    if (s->token.val == '?') {
25399
194
        if (next_token(s))
25400
0
            return -1;
25401
194
        label1 = emit_goto(s, OP_if_false, -1);
25402
25403
194
        if (js_parse_assign_expr(s))
25404
0
            return -1;
25405
194
        if (js_parse_expect(s, ':'))
25406
0
            return -1;
25407
25408
194
        label2 = emit_goto(s, OP_goto, -1);
25409
25410
194
        emit_label(s, label1);
25411
25412
194
        if (js_parse_assign_expr2(s, parse_flags & PF_IN_ACCEPTED))
25413
0
            return -1;
25414
25415
194
        emit_label(s, label2);
25416
194
    }
25417
564k
    return 0;
25418
564k
}
25419
25420
static void emit_return(JSParseState *s, BOOL hasval);
25421
25422
/* allowed parse_flags: PF_IN_ACCEPTED */
25423
static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
25424
564k
{
25425
564k
    int opcode, op, scope;
25426
564k
    JSAtom name0 = JS_ATOM_NULL;
25427
564k
    JSAtom name;
25428
25429
564k
    if (s->token.val == TOK_YIELD) {
25430
370
        BOOL is_star = FALSE, is_async;
25431
        
25432
370
        if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR))
25433
0
            return js_parse_error(s, "unexpected 'yield' keyword");
25434
370
        if (!s->cur_func->in_function_body)
25435
0
            return js_parse_error(s, "yield in default expression");
25436
370
        if (next_token(s))
25437
0
            return -1;
25438
        /* XXX: is there a better method to detect 'yield' without
25439
           parameters ? */
25440
370
        if (s->token.val != ';' && s->token.val != ')' &&
25441
370
            s->token.val != ']' && s->token.val != '}' &&
25442
370
            s->token.val != ',' && s->token.val != ':' && !s->got_lf) {
25443
370
            if (s->token.val == '*') {
25444
370
                is_star = TRUE;
25445
370
                if (next_token(s))
25446
0
                    return -1;
25447
370
            }
25448
370
            if (js_parse_assign_expr2(s, parse_flags))
25449
0
                return -1;
25450
370
        } else {
25451
0
            emit_op(s, OP_undefined);
25452
0
        }
25453
370
        is_async = (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR);
25454
25455
370
        if (is_star) {
25456
370
            int label_loop, label_return, label_next;
25457
370
            int label_return1, label_yield, label_throw, label_throw1;
25458
370
            int label_throw2;
25459
25460
370
            label_loop = new_label(s);
25461
370
            label_yield = new_label(s);
25462
25463
370
            emit_op(s, is_async ? OP_for_await_of_start : OP_for_of_start);
25464
25465
            /* remove the catch offset (XXX: could avoid pushing back
25466
               undefined) */
25467
370
            emit_op(s, OP_drop);
25468
370
            emit_op(s, OP_undefined);
25469
            
25470
370
            emit_op(s, OP_undefined); /* initial value */
25471
            
25472
370
            emit_label(s, label_loop);
25473
370
            emit_op(s, OP_iterator_next);
25474
370
            if (is_async)
25475
0
                emit_op(s, OP_await);
25476
370
            emit_op(s, OP_iterator_check_object);
25477
370
            emit_op(s, OP_get_field2);
25478
370
            emit_atom(s, JS_ATOM_done);
25479
370
            label_next = emit_goto(s, OP_if_true, -1); /* end of loop */
25480
370
            emit_label(s, label_yield);
25481
370
            if (is_async) {
25482
                /* OP_async_yield_star takes the value as parameter */
25483
0
                emit_op(s, OP_get_field);
25484
0
                emit_atom(s, JS_ATOM_value);
25485
0
                emit_op(s, OP_await);
25486
0
                emit_op(s, OP_async_yield_star);
25487
370
            } else {
25488
                /* OP_yield_star takes (value, done) as parameter */
25489
370
                emit_op(s, OP_yield_star);
25490
370
            }
25491
370
            emit_op(s, OP_dup);
25492
370
            label_return = emit_goto(s, OP_if_true, -1);
25493
370
            emit_op(s, OP_drop);
25494
370
            emit_goto(s, OP_goto, label_loop);
25495
            
25496
370
            emit_label(s, label_return);
25497
370
            emit_op(s, OP_push_i32);
25498
370
            emit_u32(s, 2);
25499
370
            emit_op(s, OP_strict_eq);
25500
370
            label_throw = emit_goto(s, OP_if_true, -1);
25501
            
25502
            /* return handling */
25503
370
            if (is_async)
25504
0
                emit_op(s, OP_await);
25505
370
            emit_op(s, OP_iterator_call);
25506
370
            emit_u8(s, 0);
25507
370
            label_return1 = emit_goto(s, OP_if_true, -1);
25508
370
            if (is_async)
25509
0
                emit_op(s, OP_await);
25510
370
            emit_op(s, OP_iterator_check_object);
25511
370
            emit_op(s, OP_get_field2);
25512
370
            emit_atom(s, JS_ATOM_done);
25513
370
            emit_goto(s, OP_if_false, label_yield);
25514
25515
370
            emit_op(s, OP_get_field);
25516
370
            emit_atom(s, JS_ATOM_value);
25517
            
25518
370
            emit_label(s, label_return1);
25519
370
            emit_op(s, OP_nip);
25520
370
            emit_op(s, OP_nip);
25521
370
            emit_op(s, OP_nip);
25522
370
            emit_return(s, TRUE);
25523
            
25524
            /* throw handling */
25525
370
            emit_label(s, label_throw);
25526
370
            emit_op(s, OP_iterator_call);
25527
370
            emit_u8(s, 1);
25528
370
            label_throw1 = emit_goto(s, OP_if_true, -1);
25529
370
            if (is_async)
25530
0
                emit_op(s, OP_await);
25531
370
            emit_op(s, OP_iterator_check_object);
25532
370
            emit_op(s, OP_get_field2);
25533
370
            emit_atom(s, JS_ATOM_done);
25534
370
            emit_goto(s, OP_if_false, label_yield);
25535
370
            emit_goto(s, OP_goto, label_next);
25536
            /* close the iterator and throw a type error exception */
25537
370
            emit_label(s, label_throw1);
25538
370
            emit_op(s, OP_iterator_call);
25539
370
            emit_u8(s, 2);
25540
370
            label_throw2 = emit_goto(s, OP_if_true, -1);
25541
370
            if (is_async)
25542
0
                emit_op(s, OP_await);
25543
370
            emit_label(s, label_throw2);
25544
25545
370
            emit_op(s, OP_throw_error);
25546
370
            emit_atom(s, JS_ATOM_NULL);
25547
370
            emit_u8(s, JS_THROW_ERROR_ITERATOR_THROW);
25548
            
25549
370
            emit_label(s, label_next);
25550
370
            emit_op(s, OP_get_field);
25551
370
            emit_atom(s, JS_ATOM_value);
25552
370
            emit_op(s, OP_nip); /* keep the value associated with
25553
                                   done = true */
25554
370
            emit_op(s, OP_nip);
25555
370
            emit_op(s, OP_nip);
25556
370
        } else {
25557
0
            int label_next;
25558
            
25559
0
            if (is_async)
25560
0
                emit_op(s, OP_await);
25561
0
            emit_op(s, OP_yield);
25562
0
            label_next = emit_goto(s, OP_if_false, -1);
25563
0
            emit_return(s, TRUE);
25564
0
            emit_label(s, label_next);
25565
0
        }
25566
370
        return 0;
25567
370
    }
25568
564k
    if (s->token.val == TOK_IDENT) {
25569
        /* name0 is used to check for OP_set_name pattern, not duplicated */
25570
531k
        name0 = s->token.u.ident.atom;
25571
531k
    }
25572
564k
    if (js_parse_cond_expr(s, parse_flags | PF_ARROW_FUNC))
25573
21
        return -1;
25574
25575
564k
    op = s->token.val;
25576
564k
    if (op == '=' || (op >= TOK_MUL_ASSIGN && op <= TOK_POW_ASSIGN)) {
25577
213k
        int label;
25578
213k
        if (next_token(s))
25579
0
            return -1;
25580
213k
        if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
25581
3
            return -1;
25582
25583
213k
        if (js_parse_assign_expr2(s, parse_flags)) {
25584
1
            JS_FreeAtom(s->ctx, name);
25585
1
            return -1;
25586
1
        }
25587
25588
213k
        if (op == '=') {
25589
213k
            if (opcode == OP_get_ref_value && name == name0) {
25590
212k
                set_object_name(s, name);
25591
212k
            }
25592
213k
        } else {
25593
280
            static const uint8_t assign_opcodes[] = {
25594
280
                OP_mul, OP_div, OP_mod, OP_add, OP_sub,
25595
280
                OP_shl, OP_sar, OP_shr, OP_and, OP_xor, OP_or,
25596
280
#ifdef CONFIG_BIGNUM
25597
280
                OP_pow,
25598
280
#endif
25599
280
                OP_pow,
25600
280
            };
25601
280
            op = assign_opcodes[op - TOK_MUL_ASSIGN];
25602
280
#ifdef CONFIG_BIGNUM
25603
280
            if (s->cur_func->js_mode & JS_MODE_MATH) {
25604
0
                if (op == OP_mod)
25605
0
                    op = OP_math_mod;
25606
0
            }
25607
280
#endif
25608
280
            emit_op(s, op);
25609
280
        }
25610
213k
        put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE);
25611
350k
    } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) {
25612
2.43k
        int label, label1, depth_lvalue, label2;
25613
        
25614
2.43k
        if (next_token(s))
25615
0
            return -1;
25616
2.43k
        if (get_lvalue(s, &opcode, &scope, &name, &label,
25617
2.43k
                       &depth_lvalue, TRUE, op) < 0)
25618
0
            return -1;
25619
25620
2.43k
        emit_op(s, OP_dup);
25621
2.43k
        if (op == TOK_DOUBLE_QUESTION_MARK_ASSIGN)
25622
2
            emit_op(s, OP_is_undefined_or_null);
25623
2.43k
        label1 = emit_goto(s, op == TOK_LOR_ASSIGN ? OP_if_true : OP_if_false,
25624
2.43k
                           -1);
25625
2.43k
        emit_op(s, OP_drop);
25626
        
25627
2.43k
        if (js_parse_assign_expr2(s, parse_flags)) {
25628
0
            JS_FreeAtom(s->ctx, name);
25629
0
            return -1;
25630
0
        }
25631
25632
2.43k
        if (opcode == OP_get_ref_value && name == name0) {
25633
2.43k
            set_object_name(s, name);
25634
2.43k
        }
25635
        
25636
2.43k
        switch(depth_lvalue) {
25637
0
        case 1:
25638
0
            emit_op(s, OP_insert2);
25639
0
            break;
25640
2.43k
        case 2:
25641
2.43k
            emit_op(s, OP_insert3);
25642
2.43k
            break;
25643
0
        case 3:
25644
0
            emit_op(s, OP_insert4);
25645
0
            break;
25646
0
        default:
25647
0
            abort();
25648
2.43k
        }
25649
25650
        /* XXX: we disable the OP_put_ref_value optimization by not
25651
           using put_lvalue() otherwise depth_lvalue is not correct */
25652
2.43k
        put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH,
25653
2.43k
                   FALSE);
25654
2.43k
        label2 = emit_goto(s, OP_goto, -1);
25655
        
25656
2.43k
        emit_label(s, label1);
25657
25658
        /* remove the lvalue stack entries */
25659
7.30k
        while (depth_lvalue != 0) {
25660
4.87k
            emit_op(s, OP_nip);
25661
4.87k
            depth_lvalue--;
25662
4.87k
        }
25663
25664
2.43k
        emit_label(s, label2);
25665
2.43k
    }
25666
564k
    return 0;
25667
564k
}
25668
25669
static __exception int js_parse_assign_expr(JSParseState *s)
25670
28.6k
{
25671
28.6k
    return js_parse_assign_expr2(s, PF_IN_ACCEPTED);
25672
28.6k
}
25673
25674
/* allowed parse_flags: PF_IN_ACCEPTED */
25675
static __exception int js_parse_expr2(JSParseState *s, int parse_flags)
25676
112k
{
25677
112k
    BOOL comma = FALSE;
25678
318k
    for(;;) {
25679
318k
        if (js_parse_assign_expr2(s, parse_flags))
25680
22
            return -1;
25681
318k
        if (comma) {
25682
            /* prevent get_lvalue from using the last expression
25683
               as an lvalue. This also prevents the conversion of
25684
               of get_var to get_ref for method lookup in function
25685
               call inside `with` statement.
25686
             */
25687
206k
            s->cur_func->last_opcode_pos = -1;
25688
206k
        }
25689
318k
        if (s->token.val != ',')
25690
112k
            break;
25691
206k
        comma = TRUE;
25692
206k
        if (next_token(s))
25693
0
            return -1;
25694
206k
        emit_op(s, OP_drop);
25695
206k
    }
25696
112k
    return 0;
25697
112k
}
25698
25699
static __exception int js_parse_expr(JSParseState *s)
25700
112k
{
25701
112k
    return js_parse_expr2(s, PF_IN_ACCEPTED);
25702
112k
}
25703
25704
static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
25705
                             JSAtom label_name,
25706
                             int label_break, int label_cont,
25707
                             int drop_count)
25708
19.5k
{
25709
19.5k
    be->prev = fd->top_break;
25710
19.5k
    fd->top_break = be;
25711
19.5k
    be->label_name = label_name;
25712
19.5k
    be->label_break = label_break;
25713
19.5k
    be->label_cont = label_cont;
25714
19.5k
    be->drop_count = drop_count;
25715
19.5k
    be->label_finally = -1;
25716
19.5k
    be->scope_level = fd->scope_level;
25717
19.5k
    be->has_iterator = FALSE;
25718
19.5k
}
25719
25720
static void pop_break_entry(JSFunctionDef *fd)
25721
19.5k
{
25722
19.5k
    BlockEnv *be;
25723
19.5k
    be = fd->top_break;
25724
19.5k
    fd->top_break = be->prev;
25725
19.5k
}
25726
25727
static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
25728
0
{
25729
0
    BlockEnv *top;
25730
0
    int i, scope_level;
25731
25732
0
    scope_level = s->cur_func->scope_level;
25733
0
    top = s->cur_func->top_break;
25734
0
    while (top != NULL) {
25735
0
        close_scopes(s, scope_level, top->scope_level);
25736
0
        scope_level = top->scope_level;
25737
0
        if (is_cont &&
25738
0
            top->label_cont != -1 &&
25739
0
            (name == JS_ATOM_NULL || top->label_name == name)) {
25740
            /* continue stays inside the same block */
25741
0
            emit_goto(s, OP_goto, top->label_cont);
25742
0
            return 0;
25743
0
        }
25744
0
        if (!is_cont &&
25745
0
            top->label_break != -1 &&
25746
0
            (name == JS_ATOM_NULL || top->label_name == name)) {
25747
0
            emit_goto(s, OP_goto, top->label_break);
25748
0
            return 0;
25749
0
        }
25750
0
        i = 0;
25751
0
        if (top->has_iterator) {
25752
0
            emit_op(s, OP_iterator_close);
25753
0
            i += 3;
25754
0
        }
25755
0
        for(; i < top->drop_count; i++)
25756
0
            emit_op(s, OP_drop);
25757
0
        if (top->label_finally != -1) {
25758
            /* must push dummy value to keep same stack depth */
25759
0
            emit_op(s, OP_undefined);
25760
0
            emit_goto(s, OP_gosub, top->label_finally);
25761
0
            emit_op(s, OP_drop);
25762
0
        }
25763
0
        top = top->prev;
25764
0
    }
25765
0
    if (name == JS_ATOM_NULL) {
25766
0
        if (is_cont)
25767
0
            return js_parse_error(s, "continue must be inside loop");
25768
0
        else
25769
0
            return js_parse_error(s, "break must be inside loop or switch");
25770
0
    } else {
25771
0
        return js_parse_error(s, "break/continue label not found");
25772
0
    }
25773
0
}
25774
25775
/* execute the finally blocks before return */
25776
static void emit_return(JSParseState *s, BOOL hasval)
25777
12.2k
{
25778
12.2k
    BlockEnv *top;
25779
12.2k
    int drop_count;
25780
25781
12.2k
    drop_count = 0;
25782
12.2k
    top = s->cur_func->top_break;
25783
13.7k
    while (top != NULL) {
25784
        /* XXX: emit the appropriate OP_leave_scope opcodes? Probably not
25785
           required as all local variables will be closed upon returning
25786
           from JS_CallInternal, but not in the same order. */
25787
1.52k
        if (top->has_iterator) {
25788
            /* with 'yield', the exact number of OP_drop to emit is
25789
               unknown, so we use a specific operation to look for
25790
               the catch offset */
25791
0
            if (!hasval) {
25792
0
                emit_op(s, OP_undefined);
25793
0
                hasval = TRUE;
25794
0
            }
25795
0
            emit_op(s, OP_iterator_close_return);
25796
0
            if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
25797
0
                int label_next, label_next2;
25798
25799
0
                emit_op(s, OP_drop); /* catch offset */
25800
0
                emit_op(s, OP_drop); /* next */
25801
0
                emit_op(s, OP_get_field2);
25802
0
                emit_atom(s, JS_ATOM_return);
25803
                /* stack: iter_obj return_func */
25804
0
                emit_op(s, OP_dup);
25805
0
                emit_op(s, OP_is_undefined_or_null);
25806
0
                label_next = emit_goto(s, OP_if_true, -1);
25807
0
                emit_op(s, OP_call_method);
25808
0
                emit_u16(s, 0);
25809
0
                emit_op(s, OP_iterator_check_object);
25810
0
                emit_op(s, OP_await);
25811
0
                label_next2 = emit_goto(s, OP_goto, -1);
25812
0
                emit_label(s, label_next);
25813
0
                emit_op(s, OP_drop);
25814
0
                emit_label(s, label_next2);
25815
0
                emit_op(s, OP_drop);
25816
0
            } else {
25817
0
                emit_op(s, OP_iterator_close);
25818
0
            }
25819
0
            drop_count = -3;
25820
0
        }
25821
1.52k
        drop_count += top->drop_count;
25822
1.52k
        if (top->label_finally != -1) {
25823
0
            while(drop_count) {
25824
                /* must keep the stack top if hasval */
25825
0
                emit_op(s, hasval ? OP_nip : OP_drop);
25826
0
                drop_count--;
25827
0
            }
25828
0
            if (!hasval) {
25829
                /* must push return value to keep same stack size */
25830
0
                emit_op(s, OP_undefined);
25831
0
                hasval = TRUE;
25832
0
            }
25833
0
            emit_goto(s, OP_gosub, top->label_finally);
25834
0
        }
25835
1.52k
        top = top->prev;
25836
1.52k
    }
25837
12.2k
    if (s->cur_func->is_derived_class_constructor) {
25838
0
        int label_return;
25839
25840
        /* 'this' can be uninitialized, so it may be accessed only if
25841
           the derived class constructor does not return an object */
25842
0
        if (hasval) {
25843
0
            emit_op(s, OP_check_ctor_return);
25844
0
            label_return = emit_goto(s, OP_if_false, -1);
25845
0
            emit_op(s, OP_drop);
25846
0
        } else {
25847
0
            label_return = -1;
25848
0
        }
25849
25850
        /* XXX: if this is not initialized, should throw the
25851
           ReferenceError in the caller realm */
25852
0
        emit_op(s, OP_scope_get_var);
25853
0
        emit_atom(s, JS_ATOM_this);
25854
0
        emit_u16(s, 0);
25855
25856
0
        emit_label(s, label_return);
25857
0
        emit_op(s, OP_return);
25858
12.2k
    } else if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
25859
457
        if (!hasval) {
25860
71
            emit_op(s, OP_undefined);
25861
386
        } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
25862
0
            emit_op(s, OP_await);
25863
0
        }
25864
457
        emit_op(s, OP_return_async);
25865
11.7k
    } else {
25866
11.7k
        emit_op(s, hasval ? OP_return : OP_return_undef);
25867
11.7k
    }
25868
12.2k
}
25869
25870
117k
#define DECL_MASK_FUNC  (1 << 0) /* allow normal function declaration */
25871
/* ored with DECL_MASK_FUNC if function declarations are allowed with a label */
25872
116k
#define DECL_MASK_FUNC_WITH_LABEL (1 << 1)
25873
116k
#define DECL_MASK_OTHER (1 << 2) /* all other declarations */
25874
116k
#define DECL_MASK_ALL   (DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL | DECL_MASK_OTHER)
25875
25876
static __exception int js_parse_statement_or_decl(JSParseState *s,
25877
                                                  int decl_mask);
25878
25879
static __exception int js_parse_statement(JSParseState *s)
25880
1.76k
{
25881
1.76k
    return js_parse_statement_or_decl(s, 0);
25882
1.76k
}
25883
25884
static __exception int js_parse_block(JSParseState *s)
25885
4.77k
{
25886
4.77k
    if (js_parse_expect(s, '{'))
25887
0
        return -1;
25888
4.77k
    if (s->token.val != '}') {
25889
4.76k
        push_scope(s);
25890
7.96k
        for(;;) {
25891
7.96k
            if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
25892
19
                return -1;
25893
7.94k
            if (s->token.val == '}')
25894
4.75k
                break;
25895
7.94k
        }
25896
4.75k
        pop_scope(s);
25897
4.75k
    }
25898
4.75k
    if (next_token(s))
25899
0
        return -1;
25900
4.75k
    return 0;
25901
4.75k
}
25902
25903
/* allowed parse_flags: PF_IN_ACCEPTED */
25904
static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
25905
                                    BOOL export_flag)
25906
765
{
25907
765
    JSContext *ctx = s->ctx;
25908
765
    JSFunctionDef *fd = s->cur_func;
25909
765
    JSAtom name = JS_ATOM_NULL;
25910
25911
1.32k
    for (;;) {
25912
1.32k
        if (s->token.val == TOK_IDENT) {
25913
1.32k
            if (s->token.u.ident.is_reserved) {
25914
0
                return js_parse_error_reserved_identifier(s);
25915
0
            }
25916
1.32k
            name = JS_DupAtom(ctx, s->token.u.ident.atom);
25917
1.32k
            if (name == JS_ATOM_let && (tok == TOK_LET || tok == TOK_CONST)) {
25918
0
                js_parse_error(s, "'let' is not a valid lexical identifier");
25919
0
                goto var_error;
25920
0
            }
25921
1.32k
            if (next_token(s))
25922
0
                goto var_error;
25923
1.32k
            if (js_define_var(s, name, tok))
25924
0
                goto var_error;
25925
1.32k
            if (export_flag) {
25926
0
                if (!add_export_entry(s, s->cur_func->module, name, name,
25927
0
                                      JS_EXPORT_TYPE_LOCAL))
25928
0
                    goto var_error;
25929
0
            }
25930
25931
1.32k
            if (s->token.val == '=') {
25932
903
                if (next_token(s))
25933
0
                    goto var_error;
25934
903
                if (tok == TOK_VAR) {
25935
                    /* Must make a reference for proper `with` semantics */
25936
903
                    int opcode, scope, label;
25937
903
                    JSAtom name1;
25938
25939
903
                    emit_op(s, OP_scope_get_var);
25940
903
                    emit_atom(s, name);
25941
903
                    emit_u16(s, fd->scope_level);
25942
903
                    if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0)
25943
0
                        goto var_error;
25944
903
                    if (js_parse_assign_expr2(s, parse_flags)) {
25945
1
                        JS_FreeAtom(ctx, name1);
25946
1
                        goto var_error;
25947
1
                    }
25948
902
                    set_object_name(s, name);
25949
902
                    put_lvalue(s, opcode, scope, name1, label,
25950
902
                               PUT_LVALUE_NOKEEP, FALSE);
25951
902
                } else {
25952
0
                    if (js_parse_assign_expr2(s, parse_flags))
25953
0
                        goto var_error;
25954
0
                    set_object_name(s, name);
25955
0
                    emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
25956
0
                        OP_scope_put_var_init : OP_scope_put_var);
25957
0
                    emit_atom(s, name);
25958
0
                    emit_u16(s, fd->scope_level);
25959
0
                }
25960
903
            } else {
25961
418
                if (tok == TOK_CONST) {
25962
0
                    js_parse_error(s, "missing initializer for const variable");
25963
0
                    goto var_error;
25964
0
                }
25965
418
                if (tok == TOK_LET) {
25966
                    /* initialize lexical variable upon entering its scope */
25967
3
                    emit_op(s, OP_undefined);
25968
3
                    emit_op(s, OP_scope_put_var_init);
25969
3
                    emit_atom(s, name);
25970
3
                    emit_u16(s, fd->scope_level);
25971
3
                }
25972
418
            }
25973
1.32k
            JS_FreeAtom(ctx, name);
25974
1.32k
        } else {
25975
3
            int skip_bits;
25976
3
            if ((s->token.val == '[' || s->token.val == '{')
25977
3
            &&  js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
25978
3
                emit_op(s, OP_undefined);
25979
3
                if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
25980
0
                    return -1;
25981
3
            } else {
25982
0
                return js_parse_error(s, "variable name expected");
25983
0
            }
25984
3
        }
25985
1.32k
        if (s->token.val != ',')
25986
764
            break;
25987
559
        if (next_token(s))
25988
0
            return -1;
25989
559
    }
25990
764
    return 0;
25991
25992
1
 var_error:
25993
1
    JS_FreeAtom(ctx, name);
25994
1
    return -1;
25995
765
}
25996
25997
/* test if the current token is a label. Use simplistic look-ahead scanner */
25998
static BOOL is_label(JSParseState *s)
25999
118k
{
26000
118k
    return (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
26001
118k
            peek_token(s, FALSE) == ':');
26002
118k
}
26003
26004
/* test if the current token is a let keyword. Use simplistic look-ahead scanner */
26005
static int is_let(JSParseState *s, int decl_mask)
26006
104k
{
26007
104k
    int res = FALSE;
26008
26009
104k
    if (token_is_pseudo_keyword(s, JS_ATOM_let)) {
26010
126
#if 1
26011
126
        JSParsePos pos;
26012
126
        js_parse_get_pos(s, &pos);
26013
126
        for (;;) {
26014
126
            if (next_token(s)) {
26015
0
                res = -1;
26016
0
                break;
26017
0
            }
26018
126
            if (s->token.val == '[') {
26019
                /* let [ is a syntax restriction:
26020
                   it never introduces an ExpressionStatement */
26021
0
                res = TRUE;
26022
0
                break;
26023
0
            }
26024
126
            if (s->token.val == '{' ||
26025
126
                (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) ||
26026
126
                s->token.val == TOK_LET ||
26027
126
                s->token.val == TOK_YIELD ||
26028
126
                s->token.val == TOK_AWAIT) {
26029
                /* Check for possible ASI if not scanning for Declaration */
26030
                /* XXX: should also check that `{` introduces a BindingPattern,
26031
                   but Firefox does not and rejects eval("let=1;let\n{if(1)2;}") */
26032
66
                if (s->last_line_num == s->token.line_num || (decl_mask & DECL_MASK_OTHER)) {
26033
66
                    res = TRUE;
26034
66
                    break;
26035
66
                }
26036
0
                break;
26037
66
            }
26038
60
            break;
26039
126
        }
26040
126
        if (js_parse_seek_token(s, &pos)) {
26041
0
            res = -1;
26042
0
        }
26043
#else
26044
        int tok = peek_token(s, TRUE);
26045
        if (tok == '{' || tok == TOK_IDENT || peek_token(s, FALSE) == '[') {
26046
            res = TRUE;
26047
        }
26048
#endif
26049
126
    }
26050
104k
    return res;
26051
104k
}
26052
26053
/* XXX: handle IteratorClose when exiting the loop before the
26054
   enumeration is done */
26055
static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
26056
                                          BOOL is_async)
26057
268
{
26058
268
    JSContext *ctx = s->ctx;
26059
268
    JSFunctionDef *fd = s->cur_func;
26060
268
    JSAtom var_name;
26061
268
    BOOL has_initializer, is_for_of, has_destructuring;
26062
268
    int tok, tok1, opcode, scope, block_scope_level;
26063
268
    int label_next, label_expr, label_cont, label_body, label_break;
26064
268
    int pos_next, pos_expr;
26065
268
    BlockEnv break_entry;
26066
26067
268
    has_initializer = FALSE;
26068
268
    has_destructuring = FALSE;
26069
268
    is_for_of = FALSE;
26070
268
    block_scope_level = fd->scope_level;
26071
268
    label_cont = new_label(s);
26072
268
    label_body = new_label(s);
26073
268
    label_break = new_label(s);
26074
268
    label_next = new_label(s);
26075
26076
    /* create scope for the lexical variables declared in the enumeration
26077
       expressions. XXX: Not completely correct because of weird capturing
26078
       semantics in `for (i of o) a.push(function(){return i})` */
26079
268
    push_scope(s);
26080
26081
    /* local for_in scope starts here so individual elements
26082
       can be closed in statement. */
26083
268
    push_break_entry(s->cur_func, &break_entry,
26084
268
                     label_name, label_break, label_cont, 1);
26085
268
    break_entry.scope_level = block_scope_level;
26086
26087
268
    label_expr = emit_goto(s, OP_goto, -1);
26088
26089
268
    pos_next = s->cur_func->byte_code.size;
26090
268
    emit_label(s, label_next);
26091
26092
268
    tok = s->token.val;
26093
268
    switch (is_let(s, DECL_MASK_OTHER)) {
26094
66
    case TRUE:
26095
66
        tok = TOK_LET;
26096
66
        break;
26097
202
    case FALSE:
26098
202
        break;
26099
0
    default:
26100
0
        return -1;
26101
268
    }
26102
268
    if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
26103
66
        if (next_token(s))
26104
0
            return -1;
26105
26106
66
        if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
26107
0
            if (s->token.val == '[' || s->token.val == '{') {
26108
0
                if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE) < 0)
26109
0
                    return -1;
26110
0
                has_destructuring = TRUE;
26111
0
            } else {
26112
0
                return js_parse_error(s, "variable name expected");
26113
0
            }
26114
0
            var_name = JS_ATOM_NULL;
26115
66
        } else {
26116
66
            var_name = JS_DupAtom(ctx, s->token.u.ident.atom);
26117
66
            if (next_token(s)) {
26118
0
                JS_FreeAtom(s->ctx, var_name);
26119
0
                return -1;
26120
0
            }
26121
66
            if (js_define_var(s, var_name, tok)) {
26122
0
                JS_FreeAtom(s->ctx, var_name);
26123
0
                return -1;
26124
0
            }
26125
66
            emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
26126
66
                    OP_scope_put_var_init : OP_scope_put_var);
26127
66
            emit_atom(s, var_name);
26128
66
            emit_u16(s, fd->scope_level);
26129
66
        }
26130
202
    } else {
26131
202
        int skip_bits;
26132
202
        if ((s->token.val == '[' || s->token.val == '{')
26133
202
        &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) {
26134
0
            if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
26135
0
                return -1;
26136
202
        } else {
26137
202
            int lvalue_label;
26138
202
            if (js_parse_left_hand_side_expr(s))
26139
0
                return -1;
26140
202
            if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label,
26141
202
                           NULL, FALSE, TOK_FOR))
26142
0
                return -1;
26143
202
            put_lvalue(s, opcode, scope, var_name, lvalue_label,
26144
202
                       PUT_LVALUE_NOKEEP_BOTTOM, FALSE);
26145
202
        }
26146
202
        var_name = JS_ATOM_NULL;
26147
202
    }
26148
268
    emit_goto(s, OP_goto, label_body);
26149
26150
268
    pos_expr = s->cur_func->byte_code.size;
26151
268
    emit_label(s, label_expr);
26152
268
    if (s->token.val == '=') {
26153
        /* XXX: potential scoping issue if inside `with` statement */
26154
0
        has_initializer = TRUE;
26155
        /* parse and evaluate initializer prior to evaluating the
26156
           object (only used with "for in" with a non lexical variable
26157
           in non strict mode */
26158
0
        if (next_token(s) || js_parse_assign_expr2(s, 0)) {
26159
0
            JS_FreeAtom(ctx, var_name);
26160
0
            return -1;
26161
0
        }
26162
0
        if (var_name != JS_ATOM_NULL) {
26163
0
            emit_op(s, OP_scope_put_var);
26164
0
            emit_atom(s, var_name);
26165
0
            emit_u16(s, fd->scope_level);
26166
0
        }
26167
0
    }
26168
268
    JS_FreeAtom(ctx, var_name);
26169
26170
268
    if (token_is_pseudo_keyword(s, JS_ATOM_of)) {
26171
2
        break_entry.has_iterator = is_for_of = TRUE;
26172
2
        break_entry.drop_count += 2;
26173
2
        if (has_initializer)
26174
0
            goto initializer_error;
26175
266
    } else if (s->token.val == TOK_IN) {
26176
266
        if (is_async)
26177
0
            return js_parse_error(s, "'for await' loop should be used with 'of'");
26178
266
        if (has_initializer &&
26179
266
            (tok != TOK_VAR || (fd->js_mode & JS_MODE_STRICT) ||
26180
0
             has_destructuring)) {
26181
0
        initializer_error:
26182
0
            return js_parse_error(s, "a declaration in the head of a for-%s loop can't have an initializer",
26183
0
                                  is_for_of ? "of" : "in");
26184
0
        }
26185
266
    } else {
26186
0
        return js_parse_error(s, "expected 'of' or 'in' in for control expression");
26187
0
    }
26188
268
    if (next_token(s))
26189
0
        return -1;
26190
268
    if (is_for_of) {
26191
2
        if (js_parse_assign_expr(s))
26192
0
            return -1;
26193
266
    } else {
26194
266
        if (js_parse_expr(s))
26195
0
            return -1;
26196
266
    }
26197
    /* close the scope after having evaluated the expression so that
26198
       the TDZ values are in the closures */
26199
268
    close_scopes(s, s->cur_func->scope_level, block_scope_level);
26200
268
    if (is_for_of) {
26201
2
        if (is_async)
26202
0
            emit_op(s, OP_for_await_of_start);
26203
2
        else
26204
2
            emit_op(s, OP_for_of_start);
26205
        /* on stack: enum_rec */
26206
266
    } else {
26207
266
        emit_op(s, OP_for_in_start);
26208
        /* on stack: enum_obj */
26209
266
    }
26210
268
    emit_goto(s, OP_goto, label_cont);
26211
26212
268
    if (js_parse_expect(s, ')'))
26213
0
        return -1;
26214
26215
268
    if (OPTIMIZE) {
26216
        /* move the `next` code here */
26217
268
        DynBuf *bc = &s->cur_func->byte_code;
26218
268
        int chunk_size = pos_expr - pos_next;
26219
268
        int offset = bc->size - pos_next;
26220
268
        int i;
26221
268
        dbuf_realloc(bc, bc->size + chunk_size);
26222
268
        dbuf_put(bc, bc->buf + pos_next, chunk_size);
26223
268
        memset(bc->buf + pos_next, OP_nop, chunk_size);
26224
        /* `next` part ends with a goto */
26225
268
        s->cur_func->last_opcode_pos = bc->size - 5;
26226
        /* relocate labels */
26227
1.81k
        for (i = label_cont; i < s->cur_func->label_count; i++) {
26228
1.54k
            LabelSlot *ls = &s->cur_func->label_slots[i];
26229
1.54k
            if (ls->pos >= pos_next && ls->pos < pos_expr)
26230
470
                ls->pos += offset;
26231
1.54k
        }
26232
268
    }
26233
26234
268
    emit_label(s, label_body);
26235
268
    if (js_parse_statement(s))
26236
3
        return -1;
26237
26238
265
    close_scopes(s, s->cur_func->scope_level, block_scope_level);
26239
26240
265
    emit_label(s, label_cont);
26241
265
    if (is_for_of) {
26242
2
        if (is_async) {
26243
            /* call the next method */
26244
            /* stack: iter_obj next catch_offset */
26245
0
            emit_op(s, OP_dup3);
26246
0
            emit_op(s, OP_drop);
26247
0
            emit_op(s, OP_call_method);
26248
0
            emit_u16(s, 0);
26249
            /* get the result of the promise */
26250
0
            emit_op(s, OP_await);
26251
            /* unwrap the value and done values */
26252
0
            emit_op(s, OP_iterator_get_value_done);
26253
2
        } else {
26254
2
            emit_op(s, OP_for_of_next);
26255
2
            emit_u8(s, 0);
26256
2
        }
26257
263
    } else {
26258
263
        emit_op(s, OP_for_in_next);
26259
263
    }
26260
    /* on stack: enum_rec / enum_obj value bool */
26261
265
    emit_goto(s, OP_if_false, label_next);
26262
    /* drop the undefined value from for_xx_next */
26263
265
    emit_op(s, OP_drop);
26264
26265
265
    emit_label(s, label_break);
26266
265
    if (is_for_of) {
26267
        /* close and drop enum_rec */
26268
2
        emit_op(s, OP_iterator_close);
26269
263
    } else {
26270
263
        emit_op(s, OP_drop);
26271
263
    }
26272
265
    pop_break_entry(s->cur_func);
26273
265
    pop_scope(s);
26274
265
    return 0;
26275
268
}
26276
26277
static void set_eval_ret_undefined(JSParseState *s)
26278
2.10k
{
26279
2.10k
    if (s->cur_func->eval_ret_idx >= 0) {
26280
1.62k
        emit_op(s, OP_undefined);
26281
1.62k
        emit_op(s, OP_put_loc);
26282
1.62k
        emit_u16(s, s->cur_func->eval_ret_idx);
26283
1.62k
    }
26284
2.10k
}
26285
26286
static __exception int js_parse_statement_or_decl(JSParseState *s,
26287
                                                  int decl_mask)
26288
118k
{
26289
118k
    JSContext *ctx = s->ctx;
26290
118k
    JSAtom label_name;
26291
118k
    int tok;
26292
26293
    /* specific label handling */
26294
    /* XXX: support multiple labels on loop statements */
26295
118k
    label_name = JS_ATOM_NULL;
26296
118k
    if (is_label(s)) {
26297
526
        BlockEnv *be;
26298
26299
526
        label_name = JS_DupAtom(ctx, s->token.u.ident.atom);
26300
26301
581
        for (be = s->cur_func->top_break; be; be = be->prev) {
26302
55
            if (be->label_name == label_name) {
26303
0
                js_parse_error(s, "duplicate label name");
26304
0
                goto fail;
26305
0
            }
26306
55
        }
26307
26308
526
        if (next_token(s))
26309
0
            goto fail;
26310
526
        if (js_parse_expect(s, ':'))
26311
0
            goto fail;
26312
526
        if (s->token.val != TOK_FOR
26313
526
        &&  s->token.val != TOK_DO
26314
526
        &&  s->token.val != TOK_WHILE) {
26315
            /* labelled regular statement */
26316
461
            int label_break, mask;
26317
461
            BlockEnv break_entry;
26318
26319
461
            label_break = new_label(s);
26320
461
            push_break_entry(s->cur_func, &break_entry,
26321
461
                             label_name, label_break, -1, 0);
26322
461
            if (!(s->cur_func->js_mode & JS_MODE_STRICT) &&
26323
461
                (decl_mask & DECL_MASK_FUNC_WITH_LABEL)) {
26324
409
                mask = DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL;
26325
409
            } else {
26326
52
                mask = 0;
26327
52
            }
26328
461
            if (js_parse_statement_or_decl(s, mask))
26329
0
                goto fail;
26330
461
            emit_label(s, label_break);
26331
461
            pop_break_entry(s->cur_func);
26332
461
            goto done;
26333
461
        }
26334
526
    }
26335
26336
118k
    switch(tok = s->token.val) {
26337
4.70k
    case '{':
26338
4.70k
        if (js_parse_block(s))
26339
9
            goto fail;
26340
4.70k
        break;
26341
4.70k
    case TOK_RETURN:
26342
33
        if (s->cur_func->is_eval) {
26343
0
            js_parse_error(s, "return not in a function");
26344
0
            goto fail;
26345
0
        }
26346
33
        if (next_token(s))
26347
0
            goto fail;
26348
33
        if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) {
26349
33
            if (js_parse_expr(s))
26350
0
                goto fail;
26351
33
            emit_return(s, TRUE);
26352
33
        } else {
26353
0
            emit_return(s, FALSE);
26354
0
        }
26355
33
        if (js_parse_expect_semi(s))
26356
0
            goto fail;
26357
33
        break;
26358
120
    case TOK_THROW:
26359
120
        if (next_token(s))
26360
0
            goto fail;
26361
120
        if (s->got_lf) {
26362
0
            js_parse_error(s, "line terminator not allowed after throw");
26363
0
            goto fail;
26364
0
        }
26365
120
        if (js_parse_expr(s))
26366
0
            goto fail;
26367
120
        emit_op(s, OP_throw);
26368
120
        if (js_parse_expect_semi(s))
26369
0
            goto fail;
26370
120
        break;
26371
120
    case TOK_LET:
26372
3
    case TOK_CONST:
26373
3
    haslet:
26374
3
        if (!(decl_mask & DECL_MASK_OTHER)) {
26375
0
            js_parse_error(s, "lexical declarations can't appear in single-statement context");
26376
0
            goto fail;
26377
0
        }
26378
        /* fall thru */
26379
762
    case TOK_VAR:
26380
762
        if (next_token(s))
26381
0
            goto fail;
26382
762
        if (js_parse_var(s, TRUE, tok, FALSE))
26383
1
            goto fail;
26384
761
        if (js_parse_expect_semi(s))
26385
0
            goto fail;
26386
761
        break;
26387
761
    case TOK_IF:
26388
310
        {
26389
310
            int label1, label2, mask;
26390
310
            if (next_token(s))
26391
0
                goto fail;
26392
            /* create a new scope for `let f;if(1) function f(){}` */
26393
310
            push_scope(s);
26394
310
            set_eval_ret_undefined(s);
26395
310
            if (js_parse_expr_paren(s))
26396
0
                goto fail;
26397
310
            label1 = emit_goto(s, OP_if_false, -1);
26398
310
            if (s->cur_func->js_mode & JS_MODE_STRICT)
26399
40
                mask = 0;
26400
270
            else
26401
270
                mask = DECL_MASK_FUNC; /* Annex B.3.4 */
26402
26403
310
            if (js_parse_statement_or_decl(s, mask))
26404
0
                goto fail;
26405
26406
310
            if (s->token.val == TOK_ELSE) {
26407
0
                label2 = emit_goto(s, OP_goto, -1);
26408
0
                if (next_token(s))
26409
0
                    goto fail;
26410
26411
0
                emit_label(s, label1);
26412
0
                if (js_parse_statement_or_decl(s, mask))
26413
0
                    goto fail;
26414
26415
0
                label1 = label2;
26416
0
            }
26417
310
            emit_label(s, label1);
26418
310
            pop_scope(s);
26419
310
        }
26420
0
        break;
26421
540
    case TOK_WHILE:
26422
540
        {
26423
540
            int label_cont, label_break;
26424
540
            BlockEnv break_entry;
26425
26426
540
            label_cont = new_label(s);
26427
540
            label_break = new_label(s);
26428
26429
540
            push_break_entry(s->cur_func, &break_entry,
26430
540
                             label_name, label_break, label_cont, 0);
26431
26432
540
            if (next_token(s))
26433
0
                goto fail;
26434
26435
540
            set_eval_ret_undefined(s);
26436
26437
540
            emit_label(s, label_cont);
26438
540
            if (js_parse_expr_paren(s))
26439
0
                goto fail;
26440
540
            emit_goto(s, OP_if_false, label_break);
26441
26442
540
            if (js_parse_statement(s))
26443
0
                goto fail;
26444
540
            emit_goto(s, OP_goto, label_cont);
26445
26446
540
            emit_label(s, label_break);
26447
26448
540
            pop_break_entry(s->cur_func);
26449
540
        }
26450
0
        break;
26451
88
    case TOK_DO:
26452
88
        {
26453
88
            int label_cont, label_break, label1;
26454
88
            BlockEnv break_entry;
26455
26456
88
            label_cont = new_label(s);
26457
88
            label_break = new_label(s);
26458
88
            label1 = new_label(s);
26459
26460
88
            push_break_entry(s->cur_func, &break_entry,
26461
88
                             label_name, label_break, label_cont, 0);
26462
26463
88
            if (next_token(s))
26464
0
                goto fail;
26465
26466
88
            emit_label(s, label1);
26467
26468
88
            set_eval_ret_undefined(s);
26469
26470
88
            if (js_parse_statement(s))
26471
2
                goto fail;
26472
26473
86
            emit_label(s, label_cont);
26474
86
            if (js_parse_expect(s, TOK_WHILE))
26475
0
                goto fail;
26476
86
            if (js_parse_expr_paren(s))
26477
0
                goto fail;
26478
            /* Insert semicolon if missing */
26479
86
            if (s->token.val == ';') {
26480
33
                if (next_token(s))
26481
0
                    goto fail;
26482
33
            }
26483
86
            emit_goto(s, OP_if_true, label1);
26484
26485
86
            emit_label(s, label_break);
26486
26487
86
            pop_break_entry(s->cur_func);
26488
86
        }
26489
0
        break;
26490
280
    case TOK_FOR:
26491
280
        {
26492
280
            int label_cont, label_break, label_body, label_test;
26493
280
            int pos_cont, pos_body, block_scope_level;
26494
280
            BlockEnv break_entry;
26495
280
            int tok, bits;
26496
280
            BOOL is_async;
26497
26498
280
            if (next_token(s))
26499
0
                goto fail;
26500
26501
280
            set_eval_ret_undefined(s);
26502
280
            bits = 0;
26503
280
            is_async = FALSE;
26504
280
            if (s->token.val == '(') {
26505
280
                js_parse_skip_parens_token(s, &bits, FALSE);
26506
280
            } else if (s->token.val == TOK_AWAIT) {
26507
0
                if (!(s->cur_func->func_kind & JS_FUNC_ASYNC)) {
26508
0
                    js_parse_error(s, "for await is only valid in asynchronous functions");
26509
0
                    goto fail;
26510
0
                }
26511
0
                is_async = TRUE;
26512
0
                if (next_token(s))
26513
0
                    goto fail;
26514
0
            }
26515
280
            if (js_parse_expect(s, '('))
26516
0
                goto fail;
26517
26518
280
            if (!(bits & SKIP_HAS_SEMI)) {
26519
                /* parse for/in or for/of */
26520
268
                if (js_parse_for_in_of(s, label_name, is_async))
26521
3
                    goto fail;
26522
265
                break;
26523
268
            }
26524
12
            block_scope_level = s->cur_func->scope_level;
26525
26526
            /* create scope for the lexical variables declared in the initial,
26527
               test and increment expressions */
26528
12
            push_scope(s);
26529
            /* initial expression */
26530
12
            tok = s->token.val;
26531
12
            if (tok != ';') {
26532
3
                switch (is_let(s, DECL_MASK_OTHER)) {
26533
0
                case TRUE:
26534
0
                    tok = TOK_LET;
26535
0
                    break;
26536
3
                case FALSE:
26537
3
                    break;
26538
0
                default:
26539
0
                    goto fail;
26540
3
                }
26541
3
                if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
26542
3
                    if (next_token(s))
26543
0
                        goto fail;
26544
3
                    if (js_parse_var(s, FALSE, tok, FALSE))
26545
0
                        goto fail;
26546
3
                } else {
26547
0
                    if (js_parse_expr2(s, FALSE))
26548
0
                        goto fail;
26549
0
                    emit_op(s, OP_drop);
26550
0
                }
26551
26552
                /* close the closures before the first iteration */
26553
3
                close_scopes(s, s->cur_func->scope_level, block_scope_level);
26554
3
            }
26555
12
            if (js_parse_expect(s, ';'))
26556
0
                goto fail;
26557
26558
12
            label_test = new_label(s);
26559
12
            label_cont = new_label(s);
26560
12
            label_body = new_label(s);
26561
12
            label_break = new_label(s);
26562
26563
12
            push_break_entry(s->cur_func, &break_entry,
26564
12
                             label_name, label_break, label_cont, 0);
26565
26566
            /* test expression */
26567
12
            if (s->token.val == ';') {
26568
                /* no test expression */
26569
9
                label_test = label_body;
26570
9
            } else {
26571
3
                emit_label(s, label_test);
26572
3
                if (js_parse_expr(s))
26573
0
                    goto fail;
26574
3
                emit_goto(s, OP_if_false, label_break);
26575
3
            }
26576
12
            if (js_parse_expect(s, ';'))
26577
0
                goto fail;
26578
26579
12
            if (s->token.val == ')') {
26580
                /* no end expression */
26581
9
                break_entry.label_cont = label_cont = label_test;
26582
9
                pos_cont = 0; /* avoid warning */
26583
9
            } else {
26584
                /* skip the end expression */
26585
3
                emit_goto(s, OP_goto, label_body);
26586
26587
3
                pos_cont = s->cur_func->byte_code.size;
26588
3
                emit_label(s, label_cont);
26589
3
                if (js_parse_expr(s))
26590
0
                    goto fail;
26591
3
                emit_op(s, OP_drop);
26592
3
                if (label_test != label_body)
26593
3
                    emit_goto(s, OP_goto, label_test);
26594
3
            }
26595
12
            if (js_parse_expect(s, ')'))
26596
0
                goto fail;
26597
26598
12
            pos_body = s->cur_func->byte_code.size;
26599
12
            emit_label(s, label_body);
26600
12
            if (js_parse_statement(s))
26601
5
                goto fail;
26602
26603
            /* close the closures before the next iteration */
26604
            /* XXX: check continue case */
26605
7
            close_scopes(s, s->cur_func->scope_level, block_scope_level);
26606
26607
7
            if (OPTIMIZE && label_test != label_body && label_cont != label_test) {
26608
                /* move the increment code here */
26609
3
                DynBuf *bc = &s->cur_func->byte_code;
26610
3
                int chunk_size = pos_body - pos_cont;
26611
3
                int offset = bc->size - pos_cont;
26612
3
                int i;
26613
3
                dbuf_realloc(bc, bc->size + chunk_size);
26614
3
                dbuf_put(bc, bc->buf + pos_cont, chunk_size);
26615
3
                memset(bc->buf + pos_cont, OP_nop, chunk_size);
26616
                /* increment part ends with a goto */
26617
3
                s->cur_func->last_opcode_pos = bc->size - 5;
26618
                /* relocate labels */
26619
21
                for (i = label_cont; i < s->cur_func->label_count; i++) {
26620
18
                    LabelSlot *ls = &s->cur_func->label_slots[i];
26621
18
                    if (ls->pos >= pos_cont && ls->pos < pos_body)
26622
6
                        ls->pos += offset;
26623
18
                }
26624
4
            } else {
26625
4
                emit_goto(s, OP_goto, label_cont);
26626
4
            }
26627
26628
7
            emit_label(s, label_break);
26629
26630
7
            pop_break_entry(s->cur_func);
26631
7
            pop_scope(s);
26632
7
        }
26633
0
        break;
26634
0
    case TOK_BREAK:
26635
0
    case TOK_CONTINUE:
26636
0
        {
26637
0
            int is_cont = s->token.val - TOK_BREAK;
26638
0
            int label;
26639
26640
0
            if (next_token(s))
26641
0
                goto fail;
26642
0
            if (!s->got_lf && s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
26643
0
                label = s->token.u.ident.atom;
26644
0
            else
26645
0
                label = JS_ATOM_NULL;
26646
0
            if (emit_break(s, label, is_cont))
26647
0
                goto fail;
26648
0
            if (label != JS_ATOM_NULL) {
26649
0
                if (next_token(s))
26650
0
                    goto fail;
26651
0
            }
26652
0
            if (js_parse_expect_semi(s))
26653
0
                goto fail;
26654
0
        }
26655
0
        break;
26656
0
    case TOK_SWITCH:
26657
0
        {
26658
0
            int label_case, label_break, label1;
26659
0
            int default_label_pos;
26660
0
            BlockEnv break_entry;
26661
26662
0
            if (next_token(s))
26663
0
                goto fail;
26664
26665
0
            set_eval_ret_undefined(s);
26666
0
            if (js_parse_expr_paren(s))
26667
0
                goto fail;
26668
26669
0
            push_scope(s);
26670
0
            label_break = new_label(s);
26671
0
            push_break_entry(s->cur_func, &break_entry,
26672
0
                             label_name, label_break, -1, 1);
26673
26674
0
            if (js_parse_expect(s, '{'))
26675
0
                goto fail;
26676
26677
0
            default_label_pos = -1;
26678
0
            label_case = -1;
26679
0
            while (s->token.val != '}') {
26680
0
                if (s->token.val == TOK_CASE) {
26681
0
                    label1 = -1;
26682
0
                    if (label_case >= 0) {
26683
                        /* skip the case if needed */
26684
0
                        label1 = emit_goto(s, OP_goto, -1);
26685
0
                    }
26686
0
                    emit_label(s, label_case);
26687
0
                    label_case = -1;
26688
0
                    for (;;) {
26689
                        /* parse a sequence of case clauses */
26690
0
                        if (next_token(s))
26691
0
                            goto fail;
26692
0
                        emit_op(s, OP_dup);
26693
0
                        if (js_parse_expr(s))
26694
0
                            goto fail;
26695
0
                        if (js_parse_expect(s, ':'))
26696
0
                            goto fail;
26697
0
                        emit_op(s, OP_strict_eq);
26698
0
                        if (s->token.val == TOK_CASE) {
26699
0
                            label1 = emit_goto(s, OP_if_true, label1);
26700
0
                        } else {
26701
0
                            label_case = emit_goto(s, OP_if_false, -1);
26702
0
                            emit_label(s, label1);
26703
0
                            break;
26704
0
                        }
26705
0
                    }
26706
0
                } else if (s->token.val == TOK_DEFAULT) {
26707
0
                    if (next_token(s))
26708
0
                        goto fail;
26709
0
                    if (js_parse_expect(s, ':'))
26710
0
                        goto fail;
26711
0
                    if (default_label_pos >= 0) {
26712
0
                        js_parse_error(s, "duplicate default");
26713
0
                        goto fail;
26714
0
                    }
26715
0
                    if (label_case < 0) {
26716
                        /* falling thru direct from switch expression */
26717
0
                        label_case = emit_goto(s, OP_goto, -1);
26718
0
                    }
26719
                    /* Emit a dummy label opcode. Label will be patched after
26720
                       the end of the switch body. Do not use emit_label(s, 0)
26721
                       because it would clobber label 0 address, preventing
26722
                       proper optimizer operation.
26723
                     */
26724
0
                    emit_op(s, OP_label);
26725
0
                    emit_u32(s, 0);
26726
0
                    default_label_pos = s->cur_func->byte_code.size - 4;
26727
0
                } else {
26728
0
                    if (label_case < 0) {
26729
                        /* falling thru direct from switch expression */
26730
0
                        js_parse_error(s, "invalid switch statement");
26731
0
                        goto fail;
26732
0
                    }
26733
0
                    if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
26734
0
                        goto fail;
26735
0
                }
26736
0
            }
26737
0
            if (js_parse_expect(s, '}'))
26738
0
                goto fail;
26739
0
            if (default_label_pos >= 0) {
26740
                /* Ugly patch for the the `default` label, shameful and risky */
26741
0
                put_u32(s->cur_func->byte_code.buf + default_label_pos,
26742
0
                        label_case);
26743
0
                s->cur_func->label_slots[label_case].pos = default_label_pos + 4;
26744
0
            } else {
26745
0
                emit_label(s, label_case);
26746
0
            }
26747
0
            emit_label(s, label_break);
26748
0
            emit_op(s, OP_drop); /* drop the switch expression */
26749
26750
0
            pop_break_entry(s->cur_func);
26751
0
            pop_scope(s);
26752
0
        }
26753
0
        break;
26754
34
    case TOK_TRY:
26755
34
        {
26756
34
            int label_catch, label_catch2, label_finally, label_end;
26757
34
            JSAtom name;
26758
34
            BlockEnv block_env;
26759
26760
34
            set_eval_ret_undefined(s);
26761
34
            if (next_token(s))
26762
0
                goto fail;
26763
34
            label_catch = new_label(s);
26764
34
            label_catch2 = new_label(s);
26765
34
            label_finally = new_label(s);
26766
34
            label_end = new_label(s);
26767
26768
34
            emit_goto(s, OP_catch, label_catch);
26769
26770
34
            push_break_entry(s->cur_func, &block_env,
26771
34
                             JS_ATOM_NULL, -1, -1, 1);
26772
34
            block_env.label_finally = label_finally;
26773
26774
34
            if (js_parse_block(s))
26775
5
                goto fail;
26776
26777
29
            pop_break_entry(s->cur_func);
26778
26779
29
            if (js_is_live_code(s)) {
26780
                /* drop the catch offset */
26781
29
                emit_op(s, OP_drop);
26782
                /* must push dummy value to keep same stack size */
26783
29
                emit_op(s, OP_undefined);
26784
29
                emit_goto(s, OP_gosub, label_finally);
26785
29
                emit_op(s, OP_drop);
26786
26787
29
                emit_goto(s, OP_goto, label_end);
26788
29
            }
26789
26790
29
            if (s->token.val == TOK_CATCH) {
26791
29
                if (next_token(s))
26792
0
                    goto fail;
26793
26794
29
                push_scope(s);  /* catch variable */
26795
29
                emit_label(s, label_catch);
26796
26797
29
                if (s->token.val == '{') {
26798
                    /* support optional-catch-binding feature */
26799
0
                    emit_op(s, OP_drop);    /* pop the exception object */
26800
29
                } else {
26801
29
                    if (js_parse_expect(s, '('))
26802
0
                        goto fail;
26803
29
                    if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
26804
0
                        if (s->token.val == '[' || s->token.val == '{') {
26805
                            /* XXX: TOK_LET is not completely correct */
26806
0
                            if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE) < 0)
26807
0
                                goto fail;
26808
0
                        } else {
26809
0
                            js_parse_error(s, "identifier expected");
26810
0
                            goto fail;
26811
0
                        }
26812
29
                    } else {
26813
29
                        name = JS_DupAtom(ctx, s->token.u.ident.atom);
26814
29
                        if (next_token(s)
26815
29
                        ||  js_define_var(s, name, TOK_CATCH) < 0) {
26816
0
                            JS_FreeAtom(ctx, name);
26817
0
                            goto fail;
26818
0
                        }
26819
                        /* store the exception value in the catch variable */
26820
29
                        emit_op(s, OP_scope_put_var);
26821
29
                        emit_u32(s, name);
26822
29
                        emit_u16(s, s->cur_func->scope_level);
26823
29
                    }
26824
29
                    if (js_parse_expect(s, ')'))
26825
0
                        goto fail;
26826
29
                }
26827
                /* XXX: should keep the address to nop it out if there is no finally block */
26828
29
                emit_goto(s, OP_catch, label_catch2);
26829
26830
29
                push_scope(s);  /* catch block */
26831
29
                push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
26832
29
                                 -1, -1, 1);
26833
29
                block_env.label_finally = label_finally;
26834
26835
29
                if (js_parse_block(s))
26836
5
                    goto fail;
26837
26838
24
                pop_break_entry(s->cur_func);
26839
24
                pop_scope(s);  /* catch block */
26840
24
                pop_scope(s);  /* catch variable */
26841
26842
24
                if (js_is_live_code(s)) {
26843
                    /* drop the catch2 offset */
26844
24
                    emit_op(s, OP_drop);
26845
                    /* XXX: should keep the address to nop it out if there is no finally block */
26846
                    /* must push dummy value to keep same stack size */
26847
24
                    emit_op(s, OP_undefined);
26848
24
                    emit_goto(s, OP_gosub, label_finally);
26849
24
                    emit_op(s, OP_drop);
26850
24
                    emit_goto(s, OP_goto, label_end);
26851
24
                }
26852
                /* catch exceptions thrown in the catch block to execute the
26853
                 * finally clause and rethrow the exception */
26854
24
                emit_label(s, label_catch2);
26855
                /* catch value is at TOS, no need to push undefined */
26856
24
                emit_goto(s, OP_gosub, label_finally);
26857
24
                emit_op(s, OP_throw);
26858
26859
24
            } else if (s->token.val == TOK_FINALLY) {
26860
                /* finally without catch : execute the finally clause
26861
                 * and rethrow the exception */
26862
0
                emit_label(s, label_catch);
26863
                /* catch value is at TOS, no need to push undefined */
26864
0
                emit_goto(s, OP_gosub, label_finally);
26865
0
                emit_op(s, OP_throw);
26866
0
            } else {
26867
0
                js_parse_error(s, "expecting catch or finally");
26868
0
                goto fail;
26869
0
            }
26870
24
            emit_label(s, label_finally);
26871
24
            if (s->token.val == TOK_FINALLY) {
26872
0
                int saved_eval_ret_idx = 0; /* avoid warning */
26873
                
26874
0
                if (next_token(s))
26875
0
                    goto fail;
26876
                /* on the stack: ret_value gosub_ret_value */
26877
0
                push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
26878
0
                                 -1, -1, 2);
26879
26880
0
                if (s->cur_func->eval_ret_idx >= 0) {
26881
                    /* 'finally' updates eval_ret only if not a normal
26882
                       termination */
26883
0
                    saved_eval_ret_idx =
26884
0
                        add_var(s->ctx, s->cur_func, JS_ATOM__ret_);
26885
0
                    if (saved_eval_ret_idx < 0)
26886
0
                        goto fail;
26887
0
                    emit_op(s, OP_get_loc);
26888
0
                    emit_u16(s, s->cur_func->eval_ret_idx);
26889
0
                    emit_op(s, OP_put_loc);
26890
0
                    emit_u16(s, saved_eval_ret_idx);
26891
0
                    set_eval_ret_undefined(s);
26892
0
                }
26893
                
26894
0
                if (js_parse_block(s))
26895
0
                    goto fail;
26896
26897
0
                if (s->cur_func->eval_ret_idx >= 0) {
26898
0
                    emit_op(s, OP_get_loc);
26899
0
                    emit_u16(s, saved_eval_ret_idx);
26900
0
                    emit_op(s, OP_put_loc);
26901
0
                    emit_u16(s, s->cur_func->eval_ret_idx);
26902
0
                }
26903
0
                pop_break_entry(s->cur_func);
26904
0
            }
26905
24
            emit_op(s, OP_ret);
26906
24
            emit_label(s, label_end);
26907
24
        }
26908
0
        break;
26909
392
    case ';':
26910
        /* empty statement */
26911
392
        if (next_token(s))
26912
0
            goto fail;
26913
392
        break;
26914
853
    case TOK_WITH:
26915
853
        if (s->cur_func->js_mode & JS_MODE_STRICT) {
26916
0
            js_parse_error(s, "invalid keyword: with");
26917
0
            goto fail;
26918
853
        } else {
26919
853
            int with_idx;
26920
26921
853
            if (next_token(s))
26922
0
                goto fail;
26923
26924
853
            if (js_parse_expr_paren(s))
26925
0
                goto fail;
26926
26927
853
            push_scope(s);
26928
853
            with_idx = define_var(s, s->cur_func, JS_ATOM__with_,
26929
853
                                  JS_VAR_DEF_WITH);
26930
853
            if (with_idx < 0)
26931
0
                goto fail;
26932
853
            emit_op(s, OP_to_object);
26933
853
            emit_op(s, OP_put_loc);
26934
853
            emit_u16(s, with_idx);
26935
26936
853
            set_eval_ret_undefined(s);
26937
853
            if (js_parse_statement(s))
26938
9
                goto fail;
26939
26940
            /* Popping scope drops lexical context for the with object variable */
26941
844
            pop_scope(s);
26942
844
        }
26943
844
        break;
26944
844
    case TOK_FUNCTION:
26945
        /* ES6 Annex B.3.2 and B.3.3 semantics */
26946
478
        if (!(decl_mask & DECL_MASK_FUNC))
26947
0
            goto func_decl_error;
26948
478
        if (!(decl_mask & DECL_MASK_OTHER) && peek_token(s, FALSE) == '*')
26949
0
            goto func_decl_error;
26950
478
        goto parse_func_var;
26951
104k
    case TOK_IDENT:
26952
104k
        if (s->token.u.ident.is_reserved) {
26953
0
            js_parse_error_reserved_identifier(s);
26954
0
            goto fail;
26955
0
        }
26956
        /* Determine if `let` introduces a Declaration or an ExpressionStatement */
26957
104k
        switch (is_let(s, decl_mask)) {
26958
0
        case TRUE:
26959
0
            tok = TOK_LET;
26960
0
            goto haslet;
26961
104k
        case FALSE:
26962
104k
            break;
26963
0
        default:
26964
0
            goto fail;
26965
104k
        }
26966
104k
        if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
26967
104k
            peek_token(s, TRUE) == TOK_FUNCTION) {
26968
0
            if (!(decl_mask & DECL_MASK_OTHER)) {
26969
0
            func_decl_error:
26970
0
                js_parse_error(s, "function declarations can't appear in single-statement context");
26971
0
                goto fail;
26972
0
            }
26973
478
        parse_func_var:
26974
478
            if (js_parse_function_decl(s, JS_PARSE_FUNC_VAR,
26975
478
                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
26976
478
                                       s->token.ptr, s->token.line_num))
26977
2
                goto fail;
26978
476
            break;
26979
478
        }
26980
104k
        goto hasexpr;
26981
26982
104k
    case TOK_CLASS:
26983
5
        if (!(decl_mask & DECL_MASK_OTHER)) {
26984
0
            js_parse_error(s, "class declarations can't appear in single-statement context");
26985
0
            goto fail;
26986
0
        }
26987
5
        if (js_parse_class(s, FALSE, JS_PARSE_EXPORT_NONE))
26988
0
            return -1;
26989
5
        break;
26990
26991
5
    case TOK_DEBUGGER:
26992
        /* currently no debugger, so just skip the keyword */
26993
0
        if (next_token(s))
26994
0
            goto fail;
26995
0
        if (js_parse_expect_semi(s))
26996
0
            goto fail;
26997
0
        break;
26998
        
26999
0
    case TOK_ENUM:
27000
0
    case TOK_EXPORT:
27001
0
    case TOK_EXTENDS:
27002
0
        js_unsupported_keyword(s, s->token.u.ident.atom);
27003
0
        goto fail;
27004
27005
5.42k
    default:
27006
109k
    hasexpr:
27007
109k
        if (js_parse_expr(s))
27008
22
            goto fail;
27009
109k
        if (s->cur_func->eval_ret_idx >= 0) {
27010
            /* store the expression value so that it can be returned
27011
               by eval() */
27012
78.8k
            emit_op(s, OP_put_loc);
27013
78.8k
            emit_u16(s, s->cur_func->eval_ret_idx);
27014
78.8k
        } else {
27015
30.7k
            emit_op(s, OP_drop); /* drop the result */
27016
30.7k
        }
27017
109k
        if (js_parse_expect_semi(s))
27018
1
            goto fail;
27019
109k
        break;
27020
118k
    }
27021
118k
done:
27022
118k
    JS_FreeAtom(ctx, label_name);
27023
118k
    return 0;
27024
64
fail:
27025
64
    JS_FreeAtom(ctx, label_name);
27026
64
    return -1;
27027
118k
}
27028
27029
/* 'name' is freed */
27030
static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
27031
12
{
27032
12
    JSModuleDef *m;
27033
12
    m = js_mallocz(ctx, sizeof(*m));
27034
12
    if (!m) {
27035
0
        JS_FreeAtom(ctx, name);
27036
0
        return NULL;
27037
0
    }
27038
12
    m->header.ref_count = 1;
27039
12
    m->module_name = name;
27040
12
    m->module_ns = JS_UNDEFINED;
27041
12
    m->func_obj = JS_UNDEFINED;
27042
12
    m->eval_exception = JS_UNDEFINED;
27043
12
    m->meta_obj = JS_UNDEFINED;
27044
12
    list_add_tail(&m->link, &ctx->loaded_modules);
27045
12
    return m;
27046
12
}
27047
27048
static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
27049
                               JS_MarkFunc *mark_func)
27050
100
{
27051
100
    int i;
27052
27053
100
    for(i = 0; i < m->export_entries_count; i++) {
27054
0
        JSExportEntry *me = &m->export_entries[i];
27055
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL &&
27056
0
            me->u.local.var_ref) {
27057
0
            mark_func(rt, &me->u.local.var_ref->header);
27058
0
        }
27059
0
    }
27060
27061
100
    JS_MarkValue(rt, m->module_ns, mark_func);
27062
100
    JS_MarkValue(rt, m->func_obj, mark_func);
27063
100
    JS_MarkValue(rt, m->eval_exception, mark_func);
27064
100
    JS_MarkValue(rt, m->meta_obj, mark_func);
27065
100
}
27066
27067
static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
27068
9
{
27069
9
    int i;
27070
27071
9
    JS_FreeAtom(ctx, m->module_name);
27072
27073
9
    for(i = 0; i < m->req_module_entries_count; i++) {
27074
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
27075
0
        JS_FreeAtom(ctx, rme->module_name);
27076
0
    }
27077
9
    js_free(ctx, m->req_module_entries);
27078
27079
9
    for(i = 0; i < m->export_entries_count; i++) {
27080
0
        JSExportEntry *me = &m->export_entries[i];
27081
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL)
27082
0
            free_var_ref(ctx->rt, me->u.local.var_ref);
27083
0
        JS_FreeAtom(ctx, me->export_name);
27084
0
        JS_FreeAtom(ctx, me->local_name);
27085
0
    }
27086
9
    js_free(ctx, m->export_entries);
27087
27088
9
    js_free(ctx, m->star_export_entries);
27089
27090
9
    for(i = 0; i < m->import_entries_count; i++) {
27091
0
        JSImportEntry *mi = &m->import_entries[i];
27092
0
        JS_FreeAtom(ctx, mi->import_name);
27093
0
    }
27094
9
    js_free(ctx, m->import_entries);
27095
27096
9
    JS_FreeValue(ctx, m->module_ns);
27097
9
    JS_FreeValue(ctx, m->func_obj);
27098
9
    JS_FreeValue(ctx, m->eval_exception);
27099
9
    JS_FreeValue(ctx, m->meta_obj);
27100
9
    list_del(&m->link);
27101
9
    js_free(ctx, m);
27102
9
}
27103
27104
static int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
27105
                                JSAtom module_name)
27106
0
{
27107
0
    JSReqModuleEntry *rme;
27108
0
    int i;
27109
27110
    /* no need to add the module request if it is already present */
27111
0
    for(i = 0; i < m->req_module_entries_count; i++) {
27112
0
        rme = &m->req_module_entries[i];
27113
0
        if (rme->module_name == module_name)
27114
0
            return i;
27115
0
    }
27116
27117
0
    if (js_resize_array(ctx, (void **)&m->req_module_entries,
27118
0
                        sizeof(JSReqModuleEntry),
27119
0
                        &m->req_module_entries_size,
27120
0
                        m->req_module_entries_count + 1))
27121
0
        return -1;
27122
0
    rme = &m->req_module_entries[m->req_module_entries_count++];
27123
0
    rme->module_name = JS_DupAtom(ctx, module_name);
27124
0
    rme->module = NULL;
27125
0
    return i;
27126
0
}
27127
27128
static JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m,
27129
                                        JSAtom export_name)
27130
0
{
27131
0
    JSExportEntry *me;
27132
0
    int i;
27133
0
    for(i = 0; i < m->export_entries_count; i++) {
27134
0
        me = &m->export_entries[i];
27135
0
        if (me->export_name == export_name)
27136
0
            return me;
27137
0
    }
27138
0
    return NULL;
27139
0
}
27140
27141
static JSExportEntry *add_export_entry2(JSContext *ctx,
27142
                                        JSParseState *s, JSModuleDef *m,
27143
                                       JSAtom local_name, JSAtom export_name,
27144
                                       JSExportTypeEnum export_type)
27145
0
{
27146
0
    JSExportEntry *me;
27147
27148
0
    if (find_export_entry(ctx, m, export_name)) {
27149
0
        char buf1[ATOM_GET_STR_BUF_SIZE];
27150
0
        if (s) {
27151
0
            js_parse_error(s, "duplicate exported name '%s'",
27152
0
                           JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name));
27153
0
        } else {
27154
0
            JS_ThrowSyntaxErrorAtom(ctx, "duplicate exported name '%s'", export_name);
27155
0
        }
27156
0
        return NULL;
27157
0
    }
27158
27159
0
    if (js_resize_array(ctx, (void **)&m->export_entries,
27160
0
                        sizeof(JSExportEntry),
27161
0
                        &m->export_entries_size,
27162
0
                        m->export_entries_count + 1))
27163
0
        return NULL;
27164
0
    me = &m->export_entries[m->export_entries_count++];
27165
0
    memset(me, 0, sizeof(*me));
27166
0
    me->local_name = JS_DupAtom(ctx, local_name);
27167
0
    me->export_name = JS_DupAtom(ctx, export_name);
27168
0
    me->export_type = export_type;
27169
0
    return me;
27170
0
}
27171
27172
static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
27173
                                       JSAtom local_name, JSAtom export_name,
27174
                                       JSExportTypeEnum export_type)
27175
0
{
27176
0
    return add_export_entry2(s->ctx, s, m, local_name, export_name,
27177
0
                             export_type);
27178
0
}
27179
27180
static int add_star_export_entry(JSContext *ctx, JSModuleDef *m,
27181
                                 int req_module_idx)
27182
0
{
27183
0
    JSStarExportEntry *se;
27184
27185
0
    if (js_resize_array(ctx, (void **)&m->star_export_entries,
27186
0
                        sizeof(JSStarExportEntry),
27187
0
                        &m->star_export_entries_size,
27188
0
                        m->star_export_entries_count + 1))
27189
0
        return -1;
27190
0
    se = &m->star_export_entries[m->star_export_entries_count++];
27191
0
    se->req_module_idx = req_module_idx;
27192
0
    return 0;
27193
0
}
27194
27195
/* create a C module */
27196
JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
27197
                           JSModuleInitFunc *func)
27198
0
{
27199
0
    JSModuleDef *m;
27200
0
    JSAtom name;
27201
0
    name = JS_NewAtom(ctx, name_str);
27202
0
    if (name == JS_ATOM_NULL)
27203
0
        return NULL;
27204
0
    m = js_new_module_def(ctx, name);
27205
0
    m->init_func = func;
27206
0
    return m;
27207
0
}
27208
27209
int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name)
27210
0
{
27211
0
    JSExportEntry *me;
27212
0
    JSAtom name;
27213
0
    name = JS_NewAtom(ctx, export_name);
27214
0
    if (name == JS_ATOM_NULL)
27215
0
        return -1;
27216
0
    me = add_export_entry2(ctx, NULL, m, JS_ATOM_NULL, name,
27217
0
                           JS_EXPORT_TYPE_LOCAL);
27218
0
    JS_FreeAtom(ctx, name);
27219
0
    if (!me)
27220
0
        return -1;
27221
0
    else
27222
0
        return 0;
27223
0
}
27224
27225
int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
27226
                       JSValue val)
27227
0
{
27228
0
    JSExportEntry *me;
27229
0
    JSAtom name;
27230
0
    name = JS_NewAtom(ctx, export_name);
27231
0
    if (name == JS_ATOM_NULL)
27232
0
        goto fail;
27233
0
    me = find_export_entry(ctx, m, name);
27234
0
    JS_FreeAtom(ctx, name);
27235
0
    if (!me)
27236
0
        goto fail;
27237
0
    set_value(ctx, me->u.local.var_ref->pvalue, val);
27238
0
    return 0;
27239
0
 fail:
27240
0
    JS_FreeValue(ctx, val);
27241
0
    return -1;
27242
0
}
27243
27244
void JS_SetModuleLoaderFunc(JSRuntime *rt,
27245
                            JSModuleNormalizeFunc *module_normalize,
27246
                            JSModuleLoaderFunc *module_loader, void *opaque)
27247
2
{
27248
2
    rt->module_normalize_func = module_normalize;
27249
2
    rt->module_loader_func = module_loader;
27250
2
    rt->module_loader_opaque = opaque;
27251
2
}
27252
27253
/* default module filename normalizer */
27254
static char *js_default_module_normalize_name(JSContext *ctx,
27255
                                              const char *base_name,
27256
                                              const char *name)
27257
0
{
27258
0
    char *filename, *p;
27259
0
    const char *r;
27260
0
    int len;
27261
27262
0
    if (name[0] != '.') {
27263
        /* if no initial dot, the module name is not modified */
27264
0
        return js_strdup(ctx, name);
27265
0
    }
27266
27267
0
    p = strrchr(base_name, '/');
27268
0
    if (p)
27269
0
        len = p - base_name;
27270
0
    else
27271
0
        len = 0;
27272
27273
0
    filename = js_malloc(ctx, len + strlen(name) + 1 + 1);
27274
0
    if (!filename)
27275
0
        return NULL;
27276
0
    memcpy(filename, base_name, len);
27277
0
    filename[len] = '\0';
27278
27279
    /* we only normalize the leading '..' or '.' */
27280
0
    r = name;
27281
0
    for(;;) {
27282
0
        if (r[0] == '.' && r[1] == '/') {
27283
0
            r += 2;
27284
0
        } else if (r[0] == '.' && r[1] == '.' && r[2] == '/') {
27285
            /* remove the last path element of filename, except if "."
27286
               or ".." */
27287
0
            if (filename[0] == '\0')
27288
0
                break;
27289
0
            p = strrchr(filename, '/');
27290
0
            if (!p)
27291
0
                p = filename;
27292
0
            else
27293
0
                p++;
27294
0
            if (!strcmp(p, ".") || !strcmp(p, ".."))
27295
0
                break;
27296
0
            if (p > filename)
27297
0
                p--;
27298
0
            *p = '\0';
27299
0
            r += 3;
27300
0
        } else {
27301
0
            break;
27302
0
        }
27303
0
    }
27304
0
    if (filename[0] != '\0')
27305
0
        strcat(filename, "/");
27306
0
    strcat(filename, r);
27307
    //    printf("normalize: %s %s -> %s\n", base_name, name, filename);
27308
0
    return filename;
27309
0
}
27310
27311
static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name)
27312
0
{
27313
0
    struct list_head *el;
27314
0
    JSModuleDef *m;
27315
    
27316
    /* first look at the loaded modules */
27317
0
    list_for_each(el, &ctx->loaded_modules) {
27318
0
        m = list_entry(el, JSModuleDef, link);
27319
0
        if (m->module_name == name)
27320
0
            return m;
27321
0
    }
27322
0
    return NULL;
27323
0
}
27324
27325
/* return NULL in case of exception (e.g. module could not be loaded) */
27326
static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx,
27327
                                                    const char *base_cname,
27328
                                                    const char *cname1)
27329
0
{
27330
0
    JSRuntime *rt = ctx->rt;
27331
0
    JSModuleDef *m;
27332
0
    char *cname;
27333
0
    JSAtom module_name;
27334
27335
0
    if (!rt->module_normalize_func) {
27336
0
        cname = js_default_module_normalize_name(ctx, base_cname, cname1);
27337
0
    } else {
27338
0
        cname = rt->module_normalize_func(ctx, base_cname, cname1,
27339
0
                                          rt->module_loader_opaque);
27340
0
    }
27341
0
    if (!cname)
27342
0
        return NULL;
27343
27344
0
    module_name = JS_NewAtom(ctx, cname);
27345
0
    if (module_name == JS_ATOM_NULL) {
27346
0
        js_free(ctx, cname);
27347
0
        return NULL;
27348
0
    }
27349
27350
    /* first look at the loaded modules */
27351
0
    m = js_find_loaded_module(ctx, module_name);
27352
0
    if (m) {
27353
0
        js_free(ctx, cname);
27354
0
        JS_FreeAtom(ctx, module_name);
27355
0
        return m;
27356
0
    }
27357
27358
0
    JS_FreeAtom(ctx, module_name);
27359
27360
    /* load the module */
27361
0
    if (!rt->module_loader_func) {
27362
        /* XXX: use a syntax error ? */
27363
0
        JS_ThrowReferenceError(ctx, "could not load module '%s'",
27364
0
                               cname);
27365
0
        js_free(ctx, cname);
27366
0
        return NULL;
27367
0
    }
27368
27369
0
    m = rt->module_loader_func(ctx, cname, rt->module_loader_opaque);
27370
0
    js_free(ctx, cname);
27371
0
    return m;
27372
0
}
27373
27374
static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx,
27375
                                                    JSAtom base_module_name,
27376
                                                    JSAtom module_name1)
27377
0
{
27378
0
    const char *base_cname, *cname;
27379
0
    JSModuleDef *m;
27380
    
27381
0
    base_cname = JS_AtomToCString(ctx, base_module_name);
27382
0
    if (!base_cname)
27383
0
        return NULL;
27384
0
    cname = JS_AtomToCString(ctx, module_name1);
27385
0
    if (!cname) {
27386
0
        JS_FreeCString(ctx, base_cname);
27387
0
        return NULL;
27388
0
    }
27389
0
    m = js_host_resolve_imported_module(ctx, base_cname, cname);
27390
0
    JS_FreeCString(ctx, base_cname);
27391
0
    JS_FreeCString(ctx, cname);
27392
0
    return m;
27393
0
}
27394
27395
typedef struct JSResolveEntry {
27396
    JSModuleDef *module;
27397
    JSAtom name;
27398
} JSResolveEntry;
27399
27400
typedef struct JSResolveState {
27401
    JSResolveEntry *array;
27402
    int size;
27403
    int count;
27404
} JSResolveState;
27405
27406
static int find_resolve_entry(JSResolveState *s,
27407
                              JSModuleDef *m, JSAtom name)
27408
0
{
27409
0
    int i;
27410
0
    for(i = 0; i < s->count; i++) {
27411
0
        JSResolveEntry *re = &s->array[i];
27412
0
        if (re->module == m && re->name == name)
27413
0
            return i;
27414
0
    }
27415
0
    return -1;
27416
0
}
27417
27418
static int add_resolve_entry(JSContext *ctx, JSResolveState *s,
27419
                             JSModuleDef *m, JSAtom name)
27420
0
{
27421
0
    JSResolveEntry *re;
27422
27423
0
    if (js_resize_array(ctx, (void **)&s->array,
27424
0
                        sizeof(JSResolveEntry),
27425
0
                        &s->size, s->count + 1))
27426
0
        return -1;
27427
0
    re = &s->array[s->count++];
27428
0
    re->module = m;
27429
0
    re->name = JS_DupAtom(ctx, name);
27430
0
    return 0;
27431
0
}
27432
27433
typedef enum JSResolveResultEnum {
27434
    JS_RESOLVE_RES_EXCEPTION = -1, /* memory alloc error */
27435
    JS_RESOLVE_RES_FOUND = 0,
27436
    JS_RESOLVE_RES_NOT_FOUND,
27437
    JS_RESOLVE_RES_CIRCULAR,
27438
    JS_RESOLVE_RES_AMBIGUOUS,
27439
} JSResolveResultEnum;
27440
27441
static JSResolveResultEnum js_resolve_export1(JSContext *ctx,
27442
                                              JSModuleDef **pmodule,
27443
                                              JSExportEntry **pme,
27444
                                              JSModuleDef *m,
27445
                                              JSAtom export_name,
27446
                                              JSResolveState *s)
27447
0
{
27448
0
    JSExportEntry *me;
27449
27450
0
    *pmodule = NULL;
27451
0
    *pme = NULL;
27452
0
    if (find_resolve_entry(s, m, export_name) >= 0)
27453
0
        return JS_RESOLVE_RES_CIRCULAR;
27454
0
    if (add_resolve_entry(ctx, s, m, export_name) < 0)
27455
0
        return JS_RESOLVE_RES_EXCEPTION;
27456
0
    me = find_export_entry(ctx, m, export_name);
27457
0
    if (me) {
27458
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
27459
            /* local export */
27460
0
            *pmodule = m;
27461
0
            *pme = me;
27462
0
            return JS_RESOLVE_RES_FOUND;
27463
0
        } else {
27464
            /* indirect export */
27465
0
            JSModuleDef *m1;
27466
0
            m1 = m->req_module_entries[me->u.req_module_idx].module;
27467
0
            if (me->local_name == JS_ATOM__star_) {
27468
                /* export ns from */
27469
0
                *pmodule = m;
27470
0
                *pme = me;
27471
0
                return JS_RESOLVE_RES_FOUND;
27472
0
            } else {
27473
0
                return js_resolve_export1(ctx, pmodule, pme, m1,
27474
0
                                          me->local_name, s);
27475
0
            }
27476
0
        }
27477
0
    } else {
27478
0
        if (export_name != JS_ATOM_default) {
27479
            /* not found in direct or indirect exports: try star exports */
27480
0
            int i;
27481
27482
0
            for(i = 0; i < m->star_export_entries_count; i++) {
27483
0
                JSStarExportEntry *se = &m->star_export_entries[i];
27484
0
                JSModuleDef *m1, *res_m;
27485
0
                JSExportEntry *res_me;
27486
0
                JSResolveResultEnum ret;
27487
27488
0
                m1 = m->req_module_entries[se->req_module_idx].module;
27489
0
                ret = js_resolve_export1(ctx, &res_m, &res_me, m1,
27490
0
                                         export_name, s);
27491
0
                if (ret == JS_RESOLVE_RES_AMBIGUOUS ||
27492
0
                    ret == JS_RESOLVE_RES_EXCEPTION) {
27493
0
                    return ret;
27494
0
                } else if (ret == JS_RESOLVE_RES_FOUND) {
27495
0
                    if (*pme != NULL) {
27496
0
                        if (*pmodule != res_m ||
27497
0
                            res_me->local_name != (*pme)->local_name) {
27498
0
                            *pmodule = NULL;
27499
0
                            *pme = NULL;
27500
0
                            return JS_RESOLVE_RES_AMBIGUOUS;
27501
0
                        }
27502
0
                    } else {
27503
0
                        *pmodule = res_m;
27504
0
                        *pme = res_me;
27505
0
                    }
27506
0
                }
27507
0
            }
27508
0
            if (*pme != NULL)
27509
0
                return JS_RESOLVE_RES_FOUND;
27510
0
        }
27511
0
        return JS_RESOLVE_RES_NOT_FOUND;
27512
0
    }
27513
0
}
27514
27515
/* If the return value is JS_RESOLVE_RES_FOUND, return the module
27516
  (*pmodule) and the corresponding local export entry
27517
  (*pme). Otherwise return (NULL, NULL) */
27518
static JSResolveResultEnum js_resolve_export(JSContext *ctx,
27519
                                             JSModuleDef **pmodule,
27520
                                             JSExportEntry **pme,
27521
                                             JSModuleDef *m,
27522
                                             JSAtom export_name)
27523
0
{
27524
0
    JSResolveState ss, *s = &ss;
27525
0
    int i;
27526
0
    JSResolveResultEnum ret;
27527
27528
0
    s->array = NULL;
27529
0
    s->size = 0;
27530
0
    s->count = 0;
27531
27532
0
    ret = js_resolve_export1(ctx, pmodule, pme, m, export_name, s);
27533
27534
0
    for(i = 0; i < s->count; i++)
27535
0
        JS_FreeAtom(ctx, s->array[i].name);
27536
0
    js_free(ctx, s->array);
27537
27538
0
    return ret;
27539
0
}
27540
27541
static void js_resolve_export_throw_error(JSContext *ctx,
27542
                                          JSResolveResultEnum res,
27543
                                          JSModuleDef *m, JSAtom export_name)
27544
0
{
27545
0
    char buf1[ATOM_GET_STR_BUF_SIZE];
27546
0
    char buf2[ATOM_GET_STR_BUF_SIZE];
27547
0
    switch(res) {
27548
0
    case JS_RESOLVE_RES_EXCEPTION:
27549
0
        break;
27550
0
    default:
27551
0
    case JS_RESOLVE_RES_NOT_FOUND:
27552
0
        JS_ThrowSyntaxError(ctx, "Could not find export '%s' in module '%s'",
27553
0
                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
27554
0
                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
27555
0
        break;
27556
0
    case JS_RESOLVE_RES_CIRCULAR:
27557
0
        JS_ThrowSyntaxError(ctx, "circular reference when looking for export '%s' in module '%s'",
27558
0
                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
27559
0
                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
27560
0
        break;
27561
0
    case JS_RESOLVE_RES_AMBIGUOUS:
27562
0
        JS_ThrowSyntaxError(ctx, "export '%s' in module '%s' is ambiguous",
27563
0
                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
27564
0
                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
27565
0
        break;
27566
0
    }
27567
0
}
27568
27569
27570
typedef enum {
27571
    EXPORTED_NAME_AMBIGUOUS,
27572
    EXPORTED_NAME_NORMAL,
27573
    EXPORTED_NAME_NS,
27574
} ExportedNameEntryEnum;
27575
27576
typedef struct ExportedNameEntry {
27577
    JSAtom export_name;
27578
    ExportedNameEntryEnum export_type;
27579
    union {
27580
        JSExportEntry *me; /* using when the list is built */
27581
        JSVarRef *var_ref; /* EXPORTED_NAME_NORMAL */
27582
        JSModuleDef *module; /* for EXPORTED_NAME_NS */
27583
    } u;
27584
} ExportedNameEntry;
27585
27586
typedef struct GetExportNamesState {
27587
    JSModuleDef **modules;
27588
    int modules_size;
27589
    int modules_count;
27590
27591
    ExportedNameEntry *exported_names;
27592
    int exported_names_size;
27593
    int exported_names_count;
27594
} GetExportNamesState;
27595
27596
static int find_exported_name(GetExportNamesState *s, JSAtom name)
27597
0
{
27598
0
    int i;
27599
0
    for(i = 0; i < s->exported_names_count; i++) {
27600
0
        if (s->exported_names[i].export_name == name)
27601
0
            return i;
27602
0
    }
27603
0
    return -1;
27604
0
}
27605
27606
static __exception int get_exported_names(JSContext *ctx,
27607
                                          GetExportNamesState *s,
27608
                                          JSModuleDef *m, BOOL from_star)
27609
0
{
27610
0
    ExportedNameEntry *en;
27611
0
    int i, j;
27612
27613
    /* check circular reference */
27614
0
    for(i = 0; i < s->modules_count; i++) {
27615
0
        if (s->modules[i] == m)
27616
0
            return 0;
27617
0
    }
27618
0
    if (js_resize_array(ctx, (void **)&s->modules, sizeof(s->modules[0]),
27619
0
                        &s->modules_size, s->modules_count + 1))
27620
0
        return -1;
27621
0
    s->modules[s->modules_count++] = m;
27622
27623
0
    for(i = 0; i < m->export_entries_count; i++) {
27624
0
        JSExportEntry *me = &m->export_entries[i];
27625
0
        if (from_star && me->export_name == JS_ATOM_default)
27626
0
            continue;
27627
0
        j = find_exported_name(s, me->export_name);
27628
0
        if (j < 0) {
27629
0
            if (js_resize_array(ctx, (void **)&s->exported_names, sizeof(s->exported_names[0]),
27630
0
                                &s->exported_names_size,
27631
0
                                s->exported_names_count + 1))
27632
0
                return -1;
27633
0
            en = &s->exported_names[s->exported_names_count++];
27634
0
            en->export_name = me->export_name;
27635
            /* avoid a second lookup for simple module exports */
27636
0
            if (from_star || me->export_type != JS_EXPORT_TYPE_LOCAL)
27637
0
                en->u.me = NULL;
27638
0
            else
27639
0
                en->u.me = me;
27640
0
        } else {
27641
0
            en = &s->exported_names[j];
27642
0
            en->u.me = NULL;
27643
0
        }
27644
0
    }
27645
0
    for(i = 0; i < m->star_export_entries_count; i++) {
27646
0
        JSStarExportEntry *se = &m->star_export_entries[i];
27647
0
        JSModuleDef *m1;
27648
0
        m1 = m->req_module_entries[se->req_module_idx].module;
27649
0
        if (get_exported_names(ctx, s, m1, TRUE))
27650
0
            return -1;
27651
0
    }
27652
0
    return 0;
27653
0
}
27654
27655
/* Unfortunately, the spec gives a different behavior from GetOwnProperty ! */
27656
static int js_module_ns_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
27657
0
{
27658
0
    return (find_own_property1(JS_VALUE_GET_OBJ(obj), atom) != NULL);
27659
0
}
27660
27661
static const JSClassExoticMethods js_module_ns_exotic_methods = {
27662
    .has_property = js_module_ns_has,
27663
};
27664
27665
static int exported_names_cmp(const void *p1, const void *p2, void *opaque)
27666
0
{
27667
0
    JSContext *ctx = opaque;
27668
0
    const ExportedNameEntry *me1 = p1;
27669
0
    const ExportedNameEntry *me2 = p2;
27670
0
    JSValue str1, str2;
27671
0
    int ret;
27672
27673
    /* XXX: should avoid allocation memory in atom comparison */
27674
0
    str1 = JS_AtomToString(ctx, me1->export_name);
27675
0
    str2 = JS_AtomToString(ctx, me2->export_name);
27676
0
    if (JS_IsException(str1) || JS_IsException(str2)) {
27677
        /* XXX: raise an error ? */
27678
0
        ret = 0;
27679
0
    } else {
27680
0
        ret = js_string_compare(ctx, JS_VALUE_GET_STRING(str1),
27681
0
                                JS_VALUE_GET_STRING(str2));
27682
0
    }
27683
0
    JS_FreeValue(ctx, str1);
27684
0
    JS_FreeValue(ctx, str2);
27685
0
    return ret;
27686
0
}
27687
27688
static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m);
27689
27690
static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
27691
                                     void *opaque)
27692
0
{
27693
0
    JSModuleDef *m = opaque;
27694
0
    return js_get_module_ns(ctx, m);
27695
0
}
27696
27697
static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
27698
0
{
27699
0
    JSValue obj;
27700
0
    JSObject *p;
27701
0
    GetExportNamesState s_s, *s = &s_s;
27702
0
    int i, ret;
27703
0
    JSProperty *pr;
27704
27705
0
    obj = JS_NewObjectClass(ctx, JS_CLASS_MODULE_NS);
27706
0
    if (JS_IsException(obj))
27707
0
        return obj;
27708
0
    p = JS_VALUE_GET_OBJ(obj);
27709
27710
0
    memset(s, 0, sizeof(*s));
27711
0
    ret = get_exported_names(ctx, s, m, FALSE);
27712
0
    js_free(ctx, s->modules);
27713
0
    if (ret)
27714
0
        goto fail;
27715
27716
    /* Resolve the exported names. The ambiguous exports are removed */
27717
0
    for(i = 0; i < s->exported_names_count; i++) {
27718
0
        ExportedNameEntry *en = &s->exported_names[i];
27719
0
        JSResolveResultEnum res;
27720
0
        JSExportEntry *res_me;
27721
0
        JSModuleDef *res_m;
27722
27723
0
        if (en->u.me) {
27724
0
            res_me = en->u.me; /* fast case: no resolution needed */
27725
0
            res_m = m;
27726
0
            res = JS_RESOLVE_RES_FOUND;
27727
0
        } else {
27728
0
            res = js_resolve_export(ctx, &res_m, &res_me, m,
27729
0
                                    en->export_name);
27730
0
        }
27731
0
        if (res != JS_RESOLVE_RES_FOUND) {
27732
0
            if (res != JS_RESOLVE_RES_AMBIGUOUS) {
27733
0
                js_resolve_export_throw_error(ctx, res, m, en->export_name);
27734
0
                goto fail;
27735
0
            }
27736
0
            en->export_type = EXPORTED_NAME_AMBIGUOUS;
27737
0
        } else {
27738
0
            if (res_me->local_name == JS_ATOM__star_) {
27739
0
                en->export_type = EXPORTED_NAME_NS;
27740
0
                en->u.module = res_m->req_module_entries[res_me->u.req_module_idx].module;
27741
0
            } else {
27742
0
                en->export_type = EXPORTED_NAME_NORMAL;
27743
0
                if (res_me->u.local.var_ref) {
27744
0
                    en->u.var_ref = res_me->u.local.var_ref;
27745
0
                } else {
27746
0
                    JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
27747
0
                    p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
27748
0
                    en->u.var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
27749
0
                }
27750
0
            }
27751
0
        }
27752
0
    }
27753
27754
    /* sort the exported names */
27755
0
    rqsort(s->exported_names, s->exported_names_count,
27756
0
           sizeof(s->exported_names[0]), exported_names_cmp, ctx);
27757
27758
0
    for(i = 0; i < s->exported_names_count; i++) {
27759
0
        ExportedNameEntry *en = &s->exported_names[i];
27760
0
        switch(en->export_type) {
27761
0
        case EXPORTED_NAME_NORMAL:
27762
0
            {
27763
0
                JSVarRef *var_ref = en->u.var_ref;
27764
0
                pr = add_property(ctx, p, en->export_name,
27765
0
                                  JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
27766
0
                                  JS_PROP_VARREF);
27767
0
                if (!pr)
27768
0
                    goto fail;
27769
0
                var_ref->header.ref_count++;
27770
0
                pr->u.var_ref = var_ref;
27771
0
            }
27772
0
            break;
27773
0
        case EXPORTED_NAME_NS:
27774
            /* the exported namespace must be created on demand */
27775
0
            if (JS_DefineAutoInitProperty(ctx, obj,
27776
0
                                          en->export_name,
27777
0
                                          JS_AUTOINIT_ID_MODULE_NS,
27778
0
                                          en->u.module, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
27779
0
                goto fail;
27780
0
            break;
27781
0
        default:
27782
0
            break;
27783
0
        }
27784
0
    }
27785
27786
0
    js_free(ctx, s->exported_names);
27787
27788
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_toStringTag,
27789
0
                           JS_AtomToString(ctx, JS_ATOM_Module),
27790
0
                           0);
27791
27792
0
    p->extensible = FALSE;
27793
0
    return obj;
27794
0
 fail:
27795
0
    js_free(ctx, s->exported_names);
27796
0
    JS_FreeValue(ctx, obj);
27797
0
    return JS_EXCEPTION;
27798
0
}
27799
27800
static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m)
27801
0
{
27802
0
    if (JS_IsUndefined(m->module_ns)) {
27803
0
        JSValue val;
27804
0
        val = js_build_module_ns(ctx, m);
27805
0
        if (JS_IsException(val))
27806
0
            return JS_EXCEPTION;
27807
0
        m->module_ns = val;
27808
0
    }
27809
0
    return JS_DupValue(ctx, m->module_ns);
27810
0
}
27811
27812
/* Load all the required modules for module 'm' */
27813
static int js_resolve_module(JSContext *ctx, JSModuleDef *m)
27814
5
{
27815
5
    int i;
27816
5
    JSModuleDef *m1;
27817
27818
5
    if (m->resolved)
27819
0
        return 0;
27820
#ifdef DUMP_MODULE_RESOLVE
27821
    {
27822
        char buf1[ATOM_GET_STR_BUF_SIZE];
27823
        printf("resolving module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
27824
    }
27825
#endif
27826
5
    m->resolved = TRUE;
27827
    /* resolve each requested module */
27828
5
    for(i = 0; i < m->req_module_entries_count; i++) {
27829
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
27830
0
        m1 = js_host_resolve_imported_module_atom(ctx, m->module_name,
27831
0
                                                  rme->module_name);
27832
0
        if (!m1)
27833
0
            return -1;
27834
0
        rme->module = m1;
27835
        /* already done in js_host_resolve_imported_module() except if
27836
           the module was loaded with JS_EvalBinary() */
27837
0
        if (js_resolve_module(ctx, m1) < 0)
27838
0
            return -1;
27839
0
    }
27840
5
    return 0;
27841
5
}
27842
27843
static JSVarRef *js_create_module_var(JSContext *ctx, BOOL is_lexical)
27844
449
{
27845
449
    JSVarRef *var_ref;
27846
449
    var_ref = js_malloc(ctx, sizeof(JSVarRef));
27847
449
    if (!var_ref)
27848
0
        return NULL;
27849
449
    var_ref->header.ref_count = 1;
27850
449
    if (is_lexical)
27851
0
        var_ref->value = JS_UNINITIALIZED;
27852
449
    else
27853
449
        var_ref->value = JS_UNDEFINED;
27854
449
    var_ref->pvalue = &var_ref->value;
27855
449
    var_ref->is_detached = TRUE;
27856
449
    add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
27857
449
    return var_ref;
27858
449
}
27859
27860
/* Create the <eval> function associated with the module */
27861
static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
27862
2
{
27863
2
    JSFunctionBytecode *b;
27864
2
    int i;
27865
2
    JSVarRef **var_refs;
27866
2
    JSValue func_obj, bfunc;
27867
2
    JSObject *p;
27868
27869
2
    bfunc = m->func_obj;
27870
2
    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
27871
2
                                      JS_CLASS_BYTECODE_FUNCTION);
27872
27873
2
    if (JS_IsException(func_obj))
27874
0
        return -1;
27875
2
    b = JS_VALUE_GET_PTR(bfunc);
27876
27877
2
    p = JS_VALUE_GET_OBJ(func_obj);
27878
2
    p->u.func.function_bytecode = b;
27879
2
    b->header.ref_count++;
27880
2
    p->u.func.home_object = NULL;
27881
2
    p->u.func.var_refs = NULL;
27882
2
    if (b->closure_var_count) {
27883
2
        var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
27884
2
        if (!var_refs)
27885
0
            goto fail;
27886
2
        p->u.func.var_refs = var_refs;
27887
27888
        /* create the global variables. The other variables are
27889
           imported from other modules */
27890
451
        for(i = 0; i < b->closure_var_count; i++) {
27891
449
            JSClosureVar *cv = &b->closure_var[i];
27892
449
            JSVarRef *var_ref;
27893
449
            if (cv->is_local) {
27894
449
                var_ref = js_create_module_var(ctx, cv->is_lexical);
27895
449
                if (!var_ref)
27896
0
                    goto fail;
27897
#ifdef DUMP_MODULE_RESOLVE
27898
                printf("local %d: %p\n", i, var_ref);
27899
#endif
27900
449
                var_refs[i] = var_ref;
27901
449
            }
27902
449
        }
27903
2
    }
27904
2
    m->func_obj = func_obj;
27905
2
    JS_FreeValue(ctx, bfunc);
27906
2
    return 0;
27907
0
 fail:
27908
0
    JS_FreeValue(ctx, func_obj);
27909
0
    return -1;
27910
2
}
27911
27912
/* must be done before js_link_module() because of cyclic references */
27913
static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
27914
2
{
27915
2
    BOOL is_c_module;
27916
2
    int i;
27917
2
    JSVarRef *var_ref;
27918
    
27919
2
    if (m->func_created)
27920
0
        return 0;
27921
27922
2
    is_c_module = (m->init_func != NULL);
27923
27924
2
    if (is_c_module) {
27925
        /* initialize the exported variables */
27926
0
        for(i = 0; i < m->export_entries_count; i++) {
27927
0
            JSExportEntry *me = &m->export_entries[i];
27928
0
            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
27929
0
                var_ref = js_create_module_var(ctx, FALSE);
27930
0
                if (!var_ref)
27931
0
                    return -1;
27932
0
                me->u.local.var_ref = var_ref;
27933
0
            }
27934
0
        }
27935
2
    } else {
27936
2
        if (js_create_module_bytecode_function(ctx, m))
27937
0
            return -1;
27938
2
    }
27939
2
    m->func_created = TRUE;
27940
27941
    /* do it on the dependencies */
27942
    
27943
2
    for(i = 0; i < m->req_module_entries_count; i++) {
27944
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
27945
0
        if (js_create_module_function(ctx, rme->module) < 0)
27946
0
            return -1;
27947
0
    }
27948
27949
2
    return 0;
27950
2
}    
27951
27952
    
27953
/* Prepare a module to be executed by resolving all the imported
27954
   variables. */
27955
static int js_link_module(JSContext *ctx, JSModuleDef *m)
27956
2
{
27957
2
    int i;
27958
2
    JSImportEntry *mi;
27959
2
    JSModuleDef *m1;
27960
2
    JSVarRef **var_refs, *var_ref;
27961
2
    JSObject *p;
27962
2
    BOOL is_c_module;
27963
2
    JSValue ret_val;
27964
    
27965
2
    if (m->instantiated)
27966
0
        return 0;
27967
2
    m->instantiated = TRUE;
27968
27969
#ifdef DUMP_MODULE_RESOLVE
27970
    {
27971
        char buf1[ATOM_GET_STR_BUF_SIZE];
27972
        printf("start instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
27973
    }
27974
#endif
27975
27976
2
    for(i = 0; i < m->req_module_entries_count; i++) {
27977
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
27978
0
        if (js_link_module(ctx, rme->module) < 0)
27979
0
            goto fail;
27980
0
    }
27981
27982
#ifdef DUMP_MODULE_RESOLVE
27983
    {
27984
        char buf1[ATOM_GET_STR_BUF_SIZE];
27985
        printf("instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
27986
    }
27987
#endif
27988
    /* check the indirect exports */
27989
2
    for(i = 0; i < m->export_entries_count; i++) {
27990
0
        JSExportEntry *me = &m->export_entries[i];
27991
0
        if (me->export_type == JS_EXPORT_TYPE_INDIRECT &&
27992
0
            me->local_name != JS_ATOM__star_) {
27993
0
            JSResolveResultEnum ret;
27994
0
            JSExportEntry *res_me;
27995
0
            JSModuleDef *res_m, *m1;
27996
0
            m1 = m->req_module_entries[me->u.req_module_idx].module;
27997
0
            ret = js_resolve_export(ctx, &res_m, &res_me, m1, me->local_name);
27998
0
            if (ret != JS_RESOLVE_RES_FOUND) {
27999
0
                js_resolve_export_throw_error(ctx, ret, m, me->export_name);
28000
0
                goto fail;
28001
0
            }
28002
0
        }
28003
0
    }
28004
28005
#ifdef DUMP_MODULE_RESOLVE
28006
    {
28007
        printf("exported bindings:\n");
28008
        for(i = 0; i < m->export_entries_count; i++) {
28009
            JSExportEntry *me = &m->export_entries[i];
28010
            printf(" name="); print_atom(ctx, me->export_name);
28011
            printf(" local="); print_atom(ctx, me->local_name);
28012
            printf(" type=%d idx=%d\n", me->export_type, me->u.local.var_idx);
28013
        }
28014
    }
28015
#endif
28016
28017
2
    is_c_module = (m->init_func != NULL);
28018
28019
2
    if (!is_c_module) {
28020
2
        p = JS_VALUE_GET_OBJ(m->func_obj);
28021
2
        var_refs = p->u.func.var_refs;
28022
28023
2
        for(i = 0; i < m->import_entries_count; i++) {
28024
0
            mi = &m->import_entries[i];
28025
#ifdef DUMP_MODULE_RESOLVE
28026
            printf("import var_idx=%d name=", mi->var_idx);
28027
            print_atom(ctx, mi->import_name);
28028
            printf(": ");
28029
#endif
28030
0
            m1 = m->req_module_entries[mi->req_module_idx].module;
28031
0
            if (mi->import_name == JS_ATOM__star_) {
28032
0
                JSValue val;
28033
                /* name space import */
28034
0
                val = js_get_module_ns(ctx, m1);
28035
0
                if (JS_IsException(val))
28036
0
                    goto fail;
28037
0
                set_value(ctx, &var_refs[mi->var_idx]->value, val);
28038
#ifdef DUMP_MODULE_RESOLVE
28039
                printf("namespace\n");
28040
#endif
28041
0
            } else {
28042
0
                JSResolveResultEnum ret;
28043
0
                JSExportEntry *res_me;
28044
0
                JSModuleDef *res_m;
28045
0
                JSObject *p1;
28046
28047
0
                ret = js_resolve_export(ctx, &res_m,
28048
0
                                        &res_me, m1, mi->import_name);
28049
0
                if (ret != JS_RESOLVE_RES_FOUND) {
28050
0
                    js_resolve_export_throw_error(ctx, ret, m1, mi->import_name);
28051
0
                    goto fail;
28052
0
                }
28053
0
                if (res_me->local_name == JS_ATOM__star_) {
28054
0
                    JSValue val;
28055
0
                    JSModuleDef *m2;
28056
                    /* name space import from */
28057
0
                    m2 = res_m->req_module_entries[res_me->u.req_module_idx].module;
28058
0
                    val = js_get_module_ns(ctx, m2);
28059
0
                    if (JS_IsException(val))
28060
0
                        goto fail;
28061
0
                    var_ref = js_create_module_var(ctx, TRUE);
28062
0
                    if (!var_ref) {
28063
0
                        JS_FreeValue(ctx, val);
28064
0
                        goto fail;
28065
0
                    }
28066
0
                    set_value(ctx, &var_ref->value, val);
28067
0
                    var_refs[mi->var_idx] = var_ref;
28068
#ifdef DUMP_MODULE_RESOLVE
28069
                    printf("namespace from\n");
28070
#endif
28071
0
                } else {
28072
0
                    var_ref = res_me->u.local.var_ref;
28073
0
                    if (!var_ref) {
28074
0
                        p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
28075
0
                        var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
28076
0
                    }
28077
0
                    var_ref->header.ref_count++;
28078
0
                    var_refs[mi->var_idx] = var_ref;
28079
#ifdef DUMP_MODULE_RESOLVE
28080
                    printf("local export (var_ref=%p)\n", var_ref);
28081
#endif
28082
0
                }
28083
0
            }
28084
0
        }
28085
28086
        /* keep the exported variables in the module export entries (they
28087
           are used when the eval function is deleted and cannot be
28088
           initialized before in case imports are exported) */
28089
2
        for(i = 0; i < m->export_entries_count; i++) {
28090
0
            JSExportEntry *me = &m->export_entries[i];
28091
0
            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
28092
0
                var_ref = var_refs[me->u.local.var_idx];
28093
0
                var_ref->header.ref_count++;
28094
0
                me->u.local.var_ref = var_ref;
28095
0
            }
28096
0
        }
28097
28098
        /* initialize the global variables */
28099
2
        ret_val = JS_Call(ctx, m->func_obj, JS_TRUE, 0, NULL);
28100
2
        if (JS_IsException(ret_val))
28101
0
            goto fail;
28102
2
        JS_FreeValue(ctx, ret_val);
28103
2
    }
28104
28105
#ifdef DUMP_MODULE_RESOLVE
28106
    printf("done instantiate\n");
28107
#endif
28108
2
    return 0;
28109
0
 fail:
28110
0
    return -1;
28111
2
}
28112
28113
/* return JS_ATOM_NULL if the name cannot be found. Only works with
28114
   not striped bytecode functions. */
28115
JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
28116
81.9k
{
28117
81.9k
    JSStackFrame *sf;
28118
81.9k
    JSFunctionBytecode *b;
28119
81.9k
    JSObject *p;
28120
    /* XXX: currently we just use the filename of the englobing
28121
       function. It does not work for eval(). Need to add a
28122
       ScriptOrModule info in JSFunctionBytecode */
28123
81.9k
    sf = ctx->rt->current_stack_frame;
28124
81.9k
    if (!sf)
28125
0
        return JS_ATOM_NULL;
28126
81.9k
    while (n_stack_levels-- > 0) {
28127
0
        sf = sf->prev_frame;
28128
0
        if (!sf)
28129
0
            return JS_ATOM_NULL;
28130
0
    }
28131
81.9k
    if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT)
28132
0
        return JS_ATOM_NULL;
28133
81.9k
    p = JS_VALUE_GET_OBJ(sf->cur_func);
28134
81.9k
    if (!js_class_has_bytecode(p->class_id))
28135
0
        return JS_ATOM_NULL;
28136
81.9k
    b = p->u.func.function_bytecode;
28137
81.9k
    if (!b->has_debug)
28138
0
        return JS_ATOM_NULL;
28139
81.9k
    return JS_DupAtom(ctx, b->debug.filename);
28140
81.9k
}
28141
28142
JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m)
28143
2
{
28144
2
    return JS_DupAtom(ctx, m->module_name);
28145
2
}
28146
28147
JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m)
28148
2
{
28149
2
    JSValue obj;
28150
    /* allocate meta_obj only if requested to save memory */
28151
2
    obj = m->meta_obj;
28152
2
    if (JS_IsUndefined(obj)) {
28153
2
        obj = JS_NewObjectProto(ctx, JS_NULL);
28154
2
        if (JS_IsException(obj))
28155
0
            return JS_EXCEPTION;
28156
2
        m->meta_obj = obj;
28157
2
    }
28158
2
    return JS_DupValue(ctx, obj);
28159
2
}
28160
28161
static JSValue js_import_meta(JSContext *ctx)
28162
0
{
28163
0
    JSAtom filename;
28164
0
    JSModuleDef *m;
28165
    
28166
0
    filename = JS_GetScriptOrModuleName(ctx, 0);
28167
0
    if (filename == JS_ATOM_NULL)
28168
0
        goto fail;
28169
28170
    /* XXX: inefficient, need to add a module or script pointer in
28171
       JSFunctionBytecode */
28172
0
    m = js_find_loaded_module(ctx, filename);
28173
0
    JS_FreeAtom(ctx, filename);
28174
0
    if (!m) {
28175
0
    fail:
28176
0
        JS_ThrowTypeError(ctx, "import.meta not supported in this context");
28177
0
        return JS_EXCEPTION;
28178
0
    }
28179
0
    return JS_GetImportMeta(ctx, m);
28180
0
}
28181
28182
/* used by os.Worker() and import() */
28183
JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
28184
                          const char *filename)
28185
0
{
28186
0
    JSModuleDef *m;
28187
0
    JSValue ret, func_obj;
28188
    
28189
0
    m = js_host_resolve_imported_module(ctx, basename, filename);
28190
0
    if (!m)
28191
0
        return NULL;
28192
    
28193
0
    if (js_resolve_module(ctx, m) < 0) {
28194
0
        js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
28195
0
        return NULL;
28196
0
    }
28197
28198
    /* Evaluate the module code */
28199
0
    func_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
28200
0
    ret = JS_EvalFunction(ctx, func_obj);
28201
0
    if (JS_IsException(ret))
28202
0
        return NULL;
28203
0
    JS_FreeValue(ctx, ret);
28204
0
    return m;
28205
0
}
28206
28207
static JSValue js_dynamic_import_job(JSContext *ctx,
28208
                                     int argc, JSValueConst *argv)
28209
0
{
28210
0
    JSValueConst *resolving_funcs = argv;
28211
0
    JSValueConst basename_val = argv[2];
28212
0
    JSValueConst specifier = argv[3];
28213
0
    JSModuleDef *m;
28214
0
    const char *basename = NULL, *filename;
28215
0
    JSValue ret, err, ns;
28216
28217
0
    if (!JS_IsString(basename_val)) {
28218
0
        JS_ThrowTypeError(ctx, "no function filename for import()");
28219
0
        goto exception;
28220
0
    }
28221
0
    basename = JS_ToCString(ctx, basename_val);
28222
0
    if (!basename)
28223
0
        goto exception;
28224
28225
0
    filename = JS_ToCString(ctx, specifier);
28226
0
    if (!filename)
28227
0
        goto exception;
28228
                     
28229
0
    m = JS_RunModule(ctx, basename, filename);
28230
0
    JS_FreeCString(ctx, filename);
28231
0
    if (!m)
28232
0
        goto exception;
28233
28234
    /* return the module namespace */
28235
0
    ns = js_get_module_ns(ctx, m);
28236
0
    if (JS_IsException(ns))
28237
0
        goto exception;
28238
28239
0
    ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
28240
0
                   1, (JSValueConst *)&ns);
28241
0
    JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
28242
0
    JS_FreeValue(ctx, ns);
28243
0
    JS_FreeCString(ctx, basename);
28244
0
    return JS_UNDEFINED;
28245
0
 exception:
28246
28247
0
    err = JS_GetException(ctx);
28248
0
    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
28249
0
                   1, (JSValueConst *)&err);
28250
0
    JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
28251
0
    JS_FreeValue(ctx, err);
28252
0
    JS_FreeCString(ctx, basename);
28253
0
    return JS_UNDEFINED;
28254
0
}
28255
28256
static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
28257
81.9k
{
28258
81.9k
    JSAtom basename;
28259
81.9k
    JSValue promise, resolving_funcs[2], basename_val;
28260
81.9k
    JSValueConst args[4];
28261
28262
81.9k
    basename = JS_GetScriptOrModuleName(ctx, 0);
28263
81.9k
    if (basename == JS_ATOM_NULL)
28264
0
        basename_val = JS_NULL;
28265
81.9k
    else
28266
81.9k
        basename_val = JS_AtomToValue(ctx, basename);
28267
81.9k
    JS_FreeAtom(ctx, basename);
28268
81.9k
    if (JS_IsException(basename_val))
28269
0
        return basename_val;
28270
    
28271
81.9k
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
28272
81.9k
    if (JS_IsException(promise)) {
28273
0
        JS_FreeValue(ctx, basename_val);
28274
0
        return promise;
28275
0
    }
28276
28277
81.9k
    args[0] = resolving_funcs[0];
28278
81.9k
    args[1] = resolving_funcs[1];
28279
81.9k
    args[2] = basename_val;
28280
81.9k
    args[3] = specifier;
28281
    
28282
81.9k
    JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args);
28283
28284
81.9k
    JS_FreeValue(ctx, basename_val);
28285
81.9k
    JS_FreeValue(ctx, resolving_funcs[0]);
28286
81.9k
    JS_FreeValue(ctx, resolving_funcs[1]);
28287
81.9k
    return promise;
28288
81.9k
}
28289
28290
/* Run the <eval> function of the module and of all its requested
28291
   modules. */
28292
static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
28293
2
{
28294
2
    JSModuleDef *m1;
28295
2
    int i;
28296
2
    JSValue ret_val;
28297
28298
2
    if (m->eval_mark)
28299
0
        return JS_UNDEFINED; /* avoid cycles */
28300
28301
2
    if (m->evaluated) {
28302
        /* if the module was already evaluated, rethrow the exception
28303
           it raised */
28304
0
        if (m->eval_has_exception) {
28305
0
            return JS_Throw(ctx, JS_DupValue(ctx, m->eval_exception));
28306
0
        } else {
28307
0
            return JS_UNDEFINED;
28308
0
        }
28309
0
    }
28310
28311
2
    m->eval_mark = TRUE;
28312
28313
2
    for(i = 0; i < m->req_module_entries_count; i++) {
28314
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
28315
0
        m1 = rme->module;
28316
0
        if (!m1->eval_mark) {
28317
0
            ret_val = js_evaluate_module(ctx, m1);
28318
0
            if (JS_IsException(ret_val)) {
28319
0
                m->eval_mark = FALSE;
28320
0
                return ret_val;
28321
0
            }
28322
0
            JS_FreeValue(ctx, ret_val);
28323
0
        }
28324
0
    }
28325
28326
2
    if (m->init_func) {
28327
        /* C module init */
28328
0
        if (m->init_func(ctx, m) < 0)
28329
0
            ret_val = JS_EXCEPTION;
28330
0
        else
28331
0
            ret_val = JS_UNDEFINED;
28332
2
    } else {
28333
2
        ret_val = JS_CallFree(ctx, m->func_obj, JS_UNDEFINED, 0, NULL);
28334
2
        m->func_obj = JS_UNDEFINED;
28335
2
    }
28336
2
    if (JS_IsException(ret_val)) {
28337
        /* save the thrown exception value */
28338
2
        m->eval_has_exception = TRUE;
28339
2
        m->eval_exception = JS_DupValue(ctx, ctx->rt->current_exception);
28340
2
    }
28341
2
    m->eval_mark = FALSE;
28342
2
    m->evaluated = TRUE;
28343
2
    return ret_val;
28344
2
}
28345
28346
static __exception JSAtom js_parse_from_clause(JSParseState *s)
28347
0
{
28348
0
    JSAtom module_name;
28349
0
    if (!token_is_pseudo_keyword(s, JS_ATOM_from)) {
28350
0
        js_parse_error(s, "from clause expected");
28351
0
        return JS_ATOM_NULL;
28352
0
    }
28353
0
    if (next_token(s))
28354
0
        return JS_ATOM_NULL;
28355
0
    if (s->token.val != TOK_STRING) {
28356
0
        js_parse_error(s, "string expected");
28357
0
        return JS_ATOM_NULL;
28358
0
    }
28359
0
    module_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
28360
0
    if (module_name == JS_ATOM_NULL)
28361
0
        return JS_ATOM_NULL;
28362
0
    if (next_token(s)) {
28363
0
        JS_FreeAtom(s->ctx, module_name);
28364
0
        return JS_ATOM_NULL;
28365
0
    }
28366
0
    return module_name;
28367
0
}
28368
28369
static __exception int js_parse_export(JSParseState *s)
28370
0
{
28371
0
    JSContext *ctx = s->ctx;
28372
0
    JSModuleDef *m = s->cur_func->module;
28373
0
    JSAtom local_name, export_name;
28374
0
    int first_export, idx, i, tok;
28375
0
    JSAtom module_name;
28376
0
    JSExportEntry *me;
28377
28378
0
    if (next_token(s))
28379
0
        return -1;
28380
28381
0
    tok = s->token.val;
28382
0
    if (tok == TOK_CLASS) {
28383
0
        return js_parse_class(s, FALSE, JS_PARSE_EXPORT_NAMED);
28384
0
    } else if (tok == TOK_FUNCTION ||
28385
0
               (token_is_pseudo_keyword(s, JS_ATOM_async) &&
28386
0
                peek_token(s, TRUE) == TOK_FUNCTION)) {
28387
0
        return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
28388
0
                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
28389
0
                                       s->token.ptr, s->token.line_num,
28390
0
                                       JS_PARSE_EXPORT_NAMED, NULL);
28391
0
    }
28392
28393
0
    if (next_token(s))
28394
0
        return -1;
28395
28396
0
    switch(tok) {
28397
0
    case '{':
28398
0
        first_export = m->export_entries_count;
28399
0
        while (s->token.val != '}') {
28400
0
            if (!token_is_ident(s->token.val)) {
28401
0
                js_parse_error(s, "identifier expected");
28402
0
                return -1;
28403
0
            }
28404
0
            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28405
0
            export_name = JS_ATOM_NULL;
28406
0
            if (next_token(s))
28407
0
                goto fail;
28408
0
            if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
28409
0
                if (next_token(s))
28410
0
                    goto fail;
28411
0
                if (!token_is_ident(s->token.val)) {
28412
0
                    js_parse_error(s, "identifier expected");
28413
0
                    goto fail;
28414
0
                }
28415
0
                export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28416
0
                if (next_token(s)) {
28417
0
                fail:
28418
0
                    JS_FreeAtom(ctx, local_name);
28419
0
                fail1:
28420
0
                    JS_FreeAtom(ctx, export_name);
28421
0
                    return -1;
28422
0
                }
28423
0
            } else {
28424
0
                export_name = JS_DupAtom(ctx, local_name);
28425
0
            }
28426
0
            me = add_export_entry(s, m, local_name, export_name,
28427
0
                                  JS_EXPORT_TYPE_LOCAL);
28428
0
            JS_FreeAtom(ctx, local_name);
28429
0
            JS_FreeAtom(ctx, export_name);
28430
0
            if (!me)
28431
0
                return -1;
28432
0
            if (s->token.val != ',')
28433
0
                break;
28434
0
            if (next_token(s))
28435
0
                return -1;
28436
0
        }
28437
0
        if (js_parse_expect(s, '}'))
28438
0
            return -1;
28439
0
        if (token_is_pseudo_keyword(s, JS_ATOM_from)) {
28440
0
            module_name = js_parse_from_clause(s);
28441
0
            if (module_name == JS_ATOM_NULL)
28442
0
                return -1;
28443
0
            idx = add_req_module_entry(ctx, m, module_name);
28444
0
            JS_FreeAtom(ctx, module_name);
28445
0
            if (idx < 0)
28446
0
                return -1;
28447
0
            for(i = first_export; i < m->export_entries_count; i++) {
28448
0
                me = &m->export_entries[i];
28449
0
                me->export_type = JS_EXPORT_TYPE_INDIRECT;
28450
0
                me->u.req_module_idx = idx;
28451
0
            }
28452
0
        }
28453
0
        break;
28454
0
    case '*':
28455
0
        if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
28456
            /* export ns from */
28457
0
            if (next_token(s))
28458
0
                return -1;
28459
0
            if (!token_is_ident(s->token.val)) {
28460
0
                js_parse_error(s, "identifier expected");
28461
0
                return -1;
28462
0
            }
28463
0
            export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28464
0
            if (next_token(s))
28465
0
                goto fail1;
28466
0
            module_name = js_parse_from_clause(s);
28467
0
            if (module_name == JS_ATOM_NULL)
28468
0
                goto fail1;
28469
0
            idx = add_req_module_entry(ctx, m, module_name);
28470
0
            JS_FreeAtom(ctx, module_name);
28471
0
            if (idx < 0)
28472
0
                goto fail1;
28473
0
            me = add_export_entry(s, m, JS_ATOM__star_, export_name,
28474
0
                                  JS_EXPORT_TYPE_INDIRECT);
28475
0
            JS_FreeAtom(ctx, export_name);
28476
0
            if (!me)
28477
0
                return -1;
28478
0
            me->u.req_module_idx = idx;
28479
0
        } else {
28480
0
            module_name = js_parse_from_clause(s);
28481
0
            if (module_name == JS_ATOM_NULL)
28482
0
                return -1;
28483
0
            idx = add_req_module_entry(ctx, m, module_name);
28484
0
            JS_FreeAtom(ctx, module_name);
28485
0
            if (idx < 0)
28486
0
                return -1;
28487
0
            if (add_star_export_entry(ctx, m, idx) < 0)
28488
0
                return -1;
28489
0
        }
28490
0
        break;
28491
0
    case TOK_DEFAULT:
28492
0
        if (s->token.val == TOK_CLASS) {
28493
0
            return js_parse_class(s, FALSE, JS_PARSE_EXPORT_DEFAULT);
28494
0
        } else if (s->token.val == TOK_FUNCTION ||
28495
0
                   (token_is_pseudo_keyword(s, JS_ATOM_async) &&
28496
0
                    peek_token(s, TRUE) == TOK_FUNCTION)) {
28497
0
            return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
28498
0
                                           JS_FUNC_NORMAL, JS_ATOM_NULL,
28499
0
                                           s->token.ptr, s->token.line_num,
28500
0
                                           JS_PARSE_EXPORT_DEFAULT, NULL);
28501
0
        } else {
28502
0
            if (js_parse_assign_expr(s))
28503
0
                return -1;
28504
0
        }
28505
        /* set the name of anonymous functions */
28506
0
        set_object_name(s, JS_ATOM_default);
28507
28508
        /* store the value in the _default_ global variable and export
28509
           it */
28510
0
        local_name = JS_ATOM__default_;
28511
0
        if (define_var(s, s->cur_func, local_name, JS_VAR_DEF_LET) < 0)
28512
0
            return -1;
28513
0
        emit_op(s, OP_scope_put_var_init);
28514
0
        emit_atom(s, local_name);
28515
0
        emit_u16(s, 0);
28516
28517
0
        if (!add_export_entry(s, m, local_name, JS_ATOM_default,
28518
0
                              JS_EXPORT_TYPE_LOCAL))
28519
0
            return -1;
28520
0
        break;
28521
0
    case TOK_VAR:
28522
0
    case TOK_LET:
28523
0
    case TOK_CONST:
28524
0
        return js_parse_var(s, TRUE, tok, TRUE);
28525
0
    default:
28526
0
        return js_parse_error(s, "invalid export syntax");
28527
0
    }
28528
0
    return js_parse_expect_semi(s);
28529
0
}
28530
28531
static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
28532
                           BOOL is_local, BOOL is_arg,
28533
                           int var_idx, JSAtom var_name,
28534
                           BOOL is_const, BOOL is_lexical,
28535
                           JSVarKindEnum var_kind);
28536
28537
static int add_import(JSParseState *s, JSModuleDef *m,
28538
                      JSAtom local_name, JSAtom import_name)
28539
0
{
28540
0
    JSContext *ctx = s->ctx;
28541
0
    int i, var_idx;
28542
0
    JSImportEntry *mi;
28543
0
    BOOL is_local;
28544
28545
0
    if (local_name == JS_ATOM_arguments || local_name == JS_ATOM_eval)
28546
0
        return js_parse_error(s, "invalid import binding");
28547
28548
0
    if (local_name != JS_ATOM_default) {
28549
0
        for (i = 0; i < s->cur_func->closure_var_count; i++) {
28550
0
            if (s->cur_func->closure_var[i].var_name == local_name)
28551
0
                return js_parse_error(s, "duplicate import binding");
28552
0
        }
28553
0
    }
28554
28555
0
    is_local = (import_name == JS_ATOM__star_);
28556
0
    var_idx = add_closure_var(ctx, s->cur_func, is_local, FALSE,
28557
0
                              m->import_entries_count,
28558
0
                              local_name, TRUE, TRUE, FALSE);
28559
0
    if (var_idx < 0)
28560
0
        return -1;
28561
0
    if (js_resize_array(ctx, (void **)&m->import_entries,
28562
0
                        sizeof(JSImportEntry),
28563
0
                        &m->import_entries_size,
28564
0
                        m->import_entries_count + 1))
28565
0
        return -1;
28566
0
    mi = &m->import_entries[m->import_entries_count++];
28567
0
    mi->import_name = JS_DupAtom(ctx, import_name);
28568
0
    mi->var_idx = var_idx;
28569
0
    return 0;
28570
0
}
28571
28572
static __exception int js_parse_import(JSParseState *s)
28573
0
{
28574
0
    JSContext *ctx = s->ctx;
28575
0
    JSModuleDef *m = s->cur_func->module;
28576
0
    JSAtom local_name, import_name, module_name;
28577
0
    int first_import, i, idx;
28578
28579
0
    if (next_token(s))
28580
0
        return -1;
28581
28582
0
    first_import = m->import_entries_count;
28583
0
    if (s->token.val == TOK_STRING) {
28584
0
        module_name = JS_ValueToAtom(ctx, s->token.u.str.str);
28585
0
        if (module_name == JS_ATOM_NULL)
28586
0
            return -1;
28587
0
        if (next_token(s)) {
28588
0
            JS_FreeAtom(ctx, module_name);
28589
0
            return -1;
28590
0
        }
28591
0
    } else {
28592
0
        if (s->token.val == TOK_IDENT) {
28593
0
            if (s->token.u.ident.is_reserved) {
28594
0
                return js_parse_error_reserved_identifier(s);
28595
0
            }
28596
            /* "default" import */
28597
0
            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28598
0
            import_name = JS_ATOM_default;
28599
0
            if (next_token(s))
28600
0
                goto fail;
28601
0
            if (add_import(s, m, local_name, import_name))
28602
0
                goto fail;
28603
0
            JS_FreeAtom(ctx, local_name);
28604
28605
0
            if (s->token.val != ',')
28606
0
                goto end_import_clause;
28607
0
            if (next_token(s))
28608
0
                return -1;
28609
0
        }
28610
28611
0
        if (s->token.val == '*') {
28612
            /* name space import */
28613
0
            if (next_token(s))
28614
0
                return -1;
28615
0
            if (!token_is_pseudo_keyword(s, JS_ATOM_as))
28616
0
                return js_parse_error(s, "expecting 'as'");
28617
0
            if (next_token(s))
28618
0
                return -1;
28619
0
            if (!token_is_ident(s->token.val)) {
28620
0
                js_parse_error(s, "identifier expected");
28621
0
                return -1;
28622
0
            }
28623
0
            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28624
0
            import_name = JS_ATOM__star_;
28625
0
            if (next_token(s))
28626
0
                goto fail;
28627
0
            if (add_import(s, m, local_name, import_name))
28628
0
                goto fail;
28629
0
            JS_FreeAtom(ctx, local_name);
28630
0
        } else if (s->token.val == '{') {
28631
0
            if (next_token(s))
28632
0
                return -1;
28633
28634
0
            while (s->token.val != '}') {
28635
0
                if (!token_is_ident(s->token.val)) {
28636
0
                    js_parse_error(s, "identifier expected");
28637
0
                    return -1;
28638
0
                }
28639
0
                import_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28640
0
                local_name = JS_ATOM_NULL;
28641
0
                if (next_token(s))
28642
0
                    goto fail;
28643
0
                if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
28644
0
                    if (next_token(s))
28645
0
                        goto fail;
28646
0
                    if (!token_is_ident(s->token.val)) {
28647
0
                        js_parse_error(s, "identifier expected");
28648
0
                        goto fail;
28649
0
                    }
28650
0
                    local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
28651
0
                    if (next_token(s)) {
28652
0
                    fail:
28653
0
                        JS_FreeAtom(ctx, local_name);
28654
0
                        JS_FreeAtom(ctx, import_name);
28655
0
                        return -1;
28656
0
                    }
28657
0
                } else {
28658
0
                    local_name = JS_DupAtom(ctx, import_name);
28659
0
                }
28660
0
                if (add_import(s, m, local_name, import_name))
28661
0
                    goto fail;
28662
0
                JS_FreeAtom(ctx, local_name);
28663
0
                JS_FreeAtom(ctx, import_name);
28664
0
                if (s->token.val != ',')
28665
0
                    break;
28666
0
                if (next_token(s))
28667
0
                    return -1;
28668
0
            }
28669
0
            if (js_parse_expect(s, '}'))
28670
0
                return -1;
28671
0
        }
28672
0
    end_import_clause:
28673
0
        module_name = js_parse_from_clause(s);
28674
0
        if (module_name == JS_ATOM_NULL)
28675
0
            return -1;
28676
0
    }
28677
0
    idx = add_req_module_entry(ctx, m, module_name);
28678
0
    JS_FreeAtom(ctx, module_name);
28679
0
    if (idx < 0)
28680
0
        return -1;
28681
0
    for(i = first_import; i < m->import_entries_count; i++)
28682
0
        m->import_entries[i].req_module_idx = idx;
28683
28684
0
    return js_parse_expect_semi(s);
28685
0
}
28686
28687
static __exception int js_parse_source_element(JSParseState *s)
28688
119k
{
28689
119k
    JSFunctionDef *fd = s->cur_func;
28690
119k
    int tok;
28691
    
28692
119k
    if (s->token.val == TOK_FUNCTION ||
28693
119k
        (token_is_pseudo_keyword(s, JS_ATOM_async) &&
28694
108k
         peek_token(s, TRUE) == TOK_FUNCTION)) {
28695
11.2k
        if (js_parse_function_decl(s, JS_PARSE_FUNC_STATEMENT,
28696
11.2k
                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
28697
11.2k
                                   s->token.ptr, s->token.line_num))
28698
4
            return -1;
28699
108k
    } else if (s->token.val == TOK_EXPORT && fd->module) {
28700
0
        if (js_parse_export(s))
28701
0
            return -1;
28702
108k
    } else if (s->token.val == TOK_IMPORT && fd->module &&
28703
108k
               ((tok = peek_token(s, FALSE)) != '(' && tok != '.'))  {
28704
        /* the peek_token is needed to avoid confusion with ImportCall
28705
           (dynamic import) or import.meta */
28706
0
        if (js_parse_import(s))
28707
0
            return -1;
28708
108k
    } else {
28709
108k
        if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
28710
26
            return -1;
28711
108k
    }
28712
119k
    return 0;
28713
119k
}
28714
28715
static JSFunctionDef *js_new_function_def(JSContext *ctx,
28716
                                          JSFunctionDef *parent,
28717
                                          BOOL is_eval,
28718
                                          BOOL is_func_expr,
28719
                                          const char *filename, int line_num)
28720
53.6k
{
28721
53.6k
    JSFunctionDef *fd;
28722
28723
53.6k
    fd = js_mallocz(ctx, sizeof(*fd));
28724
53.6k
    if (!fd)
28725
1
        return NULL;
28726
28727
53.6k
    fd->ctx = ctx;
28728
53.6k
    init_list_head(&fd->child_list);
28729
28730
    /* insert in parent list */
28731
53.6k
    fd->parent = parent;
28732
53.6k
    fd->parent_cpool_idx = -1;
28733
53.6k
    if (parent) {
28734
12.6k
        list_add_tail(&fd->link, &parent->child_list);
28735
12.6k
        fd->js_mode = parent->js_mode;
28736
12.6k
        fd->parent_scope_level = parent->scope_level;
28737
12.6k
    }
28738
28739
53.6k
    fd->is_eval = is_eval;
28740
53.6k
    fd->is_func_expr = is_func_expr;
28741
53.6k
    js_dbuf_init(ctx, &fd->byte_code);
28742
53.6k
    fd->last_opcode_pos = -1;
28743
53.6k
    fd->func_name = JS_ATOM_NULL;
28744
53.6k
    fd->var_object_idx = -1;
28745
53.6k
    fd->arg_var_object_idx = -1;
28746
53.6k
    fd->arguments_var_idx = -1;
28747
53.6k
    fd->arguments_arg_idx = -1;
28748
53.6k
    fd->func_var_idx = -1;
28749
53.6k
    fd->eval_ret_idx = -1;
28750
53.6k
    fd->this_var_idx = -1;
28751
53.6k
    fd->new_target_var_idx = -1;
28752
53.6k
    fd->this_active_func_var_idx = -1;
28753
53.6k
    fd->home_object_var_idx = -1;
28754
28755
    /* XXX: should distinguish arg, var and var object and body scopes */
28756
53.6k
    fd->scopes = fd->def_scope_array;
28757
53.6k
    fd->scope_size = countof(fd->def_scope_array);
28758
53.6k
    fd->scope_count = 1;
28759
53.6k
    fd->scopes[0].first = -1;
28760
53.6k
    fd->scopes[0].parent = -1;
28761
53.6k
    fd->scope_level = 0;  /* 0: var/arg scope */
28762
53.6k
    fd->scope_first = -1;
28763
53.6k
    fd->body_scope = -1;
28764
28765
53.6k
    fd->filename = JS_NewAtom(ctx, filename);
28766
53.6k
    fd->line_num = line_num;
28767
28768
53.6k
    js_dbuf_init(ctx, &fd->pc2line);
28769
    //fd->pc2line_last_line_num = line_num;
28770
    //fd->pc2line_last_pc = 0;
28771
53.6k
    fd->last_opcode_line_num = line_num;
28772
28773
53.6k
    return fd;
28774
53.6k
}
28775
28776
static void free_bytecode_atoms(JSRuntime *rt,
28777
                                const uint8_t *bc_buf, int bc_len,
28778
                                BOOL use_short_opcodes)
28779
53.6k
{
28780
53.6k
    int pos, len, op;
28781
53.6k
    JSAtom atom;
28782
53.6k
    const JSOpCode *oi;
28783
    
28784
53.6k
    pos = 0;
28785
2.58M
    while (pos < bc_len) {
28786
2.53M
        op = bc_buf[pos];
28787
2.53M
        if (use_short_opcodes)
28788
2.05M
            oi = &short_opcode_info(op);
28789
475k
        else
28790
475k
            oi = &opcode_info[op];
28791
            
28792
2.53M
        len = oi->size;
28793
2.53M
        switch(oi->fmt) {
28794
591k
        case OP_FMT_atom:
28795
594k
        case OP_FMT_atom_u8:
28796
692k
        case OP_FMT_atom_u16:
28797
1.04M
        case OP_FMT_atom_label_u8:
28798
1.06M
        case OP_FMT_atom_label_u16:
28799
1.06M
            atom = get_u32(bc_buf + pos + 1);
28800
1.06M
            JS_FreeAtomRT(rt, atom);
28801
1.06M
            break;
28802
1.46M
        default:
28803
1.46M
            break;
28804
2.53M
        }
28805
2.53M
        pos += len;
28806
2.53M
    }
28807
53.6k
}
28808
28809
static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd)
28810
8.03k
{
28811
8.03k
    int i;
28812
8.03k
    struct list_head *el, *el1;
28813
28814
    /* free the child functions */
28815
8.03k
    list_for_each_safe(el, el1, &fd->child_list) {
28816
7.99k
        JSFunctionDef *fd1;
28817
7.99k
        fd1 = list_entry(el, JSFunctionDef, link);
28818
7.99k
        js_free_function_def(ctx, fd1);
28819
7.99k
    }
28820
28821
8.03k
    free_bytecode_atoms(ctx->rt, fd->byte_code.buf, fd->byte_code.size,
28822
8.03k
                        fd->use_short_opcodes);
28823
8.03k
    dbuf_free(&fd->byte_code);
28824
8.03k
    js_free(ctx, fd->jump_slots);
28825
8.03k
    js_free(ctx, fd->label_slots);
28826
8.03k
    js_free(ctx, fd->line_number_slots);
28827
28828
16.5k
    for(i = 0; i < fd->cpool_count; i++) {
28829
8.53k
        JS_FreeValue(ctx, fd->cpool[i]);
28830
8.53k
    }
28831
8.03k
    js_free(ctx, fd->cpool);
28832
28833
8.03k
    JS_FreeAtom(ctx, fd->func_name);
28834
28835
8.81k
    for(i = 0; i < fd->var_count; i++) {
28836
779
        JS_FreeAtom(ctx, fd->vars[i].var_name);
28837
779
    }
28838
8.03k
    js_free(ctx, fd->vars);
28839
8.29k
    for(i = 0; i < fd->arg_count; i++) {
28840
261
        JS_FreeAtom(ctx, fd->args[i].var_name);
28841
261
    }
28842
8.03k
    js_free(ctx, fd->args);
28843
28844
15.1k
    for(i = 0; i < fd->global_var_count; i++) {
28845
7.12k
        JS_FreeAtom(ctx, fd->global_vars[i].var_name);
28846
7.12k
    }
28847
8.03k
    js_free(ctx, fd->global_vars);
28848
28849
8.16k
    for(i = 0; i < fd->closure_var_count; i++) {
28850
131
        JSClosureVar *cv = &fd->closure_var[i];
28851
131
        JS_FreeAtom(ctx, cv->var_name);
28852
131
    }
28853
8.03k
    js_free(ctx, fd->closure_var);
28854
28855
8.03k
    if (fd->scopes != fd->def_scope_array)
28856
27
        js_free(ctx, fd->scopes);
28857
28858
8.03k
    JS_FreeAtom(ctx, fd->filename);
28859
8.03k
    dbuf_free(&fd->pc2line);
28860
28861
8.03k
    js_free(ctx, fd->source);
28862
28863
8.03k
    if (fd->parent) {
28864
        /* remove in parent list */
28865
8.01k
        list_del(&fd->link);
28866
8.01k
    }
28867
8.03k
    js_free(ctx, fd);
28868
8.03k
}
28869
28870
#ifdef DUMP_BYTECODE
28871
static const char *skip_lines(const char *p, int n) {
28872
    while (n-- > 0 && *p) {
28873
        while (*p && *p++ != '\n')
28874
            continue;
28875
    }
28876
    return p;
28877
}
28878
28879
static void print_lines(const char *source, int line, int line1) {
28880
    const char *s = source;
28881
    const char *p = skip_lines(s, line);
28882
    if (*p) {
28883
        while (line++ < line1) {
28884
            p = skip_lines(s = p, 1);
28885
            printf(";; %.*s", (int)(p - s), s);
28886
            if (!*p) {
28887
                if (p[-1] != '\n')
28888
                    printf("\n");
28889
                break;
28890
            }
28891
        }
28892
    }
28893
}
28894
28895
static void dump_byte_code(JSContext *ctx, int pass,
28896
                           const uint8_t *tab, int len,
28897
                           const JSVarDef *args, int arg_count,
28898
                           const JSVarDef *vars, int var_count,
28899
                           const JSClosureVar *closure_var, int closure_var_count,
28900
                           const JSValue *cpool, uint32_t cpool_count,
28901
                           const char *source, int line_num,
28902
                           const LabelSlot *label_slots, JSFunctionBytecode *b)
28903
{
28904
    const JSOpCode *oi;
28905
    int pos, pos_next, op, size, idx, addr, line, line1, in_source;
28906
    uint8_t *bits = js_mallocz(ctx, len * sizeof(*bits));
28907
    BOOL use_short_opcodes = (b != NULL);
28908
28909
    /* scan for jump targets */
28910
    for (pos = 0; pos < len; pos = pos_next) {
28911
        op = tab[pos];
28912
        if (use_short_opcodes)
28913
            oi = &short_opcode_info(op);
28914
        else
28915
            oi = &opcode_info[op];
28916
        pos_next = pos + oi->size;
28917
        if (op < OP_COUNT) {
28918
            switch (oi->fmt) {
28919
#if SHORT_OPCODES
28920
            case OP_FMT_label8:
28921
                pos++;
28922
                addr = (int8_t)tab[pos];
28923
                goto has_addr;
28924
            case OP_FMT_label16:
28925
                pos++;
28926
                addr = (int16_t)get_u16(tab + pos);
28927
                goto has_addr;
28928
#endif
28929
            case OP_FMT_atom_label_u8:
28930
            case OP_FMT_atom_label_u16:
28931
                pos += 4;
28932
                /* fall thru */
28933
            case OP_FMT_label:
28934
            case OP_FMT_label_u16:
28935
                pos++;
28936
                addr = get_u32(tab + pos);
28937
                goto has_addr;
28938
            has_addr:
28939
                if (pass == 1)
28940
                    addr = label_slots[addr].pos;
28941
                if (pass == 2)
28942
                    addr = label_slots[addr].pos2;
28943
                if (pass == 3)
28944
                    addr += pos;
28945
                if (addr >= 0 && addr < len)
28946
                    bits[addr] |= 1;
28947
                break;
28948
            }
28949
        }
28950
    }
28951
    in_source = 0;
28952
    if (source) {
28953
        /* Always print first line: needed if single line */
28954
        print_lines(source, 0, 1);
28955
        in_source = 1;
28956
    }
28957
    line1 = line = 1;
28958
    pos = 0;
28959
    while (pos < len) {
28960
        op = tab[pos];
28961
        if (source) {
28962
            if (b) {
28963
                line1 = find_line_num(ctx, b, pos) - line_num + 1;
28964
            } else if (op == OP_line_num) {
28965
                line1 = get_u32(tab + pos + 1) - line_num + 1;
28966
            }
28967
            if (line1 > line) {
28968
                if (!in_source)
28969
                    printf("\n");
28970
                in_source = 1;
28971
                print_lines(source, line, line1);
28972
                line = line1;
28973
                //bits[pos] |= 2;
28974
            }
28975
        }
28976
        if (in_source)
28977
            printf("\n");
28978
        in_source = 0;
28979
        if (op >= OP_COUNT) {
28980
            printf("invalid opcode (0x%02x)\n", op);
28981
            pos++;
28982
            continue;
28983
        }
28984
        if (use_short_opcodes)
28985
            oi = &short_opcode_info(op);
28986
        else
28987
            oi = &opcode_info[op];
28988
        size = oi->size;
28989
        if (pos + size > len) {
28990
            printf("truncated opcode (0x%02x)\n", op);
28991
            break;
28992
        }
28993
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 16)
28994
        {
28995
            int i, x, x0;
28996
            x = x0 = printf("%5d ", pos);
28997
            for (i = 0; i < size; i++) {
28998
                if (i == 6) {
28999
                    printf("\n%*s", x = x0, "");
29000
                }
29001
                x += printf(" %02X", tab[pos + i]);
29002
            }
29003
            printf("%*s", x0 + 20 - x, "");
29004
        }
29005
#endif
29006
        if (bits[pos]) {
29007
            printf("%5d:  ", pos);
29008
        } else {
29009
            printf("        ");
29010
        }
29011
        printf("%s", oi->name);
29012
        pos++;
29013
        switch(oi->fmt) {
29014
        case OP_FMT_none_int:
29015
            printf(" %d", op - OP_push_0);
29016
            break;
29017
        case OP_FMT_npopx:
29018
            printf(" %d", op - OP_call0);
29019
            break;
29020
        case OP_FMT_u8:
29021
            printf(" %u", get_u8(tab + pos));
29022
            break;
29023
        case OP_FMT_i8:
29024
            printf(" %d", get_i8(tab + pos));
29025
            break;
29026
        case OP_FMT_u16:
29027
        case OP_FMT_npop:
29028
            printf(" %u", get_u16(tab + pos));
29029
            break;
29030
        case OP_FMT_npop_u16:
29031
            printf(" %u,%u", get_u16(tab + pos), get_u16(tab + pos + 2));
29032
            break;
29033
        case OP_FMT_i16:
29034
            printf(" %d", get_i16(tab + pos));
29035
            break;
29036
        case OP_FMT_i32:
29037
            printf(" %d", get_i32(tab + pos));
29038
            break;
29039
        case OP_FMT_u32:
29040
            printf(" %u", get_u32(tab + pos));
29041
            break;
29042
#if SHORT_OPCODES
29043
        case OP_FMT_label8:
29044
            addr = get_i8(tab + pos);
29045
            goto has_addr1;
29046
        case OP_FMT_label16:
29047
            addr = get_i16(tab + pos);
29048
            goto has_addr1;
29049
#endif
29050
        case OP_FMT_label:
29051
            addr = get_u32(tab + pos);
29052
            goto has_addr1;
29053
        has_addr1:
29054
            if (pass == 1)
29055
                printf(" %u:%u", addr, label_slots[addr].pos);
29056
            if (pass == 2)
29057
                printf(" %u:%u", addr, label_slots[addr].pos2);
29058
            if (pass == 3)
29059
                printf(" %u", addr + pos);
29060
            break;
29061
        case OP_FMT_label_u16:
29062
            addr = get_u32(tab + pos);
29063
            if (pass == 1)
29064
                printf(" %u:%u", addr, label_slots[addr].pos);
29065
            if (pass == 2)
29066
                printf(" %u:%u", addr, label_slots[addr].pos2);
29067
            if (pass == 3)
29068
                printf(" %u", addr + pos);
29069
            printf(",%u", get_u16(tab + pos + 4));
29070
            break;
29071
#if SHORT_OPCODES
29072
        case OP_FMT_const8:
29073
            idx = get_u8(tab + pos);
29074
            goto has_pool_idx;
29075
#endif
29076
        case OP_FMT_const:
29077
            idx = get_u32(tab + pos);
29078
            goto has_pool_idx;
29079
        has_pool_idx:
29080
            printf(" %u: ", idx);
29081
            if (idx < cpool_count) {
29082
                JS_DumpValue(ctx, cpool[idx]);
29083
            }
29084
            break;
29085
        case OP_FMT_atom:
29086
            printf(" ");
29087
            print_atom(ctx, get_u32(tab + pos));
29088
            break;
29089
        case OP_FMT_atom_u8:
29090
            printf(" ");
29091
            print_atom(ctx, get_u32(tab + pos));
29092
            printf(",%d", get_u8(tab + pos + 4));
29093
            break;
29094
        case OP_FMT_atom_u16:
29095
            printf(" ");
29096
            print_atom(ctx, get_u32(tab + pos));
29097
            printf(",%d", get_u16(tab + pos + 4));
29098
            break;
29099
        case OP_FMT_atom_label_u8:
29100
        case OP_FMT_atom_label_u16:
29101
            printf(" ");
29102
            print_atom(ctx, get_u32(tab + pos));
29103
            addr = get_u32(tab + pos + 4);
29104
            if (pass == 1)
29105
                printf(",%u:%u", addr, label_slots[addr].pos);
29106
            if (pass == 2)
29107
                printf(",%u:%u", addr, label_slots[addr].pos2);
29108
            if (pass == 3)
29109
                printf(",%u", addr + pos + 4);
29110
            if (oi->fmt == OP_FMT_atom_label_u8)
29111
                printf(",%u", get_u8(tab + pos + 8));
29112
            else
29113
                printf(",%u", get_u16(tab + pos + 8));
29114
            break;
29115
        case OP_FMT_none_loc:
29116
            idx = (op - OP_get_loc0) % 4;
29117
            goto has_loc;
29118
        case OP_FMT_loc8:
29119
            idx = get_u8(tab + pos);
29120
            goto has_loc;
29121
        case OP_FMT_loc:
29122
            idx = get_u16(tab + pos);
29123
        has_loc:
29124
            printf(" %d: ", idx);
29125
            if (idx < var_count) {
29126
                print_atom(ctx, vars[idx].var_name);
29127
            }
29128
            break;
29129
        case OP_FMT_none_arg:
29130
            idx = (op - OP_get_arg0) % 4;
29131
            goto has_arg;
29132
        case OP_FMT_arg:
29133
            idx = get_u16(tab + pos);
29134
        has_arg:
29135
            printf(" %d: ", idx);
29136
            if (idx < arg_count) {
29137
                print_atom(ctx, args[idx].var_name);
29138
            }
29139
            break;
29140
        case OP_FMT_none_var_ref:
29141
            idx = (op - OP_get_var_ref0) % 4;
29142
            goto has_var_ref;
29143
        case OP_FMT_var_ref:
29144
            idx = get_u16(tab + pos);
29145
        has_var_ref:
29146
            printf(" %d: ", idx);
29147
            if (idx < closure_var_count) {
29148
                print_atom(ctx, closure_var[idx].var_name);
29149
            }
29150
            break;
29151
        default:
29152
            break;
29153
        }
29154
        printf("\n");
29155
        pos += oi->size - 1;
29156
    }
29157
    if (source) {
29158
        if (!in_source)
29159
            printf("\n");
29160
        print_lines(source, line, INT32_MAX);
29161
    }
29162
    js_free(ctx, bits);
29163
}
29164
29165
static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int len,
29166
                                                 int line_num)
29167
{
29168
    const uint8_t *p_end, *p_next, *p;
29169
    int pc, v;
29170
    unsigned int op;
29171
29172
    if (len <= 0)
29173
        return;
29174
29175
    printf("%5s %5s\n", "PC", "LINE");
29176
29177
    p = buf;
29178
    p_end = buf + len;
29179
    pc = 0;
29180
    while (p < p_end) {
29181
        op = *p++;
29182
        if (op == 0) {
29183
            v = unicode_from_utf8(p, p_end - p, &p_next);
29184
            if (v < 0)
29185
                goto fail;
29186
            pc += v;
29187
            p = p_next;
29188
            v = unicode_from_utf8(p, p_end - p, &p_next);
29189
            if (v < 0) {
29190
            fail:
29191
                printf("invalid pc2line encode pos=%d\n", (int)(p - buf));
29192
                return;
29193
            }
29194
            if (!(v & 1)) {
29195
                v = v >> 1;
29196
            } else {
29197
                v = -(v >> 1) - 1;
29198
            }
29199
            line_num += v;
29200
            p = p_next;
29201
        } else {
29202
            op -= PC2LINE_OP_FIRST;
29203
            pc += (op / PC2LINE_RANGE);
29204
            line_num += (op % PC2LINE_RANGE) + PC2LINE_BASE;
29205
        }
29206
        printf("%5d %5d\n", pc, line_num);
29207
    }
29208
}
29209
29210
static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionBytecode *b)
29211
{
29212
    int i;
29213
    char atom_buf[ATOM_GET_STR_BUF_SIZE];
29214
    const char *str;
29215
29216
    if (b->has_debug && b->debug.filename != JS_ATOM_NULL) {
29217
        str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->debug.filename);
29218
        printf("%s:%d: ", str, b->debug.line_num);
29219
    }
29220
29221
    str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name);
29222
    printf("function: %s%s\n", &"*"[b->func_kind != JS_FUNC_GENERATOR], str);
29223
    if (b->js_mode) {
29224
        printf("  mode:");
29225
        if (b->js_mode & JS_MODE_STRICT)
29226
            printf(" strict");
29227
#ifdef CONFIG_BIGNUM
29228
        if (b->js_mode & JS_MODE_MATH)
29229
            printf(" math");
29230
#endif
29231
        printf("\n");
29232
    }
29233
    if (b->arg_count && b->vardefs) {
29234
        printf("  args:");
29235
        for(i = 0; i < b->arg_count; i++) {
29236
            printf(" %s", JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf),
29237
                                        b->vardefs[i].var_name));
29238
        }
29239
        printf("\n");
29240
    }
29241
    if (b->var_count && b->vardefs) {
29242
        printf("  locals:\n");
29243
        for(i = 0; i < b->var_count; i++) {
29244
            JSVarDef *vd = &b->vardefs[b->arg_count + i];
29245
            printf("%5d: %s %s", i,
29246
                   vd->var_kind == JS_VAR_CATCH ? "catch" :
29247
                   (vd->var_kind == JS_VAR_FUNCTION_DECL ||
29248
                    vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) ? "function" :
29249
                   vd->is_const ? "const" :
29250
                   vd->is_lexical ? "let" : "var",
29251
                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), vd->var_name));
29252
            if (vd->scope_level)
29253
                printf(" [level:%d next:%d]", vd->scope_level, vd->scope_next);
29254
            printf("\n");
29255
        }
29256
    }
29257
    if (b->closure_var_count) {
29258
        printf("  closure vars:\n");
29259
        for(i = 0; i < b->closure_var_count; i++) {
29260
            JSClosureVar *cv = &b->closure_var[i];
29261
            printf("%5d: %s %s:%s%d %s\n", i,
29262
                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), cv->var_name),
29263
                   cv->is_local ? "local" : "parent",
29264
                   cv->is_arg ? "arg" : "loc", cv->var_idx,
29265
                   cv->is_const ? "const" :
29266
                   cv->is_lexical ? "let" : "var");
29267
        }
29268
    }
29269
    printf("  stack_size: %d\n", b->stack_size);
29270
    printf("  opcodes:\n");
29271
    dump_byte_code(ctx, 3, b->byte_code_buf, b->byte_code_len,
29272
                   b->vardefs, b->arg_count,
29273
                   b->vardefs ? b->vardefs + b->arg_count : NULL, b->var_count,
29274
                   b->closure_var, b->closure_var_count,
29275
                   b->cpool, b->cpool_count,
29276
                   b->has_debug ? b->debug.source : NULL,
29277
                   b->has_debug ? b->debug.line_num : -1, NULL, b);
29278
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32)
29279
    if (b->has_debug)
29280
        dump_pc2line(ctx, b->debug.pc2line_buf, b->debug.pc2line_len, b->debug.line_num);
29281
#endif
29282
    printf("\n");
29283
}
29284
#endif
29285
29286
static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
29287
                           BOOL is_local, BOOL is_arg,
29288
                           int var_idx, JSAtom var_name,
29289
                           BOOL is_const, BOOL is_lexical,
29290
                           JSVarKindEnum var_kind)
29291
2.20k
{
29292
2.20k
    JSClosureVar *cv;
29293
29294
    /* the closure variable indexes are currently stored on 16 bits */
29295
2.20k
    if (s->closure_var_count >= JS_MAX_LOCAL_VARS) {
29296
0
        JS_ThrowInternalError(ctx, "too many closure variables");
29297
0
        return -1;
29298
0
    }
29299
29300
2.20k
    if (js_resize_array(ctx, (void **)&s->closure_var,
29301
2.20k
                        sizeof(s->closure_var[0]),
29302
2.20k
                        &s->closure_var_size, s->closure_var_count + 1))
29303
0
        return -1;
29304
2.20k
    cv = &s->closure_var[s->closure_var_count++];
29305
2.20k
    cv->is_local = is_local;
29306
2.20k
    cv->is_arg = is_arg;
29307
2.20k
    cv->is_const = is_const;
29308
2.20k
    cv->is_lexical = is_lexical;
29309
2.20k
    cv->var_kind = var_kind;
29310
2.20k
    cv->var_idx = var_idx;
29311
2.20k
    cv->var_name = JS_DupAtom(ctx, var_name);
29312
2.20k
    return s->closure_var_count - 1;
29313
2.20k
}
29314
29315
static int find_closure_var(JSContext *ctx, JSFunctionDef *s,
29316
                            JSAtom var_name)
29317
0
{
29318
0
    int i;
29319
0
    for(i = 0; i < s->closure_var_count; i++) {
29320
0
        JSClosureVar *cv = &s->closure_var[i];
29321
0
        if (cv->var_name == var_name)
29322
0
            return i;
29323
0
    }
29324
0
    return -1;
29325
0
}
29326
29327
/* 'fd' must be a parent of 's'. Create in 's' a closure referencing a
29328
   local variable (is_local = TRUE) or a closure (is_local = FALSE) in
29329
   'fd' */
29330
static int get_closure_var2(JSContext *ctx, JSFunctionDef *s,
29331
                            JSFunctionDef *fd, BOOL is_local,
29332
                            BOOL is_arg, int var_idx, JSAtom var_name,
29333
                            BOOL is_const, BOOL is_lexical,
29334
                            JSVarKindEnum var_kind)
29335
2.91k
{
29336
2.91k
    int i;
29337
29338
2.91k
    if (fd != s->parent) {
29339
1.13k
        var_idx = get_closure_var2(ctx, s->parent, fd, is_local,
29340
1.13k
                                   is_arg, var_idx, var_name,
29341
1.13k
                                   is_const, is_lexical, var_kind);
29342
1.13k
        if (var_idx < 0)
29343
0
            return -1;
29344
1.13k
        is_local = FALSE;
29345
1.13k
    }
29346
27.8k
    for(i = 0; i < s->closure_var_count; i++) {
29347
26.1k
        JSClosureVar *cv = &s->closure_var[i];
29348
26.1k
        if (cv->var_idx == var_idx && cv->is_arg == is_arg &&
29349
26.1k
            cv->is_local == is_local)
29350
1.28k
            return i;
29351
26.1k
    }
29352
1.63k
    return add_closure_var(ctx, s, is_local, is_arg, var_idx, var_name,
29353
1.63k
                           is_const, is_lexical, var_kind);
29354
2.91k
}
29355
29356
static int get_closure_var(JSContext *ctx, JSFunctionDef *s,
29357
                           JSFunctionDef *fd, BOOL is_arg,
29358
                           int var_idx, JSAtom var_name,
29359
                           BOOL is_const, BOOL is_lexical,
29360
                           JSVarKindEnum var_kind)
29361
1.62k
{
29362
1.62k
    return get_closure_var2(ctx, s, fd, TRUE, is_arg,
29363
1.62k
                            var_idx, var_name, is_const, is_lexical,
29364
1.62k
                            var_kind);
29365
1.62k
}
29366
29367
static int get_with_scope_opcode(int op)
29368
351k
{
29369
351k
    if (op == OP_scope_get_var_undef)
29370
0
        return OP_with_get_var;
29371
351k
    else
29372
351k
        return OP_with_get_var + (op - OP_scope_get_var);
29373
351k
}
29374
29375
static BOOL can_opt_put_ref_value(const uint8_t *bc_buf, int pos)
29376
23.0k
{
29377
23.0k
    int opcode = bc_buf[pos];
29378
23.0k
    return (bc_buf[pos + 1] == OP_put_ref_value &&
29379
23.0k
            (opcode == OP_insert3 ||
29380
673
             opcode == OP_perm4 ||
29381
673
             opcode == OP_nop ||
29382
673
             opcode == OP_rot3l));
29383
23.0k
}
29384
29385
static BOOL can_opt_put_global_ref_value(const uint8_t *bc_buf, int pos)
29386
44.0k
{
29387
44.0k
    int opcode = bc_buf[pos];
29388
44.0k
    return (bc_buf[pos + 1] == OP_put_ref_value &&
29389
44.0k
            (opcode == OP_insert3 ||
29390
21.1k
             opcode == OP_perm4 ||
29391
21.1k
             opcode == OP_nop ||
29392
21.1k
             opcode == OP_rot3l));
29393
44.0k
}
29394
29395
static int optimize_scope_make_ref(JSContext *ctx, JSFunctionDef *s,
29396
                                   DynBuf *bc, uint8_t *bc_buf,
29397
                                   LabelSlot *ls, int pos_next,
29398
                                   int get_op, int var_idx)
29399
673
{
29400
673
    int label_pos, end_pos, pos;
29401
29402
    /* XXX: should optimize `loc(a) += expr` as `expr add_loc(a)`
29403
       but only if expr does not modify `a`.
29404
       should scan the code between pos_next and label_pos
29405
       for operations that can potentially change `a`:
29406
       OP_scope_make_ref(a), function calls, jumps and gosub.
29407
     */
29408
    /* replace the reference get/put with normal variable
29409
       accesses */
29410
673
    if (bc_buf[pos_next] == OP_get_ref_value) {
29411
167
        dbuf_putc(bc, get_op);
29412
167
        dbuf_put_u16(bc, var_idx);
29413
167
        pos_next++;
29414
167
    }
29415
    /* remove the OP_label to make room for replacement */
29416
    /* label should have a refcount of 0 anyway */
29417
    /* XXX: should avoid this patch by inserting nops in phase 1 */
29418
673
    label_pos = ls->pos;
29419
673
    pos = label_pos - 5;
29420
673
    assert(bc_buf[pos] == OP_label);
29421
    /* label points to an instruction pair:
29422
       - insert3 / put_ref_value
29423
       - perm4 / put_ref_value
29424
       - rot3l / put_ref_value
29425
       - nop / put_ref_value
29426
     */
29427
673
    end_pos = label_pos + 2;
29428
673
    if (bc_buf[label_pos] == OP_insert3)
29429
75
        bc_buf[pos++] = OP_dup;
29430
673
    bc_buf[pos] = get_op + 1;
29431
673
    put_u16(bc_buf + pos + 1, var_idx);
29432
673
    pos += 3;
29433
    /* pad with OP_nop */
29434
3.29k
    while (pos < end_pos)
29435
2.61k
        bc_buf[pos++] = OP_nop;
29436
673
    return pos_next;
29437
673
}
29438
29439
static int optimize_scope_make_global_ref(JSContext *ctx, JSFunctionDef *s,
29440
                                          DynBuf *bc, uint8_t *bc_buf,
29441
                                          LabelSlot *ls, int pos_next,
29442
                                          JSAtom var_name)
29443
21.1k
{
29444
21.1k
    int label_pos, end_pos, pos, op;
29445
21.1k
    BOOL is_strict;
29446
21.1k
    is_strict = ((s->js_mode & JS_MODE_STRICT) != 0);
29447
29448
    /* replace the reference get/put with normal variable
29449
       accesses */
29450
21.1k
    if (is_strict) {
29451
        /* need to check if the variable exists before evaluating the right
29452
           expression */
29453
        /* XXX: need an extra OP_true if destructuring an array */
29454
35
        dbuf_putc(bc, OP_check_var);
29455
35
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29456
21.1k
    } else {
29457
        /* XXX: need 2 extra OP_true if destructuring an array */
29458
21.1k
    }
29459
21.1k
    if (bc_buf[pos_next] == OP_get_ref_value) {
29460
224
        dbuf_putc(bc, OP_get_var);
29461
224
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29462
224
        pos_next++;
29463
224
    }
29464
    /* remove the OP_label to make room for replacement */
29465
    /* label should have a refcount of 0 anyway */
29466
    /* XXX: should have emitted several OP_nop to avoid this kludge */
29467
21.1k
    label_pos = ls->pos;
29468
21.1k
    pos = label_pos - 5;
29469
21.1k
    assert(bc_buf[pos] == OP_label);
29470
21.1k
    end_pos = label_pos + 2;
29471
21.1k
    op = bc_buf[label_pos];
29472
21.1k
    if (is_strict) {
29473
35
        if (op != OP_nop) {
29474
35
            switch(op) {
29475
35
            case OP_insert3:
29476
35
                op = OP_insert2;
29477
35
                break;
29478
0
            case OP_perm4:
29479
0
                op = OP_perm3;
29480
0
                break;
29481
0
            case OP_rot3l:
29482
0
                op = OP_swap;
29483
0
                break;
29484
0
            default:
29485
0
                abort();
29486
35
            }
29487
35
            bc_buf[pos++] = op;
29488
35
        }
29489
21.1k
    } else {
29490
21.1k
        if (op == OP_insert3)
29491
20.8k
            bc_buf[pos++] = OP_dup;
29492
21.1k
    }
29493
21.1k
    if (is_strict) {
29494
35
        bc_buf[pos] = OP_put_var_strict;
29495
        /* XXX: need 1 extra OP_drop if destructuring an array */
29496
21.1k
    } else {
29497
21.1k
        bc_buf[pos] = OP_put_var;
29498
        /* XXX: need 2 extra OP_drop if destructuring an array */
29499
21.1k
    }
29500
21.1k
    put_u32(bc_buf + pos + 1, JS_DupAtom(ctx, var_name));
29501
21.1k
    pos += 5;
29502
    /* pad with OP_nop */
29503
42.5k
    while (pos < end_pos)
29504
21.3k
        bc_buf[pos++] = OP_nop;
29505
21.1k
    return pos_next;
29506
21.1k
}
29507
29508
static int add_var_this(JSContext *ctx, JSFunctionDef *fd)
29509
158
{
29510
158
    int idx;
29511
158
    idx = add_var(ctx, fd, JS_ATOM_this);
29512
158
    if (idx >= 0 && fd->is_derived_class_constructor) {
29513
0
        JSVarDef *vd = &fd->vars[idx];
29514
        /* XXX: should have is_this flag or var type */
29515
0
        vd->is_lexical = 1; /* used to trigger 'uninitialized' checks
29516
                               in a derived class constructor */
29517
0
    }
29518
158
    return idx;
29519
158
}
29520
29521
static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s,
29522
                               JSAtom var_name)
29523
232
{
29524
232
    int var_idx;
29525
29526
232
    if (!s->has_this_binding)
29527
0
        return -1;
29528
232
    switch(var_name) {
29529
77
    case JS_ATOM_home_object:
29530
        /* 'home_object' pseudo variable */
29531
77
        if (s->home_object_var_idx < 0)
29532
77
            s->home_object_var_idx = add_var(ctx, s, var_name);
29533
77
        var_idx = s->home_object_var_idx;
29534
77
        break;
29535
0
    case JS_ATOM_this_active_func:
29536
        /* 'this.active_func' pseudo variable */
29537
0
        if (s->this_active_func_var_idx < 0)
29538
0
            s->this_active_func_var_idx = add_var(ctx, s, var_name);
29539
0
        var_idx = s->this_active_func_var_idx;
29540
0
        break;
29541
0
    case JS_ATOM_new_target:
29542
        /* 'new.target' pseudo variable */
29543
0
        if (s->new_target_var_idx < 0)
29544
0
            s->new_target_var_idx = add_var(ctx, s, var_name);
29545
0
        var_idx = s->new_target_var_idx;
29546
0
        break;
29547
155
    case JS_ATOM_this:
29548
        /* 'this' pseudo variable */
29549
155
        if (s->this_var_idx < 0)
29550
155
            s->this_var_idx = add_var_this(ctx, s);
29551
155
        var_idx = s->this_var_idx;
29552
155
        break;
29553
0
    default:
29554
0
        var_idx = -1;
29555
0
        break;
29556
232
    }
29557
232
    return var_idx;
29558
232
}
29559
29560
/* test if 'var_name' is in the variable object on the stack. If is it
29561
   the case, handle it and jump to 'label_done' */
29562
static void var_object_test(JSContext *ctx, JSFunctionDef *s,
29563
                            JSAtom var_name, int op, DynBuf *bc,
29564
                            int *plabel_done, BOOL is_with)
29565
351k
{
29566
351k
    dbuf_putc(bc, get_with_scope_opcode(op));
29567
351k
    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29568
351k
    *plabel_done = new_label_fd(s, *plabel_done);
29569
351k
    dbuf_put_u32(bc, *plabel_done);
29570
351k
    dbuf_putc(bc, is_with);
29571
351k
    update_label(s, *plabel_done, 1);
29572
351k
    s->jump_size++;
29573
351k
}
29574
    
29575
/* return the position of the next opcode */
29576
static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
29577
                             JSAtom var_name, int scope_level, int op,
29578
                             DynBuf *bc, uint8_t *bc_buf,
29579
                             LabelSlot *ls, int pos_next)
29580
499k
{
29581
499k
    int idx, var_idx, is_put;
29582
499k
    int label_done;
29583
499k
    JSFunctionDef *fd;
29584
499k
    JSVarDef *vd;
29585
499k
    BOOL is_pseudo_var, is_arg_scope;
29586
29587
499k
    label_done = -1;
29588
29589
    /* XXX: could be simpler to use a specific function to
29590
       resolve the pseudo variables */
29591
499k
    is_pseudo_var = (var_name == JS_ATOM_home_object ||
29592
499k
                     var_name == JS_ATOM_this_active_func ||
29593
499k
                     var_name == JS_ATOM_new_target ||
29594
499k
                     var_name == JS_ATOM_this);
29595
29596
    /* resolve local scoped variables */
29597
499k
    var_idx = -1;
29598
855k
    for (idx = s->scopes[scope_level].first; idx >= 0;) {
29599
356k
        vd = &s->vars[idx];
29600
356k
        if (vd->var_name == var_name) {
29601
1.07k
            if (op == OP_scope_put_var || op == OP_scope_make_ref) {
29602
166
                if (vd->is_const) {
29603
0
                    dbuf_putc(bc, OP_throw_error);
29604
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29605
0
                    dbuf_putc(bc, JS_THROW_VAR_RO);
29606
0
                    goto done;
29607
0
                }
29608
166
            }
29609
1.07k
            var_idx = idx;
29610
1.07k
            break;
29611
1.07k
        } else
29612
355k
        if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
29613
350k
            dbuf_putc(bc, OP_get_loc);
29614
350k
            dbuf_put_u16(bc, idx);
29615
350k
            var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
29616
350k
        }
29617
355k
        idx = vd->scope_next;
29618
355k
    }
29619
499k
    is_arg_scope = (idx == ARG_SCOPE_END);
29620
499k
    if (var_idx < 0) {
29621
        /* argument scope: variables are not visible but pseudo
29622
           variables are visible */
29623
498k
        if (!is_arg_scope) {
29624
498k
            var_idx = find_var(ctx, s, var_name);
29625
498k
        }
29626
29627
498k
        if (var_idx < 0 && is_pseudo_var)
29628
232
            var_idx = resolve_pseudo_var(ctx, s, var_name);
29629
29630
498k
        if (var_idx < 0 && var_name == JS_ATOM_arguments &&
29631
498k
            s->has_arguments_binding) {
29632
            /* 'arguments' pseudo variable */
29633
0
            var_idx = add_arguments_var(ctx, s);
29634
0
        }
29635
498k
        if (var_idx < 0 && s->is_func_expr && var_name == s->func_name) {
29636
            /* add a new variable with the function name */
29637
0
            var_idx = add_func_var(ctx, s, var_name);
29638
0
        }
29639
498k
    }
29640
499k
    if (var_idx >= 0) {
29641
4.06k
        if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
29642
4.06k
            !(var_idx & ARGUMENT_VAR_OFFSET) &&
29643
4.06k
            s->vars[var_idx].is_const) {
29644
            /* only happens when assigning a function expression name
29645
               in strict mode */
29646
0
            dbuf_putc(bc, OP_throw_error);
29647
0
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29648
0
            dbuf_putc(bc, JS_THROW_VAR_RO);
29649
0
            goto done;
29650
0
        }
29651
        /* OP_scope_put_var_init is only used to initialize a
29652
           lexical variable, so it is never used in a with or var object. It
29653
           can be used with a closure (module global variable case). */
29654
4.06k
        switch (op) {
29655
197
        case OP_scope_make_ref:
29656
197
            if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
29657
197
                s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
29658
                /* Create a dummy object reference for the func_var */
29659
0
                dbuf_putc(bc, OP_object);
29660
0
                dbuf_putc(bc, OP_get_loc);
29661
0
                dbuf_put_u16(bc, var_idx);
29662
0
                dbuf_putc(bc, OP_define_field);
29663
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29664
0
                dbuf_putc(bc, OP_push_atom_value);
29665
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29666
0
            } else
29667
197
            if (label_done == -1 && can_opt_put_ref_value(bc_buf, ls->pos)) {
29668
191
                int get_op;
29669
191
                if (var_idx & ARGUMENT_VAR_OFFSET) {
29670
21
                    get_op = OP_get_arg;
29671
21
                    var_idx -= ARGUMENT_VAR_OFFSET;
29672
170
                } else {
29673
170
                    if (s->vars[var_idx].is_lexical)
29674
3
                        get_op = OP_get_loc_check;
29675
167
                    else
29676
167
                        get_op = OP_get_loc;
29677
170
                }
29678
191
                pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
29679
191
                                                   pos_next, get_op, var_idx);
29680
191
            } else {
29681
                /* Create a dummy object with a named slot that is
29682
                   a reference to the local variable */
29683
6
                if (var_idx & ARGUMENT_VAR_OFFSET) {
29684
0
                    dbuf_putc(bc, OP_make_arg_ref);
29685
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29686
0
                    dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
29687
6
                } else {
29688
6
                    dbuf_putc(bc, OP_make_loc_ref);
29689
6
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29690
6
                    dbuf_put_u16(bc, var_idx);
29691
6
                }
29692
6
            }
29693
197
            break;
29694
0
        case OP_scope_get_ref:
29695
0
            dbuf_putc(bc, OP_undefined);
29696
            /* fall thru */
29697
0
        case OP_scope_get_var_undef:
29698
3.06k
        case OP_scope_get_var:
29699
3.16k
        case OP_scope_put_var:
29700
3.87k
        case OP_scope_put_var_init:
29701
3.87k
            is_put = (op == OP_scope_put_var || op == OP_scope_put_var_init);
29702
3.87k
            if (var_idx & ARGUMENT_VAR_OFFSET) {
29703
21
                dbuf_putc(bc, OP_get_arg + is_put);
29704
21
                dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
29705
3.85k
            } else {
29706
3.85k
                if (is_put) {
29707
805
                    if (s->vars[var_idx].is_lexical) {
29708
704
                        if (op == OP_scope_put_var_init) {
29709
                            /* 'this' can only be initialized once */
29710
704
                            if (var_name == JS_ATOM_this)
29711
0
                                dbuf_putc(bc, OP_put_loc_check_init);
29712
704
                            else
29713
704
                                dbuf_putc(bc, OP_put_loc);
29714
704
                        } else {
29715
0
                            dbuf_putc(bc, OP_put_loc_check);
29716
0
                        }
29717
704
                    } else {
29718
101
                        dbuf_putc(bc, OP_put_loc);
29719
101
                    }
29720
3.04k
                } else {
29721
3.04k
                    if (s->vars[var_idx].is_lexical) {
29722
148
                        dbuf_putc(bc, OP_get_loc_check);
29723
2.89k
                    } else {
29724
2.89k
                        dbuf_putc(bc, OP_get_loc);
29725
2.89k
                    }
29726
3.04k
                }
29727
3.85k
                dbuf_put_u16(bc, var_idx);
29728
3.85k
            }
29729
3.87k
            break;
29730
0
        case OP_scope_delete_var:
29731
0
            dbuf_putc(bc, OP_push_false);
29732
0
            break;
29733
4.06k
        }
29734
4.06k
        goto done;
29735
4.06k
    }
29736
    /* check eval object */
29737
495k
    if (!is_arg_scope && s->var_object_idx >= 0 && !is_pseudo_var) {
29738
0
        dbuf_putc(bc, OP_get_loc);
29739
0
        dbuf_put_u16(bc, s->var_object_idx);
29740
0
        var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
29741
0
    }
29742
    /* check eval object in argument scope */
29743
495k
    if (s->arg_var_object_idx >= 0 && !is_pseudo_var) {
29744
0
        dbuf_putc(bc, OP_get_loc);
29745
0
        dbuf_put_u16(bc, s->arg_var_object_idx);
29746
0
        var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
29747
0
    }
29748
29749
    /* check parent scopes */
29750
514k
    for (fd = s; fd->parent;) {
29751
36.3k
        scope_level = fd->parent_scope_level;
29752
36.3k
        fd = fd->parent;
29753
50.8k
        for (idx = fd->scopes[scope_level].first; idx >= 0;) {
29754
14.9k
            vd = &fd->vars[idx];
29755
14.9k
            if (vd->var_name == var_name) {
29756
469
                if (op == OP_scope_put_var || op == OP_scope_make_ref) {
29757
163
                    if (vd->is_const) {
29758
0
                        dbuf_putc(bc, OP_throw_error);
29759
0
                        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29760
0
                        dbuf_putc(bc, JS_THROW_VAR_RO);
29761
0
                        goto done;
29762
0
                    }
29763
163
                }
29764
469
                var_idx = idx;
29765
469
                break;
29766
14.5k
            } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
29767
1.08k
                vd->is_captured = 1;
29768
1.08k
                idx = get_closure_var(ctx, s, fd, FALSE, idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
29769
1.08k
                if (idx >= 0) {
29770
1.08k
                    dbuf_putc(bc, OP_get_var_ref);
29771
1.08k
                    dbuf_put_u16(bc, idx);
29772
1.08k
                    var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
29773
1.08k
                }
29774
1.08k
            }
29775
14.5k
            idx = vd->scope_next;
29776
14.5k
        }
29777
36.3k
        is_arg_scope = (idx == ARG_SCOPE_END);
29778
36.3k
        if (var_idx >= 0)
29779
469
            break;
29780
        
29781
35.8k
        if (!is_arg_scope) {
29782
35.7k
            var_idx = find_var(ctx, fd, var_name);
29783
35.7k
            if (var_idx >= 0)
29784
62
                break;
29785
35.7k
        }
29786
35.7k
        if (is_pseudo_var) {
29787
0
            var_idx = resolve_pseudo_var(ctx, fd, var_name);
29788
0
            if (var_idx >= 0)
29789
0
                break;
29790
0
        }
29791
35.7k
        if (var_name == JS_ATOM_arguments && fd->has_arguments_binding) {
29792
0
            var_idx = add_arguments_var(ctx, fd);
29793
0
            break;
29794
0
        }
29795
35.7k
        if (fd->is_func_expr && fd->func_name == var_name) {
29796
            /* add a new variable with the function name */
29797
0
            var_idx = add_func_var(ctx, fd, var_name);
29798
0
            break;
29799
0
        }
29800
29801
        /* check eval object */
29802
35.7k
        if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
29803
0
            vd = &fd->vars[fd->var_object_idx];
29804
0
            vd->is_captured = 1;
29805
0
            idx = get_closure_var(ctx, s, fd, FALSE,
29806
0
                                  fd->var_object_idx, vd->var_name,
29807
0
                                  FALSE, FALSE, JS_VAR_NORMAL);
29808
0
            dbuf_putc(bc, OP_get_var_ref);
29809
0
            dbuf_put_u16(bc, idx);
29810
0
            var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
29811
0
        }
29812
29813
        /* check eval object in argument scope */
29814
35.7k
        if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
29815
0
            vd = &fd->vars[fd->arg_var_object_idx];
29816
0
            vd->is_captured = 1;
29817
0
            idx = get_closure_var(ctx, s, fd, FALSE,
29818
0
                                  fd->arg_var_object_idx, vd->var_name,
29819
0
                                  FALSE, FALSE, JS_VAR_NORMAL);
29820
0
            dbuf_putc(bc, OP_get_var_ref);
29821
0
            dbuf_put_u16(bc, idx);
29822
0
            var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
29823
0
        }
29824
        
29825
35.7k
        if (fd->is_eval)
29826
17.2k
            break; /* it it necessarily the top level function */
29827
35.7k
    }
29828
29829
    /* check direct eval scope (in the closure of the eval function
29830
       which is necessarily at the top level) */
29831
495k
    if (!fd)
29832
0
        fd = s;
29833
495k
    if (var_idx < 0 && fd->is_eval) {
29834
495k
        int idx1;
29835
12.6M
        for (idx1 = 0; idx1 < fd->closure_var_count; idx1++) {
29836
12.2M
            JSClosureVar *cv = &fd->closure_var[idx1];
29837
12.2M
            if (var_name == cv->var_name) {
29838
23.5k
                if (fd != s) {
29839
20
                    idx = get_closure_var2(ctx, s, fd,
29840
20
                                           FALSE,
29841
20
                                           cv->is_arg, idx1,
29842
20
                                           cv->var_name, cv->is_const,
29843
20
                                           cv->is_lexical, cv->var_kind);
29844
23.5k
                } else {
29845
23.5k
                    idx = idx1;
29846
23.5k
                }
29847
23.5k
                goto has_idx;
29848
12.1M
            } else if ((cv->var_name == JS_ATOM__var_ ||
29849
12.1M
                        cv->var_name == JS_ATOM__arg_var_ ||
29850
12.1M
                        cv->var_name == JS_ATOM__with_) && !is_pseudo_var) {
29851
0
                int is_with = (cv->var_name == JS_ATOM__with_);
29852
0
                if (fd != s) {
29853
0
                    idx = get_closure_var2(ctx, s, fd,
29854
0
                                           FALSE,
29855
0
                                           cv->is_arg, idx1,
29856
0
                                           cv->var_name, FALSE, FALSE,
29857
0
                                           JS_VAR_NORMAL);
29858
0
                } else {
29859
0
                    idx = idx1;
29860
0
                }
29861
0
                dbuf_putc(bc, OP_get_var_ref);
29862
0
                dbuf_put_u16(bc, idx);
29863
0
                var_object_test(ctx, s, var_name, op, bc, &label_done, is_with);
29864
0
            }
29865
12.2M
        }
29866
495k
    }
29867
29868
472k
    if (var_idx >= 0) {
29869
        /* find the corresponding closure variable */
29870
531
        if (var_idx & ARGUMENT_VAR_OFFSET) {
29871
62
            fd->args[var_idx - ARGUMENT_VAR_OFFSET].is_captured = 1;
29872
62
            idx = get_closure_var(ctx, s, fd,
29873
62
                                  TRUE, var_idx - ARGUMENT_VAR_OFFSET,
29874
62
                                  var_name, FALSE, FALSE, JS_VAR_NORMAL);
29875
469
        } else {
29876
469
            fd->vars[var_idx].is_captured = 1;
29877
469
            idx = get_closure_var(ctx, s, fd,
29878
469
                                  FALSE, var_idx,
29879
469
                                  var_name,
29880
469
                                  fd->vars[var_idx].is_const,
29881
469
                                  fd->vars[var_idx].is_lexical,
29882
469
                                  fd->vars[var_idx].var_kind);
29883
469
        }
29884
531
        if (idx >= 0) {
29885
24.1k
        has_idx:
29886
24.1k
            if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
29887
24.1k
                s->closure_var[idx].is_const) {
29888
0
                dbuf_putc(bc, OP_throw_error);
29889
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29890
0
                dbuf_putc(bc, JS_THROW_VAR_RO);
29891
0
                goto done;
29892
0
            }
29893
24.1k
            switch (op) {
29894
22.9k
            case OP_scope_make_ref:
29895
22.9k
                if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
29896
                    /* Create a dummy object reference for the func_var */
29897
0
                    dbuf_putc(bc, OP_object);
29898
0
                    dbuf_putc(bc, OP_get_var_ref);
29899
0
                    dbuf_put_u16(bc, idx);
29900
0
                    dbuf_putc(bc, OP_define_field);
29901
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29902
0
                    dbuf_putc(bc, OP_push_atom_value);
29903
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29904
0
                } else
29905
22.9k
                if (label_done == -1 &&
29906
22.9k
                    can_opt_put_ref_value(bc_buf, ls->pos)) {
29907
482
                    int get_op;
29908
482
                    if (s->closure_var[idx].is_lexical)
29909
14
                        get_op = OP_get_var_ref_check;
29910
468
                    else
29911
468
                        get_op = OP_get_var_ref;
29912
482
                    pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
29913
482
                                                       pos_next,
29914
482
                                                       get_op, idx);
29915
22.5k
                } else {
29916
                    /* Create a dummy object with a named slot that is
29917
                       a reference to the closure variable */
29918
22.5k
                    dbuf_putc(bc, OP_make_var_ref_ref);
29919
22.5k
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29920
22.5k
                    dbuf_put_u16(bc, idx);
29921
22.5k
                }
29922
22.9k
                break;
29923
0
            case OP_scope_get_ref:
29924
                /* XXX: should create a dummy object with a named slot that is
29925
                   a reference to the closure variable */
29926
0
                dbuf_putc(bc, OP_undefined);
29927
                /* fall thru */
29928
0
            case OP_scope_get_var_undef:
29929
1.12k
            case OP_scope_get_var:
29930
1.12k
            case OP_scope_put_var:
29931
1.12k
            case OP_scope_put_var_init:
29932
1.12k
                is_put = (op == OP_scope_put_var ||
29933
1.12k
                          op == OP_scope_put_var_init);
29934
1.12k
                if (is_put) {
29935
0
                    if (s->closure_var[idx].is_lexical) {
29936
0
                        if (op == OP_scope_put_var_init) {
29937
                            /* 'this' can only be initialized once */
29938
0
                            if (var_name == JS_ATOM_this)
29939
0
                                dbuf_putc(bc, OP_put_var_ref_check_init);
29940
0
                            else
29941
0
                                dbuf_putc(bc, OP_put_var_ref);
29942
0
                        } else {
29943
0
                            dbuf_putc(bc, OP_put_var_ref_check);
29944
0
                        }
29945
0
                    } else {
29946
0
                        dbuf_putc(bc, OP_put_var_ref);
29947
0
                    }
29948
1.12k
                } else {
29949
1.12k
                    if (s->closure_var[idx].is_lexical) {
29950
305
                        dbuf_putc(bc, OP_get_var_ref_check);
29951
819
                    } else {
29952
819
                        dbuf_putc(bc, OP_get_var_ref);
29953
819
                    }
29954
1.12k
                }
29955
1.12k
                dbuf_put_u16(bc, idx);
29956
1.12k
                break;
29957
0
            case OP_scope_delete_var:
29958
0
                dbuf_putc(bc, OP_push_false);
29959
0
                break;
29960
24.1k
            }
29961
24.1k
            goto done;
29962
24.1k
        }
29963
531
    }
29964
29965
    /* global variable access */
29966
29967
471k
    switch (op) {
29968
213k
    case OP_scope_make_ref:
29969
213k
        if (label_done == -1 && can_opt_put_global_ref_value(bc_buf, ls->pos)) {
29970
21.1k
            pos_next = optimize_scope_make_global_ref(ctx, s, bc, bc_buf, ls,
29971
21.1k
                                                      pos_next, var_name);
29972
192k
        } else {
29973
192k
            dbuf_putc(bc, OP_make_var_ref);
29974
192k
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29975
192k
        }
29976
213k
        break;
29977
502
    case OP_scope_get_ref:
29978
        /* XXX: should create a dummy object with a named slot that is
29979
           a reference to the global variable */
29980
502
        dbuf_putc(bc, OP_undefined);
29981
502
        dbuf_putc(bc, OP_get_var);
29982
502
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29983
502
        break;
29984
0
    case OP_scope_get_var_undef:
29985
257k
    case OP_scope_get_var:
29986
257k
    case OP_scope_put_var:
29987
257k
        dbuf_putc(bc, OP_get_var_undef + (op - OP_scope_get_var_undef));
29988
257k
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29989
257k
        break;
29990
0
    case OP_scope_put_var_init:
29991
0
        dbuf_putc(bc, OP_put_var_init);
29992
0
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29993
0
        break;
29994
0
    case OP_scope_delete_var:
29995
0
        dbuf_putc(bc, OP_delete_var);
29996
0
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
29997
0
        break;
29998
471k
    }
29999
499k
done:
30000
499k
    if (label_done >= 0) {
30001
342k
        dbuf_putc(bc, OP_label);
30002
342k
        dbuf_put_u32(bc, label_done);
30003
342k
        s->label_slots[label_done].pos2 = bc->size;
30004
342k
    }
30005
499k
    return pos_next;
30006
471k
}
30007
30008
/* search in all scopes */
30009
static int find_private_class_field_all(JSContext *ctx, JSFunctionDef *fd,
30010
                                        JSAtom name, int scope_level)
30011
0
{
30012
0
    int idx;
30013
30014
0
    idx = fd->scopes[scope_level].first;
30015
0
    while (idx >= 0) {
30016
0
        if (fd->vars[idx].var_name == name)
30017
0
            return idx;
30018
0
        idx = fd->vars[idx].scope_next;
30019
0
    }
30020
0
    return -1;
30021
0
}
30022
30023
static void get_loc_or_ref(DynBuf *bc, BOOL is_ref, int idx)
30024
0
{
30025
    /* if the field is not initialized, the error is catched when
30026
       accessing it */
30027
0
    if (is_ref) 
30028
0
        dbuf_putc(bc, OP_get_var_ref);
30029
0
    else
30030
0
        dbuf_putc(bc, OP_get_loc);
30031
0
    dbuf_put_u16(bc, idx);
30032
0
}
30033
30034
static int resolve_scope_private_field1(JSContext *ctx,
30035
                                        BOOL *pis_ref, int *pvar_kind,
30036
                                        JSFunctionDef *s,
30037
                                        JSAtom var_name, int scope_level)
30038
0
{
30039
0
    int idx, var_kind;
30040
0
    JSFunctionDef *fd;
30041
0
    BOOL is_ref;
30042
    
30043
0
    fd = s;
30044
0
    is_ref = FALSE;
30045
0
    for(;;) {
30046
0
        idx = find_private_class_field_all(ctx, fd, var_name, scope_level);
30047
0
        if (idx >= 0) {
30048
0
            var_kind = fd->vars[idx].var_kind;
30049
0
            if (is_ref) {
30050
0
                idx = get_closure_var(ctx, s, fd, FALSE, idx, var_name,
30051
0
                                      TRUE, TRUE, JS_VAR_NORMAL);
30052
0
                if (idx < 0)
30053
0
                    return -1;
30054
0
            }
30055
0
            break;
30056
0
        }
30057
0
        scope_level = fd->parent_scope_level;
30058
0
        if (!fd->parent) {
30059
0
            if (fd->is_eval) {
30060
                /* closure of the eval function (top level) */
30061
0
                for (idx = 0; idx < fd->closure_var_count; idx++) {
30062
0
                    JSClosureVar *cv = &fd->closure_var[idx];
30063
0
                    if (cv->var_name == var_name) {
30064
0
                        var_kind = cv->var_kind;
30065
0
                        is_ref = TRUE;
30066
0
                        if (fd != s) {
30067
0
                            idx = get_closure_var2(ctx, s, fd,
30068
0
                                                   FALSE,
30069
0
                                                   cv->is_arg, idx,
30070
0
                                                   cv->var_name, cv->is_const,
30071
0
                                                   cv->is_lexical,
30072
0
                                                   cv->var_kind);
30073
0
                            if (idx < 0)
30074
0
                                return -1;
30075
0
                        }
30076
0
                        goto done;
30077
0
                    }
30078
0
                }
30079
0
            }
30080
            /* XXX: no line number info */
30081
0
            JS_ThrowSyntaxErrorAtom(ctx, "undefined private field '%s'",
30082
0
                                    var_name);
30083
0
            return -1;
30084
0
        } else {
30085
0
            fd = fd->parent;
30086
0
        }
30087
0
        is_ref = TRUE;
30088
0
    }
30089
0
 done:
30090
0
    *pis_ref = is_ref;
30091
0
    *pvar_kind = var_kind;
30092
0
    return idx;
30093
0
}
30094
30095
/* return 0 if OK or -1 if the private field could not be resolved */
30096
static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
30097
                                       JSAtom var_name, int scope_level, int op,
30098
                                       DynBuf *bc)
30099
0
{
30100
0
    int idx, var_kind;
30101
0
    BOOL is_ref;
30102
30103
0
    idx = resolve_scope_private_field1(ctx, &is_ref, &var_kind, s,
30104
0
                                       var_name, scope_level);
30105
0
    if (idx < 0)
30106
0
        return -1;
30107
0
    assert(var_kind != JS_VAR_NORMAL);
30108
0
    switch (op) {
30109
0
    case OP_scope_get_private_field:
30110
0
    case OP_scope_get_private_field2:
30111
0
        switch(var_kind) {
30112
0
        case JS_VAR_PRIVATE_FIELD:
30113
0
            if (op == OP_scope_get_private_field2)
30114
0
                dbuf_putc(bc, OP_dup);
30115
0
            get_loc_or_ref(bc, is_ref, idx);
30116
0
            dbuf_putc(bc, OP_get_private_field);
30117
0
            break;
30118
0
        case JS_VAR_PRIVATE_METHOD:
30119
0
            get_loc_or_ref(bc, is_ref, idx);
30120
0
            dbuf_putc(bc, OP_check_brand);
30121
0
            if (op != OP_scope_get_private_field2)
30122
0
                dbuf_putc(bc, OP_nip);
30123
0
            break;
30124
0
        case JS_VAR_PRIVATE_GETTER:
30125
0
        case JS_VAR_PRIVATE_GETTER_SETTER:
30126
0
            if (op == OP_scope_get_private_field2)
30127
0
                dbuf_putc(bc, OP_dup);
30128
0
            get_loc_or_ref(bc, is_ref, idx);
30129
0
            dbuf_putc(bc, OP_check_brand);
30130
0
            dbuf_putc(bc, OP_call_method);
30131
0
            dbuf_put_u16(bc, 0);
30132
0
            break;
30133
0
        case JS_VAR_PRIVATE_SETTER:
30134
            /* XXX: add clearer error message */
30135
0
            dbuf_putc(bc, OP_throw_error);
30136
0
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30137
0
            dbuf_putc(bc, JS_THROW_VAR_RO);
30138
0
            break;
30139
0
        default:
30140
0
            abort();
30141
0
        }
30142
0
        break;
30143
0
    case OP_scope_put_private_field:
30144
0
        switch(var_kind) {
30145
0
        case JS_VAR_PRIVATE_FIELD:
30146
0
            get_loc_or_ref(bc, is_ref, idx);
30147
0
            dbuf_putc(bc, OP_put_private_field);
30148
0
            break;
30149
0
        case JS_VAR_PRIVATE_METHOD:
30150
0
        case JS_VAR_PRIVATE_GETTER:
30151
            /* XXX: add clearer error message */
30152
0
            dbuf_putc(bc, OP_throw_error);
30153
0
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
30154
0
            dbuf_putc(bc, JS_THROW_VAR_RO);
30155
0
            break;
30156
0
        case JS_VAR_PRIVATE_SETTER:
30157
0
        case JS_VAR_PRIVATE_GETTER_SETTER:
30158
0
            {
30159
0
                JSAtom setter_name = get_private_setter_name(ctx, var_name);
30160
0
                if (setter_name == JS_ATOM_NULL)
30161
0
                    return -1;
30162
0
                idx = resolve_scope_private_field1(ctx, &is_ref,
30163
0
                                                   &var_kind, s,
30164
0
                                                   setter_name, scope_level);
30165
0
                JS_FreeAtom(ctx, setter_name);
30166
0
                if (idx < 0)
30167
0
                    return -1;
30168
0
                assert(var_kind == JS_VAR_PRIVATE_SETTER);
30169
0
                get_loc_or_ref(bc, is_ref, idx);
30170
0
                dbuf_putc(bc, OP_swap);
30171
                /* obj func value */
30172
0
                dbuf_putc(bc, OP_rot3r);
30173
                /* value obj func */
30174
0
                dbuf_putc(bc, OP_check_brand);
30175
0
                dbuf_putc(bc, OP_rot3l);
30176
                /* obj func value */
30177
0
                dbuf_putc(bc, OP_call_method);
30178
0
                dbuf_put_u16(bc, 1);
30179
0
            }
30180
0
            break;
30181
0
        default:
30182
0
            abort();
30183
0
        }
30184
0
        break;
30185
0
    default:
30186
0
        abort();
30187
0
    }
30188
0
    return 0;
30189
0
}
30190
30191
static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,
30192
                                         int scope_level)
30193
5
{
30194
5
    int idx;
30195
5
    JSVarDef *vd;
30196
30197
9
    for (idx = s->scopes[scope_level].first; idx >= 0;) {
30198
4
        vd = &s->vars[idx];
30199
4
        vd->is_captured = 1;
30200
4
        idx = vd->scope_next;
30201
4
    }
30202
5
}
30203
30204
/* XXX: should handle the argument scope generically */
30205
static BOOL is_var_in_arg_scope(const JSVarDef *vd)
30206
0
{
30207
0
    return (vd->var_name == JS_ATOM_home_object ||
30208
0
            vd->var_name == JS_ATOM_this_active_func ||
30209
0
            vd->var_name == JS_ATOM_new_target ||
30210
0
            vd->var_name == JS_ATOM_this ||
30211
0
            vd->var_name == JS_ATOM__arg_var_ ||
30212
0
            vd->var_kind == JS_VAR_FUNCTION_NAME);
30213
0
}
30214
30215
static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
30216
4
{
30217
4
    JSFunctionDef *fd;
30218
4
    JSVarDef *vd;
30219
4
    int i, scope_level, scope_idx;
30220
4
    BOOL has_arguments_binding, has_this_binding, is_arg_scope;
30221
30222
    /* in non strict mode, variables are created in the caller's
30223
       environment object */
30224
4
    if (!s->is_eval && !(s->js_mode & JS_MODE_STRICT)) {
30225
0
        s->var_object_idx = add_var(ctx, s, JS_ATOM__var_);
30226
0
        if (s->has_parameter_expressions) {
30227
            /* an additional variable object is needed for the
30228
               argument scope */
30229
0
            s->arg_var_object_idx = add_var(ctx, s, JS_ATOM__arg_var_);
30230
0
        }
30231
0
    }
30232
30233
    /* eval can potentially use 'arguments' so we must define it */
30234
4
    has_this_binding = s->has_this_binding;
30235
4
    if (has_this_binding) {
30236
3
        if (s->this_var_idx < 0)
30237
3
            s->this_var_idx = add_var_this(ctx, s);
30238
3
        if (s->new_target_var_idx < 0)
30239
3
            s->new_target_var_idx = add_var(ctx, s, JS_ATOM_new_target);
30240
3
        if (s->is_derived_class_constructor && s->this_active_func_var_idx < 0)
30241
0
            s->this_active_func_var_idx = add_var(ctx, s, JS_ATOM_this_active_func);
30242
3
        if (s->has_home_object && s->home_object_var_idx < 0)
30243
0
            s->home_object_var_idx = add_var(ctx, s, JS_ATOM_home_object);
30244
3
    }
30245
4
    has_arguments_binding = s->has_arguments_binding;
30246
4
    if (has_arguments_binding) {
30247
1
        add_arguments_var(ctx, s);
30248
        /* also add an arguments binding in the argument scope to
30249
           raise an error if a direct eval in the argument scope tries
30250
           to redefine it */
30251
1
        if (s->has_parameter_expressions && !(s->js_mode & JS_MODE_STRICT))
30252
0
            add_arguments_arg(ctx, s);
30253
1
    }
30254
4
    if (s->is_func_expr && s->func_name != JS_ATOM_NULL)
30255
0
        add_func_var(ctx, s, s->func_name);
30256
30257
    /* eval can use all the variables of the enclosing functions, so
30258
       they must be all put in the closure. The closure variables are
30259
       ordered by scope. It works only because no closure are created
30260
       before. */
30261
4
    assert(s->is_eval || s->closure_var_count == 0);
30262
30263
    /* XXX: inefficient, but eval performance is less critical */
30264
4
    fd = s;
30265
8
    for(;;) {
30266
8
        scope_level = fd->parent_scope_level;
30267
8
        fd = fd->parent;
30268
8
        if (!fd)
30269
4
            break;
30270
        /* add 'this' if it was not previously added */
30271
4
        if (!has_this_binding && fd->has_this_binding) {
30272
1
            if (fd->this_var_idx < 0)
30273
0
                fd->this_var_idx = add_var_this(ctx, fd);
30274
1
            if (fd->new_target_var_idx < 0)
30275
0
                fd->new_target_var_idx = add_var(ctx, fd, JS_ATOM_new_target);
30276
1
            if (fd->is_derived_class_constructor && fd->this_active_func_var_idx < 0)
30277
0
                fd->this_active_func_var_idx = add_var(ctx, fd, JS_ATOM_this_active_func);
30278
1
            if (fd->has_home_object && fd->home_object_var_idx < 0)
30279
0
                fd->home_object_var_idx = add_var(ctx, fd, JS_ATOM_home_object);
30280
1
            has_this_binding = TRUE;
30281
1
        }
30282
        /* add 'arguments' if it was not previously added */
30283
4
        if (!has_arguments_binding && fd->has_arguments_binding) {
30284
0
            add_arguments_var(ctx, fd);
30285
0
            has_arguments_binding = TRUE;
30286
0
        }
30287
        /* add function name */
30288
4
        if (fd->is_func_expr && fd->func_name != JS_ATOM_NULL)
30289
0
            add_func_var(ctx, fd, fd->func_name);
30290
30291
        /* add lexical variables */
30292
4
        scope_idx = fd->scopes[scope_level].first;
30293
10
        while (scope_idx >= 0) {
30294
6
            vd = &fd->vars[scope_idx];
30295
6
            vd->is_captured = 1;
30296
6
            get_closure_var(ctx, s, fd, FALSE, scope_idx,
30297
6
                            vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);
30298
6
            scope_idx = vd->scope_next;
30299
6
        }
30300
4
        is_arg_scope = (scope_idx == ARG_SCOPE_END);
30301
4
        if (!is_arg_scope) {
30302
            /* add unscoped variables */
30303
6
            for(i = 0; i < fd->arg_count; i++) {
30304
2
                vd = &fd->args[i];
30305
2
                if (vd->var_name != JS_ATOM_NULL) {
30306
2
                    get_closure_var(ctx, s, fd,
30307
2
                                    TRUE, i, vd->var_name, FALSE, FALSE,
30308
2
                                    JS_VAR_NORMAL);
30309
2
                }
30310
2
            }
30311
21
            for(i = 0; i < fd->var_count; i++) {
30312
17
                vd = &fd->vars[i];
30313
                /* do not close top level last result */
30314
17
                if (vd->scope_level == 0 &&
30315
17
                    vd->var_name != JS_ATOM__ret_ &&
30316
17
                    vd->var_name != JS_ATOM_NULL) {
30317
2
                    get_closure_var(ctx, s, fd,
30318
2
                                    FALSE, i, vd->var_name, FALSE, FALSE,
30319
2
                                    JS_VAR_NORMAL);
30320
2
                }
30321
17
            }
30322
4
        } else {
30323
0
            for(i = 0; i < fd->var_count; i++) {
30324
0
                vd = &fd->vars[i];
30325
                /* do not close top level last result */
30326
0
                if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
30327
0
                    get_closure_var(ctx, s, fd,
30328
0
                                    FALSE, i, vd->var_name, FALSE, FALSE,
30329
0
                                    JS_VAR_NORMAL);
30330
0
                }
30331
0
            }
30332
0
        }
30333
4
        if (fd->is_eval) {
30334
2
            int idx;
30335
            /* add direct eval variables (we are necessarily at the
30336
               top level) */
30337
131
            for (idx = 0; idx < fd->closure_var_count; idx++) {
30338
129
                JSClosureVar *cv = &fd->closure_var[idx];
30339
129
                get_closure_var2(ctx, s, fd,
30340
129
                                 FALSE, cv->is_arg,
30341
129
                                 idx, cv->var_name, cv->is_const,
30342
129
                                 cv->is_lexical, cv->var_kind);
30343
129
            }
30344
2
        }
30345
4
    }
30346
4
}
30347
30348
static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
30349
                                 JSVarDef *vd, int var_idx)
30350
81.9k
{
30351
81.9k
    cv->is_local = TRUE;
30352
81.9k
    cv->is_arg = FALSE;
30353
81.9k
    cv->is_const = vd->is_const;
30354
81.9k
    cv->is_lexical = vd->is_lexical;
30355
81.9k
    cv->var_kind = vd->var_kind;
30356
81.9k
    cv->var_idx = var_idx;
30357
81.9k
    cv->var_name = JS_DupAtom(ctx, vd->var_name);
30358
81.9k
}
30359
30360
/* for direct eval compilation: add references to the variables of the
30361
   calling function */
30362
static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
30363
                                             JSFunctionBytecode *b, int scope_idx)
30364
40.9k
{
30365
40.9k
    int i, count;
30366
40.9k
    JSVarDef *vd;
30367
40.9k
    BOOL is_arg_scope;
30368
    
30369
40.9k
    count = b->arg_count + b->var_count + b->closure_var_count;
30370
40.9k
    s->closure_var = NULL;
30371
40.9k
    s->closure_var_count = 0;
30372
40.9k
    s->closure_var_size = count;
30373
40.9k
    if (count == 0)
30374
0
        return 0;
30375
40.9k
    s->closure_var = js_malloc(ctx, sizeof(s->closure_var[0]) * count);
30376
40.9k
    if (!s->closure_var)
30377
1
        return -1;
30378
    /* Add lexical variables in scope at the point of evaluation */
30379
40.9k
    for (i = scope_idx; i >= 0;) {
30380
0
        vd = &b->vardefs[b->arg_count + i];
30381
0
        if (vd->scope_level > 0) {
30382
0
            JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
30383
0
            set_closure_from_var(ctx, cv, vd, i);
30384
0
        }
30385
0
        i = vd->scope_next;
30386
0
    }
30387
40.9k
    is_arg_scope = (i == ARG_SCOPE_END);
30388
40.9k
    if (!is_arg_scope) {
30389
        /* Add argument variables */
30390
40.9k
        for(i = 0; i < b->arg_count; i++) {
30391
0
            JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
30392
0
            vd = &b->vardefs[i];
30393
0
            cv->is_local = TRUE;
30394
0
            cv->is_arg = TRUE;
30395
0
            cv->is_const = FALSE;
30396
0
            cv->is_lexical = FALSE;
30397
0
            cv->var_kind = JS_VAR_NORMAL;
30398
0
            cv->var_idx = i;
30399
0
            cv->var_name = JS_DupAtom(ctx, vd->var_name);
30400
0
        }
30401
        /* Add local non lexical variables */
30402
450k
        for(i = 0; i < b->var_count; i++) {
30403
409k
            vd = &b->vardefs[b->arg_count + i];
30404
409k
            if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) {
30405
81.9k
                JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
30406
81.9k
                set_closure_from_var(ctx, cv, vd, i);
30407
81.9k
            }
30408
409k
        }
30409
40.9k
    } else {
30410
        /* only add pseudo variables */
30411
0
        for(i = 0; i < b->var_count; i++) {
30412
0
            vd = &b->vardefs[b->arg_count + i];
30413
0
            if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
30414
0
                JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
30415
0
                set_closure_from_var(ctx, cv, vd, i);
30416
0
            }
30417
0
        }
30418
0
    }
30419
2.78M
    for(i = 0; i < b->closure_var_count; i++) {
30420
2.74M
        JSClosureVar *cv0 = &b->closure_var[i];
30421
2.74M
        JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
30422
2.74M
        cv->is_local = FALSE;
30423
2.74M
        cv->is_arg = cv0->is_arg;
30424
2.74M
        cv->is_const = cv0->is_const;
30425
2.74M
        cv->is_lexical = cv0->is_lexical;
30426
2.74M
        cv->var_kind = cv0->var_kind;
30427
2.74M
        cv->var_idx = i;
30428
2.74M
        cv->var_name = JS_DupAtom(ctx, cv0->var_name);
30429
2.74M
    }
30430
40.9k
    return 0;
30431
40.9k
}
30432
30433
typedef struct CodeContext {
30434
    const uint8_t *bc_buf; /* code buffer */
30435
    int bc_len;   /* length of the code buffer */
30436
    int pos;      /* position past the matched code pattern */
30437
    int line_num; /* last visited OP_line_num parameter or -1 */
30438
    int op;
30439
    int idx;
30440
    int label;
30441
    int val;
30442
    JSAtom atom;
30443
} CodeContext;
30444
30445
964k
#define M2(op1, op2)            ((op1) | ((op2) << 8))
30446
429k
#define M3(op1, op2, op3)       ((op1) | ((op2) << 8) | ((op3) << 16))
30447
74
#define M4(op1, op2, op3, op4)  ((op1) | ((op2) << 8) | ((op3) << 16) | ((op4) << 24))
30448
30449
static BOOL code_match(CodeContext *s, int pos, ...)
30450
2.24M
{
30451
2.24M
    const uint8_t *tab = s->bc_buf;
30452
2.24M
    int op, len, op1, line_num, pos_next;
30453
2.24M
    va_list ap;
30454
2.24M
    BOOL ret = FALSE;
30455
30456
2.24M
    line_num = -1;
30457
2.24M
    va_start(ap, pos);
30458
30459
2.63M
    for(;;) {
30460
2.63M
        op1 = va_arg(ap, int);
30461
2.63M
        if (op1 == -1) {
30462
219k
            s->pos = pos;
30463
219k
            s->line_num = line_num;
30464
219k
            ret = TRUE;
30465
219k
            break;
30466
219k
        }
30467
2.43M
        for (;;) {
30468
2.43M
            if (pos >= s->bc_len)
30469
0
                goto done;
30470
2.43M
            op = tab[pos];
30471
2.43M
            len = opcode_info[op].size;
30472
2.43M
            pos_next = pos + len;
30473
2.43M
            if (pos_next > s->bc_len)
30474
0
                goto done;
30475
2.43M
            if (op == OP_line_num) {
30476
20.2k
                line_num = get_u32(tab + pos + 1);
30477
20.2k
                pos = pos_next;
30478
2.41M
            } else {
30479
2.41M
                break;
30480
2.41M
            }
30481
2.43M
        }
30482
2.41M
        if (op != op1) {
30483
2.19M
            if (op1 == (uint8_t)op1 || !op)
30484
807k
                break;
30485
1.39M
            if (op != (uint8_t)op1
30486
1.39M
            &&  op != (uint8_t)(op1 >> 8)
30487
1.39M
            &&  op != (uint8_t)(op1 >> 16)
30488
1.39M
            &&  op != (uint8_t)(op1 >> 24)) {
30489
1.21M
                break;
30490
1.21M
            }
30491
173k
            s->op = op;
30492
173k
        }
30493
30494
392k
        pos++;
30495
392k
        switch(opcode_info[op].fmt) {
30496
0
        case OP_FMT_loc8:
30497
0
        case OP_FMT_u8:
30498
0
            {
30499
0
                int idx = tab[pos];
30500
0
                int arg = va_arg(ap, int);
30501
0
                if (arg == -1) {
30502
0
                    s->idx = idx;
30503
0
                } else {
30504
0
                    if (arg != idx)
30505
0
                        goto done;
30506
0
                }
30507
0
                break;
30508
0
            }
30509
0
        case OP_FMT_u16:
30510
0
        case OP_FMT_npop:
30511
41.6k
        case OP_FMT_loc:
30512
41.7k
        case OP_FMT_arg:
30513
41.7k
        case OP_FMT_var_ref:
30514
41.7k
            {
30515
41.7k
                int idx = get_u16(tab + pos);
30516
41.7k
                int arg = va_arg(ap, int);
30517
41.7k
                if (arg == -1) {
30518
245
                    s->idx = idx;
30519
41.5k
                } else {
30520
41.5k
                    if (arg != idx)
30521
255
                        goto done;
30522
41.5k
                }
30523
41.5k
                break;
30524
41.7k
            }
30525
41.5k
        case OP_FMT_i32:
30526
2
        case OP_FMT_u32:
30527
3.77k
        case OP_FMT_label:
30528
3.77k
        case OP_FMT_const:
30529
3.77k
            {
30530
3.77k
                s->label = get_u32(tab + pos);
30531
3.77k
                break;
30532
3.77k
            }
30533
0
        case OP_FMT_label_u16:
30534
0
            {
30535
0
                s->label = get_u32(tab + pos);
30536
0
                s->val = get_u16(tab + pos + 4);
30537
0
                break;
30538
3.77k
            }
30539
458
        case OP_FMT_atom:
30540
458
            {
30541
458
                s->atom = get_u32(tab + pos);
30542
458
                break;
30543
3.77k
            }
30544
0
        case OP_FMT_atom_u8:
30545
0
            {
30546
0
                s->atom = get_u32(tab + pos);
30547
0
                s->val = get_u8(tab + pos + 4);
30548
0
                break;
30549
3.77k
            }
30550
0
        case OP_FMT_atom_u16:
30551
0
            {
30552
0
                s->atom = get_u32(tab + pos);
30553
0
                s->val = get_u16(tab + pos + 4);
30554
0
                break;
30555
3.77k
            }
30556
0
        case OP_FMT_atom_label_u8:
30557
0
            {
30558
0
                s->atom = get_u32(tab + pos);
30559
0
                s->label = get_u32(tab + pos + 4);
30560
0
                s->val = get_u8(tab + pos + 8);
30561
0
                break;
30562
3.77k
            }
30563
346k
        default:
30564
346k
            break;
30565
392k
        }
30566
392k
        pos = pos_next;
30567
392k
    }
30568
2.24M
 done:
30569
2.24M
    va_end(ap);
30570
2.24M
    return ret;
30571
2.24M
}
30572
30573
static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, DynBuf *bc)
30574
45.5k
{
30575
45.5k
    int i, idx, label_next = -1;
30576
30577
    /* add the hoisted functions in arguments and local variables */
30578
46.7k
    for(i = 0; i < s->arg_count; i++) {
30579
1.18k
        JSVarDef *vd = &s->args[i];
30580
1.18k
        if (vd->func_pool_idx >= 0) {
30581
0
            dbuf_putc(bc, OP_fclosure);
30582
0
            dbuf_put_u32(bc, vd->func_pool_idx);
30583
0
            dbuf_putc(bc, OP_put_arg);
30584
0
            dbuf_put_u16(bc, i);
30585
0
        }
30586
1.18k
    }
30587
88.2k
    for(i = 0; i < s->var_count; i++) {
30588
42.7k
        JSVarDef *vd = &s->vars[i];
30589
42.7k
        if (vd->scope_level == 0 && vd->func_pool_idx >= 0) {
30590
10
            dbuf_putc(bc, OP_fclosure);
30591
10
            dbuf_put_u32(bc, vd->func_pool_idx);
30592
10
            dbuf_putc(bc, OP_put_loc);
30593
10
            dbuf_put_u16(bc, i);
30594
10
        }
30595
42.7k
    }
30596
30597
    /* the module global variables must be initialized before
30598
       evaluating the module so that the exported functions are
30599
       visible if there are cyclic module references */
30600
45.5k
    if (s->module) {
30601
3
        label_next = new_label_fd(s, -1);
30602
        
30603
        /* if 'this' is true, initialize the global variables and return */
30604
3
        dbuf_putc(bc, OP_push_this);
30605
3
        dbuf_putc(bc, OP_if_false);
30606
3
        dbuf_put_u32(bc, label_next);
30607
3
        update_label(s, label_next, 1);
30608
3
        s->jump_size++;
30609
3
    }
30610
    
30611
    /* add the global variables (only happens if s->is_global_var is
30612
       true) */
30613
47.2k
    for(i = 0; i < s->global_var_count; i++) {
30614
1.70k
        JSGlobalVar *hf = &s->global_vars[i];
30615
1.70k
        int has_closure = 0;
30616
1.70k
        BOOL force_init = hf->force_init;
30617
        /* we are in an eval, so the closure contains all the
30618
           enclosing variables */
30619
        /* If the outer function has a variable environment,
30620
           create a property for the variable there */
30621
7.26k
        for(idx = 0; idx < s->closure_var_count; idx++) {
30622
6.07k
            JSClosureVar *cv = &s->closure_var[idx];
30623
6.07k
            if (cv->var_name == hf->var_name) {
30624
511
                has_closure = 2;
30625
511
                force_init = FALSE;
30626
511
                break;
30627
511
            }
30628
5.56k
            if (cv->var_name == JS_ATOM__var_ ||
30629
5.56k
                cv->var_name == JS_ATOM__arg_var_) {
30630
0
                dbuf_putc(bc, OP_get_var_ref);
30631
0
                dbuf_put_u16(bc, idx);
30632
0
                has_closure = 1;
30633
0
                force_init = TRUE;
30634
0
                break;
30635
0
            }
30636
5.56k
        }
30637
1.70k
        if (!has_closure) {
30638
1.19k
            int flags;
30639
            
30640
1.19k
            flags = 0;
30641
1.19k
            if (s->eval_type != JS_EVAL_TYPE_GLOBAL)
30642
0
                flags |= JS_PROP_CONFIGURABLE;
30643
1.19k
            if (hf->cpool_idx >= 0 && !hf->is_lexical) {
30644
                /* global function definitions need a specific handling */
30645
784
                dbuf_putc(bc, OP_fclosure);
30646
784
                dbuf_put_u32(bc, hf->cpool_idx);
30647
                
30648
784
                dbuf_putc(bc, OP_define_func);
30649
784
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
30650
784
                dbuf_putc(bc, flags);
30651
                
30652
784
                goto done_global_var;
30653
784
            } else {
30654
408
                if (hf->is_lexical) {
30655
0
                    flags |= DEFINE_GLOBAL_LEX_VAR;
30656
0
                    if (!hf->is_const)
30657
0
                        flags |= JS_PROP_WRITABLE;
30658
0
                }
30659
408
                dbuf_putc(bc, OP_define_var);
30660
408
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
30661
408
                dbuf_putc(bc, flags);
30662
408
            }
30663
1.19k
        }
30664
919
        if (hf->cpool_idx >= 0 || force_init) {
30665
0
            if (hf->cpool_idx >= 0) {
30666
0
                dbuf_putc(bc, OP_fclosure);
30667
0
                dbuf_put_u32(bc, hf->cpool_idx);
30668
0
                if (hf->var_name == JS_ATOM__default_) {
30669
                    /* set default export function name */
30670
0
                    dbuf_putc(bc, OP_set_name);
30671
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, JS_ATOM_default));
30672
0
                }
30673
0
            } else {
30674
0
                dbuf_putc(bc, OP_undefined);
30675
0
            }
30676
0
            if (has_closure == 2) {
30677
0
                dbuf_putc(bc, OP_put_var_ref);
30678
0
                dbuf_put_u16(bc, idx);
30679
0
            } else if (has_closure == 1) {
30680
0
                dbuf_putc(bc, OP_define_field);
30681
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
30682
0
                dbuf_putc(bc, OP_drop);
30683
0
            } else {
30684
                /* XXX: Check if variable is writable and enumerable */
30685
0
                dbuf_putc(bc, OP_put_var);
30686
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
30687
0
            }
30688
0
        }
30689
1.70k
    done_global_var:
30690
1.70k
        JS_FreeAtom(ctx, hf->var_name);
30691
1.70k
    }
30692
30693
45.5k
    if (s->module) {
30694
3
        dbuf_putc(bc, OP_return_undef);
30695
        
30696
3
        dbuf_putc(bc, OP_label);
30697
3
        dbuf_put_u32(bc, label_next);
30698
3
        s->label_slots[label_next].pos2 = bc->size;
30699
3
    }
30700
30701
45.5k
    js_free(ctx, s->global_vars);
30702
45.5k
    s->global_vars = NULL;
30703
45.5k
    s->global_var_count = 0;
30704
45.5k
    s->global_var_size = 0;
30705
45.5k
}
30706
30707
static int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len,
30708
                          int pos, int *linep)
30709
129k
{
30710
129k
    int op, len, label;
30711
30712
190k
    for (; pos < bc_len; pos += len) {
30713
99.5k
        op = bc_buf[pos];
30714
99.5k
        len = opcode_info[op].size;
30715
99.5k
        if (op == OP_line_num) {
30716
284
            *linep = get_u32(bc_buf + pos + 1);
30717
284
        } else
30718
99.2k
        if (op == OP_label) {
30719
55.0k
            label = get_u32(bc_buf + pos + 1);
30720
55.0k
            if (update_label(s, label, 0) > 0)
30721
38.0k
                break;
30722
#if 0
30723
            if (s->label_slots[label].first_reloc) {
30724
                printf("line %d: unreferenced label %d:%d has relocations\n",
30725
                       *linep, label, s->label_slots[label].pos2);
30726
            }
30727
#endif
30728
16.9k
            assert(s->label_slots[label].first_reloc == NULL);
30729
44.2k
        } else {
30730
            /* XXX: output a warning for unreachable code? */
30731
44.2k
            JSAtom atom;
30732
44.2k
            switch(opcode_info[op].fmt) {
30733
11.9k
            case OP_FMT_label:
30734
11.9k
            case OP_FMT_label_u16:
30735
11.9k
                label = get_u32(bc_buf + pos + 1);
30736
11.9k
                update_label(s, label, -1);
30737
11.9k
                break;
30738
0
            case OP_FMT_atom_label_u8:
30739
5.01k
            case OP_FMT_atom_label_u16:
30740
5.01k
                label = get_u32(bc_buf + pos + 5);
30741
5.01k
                update_label(s, label, -1);
30742
                /* fall thru */
30743
5.34k
            case OP_FMT_atom:
30744
5.35k
            case OP_FMT_atom_u8:
30745
10.4k
            case OP_FMT_atom_u16:
30746
10.4k
                atom = get_u32(bc_buf + pos + 1);
30747
10.4k
                JS_FreeAtom(s->ctx, atom);
30748
10.4k
                break;
30749
21.8k
            default:
30750
21.8k
                break;
30751
44.2k
            }
30752
44.2k
        }
30753
99.5k
    }
30754
129k
    return pos;
30755
129k
}
30756
30757
static int get_label_pos(JSFunctionDef *s, int label)
30758
3.01k
{
30759
3.01k
    int i, pos;
30760
3.02k
    for (i = 0; i < 20; i++) {
30761
3.02k
        pos = s->label_slots[label].pos;
30762
3.02k
        for (;;) {
30763
3.02k
            switch (s->byte_code.buf[pos]) {
30764
0
            case OP_line_num:
30765
0
            case OP_label:
30766
0
                pos += 5;
30767
0
                continue;
30768
8
            case OP_goto:
30769
8
                label = get_u32(s->byte_code.buf + pos + 1);
30770
8
                break;
30771
3.01k
            default:
30772
3.01k
                return pos;
30773
3.02k
            }
30774
8
            break;
30775
3.02k
        }
30776
3.02k
    }
30777
0
    return pos;
30778
3.01k
}
30779
30780
/* convert global variable accesses to local variables or closure
30781
   variables when necessary */
30782
static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
30783
45.6k
{
30784
45.6k
    int pos, pos_next, bc_len, op, len, i, idx, line_num;
30785
45.6k
    uint8_t *bc_buf;
30786
45.6k
    JSAtom var_name;
30787
45.6k
    DynBuf bc_out;
30788
45.6k
    CodeContext cc;
30789
45.6k
    int scope;
30790
30791
45.6k
    cc.bc_buf = bc_buf = s->byte_code.buf;
30792
45.6k
    cc.bc_len = bc_len = s->byte_code.size;
30793
45.6k
    js_dbuf_init(ctx, &bc_out);
30794
30795
    /* first pass for runtime checks (must be done before the
30796
       variables are created) */
30797
47.3k
    for(i = 0; i < s->global_var_count; i++) {
30798
1.70k
        JSGlobalVar *hf = &s->global_vars[i];
30799
1.70k
        int flags;
30800
        
30801
        /* check if global variable (XXX: simplify) */
30802
7.26k
        for(idx = 0; idx < s->closure_var_count; idx++) {
30803
6.07k
            JSClosureVar *cv = &s->closure_var[idx];
30804
6.07k
            if (cv->var_name == hf->var_name) {
30805
511
                if (s->eval_type == JS_EVAL_TYPE_DIRECT &&
30806
511
                    cv->is_lexical) {
30807
                    /* Check if a lexical variable is
30808
                       redefined as 'var'. XXX: Could abort
30809
                       compilation here, but for consistency
30810
                       with the other checks, we delay the
30811
                       error generation. */
30812
0
                    dbuf_putc(&bc_out, OP_throw_error);
30813
0
                    dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
30814
0
                    dbuf_putc(&bc_out, JS_THROW_VAR_REDECL);
30815
0
                }
30816
511
                goto next;
30817
511
            }
30818
5.56k
            if (cv->var_name == JS_ATOM__var_ ||
30819
5.56k
                cv->var_name == JS_ATOM__arg_var_)
30820
0
                goto next;
30821
5.56k
        }
30822
        
30823
1.19k
        dbuf_putc(&bc_out, OP_check_define_var);
30824
1.19k
        dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
30825
1.19k
        flags = 0;
30826
1.19k
        if (hf->is_lexical)
30827
0
            flags |= DEFINE_GLOBAL_LEX_VAR;
30828
1.19k
        if (hf->cpool_idx >= 0)
30829
784
            flags |= DEFINE_GLOBAL_FUNC_VAR;
30830
1.19k
        dbuf_putc(&bc_out, flags);
30831
1.70k
    next: ;
30832
1.70k
    }
30833
30834
45.6k
    line_num = 0; /* avoid warning */
30835
1.66M
    for (pos = 0; pos < bc_len; pos = pos_next) {
30836
1.62M
        op = bc_buf[pos];
30837
1.62M
        len = opcode_info[op].size;
30838
1.62M
        pos_next = pos + len;
30839
1.62M
        switch(op) {
30840
114k
        case OP_line_num:
30841
114k
            line_num = get_u32(bc_buf + pos + 1);
30842
114k
            s->line_number_size++;
30843
114k
            goto no_change;
30844
30845
3
        case OP_eval: /* convert scope index to adjusted variable index */
30846
3
            {
30847
3
                int call_argc = get_u16(bc_buf + pos + 1);
30848
3
                scope = get_u16(bc_buf + pos + 1 + 2);
30849
3
                mark_eval_captured_variables(ctx, s, scope);
30850
3
                dbuf_putc(&bc_out, op);
30851
3
                dbuf_put_u16(&bc_out, call_argc);
30852
3
                dbuf_put_u16(&bc_out, s->scopes[scope].first + 1);
30853
3
            }
30854
3
            break;
30855
2
        case OP_apply_eval: /* convert scope index to adjusted variable index */
30856
2
            scope = get_u16(bc_buf + pos + 1);
30857
2
            mark_eval_captured_variables(ctx, s, scope);
30858
2
            dbuf_putc(&bc_out, op);
30859
2
            dbuf_put_u16(&bc_out, s->scopes[scope].first + 1);
30860
2
            break;
30861
0
        case OP_scope_get_var_undef:
30862
261k
        case OP_scope_get_var:
30863
261k
        case OP_scope_put_var:
30864
261k
        case OP_scope_delete_var:
30865
262k
        case OP_scope_get_ref:
30866
262k
        case OP_scope_put_var_init:
30867
262k
            var_name = get_u32(bc_buf + pos + 1);
30868
262k
            scope = get_u16(bc_buf + pos + 5);
30869
262k
            pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
30870
262k
                                         NULL, NULL, pos_next);
30871
262k
            JS_FreeAtom(ctx, var_name);
30872
262k
            break;
30873
236k
        case OP_scope_make_ref:
30874
236k
            {
30875
236k
                int label;
30876
236k
                LabelSlot *ls;
30877
236k
                var_name = get_u32(bc_buf + pos + 1);
30878
236k
                label = get_u32(bc_buf + pos + 5);
30879
236k
                scope = get_u16(bc_buf + pos + 9);
30880
236k
                ls = &s->label_slots[label];
30881
236k
                ls->ref_count--;  /* always remove label reference */
30882
236k
                pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
30883
236k
                                             bc_buf, ls, pos_next);
30884
236k
                JS_FreeAtom(ctx, var_name);
30885
236k
            }
30886
236k
            break;
30887
0
        case OP_scope_get_private_field:
30888
0
        case OP_scope_get_private_field2:
30889
0
        case OP_scope_put_private_field:
30890
0
            {
30891
0
                int ret;
30892
0
                var_name = get_u32(bc_buf + pos + 1);
30893
0
                scope = get_u16(bc_buf + pos + 5);
30894
0
                ret = resolve_scope_private_field(ctx, s, var_name, scope, op, &bc_out);
30895
0
                if (ret < 0)
30896
0
                    goto fail;
30897
0
                JS_FreeAtom(ctx, var_name);
30898
0
            }
30899
0
            break;
30900
24
        case OP_gosub:
30901
24
            s->jump_size++;
30902
24
            if (OPTIMIZE) {
30903
                /* remove calls to empty finalizers  */
30904
24
                int label;
30905
24
                LabelSlot *ls;
30906
30907
24
                label = get_u32(bc_buf + pos + 1);
30908
24
                assert(label >= 0 && label < s->label_count);
30909
24
                ls = &s->label_slots[label];
30910
24
                if (code_match(&cc, ls->pos, OP_ret, -1)) {
30911
24
                    ls->ref_count--;
30912
24
                    break;
30913
24
                }
30914
24
            }
30915
0
            goto no_change;
30916
59.6k
        case OP_drop:
30917
59.6k
            if (0) {
30918
                /* remove drops before return_undef */
30919
                /* do not perform this optimization in pass2 because
30920
                   it breaks patterns recognised in resolve_labels */
30921
0
                int pos1 = pos_next;
30922
0
                int line1 = line_num;
30923
0
                while (code_match(&cc, pos1, OP_drop, -1)) {
30924
0
                    if (cc.line_num >= 0) line1 = cc.line_num;
30925
0
                    pos1 = cc.pos;
30926
0
                }
30927
0
                if (code_match(&cc, pos1, OP_return_undef, -1)) {
30928
0
                    pos_next = pos1;
30929
0
                    if (line1 != -1 && line1 != line_num) {
30930
0
                        line_num = line1;
30931
0
                        s->line_number_size++;
30932
0
                        dbuf_putc(&bc_out, OP_line_num);
30933
0
                        dbuf_put_u32(&bc_out, line_num);
30934
0
                    }
30935
0
                    break;
30936
0
                }
30937
0
            }
30938
59.6k
            goto no_change;
30939
172k
        case OP_insert3:
30940
172k
            if (OPTIMIZE) {
30941
                /* Transformation: insert3 put_array_el|put_ref_value drop -> put_array_el|put_ref_value */
30942
172k
                if (code_match(&cc, pos_next, M2(OP_put_array_el, OP_put_ref_value), OP_drop, -1)) {
30943
165k
                    dbuf_putc(&bc_out, cc.op);
30944
165k
                    pos_next = cc.pos;
30945
165k
                    if (cc.line_num != -1 && cc.line_num != line_num) {
30946
0
                        line_num = cc.line_num;
30947
0
                        s->line_number_size++;
30948
0
                        dbuf_putc(&bc_out, OP_line_num);
30949
0
                        dbuf_put_u32(&bc_out, line_num);
30950
0
                    }
30951
165k
                    break;
30952
165k
                }
30953
172k
            }
30954
6.43k
            goto no_change;
30955
30956
24.5k
        case OP_goto:
30957
24.5k
            s->jump_size++;
30958
            /* fall thru */
30959
24.5k
        case OP_tail_call:
30960
24.5k
        case OP_tail_call_method:
30961
66.1k
        case OP_return:
30962
70.1k
        case OP_return_undef:
30963
70.2k
        case OP_throw:
30964
70.6k
        case OP_throw_error:
30965
70.6k
        case OP_ret:
30966
70.6k
            if (OPTIMIZE) {
30967
                /* remove dead code */
30968
70.6k
                int line = -1;
30969
70.6k
                dbuf_put(&bc_out, bc_buf + pos, len);
30970
70.6k
                pos = skip_dead_code(s, bc_buf, bc_len, pos + len, &line);
30971
70.6k
                pos_next = pos;
30972
70.6k
                if (pos < bc_len && line >= 0 && line_num != line) {
30973
62
                    line_num = line;
30974
62
                    s->line_number_size++;
30975
62
                    dbuf_putc(&bc_out, OP_line_num);
30976
62
                    dbuf_put_u32(&bc_out, line_num);
30977
62
                }
30978
70.6k
                break;
30979
70.6k
            }
30980
0
            goto no_change;
30981
30982
247k
        case OP_label:
30983
247k
            {
30984
247k
                int label;
30985
247k
                LabelSlot *ls;
30986
30987
247k
                label = get_u32(bc_buf + pos + 1);
30988
247k
                assert(label >= 0 && label < s->label_count);
30989
247k
                ls = &s->label_slots[label];
30990
247k
                ls->pos2 = bc_out.size + opcode_info[op].size;
30991
247k
            }
30992
0
            goto no_change;
30993
30994
48.3k
        case OP_enter_scope:
30995
48.3k
            {
30996
48.3k
                int scope_idx, scope = get_u16(bc_buf + pos + 1);
30997
30998
48.3k
                if (scope == s->body_scope) {
30999
45.5k
                    instantiate_hoisted_definitions(ctx, s, &bc_out);
31000
45.5k
                }
31001
31002
49.8k
                for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
31003
2.23k
                    JSVarDef *vd = &s->vars[scope_idx];
31004
2.23k
                    if (vd->scope_level == scope) {
31005
1.48k
                        if (scope_idx != s->arguments_arg_idx) {
31006
1.48k
                            if (vd->var_kind == JS_VAR_FUNCTION_DECL ||
31007
1.48k
                                vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) {
31008
                                /* Initialize lexical variable upon entering scope */
31009
1
                                dbuf_putc(&bc_out, OP_fclosure);
31010
1
                                dbuf_put_u32(&bc_out, vd->func_pool_idx);
31011
1
                                dbuf_putc(&bc_out, OP_put_loc);
31012
1
                                dbuf_put_u16(&bc_out, scope_idx);
31013
1.47k
                            } else {
31014
                                /* XXX: should check if variable can be used
31015
                                   before initialization */
31016
1.47k
                                dbuf_putc(&bc_out, OP_set_loc_uninitialized);
31017
1.47k
                                dbuf_put_u16(&bc_out, scope_idx);
31018
1.47k
                            }
31019
1.48k
                        }
31020
1.48k
                        scope_idx = vd->scope_next;
31021
1.48k
                    } else {
31022
751
                        break;
31023
751
                    }
31024
2.23k
                }
31025
48.3k
            }
31026
48.3k
            break;
31027
31028
3.22k
        case OP_leave_scope:
31029
3.22k
            {
31030
3.22k
                int scope_idx, scope = get_u16(bc_buf + pos + 1);
31031
31032
4.77k
                for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
31033
2.61k
                    JSVarDef *vd = &s->vars[scope_idx];
31034
2.61k
                    if (vd->scope_level == scope) {
31035
1.54k
                        if (vd->is_captured) {
31036
418
                            dbuf_putc(&bc_out, OP_close_loc);
31037
418
                            dbuf_put_u16(&bc_out, scope_idx);
31038
418
                        }
31039
1.54k
                        scope_idx = vd->scope_next;
31040
1.54k
                    } else {
31041
1.06k
                        break;
31042
1.06k
                    }
31043
2.61k
                }
31044
3.22k
            }
31045
3.22k
            break;
31046
31047
494
        case OP_set_name:
31048
494
            {
31049
                /* remove dummy set_name opcodes */
31050
494
                JSAtom name = get_u32(bc_buf + pos + 1);
31051
494
                if (name == JS_ATOM_NULL)
31052
303
                    break;
31053
494
            }
31054
191
            goto no_change;
31055
31056
3.66k
        case OP_if_false:
31057
8.52k
        case OP_if_true:
31058
8.53k
        case OP_catch:
31059
8.53k
            s->jump_size++;
31060
8.53k
            goto no_change;
31061
31062
76.0k
        case OP_dup:
31063
76.0k
            if (OPTIMIZE) {
31064
                /* Transformation: dup if_false(l1) drop, l1: if_false(l2) -> if_false(l2) */
31065
                /* Transformation: dup if_true(l1) drop, l1: if_true(l2) -> if_true(l2) */
31066
76.0k
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), OP_drop, -1)) {
31067
3.01k
                    int lab0, lab1, op1, pos1, line1, pos2;
31068
3.01k
                    lab0 = lab1 = cc.label;
31069
3.01k
                    assert(lab1 >= 0 && lab1 < s->label_count);
31070
3.01k
                    op1 = cc.op;
31071
3.01k
                    pos1 = cc.pos;
31072
3.01k
                    line1 = cc.line_num;
31073
3.01k
                    while (code_match(&cc, (pos2 = get_label_pos(s, lab1)), OP_dup, op1, OP_drop, -1)) {
31074
0
                        lab1 = cc.label;
31075
0
                    }
31076
3.01k
                    if (code_match(&cc, pos2, op1, -1)) {
31077
0
                        s->jump_size++;
31078
0
                        update_label(s, lab0, -1);
31079
0
                        update_label(s, cc.label, +1);
31080
0
                        dbuf_putc(&bc_out, op1);
31081
0
                        dbuf_put_u32(&bc_out, cc.label);
31082
0
                        pos_next = pos1;
31083
0
                        if (line1 != -1 && line1 != line_num) {
31084
0
                            line_num = line1;
31085
0
                            s->line_number_size++;
31086
0
                            dbuf_putc(&bc_out, OP_line_num);
31087
0
                            dbuf_put_u32(&bc_out, line_num);
31088
0
                        }
31089
0
                        break;
31090
0
                    }
31091
3.01k
                }
31092
76.0k
            }
31093
76.0k
            goto no_change;
31094
31095
76.0k
        case OP_nop:
31096
            /* remove erased code */
31097
24.3k
            break;
31098
1
        case OP_set_class_name:
31099
            /* only used during parsing */
31100
1
            break;
31101
            
31102
295k
        default:
31103
808k
        no_change:
31104
808k
            dbuf_put(&bc_out, bc_buf + pos, len);
31105
808k
            break;
31106
1.62M
        }
31107
1.62M
    }
31108
31109
    /* set the new byte code */
31110
45.6k
    dbuf_free(&s->byte_code);
31111
45.6k
    s->byte_code = bc_out;
31112
45.6k
    if (dbuf_error(&s->byte_code)) {
31113
2
        JS_ThrowOutOfMemory(ctx);
31114
2
        return -1;
31115
2
    }
31116
45.6k
    return 0;
31117
0
 fail:
31118
    /* continue the copy to keep the atom refcounts consistent */
31119
    /* XXX: find a better solution ? */
31120
0
    for (; pos < bc_len; pos = pos_next) {
31121
0
        op = bc_buf[pos];
31122
0
        len = opcode_info[op].size;
31123
0
        pos_next = pos + len;
31124
0
        dbuf_put(&bc_out, bc_buf + pos, len);
31125
0
    }
31126
0
    dbuf_free(&s->byte_code);
31127
0
    s->byte_code = bc_out;
31128
0
    return -1;
31129
45.6k
}
31130
31131
/* the pc2line table gives a line number for each PC value */
31132
static void add_pc2line_info(JSFunctionDef *s, uint32_t pc, int line_num)
31133
1.80M
{
31134
1.80M
    if (s->line_number_slots != NULL
31135
1.80M
    &&  s->line_number_count < s->line_number_size
31136
1.80M
    &&  pc >= s->line_number_last_pc
31137
1.80M
    &&  line_num != s->line_number_last) {
31138
26.8k
        s->line_number_slots[s->line_number_count].pc = pc;
31139
26.8k
        s->line_number_slots[s->line_number_count].line_num = line_num;
31140
26.8k
        s->line_number_count++;
31141
26.8k
        s->line_number_last_pc = pc;
31142
26.8k
        s->line_number_last = line_num;
31143
26.8k
    }
31144
1.80M
}
31145
31146
static void compute_pc2line_info(JSFunctionDef *s)
31147
45.6k
{
31148
45.6k
    if (!(s->js_mode & JS_MODE_STRIP) && s->line_number_slots) {
31149
45.2k
        int last_line_num = s->line_num;
31150
45.2k
        uint32_t last_pc = 0;
31151
45.2k
        int i;
31152
31153
45.2k
        js_dbuf_init(s->ctx, &s->pc2line);
31154
72.0k
        for (i = 0; i < s->line_number_count; i++) {
31155
26.8k
            uint32_t pc = s->line_number_slots[i].pc;
31156
26.8k
            int line_num = s->line_number_slots[i].line_num;
31157
26.8k
            int diff_pc, diff_line;
31158
31159
26.8k
            if (line_num < 0)
31160
0
                continue;
31161
31162
26.8k
            diff_pc = pc - last_pc;
31163
26.8k
            diff_line = line_num - last_line_num;
31164
26.8k
            if (diff_line == 0 || diff_pc < 0)
31165
0
                continue;
31166
31167
26.8k
            if (diff_line >= PC2LINE_BASE &&
31168
26.8k
                diff_line < PC2LINE_BASE + PC2LINE_RANGE &&
31169
26.8k
                diff_pc <= PC2LINE_DIFF_PC_MAX) {
31170
14.9k
                dbuf_putc(&s->pc2line, (diff_line - PC2LINE_BASE) +
31171
14.9k
                          diff_pc * PC2LINE_RANGE + PC2LINE_OP_FIRST);
31172
14.9k
            } else {
31173
                /* longer encoding */
31174
11.8k
                dbuf_putc(&s->pc2line, 0);
31175
11.8k
                dbuf_put_leb128(&s->pc2line, diff_pc);
31176
11.8k
                dbuf_put_sleb128(&s->pc2line, diff_line);
31177
11.8k
            }
31178
26.8k
            last_pc = pc;
31179
26.8k
            last_line_num = line_num;
31180
26.8k
        }
31181
45.2k
    }
31182
45.6k
}
31183
31184
static RelocEntry *add_reloc(JSContext *ctx, LabelSlot *ls, uint32_t addr, int size)
31185
363k
{
31186
363k
    RelocEntry *re;
31187
363k
    re = js_malloc(ctx, sizeof(*re));
31188
363k
    if (!re)
31189
0
        return NULL;
31190
363k
    re->addr = addr;
31191
363k
    re->size = size;
31192
363k
    re->next = ls->first_reloc;
31193
363k
    ls->first_reloc = re;
31194
363k
    return re;
31195
363k
}
31196
31197
static BOOL code_has_label(CodeContext *s, int pos, int label)
31198
21.5k
{
31199
35.0k
    while (pos < s->bc_len) {
31200
35.0k
        int op = s->bc_buf[pos];
31201
35.0k
        if (op == OP_line_num) {
31202
437
            pos += 5;
31203
437
            continue;
31204
437
        }
31205
34.5k
        if (op == OP_label) {
31206
13.9k
            int lab = get_u32(s->bc_buf + pos + 1);
31207
13.9k
            if (lab == label)
31208
872
                return TRUE;
31209
13.0k
            pos += 5;
31210
13.0k
            continue;
31211
13.9k
        }
31212
20.6k
        if (op == OP_goto) {
31213
6.92k
            int lab = get_u32(s->bc_buf + pos + 1);
31214
6.92k
            if (lab == label)
31215
32
                return TRUE;
31216
6.92k
        }
31217
20.6k
        break;
31218
20.6k
    }
31219
20.6k
    return FALSE;
31220
21.5k
}
31221
31222
/* return the target label, following the OP_goto jumps
31223
   the first opcode at destination is stored in *pop
31224
 */
31225
static int find_jump_target(JSFunctionDef *s, int label, int *pop, int *pline)
31226
372k
{
31227
372k
    int i, pos, op;
31228
31229
372k
    update_label(s, label, -1);
31230
384k
    for (i = 0; i < 10; i++) {
31231
384k
        assert(label >= 0 && label < s->label_count);
31232
384k
        pos = s->label_slots[label].pos2;
31233
558k
        for (;;) {
31234
558k
            switch(op = s->byte_code.buf[pos]) {
31235
5.50k
            case OP_line_num:
31236
5.50k
                if (pline)
31237
344
                    *pline = get_u32(s->byte_code.buf + pos + 1);
31238
                /* fall thru */
31239
174k
            case OP_label:
31240
174k
                pos += opcode_info[op].size;
31241
174k
                continue;
31242
11.7k
            case OP_goto:
31243
11.7k
                label = get_u32(s->byte_code.buf + pos + 1);
31244
11.7k
                break;
31245
5.84k
            case OP_drop:
31246
                /* ignore drop opcodes if followed by OP_return_undef */
31247
5.84k
                while (s->byte_code.buf[++pos] == OP_drop)
31248
0
                    continue;
31249
5.84k
                if (s->byte_code.buf[pos] == OP_return_undef)
31250
77
                    op = OP_return_undef;
31251
                /* fall thru */
31252
372k
            default:
31253
372k
                goto done;
31254
558k
            }
31255
11.7k
            break;
31256
558k
        }
31257
384k
    }
31258
    /* cycle detected, could issue a warning */
31259
372k
 done:
31260
372k
    *pop = op;
31261
372k
    update_label(s, label, +1);
31262
372k
    return label;
31263
372k
}
31264
31265
static void push_short_int(DynBuf *bc_out, int val)
31266
1.66k
{
31267
1.66k
#if SHORT_OPCODES
31268
1.66k
    if (val >= -1 && val <= 7) {
31269
1.43k
        dbuf_putc(bc_out, OP_push_0 + val);
31270
1.43k
        return;
31271
1.43k
    }
31272
232
    if (val == (int8_t)val) {
31273
178
        dbuf_putc(bc_out, OP_push_i8);
31274
178
        dbuf_putc(bc_out, val);
31275
178
        return;
31276
178
    }
31277
54
    if (val == (int16_t)val) {
31278
35
        dbuf_putc(bc_out, OP_push_i16);
31279
35
        dbuf_put_u16(bc_out, val);
31280
35
        return;
31281
35
    }
31282
19
#endif
31283
19
    dbuf_putc(bc_out, OP_push_i32);
31284
19
    dbuf_put_u32(bc_out, val);
31285
19
}
31286
31287
static void put_short_code(DynBuf *bc_out, int op, int idx)
31288
407k
{
31289
407k
#if SHORT_OPCODES
31290
407k
    if (idx < 4) {
31291
395k
        switch (op) {
31292
343k
        case OP_get_loc:
31293
343k
            dbuf_putc(bc_out, OP_get_loc0 + idx);
31294
343k
            return;
31295
6.01k
        case OP_put_loc:
31296
6.01k
            dbuf_putc(bc_out, OP_put_loc0 + idx);
31297
6.01k
            return;
31298
41.0k
        case OP_set_loc:
31299
41.0k
            dbuf_putc(bc_out, OP_set_loc0 + idx);
31300
41.0k
            return;
31301
404
        case OP_get_arg:
31302
404
            dbuf_putc(bc_out, OP_get_arg0 + idx);
31303
404
            return;
31304
19
        case OP_put_arg:
31305
19
            dbuf_putc(bc_out, OP_put_arg0 + idx);
31306
19
            return;
31307
87
        case OP_set_arg:
31308
87
            dbuf_putc(bc_out, OP_set_arg0 + idx);
31309
87
            return;
31310
607
        case OP_get_var_ref:
31311
607
            dbuf_putc(bc_out, OP_get_var_ref0 + idx);
31312
607
            return;
31313
12
        case OP_put_var_ref:
31314
12
            dbuf_putc(bc_out, OP_put_var_ref0 + idx);
31315
12
            return;
31316
17
        case OP_set_var_ref:
31317
17
            dbuf_putc(bc_out, OP_set_var_ref0 + idx);
31318
17
            return;
31319
2.98k
        case OP_call:
31320
2.98k
            dbuf_putc(bc_out, OP_call0 + idx);
31321
2.98k
            return;
31322
395k
        }
31323
395k
    }
31324
13.0k
    if (idx < 256) {
31325
12.8k
        switch (op) {
31326
9.45k
        case OP_get_loc:
31327
9.45k
            dbuf_putc(bc_out, OP_get_loc8);
31328
9.45k
            dbuf_putc(bc_out, idx);
31329
9.45k
            return;
31330
732
        case OP_put_loc:
31331
732
            dbuf_putc(bc_out, OP_put_loc8);
31332
732
            dbuf_putc(bc_out, idx);
31333
732
            return;
31334
226
        case OP_set_loc:
31335
226
            dbuf_putc(bc_out, OP_set_loc8);
31336
226
            dbuf_putc(bc_out, idx);
31337
226
            return;
31338
12.8k
        }
31339
12.8k
    }
31340
2.63k
#endif
31341
2.63k
    dbuf_putc(bc_out, op);
31342
2.63k
    dbuf_put_u16(bc_out, idx);
31343
2.63k
}
31344
31345
/* peephole optimizations and resolve goto/labels */
31346
static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
31347
45.6k
{
31348
45.6k
    int pos, pos_next, bc_len, op, op1, len, i, line_num;
31349
45.6k
    const uint8_t *bc_buf;
31350
45.6k
    DynBuf bc_out;
31351
45.6k
    LabelSlot *label_slots, *ls;
31352
45.6k
    RelocEntry *re, *re_next;
31353
45.6k
    CodeContext cc;
31354
45.6k
    int label;
31355
45.6k
#if SHORT_OPCODES
31356
45.6k
    JumpSlot *jp;
31357
45.6k
#endif
31358
31359
45.6k
    label_slots = s->label_slots;
31360
31361
45.6k
    line_num = s->line_num;
31362
31363
45.6k
    cc.bc_buf = bc_buf = s->byte_code.buf;
31364
45.6k
    cc.bc_len = bc_len = s->byte_code.size;
31365
45.6k
    js_dbuf_init(ctx, &bc_out);
31366
31367
45.6k
#if SHORT_OPCODES
31368
45.6k
    if (s->jump_size) {
31369
443
        s->jump_slots = js_mallocz(s->ctx, sizeof(*s->jump_slots) * s->jump_size);
31370
443
        if (s->jump_slots == NULL)
31371
0
            return -1;
31372
443
    }
31373
45.6k
#endif
31374
    /* XXX: Should skip this phase if not generating SHORT_OPCODES */
31375
45.6k
    if (s->line_number_size && !(s->js_mode & JS_MODE_STRIP)) {
31376
45.2k
        s->line_number_slots = js_mallocz(s->ctx, sizeof(*s->line_number_slots) * s->line_number_size);
31377
45.2k
        if (s->line_number_slots == NULL)
31378
0
            return -1;
31379
45.2k
        s->line_number_last = s->line_num;
31380
45.2k
        s->line_number_last_pc = 0;
31381
45.2k
    }
31382
31383
    /* initialize the 'home_object' variable if needed */
31384
45.6k
    if (s->home_object_var_idx >= 0) {
31385
77
        dbuf_putc(&bc_out, OP_special_object);
31386
77
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_HOME_OBJECT);
31387
77
        put_short_code(&bc_out, OP_put_loc, s->home_object_var_idx);
31388
77
    }
31389
    /* initialize the 'this.active_func' variable if needed */
31390
45.6k
    if (s->this_active_func_var_idx >= 0) {
31391
0
        dbuf_putc(&bc_out, OP_special_object);
31392
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
31393
0
        put_short_code(&bc_out, OP_put_loc, s->this_active_func_var_idx);
31394
0
    }
31395
    /* initialize the 'new.target' variable if needed */
31396
45.6k
    if (s->new_target_var_idx >= 0) {
31397
2
        dbuf_putc(&bc_out, OP_special_object);
31398
2
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_NEW_TARGET);
31399
2
        put_short_code(&bc_out, OP_put_loc, s->new_target_var_idx);
31400
2
    }
31401
    /* initialize the 'this' variable if needed. In a derived class
31402
       constructor, this is initially uninitialized. */
31403
45.6k
    if (s->this_var_idx >= 0) {
31404
157
        if (s->is_derived_class_constructor) {
31405
0
            dbuf_putc(&bc_out, OP_set_loc_uninitialized);
31406
0
            dbuf_put_u16(&bc_out, s->this_var_idx);
31407
157
        } else {
31408
157
            dbuf_putc(&bc_out, OP_push_this);
31409
157
            put_short_code(&bc_out, OP_put_loc, s->this_var_idx);
31410
157
        }
31411
157
    }
31412
    /* initialize the 'arguments' variable if needed */
31413
45.6k
    if (s->arguments_var_idx >= 0) {
31414
1
        if ((s->js_mode & JS_MODE_STRICT) || !s->has_simple_parameter_list) {
31415
1
            dbuf_putc(&bc_out, OP_special_object);
31416
1
            dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_ARGUMENTS);
31417
1
        } else {
31418
0
            dbuf_putc(&bc_out, OP_special_object);
31419
0
            dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS);
31420
0
        }
31421
1
        if (s->arguments_arg_idx >= 0)
31422
0
            put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);
31423
1
        put_short_code(&bc_out, OP_put_loc, s->arguments_var_idx);
31424
1
    }
31425
    /* initialize a reference to the current function if needed */
31426
45.6k
    if (s->func_var_idx >= 0) {
31427
0
        dbuf_putc(&bc_out, OP_special_object);
31428
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
31429
0
        put_short_code(&bc_out, OP_put_loc, s->func_var_idx);
31430
0
    }
31431
    /* initialize the variable environment object if needed */
31432
45.6k
    if (s->var_object_idx >= 0) {
31433
0
        dbuf_putc(&bc_out, OP_special_object);
31434
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
31435
0
        put_short_code(&bc_out, OP_put_loc, s->var_object_idx);
31436
0
    }
31437
45.6k
    if (s->arg_var_object_idx >= 0) {
31438
0
        dbuf_putc(&bc_out, OP_special_object);
31439
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
31440
0
        put_short_code(&bc_out, OP_put_loc, s->arg_var_object_idx);
31441
0
    }
31442
31443
2.54M
    for (pos = 0; pos < bc_len; pos = pos_next) {
31444
2.50M
        int val;
31445
2.50M
        op = bc_buf[pos];
31446
2.50M
        len = opcode_info[op].size;
31447
2.50M
        pos_next = pos + len;
31448
2.50M
        switch(op) {
31449
112k
        case OP_line_num:
31450
            /* line number info (for debug). We put it in a separate
31451
               compressed table to reduce memory usage and get better
31452
               performance */
31453
112k
            line_num = get_u32(bc_buf + pos + 1);
31454
112k
            break;
31455
31456
578k
        case OP_label:
31457
578k
            {
31458
578k
                label = get_u32(bc_buf + pos + 1);
31459
578k
                assert(label >= 0 && label < s->label_count);
31460
578k
                ls = &label_slots[label];
31461
578k
                assert(ls->addr == -1);
31462
578k
                ls->addr = bc_out.size;
31463
                /* resolve the relocation entries */
31464
942k
                for(re = ls->first_reloc; re != NULL; re = re_next) {
31465
363k
                    int diff = ls->addr - re->addr;
31466
363k
                    re_next = re->next;
31467
363k
                    switch (re->size) {
31468
353k
                    case 4:
31469
353k
                        put_u32(bc_out.buf + re->addr, diff);
31470
353k
                        break;
31471
1.23k
                    case 2:
31472
1.23k
                        assert(diff == (int16_t)diff);
31473
1.23k
                        put_u16(bc_out.buf + re->addr, diff);
31474
1.23k
                        break;
31475
8.89k
                    case 1:
31476
8.89k
                        assert(diff == (int8_t)diff);
31477
8.89k
                        put_u8(bc_out.buf + re->addr, diff);
31478
8.89k
                        break;
31479
363k
                    }
31480
363k
                    js_free(ctx, re);
31481
363k
                }
31482
578k
                ls->first_reloc = NULL;
31483
578k
            }
31484
0
            break;
31485
31486
3.07k
        case OP_call:
31487
3.68k
        case OP_call_method:
31488
3.68k
            {
31489
                /* detect and transform tail calls */
31490
3.68k
                int argc;
31491
3.68k
                argc = get_u16(bc_buf + pos + 1);
31492
3.68k
                if (code_match(&cc, pos_next, OP_return, -1)) {
31493
144
                    if (cc.line_num >= 0) line_num = cc.line_num;
31494
144
                    add_pc2line_info(s, bc_out.size, line_num);
31495
144
                    put_short_code(&bc_out, op + 1, argc);
31496
144
                    pos_next = skip_dead_code(s, bc_buf, bc_len, cc.pos, &line_num);
31497
144
                    break;
31498
144
                }
31499
3.54k
                add_pc2line_info(s, bc_out.size, line_num);
31500
3.54k
                put_short_code(&bc_out, op, argc);
31501
3.54k
                break;
31502
3.68k
            }
31503
0
            goto no_change;
31504
31505
41.4k
        case OP_return:
31506
45.4k
        case OP_return_undef:
31507
45.8k
        case OP_return_async:
31508
45.8k
        case OP_throw:
31509
46.2k
        case OP_throw_error:
31510
46.2k
            pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
31511
46.2k
            goto no_change;
31512
31513
12.5k
        case OP_goto:
31514
12.5k
            label = get_u32(bc_buf + pos + 1);
31515
12.7k
        has_goto:
31516
12.7k
            if (OPTIMIZE) {
31517
12.7k
                int line1 = -1;
31518
                /* Use custom matcher because multiple labels can follow */
31519
12.7k
                label = find_jump_target(s, label, &op1, &line1);
31520
12.7k
                if (code_has_label(&cc, pos_next, label)) {
31521
                    /* jump to next instruction: remove jump */
31522
392
                    update_label(s, label, -1);
31523
392
                    break;
31524
392
                }
31525
12.3k
                if (op1 == OP_return || op1 == OP_return_undef || op1 == OP_throw) {
31526
                    /* jump to return/throw: remove jump, append return/throw */
31527
                    /* updating the line number obfuscates assembly listing */
31528
                    //if (line1 >= 0) line_num = line1;
31529
44
                    update_label(s, label, -1);
31530
44
                    add_pc2line_info(s, bc_out.size, line_num);
31531
44
                    dbuf_putc(&bc_out, op1);
31532
44
                    pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
31533
44
                    break;
31534
44
                }
31535
                /* XXX: should duplicate single instructions followed by goto or return */
31536
                /* For example, can match one of these followed by return:
31537
                   push_i32 / push_const / push_atom_value / get_var /
31538
                   undefined / null / push_false / push_true / get_ref_value /
31539
                   get_loc / get_arg / get_var_ref
31540
                 */
31541
12.3k
            }
31542
12.2k
            goto has_label;
31543
31544
12.2k
        case OP_gosub:
31545
0
            label = get_u32(bc_buf + pos + 1);
31546
0
            if (0 && OPTIMIZE) {
31547
0
                label = find_jump_target(s, label, &op1, NULL);
31548
0
                if (op1 == OP_ret) {
31549
0
                    update_label(s, label, -1);
31550
                    /* empty finally clause: remove gosub */
31551
0
                    break;
31552
0
                }
31553
0
            }
31554
0
            goto has_label;
31555
31556
16
        case OP_catch:
31557
16
            label = get_u32(bc_buf + pos + 1);
31558
16
            goto has_label;
31559
31560
4.86k
        case OP_if_true:
31561
8.31k
        case OP_if_false:
31562
8.31k
            label = get_u32(bc_buf + pos + 1);
31563
8.31k
            if (OPTIMIZE) {
31564
8.31k
                label = find_jump_target(s, label, &op1, NULL);
31565
                /* transform if_false/if_true(l1) label(l1) -> drop label(l1) */
31566
8.31k
                if (code_has_label(&cc, pos_next, label)) {
31567
370
                    update_label(s, label, -1);
31568
370
                    dbuf_putc(&bc_out, OP_drop);
31569
370
                    break;
31570
370
                }
31571
                /* transform if_false(l1) goto(l2) label(l1) -> if_false(l2) label(l1) */
31572
7.94k
                if (code_match(&cc, pos_next, OP_goto, -1)) {
31573
523
                    int pos1 = cc.pos;
31574
523
                    int line1 = cc.line_num;
31575
523
                    if (code_has_label(&cc, pos1, label)) {
31576
142
                        if (line1 >= 0) line_num = line1;
31577
142
                        pos_next = pos1;
31578
142
                        update_label(s, label, -1);
31579
142
                        label = cc.label;
31580
142
                        op ^= OP_if_true ^ OP_if_false;
31581
142
                    }
31582
523
                }
31583
7.94k
            }
31584
20.2k
        has_label:
31585
20.2k
            add_pc2line_info(s, bc_out.size, line_num);
31586
20.2k
            if (op == OP_goto) {
31587
12.2k
                pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
31588
12.2k
            }
31589
20.2k
            assert(label >= 0 && label < s->label_count);
31590
20.2k
            ls = &label_slots[label];
31591
20.2k
#if SHORT_OPCODES
31592
20.2k
            jp = &s->jump_slots[s->jump_count++];
31593
20.2k
            jp->op = op;
31594
20.2k
            jp->size = 4;
31595
20.2k
            jp->pos = bc_out.size + 1;
31596
20.2k
            jp->label = label;
31597
31598
20.2k
            if (ls->addr == -1) {
31599
11.8k
                int diff = ls->pos2 - pos - 1;
31600
11.8k
                if (diff < 128 && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
31601
8.89k
                    jp->size = 1;
31602
8.89k
                    jp->op = OP_if_false8 + (op - OP_if_false);
31603
8.89k
                    dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
31604
8.89k
                    dbuf_putc(&bc_out, 0);
31605
8.89k
                    if (!add_reloc(ctx, ls, bc_out.size - 1, 1))
31606
0
                        goto fail;
31607
8.89k
                    break;
31608
8.89k
                }
31609
2.93k
                if (diff < 32768 && op == OP_goto) {
31610
1.23k
                    jp->size = 2;
31611
1.23k
                    jp->op = OP_goto16;
31612
1.23k
                    dbuf_putc(&bc_out, OP_goto16);
31613
1.23k
                    dbuf_put_u16(&bc_out, 0);
31614
1.23k
                    if (!add_reloc(ctx, ls, bc_out.size - 2, 2))
31615
0
                        goto fail;
31616
1.23k
                    break;
31617
1.23k
                }
31618
8.40k
            } else {
31619
8.40k
                int diff = ls->addr - bc_out.size - 1;
31620
8.40k
                if (diff == (int8_t)diff && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
31621
2.74k
                    jp->size = 1;
31622
2.74k
                    jp->op = OP_if_false8 + (op - OP_if_false);
31623
2.74k
                    dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
31624
2.74k
                    dbuf_putc(&bc_out, diff);
31625
2.74k
                    break;
31626
2.74k
                }
31627
5.65k
                if (diff == (int16_t)diff && op == OP_goto) {
31628
5.59k
                    jp->size = 2;
31629
5.59k
                    jp->op = OP_goto16;
31630
5.59k
                    dbuf_putc(&bc_out, OP_goto16);
31631
5.59k
                    dbuf_put_u16(&bc_out, diff);
31632
5.59k
                    break;
31633
5.59k
                }
31634
5.65k
            }
31635
1.76k
#endif
31636
1.76k
            dbuf_putc(&bc_out, op);
31637
1.76k
            dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
31638
1.76k
            if (ls->addr == -1) {
31639
                /* unresolved yet: create a new relocation entry */
31640
1.69k
                if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
31641
0
                    goto fail;
31642
1.69k
            }
31643
1.76k
            break;
31644
174k
        case OP_with_get_var:
31645
174k
        case OP_with_put_var:
31646
174k
        case OP_with_delete_var:
31647
346k
        case OP_with_make_ref:
31648
351k
        case OP_with_get_ref:
31649
351k
        case OP_with_get_ref_undef:
31650
351k
            {
31651
351k
                JSAtom atom;
31652
351k
                int is_with;
31653
31654
351k
                atom = get_u32(bc_buf + pos + 1);
31655
351k
                label = get_u32(bc_buf + pos + 5);
31656
351k
                is_with = bc_buf[pos + 9];
31657
351k
                if (OPTIMIZE) {
31658
351k
                    label = find_jump_target(s, label, &op1, NULL);
31659
351k
                }
31660
351k
                assert(label >= 0 && label < s->label_count);
31661
351k
                ls = &label_slots[label];
31662
351k
                add_pc2line_info(s, bc_out.size, line_num);
31663
351k
#if SHORT_OPCODES
31664
351k
                jp = &s->jump_slots[s->jump_count++];
31665
351k
                jp->op = op;
31666
351k
                jp->size = 4;
31667
351k
                jp->pos = bc_out.size + 5;
31668
351k
                jp->label = label;
31669
351k
#endif
31670
351k
                dbuf_putc(&bc_out, op);
31671
351k
                dbuf_put_u32(&bc_out, atom);
31672
351k
                dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
31673
351k
                if (ls->addr == -1) {
31674
                    /* unresolved yet: create a new relocation entry */
31675
351k
                    if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
31676
0
                        goto fail;
31677
351k
                }
31678
351k
                dbuf_putc(&bc_out, is_with);
31679
351k
            }
31680
0
            break;
31681
31682
57.4k
        case OP_drop:
31683
57.4k
            if (OPTIMIZE) {
31684
                /* remove useless drops before return */
31685
57.4k
                if (code_match(&cc, pos_next, OP_return_undef, -1)) {
31686
3.96k
                    if (cc.line_num >= 0) line_num = cc.line_num;
31687
3.96k
                    break;
31688
3.96k
                }
31689
57.4k
            }
31690
53.4k
            goto no_change;
31691
31692
53.4k
        case OP_null:
31693
7
#if SHORT_OPCODES
31694
7
            if (OPTIMIZE) {
31695
                /* transform null strict_eq into is_null */
31696
7
                if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
31697
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
31698
0
                    add_pc2line_info(s, bc_out.size, line_num);
31699
0
                    dbuf_putc(&bc_out, OP_is_null);
31700
0
                    pos_next = cc.pos;
31701
0
                    break;
31702
0
                }
31703
                /* transform null strict_neq if_false/if_true -> is_null if_true/if_false */
31704
7
                if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
31705
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
31706
0
                    add_pc2line_info(s, bc_out.size, line_num);
31707
0
                    dbuf_putc(&bc_out, OP_is_null);
31708
0
                    pos_next = cc.pos;
31709
0
                    label = cc.label;
31710
0
                    op = cc.op ^ OP_if_false ^ OP_if_true;
31711
0
                    goto has_label;
31712
0
                }
31713
7
            }
31714
7
#endif
31715
            /* fall thru */
31716
84
        case OP_push_false:
31717
86
        case OP_push_true:
31718
86
            if (OPTIMIZE) {
31719
86
                val = (op == OP_push_true);
31720
86
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
31721
159
                has_constant_test:
31722
159
                    if (cc.line_num >= 0) line_num = cc.line_num;
31723
159
                    if (val == cc.op - OP_if_false) {
31724
                        /* transform null if_false(l1) -> goto l1 */
31725
                        /* transform false if_false(l1) -> goto l1 */
31726
                        /* transform true if_true(l1) -> goto l1 */
31727
138
                        pos_next = cc.pos;
31728
138
                        op = OP_goto;
31729
138
                        label = cc.label;
31730
138
                        goto has_goto;
31731
138
                    } else {
31732
                        /* transform null if_true(l1) -> nop */
31733
                        /* transform false if_true(l1) -> nop */
31734
                        /* transform true if_false(l1) -> nop */
31735
21
                        pos_next = cc.pos;
31736
21
                        update_label(s, cc.label, -1);
31737
21
                        break;
31738
21
                    }
31739
159
                }
31740
86
            }
31741
9
            goto no_change;
31742
31743
2.35k
        case OP_push_i32:
31744
2.35k
            if (OPTIMIZE) {
31745
                /* transform i32(val) neg -> i32(-val) */
31746
2.35k
                val = get_i32(bc_buf + pos + 1);
31747
2.35k
                if ((val != INT32_MIN && val != 0)
31748
2.35k
                &&  code_match(&cc, pos_next, OP_neg, -1)) {
31749
1
                    if (cc.line_num >= 0) line_num = cc.line_num;
31750
1
                    if (code_match(&cc, cc.pos, OP_drop, -1)) {
31751
0
                        if (cc.line_num >= 0) line_num = cc.line_num;
31752
1
                    } else {
31753
1
                        add_pc2line_info(s, bc_out.size, line_num);
31754
1
                        push_short_int(&bc_out, -val);
31755
1
                    }
31756
1
                    pos_next = cc.pos;
31757
1
                    break;
31758
1
                }
31759
                /* remove push/drop pairs generated by the parser */
31760
2.35k
                if (code_match(&cc, pos_next, OP_drop, -1)) {
31761
667
                    if (cc.line_num >= 0) line_num = cc.line_num;
31762
667
                    pos_next = cc.pos;
31763
667
                    break;
31764
667
                }
31765
                /* Optimize constant tests: `if (0)`, `if (1)`, `if (!0)`... */
31766
1.68k
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
31767
21
                    val = (val != 0);
31768
21
                    goto has_constant_test;
31769
21
                }
31770
1.66k
                add_pc2line_info(s, bc_out.size, line_num);
31771
1.66k
                push_short_int(&bc_out, val);
31772
1.66k
                break;
31773
1.68k
            }
31774
0
            goto no_change;
31775
31776
0
#if SHORT_OPCODES
31777
840
        case OP_push_const:
31778
2.20k
        case OP_fclosure:
31779
2.20k
            if (OPTIMIZE) {
31780
2.20k
                int idx = get_u32(bc_buf + pos + 1);
31781
2.20k
                if (idx < 256) {
31782
1.74k
                    add_pc2line_info(s, bc_out.size, line_num);
31783
1.74k
                    dbuf_putc(&bc_out, OP_push_const8 + op - OP_push_const);
31784
1.74k
                    dbuf_putc(&bc_out, idx);
31785
1.74k
                    break;
31786
1.74k
                }
31787
2.20k
            }
31788
463
            goto no_change;
31789
31790
44.6k
        case OP_get_field:
31791
44.6k
            if (OPTIMIZE) {
31792
44.6k
                JSAtom atom = get_u32(bc_buf + pos + 1);
31793
44.6k
                if (atom == JS_ATOM_length) {
31794
2
                    JS_FreeAtom(ctx, atom);
31795
2
                    add_pc2line_info(s, bc_out.size, line_num);
31796
2
                    dbuf_putc(&bc_out, OP_get_length);
31797
2
                    break;
31798
2
                }
31799
44.6k
            }
31800
44.6k
            goto no_change;
31801
44.6k
#endif
31802
44.6k
        case OP_push_atom_value:
31803
1.43k
            if (OPTIMIZE) {
31804
1.43k
                JSAtom atom = get_u32(bc_buf + pos + 1);
31805
                /* remove push/drop pairs generated by the parser */
31806
1.43k
                if (code_match(&cc, pos_next, OP_drop, -1)) {
31807
1.06k
                    JS_FreeAtom(ctx, atom);
31808
1.06k
                    if (cc.line_num >= 0) line_num = cc.line_num;
31809
1.06k
                    pos_next = cc.pos;
31810
1.06k
                    break;
31811
1.06k
                }
31812
369
#if SHORT_OPCODES
31813
369
                if (atom == JS_ATOM_empty_string) {
31814
67
                    JS_FreeAtom(ctx, atom);
31815
67
                    add_pc2line_info(s, bc_out.size, line_num);
31816
67
                    dbuf_putc(&bc_out, OP_push_empty_string);
31817
67
                    break;
31818
67
                }
31819
369
#endif
31820
369
            }
31821
302
            goto no_change;
31822
31823
302
        case OP_to_propkey:
31824
74
        case OP_to_propkey2:
31825
74
            if (OPTIMIZE) {
31826
                /* remove redundant to_propkey/to_propkey2 opcodes when storing simple data */
31827
74
                if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_put_array_el, -1)
31828
74
                ||  code_match(&cc, pos_next, M3(OP_push_i32, OP_push_const, OP_push_atom_value), OP_put_array_el, -1)
31829
74
                ||  code_match(&cc, pos_next, M4(OP_undefined, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) {
31830
2
                    break;
31831
2
                }
31832
74
            }
31833
72
            goto no_change;
31834
31835
5.10k
        case OP_undefined:
31836
5.10k
            if (OPTIMIZE) {
31837
                /* remove push/drop pairs generated by the parser */
31838
5.10k
                if (code_match(&cc, pos_next, OP_drop, -1)) {
31839
303
                    if (cc.line_num >= 0) line_num = cc.line_num;
31840
303
                    pos_next = cc.pos;
31841
303
                    break;
31842
303
                }
31843
                /* transform undefined return -> return_undefined */
31844
4.79k
                if (code_match(&cc, pos_next, OP_return, -1)) {
31845
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
31846
0
                    add_pc2line_info(s, bc_out.size, line_num);
31847
0
                    dbuf_putc(&bc_out, OP_return_undef);
31848
0
                    pos_next = cc.pos;
31849
0
                    break;
31850
0
                }
31851
                /* transform undefined if_true(l1)/if_false(l1) -> nop/goto(l1) */
31852
4.79k
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
31853
61
                    val = 0;
31854
61
                    goto has_constant_test;
31855
61
                }
31856
4.73k
#if SHORT_OPCODES
31857
                /* transform undefined strict_eq -> is_undefined */
31858
4.73k
                if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
31859
2.06k
                    if (cc.line_num >= 0) line_num = cc.line_num;
31860
2.06k
                    add_pc2line_info(s, bc_out.size, line_num);
31861
2.06k
                    dbuf_putc(&bc_out, OP_is_undefined);
31862
2.06k
                    pos_next = cc.pos;
31863
2.06k
                    break;
31864
2.06k
                }
31865
                /* transform undefined strict_neq if_false/if_true -> is_undefined if_true/if_false */
31866
2.67k
                if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
31867
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
31868
0
                    add_pc2line_info(s, bc_out.size, line_num);
31869
0
                    dbuf_putc(&bc_out, OP_is_undefined);
31870
0
                    pos_next = cc.pos;
31871
0
                    label = cc.label;
31872
0
                    op = cc.op ^ OP_if_false ^ OP_if_true;
31873
0
                    goto has_label;
31874
0
                }
31875
2.67k
#endif
31876
2.67k
            }
31877
2.67k
            goto no_change;
31878
31879
2.67k
        case OP_insert2:
31880
456
            if (OPTIMIZE) {
31881
                /* Transformation:
31882
                   insert2 put_field(a) drop -> put_field(a)
31883
                   insert2 put_var_strict(a) drop -> put_var_strict(a)
31884
                */
31885
456
                if (code_match(&cc, pos_next, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
31886
7
                    if (cc.line_num >= 0) line_num = cc.line_num;
31887
7
                    add_pc2line_info(s, bc_out.size, line_num);
31888
7
                    dbuf_putc(&bc_out, cc.op);
31889
7
                    dbuf_put_u32(&bc_out, cc.atom);
31890
7
                    pos_next = cc.pos;
31891
7
                    break;
31892
7
                }
31893
456
            }
31894
449
            goto no_change;
31895
31896
75.8k
        case OP_dup:
31897
75.8k
            if (OPTIMIZE) {
31898
                /* Transformation: dup put_x(n) drop -> put_x(n) */
31899
75.8k
                int op1, line2 = -1;
31900
                /* Transformation: dup put_x(n) -> set_x(n) */
31901
75.8k
                if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, -1)) {
31902
213
                    if (cc.line_num >= 0) line_num = cc.line_num;
31903
213
                    op1 = cc.op + 1;  /* put_x -> set_x */
31904
213
                    pos_next = cc.pos;
31905
213
                    if (code_match(&cc, cc.pos, OP_drop, -1)) {
31906
8
                        if (cc.line_num >= 0) line_num = cc.line_num;
31907
8
                        op1 -= 1; /* set_x drop -> put_x */
31908
8
                        pos_next = cc.pos;
31909
8
                        if (code_match(&cc, cc.pos, op1 - 1, cc.idx, -1)) {
31910
2
                            line2 = cc.line_num; /* delay line number update */
31911
2
                            op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
31912
2
                            pos_next = cc.pos;
31913
2
                        }
31914
8
                    }
31915
213
                    add_pc2line_info(s, bc_out.size, line_num);
31916
213
                    put_short_code(&bc_out, op1, cc.idx);
31917
213
                    if (line2 >= 0) line_num = line2;
31918
213
                    break;
31919
213
                }
31920
75.8k
            }
31921
75.6k
            goto no_change;
31922
31923
353k
        case OP_get_loc:
31924
353k
            if (OPTIMIZE) {
31925
                /* transformation:
31926
                   get_loc(n) post_dec put_loc(n) drop -> dec_loc(n)
31927
                   get_loc(n) post_inc put_loc(n) drop -> inc_loc(n)
31928
                   get_loc(n) dec dup put_loc(n) drop -> dec_loc(n)
31929
                   get_loc(n) inc dup put_loc(n) drop -> inc_loc(n)
31930
                 */
31931
353k
                int idx;
31932
353k
                idx = get_u16(bc_buf + pos + 1);
31933
353k
                if (idx >= 256)
31934
180
                    goto no_change;
31935
353k
                if (code_match(&cc, pos_next, M2(OP_post_dec, OP_post_inc), OP_put_loc, idx, OP_drop, -1) ||
31936
353k
                    code_match(&cc, pos_next, M2(OP_dec, OP_inc), OP_dup, OP_put_loc, idx, OP_drop, -1)) {
31937
101
                    if (cc.line_num >= 0) line_num = cc.line_num;
31938
101
                    add_pc2line_info(s, bc_out.size, line_num);
31939
101
                    dbuf_putc(&bc_out, (cc.op == OP_inc || cc.op == OP_post_inc) ? OP_inc_loc : OP_dec_loc);
31940
101
                    dbuf_putc(&bc_out, idx);
31941
101
                    pos_next = cc.pos;
31942
101
                    break;
31943
101
                }
31944
                /* transformation:
31945
                   get_loc(n) push_atom_value(x) add dup put_loc(n) drop -> push_atom_value(x) add_loc(n)
31946
                 */
31947
353k
                if (code_match(&cc, pos_next, OP_push_atom_value, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
31948
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
31949
0
                    add_pc2line_info(s, bc_out.size, line_num);
31950
0
#if SHORT_OPCODES
31951
0
                    if (cc.atom == JS_ATOM_empty_string) {
31952
0
                        JS_FreeAtom(ctx, cc.atom);
31953
0
                        dbuf_putc(&bc_out, OP_push_empty_string);
31954
0
                    } else
31955
0
#endif
31956
0
                    {
31957
0
                        dbuf_putc(&bc_out, OP_push_atom_value);
31958
0
                        dbuf_put_u32(&bc_out, cc.atom);
31959
0
                    }
31960
0
                    dbuf_putc(&bc_out, OP_add_loc);
31961
0
                    dbuf_putc(&bc_out, idx);
31962
0
                    pos_next = cc.pos;
31963
0
                    break;
31964
0
                }
31965
                /* transformation:
31966
                   get_loc(n) push_i32(x) add dup put_loc(n) drop -> push_i32(x) add_loc(n)
31967
                 */
31968
353k
                if (code_match(&cc, pos_next, OP_push_i32, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
31969
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
31970
0
                    add_pc2line_info(s, bc_out.size, line_num);
31971
0
                    push_short_int(&bc_out, cc.label);
31972
0
                    dbuf_putc(&bc_out, OP_add_loc);
31973
0
                    dbuf_putc(&bc_out, idx);
31974
0
                    pos_next = cc.pos;
31975
0
                    break;
31976
0
                }
31977
                /* transformation: XXX: also do these:
31978
                   get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x) add_loc(n)
31979
                   get_loc(n) get_arg(x) add dup put_loc(n) drop -> get_arg(x) add_loc(n)
31980
                   get_loc(n) get_var_ref(x) add dup put_loc(n) drop -> get_var_ref(x) add_loc(n)
31981
                 */
31982
353k
                if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
31983
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
31984
0
                    add_pc2line_info(s, bc_out.size, line_num);
31985
0
                    put_short_code(&bc_out, cc.op, cc.idx);
31986
0
                    dbuf_putc(&bc_out, OP_add_loc);
31987
0
                    dbuf_putc(&bc_out, idx);
31988
0
                    pos_next = cc.pos;
31989
0
                    break;
31990
0
                }
31991
353k
                add_pc2line_info(s, bc_out.size, line_num);
31992
353k
                put_short_code(&bc_out, op, idx);
31993
353k
                break;
31994
353k
            }
31995
0
            goto no_change;
31996
0
#if SHORT_OPCODES
31997
404
        case OP_get_arg:
31998
2.33k
        case OP_get_var_ref:
31999
2.33k
            if (OPTIMIZE) {
32000
2.33k
                int idx;
32001
2.33k
                idx = get_u16(bc_buf + pos + 1);
32002
2.33k
                add_pc2line_info(s, bc_out.size, line_num);
32003
2.33k
                put_short_code(&bc_out, op, idx);
32004
2.33k
                break;
32005
2.33k
            }
32006
0
            goto no_change;
32007
0
#endif
32008
47.8k
        case OP_put_loc:
32009
47.8k
        case OP_put_arg:
32010
48.2k
        case OP_put_var_ref:
32011
48.2k
            if (OPTIMIZE) {
32012
                /* transformation: put_x(n) get_x(n) -> set_x(n) */
32013
48.2k
                int idx;
32014
48.2k
                idx = get_u16(bc_buf + pos + 1);
32015
48.2k
                if (code_match(&cc, pos_next, op - 1, idx, -1)) {
32016
41.1k
                    if (cc.line_num >= 0) line_num = cc.line_num;
32017
41.1k
                    add_pc2line_info(s, bc_out.size, line_num);
32018
41.1k
                    put_short_code(&bc_out, op + 1, idx);
32019
41.1k
                    pos_next = cc.pos;
32020
41.1k
                    break;
32021
41.1k
                }
32022
7.07k
                add_pc2line_info(s, bc_out.size, line_num);
32023
7.07k
                put_short_code(&bc_out, op, idx);
32024
7.07k
                break;
32025
48.2k
            }
32026
0
            goto no_change;
32027
32028
55
        case OP_post_inc:
32029
57
        case OP_post_dec:
32030
57
            if (OPTIMIZE) {
32031
                /* transformation:
32032
                   post_inc put_x drop -> inc put_x
32033
                   post_inc perm3 put_field drop -> inc put_field
32034
                   post_inc perm3 put_var_strict drop -> inc put_var_strict
32035
                   post_inc perm4 put_array_el drop -> inc put_array_el
32036
                 */
32037
57
                int op1, idx;
32038
57
                if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, OP_drop, -1)) {
32039
27
                    if (cc.line_num >= 0) line_num = cc.line_num;
32040
27
                    op1 = cc.op;
32041
27
                    idx = cc.idx;
32042
27
                    pos_next = cc.pos;
32043
27
                    if (code_match(&cc, cc.pos, op1 - 1, idx, -1)) {
32044
4
                        if (cc.line_num >= 0) line_num = cc.line_num;
32045
4
                        op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
32046
4
                        pos_next = cc.pos;
32047
4
                    }
32048
27
                    add_pc2line_info(s, bc_out.size, line_num);
32049
27
                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
32050
27
                    put_short_code(&bc_out, op1, idx);
32051
27
                    break;
32052
27
                }
32053
30
                if (code_match(&cc, pos_next, OP_perm3, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
32054
1
                    if (cc.line_num >= 0) line_num = cc.line_num;
32055
1
                    add_pc2line_info(s, bc_out.size, line_num);
32056
1
                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
32057
1
                    dbuf_putc(&bc_out, cc.op);
32058
1
                    dbuf_put_u32(&bc_out, cc.atom);
32059
1
                    pos_next = cc.pos;
32060
1
                    break;
32061
1
                }
32062
29
                if (code_match(&cc, pos_next, OP_perm4, OP_put_array_el, OP_drop, -1)) {
32063
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32064
0
                    add_pc2line_info(s, bc_out.size, line_num);
32065
0
                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
32066
0
                    dbuf_putc(&bc_out, OP_put_array_el);
32067
0
                    pos_next = cc.pos;
32068
0
                    break;
32069
0
                }
32070
29
            }
32071
29
            goto no_change;
32072
32073
29
#if SHORT_OPCODES
32074
29
        case OP_typeof:
32075
2
            if (OPTIMIZE) {
32076
                /* simplify typeof tests */
32077
2
                if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) {
32078
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
32079
0
                    int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq;
32080
0
                    int op2 = -1;
32081
0
                    switch (cc.atom) {
32082
0
                    case JS_ATOM_undefined:
32083
0
                        op2 = OP_typeof_is_undefined;
32084
0
                        break;
32085
0
                    case JS_ATOM_function:
32086
0
                        op2 = OP_typeof_is_function;
32087
0
                        break;
32088
0
                    }
32089
0
                    if (op2 >= 0) {
32090
                        /* transform typeof(s) == "<type>" into is_<type> */
32091
0
                        if (op1 == OP_strict_eq) {
32092
0
                            add_pc2line_info(s, bc_out.size, line_num);
32093
0
                            dbuf_putc(&bc_out, op2);
32094
0
                            JS_FreeAtom(ctx, cc.atom);
32095
0
                            pos_next = cc.pos;
32096
0
                            break;
32097
0
                        }
32098
0
                        if (op1 == OP_strict_neq && code_match(&cc, cc.pos, OP_if_false, -1)) {
32099
                            /* transform typeof(s) != "<type>" if_false into is_<type> if_true */
32100
0
                            if (cc.line_num >= 0) line_num = cc.line_num;
32101
0
                            add_pc2line_info(s, bc_out.size, line_num);
32102
0
                            dbuf_putc(&bc_out, op2);
32103
0
                            JS_FreeAtom(ctx, cc.atom);
32104
0
                            pos_next = cc.pos;
32105
0
                            label = cc.label;
32106
0
                            op = OP_if_true;
32107
0
                            goto has_label;
32108
0
                        }
32109
0
                    }
32110
0
                }
32111
2
            }
32112
2
            goto no_change;
32113
2
#endif
32114
32115
794k
        default:
32116
1.01M
        no_change:
32117
1.01M
            add_pc2line_info(s, bc_out.size, line_num);
32118
1.01M
            dbuf_put(&bc_out, bc_buf + pos, len);
32119
1.01M
            break;
32120
2.50M
        }
32121
2.50M
    }
32122
32123
    /* check that there were no missing labels */
32124
663k
    for(i = 0; i < s->label_count; i++) {
32125
617k
        assert(label_slots[i].first_reloc == NULL);
32126
617k
    }
32127
45.6k
#if SHORT_OPCODES
32128
45.6k
    if (OPTIMIZE) {
32129
        /* more jump optimizations */
32130
45.6k
        int patch_offsets = 0;
32131
417k
        for (i = 0, jp = s->jump_slots; i < s->jump_count; i++, jp++) {
32132
372k
            LabelSlot *ls;
32133
372k
            JumpSlot *jp1;
32134
372k
            int j, pos, diff, delta;
32135
32136
372k
            delta = 3;
32137
372k
            switch (op = jp->op) {
32138
6.83k
            case OP_goto16:
32139
6.83k
                delta = 1;
32140
                /* fall thru */
32141
6.92k
            case OP_if_false:
32142
8.57k
            case OP_if_true:
32143
8.57k
            case OP_goto:
32144
8.57k
                pos = jp->pos;
32145
8.57k
                diff = s->label_slots[jp->label].addr - pos;
32146
8.57k
                if (diff >= -128 && diff <= 127 + delta) {
32147
                    //put_u8(bc_out.buf + pos, diff);
32148
698
                    jp->size = 1;
32149
698
                    if (op == OP_goto16) {
32150
58
                        bc_out.buf[pos - 1] = jp->op = OP_goto8;
32151
640
                    } else {
32152
640
                        bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false);
32153
640
                    }
32154
698
                    goto shrink;
32155
698
                } else
32156
7.87k
                if (diff == (int16_t)diff && op == OP_goto) {
32157
                    //put_u16(bc_out.buf + pos, diff);
32158
0
                    jp->size = 2;
32159
0
                    delta = 2;
32160
0
                    bc_out.buf[pos - 1] = jp->op = OP_goto16;
32161
698
                shrink:
32162
                    /* XXX: should reduce complexity, using 2 finger copy scheme */
32163
698
                    memmove(bc_out.buf + pos + jp->size, bc_out.buf + pos + jp->size + delta,
32164
698
                            bc_out.size - pos - jp->size - delta);
32165
698
                    bc_out.size -= delta;
32166
698
                    patch_offsets++;
32167
6.84M
                    for (j = 0, ls = s->label_slots; j < s->label_count; j++, ls++) {
32168
6.84M
                        if (ls->addr > pos)
32169
2.74M
                            ls->addr -= delta;
32170
6.84M
                    }
32171
1.93M
                    for (j = i + 1, jp1 = jp + 1; j < s->jump_count; j++, jp1++) {
32172
1.93M
                        if (jp1->pos > pos)
32173
1.93M
                            jp1->pos -= delta;
32174
1.93M
                    }
32175
808k
                    for (j = 0; j < s->line_number_count; j++) {
32176
807k
                        if (s->line_number_slots[j].pc > pos)
32177
387k
                            s->line_number_slots[j].pc -= delta;
32178
807k
                    }
32179
698
                    continue;
32180
0
                }
32181
7.87k
                break;
32182
372k
            }
32183
372k
        }
32184
45.6k
        if (patch_offsets) {
32185
18
            JumpSlot *jp1;
32186
18
            int j;
32187
241k
            for (j = 0, jp1 = s->jump_slots; j < s->jump_count; j++, jp1++) {
32188
241k
                int diff1 = s->label_slots[jp1->label].addr - jp1->pos;
32189
241k
                switch (jp1->size) {
32190
8.40k
                case 1:
32191
8.40k
                    put_u8(bc_out.buf + jp1->pos, diff1);
32192
8.40k
                    break;
32193
6.70k
                case 2:
32194
6.70k
                    put_u16(bc_out.buf + jp1->pos, diff1);
32195
6.70k
                    break;
32196
225k
                case 4:
32197
225k
                    put_u32(bc_out.buf + jp1->pos, diff1);
32198
225k
                    break;
32199
241k
                }
32200
241k
            }
32201
18
        }
32202
45.6k
    }
32203
45.6k
    js_free(ctx, s->jump_slots);
32204
45.6k
    s->jump_slots = NULL;
32205
45.6k
#endif
32206
45.6k
    js_free(ctx, s->label_slots);
32207
45.6k
    s->label_slots = NULL;
32208
    /* XXX: should delay until copying to runtime bytecode function */
32209
45.6k
    compute_pc2line_info(s);
32210
45.6k
    js_free(ctx, s->line_number_slots);
32211
45.6k
    s->line_number_slots = NULL;
32212
    /* set the new byte code */
32213
45.6k
    dbuf_free(&s->byte_code);
32214
45.6k
    s->byte_code = bc_out;
32215
45.6k
    s->use_short_opcodes = TRUE;
32216
45.6k
    if (dbuf_error(&s->byte_code)) {
32217
0
        JS_ThrowOutOfMemory(ctx);
32218
0
        return -1;
32219
0
    }
32220
45.6k
    return 0;
32221
0
 fail:
32222
    /* XXX: not safe */
32223
0
    dbuf_free(&bc_out);
32224
0
    return -1;
32225
45.6k
}
32226
32227
/* compute the maximum stack size needed by the function */
32228
32229
typedef struct StackSizeState {
32230
    int bc_len;
32231
    int stack_len_max;
32232
    uint16_t *stack_level_tab;
32233
    int *pc_stack;
32234
    int pc_stack_len;
32235
    int pc_stack_size;
32236
} StackSizeState;
32237
32238
/* 'op' is only used for error indication */
32239
static __exception int ss_check(JSContext *ctx, StackSizeState *s,
32240
                                int pos, int op, int stack_len)
32241
2.16M
{
32242
2.16M
    if ((unsigned)pos >= s->bc_len) {
32243
0
        JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
32244
0
        return -1;
32245
0
    }
32246
2.16M
    if (stack_len > s->stack_len_max) {
32247
41
        s->stack_len_max = stack_len;
32248
41
        if (s->stack_len_max > JS_STACK_SIZE_MAX) {
32249
0
            JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
32250
0
            return -1;
32251
0
        }
32252
41
    }
32253
2.16M
    if (s->stack_level_tab[pos] != 0xffff) {
32254
        /* already explored: check that the stack size is consistent */
32255
358k
        if (s->stack_level_tab[pos] != stack_len) {
32256
0
            JS_ThrowInternalError(ctx, "unconsistent stack size: %d %d (pc=%d)",
32257
0
                                  s->stack_level_tab[pos], stack_len, pos);
32258
0
            return -1;
32259
358k
        } else {
32260
358k
            return 0;
32261
358k
        }
32262
358k
    }
32263
32264
    /* mark as explored and store the stack size */
32265
1.80M
    s->stack_level_tab[pos] = stack_len;
32266
32267
    /* queue the new PC to explore */
32268
1.80M
    if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]),
32269
1.80M
                        &s->pc_stack_size, s->pc_stack_len + 1))
32270
0
        return -1;
32271
1.80M
    s->pc_stack[s->pc_stack_len++] = pos;
32272
1.80M
    return 0;
32273
1.80M
}
32274
32275
static __exception int compute_stack_size(JSContext *ctx,
32276
                                          JSFunctionDef *fd,
32277
                                          int *pstack_size)
32278
45.6k
{
32279
45.6k
    StackSizeState s_s, *s = &s_s;
32280
45.6k
    int i, diff, n_pop, pos_next, stack_len, pos, op;
32281
45.6k
    const JSOpCode *oi;
32282
45.6k
    const uint8_t *bc_buf;
32283
32284
45.6k
    bc_buf = fd->byte_code.buf;
32285
45.6k
    s->bc_len = fd->byte_code.size;
32286
    /* bc_len > 0 */
32287
45.6k
    s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) *
32288
45.6k
                                   s->bc_len);
32289
45.6k
    if (!s->stack_level_tab)
32290
0
        return -1;
32291
7.30M
    for(i = 0; i < s->bc_len; i++)
32292
7.26M
        s->stack_level_tab[i] = 0xffff;
32293
45.6k
    s->stack_len_max = 0;
32294
45.6k
    s->pc_stack = NULL;
32295
45.6k
    s->pc_stack_len = 0;
32296
45.6k
    s->pc_stack_size = 0;
32297
32298
    /* breadth-first graph exploration */
32299
45.6k
    if (ss_check(ctx, s, 0, OP_invalid, 0))
32300
0
        goto fail;
32301
32302
1.84M
    while (s->pc_stack_len > 0) {
32303
1.80M
        pos = s->pc_stack[--s->pc_stack_len];
32304
1.80M
        stack_len = s->stack_level_tab[pos];
32305
1.80M
        op = bc_buf[pos];
32306
1.80M
        if (op == 0 || op >= OP_COUNT) {
32307
0
            JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos);
32308
0
            goto fail;
32309
0
        }
32310
1.80M
        oi = &short_opcode_info(op);
32311
1.80M
        pos_next = pos + oi->size;
32312
1.80M
        if (pos_next > s->bc_len) {
32313
0
            JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
32314
0
            goto fail;
32315
0
        }
32316
1.80M
        n_pop = oi->n_pop;
32317
        /* call pops a variable number of arguments */
32318
1.80M
        if (oi->fmt == OP_FMT_npop || oi->fmt == OP_FMT_npop_u16) {
32319
1.05k
            n_pop += get_u16(bc_buf + pos + 1);
32320
1.80M
        } else {
32321
1.80M
#if SHORT_OPCODES
32322
1.80M
            if (oi->fmt == OP_FMT_npopx) {
32323
2.98k
                n_pop += op - OP_call0;
32324
2.98k
            }
32325
1.80M
#endif
32326
1.80M
        }
32327
32328
1.80M
        if (stack_len < n_pop) {
32329
0
            JS_ThrowInternalError(ctx, "stack underflow (op=%d, pc=%d)", op, pos);
32330
0
            goto fail;
32331
0
        }
32332
1.80M
        stack_len += oi->n_push - n_pop;
32333
1.80M
        if (stack_len > s->stack_len_max) {
32334
46.8k
            s->stack_len_max = stack_len;
32335
46.8k
            if (s->stack_len_max > JS_STACK_SIZE_MAX) {
32336
0
                JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
32337
0
                goto fail;
32338
0
            }
32339
46.8k
        }
32340
1.80M
        switch(op) {
32341
88
        case OP_tail_call:
32342
144
        case OP_tail_call_method:
32343
41.5k
        case OP_return:
32344
45.6k
        case OP_return_undef:
32345
46.0k
        case OP_return_async:
32346
46.0k
        case OP_throw:
32347
46.4k
        case OP_throw_error:
32348
46.4k
        case OP_ret:
32349
46.4k
            goto done_insn;
32350
0
        case OP_goto:
32351
0
            diff = get_u32(bc_buf + pos + 1);
32352
0
            pos_next = pos + 1 + diff;
32353
0
            break;
32354
0
#if SHORT_OPCODES
32355
6.77k
        case OP_goto16:
32356
6.77k
            diff = (int16_t)get_u16(bc_buf + pos + 1);
32357
6.77k
            pos_next = pos + 1 + diff;
32358
6.77k
            break;
32359
5.37k
        case OP_goto8:
32360
5.37k
            diff = (int8_t)bc_buf[pos + 1];
32361
5.37k
            pos_next = pos + 1 + diff;
32362
5.37k
            break;
32363
3.60k
        case OP_if_true8:
32364
6.73k
        case OP_if_false8:
32365
6.73k
            diff = (int8_t)bc_buf[pos + 1];
32366
6.73k
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
32367
0
                goto fail;
32368
6.73k
            break;
32369
6.73k
#endif
32370
6.73k
        case OP_if_true:
32371
1.10k
        case OP_if_false:
32372
1.12k
        case OP_catch:
32373
1.12k
            diff = get_u32(bc_buf + pos + 1);
32374
1.12k
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
32375
0
                goto fail;
32376
1.12k
            break;
32377
1.12k
        case OP_gosub:
32378
0
            diff = get_u32(bc_buf + pos + 1);
32379
0
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1))
32380
0
                goto fail;
32381
0
            break;
32382
174k
        case OP_with_get_var:
32383
174k
        case OP_with_delete_var:
32384
174k
            diff = get_u32(bc_buf + pos + 5);
32385
174k
            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1))
32386
0
                goto fail;
32387
174k
            break;
32388
174k
        case OP_with_make_ref:
32389
177k
        case OP_with_get_ref:
32390
177k
        case OP_with_get_ref_undef:
32391
177k
            diff = get_u32(bc_buf + pos + 5);
32392
177k
            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2))
32393
0
                goto fail;
32394
177k
            break;
32395
177k
        case OP_with_put_var:
32396
0
            diff = get_u32(bc_buf + pos + 5);
32397
0
            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1))
32398
0
                goto fail;
32399
0
            break;
32400
32401
1.38M
        default:
32402
1.38M
            break;
32403
1.80M
        }
32404
1.75M
        if (ss_check(ctx, s, pos_next, op, stack_len))
32405
0
            goto fail;
32406
1.80M
    done_insn: ;
32407
1.80M
    }
32408
45.6k
    js_free(ctx, s->stack_level_tab);
32409
45.6k
    js_free(ctx, s->pc_stack);
32410
45.6k
    *pstack_size = s->stack_len_max;
32411
45.6k
    return 0;
32412
0
 fail:
32413
0
    js_free(ctx, s->stack_level_tab);
32414
0
    js_free(ctx, s->pc_stack);
32415
0
    *pstack_size = 0;
32416
0
    return -1;
32417
45.6k
}
32418
32419
static int add_module_variables(JSContext *ctx, JSFunctionDef *fd)
32420
4
{
32421
4
    int i, idx;
32422
4
    JSModuleDef *m = fd->module;
32423
4
    JSExportEntry *me;
32424
4
    JSGlobalVar *hf;
32425
32426
    /* The imported global variables were added as closure variables
32427
       in js_parse_import(). We add here the module global
32428
       variables. */
32429
32430
577
    for(i = 0; i < fd->global_var_count; i++) {
32431
573
        hf = &fd->global_vars[i];
32432
573
        if (add_closure_var(ctx, fd, TRUE, FALSE, i, hf->var_name, hf->is_const,
32433
573
                            hf->is_lexical, FALSE) < 0)
32434
0
            return -1;
32435
573
    }
32436
32437
    /* resolve the variable names of the local exports */
32438
4
    for(i = 0; i < m->export_entries_count; i++) {
32439
0
        me = &m->export_entries[i];
32440
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
32441
0
            idx = find_closure_var(ctx, fd, me->local_name);
32442
0
            if (idx < 0) {
32443
0
                JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does not exist",
32444
0
                                        me->local_name);
32445
0
                return -1;
32446
0
            }
32447
0
            me->u.local.var_idx = idx;
32448
0
        }
32449
0
    }
32450
4
    return 0;
32451
4
}
32452
32453
/* create a function object from a function definition. The function
32454
   definition is freed. All the child functions are also created. It
32455
   must be done this way to resolve all the variables. */
32456
static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
32457
45.6k
{
32458
45.6k
    JSValue func_obj;
32459
45.6k
    JSFunctionBytecode *b;
32460
45.6k
    struct list_head *el, *el1;
32461
45.6k
    int stack_size, scope, idx;
32462
45.6k
    int function_size, byte_code_offset, cpool_offset;
32463
45.6k
    int closure_var_offset, vardefs_offset;
32464
32465
    /* recompute scope linkage */
32466
139k
    for (scope = 0; scope < fd->scope_count; scope++) {
32467
94.1k
        fd->scopes[scope].first = -1;
32468
94.1k
    }
32469
45.6k
    if (fd->has_parameter_expressions) {
32470
        /* special end of variable list marker for the argument scope */
32471
118
        fd->scopes[ARG_SCOPE_INDEX].first = ARG_SCOPE_END;
32472
118
    }
32473
88.2k
    for (idx = 0; idx < fd->var_count; idx++) {
32474
42.6k
        JSVarDef *vd = &fd->vars[idx];
32475
42.6k
        vd->scope_next = fd->scopes[vd->scope_level].first;
32476
42.6k
        fd->scopes[vd->scope_level].first = idx;
32477
42.6k
    }
32478
48.5k
    for (scope = 2; scope < fd->scope_count; scope++) {
32479
2.89k
        JSVarScope *sd = &fd->scopes[scope];
32480
2.89k
        if (sd->first < 0)
32481
1.89k
            sd->first = fd->scopes[sd->parent].first;
32482
2.89k
    }
32483
88.2k
    for (idx = 0; idx < fd->var_count; idx++) {
32484
42.6k
        JSVarDef *vd = &fd->vars[idx];
32485
42.6k
        if (vd->scope_next < 0 && vd->scope_level > 1) {
32486
995
            scope = fd->scopes[vd->scope_level].parent;
32487
995
            vd->scope_next = fd->scopes[scope].first;
32488
995
        }
32489
42.6k
    }
32490
32491
    /* if the function contains an eval call, the closure variables
32492
       are used to compile the eval and they must be ordered by scope,
32493
       so it is necessary to create the closure variables before any
32494
       other variable lookup is done. */
32495
45.6k
    if (fd->has_eval_call)
32496
4
        add_eval_variables(ctx, fd);
32497
32498
    /* add the module global variables in the closure */
32499
45.6k
    if (fd->module) {
32500
4
        if (add_module_variables(ctx, fd))
32501
0
            goto fail;
32502
4
    }
32503
32504
    /* first create all the child functions */
32505
45.6k
    list_for_each_safe(el, el1, &fd->child_list) {
32506
4.64k
        JSFunctionDef *fd1;
32507
4.64k
        int cpool_idx;
32508
32509
4.64k
        fd1 = list_entry(el, JSFunctionDef, link);
32510
4.64k
        cpool_idx = fd1->parent_cpool_idx;
32511
4.64k
        func_obj = js_create_function(ctx, fd1);
32512
4.64k
        if (JS_IsException(func_obj))
32513
1
            goto fail;
32514
        /* save it in the constant pool */
32515
4.64k
        assert(cpool_idx >= 0);
32516
4.64k
        fd->cpool[cpool_idx] = func_obj;
32517
4.64k
    }
32518
32519
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 4)
32520
    if (!(fd->js_mode & JS_MODE_STRIP)) {
32521
        printf("pass 1\n");
32522
        dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size,
32523
                       fd->args, fd->arg_count, fd->vars, fd->var_count,
32524
                       fd->closure_var, fd->closure_var_count,
32525
                       fd->cpool, fd->cpool_count, fd->source, fd->line_num,
32526
                       fd->label_slots, NULL);
32527
        printf("\n");
32528
    }
32529
#endif
32530
32531
45.6k
    if (resolve_variables(ctx, fd))
32532
2
        goto fail;
32533
32534
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 2)
32535
    if (!(fd->js_mode & JS_MODE_STRIP)) {
32536
        printf("pass 2\n");
32537
        dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size,
32538
                       fd->args, fd->arg_count, fd->vars, fd->var_count,
32539
                       fd->closure_var, fd->closure_var_count,
32540
                       fd->cpool, fd->cpool_count, fd->source, fd->line_num,
32541
                       fd->label_slots, NULL);
32542
        printf("\n");
32543
    }
32544
#endif
32545
32546
45.6k
    if (resolve_labels(ctx, fd))
32547
0
        goto fail;
32548
32549
45.6k
    if (compute_stack_size(ctx, fd, &stack_size) < 0)
32550
0
        goto fail;
32551
32552
45.6k
    if (fd->js_mode & JS_MODE_STRIP) {
32553
0
        function_size = offsetof(JSFunctionBytecode, debug);
32554
45.6k
    } else {
32555
45.6k
        function_size = sizeof(*b);
32556
45.6k
    }
32557
45.6k
    cpool_offset = function_size;
32558
45.6k
    function_size += fd->cpool_count * sizeof(*fd->cpool);
32559
45.6k
    vardefs_offset = function_size;
32560
45.6k
    if (!(fd->js_mode & JS_MODE_STRIP) || fd->has_eval_call) {
32561
45.6k
        function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs);
32562
45.6k
    }
32563
45.6k
    closure_var_offset = function_size;
32564
45.6k
    function_size += fd->closure_var_count * sizeof(*fd->closure_var);
32565
45.6k
    byte_code_offset = function_size;
32566
45.6k
    function_size += fd->byte_code.size;
32567
32568
45.6k
    b = js_mallocz(ctx, function_size);
32569
45.6k
    if (!b)
32570
0
        goto fail;
32571
45.6k
    b->header.ref_count = 1;
32572
32573
45.6k
    b->byte_code_buf = (void *)((uint8_t*)b + byte_code_offset);
32574
45.6k
    b->byte_code_len = fd->byte_code.size;
32575
45.6k
    memcpy(b->byte_code_buf, fd->byte_code.buf, fd->byte_code.size);
32576
45.6k
    js_free(ctx, fd->byte_code.buf);
32577
45.6k
    fd->byte_code.buf = NULL;
32578
32579
45.6k
    b->func_name = fd->func_name;
32580
45.6k
    if (fd->arg_count + fd->var_count > 0) {
32581
41.7k
        if ((fd->js_mode & JS_MODE_STRIP) && !fd->has_eval_call) {
32582
            /* Strip variable definitions not needed at runtime */
32583
0
            int i;
32584
0
            for(i = 0; i < fd->var_count; i++) {
32585
0
                JS_FreeAtom(ctx, fd->vars[i].var_name);
32586
0
            }
32587
0
            for(i = 0; i < fd->arg_count; i++) {
32588
0
                JS_FreeAtom(ctx, fd->args[i].var_name);
32589
0
            }
32590
0
            for(i = 0; i < fd->closure_var_count; i++) {
32591
0
                JS_FreeAtom(ctx, fd->closure_var[i].var_name);
32592
0
                fd->closure_var[i].var_name = JS_ATOM_NULL;
32593
0
            }
32594
41.7k
        } else {
32595
41.7k
            b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
32596
41.7k
            memcpy(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
32597
41.7k
            memcpy(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
32598
41.7k
        }
32599
41.7k
        b->var_count = fd->var_count;
32600
41.7k
        b->arg_count = fd->arg_count;
32601
41.7k
        b->defined_arg_count = fd->defined_arg_count;
32602
41.7k
        js_free(ctx, fd->args);
32603
41.7k
        js_free(ctx, fd->vars);
32604
41.7k
    }
32605
45.6k
    b->cpool_count = fd->cpool_count;
32606
45.6k
    if (b->cpool_count) {
32607
238
        b->cpool = (void *)((uint8_t*)b + cpool_offset);
32608
238
        memcpy(b->cpool, fd->cpool, b->cpool_count * sizeof(*b->cpool));
32609
238
    }
32610
45.6k
    js_free(ctx, fd->cpool);
32611
45.6k
    fd->cpool = NULL;
32612
32613
45.6k
    b->stack_size = stack_size;
32614
32615
45.6k
    if (fd->js_mode & JS_MODE_STRIP) {
32616
0
        JS_FreeAtom(ctx, fd->filename);
32617
0
        dbuf_free(&fd->pc2line);    // probably useless
32618
45.6k
    } else {
32619
        /* XXX: source and pc2line info should be packed at the end of the
32620
           JSFunctionBytecode structure, avoiding allocation overhead
32621
         */
32622
45.6k
        b->has_debug = 1;
32623
45.6k
        b->debug.filename = fd->filename;
32624
45.6k
        b->debug.line_num = fd->line_num;
32625
32626
        //DynBuf pc2line;
32627
        //compute_pc2line_info(fd, &pc2line);
32628
        //js_free(ctx, fd->line_number_slots)
32629
45.6k
        b->debug.pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size);
32630
45.6k
        if (!b->debug.pc2line_buf)
32631
41.4k
            b->debug.pc2line_buf = fd->pc2line.buf;
32632
45.6k
        b->debug.pc2line_len = fd->pc2line.size;
32633
45.6k
        b->debug.source = fd->source;
32634
45.6k
        b->debug.source_len = fd->source_len;
32635
45.6k
    }
32636
45.6k
    if (fd->scopes != fd->def_scope_array)
32637
23
        js_free(ctx, fd->scopes);
32638
32639
45.6k
    b->closure_var_count = fd->closure_var_count;
32640
45.6k
    if (b->closure_var_count) {
32641
41.3k
        b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
32642
41.3k
        memcpy(b->closure_var, fd->closure_var, b->closure_var_count * sizeof(*b->closure_var));
32643
41.3k
    }
32644
45.6k
    js_free(ctx, fd->closure_var);
32645
45.6k
    fd->closure_var = NULL;
32646
32647
45.6k
    b->has_prototype = fd->has_prototype;
32648
45.6k
    b->has_simple_parameter_list = fd->has_simple_parameter_list;
32649
45.6k
    b->js_mode = fd->js_mode;
32650
45.6k
    b->is_derived_class_constructor = fd->is_derived_class_constructor;
32651
45.6k
    b->func_kind = fd->func_kind;
32652
45.6k
    b->need_home_object = (fd->home_object_var_idx >= 0 ||
32653
45.6k
                           fd->need_home_object);
32654
45.6k
    b->new_target_allowed = fd->new_target_allowed;
32655
45.6k
    b->super_call_allowed = fd->super_call_allowed;
32656
45.6k
    b->super_allowed = fd->super_allowed;
32657
45.6k
    b->arguments_allowed = fd->arguments_allowed;
32658
45.6k
    b->backtrace_barrier = fd->backtrace_barrier;
32659
45.6k
    b->realm = JS_DupContext(ctx);
32660
32661
45.6k
    add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
32662
    
32663
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 1)
32664
    if (!(fd->js_mode & JS_MODE_STRIP)) {
32665
        js_dump_function_bytecode(ctx, b);
32666
    }
32667
#endif
32668
32669
45.6k
    if (fd->parent) {
32670
        /* remove from parent list */
32671
4.64k
        list_del(&fd->link);
32672
4.64k
    }
32673
32674
45.6k
    js_free(ctx, fd);
32675
45.6k
    return JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
32676
3
 fail:
32677
3
    js_free_function_def(ctx, fd);
32678
3
    return JS_EXCEPTION;
32679
45.6k
}
32680
32681
static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)
32682
45.6k
{
32683
45.6k
    int i;
32684
32685
#if 0
32686
    {
32687
        char buf[ATOM_GET_STR_BUF_SIZE];
32688
        printf("freeing %s\n",
32689
               JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
32690
    }
32691
#endif
32692
45.6k
    free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE);
32693
32694
45.6k
    if (b->vardefs) {
32695
85.8k
        for(i = 0; i < b->arg_count + b->var_count; i++) {
32696
44.0k
            JS_FreeAtomRT(rt, b->vardefs[i].var_name);
32697
44.0k
        }
32698
41.7k
    }
32699
51.0k
    for(i = 0; i < b->cpool_count; i++)
32700
5.42k
        JS_FreeValueRT(rt, b->cpool[i]);
32701
32702
2.87M
    for(i = 0; i < b->closure_var_count; i++) {
32703
2.82M
        JSClosureVar *cv = &b->closure_var[i];
32704
2.82M
        JS_FreeAtomRT(rt, cv->var_name);
32705
2.82M
    }
32706
45.6k
    if (b->realm)
32707
45.6k
        JS_FreeContext(b->realm);
32708
32709
45.6k
    JS_FreeAtomRT(rt, b->func_name);
32710
45.6k
    if (b->has_debug) {
32711
45.6k
        JS_FreeAtomRT(rt, b->debug.filename);
32712
45.6k
        js_free_rt(rt, b->debug.pc2line_buf);
32713
45.6k
        js_free_rt(rt, b->debug.source);
32714
45.6k
    }
32715
32716
45.6k
    remove_gc_object(&b->header);
32717
45.6k
    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && b->header.ref_count != 0) {
32718
2
        list_add_tail(&b->header.link, &rt->gc_zero_ref_count_list);
32719
45.6k
    } else {
32720
45.6k
        js_free_rt(rt, b);
32721
45.6k
    }
32722
45.6k
}
32723
32724
static __exception int js_parse_directives(JSParseState *s)
32725
52.8k
{
32726
52.8k
    char str[20];
32727
52.8k
    JSParsePos pos;
32728
52.8k
    BOOL has_semi;
32729
32730
52.8k
    if (s->token.val != TOK_STRING)
32731
52.8k
        return 0;
32732
32733
0
    js_parse_get_pos(s, &pos);
32734
32735
0
    while(s->token.val == TOK_STRING) {
32736
        /* Copy actual source string representation */
32737
0
        snprintf(str, sizeof str, "%.*s",
32738
0
                 (int)(s->buf_ptr - s->token.ptr - 2), s->token.ptr + 1);
32739
32740
0
        if (next_token(s))
32741
0
            return -1;
32742
32743
0
        has_semi = FALSE;
32744
0
        switch (s->token.val) {
32745
0
        case ';':
32746
0
            if (next_token(s))
32747
0
                return -1;
32748
0
            has_semi = TRUE;
32749
0
            break;
32750
0
        case '}':
32751
0
        case TOK_EOF:
32752
0
            has_semi = TRUE;
32753
0
            break;
32754
0
        case TOK_NUMBER:
32755
0
        case TOK_STRING:
32756
0
        case TOK_TEMPLATE:
32757
0
        case TOK_IDENT:
32758
0
        case TOK_REGEXP:
32759
0
        case TOK_DEC:
32760
0
        case TOK_INC:
32761
0
        case TOK_NULL:
32762
0
        case TOK_FALSE:
32763
0
        case TOK_TRUE:
32764
0
        case TOK_IF:
32765
0
        case TOK_RETURN:
32766
0
        case TOK_VAR:
32767
0
        case TOK_THIS:
32768
0
        case TOK_DELETE:
32769
0
        case TOK_TYPEOF:
32770
0
        case TOK_NEW:
32771
0
        case TOK_DO:
32772
0
        case TOK_WHILE:
32773
0
        case TOK_FOR:
32774
0
        case TOK_SWITCH:
32775
0
        case TOK_THROW:
32776
0
        case TOK_TRY:
32777
0
        case TOK_FUNCTION:
32778
0
        case TOK_DEBUGGER:
32779
0
        case TOK_WITH:
32780
0
        case TOK_CLASS:
32781
0
        case TOK_CONST:
32782
0
        case TOK_ENUM:
32783
0
        case TOK_EXPORT:
32784
0
        case TOK_IMPORT:
32785
0
        case TOK_SUPER:
32786
0
        case TOK_INTERFACE:
32787
0
        case TOK_LET:
32788
0
        case TOK_PACKAGE:
32789
0
        case TOK_PRIVATE:
32790
0
        case TOK_PROTECTED:
32791
0
        case TOK_PUBLIC:
32792
0
        case TOK_STATIC:
32793
            /* automatic insertion of ';' */
32794
0
            if (s->got_lf)
32795
0
                has_semi = TRUE;
32796
0
            break;
32797
0
        default:
32798
0
            break;
32799
0
        }
32800
0
        if (!has_semi)
32801
0
            break;
32802
0
        if (!strcmp(str, "use strict")) {
32803
0
            s->cur_func->has_use_strict = TRUE;
32804
0
            s->cur_func->js_mode |= JS_MODE_STRICT;
32805
0
        }
32806
0
#if !defined(DUMP_BYTECODE) || !(DUMP_BYTECODE & 8)
32807
0
        else if (!strcmp(str, "use strip")) {
32808
0
            s->cur_func->js_mode |= JS_MODE_STRIP;
32809
0
        }
32810
0
#endif
32811
0
#ifdef CONFIG_BIGNUM
32812
0
        else if (s->ctx->bignum_ext && !strcmp(str, "use math")) {
32813
0
            s->cur_func->js_mode |= JS_MODE_MATH;
32814
0
        }
32815
0
#endif
32816
0
    }
32817
0
    return js_parse_seek_token(s, &pos);
32818
0
}
32819
32820
static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
32821
                                         JSAtom func_name)
32822
12.5k
{
32823
12.5k
    JSAtom name;
32824
12.5k
    int i, idx;
32825
32826
12.5k
    if (fd->js_mode & JS_MODE_STRICT) {
32827
271
        if (!fd->has_simple_parameter_list && fd->has_use_strict) {
32828
0
            return js_parse_error(s, "\"use strict\" not allowed in function with default or destructuring parameter");
32829
0
        }
32830
271
        if (func_name == JS_ATOM_eval || func_name == JS_ATOM_arguments) {
32831
0
            return js_parse_error(s, "invalid function name in strict code");
32832
0
        }
32833
594
        for (idx = 0; idx < fd->arg_count; idx++) {
32834
323
            name = fd->args[idx].var_name;
32835
32836
323
            if (name == JS_ATOM_eval || name == JS_ATOM_arguments) {
32837
0
                return js_parse_error(s, "invalid argument name in strict code");
32838
0
            }
32839
323
        }
32840
271
    }
32841
    /* check async_generator case */
32842
12.5k
    if ((fd->js_mode & JS_MODE_STRICT)
32843
12.5k
    ||  !fd->has_simple_parameter_list
32844
12.5k
    ||  (fd->func_type == JS_PARSE_FUNC_METHOD && fd->func_kind == JS_FUNC_ASYNC)
32845
12.5k
    ||  fd->func_type == JS_PARSE_FUNC_ARROW
32846
12.5k
    ||  fd->func_type == JS_PARSE_FUNC_METHOD) {
32847
2.18k
        for (idx = 0; idx < fd->arg_count; idx++) {
32848
1.38k
            name = fd->args[idx].var_name;
32849
1.38k
            if (name != JS_ATOM_NULL) {
32850
2.44k
                for (i = 0; i < idx; i++) {
32851
1.10k
                    if (fd->args[i].var_name == name)
32852
0
                        goto duplicate;
32853
1.10k
                }
32854
                /* Check if argument name duplicates a destructuring parameter */
32855
                /* XXX: should have a flag for such variables */
32856
3.10k
                for (i = 0; i < fd->var_count; i++) {
32857
1.75k
                    if (fd->vars[i].var_name == name &&
32858
1.75k
                        fd->vars[i].scope_level == 0)
32859
0
                        goto duplicate;
32860
1.75k
                }
32861
1.34k
            }
32862
1.38k
        }
32863
802
    }
32864
12.5k
    return 0;
32865
32866
0
duplicate:
32867
0
    return js_parse_error(s, "duplicate argument names not allowed in this context");
32868
12.5k
}
32869
32870
/* create a function to initialize class fields */
32871
static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s)
32872
88
{
32873
88
    JSFunctionDef *fd;
32874
    
32875
88
    fd = js_new_function_def(s->ctx, s->cur_func, FALSE, FALSE,
32876
88
                             s->filename, 0);
32877
88
    if (!fd)
32878
0
        return NULL;
32879
88
    fd->func_name = JS_ATOM_NULL;
32880
88
    fd->has_prototype = FALSE;
32881
88
    fd->has_home_object = TRUE;
32882
    
32883
88
    fd->has_arguments_binding = FALSE;
32884
88
    fd->has_this_binding = TRUE;
32885
88
    fd->is_derived_class_constructor = FALSE;
32886
88
    fd->new_target_allowed = TRUE;
32887
88
    fd->super_call_allowed = FALSE;
32888
88
    fd->super_allowed = fd->has_home_object;
32889
88
    fd->arguments_allowed = FALSE;
32890
    
32891
88
    fd->func_kind = JS_FUNC_NORMAL;
32892
88
    fd->func_type = JS_PARSE_FUNC_METHOD;
32893
88
    return fd;
32894
88
}
32895
32896
/* func_name must be JS_ATOM_NULL for JS_PARSE_FUNC_STATEMENT and
32897
   JS_PARSE_FUNC_EXPR, JS_PARSE_FUNC_ARROW and JS_PARSE_FUNC_VAR */
32898
static __exception int js_parse_function_decl2(JSParseState *s,
32899
                                               JSParseFunctionEnum func_type,
32900
                                               JSFunctionKindEnum func_kind,
32901
                                               JSAtom func_name,
32902
                                               const uint8_t *ptr,
32903
                                               int function_line_num,
32904
                                               JSParseExportEnum export_flag,
32905
                                               JSFunctionDef **pfd)
32906
12.5k
{
32907
12.5k
    JSContext *ctx = s->ctx;
32908
12.5k
    JSFunctionDef *fd = s->cur_func;
32909
12.5k
    BOOL is_expr;
32910
12.5k
    int func_idx, lexical_func_idx = -1;
32911
12.5k
    BOOL has_opt_arg;
32912
12.5k
    BOOL create_func_var = FALSE;
32913
32914
12.5k
    is_expr = (func_type != JS_PARSE_FUNC_STATEMENT &&
32915
12.5k
               func_type != JS_PARSE_FUNC_VAR);
32916
32917
12.5k
    if (func_type == JS_PARSE_FUNC_STATEMENT ||
32918
12.5k
        func_type == JS_PARSE_FUNC_VAR ||
32919
12.5k
        func_type == JS_PARSE_FUNC_EXPR) {
32920
11.7k
        if (func_kind == JS_FUNC_NORMAL &&
32921
11.7k
            token_is_pseudo_keyword(s, JS_ATOM_async) &&
32922
11.7k
            peek_token(s, TRUE) != '\n') {
32923
0
            if (next_token(s))
32924
0
                return -1;
32925
0
            func_kind = JS_FUNC_ASYNC;
32926
0
        }
32927
11.7k
        if (next_token(s))
32928
0
            return -1;
32929
11.7k
        if (s->token.val == '*') {
32930
87
            if (next_token(s))
32931
0
                return -1;
32932
87
            func_kind |= JS_FUNC_GENERATOR;
32933
87
        }
32934
32935
11.7k
        if (s->token.val == TOK_IDENT) {
32936
11.7k
            if (s->token.u.ident.is_reserved ||
32937
11.7k
                (s->token.u.ident.atom == JS_ATOM_yield &&
32938
11.7k
                 func_type == JS_PARSE_FUNC_EXPR &&
32939
11.7k
                 (func_kind & JS_FUNC_GENERATOR)) ||
32940
11.7k
                (s->token.u.ident.atom == JS_ATOM_await &&
32941
11.7k
                 func_type == JS_PARSE_FUNC_EXPR &&
32942
11.7k
                 (func_kind & JS_FUNC_ASYNC))) {
32943
0
                return js_parse_error_reserved_identifier(s);
32944
0
            }
32945
11.7k
        }
32946
11.7k
        if (s->token.val == TOK_IDENT ||
32947
11.7k
            (((s->token.val == TOK_YIELD && !(fd->js_mode & JS_MODE_STRICT)) ||
32948
0
             (s->token.val == TOK_AWAIT && !s->is_module)) &&
32949
11.7k
             func_type == JS_PARSE_FUNC_EXPR)) {
32950
11.7k
            func_name = JS_DupAtom(ctx, s->token.u.ident.atom);
32951
11.7k
            if (next_token(s)) {
32952
1
                JS_FreeAtom(ctx, func_name);
32953
1
                return -1;
32954
1
            }
32955
11.7k
        } else {
32956
0
            if (func_type != JS_PARSE_FUNC_EXPR &&
32957
0
                export_flag != JS_PARSE_EXPORT_DEFAULT) {
32958
0
                return js_parse_error(s, "function name expected");
32959
0
            }
32960
0
        }
32961
11.7k
    } else if (func_type != JS_PARSE_FUNC_ARROW) {
32962
219
        func_name = JS_DupAtom(ctx, func_name);
32963
219
    }
32964
32965
12.5k
    if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_MODULE &&
32966
12.5k
        (func_type == JS_PARSE_FUNC_STATEMENT || func_type == JS_PARSE_FUNC_VAR)) {
32967
3
        JSGlobalVar *hf;
32968
3
        hf = find_global_var(fd, func_name);
32969
        /* XXX: should check scope chain */
32970
3
        if (hf && hf->scope_level == fd->scope_level) {
32971
0
            js_parse_error(s, "invalid redefinition of global identifier in module code");
32972
0
            JS_FreeAtom(ctx, func_name);
32973
0
            return -1;
32974
0
        }
32975
3
    }
32976
32977
12.5k
    if (func_type == JS_PARSE_FUNC_VAR) {
32978
478
        if (!(fd->js_mode & JS_MODE_STRICT)
32979
478
        && func_kind == JS_FUNC_NORMAL
32980
478
        &&  find_lexical_decl(ctx, fd, func_name, fd->scope_first, FALSE) < 0
32981
478
        &&  !((func_idx = find_var(ctx, fd, func_name)) >= 0 && (func_idx & ARGUMENT_VAR_OFFSET))
32982
478
        &&  !(func_name == JS_ATOM_arguments && fd->has_arguments_binding)) {
32983
3
            create_func_var = TRUE;
32984
3
        }
32985
        /* Create the lexical name here so that the function closure
32986
           contains it */
32987
478
        if (fd->is_eval &&
32988
478
            (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
32989
478
             fd->eval_type == JS_EVAL_TYPE_MODULE) &&
32990
478
            fd->scope_level == fd->body_scope) {
32991
            /* avoid creating a lexical variable in the global
32992
               scope. XXX: check annex B */
32993
0
            JSGlobalVar *hf;
32994
0
            hf = find_global_var(fd, func_name);
32995
            /* XXX: should check scope chain */
32996
0
            if (hf && hf->scope_level == fd->scope_level) {
32997
0
                js_parse_error(s, "invalid redefinition of global identifier");
32998
0
                JS_FreeAtom(ctx, func_name);
32999
0
                return -1;
33000
0
            }
33001
478
        } else {
33002
            /* Always create a lexical name, fail if at the same scope as
33003
               existing name */
33004
            /* Lexical variable will be initialized upon entering scope */
33005
478
            lexical_func_idx = define_var(s, fd, func_name,
33006
478
                                          func_kind != JS_FUNC_NORMAL ?
33007
7
                                          JS_VAR_DEF_NEW_FUNCTION_DECL :
33008
478
                                          JS_VAR_DEF_FUNCTION_DECL);
33009
478
            if (lexical_func_idx < 0) {
33010
0
                JS_FreeAtom(ctx, func_name);
33011
0
                return -1;
33012
0
            }
33013
478
        }
33014
478
    }
33015
33016
12.5k
    fd = js_new_function_def(ctx, fd, FALSE, is_expr,
33017
12.5k
                             s->filename, function_line_num);
33018
12.5k
    if (!fd) {
33019
1
        JS_FreeAtom(ctx, func_name);
33020
1
        return -1;
33021
1
    }
33022
12.5k
    if (pfd)
33023
219
        *pfd = fd;
33024
12.5k
    s->cur_func = fd;
33025
12.5k
    fd->func_name = func_name;
33026
    /* XXX: test !fd->is_generator is always false */
33027
12.5k
    fd->has_prototype = (func_type == JS_PARSE_FUNC_STATEMENT ||
33028
12.5k
                         func_type == JS_PARSE_FUNC_VAR ||
33029
12.5k
                         func_type == JS_PARSE_FUNC_EXPR) &&
33030
12.5k
                        func_kind == JS_FUNC_NORMAL;
33031
12.5k
    fd->has_home_object = (func_type == JS_PARSE_FUNC_METHOD ||
33032
12.5k
                           func_type == JS_PARSE_FUNC_GETTER ||
33033
12.5k
                           func_type == JS_PARSE_FUNC_SETTER ||
33034
12.5k
                           func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
33035
12.5k
                           func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
33036
12.5k
    fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW);
33037
12.5k
    fd->has_this_binding = fd->has_arguments_binding;
33038
12.5k
    fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
33039
12.5k
    if (func_type == JS_PARSE_FUNC_ARROW) {
33040
571
        fd->new_target_allowed = fd->parent->new_target_allowed;
33041
571
        fd->super_call_allowed = fd->parent->super_call_allowed;
33042
571
        fd->super_allowed = fd->parent->super_allowed;
33043
571
        fd->arguments_allowed = fd->parent->arguments_allowed;
33044
11.9k
    } else {
33045
11.9k
        fd->new_target_allowed = TRUE;
33046
11.9k
        fd->super_call_allowed = fd->is_derived_class_constructor;
33047
11.9k
        fd->super_allowed = fd->has_home_object;
33048
11.9k
        fd->arguments_allowed = TRUE;
33049
11.9k
    }
33050
33051
    /* fd->in_function_body == FALSE prevents yield/await during the parsing
33052
       of the arguments in generator/async functions. They are parsed as
33053
       regular identifiers for other function kinds. */
33054
12.5k
    fd->func_kind = func_kind;
33055
12.5k
    fd->func_type = func_type;
33056
33057
12.5k
    if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
33058
12.5k
        func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
33059
        /* error if not invoked as a constructor */
33060
88
        emit_op(s, OP_check_ctor);
33061
88
    }
33062
33063
12.5k
    if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
33064
88
        emit_class_field_init(s);
33065
88
    }
33066
    
33067
    /* parse arguments */
33068
12.5k
    fd->has_simple_parameter_list = TRUE;
33069
12.5k
    fd->has_parameter_expressions = FALSE;
33070
12.5k
    has_opt_arg = FALSE;
33071
12.5k
    if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) {
33072
353
        JSAtom name;
33073
353
        if (s->token.u.ident.is_reserved) {
33074
0
            js_parse_error_reserved_identifier(s);
33075
0
            goto fail;
33076
0
        }
33077
353
        name = s->token.u.ident.atom;
33078
353
        if (add_arg(ctx, fd, name) < 0)
33079
0
            goto fail;
33080
353
        fd->defined_arg_count = 1;
33081
12.2k
    } else {
33082
12.2k
        if (s->token.val == '(') {
33083
12.2k
            int skip_bits;
33084
            /* if there is an '=' inside the parameter list, we
33085
               consider there is a parameter expression inside */
33086
12.2k
            js_parse_skip_parens_token(s, &skip_bits, FALSE);
33087
12.2k
            if (skip_bits & SKIP_HAS_ASSIGNMENT)
33088
147
                fd->has_parameter_expressions = TRUE;
33089
12.2k
            if (next_token(s))
33090
0
                goto fail;
33091
12.2k
        } else {
33092
0
            if (js_parse_expect(s, '('))
33093
0
                goto fail;
33094
0
        }
33095
33096
12.2k
        if (fd->has_parameter_expressions) {
33097
147
            fd->scope_level = -1; /* force no parent scope */
33098
147
            if (push_scope(s) < 0)
33099
0
                return -1;
33100
147
        }
33101
        
33102
13.0k
        while (s->token.val != ')') {
33103
1.08k
            JSAtom name;
33104
1.08k
            BOOL rest = FALSE;
33105
1.08k
            int idx, has_initializer;
33106
33107
1.08k
            if (s->token.val == TOK_ELLIPSIS) {
33108
0
                fd->has_simple_parameter_list = FALSE;
33109
0
                rest = TRUE;
33110
0
                if (next_token(s))
33111
0
                    goto fail;
33112
0
            }
33113
1.08k
            if (s->token.val == '[' || s->token.val == '{') {
33114
42
                fd->has_simple_parameter_list = FALSE;
33115
42
                if (rest) {
33116
0
                    emit_op(s, OP_rest);
33117
0
                    emit_u16(s, fd->arg_count);
33118
42
                } else {
33119
                    /* unnamed arg for destructuring */
33120
42
                    idx = add_arg(ctx, fd, JS_ATOM_NULL);
33121
42
                    emit_op(s, OP_get_arg);
33122
42
                    emit_u16(s, idx);
33123
42
                }
33124
42
                has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE);
33125
42
                if (has_initializer < 0)
33126
0
                    goto fail;
33127
42
                if (has_initializer)
33128
4
                    has_opt_arg = TRUE;
33129
42
                if (!has_opt_arg)
33130
38
                    fd->defined_arg_count++;
33131
1.04k
            } else if (s->token.val == TOK_IDENT) {
33132
1.04k
                if (s->token.u.ident.is_reserved) {
33133
0
                    js_parse_error_reserved_identifier(s);
33134
0
                    goto fail;
33135
0
                }
33136
1.04k
                name = s->token.u.ident.atom;
33137
1.04k
                if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
33138
0
                    js_parse_error_reserved_identifier(s);
33139
0
                    goto fail;
33140
0
                }
33141
1.04k
                if (fd->has_parameter_expressions) {
33142
428
                    if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0)
33143
0
                        goto fail;
33144
428
                }
33145
                /* XXX: could avoid allocating an argument if rest is true */
33146
1.04k
                idx = add_arg(ctx, fd, name);
33147
1.04k
                if (idx < 0)
33148
0
                    goto fail;
33149
1.04k
                if (next_token(s))
33150
0
                    goto fail;
33151
1.04k
                if (rest) {
33152
0
                    emit_op(s, OP_rest);
33153
0
                    emit_u16(s, idx);
33154
0
                    if (fd->has_parameter_expressions) {
33155
0
                        emit_op(s, OP_dup);
33156
0
                        emit_op(s, OP_scope_put_var_init);
33157
0
                        emit_atom(s, name);
33158
0
                        emit_u16(s, fd->scope_level);
33159
0
                    }
33160
0
                    emit_op(s, OP_put_arg);
33161
0
                    emit_u16(s, idx);
33162
0
                    fd->has_simple_parameter_list = FALSE;
33163
0
                    has_opt_arg = TRUE;
33164
1.04k
                } else if (s->token.val == '=') {
33165
109
                    int label;
33166
                    
33167
109
                    fd->has_simple_parameter_list = FALSE;
33168
109
                    has_opt_arg = TRUE;
33169
33170
109
                    if (next_token(s))
33171
0
                        goto fail;
33172
33173
109
                    label = new_label(s);
33174
109
                    emit_op(s, OP_get_arg);
33175
109
                    emit_u16(s, idx);
33176
109
                    emit_op(s, OP_dup);
33177
109
                    emit_op(s, OP_undefined);
33178
109
                    emit_op(s, OP_strict_eq);
33179
109
                    emit_goto(s, OP_if_false, label);
33180
109
                    emit_op(s, OP_drop);
33181
109
                    if (js_parse_assign_expr(s))
33182
0
                        goto fail;
33183
109
                    set_object_name(s, name);
33184
109
                    emit_op(s, OP_dup);
33185
109
                    emit_op(s, OP_put_arg);
33186
109
                    emit_u16(s, idx);
33187
109
                    emit_label(s, label);
33188
109
                    emit_op(s, OP_scope_put_var_init);
33189
109
                    emit_atom(s, name);
33190
109
                    emit_u16(s, fd->scope_level);
33191
936
                } else {
33192
936
                    if (!has_opt_arg) {
33193
901
                        fd->defined_arg_count++;
33194
901
                    }
33195
936
                    if (fd->has_parameter_expressions) {
33196
                        /* copy the argument to the argument scope */
33197
319
                        emit_op(s, OP_get_arg);
33198
319
                        emit_u16(s, idx);
33199
319
                        emit_op(s, OP_scope_put_var_init);
33200
319
                        emit_atom(s, name);
33201
319
                        emit_u16(s, fd->scope_level);
33202
319
                    }
33203
936
                }
33204
1.04k
            } else {
33205
0
                js_parse_error(s, "missing formal parameter");
33206
0
                goto fail;
33207
0
            }
33208
1.08k
            if (rest && s->token.val != ')') {
33209
0
                js_parse_expect(s, ')');
33210
0
                goto fail;
33211
0
            }
33212
1.08k
            if (s->token.val == ')')
33213
210
                break;
33214
877
            if (js_parse_expect(s, ','))
33215
0
                goto fail;
33216
877
        }
33217
12.2k
        if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) ||
33218
12.2k
            (func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) {
33219
0
            js_parse_error(s, "invalid number of arguments for getter or setter");
33220
0
            goto fail;
33221
0
        }
33222
12.2k
    }
33223
33224
12.5k
    if (fd->has_parameter_expressions) {
33225
147
        int idx;
33226
33227
        /* Copy the variables in the argument scope to the variable
33228
           scope (see FunctionDeclarationInstantiation() in spec). The
33229
           normal arguments are already present, so no need to copy
33230
           them. */
33231
147
        idx = fd->scopes[fd->scope_level].first;
33232
681
        while (idx >= 0) {
33233
534
            JSVarDef *vd = &fd->vars[idx];
33234
534
            if (vd->scope_level != fd->scope_level)
33235
0
                break;
33236
534
            if (find_var(ctx, fd, vd->var_name) < 0) {
33237
106
                if (add_var(ctx, fd, vd->var_name) < 0)
33238
0
                    goto fail;
33239
106
                vd = &fd->vars[idx]; /* fd->vars may have been reallocated */
33240
106
                emit_op(s, OP_scope_get_var);
33241
106
                emit_atom(s, vd->var_name);
33242
106
                emit_u16(s, fd->scope_level);
33243
106
                emit_op(s, OP_scope_put_var);
33244
106
                emit_atom(s, vd->var_name);
33245
106
                emit_u16(s, 0);
33246
106
            }
33247
534
            idx = vd->scope_next;
33248
534
        }
33249
        
33250
        /* the argument scope has no parent, hence we don't use pop_scope(s) */
33251
147
        emit_op(s, OP_leave_scope);
33252
147
        emit_u16(s, fd->scope_level);
33253
33254
        /* set the variable scope as the current scope */
33255
147
        fd->scope_level = 0;
33256
147
        fd->scope_first = fd->scopes[fd->scope_level].first;
33257
147
    }
33258
    
33259
12.5k
    if (next_token(s))
33260
0
        goto fail;
33261
33262
    /* generator function: yield after the parameters are evaluated */
33263
12.5k
    if (func_kind == JS_FUNC_GENERATOR ||
33264
12.5k
        func_kind == JS_FUNC_ASYNC_GENERATOR)
33265
86
        emit_op(s, OP_initial_yield);
33266
33267
    /* in generators, yield expression is forbidden during the parsing
33268
       of the arguments */
33269
12.5k
    fd->in_function_body = TRUE;
33270
12.5k
    push_scope(s);  /* enter body scope */
33271
12.5k
    fd->body_scope = fd->scope_level;
33272
33273
12.5k
    if (s->token.val == TOK_ARROW) {
33274
711
        if (next_token(s))
33275
0
            goto fail;
33276
33277
711
        if (s->token.val != '{') {
33278
699
            if (js_parse_function_check_names(s, fd, func_name))
33279
0
                goto fail;
33280
33281
699
            if (js_parse_assign_expr(s))
33282
0
                goto fail;
33283
33284
699
            if (func_kind != JS_FUNC_NORMAL)
33285
13
                emit_op(s, OP_return_async);
33286
686
            else
33287
686
                emit_op(s, OP_return);
33288
33289
699
            if (!(fd->js_mode & JS_MODE_STRIP)) {
33290
                /* save the function source code */
33291
                /* the end of the function source code is after the last
33292
                   token of the function source stored into s->last_ptr */
33293
699
                fd->source_len = s->last_ptr - ptr;
33294
699
                fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
33295
699
                if (!fd->source)
33296
0
                    goto fail;
33297
699
            }
33298
699
            goto done;
33299
699
        }
33300
711
    }
33301
33302
11.8k
    if (js_parse_expect(s, '{'))
33303
1
        goto fail;
33304
33305
11.8k
    if (js_parse_directives(s))
33306
0
        goto fail;
33307
33308
    /* in strict_mode, check function and argument names */
33309
11.8k
    if (js_parse_function_check_names(s, fd, func_name))
33310
0
        goto fail;
33311
33312
46.1k
    while (s->token.val != '}') {
33313
34.3k
        if (js_parse_source_element(s))
33314
8
            goto fail;
33315
34.3k
    }
33316
11.8k
    if (!(fd->js_mode & JS_MODE_STRIP)) {
33317
        /* save the function source code */
33318
11.8k
        fd->source_len = s->buf_ptr - ptr;
33319
11.8k
        fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
33320
11.8k
        if (!fd->source)
33321
1
            goto fail;
33322
11.8k
    }
33323
33324
11.8k
    if (next_token(s)) {
33325
        /* consume the '}' */
33326
0
        goto fail;
33327
0
    }
33328
33329
    /* in case there is no return, add one */
33330
11.8k
    if (js_is_live_code(s)) {
33331
11.8k
        emit_return(s, FALSE);
33332
11.8k
    }
33333
12.5k
done:
33334
12.5k
    s->cur_func = fd->parent;
33335
33336
    /* create the function object */
33337
12.5k
    {
33338
12.5k
        int idx;
33339
12.5k
        JSAtom func_name = fd->func_name;
33340
33341
        /* the real object will be set at the end of the compilation */
33342
12.5k
        idx = cpool_add(s, JS_NULL);
33343
12.5k
        fd->parent_cpool_idx = idx;
33344
33345
12.5k
        if (is_expr) {
33346
            /* for constructors, no code needs to be generated here */
33347
797
            if (func_type != JS_PARSE_FUNC_CLASS_CONSTRUCTOR &&
33348
797
                func_type != JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
33349
                /* OP_fclosure creates the function object from the bytecode
33350
                   and adds the scope information */
33351
709
                emit_op(s, OP_fclosure);
33352
709
                emit_u32(s, idx);
33353
709
                if (func_name == JS_ATOM_NULL) {
33354
700
                    emit_op(s, OP_set_name);
33355
700
                    emit_u32(s, JS_ATOM_NULL);
33356
700
                }
33357
709
            }
33358
11.7k
        } else if (func_type == JS_PARSE_FUNC_VAR) {
33359
476
            emit_op(s, OP_fclosure);
33360
476
            emit_u32(s, idx);
33361
476
            if (create_func_var) {
33362
3
                if (s->cur_func->is_global_var) {
33363
3
                    JSGlobalVar *hf;
33364
                    /* the global variable must be defined at the start of the
33365
                       function */
33366
3
                    hf = add_global_var(ctx, s->cur_func, func_name);
33367
3
                    if (!hf)
33368
0
                        goto fail;
33369
                    /* it is considered as defined at the top level
33370
                       (needed for annex B.3.3.4 and B.3.3.5
33371
                       checks) */
33372
3
                    hf->scope_level = 0; 
33373
3
                    hf->force_init = ((s->cur_func->js_mode & JS_MODE_STRICT) != 0);
33374
                    /* store directly into global var, bypass lexical scope */
33375
3
                    emit_op(s, OP_dup);
33376
3
                    emit_op(s, OP_scope_put_var);
33377
3
                    emit_atom(s, func_name);
33378
3
                    emit_u16(s, 0);
33379
3
                } else {
33380
                    /* do not call define_var to bypass lexical scope check */
33381
0
                    func_idx = find_var(ctx, s->cur_func, func_name);
33382
0
                    if (func_idx < 0) {
33383
0
                        func_idx = add_var(ctx, s->cur_func, func_name);
33384
0
                        if (func_idx < 0)
33385
0
                            goto fail;
33386
0
                    }
33387
                    /* store directly into local var, bypass lexical catch scope */
33388
0
                    emit_op(s, OP_dup);
33389
0
                    emit_op(s, OP_scope_put_var);
33390
0
                    emit_atom(s, func_name);
33391
0
                    emit_u16(s, 0);
33392
0
                }
33393
3
            }
33394
476
            if (lexical_func_idx >= 0) {
33395
                /* lexical variable will be initialized upon entering scope */
33396
476
                s->cur_func->vars[lexical_func_idx].func_pool_idx = idx;
33397
476
                emit_op(s, OP_drop);
33398
476
            } else {
33399
                /* store function object into its lexical name */
33400
                /* XXX: could use OP_put_loc directly */
33401
0
                emit_op(s, OP_scope_put_var_init);
33402
0
                emit_atom(s, func_name);
33403
0
                emit_u16(s, s->cur_func->scope_level);
33404
0
            }
33405
11.2k
        } else {
33406
11.2k
            if (!s->cur_func->is_global_var) {
33407
3.75k
                int var_idx = define_var(s, s->cur_func, func_name, JS_VAR_DEF_VAR);
33408
33409
3.75k
                if (var_idx < 0)
33410
0
                    goto fail;
33411
                /* the variable will be assigned at the top of the function */
33412
3.75k
                if (var_idx & ARGUMENT_VAR_OFFSET) {
33413
154
                    s->cur_func->args[var_idx - ARGUMENT_VAR_OFFSET].func_pool_idx = idx;
33414
3.59k
                } else {
33415
3.59k
                    s->cur_func->vars[var_idx].func_pool_idx = idx;
33416
3.59k
                }
33417
7.53k
            } else {
33418
7.53k
                JSAtom func_var_name;
33419
7.53k
                JSGlobalVar *hf;
33420
7.53k
                if (func_name == JS_ATOM_NULL)
33421
0
                    func_var_name = JS_ATOM__default_; /* export default */
33422
7.53k
                else
33423
7.53k
                    func_var_name = func_name;
33424
                /* the variable will be assigned at the top of the function */
33425
7.53k
                hf = add_global_var(ctx, s->cur_func, func_var_name);
33426
7.53k
                if (!hf)
33427
0
                    goto fail;
33428
7.53k
                hf->cpool_idx = idx;
33429
7.53k
                if (export_flag != JS_PARSE_EXPORT_NONE) {
33430
0
                    if (!add_export_entry(s, s->cur_func->module, func_var_name,
33431
0
                                          export_flag == JS_PARSE_EXPORT_NAMED ? func_var_name : JS_ATOM_default, JS_EXPORT_TYPE_LOCAL))
33432
0
                        goto fail;
33433
0
                }
33434
7.53k
            }
33435
11.2k
        }
33436
12.5k
    }
33437
12.5k
    return 0;
33438
10
 fail:
33439
10
    s->cur_func = fd->parent;
33440
10
    js_free_function_def(ctx, fd);
33441
10
    if (pfd)
33442
0
        *pfd = NULL;
33443
10
    return -1;
33444
12.5k
}
33445
33446
static __exception int js_parse_function_decl(JSParseState *s,
33447
                                              JSParseFunctionEnum func_type,
33448
                                              JSFunctionKindEnum func_kind,
33449
                                              JSAtom func_name,
33450
                                              const uint8_t *ptr,
33451
                                              int function_line_num)
33452
12.3k
{
33453
12.3k
    return js_parse_function_decl2(s, func_type, func_kind, func_name, ptr,
33454
12.3k
                                   function_line_num, JS_PARSE_EXPORT_NONE,
33455
12.3k
                                   NULL);
33456
12.3k
}
33457
33458
static __exception int js_parse_program(JSParseState *s)
33459
41.0k
{
33460
41.0k
    JSFunctionDef *fd = s->cur_func;
33461
41.0k
    int idx;
33462
33463
41.0k
    if (next_token(s))
33464
0
        return -1;
33465
33466
41.0k
    if (js_parse_directives(s))
33467
0
        return -1;
33468
33469
41.0k
    fd->is_global_var = (fd->eval_type == JS_EVAL_TYPE_GLOBAL) ||
33470
41.0k
        (fd->eval_type == JS_EVAL_TYPE_MODULE) ||
33471
41.0k
        !(fd->js_mode & JS_MODE_STRICT);
33472
33473
41.0k
    if (!s->is_module) {
33474
        /* hidden variable for the return value */
33475
41.0k
        fd->eval_ret_idx = idx = add_var(s->ctx, fd, JS_ATOM__ret_);
33476
41.0k
        if (idx < 0)
33477
0
            return -1;
33478
41.0k
    }
33479
33480
126k
    while (s->token.val != TOK_EOF) {
33481
85.0k
        if (js_parse_source_element(s))
33482
22
            return -1;
33483
85.0k
    }
33484
33485
41.0k
    if (!s->is_module) {
33486
        /* return the value of the hidden variable eval_ret_idx  */
33487
41.0k
        emit_op(s, OP_get_loc);
33488
41.0k
        emit_u16(s, fd->eval_ret_idx);
33489
33490
41.0k
        emit_op(s, OP_return);
33491
41.0k
    } else {
33492
4
        emit_op(s, OP_return_undef);
33493
4
    }
33494
33495
41.0k
    return 0;
33496
41.0k
}
33497
33498
static void js_parse_init(JSContext *ctx, JSParseState *s,
33499
                          const char *input, size_t input_len,
33500
                          const char *filename)
33501
41.0k
{
33502
41.0k
    memset(s, 0, sizeof(*s));
33503
41.0k
    s->ctx = ctx;
33504
41.0k
    s->filename = filename;
33505
41.0k
    s->line_num = 1;
33506
41.0k
    s->buf_ptr = (const uint8_t *)input;
33507
41.0k
    s->buf_end = s->buf_ptr + input_len;
33508
41.0k
    s->token.val = ' ';
33509
41.0k
    s->token.line_num = 1;
33510
41.0k
}
33511
33512
static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,
33513
                                       JSValueConst this_obj,
33514
                                       JSVarRef **var_refs, JSStackFrame *sf)
33515
41.0k
{
33516
41.0k
    JSValue ret_val;
33517
41.0k
    uint32_t tag;
33518
33519
41.0k
    tag = JS_VALUE_GET_TAG(fun_obj);
33520
41.0k
    if (tag == JS_TAG_FUNCTION_BYTECODE) {
33521
41.0k
        fun_obj = js_closure(ctx, fun_obj, var_refs, sf);
33522
41.0k
        ret_val = JS_CallFree(ctx, fun_obj, this_obj, 0, NULL);
33523
41.0k
    } else if (tag == JS_TAG_MODULE) {
33524
2
        JSModuleDef *m;
33525
2
        m = JS_VALUE_GET_PTR(fun_obj);
33526
        /* the module refcount should be >= 2 */
33527
2
        JS_FreeValue(ctx, fun_obj);
33528
2
        if (js_create_module_function(ctx, m) < 0)
33529
0
            goto fail;
33530
2
        if (js_link_module(ctx, m) < 0)
33531
0
            goto fail;
33532
2
        ret_val = js_evaluate_module(ctx, m);
33533
2
        if (JS_IsException(ret_val)) {
33534
2
        fail:
33535
2
            js_free_modules(ctx, JS_FREE_MODULE_NOT_EVALUATED);
33536
2
            return JS_EXCEPTION;
33537
2
        }
33538
2
    } else {
33539
0
        JS_FreeValue(ctx, fun_obj);
33540
0
        ret_val = JS_ThrowTypeError(ctx, "bytecode function expected");
33541
0
    }
33542
41.0k
    return ret_val;
33543
41.0k
}
33544
33545
JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj)
33546
2
{
33547
2
    return JS_EvalFunctionInternal(ctx, fun_obj, ctx->global_obj, NULL, NULL);
33548
2
}
33549
33550
static void skip_shebang(JSParseState *s)
33551
41.0k
{
33552
41.0k
    const uint8_t *p = s->buf_ptr;
33553
41.0k
    int c;
33554
33555
41.0k
    if (p[0] == '#' && p[1] == '!') {
33556
0
        p += 2;
33557
0
        while (p < s->buf_end) {
33558
0
            if (*p == '\n' || *p == '\r') {
33559
0
                break;
33560
0
            } else if (*p >= 0x80) {
33561
0
                c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
33562
0
                if (c == CP_LS || c == CP_PS) {
33563
0
                    break;
33564
0
                } else if (c == -1) {
33565
0
                    p++; /* skip invalid UTF-8 */
33566
0
                }
33567
0
            } else {
33568
0
                p++;
33569
0
            }
33570
0
        }
33571
0
        s->buf_ptr = p;
33572
0
    }
33573
41.0k
}
33574
33575
/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
33576
static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
33577
                                 const char *input, size_t input_len,
33578
                                 const char *filename, int flags, int scope_idx)
33579
41.0k
{
33580
41.0k
    JSParseState s1, *s = &s1;
33581
41.0k
    int err, js_mode, eval_type;
33582
41.0k
    JSValue fun_obj, ret_val;
33583
41.0k
    JSStackFrame *sf;
33584
41.0k
    JSVarRef **var_refs;
33585
41.0k
    JSFunctionBytecode *b;
33586
41.0k
    JSFunctionDef *fd;
33587
41.0k
    JSModuleDef *m;
33588
33589
41.0k
    js_parse_init(ctx, s, input, input_len, filename);
33590
41.0k
    skip_shebang(s);
33591
33592
41.0k
    eval_type = flags & JS_EVAL_TYPE_MASK;
33593
41.0k
    m = NULL;
33594
41.0k
    if (eval_type == JS_EVAL_TYPE_DIRECT) {
33595
40.9k
        JSObject *p;
33596
40.9k
        sf = ctx->rt->current_stack_frame;
33597
40.9k
        assert(sf != NULL);
33598
40.9k
        assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT);
33599
40.9k
        p = JS_VALUE_GET_OBJ(sf->cur_func);
33600
40.9k
        assert(js_class_has_bytecode(p->class_id));
33601
40.9k
        b = p->u.func.function_bytecode;
33602
40.9k
        var_refs = p->u.func.var_refs;
33603
40.9k
        js_mode = b->js_mode;
33604
40.9k
    } else {
33605
57
        sf = NULL;
33606
57
        b = NULL;
33607
57
        var_refs = NULL;
33608
57
        js_mode = 0;
33609
57
        if (flags & JS_EVAL_FLAG_STRICT)
33610
0
            js_mode |= JS_MODE_STRICT;
33611
57
        if (flags & JS_EVAL_FLAG_STRIP)
33612
0
            js_mode |= JS_MODE_STRIP;
33613
57
        if (eval_type == JS_EVAL_TYPE_MODULE) {
33614
10
            JSAtom module_name = JS_NewAtom(ctx, filename);
33615
10
            if (module_name == JS_ATOM_NULL)
33616
0
                return JS_EXCEPTION;
33617
10
            m = js_new_module_def(ctx, module_name);
33618
10
            if (!m)
33619
0
                return JS_EXCEPTION;
33620
10
            js_mode |= JS_MODE_STRICT;
33621
10
        }
33622
57
    }
33623
41.0k
    fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename, 1);
33624
41.0k
    if (!fd)
33625
0
        goto fail1;
33626
41.0k
    s->cur_func = fd;
33627
41.0k
    fd->eval_type = eval_type;
33628
41.0k
    fd->has_this_binding = (eval_type != JS_EVAL_TYPE_DIRECT);
33629
41.0k
    fd->backtrace_barrier = ((flags & JS_EVAL_FLAG_BACKTRACE_BARRIER) != 0);
33630
41.0k
    if (eval_type == JS_EVAL_TYPE_DIRECT) {
33631
40.9k
        fd->new_target_allowed = b->new_target_allowed;
33632
40.9k
        fd->super_call_allowed = b->super_call_allowed;
33633
40.9k
        fd->super_allowed = b->super_allowed;
33634
40.9k
        fd->arguments_allowed = b->arguments_allowed;
33635
40.9k
    } else {
33636
57
        fd->new_target_allowed = FALSE;
33637
57
        fd->super_call_allowed = FALSE;
33638
57
        fd->super_allowed = FALSE;
33639
57
        fd->arguments_allowed = TRUE;
33640
57
    }
33641
41.0k
    fd->js_mode = js_mode;
33642
41.0k
    fd->func_name = JS_DupAtom(ctx, JS_ATOM__eval_);
33643
41.0k
    if (b) {
33644
40.9k
        if (add_closure_variables(ctx, fd, b, scope_idx))
33645
1
            goto fail;
33646
40.9k
    }
33647
41.0k
    fd->module = m;
33648
41.0k
    s->is_module = (m != NULL);
33649
41.0k
    s->allow_html_comments = !s->is_module;
33650
33651
41.0k
    push_scope(s); /* body scope */
33652
41.0k
    fd->body_scope = fd->scope_level;
33653
    
33654
41.0k
    err = js_parse_program(s);
33655
41.0k
    if (err) {
33656
23
    fail:
33657
23
        free_token(s, &s->token);
33658
23
        js_free_function_def(ctx, fd);
33659
23
        goto fail1;
33660
22
    }
33661
33662
    /* create the function object and all the enclosed functions */
33663
41.0k
    fun_obj = js_create_function(ctx, fd);
33664
41.0k
    if (JS_IsException(fun_obj))
33665
2
        goto fail1;
33666
    /* Could add a flag to avoid resolution if necessary */
33667
41.0k
    if (m) {
33668
3
        m->func_obj = fun_obj;
33669
3
        if (js_resolve_module(ctx, m) < 0)
33670
0
            goto fail1;
33671
3
        fun_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
33672
3
    }
33673
41.0k
    if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {
33674
3
        ret_val = fun_obj;
33675
41.0k
    } else {
33676
41.0k
        ret_val = JS_EvalFunctionInternal(ctx, fun_obj, this_obj, var_refs, sf);
33677
41.0k
    }
33678
41.0k
    return ret_val;
33679
25
 fail1:
33680
    /* XXX: should free all the unresolved dependencies */
33681
25
    if (m)
33682
7
        js_free_module_def(ctx, m);
33683
25
    return JS_EXCEPTION;
33684
41.0k
}
33685
33686
/* the indirection is needed to make 'eval' optional */
33687
static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
33688
                               const char *input, size_t input_len,
33689
                               const char *filename, int flags, int scope_idx)
33690
41.0k
{
33691
41.0k
    if (unlikely(!ctx->eval_internal)) {
33692
0
        return JS_ThrowTypeError(ctx, "eval is not supported");
33693
0
    }
33694
41.0k
    return ctx->eval_internal(ctx, this_obj, input, input_len, filename,
33695
41.0k
                              flags, scope_idx);
33696
41.0k
}
33697
33698
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
33699
                             JSValueConst val, int flags, int scope_idx)
33700
40.9k
{
33701
40.9k
    JSValue ret;
33702
40.9k
    const char *str;
33703
40.9k
    size_t len;
33704
33705
40.9k
    if (!JS_IsString(val))
33706
0
        return JS_DupValue(ctx, val);
33707
40.9k
    str = JS_ToCStringLen(ctx, &len, val);
33708
40.9k
    if (!str)
33709
0
        return JS_EXCEPTION;
33710
40.9k
    ret = JS_EvalInternal(ctx, this_obj, str, len, "<input>", flags, scope_idx);
33711
40.9k
    JS_FreeCString(ctx, str);
33712
40.9k
    return ret;
33713
33714
40.9k
}
33715
33716
JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
33717
                    const char *input, size_t input_len,
33718
                    const char *filename, int eval_flags)
33719
57
{
33720
57
    int eval_type = eval_flags & JS_EVAL_TYPE_MASK;
33721
57
    JSValue ret;
33722
33723
57
    assert(eval_type == JS_EVAL_TYPE_GLOBAL ||
33724
57
           eval_type == JS_EVAL_TYPE_MODULE);
33725
57
    ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename,
33726
57
                          eval_flags, -1);
33727
57
    return ret;
33728
57
}
33729
33730
JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
33731
                const char *filename, int eval_flags)
33732
57
{
33733
57
    return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename,
33734
57
                       eval_flags);
33735
57
}
33736
33737
int JS_ResolveModule(JSContext *ctx, JSValueConst obj)
33738
2
{
33739
2
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
33740
2
        JSModuleDef *m = JS_VALUE_GET_PTR(obj);
33741
2
        if (js_resolve_module(ctx, m) < 0) {
33742
0
            js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
33743
0
            return -1;
33744
0
        }
33745
2
    }
33746
2
    return 0;
33747
2
}
33748
33749
/*******************************************************************/
33750
/* object list */
33751
33752
typedef struct {
33753
    JSObject *obj;
33754
    uint32_t hash_next; /* -1 if no next entry */
33755
} JSObjectListEntry;
33756
33757
/* XXX: reuse it to optimize weak references */
33758
typedef struct {
33759
    JSObjectListEntry *object_tab;
33760
    int object_count;
33761
    int object_size;
33762
    uint32_t *hash_table;
33763
    uint32_t hash_size;
33764
} JSObjectList;
33765
33766
static void js_object_list_init(JSObjectList *s)
33767
3
{
33768
3
    memset(s, 0, sizeof(*s));
33769
3
}
33770
33771
static uint32_t js_object_list_get_hash(JSObject *p, uint32_t hash_size)
33772
0
{
33773
0
    return ((uintptr_t)p * 3163) & (hash_size - 1);
33774
0
}
33775
33776
static int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s,
33777
                                 uint32_t new_hash_size)
33778
0
{
33779
0
    JSObjectListEntry *e;
33780
0
    uint32_t i, h, *new_hash_table;
33781
33782
0
    new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size);
33783
0
    if (!new_hash_table)
33784
0
        return -1;
33785
0
    js_free(ctx, s->hash_table);
33786
0
    s->hash_table = new_hash_table;
33787
0
    s->hash_size = new_hash_size;
33788
    
33789
0
    for(i = 0; i < s->hash_size; i++) {
33790
0
        s->hash_table[i] = -1;
33791
0
    }
33792
0
    for(i = 0; i < s->object_count; i++) {
33793
0
        e = &s->object_tab[i];
33794
0
        h = js_object_list_get_hash(e->obj, s->hash_size); 
33795
0
        e->hash_next = s->hash_table[h];
33796
0
        s->hash_table[h] = i;
33797
0
    }
33798
0
    return 0;
33799
0
}
33800
33801
/* the reference count of 'obj' is not modified. Return 0 if OK, -1 if
33802
   memory error */
33803
static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj)
33804
0
{
33805
0
    JSObjectListEntry *e;
33806
0
    uint32_t h, new_hash_size;
33807
    
33808
0
    if (js_resize_array(ctx, (void *)&s->object_tab,
33809
0
                        sizeof(s->object_tab[0]),
33810
0
                        &s->object_size, s->object_count + 1))
33811
0
        return -1;
33812
0
    if (unlikely((s->object_count + 1) >= s->hash_size)) {
33813
0
        new_hash_size = max_uint32(s->hash_size, 4);
33814
0
        while (new_hash_size <= s->object_count)
33815
0
            new_hash_size *= 2;
33816
0
        if (js_object_list_resize_hash(ctx, s, new_hash_size))
33817
0
            return -1;
33818
0
    }
33819
0
    e = &s->object_tab[s->object_count++];
33820
0
    h = js_object_list_get_hash(obj, s->hash_size); 
33821
0
    e->obj = obj;
33822
0
    e->hash_next = s->hash_table[h];
33823
0
    s->hash_table[h] = s->object_count - 1;
33824
0
    return 0;
33825
0
}
33826
33827
/* return -1 if not present or the object index */
33828
static int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj)
33829
0
{
33830
0
    JSObjectListEntry *e;
33831
0
    uint32_t h, p;
33832
33833
    /* must test empty size because there is no hash table */
33834
0
    if (s->object_count == 0)
33835
0
        return -1;
33836
0
    h = js_object_list_get_hash(obj, s->hash_size); 
33837
0
    p = s->hash_table[h];
33838
0
    while (p != -1) {
33839
0
        e = &s->object_tab[p];
33840
0
        if (e->obj == obj)
33841
0
            return p;
33842
0
        p = e->hash_next;
33843
0
    }
33844
0
    return -1;
33845
0
}
33846
33847
static void js_object_list_end(JSContext *ctx, JSObjectList *s)
33848
3
{
33849
3
    js_free(ctx, s->object_tab);
33850
3
    js_free(ctx, s->hash_table);
33851
3
}
33852
33853
/*******************************************************************/
33854
/* binary object writer & reader */
33855
33856
typedef enum BCTagEnum {
33857
    BC_TAG_NULL = 1,
33858
    BC_TAG_UNDEFINED,
33859
    BC_TAG_BOOL_FALSE,
33860
    BC_TAG_BOOL_TRUE,
33861
    BC_TAG_INT32,
33862
    BC_TAG_FLOAT64,
33863
    BC_TAG_STRING,
33864
    BC_TAG_OBJECT,
33865
    BC_TAG_ARRAY,
33866
    BC_TAG_BIG_INT,
33867
    BC_TAG_BIG_FLOAT,
33868
    BC_TAG_BIG_DECIMAL,
33869
    BC_TAG_TEMPLATE_OBJECT,
33870
    BC_TAG_FUNCTION_BYTECODE,
33871
    BC_TAG_MODULE,
33872
    BC_TAG_TYPED_ARRAY,
33873
    BC_TAG_ARRAY_BUFFER,
33874
    BC_TAG_SHARED_ARRAY_BUFFER,
33875
    BC_TAG_DATE,
33876
    BC_TAG_OBJECT_VALUE,
33877
    BC_TAG_OBJECT_REFERENCE,
33878
} BCTagEnum;
33879
33880
#ifdef CONFIG_BIGNUM
33881
4
#define BC_BASE_VERSION 2
33882
#else
33883
#define BC_BASE_VERSION 1
33884
#endif
33885
0
#define BC_BE_VERSION 0x40
33886
#ifdef WORDS_BIGENDIAN
33887
#define BC_VERSION (BC_BASE_VERSION | BC_BE_VERSION)
33888
#else
33889
4
#define BC_VERSION BC_BASE_VERSION
33890
#endif
33891
33892
typedef struct BCWriterState {
33893
    JSContext *ctx;
33894
    DynBuf dbuf;
33895
    BOOL byte_swap : 8;
33896
    BOOL allow_bytecode : 8;
33897
    BOOL allow_sab : 8;
33898
    BOOL allow_reference : 8;
33899
    uint32_t first_atom;
33900
    uint32_t *atom_to_idx;
33901
    int atom_to_idx_size;
33902
    JSAtom *idx_to_atom;
33903
    int idx_to_atom_count;
33904
    int idx_to_atom_size;
33905
    uint8_t **sab_tab;
33906
    int sab_tab_len;
33907
    int sab_tab_size;
33908
    /* list of referenced objects (used if allow_reference = TRUE) */
33909
    JSObjectList object_list;
33910
} BCWriterState;
33911
33912
#ifdef DUMP_READ_OBJECT
33913
static const char * const bc_tag_str[] = {
33914
    "invalid",
33915
    "null",
33916
    "undefined",
33917
    "false",
33918
    "true",
33919
    "int32",
33920
    "float64",
33921
    "string",
33922
    "object",
33923
    "array",
33924
    "bigint",
33925
    "bigfloat",
33926
    "bigdecimal",
33927
    "template",
33928
    "function",
33929
    "module",
33930
    "TypedArray",
33931
    "ArrayBuffer",
33932
    "SharedArrayBuffer",
33933
    "Date",
33934
    "ObjectValue",
33935
    "ObjectReference",
33936
};
33937
#endif
33938
33939
static void bc_put_u8(BCWriterState *s, uint8_t v)
33940
840
{
33941
840
    dbuf_putc(&s->dbuf, v);
33942
840
}
33943
33944
static void bc_put_u16(BCWriterState *s, uint16_t v)
33945
22
{
33946
22
    if (s->byte_swap)
33947
0
        v = bswap16(v);
33948
22
    dbuf_put_u16(&s->dbuf, v);
33949
22
}
33950
33951
static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
33952
0
{
33953
0
    if (s->byte_swap)
33954
0
        v = bswap32(v);
33955
0
    dbuf_put_u32(&s->dbuf, v);
33956
0
}
33957
33958
static void bc_put_u64(BCWriterState *s, uint64_t v)
33959
10
{
33960
10
    if (s->byte_swap)
33961
0
        v = bswap64(v);
33962
10
    dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v));
33963
10
}
33964
33965
static void bc_put_leb128(BCWriterState *s, uint32_t v)
33966
1.86k
{
33967
1.86k
    dbuf_put_leb128(&s->dbuf, v);
33968
1.86k
}
33969
33970
static void bc_put_sleb128(BCWriterState *s, int32_t v)
33971
22
{
33972
22
    dbuf_put_sleb128(&s->dbuf, v);
33973
22
}
33974
33975
static void bc_set_flags(uint32_t *pflags, int *pidx, uint32_t val, int n)
33976
3.92k
{
33977
3.92k
    *pflags = *pflags | (val << *pidx);
33978
3.92k
    *pidx += n;
33979
3.92k
}
33980
33981
static int bc_atom_to_idx(BCWriterState *s, uint32_t *pres, JSAtom atom)
33982
89.8k
{
33983
89.8k
    uint32_t v;
33984
33985
89.8k
    if (atom < s->first_atom || __JS_AtomIsTaggedInt(atom)) {
33986
36
        *pres = atom;
33987
36
        return 0;
33988
36
    }
33989
89.8k
    atom -= s->first_atom;
33990
89.8k
    if (atom < s->atom_to_idx_size && s->atom_to_idx[atom] != 0) {
33991
89.7k
        *pres = s->atom_to_idx[atom];
33992
89.7k
        return 0;
33993
89.7k
    }
33994
126
    if (atom >= s->atom_to_idx_size) {
33995
12
        int old_size, i;
33996
12
        old_size = s->atom_to_idx_size;
33997
12
        if (js_resize_array(s->ctx, (void **)&s->atom_to_idx,
33998
12
                            sizeof(s->atom_to_idx[0]), &s->atom_to_idx_size,
33999
12
                            atom + 1))
34000
6
            return -1;
34001
        /* XXX: could add a specific js_resize_array() function to do it */
34002
1.17k
        for(i = old_size; i < s->atom_to_idx_size; i++)
34003
1.17k
            s->atom_to_idx[i] = 0;
34004
6
    }
34005
120
    if (js_resize_array(s->ctx, (void **)&s->idx_to_atom,
34006
120
                        sizeof(s->idx_to_atom[0]),
34007
120
                        &s->idx_to_atom_size, s->idx_to_atom_count + 1))
34008
0
        goto fail;
34009
34010
120
    v = s->idx_to_atom_count++;
34011
120
    s->idx_to_atom[v] = atom + s->first_atom;
34012
120
    v += s->first_atom;
34013
120
    s->atom_to_idx[atom] = v;
34014
120
    *pres = v;
34015
120
    return 0;
34016
0
 fail:
34017
0
    *pres = 0;
34018
0
    return -1;
34019
120
}
34020
34021
static int bc_put_atom(BCWriterState *s, JSAtom atom)
34022
791
{
34023
791
    uint32_t v;
34024
34025
791
    if (__JS_AtomIsTaggedInt(atom)) {
34026
0
        v = (__JS_AtomToUInt32(atom) << 1) | 1;
34027
791
    } else {
34028
791
        if (bc_atom_to_idx(s, &v, atom))
34029
5
            return -1;
34030
786
        v <<= 1;
34031
786
    }
34032
786
    bc_put_leb128(s, v);
34033
786
    return 0;
34034
791
}
34035
34036
static void bc_byte_swap(uint8_t *bc_buf, int bc_len)
34037
0
{
34038
0
    int pos, len, op, fmt;
34039
34040
0
    pos = 0;
34041
0
    while (pos < bc_len) {
34042
0
        op = bc_buf[pos];
34043
0
        len = short_opcode_info(op).size;
34044
0
        fmt = short_opcode_info(op).fmt;
34045
0
        switch(fmt) {
34046
0
        case OP_FMT_u16:
34047
0
        case OP_FMT_i16:
34048
0
        case OP_FMT_label16:
34049
0
        case OP_FMT_npop:
34050
0
        case OP_FMT_loc:
34051
0
        case OP_FMT_arg:
34052
0
        case OP_FMT_var_ref:
34053
0
            put_u16(bc_buf + pos + 1,
34054
0
                    bswap16(get_u16(bc_buf + pos + 1)));
34055
0
            break;
34056
0
        case OP_FMT_i32:
34057
0
        case OP_FMT_u32:
34058
0
        case OP_FMT_const:
34059
0
        case OP_FMT_label:
34060
0
        case OP_FMT_atom:
34061
0
        case OP_FMT_atom_u8:
34062
0
            put_u32(bc_buf + pos + 1,
34063
0
                    bswap32(get_u32(bc_buf + pos + 1)));
34064
0
            break;
34065
0
        case OP_FMT_atom_u16:
34066
0
        case OP_FMT_label_u16:
34067
0
            put_u32(bc_buf + pos + 1,
34068
0
                    bswap32(get_u32(bc_buf + pos + 1)));
34069
0
            put_u16(bc_buf + pos + 1 + 4,
34070
0
                    bswap16(get_u16(bc_buf + pos + 1 + 4)));
34071
0
            break;
34072
0
        case OP_FMT_atom_label_u8:
34073
0
        case OP_FMT_atom_label_u16:
34074
0
            put_u32(bc_buf + pos + 1,
34075
0
                    bswap32(get_u32(bc_buf + pos + 1)));
34076
0
            put_u32(bc_buf + pos + 1 + 4,
34077
0
                    bswap32(get_u32(bc_buf + pos + 1 + 4)));
34078
0
            if (fmt == OP_FMT_atom_label_u16) {
34079
0
                put_u16(bc_buf + pos + 1 + 4 + 4,
34080
0
                        bswap16(get_u16(bc_buf + pos + 1 + 4 + 4)));
34081
0
            }
34082
0
            break;
34083
0
        case OP_FMT_npop_u16:
34084
0
            put_u16(bc_buf + pos + 1,
34085
0
                    bswap16(get_u16(bc_buf + pos + 1)));
34086
0
            put_u16(bc_buf + pos + 1 + 2,
34087
0
                    bswap16(get_u16(bc_buf + pos + 1 + 2)));
34088
0
            break;
34089
0
        default:
34090
0
            break;
34091
0
        }
34092
0
        pos += len;
34093
0
    }
34094
0
}
34095
34096
static int JS_WriteFunctionBytecode(BCWriterState *s,
34097
                                    const uint8_t *bc_buf1, int bc_len)
34098
14
{
34099
14
    int pos, len, op;
34100
14
    JSAtom atom;
34101
14
    uint8_t *bc_buf;
34102
14
    uint32_t val;
34103
34104
14
    bc_buf = js_malloc(s->ctx, bc_len);
34105
14
    if (!bc_buf)
34106
0
        return -1;
34107
14
    memcpy(bc_buf, bc_buf1, bc_len);
34108
34109
14
    pos = 0;
34110
252k
    while (pos < bc_len) {
34111
252k
        op = bc_buf[pos];
34112
252k
        len = short_opcode_info(op).size;
34113
252k
        switch(short_opcode_info(op).fmt) {
34114
66.7k
        case OP_FMT_atom:
34115
66.7k
        case OP_FMT_atom_u8:
34116
89.1k
        case OP_FMT_atom_u16:
34117
89.1k
        case OP_FMT_atom_label_u8:
34118
89.1k
        case OP_FMT_atom_label_u16:
34119
89.1k
            atom = get_u32(bc_buf + pos + 1);
34120
89.1k
            if (bc_atom_to_idx(s, &val, atom))
34121
1
                goto fail;
34122
89.1k
            put_u32(bc_buf + pos + 1, val);
34123
89.1k
            break;
34124
163k
        default:
34125
163k
            break;
34126
252k
        }
34127
252k
        pos += len;
34128
252k
    }
34129
34130
13
    if (s->byte_swap)
34131
0
        bc_byte_swap(bc_buf, bc_len);
34132
34133
13
    dbuf_put(&s->dbuf, bc_buf, bc_len);
34134
34135
13
    js_free(s->ctx, bc_buf);
34136
13
    return 0;
34137
1
 fail:
34138
1
    js_free(s->ctx, bc_buf);
34139
1
    return -1;
34140
14
}
34141
34142
static void JS_WriteString(BCWriterState *s, JSString *p)
34143
113
{
34144
113
    int i;
34145
113
    bc_put_leb128(s, ((uint32_t)p->len << 1) | p->is_wide_char);
34146
113
    if (p->is_wide_char) {
34147
9
        for(i = 0; i < p->len; i++)
34148
8
            bc_put_u16(s, p->u.str16[i]);
34149
112
    } else {
34150
112
        dbuf_put(&s->dbuf, p->u.str8, p->len);
34151
112
    }
34152
113
}
34153
34154
#ifdef CONFIG_BIGNUM
34155
static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj)
34156
22
{
34157
22
    uint32_t tag, tag1;
34158
22
    int64_t e;
34159
22
    JSBigFloat *bf = JS_VALUE_GET_PTR(obj);
34160
22
    bf_t *a = &bf->num;
34161
22
    size_t len, i, n1, j;
34162
22
    limb_t v;
34163
34164
22
    tag = JS_VALUE_GET_TAG(obj);
34165
22
    switch(tag) {
34166
22
    case JS_TAG_BIG_INT:
34167
22
        tag1 = BC_TAG_BIG_INT;
34168
22
        break;
34169
0
    case JS_TAG_BIG_FLOAT:
34170
0
        tag1 = BC_TAG_BIG_FLOAT;
34171
0
        break;
34172
0
    case JS_TAG_BIG_DECIMAL:
34173
0
        tag1 = BC_TAG_BIG_DECIMAL;
34174
0
        break;
34175
0
    default:
34176
0
        abort();
34177
22
    }
34178
22
    bc_put_u8(s, tag1);
34179
34180
    /* sign + exponent */
34181
22
    if (a->expn == BF_EXP_ZERO)
34182
0
        e = 0;
34183
22
    else if (a->expn == BF_EXP_INF)
34184
0
        e = 1;
34185
22
    else if (a->expn == BF_EXP_NAN)
34186
0
        e = 2;
34187
22
    else if (a->expn >= 0)
34188
22
        e = a->expn + 3;
34189
0
    else
34190
0
        e = a->expn;
34191
22
    e = (e << 1) | a->sign;
34192
22
    if (e < INT32_MIN || e > INT32_MAX) {
34193
0
        JS_ThrowInternalError(s->ctx, "bignum exponent is too large");
34194
0
        return -1;
34195
0
    }
34196
22
    bc_put_sleb128(s, e);
34197
34198
    /* mantissa */
34199
22
    if (a->len != 0) {
34200
22
        if (tag != JS_TAG_BIG_DECIMAL) {
34201
22
            i = 0;
34202
22
            while (i < a->len && a->tab[i] == 0)
34203
0
                i++;
34204
22
            assert(i < a->len);
34205
22
            v = a->tab[i];
34206
22
            n1 = sizeof(limb_t);
34207
144
            while ((v & 0xff) == 0) {
34208
122
                n1--;
34209
122
                v >>= 8;
34210
122
            }
34211
22
            i++;
34212
22
            len = (a->len - i) * sizeof(limb_t) + n1;
34213
22
            if (len > INT32_MAX) {
34214
0
                JS_ThrowInternalError(s->ctx, "bignum is too large");
34215
0
                return -1;
34216
0
            }
34217
22
            bc_put_leb128(s, len);
34218
            /* always saved in byte based little endian representation */
34219
76
            for(j = 0; j < n1; j++) {
34220
54
                dbuf_putc(&s->dbuf, v >> (j * 8));
34221
54
            }
34222
22
            for(; i < a->len; i++) {
34223
0
                limb_t v = a->tab[i];
34224
#if LIMB_BITS == 32
34225
#ifdef WORDS_BIGENDIAN
34226
                v = bswap32(v);
34227
#endif
34228
                dbuf_put_u32(&s->dbuf, v);
34229
#else
34230
#ifdef WORDS_BIGENDIAN
34231
                v = bswap64(v);
34232
#endif
34233
0
                dbuf_put_u64(&s->dbuf, v);
34234
0
#endif
34235
0
            }
34236
22
        } else {
34237
0
            int bpos, d;
34238
0
            uint8_t v8;
34239
0
            size_t i0;
34240
            
34241
            /* little endian BCD */
34242
0
            i = 0;
34243
0
            while (i < a->len && a->tab[i] == 0)
34244
0
                i++;
34245
0
            assert(i < a->len);
34246
0
            len = a->len * LIMB_DIGITS;
34247
0
            v = a->tab[i];
34248
0
            j = 0;
34249
0
            while ((v % 10) == 0) {
34250
0
                j++;
34251
0
                v /= 10;
34252
0
            }
34253
0
            len -= j;
34254
0
            assert(len > 0);
34255
0
            if (len > INT32_MAX) {
34256
0
                JS_ThrowInternalError(s->ctx, "bignum is too large");
34257
0
                return -1;
34258
0
            }
34259
0
            bc_put_leb128(s, len);
34260
            
34261
0
            bpos = 0;
34262
0
            v8 = 0;
34263
0
            i0 = i;
34264
0
            for(; i < a->len; i++) {
34265
0
                if (i != i0) {
34266
0
                    v = a->tab[i];
34267
0
                    j = 0;
34268
0
                }
34269
0
                for(; j < LIMB_DIGITS; j++) {
34270
0
                    d = v % 10;
34271
0
                    v /= 10;
34272
0
                    if (bpos == 0) {
34273
0
                        v8 = d;
34274
0
                        bpos = 1;
34275
0
                    } else {
34276
0
                        dbuf_putc(&s->dbuf, v8 | (d << 4));
34277
0
                        bpos = 0;
34278
0
                    }
34279
0
                }
34280
0
            }
34281
            /* flush the last digit */
34282
0
            if (bpos) {
34283
0
                dbuf_putc(&s->dbuf, v8);
34284
0
            }
34285
0
        }
34286
22
    }
34287
22
    return 0;
34288
22
}
34289
#endif /* CONFIG_BIGNUM */
34290
34291
static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj);
34292
34293
static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
34294
14
{
34295
14
    JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj);
34296
14
    uint32_t flags;
34297
14
    int idx, i;
34298
    
34299
14
    bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE);
34300
14
    flags = idx = 0;
34301
14
    bc_set_flags(&flags, &idx, b->has_prototype, 1);
34302
14
    bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1);
34303
14
    bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1);
34304
14
    bc_set_flags(&flags, &idx, b->need_home_object, 1);
34305
14
    bc_set_flags(&flags, &idx, b->func_kind, 2);
34306
14
    bc_set_flags(&flags, &idx, b->new_target_allowed, 1);
34307
14
    bc_set_flags(&flags, &idx, b->super_call_allowed, 1);
34308
14
    bc_set_flags(&flags, &idx, b->super_allowed, 1);
34309
14
    bc_set_flags(&flags, &idx, b->arguments_allowed, 1);
34310
14
    bc_set_flags(&flags, &idx, b->has_debug, 1);
34311
14
    bc_set_flags(&flags, &idx, b->backtrace_barrier, 1);
34312
14
    assert(idx <= 16);
34313
14
    bc_put_u16(s, flags);
34314
14
    bc_put_u8(s, b->js_mode);
34315
14
    bc_put_atom(s, b->func_name);
34316
    
34317
14
    bc_put_leb128(s, b->arg_count);
34318
14
    bc_put_leb128(s, b->var_count);
34319
14
    bc_put_leb128(s, b->defined_arg_count);
34320
14
    bc_put_leb128(s, b->stack_size);
34321
14
    bc_put_leb128(s, b->closure_var_count);
34322
14
    bc_put_leb128(s, b->cpool_count);
34323
14
    bc_put_leb128(s, b->byte_code_len);
34324
14
    if (b->vardefs) {
34325
        /* XXX: this field is redundant */
34326
13
        bc_put_leb128(s, b->arg_count + b->var_count);
34327
45
        for(i = 0; i < b->arg_count + b->var_count; i++) {
34328
32
            JSVarDef *vd = &b->vardefs[i];
34329
32
            bc_put_atom(s, vd->var_name);
34330
32
            bc_put_leb128(s, vd->scope_level);
34331
32
            bc_put_leb128(s, vd->scope_next + 1);
34332
32
            flags = idx = 0;
34333
32
            bc_set_flags(&flags, &idx, vd->var_kind, 4);
34334
32
            bc_set_flags(&flags, &idx, vd->is_const, 1);
34335
32
            bc_set_flags(&flags, &idx, vd->is_lexical, 1);
34336
32
            bc_set_flags(&flags, &idx, vd->is_captured, 1);
34337
32
            assert(idx <= 8);
34338
32
            bc_put_u8(s, flags);
34339
32
        }
34340
13
    } else {
34341
1
        bc_put_leb128(s, 0);
34342
1
    }
34343
    
34344
743
    for(i = 0; i < b->closure_var_count; i++) {
34345
729
        JSClosureVar *cv = &b->closure_var[i];
34346
729
        bc_put_atom(s, cv->var_name);
34347
729
        bc_put_leb128(s, cv->var_idx);
34348
729
        flags = idx = 0;
34349
729
        bc_set_flags(&flags, &idx, cv->is_local, 1);
34350
729
        bc_set_flags(&flags, &idx, cv->is_arg, 1);
34351
729
        bc_set_flags(&flags, &idx, cv->is_const, 1);
34352
729
        bc_set_flags(&flags, &idx, cv->is_lexical, 1);
34353
729
        bc_set_flags(&flags, &idx, cv->var_kind, 4);
34354
729
        assert(idx <= 8);
34355
729
        bc_put_u8(s, flags);
34356
729
    }
34357
    
34358
14
    if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len))
34359
1
        goto fail;
34360
    
34361
13
    if (b->has_debug) {
34362
13
        bc_put_atom(s, b->debug.filename);
34363
13
        bc_put_leb128(s, b->debug.line_num);
34364
13
        bc_put_leb128(s, b->debug.pc2line_len);
34365
13
        dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len);
34366
13
    }
34367
    
34368
70
    for(i = 0; i < b->cpool_count; i++) {
34369
57
        if (JS_WriteObjectRec(s, b->cpool[i]))
34370
0
            goto fail;
34371
57
    }
34372
13
    return 0;
34373
1
 fail:
34374
1
    return -1;
34375
13
}
34376
34377
static int JS_WriteModule(BCWriterState *s, JSValueConst obj)
34378
3
{
34379
3
    JSModuleDef *m = JS_VALUE_GET_PTR(obj);
34380
3
    int i;
34381
    
34382
3
    bc_put_u8(s, BC_TAG_MODULE);
34383
3
    bc_put_atom(s, m->module_name);
34384
    
34385
3
    bc_put_leb128(s, m->req_module_entries_count);
34386
3
    for(i = 0; i < m->req_module_entries_count; i++) {
34387
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
34388
0
        bc_put_atom(s, rme->module_name);
34389
0
    }
34390
    
34391
3
    bc_put_leb128(s, m->export_entries_count);
34392
3
    for(i = 0; i < m->export_entries_count; i++) {
34393
0
        JSExportEntry *me = &m->export_entries[i];
34394
0
        bc_put_u8(s, me->export_type);
34395
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
34396
0
            bc_put_leb128(s, me->u.local.var_idx);
34397
0
        } else {
34398
0
            bc_put_leb128(s, me->u.req_module_idx);
34399
0
            bc_put_atom(s, me->local_name);
34400
0
        }
34401
0
        bc_put_atom(s, me->export_name);
34402
0
    }
34403
    
34404
3
    bc_put_leb128(s, m->star_export_entries_count);
34405
3
    for(i = 0; i < m->star_export_entries_count; i++) {
34406
0
        JSStarExportEntry *se = &m->star_export_entries[i];
34407
0
        bc_put_leb128(s, se->req_module_idx);
34408
0
    }
34409
    
34410
3
    bc_put_leb128(s, m->import_entries_count);
34411
3
    for(i = 0; i < m->import_entries_count; i++) {
34412
0
        JSImportEntry *mi = &m->import_entries[i];
34413
0
        bc_put_leb128(s, mi->var_idx);
34414
0
        bc_put_atom(s, mi->import_name);
34415
0
        bc_put_leb128(s, mi->req_module_idx);
34416
0
    }
34417
    
34418
3
    if (JS_WriteObjectRec(s, m->func_obj))
34419
1
        goto fail;
34420
2
    return 0;
34421
1
 fail:
34422
1
    return -1;
34423
3
}
34424
34425
static int JS_WriteArray(BCWriterState *s, JSValueConst obj)
34426
0
{
34427
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
34428
0
    uint32_t i, len;
34429
0
    JSValue val;
34430
0
    int ret;
34431
0
    BOOL is_template;
34432
    
34433
0
    if (s->allow_bytecode && !p->extensible) {
34434
        /* not extensible array: we consider it is a
34435
           template when we are saving bytecode */
34436
0
        bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT);
34437
0
        is_template = TRUE;
34438
0
    } else {
34439
0
        bc_put_u8(s, BC_TAG_ARRAY);
34440
0
        is_template = FALSE;
34441
0
    }
34442
0
    if (js_get_length32(s->ctx, &len, obj))
34443
0
        goto fail1;
34444
0
    bc_put_leb128(s, len);
34445
0
    for(i = 0; i < len; i++) {
34446
0
        val = JS_GetPropertyUint32(s->ctx, obj, i);
34447
0
        if (JS_IsException(val))
34448
0
            goto fail1;
34449
0
        ret = JS_WriteObjectRec(s, val);
34450
0
        JS_FreeValue(s->ctx, val);
34451
0
        if (ret)
34452
0
            goto fail1;
34453
0
    }
34454
0
    if (is_template) {
34455
0
        val = JS_GetProperty(s->ctx, obj, JS_ATOM_raw);
34456
0
        if (JS_IsException(val))
34457
0
            goto fail1;
34458
0
        ret = JS_WriteObjectRec(s, val);
34459
0
        JS_FreeValue(s->ctx, val);
34460
0
        if (ret)
34461
0
            goto fail1;
34462
0
    }
34463
0
    return 0;
34464
0
 fail1:
34465
0
    return -1;
34466
0
}
34467
34468
static int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj)
34469
0
{
34470
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
34471
0
    uint32_t i, prop_count;
34472
0
    JSShape *sh;
34473
0
    JSShapeProperty *pr;
34474
0
    int pass;
34475
0
    JSAtom atom;
34476
34477
0
    bc_put_u8(s, BC_TAG_OBJECT);
34478
0
    prop_count = 0;
34479
0
    sh = p->shape;
34480
0
    for(pass = 0; pass < 2; pass++) {
34481
0
        if (pass == 1)
34482
0
            bc_put_leb128(s, prop_count);
34483
0
        for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
34484
0
            atom = pr->atom;
34485
0
            if (atom != JS_ATOM_NULL &&
34486
0
                JS_AtomIsString(s->ctx, atom) &&
34487
0
                (pr->flags & JS_PROP_ENUMERABLE)) {
34488
0
                if (pr->flags & JS_PROP_TMASK) {
34489
0
                    JS_ThrowTypeError(s->ctx, "only value properties are supported");
34490
0
                    goto fail;
34491
0
                }
34492
0
                if (pass == 0) {
34493
0
                    prop_count++;
34494
0
                } else {
34495
0
                    bc_put_atom(s, atom);
34496
0
                    if (JS_WriteObjectRec(s, p->prop[i].u.value))
34497
0
                        goto fail;
34498
0
                }
34499
0
            }
34500
0
        }
34501
0
    }
34502
0
    return 0;
34503
0
 fail:
34504
0
    return -1;
34505
0
}
34506
34507
static int JS_WriteTypedArray(BCWriterState *s, JSValueConst obj)
34508
0
{
34509
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
34510
0
    JSTypedArray *ta = p->u.typed_array;
34511
34512
0
    bc_put_u8(s, BC_TAG_TYPED_ARRAY);
34513
0
    bc_put_u8(s, p->class_id - JS_CLASS_UINT8C_ARRAY);
34514
0
    bc_put_leb128(s, p->u.array.count);
34515
0
    bc_put_leb128(s, ta->offset);
34516
0
    if (JS_WriteObjectRec(s, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)))
34517
0
        return -1;
34518
0
    return 0;
34519
0
}
34520
34521
static int JS_WriteArrayBuffer(BCWriterState *s, JSValueConst obj)
34522
0
{
34523
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
34524
0
    JSArrayBuffer *abuf = p->u.array_buffer;
34525
0
    if (abuf->detached) {
34526
0
        JS_ThrowTypeErrorDetachedArrayBuffer(s->ctx);
34527
0
        return -1;
34528
0
    }
34529
0
    bc_put_u8(s, BC_TAG_ARRAY_BUFFER);
34530
0
    bc_put_leb128(s, abuf->byte_length);
34531
0
    dbuf_put(&s->dbuf, abuf->data, abuf->byte_length);
34532
0
    return 0;
34533
0
}
34534
34535
static int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValueConst obj)
34536
0
{
34537
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
34538
0
    JSArrayBuffer *abuf = p->u.array_buffer;
34539
0
    assert(!abuf->detached); /* SharedArrayBuffer are never detached */
34540
0
    bc_put_u8(s, BC_TAG_SHARED_ARRAY_BUFFER);
34541
0
    bc_put_leb128(s, abuf->byte_length);
34542
0
    bc_put_u64(s, (uintptr_t)abuf->data);
34543
0
    if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]),
34544
0
                        &s->sab_tab_size, s->sab_tab_len + 1))
34545
0
        return -1;
34546
    /* keep the SAB pointer so that the user can clone it or free it */
34547
0
    s->sab_tab[s->sab_tab_len++] = abuf->data;
34548
0
    return 0;
34549
0
}
34550
34551
static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
34552
63
{
34553
63
    uint32_t tag;
34554
34555
63
    if (js_check_stack_overflow(s->ctx->rt, 0)) {
34556
0
        JS_ThrowStackOverflow(s->ctx);
34557
0
        return -1;
34558
0
    }
34559
34560
63
    tag = JS_VALUE_GET_NORM_TAG(obj);
34561
63
    switch(tag) {
34562
0
    case JS_TAG_NULL:
34563
0
        bc_put_u8(s, BC_TAG_NULL);
34564
0
        break;
34565
0
    case JS_TAG_UNDEFINED:
34566
0
        bc_put_u8(s, BC_TAG_UNDEFINED);
34567
0
        break;
34568
0
    case JS_TAG_BOOL:
34569
0
        bc_put_u8(s, BC_TAG_BOOL_FALSE + JS_VALUE_GET_INT(obj));
34570
0
        break;
34571
0
    case JS_TAG_INT:
34572
0
        bc_put_u8(s, BC_TAG_INT32);
34573
0
        bc_put_sleb128(s, JS_VALUE_GET_INT(obj));
34574
0
        break;
34575
10
    case JS_TAG_FLOAT64:
34576
10
        {
34577
10
            JSFloat64Union u;
34578
10
            bc_put_u8(s, BC_TAG_FLOAT64);
34579
10
            u.d = JS_VALUE_GET_FLOAT64(obj);
34580
10
            bc_put_u64(s, u.u64);
34581
10
        }
34582
10
        break;
34583
14
    case JS_TAG_STRING:
34584
14
        {
34585
14
            JSString *p = JS_VALUE_GET_STRING(obj);
34586
14
            bc_put_u8(s, BC_TAG_STRING);
34587
14
            JS_WriteString(s, p);
34588
14
        }
34589
14
        break;
34590
14
    case JS_TAG_FUNCTION_BYTECODE:
34591
14
        if (!s->allow_bytecode)
34592
0
            goto invalid_tag;
34593
14
        if (JS_WriteFunctionTag(s, obj))
34594
1
            goto fail;
34595
13
        break;
34596
13
    case JS_TAG_MODULE:
34597
3
        if (!s->allow_bytecode)
34598
0
            goto invalid_tag;
34599
3
        if (JS_WriteModule(s, obj))
34600
1
            goto fail;
34601
2
        break;
34602
2
    case JS_TAG_OBJECT:
34603
0
        {
34604
0
            JSObject *p = JS_VALUE_GET_OBJ(obj);
34605
0
            int ret, idx;
34606
            
34607
0
            if (s->allow_reference) {
34608
0
                idx = js_object_list_find(s->ctx, &s->object_list, p);
34609
0
                if (idx >= 0) {
34610
0
                    bc_put_u8(s, BC_TAG_OBJECT_REFERENCE);
34611
0
                    bc_put_leb128(s, idx);
34612
0
                    break;
34613
0
                } else {
34614
0
                    if (js_object_list_add(s->ctx, &s->object_list, p))
34615
0
                        goto fail;
34616
0
                }
34617
0
            } else {
34618
0
                if (p->tmp_mark) {
34619
0
                    JS_ThrowTypeError(s->ctx, "circular reference");
34620
0
                    goto fail;
34621
0
                }
34622
0
                p->tmp_mark = 1;
34623
0
            }
34624
0
            switch(p->class_id) {
34625
0
            case JS_CLASS_ARRAY:
34626
0
                ret = JS_WriteArray(s, obj);
34627
0
                break;
34628
0
            case JS_CLASS_OBJECT:
34629
0
                ret = JS_WriteObjectTag(s, obj);
34630
0
                break;
34631
0
            case JS_CLASS_ARRAY_BUFFER:
34632
0
                ret = JS_WriteArrayBuffer(s, obj);
34633
0
                break;
34634
0
            case JS_CLASS_SHARED_ARRAY_BUFFER:
34635
0
                if (!s->allow_sab)
34636
0
                    goto invalid_tag;
34637
0
                ret = JS_WriteSharedArrayBuffer(s, obj);
34638
0
                break;
34639
0
            case JS_CLASS_DATE:
34640
0
                bc_put_u8(s, BC_TAG_DATE);
34641
0
                ret = JS_WriteObjectRec(s, p->u.object_data);
34642
0
                break;
34643
0
            case JS_CLASS_NUMBER:
34644
0
            case JS_CLASS_STRING:
34645
0
            case JS_CLASS_BOOLEAN:
34646
0
#ifdef CONFIG_BIGNUM
34647
0
            case JS_CLASS_BIG_INT:
34648
0
            case JS_CLASS_BIG_FLOAT:
34649
0
            case JS_CLASS_BIG_DECIMAL:
34650
0
#endif
34651
0
                bc_put_u8(s, BC_TAG_OBJECT_VALUE);
34652
0
                ret = JS_WriteObjectRec(s, p->u.object_data);
34653
0
                break;
34654
0
            default:
34655
0
                if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
34656
0
                    p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
34657
0
                    ret = JS_WriteTypedArray(s, obj);
34658
0
                } else {
34659
0
                    JS_ThrowTypeError(s->ctx, "unsupported object class");
34660
0
                    ret = -1;
34661
0
                }
34662
0
                break;
34663
0
            }
34664
0
            p->tmp_mark = 0;
34665
0
            if (ret)
34666
0
                goto fail;
34667
0
        }
34668
0
        break;
34669
0
#ifdef CONFIG_BIGNUM
34670
22
    case JS_TAG_BIG_INT:
34671
22
    case JS_TAG_BIG_FLOAT:
34672
22
    case JS_TAG_BIG_DECIMAL:
34673
22
        if (JS_WriteBigNum(s, obj))
34674
0
            goto fail;
34675
22
        break;
34676
22
#endif
34677
22
    default:
34678
0
    invalid_tag:
34679
0
        JS_ThrowInternalError(s->ctx, "unsupported tag (%d)", tag);
34680
0
        goto fail;
34681
63
    }
34682
61
    return 0;
34683
34684
2
 fail:
34685
2
    return -1;
34686
63
}
34687
34688
/* create the atom table */
34689
static int JS_WriteObjectAtoms(BCWriterState *s)
34690
2
{
34691
2
    JSRuntime *rt = s->ctx->rt;
34692
2
    DynBuf dbuf1;
34693
2
    int i, atoms_size;
34694
2
    uint8_t version;
34695
34696
2
    dbuf1 = s->dbuf;
34697
2
    js_dbuf_init(s->ctx, &s->dbuf);
34698
34699
2
    version = BC_VERSION;
34700
2
    if (s->byte_swap)
34701
0
        version ^= BC_BE_VERSION;
34702
2
    bc_put_u8(s, version);
34703
34704
2
    bc_put_leb128(s, s->idx_to_atom_count);
34705
101
    for(i = 0; i < s->idx_to_atom_count; i++) {
34706
99
        JSAtomStruct *p = rt->atom_array[s->idx_to_atom[i]];
34707
99
        JS_WriteString(s, p);
34708
99
    }
34709
    /* XXX: should check for OOM in above phase */
34710
34711
    /* move the atoms at the start */
34712
    /* XXX: could just append dbuf1 data, but it uses more memory if
34713
       dbuf1 is larger than dbuf */
34714
2
    atoms_size = s->dbuf.size;
34715
2
    if (dbuf_realloc(&dbuf1, dbuf1.size + atoms_size))
34716
0
        goto fail;
34717
2
    memmove(dbuf1.buf + atoms_size, dbuf1.buf, dbuf1.size);
34718
2
    memcpy(dbuf1.buf, s->dbuf.buf, atoms_size);
34719
2
    dbuf1.size += atoms_size;
34720
2
    dbuf_free(&s->dbuf);
34721
2
    s->dbuf = dbuf1;
34722
2
    return 0;
34723
0
 fail:
34724
0
    dbuf_free(&dbuf1);
34725
0
    return -1;
34726
2
}
34727
34728
uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
34729
                         int flags, uint8_t ***psab_tab, size_t *psab_tab_len)
34730
3
{
34731
3
    BCWriterState ss, *s = &ss;
34732
34733
3
    memset(s, 0, sizeof(*s));
34734
3
    s->ctx = ctx;
34735
    /* XXX: byte swapped output is untested */
34736
3
    s->byte_swap = ((flags & JS_WRITE_OBJ_BSWAP) != 0);
34737
3
    s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);
34738
3
    s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
34739
3
    s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0);
34740
    /* XXX: could use a different version when bytecode is included */
34741
3
    if (s->allow_bytecode)
34742
3
        s->first_atom = JS_ATOM_END;
34743
0
    else
34744
0
        s->first_atom = 1;
34745
3
    js_dbuf_init(ctx, &s->dbuf);
34746
3
    js_object_list_init(&s->object_list);
34747
    
34748
3
    if (JS_WriteObjectRec(s, obj))
34749
1
        goto fail;
34750
2
    if (JS_WriteObjectAtoms(s))
34751
0
        goto fail;
34752
2
    js_object_list_end(ctx, &s->object_list);
34753
2
    js_free(ctx, s->atom_to_idx);
34754
2
    js_free(ctx, s->idx_to_atom);
34755
2
    *psize = s->dbuf.size;
34756
2
    if (psab_tab)
34757
0
        *psab_tab = s->sab_tab;
34758
2
    if (psab_tab_len)
34759
0
        *psab_tab_len = s->sab_tab_len;
34760
2
    return s->dbuf.buf;
34761
1
 fail:
34762
1
    js_object_list_end(ctx, &s->object_list);
34763
1
    js_free(ctx, s->atom_to_idx);
34764
1
    js_free(ctx, s->idx_to_atom);
34765
1
    dbuf_free(&s->dbuf);
34766
1
    *psize = 0;
34767
1
    if (psab_tab)
34768
0
        *psab_tab = NULL;
34769
1
    if (psab_tab_len)
34770
0
        *psab_tab_len = 0;
34771
1
    return NULL;
34772
2
}
34773
34774
uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
34775
                        int flags)
34776
3
{
34777
3
    return JS_WriteObject2(ctx, psize, obj, flags, NULL, NULL);
34778
3
}
34779
34780
typedef struct BCReaderState {
34781
    JSContext *ctx;
34782
    const uint8_t *buf_start, *ptr, *buf_end;
34783
    uint32_t first_atom;
34784
    uint32_t idx_to_atom_count;
34785
    JSAtom *idx_to_atom;
34786
    int error_state;
34787
    BOOL allow_sab : 8;
34788
    BOOL allow_bytecode : 8;
34789
    BOOL is_rom_data : 8;
34790
    BOOL allow_reference : 8;
34791
    /* object references */
34792
    JSObject **objects;
34793
    int objects_count;
34794
    int objects_size;
34795
    
34796
#ifdef DUMP_READ_OBJECT
34797
    const uint8_t *ptr_last;
34798
    int level;
34799
#endif
34800
} BCReaderState;
34801
34802
#ifdef DUMP_READ_OBJECT
34803
static void __attribute__((format(printf, 2, 3))) bc_read_trace(BCReaderState *s, const char *fmt, ...) {
34804
    va_list ap;
34805
    int i, n, n0;
34806
34807
    if (!s->ptr_last)
34808
        s->ptr_last = s->buf_start;
34809
34810
    n = n0 = 0;
34811
    if (s->ptr > s->ptr_last || s->ptr == s->buf_start) {
34812
        n0 = printf("%04x: ", (int)(s->ptr_last - s->buf_start));
34813
        n += n0;
34814
    }
34815
    for (i = 0; s->ptr_last < s->ptr; i++) {
34816
        if ((i & 7) == 0 && i > 0) {
34817
            printf("\n%*s", n0, "");
34818
            n = n0;
34819
        }
34820
        n += printf(" %02x", *s->ptr_last++);
34821
    }
34822
    if (*fmt == '}')
34823
        s->level--;
34824
    if (n < 32 + s->level * 2) {
34825
        printf("%*s", 32 + s->level * 2 - n, "");
34826
    }
34827
    va_start(ap, fmt);
34828
    vfprintf(stdout, fmt, ap);
34829
    va_end(ap);
34830
    if (strchr(fmt, '{'))
34831
        s->level++;
34832
}
34833
#else
34834
#define bc_read_trace(...)
34835
#endif
34836
34837
static int bc_read_error_end(BCReaderState *s)
34838
0
{
34839
0
    if (!s->error_state) {
34840
0
        JS_ThrowSyntaxError(s->ctx, "read after the end of the buffer");
34841
0
    }
34842
0
    return s->error_state = -1;
34843
0
}
34844
34845
static int bc_get_u8(BCReaderState *s, uint8_t *pval)
34846
821
{
34847
821
    if (unlikely(s->buf_end - s->ptr < 1)) {
34848
0
        *pval = 0; /* avoid warning */
34849
0
        return bc_read_error_end(s);
34850
0
    }
34851
821
    *pval = *s->ptr++;
34852
821
    return 0;
34853
821
}
34854
34855
static int bc_get_u16(BCReaderState *s, uint16_t *pval)
34856
13
{
34857
13
    if (unlikely(s->buf_end - s->ptr < 2)) {
34858
0
        *pval = 0; /* avoid warning */
34859
0
        return bc_read_error_end(s);
34860
0
    }
34861
13
    *pval = get_u16(s->ptr);
34862
13
    s->ptr += 2;
34863
13
    return 0;
34864
13
}
34865
34866
static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
34867
0
{
34868
0
    if (unlikely(s->buf_end - s->ptr < 4)) {
34869
0
        *pval = 0; /* avoid warning */
34870
0
        return bc_read_error_end(s);
34871
0
    }
34872
0
    *pval = get_u32(s->ptr);
34873
0
    s->ptr += 4;
34874
0
    return 0;
34875
0
}
34876
34877
static int bc_get_u64(BCReaderState *s, uint64_t *pval)
34878
10
{
34879
10
    if (unlikely(s->buf_end - s->ptr < 8)) {
34880
0
        *pval = 0; /* avoid warning */
34881
0
        return bc_read_error_end(s);
34882
0
    }
34883
10
    *pval = get_u64(s->ptr);
34884
10
    s->ptr += 8;
34885
10
    return 0;
34886
10
}
34887
34888
static int bc_get_leb128(BCReaderState *s, uint32_t *pval)
34889
1.70k
{
34890
1.70k
    int ret;
34891
1.70k
    ret = get_leb128(pval, s->ptr, s->buf_end);
34892
1.70k
    if (unlikely(ret < 0))
34893
0
        return bc_read_error_end(s);
34894
1.70k
    s->ptr += ret;
34895
1.70k
    return 0;
34896
1.70k
}
34897
34898
static int bc_get_sleb128(BCReaderState *s, int32_t *pval)
34899
22
{
34900
22
    int ret;
34901
22
    ret = get_sleb128(pval, s->ptr, s->buf_end);
34902
22
    if (unlikely(ret < 0))
34903
0
        return bc_read_error_end(s);
34904
22
    s->ptr += ret;
34905
22
    return 0;
34906
22
}
34907
34908
/* XXX: used to read an `int` with a positive value */
34909
static int bc_get_leb128_int(BCReaderState *s, int *pval)
34910
801
{
34911
801
    return bc_get_leb128(s, (uint32_t *)pval);
34912
801
}
34913
34914
static int bc_get_leb128_u16(BCReaderState *s, uint16_t *pval)
34915
52
{
34916
52
    uint32_t val;
34917
52
    if (bc_get_leb128(s, &val)) {
34918
0
        *pval = 0;
34919
0
        return -1;
34920
0
    }
34921
52
    *pval = val;
34922
52
    return 0;
34923
52
}
34924
34925
static int bc_get_buf(BCReaderState *s, uint8_t *buf, uint32_t buf_len)
34926
20
{
34927
20
    if (buf_len != 0) {
34928
20
        if (unlikely(!buf || s->buf_end - s->ptr < buf_len))
34929
0
            return bc_read_error_end(s);
34930
20
        memcpy(buf, s->ptr, buf_len);
34931
20
        s->ptr += buf_len;
34932
20
    }
34933
20
    return 0;
34934
20
}
34935
34936
static int bc_idx_to_atom(BCReaderState *s, JSAtom *patom, uint32_t idx)
34937
89.8k
{
34938
89.8k
    JSAtom atom;
34939
34940
89.8k
    if (__JS_AtomIsTaggedInt(idx)) {
34941
1
        atom = idx;
34942
89.8k
    } else if (idx < s->first_atom) {
34943
33
        atom = JS_DupAtom(s->ctx, idx);
34944
89.7k
    } else {
34945
89.7k
        idx -= s->first_atom;
34946
89.7k
        if (idx >= s->idx_to_atom_count) {
34947
0
            JS_ThrowSyntaxError(s->ctx, "invalid atom index (pos=%u)",
34948
0
                                (unsigned int)(s->ptr - s->buf_start));
34949
0
            *patom = JS_ATOM_NULL;
34950
0
            return s->error_state = -1;
34951
0
        }
34952
89.7k
        atom = JS_DupAtom(s->ctx, s->idx_to_atom[idx]);
34953
89.7k
    }
34954
89.8k
    *patom = atom;
34955
89.8k
    return 0;
34956
89.8k
}
34957
34958
static int bc_get_atom(BCReaderState *s, JSAtom *patom)
34959
719
{
34960
719
    uint32_t v;
34961
719
    if (bc_get_leb128(s, &v))
34962
0
        return -1;
34963
719
    if (v & 1) {
34964
0
        *patom = __JS_AtomFromUInt32(v >> 1);
34965
0
        return 0;
34966
719
    } else {
34967
719
        return bc_idx_to_atom(s, patom, v >> 1);
34968
719
    }
34969
719
}
34970
34971
static JSString *JS_ReadString(BCReaderState *s)
34972
113
{
34973
113
    uint32_t len;
34974
113
    size_t size;
34975
113
    BOOL is_wide_char;
34976
113
    JSString *p;
34977
34978
113
    if (bc_get_leb128(s, &len))
34979
0
        return NULL;
34980
113
    is_wide_char = len & 1;
34981
113
    len >>= 1;
34982
113
    p = js_alloc_string(s->ctx, len, is_wide_char);
34983
113
    if (!p) {
34984
0
        s->error_state = -1;
34985
0
        return NULL;
34986
0
    }
34987
113
    size = (size_t)len << is_wide_char;
34988
113
    if ((s->buf_end - s->ptr) < size) {
34989
0
        bc_read_error_end(s);
34990
0
        js_free_string(s->ctx->rt, p);
34991
0
        return NULL;
34992
0
    }
34993
113
    memcpy(p->u.str8, s->ptr, size);
34994
113
    s->ptr += size;
34995
113
    if (!is_wide_char) {
34996
112
        p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */
34997
112
    }
34998
#ifdef DUMP_READ_OBJECT
34999
    JS_DumpString(s->ctx->rt, p); printf("\n");
35000
#endif
35001
113
    return p;
35002
113
}
35003
35004
static uint32_t bc_get_flags(uint32_t flags, int *pidx, int n)
35005
3.57k
{
35006
3.57k
    uint32_t val;
35007
    /* XXX: this does not work for n == 32 */
35008
3.57k
    val = (flags >> *pidx) & ((1U << n) - 1);
35009
3.57k
    *pidx += n;
35010
3.57k
    return val;
35011
3.57k
}
35012
35013
static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
35014
                                   int byte_code_offset, uint32_t bc_len)
35015
13
{
35016
13
    uint8_t *bc_buf;
35017
13
    int pos, len, op;
35018
13
    JSAtom atom;
35019
13
    uint32_t idx;
35020
35021
13
    if (s->is_rom_data) {
35022
        /* directly use the input buffer */
35023
0
        if (unlikely(s->buf_end - s->ptr < bc_len))
35024
0
            return bc_read_error_end(s);
35025
0
        bc_buf = (uint8_t *)s->ptr;
35026
0
        s->ptr += bc_len;
35027
13
    } else {
35028
13
        bc_buf = (void *)((uint8_t*)b + byte_code_offset);
35029
13
        if (bc_get_buf(s, bc_buf, bc_len))
35030
0
            return -1;
35031
13
    }
35032
13
    b->byte_code_buf = bc_buf;
35033
35034
13
    pos = 0;
35035
252k
    while (pos < bc_len) {
35036
252k
        op = bc_buf[pos];
35037
252k
        len = short_opcode_info(op).size;
35038
252k
        switch(short_opcode_info(op).fmt) {
35039
66.7k
        case OP_FMT_atom:
35040
66.7k
        case OP_FMT_atom_u8:
35041
89.1k
        case OP_FMT_atom_u16:
35042
89.1k
        case OP_FMT_atom_label_u8:
35043
89.1k
        case OP_FMT_atom_label_u16:
35044
89.1k
            idx = get_u32(bc_buf + pos + 1);
35045
89.1k
            if (s->is_rom_data) {
35046
                /* just increment the reference count of the atom */
35047
0
                JS_DupAtom(s->ctx, (JSAtom)idx);
35048
89.1k
            } else {
35049
89.1k
                if (bc_idx_to_atom(s, &atom, idx)) {
35050
                    /* Note: the atoms will be freed up to this position */
35051
0
                    b->byte_code_len = pos;
35052
0
                    return -1;
35053
0
                }
35054
89.1k
                put_u32(bc_buf + pos + 1, atom);
35055
#ifdef DUMP_READ_OBJECT
35056
                bc_read_trace(s, "at %d, fixup atom: ", pos + 1); print_atom(s->ctx, atom); printf("\n");
35057
#endif
35058
89.1k
            }
35059
89.1k
            break;
35060
163k
        default:
35061
163k
            break;
35062
252k
        }
35063
252k
        pos += len;
35064
252k
    }
35065
13
    return 0;
35066
13
}
35067
35068
#ifdef CONFIG_BIGNUM
35069
static JSValue JS_ReadBigNum(BCReaderState *s, int tag)
35070
22
{
35071
22
    JSValue obj = JS_UNDEFINED;
35072
22
    uint8_t v8;
35073
22
    int32_t e;
35074
22
    uint32_t len;
35075
22
    limb_t l, i, n, j;
35076
22
    JSBigFloat *p;
35077
22
    limb_t v;
35078
22
    bf_t *a;
35079
22
    int bpos, d;
35080
    
35081
22
    p = js_new_bf(s->ctx);
35082
22
    if (!p)
35083
0
        goto fail;
35084
22
    switch(tag) {
35085
22
    case BC_TAG_BIG_INT:
35086
22
        obj = JS_MKPTR(JS_TAG_BIG_INT, p);
35087
22
        break;
35088
0
    case BC_TAG_BIG_FLOAT:
35089
0
        obj = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
35090
0
        break;
35091
0
    case BC_TAG_BIG_DECIMAL:
35092
0
        obj = JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
35093
0
        break;
35094
0
    default:
35095
0
        abort();
35096
22
    }
35097
35098
    /* sign + exponent */
35099
22
    if (bc_get_sleb128(s, &e))
35100
0
        goto fail;
35101
35102
22
    a = &p->num;
35103
22
    a->sign = e & 1;
35104
22
    e >>= 1;
35105
22
    if (e == 0)
35106
0
        a->expn = BF_EXP_ZERO;
35107
22
    else if (e == 1)
35108
0
        a->expn = BF_EXP_INF;
35109
22
    else if (e == 2)
35110
0
        a->expn = BF_EXP_NAN;
35111
22
    else if (e >= 3)
35112
22
        a->expn = e - 3;
35113
0
    else
35114
0
        a->expn = e;
35115
35116
    /* mantissa */
35117
22
    if (a->expn != BF_EXP_ZERO &&
35118
22
        a->expn != BF_EXP_INF &&
35119
22
        a->expn != BF_EXP_NAN) {
35120
22
        if (bc_get_leb128(s, &len))
35121
0
            goto fail;
35122
22
        bc_read_trace(s, "len=%" PRId64 "\n", (int64_t)len);
35123
22
        if (len == 0) {
35124
0
            JS_ThrowInternalError(s->ctx, "invalid bignum length");
35125
0
            goto fail;
35126
0
        }
35127
22
        if (tag != BC_TAG_BIG_DECIMAL)
35128
22
            l = (len + sizeof(limb_t) - 1) / sizeof(limb_t);
35129
0
        else
35130
0
            l = (len + LIMB_DIGITS - 1) / LIMB_DIGITS;
35131
22
        if (bf_resize(a, l)) {
35132
0
            JS_ThrowOutOfMemory(s->ctx);
35133
0
            goto fail;
35134
0
        }
35135
22
        if (tag != BC_TAG_BIG_DECIMAL) {
35136
22
            n = len & (sizeof(limb_t) - 1);
35137
22
            if (n != 0) {
35138
22
                v = 0;
35139
76
                for(i = 0; i < n; i++) {
35140
54
                    if (bc_get_u8(s, &v8))
35141
0
                        goto fail;
35142
54
                    v |= (limb_t)v8 << ((sizeof(limb_t) - n + i) * 8);
35143
54
                }
35144
22
                a->tab[0] = v;
35145
22
                i = 1;
35146
22
            } else {
35147
0
                i = 0;
35148
0
            }
35149
22
            for(; i < l; i++) {
35150
#if LIMB_BITS == 32
35151
                if (bc_get_u32(s, &v))
35152
                    goto fail;
35153
#ifdef WORDS_BIGENDIAN
35154
                v = bswap32(v);
35155
#endif
35156
#else
35157
0
                if (bc_get_u64(s, &v))
35158
0
                    goto fail;
35159
#ifdef WORDS_BIGENDIAN
35160
                v = bswap64(v);
35161
#endif
35162
0
#endif
35163
0
                a->tab[i] = v;
35164
0
            }
35165
22
        } else {
35166
0
            bpos = 0;
35167
0
            for(i = 0; i < l; i++) {
35168
0
                if (i == 0 && (n = len % LIMB_DIGITS) != 0) {
35169
0
                    j = LIMB_DIGITS - n;
35170
0
                } else {
35171
0
                    j = 0;
35172
0
                }
35173
0
                v = 0;
35174
0
                for(; j < LIMB_DIGITS; j++) {
35175
0
                    if (bpos == 0) {
35176
0
                        if (bc_get_u8(s, &v8))
35177
0
                            goto fail;
35178
0
                        d = v8 & 0xf;
35179
0
                        bpos = 1;
35180
0
                    } else {
35181
0
                        d = v8 >> 4;
35182
0
                        bpos = 0;
35183
0
                    }
35184
0
                    if (d >= 10) {
35185
0
                        JS_ThrowInternalError(s->ctx, "invalid digit");
35186
0
                        goto fail;
35187
0
                    }
35188
0
                    v += mp_pow_dec[j] * d;
35189
0
                }
35190
0
                a->tab[i] = v;
35191
0
            }
35192
0
        }
35193
22
    }
35194
22
    bc_read_trace(s, "}\n");
35195
22
    return obj;
35196
0
 fail:
35197
0
    JS_FreeValue(s->ctx, obj);
35198
0
    return JS_EXCEPTION;
35199
22
}
35200
#endif /* CONFIG_BIGNUM */
35201
35202
static JSValue JS_ReadObjectRec(BCReaderState *s);
35203
35204
static int BC_add_object_ref1(BCReaderState *s, JSObject *p)
35205
0
{
35206
0
    if (s->allow_reference) {
35207
0
        if (js_resize_array(s->ctx, (void *)&s->objects,
35208
0
                            sizeof(s->objects[0]),
35209
0
                            &s->objects_size, s->objects_count + 1))
35210
0
            return -1;
35211
0
        s->objects[s->objects_count++] = p;
35212
0
    }
35213
0
    return 0;
35214
0
}
35215
35216
static int BC_add_object_ref(BCReaderState *s, JSValueConst obj)
35217
0
{
35218
0
    return BC_add_object_ref1(s, JS_VALUE_GET_OBJ(obj));
35219
0
}
35220
35221
static JSValue JS_ReadFunctionTag(BCReaderState *s)
35222
13
{
35223
13
    JSContext *ctx = s->ctx;
35224
13
    JSFunctionBytecode bc, *b;
35225
13
    JSValue obj = JS_UNDEFINED;
35226
13
    uint16_t v16;
35227
13
    uint8_t v8;
35228
13
    int idx, i, local_count;
35229
13
    int function_size, cpool_offset, byte_code_offset;
35230
13
    int closure_var_offset, vardefs_offset;
35231
35232
13
    memset(&bc, 0, sizeof(bc));
35233
13
    bc.header.ref_count = 1;
35234
    //bc.gc_header.mark = 0;
35235
35236
13
    if (bc_get_u16(s, &v16))
35237
0
        goto fail;
35238
13
    idx = 0;
35239
13
    bc.has_prototype = bc_get_flags(v16, &idx, 1);
35240
13
    bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1);
35241
13
    bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1);
35242
13
    bc.need_home_object = bc_get_flags(v16, &idx, 1);
35243
13
    bc.func_kind = bc_get_flags(v16, &idx, 2);
35244
13
    bc.new_target_allowed = bc_get_flags(v16, &idx, 1);
35245
13
    bc.super_call_allowed = bc_get_flags(v16, &idx, 1);
35246
13
    bc.super_allowed = bc_get_flags(v16, &idx, 1);
35247
13
    bc.arguments_allowed = bc_get_flags(v16, &idx, 1);
35248
13
    bc.has_debug = bc_get_flags(v16, &idx, 1);
35249
13
    bc.backtrace_barrier = bc_get_flags(v16, &idx, 1);
35250
13
    bc.read_only_bytecode = s->is_rom_data;
35251
13
    if (bc_get_u8(s, &v8))
35252
0
        goto fail;
35253
13
    bc.js_mode = v8;
35254
13
    if (bc_get_atom(s, &bc.func_name))  //@ atom leak if failure
35255
0
        goto fail;
35256
13
    if (bc_get_leb128_u16(s, &bc.arg_count))
35257
0
        goto fail;
35258
13
    if (bc_get_leb128_u16(s, &bc.var_count))
35259
0
        goto fail;
35260
13
    if (bc_get_leb128_u16(s, &bc.defined_arg_count))
35261
0
        goto fail;
35262
13
    if (bc_get_leb128_u16(s, &bc.stack_size))
35263
0
        goto fail;
35264
13
    if (bc_get_leb128_int(s, &bc.closure_var_count))
35265
0
        goto fail;
35266
13
    if (bc_get_leb128_int(s, &bc.cpool_count))
35267
0
        goto fail;
35268
13
    if (bc_get_leb128_int(s, &bc.byte_code_len))
35269
0
        goto fail;
35270
13
    if (bc_get_leb128_int(s, &local_count))
35271
0
        goto fail;
35272
35273
13
    if (bc.has_debug) {
35274
13
        function_size = sizeof(*b);
35275
13
    } else {
35276
0
        function_size = offsetof(JSFunctionBytecode, debug);
35277
0
    }
35278
13
    cpool_offset = function_size;
35279
13
    function_size += bc.cpool_count * sizeof(*bc.cpool);
35280
13
    vardefs_offset = function_size;
35281
13
    function_size += local_count * sizeof(*bc.vardefs);
35282
13
    closure_var_offset = function_size;
35283
13
    function_size += bc.closure_var_count * sizeof(*bc.closure_var);
35284
13
    byte_code_offset = function_size;
35285
13
    if (!bc.read_only_bytecode) {
35286
13
        function_size += bc.byte_code_len;
35287
13
    }
35288
35289
13
    b = js_mallocz(ctx, function_size);
35290
13
    if (!b)
35291
0
        return JS_EXCEPTION;
35292
            
35293
13
    memcpy(b, &bc, offsetof(JSFunctionBytecode, debug));
35294
13
    b->header.ref_count = 1;
35295
13
    if (local_count != 0) {
35296
12
        b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
35297
12
    }
35298
13
    if (b->closure_var_count != 0) {
35299
7
        b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
35300
7
    }
35301
13
    if (b->cpool_count != 0) {
35302
3
        b->cpool = (void *)((uint8_t*)b + cpool_offset);
35303
3
    }
35304
    
35305
13
    add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
35306
            
35307
13
    obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
35308
35309
#ifdef DUMP_READ_OBJECT
35310
    bc_read_trace(s, "name: "); print_atom(s->ctx, b->func_name); printf("\n");
35311
#endif
35312
13
    bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n",
35313
13
                  b->arg_count, b->var_count, b->defined_arg_count,
35314
13
                  b->closure_var_count, b->cpool_count);
35315
13
    bc_read_trace(s, "stack=%d bclen=%d locals=%d\n",
35316
13
                  b->stack_size, b->byte_code_len, local_count);
35317
35318
13
    if (local_count != 0) {
35319
12
        bc_read_trace(s, "vars {\n");
35320
36
        for(i = 0; i < local_count; i++) {
35321
24
            JSVarDef *vd = &b->vardefs[i];
35322
24
            if (bc_get_atom(s, &vd->var_name))
35323
0
                goto fail;
35324
24
            if (bc_get_leb128_int(s, &vd->scope_level))
35325
0
                goto fail;
35326
24
            if (bc_get_leb128_int(s, &vd->scope_next))
35327
0
                goto fail;
35328
24
            vd->scope_next--;
35329
24
            if (bc_get_u8(s, &v8))
35330
0
                goto fail;
35331
24
            idx = 0;
35332
24
            vd->var_kind = bc_get_flags(v8, &idx, 4);
35333
24
            vd->is_const = bc_get_flags(v8, &idx, 1);
35334
24
            vd->is_lexical = bc_get_flags(v8, &idx, 1);
35335
24
            vd->is_captured = bc_get_flags(v8, &idx, 1);
35336
#ifdef DUMP_READ_OBJECT
35337
            bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n");
35338
#endif
35339
24
        }
35340
12
        bc_read_trace(s, "}\n");
35341
12
    }
35342
13
    if (b->closure_var_count != 0) {
35343
7
        bc_read_trace(s, "closure vars {\n");
35344
674
        for(i = 0; i < b->closure_var_count; i++) {
35345
667
            JSClosureVar *cv = &b->closure_var[i];
35346
667
            int var_idx;
35347
667
            if (bc_get_atom(s, &cv->var_name))
35348
0
                goto fail;
35349
667
            if (bc_get_leb128_int(s, &var_idx))
35350
0
                goto fail;
35351
667
            cv->var_idx = var_idx;
35352
667
            if (bc_get_u8(s, &v8))
35353
0
                goto fail;
35354
667
            idx = 0;
35355
667
            cv->is_local = bc_get_flags(v8, &idx, 1);
35356
667
            cv->is_arg = bc_get_flags(v8, &idx, 1);
35357
667
            cv->is_const = bc_get_flags(v8, &idx, 1);
35358
667
            cv->is_lexical = bc_get_flags(v8, &idx, 1);
35359
667
            cv->var_kind = bc_get_flags(v8, &idx, 4);
35360
#ifdef DUMP_READ_OBJECT
35361
            bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); printf("\n");
35362
#endif
35363
667
        }
35364
7
        bc_read_trace(s, "}\n");
35365
7
    }
35366
13
    {
35367
13
        bc_read_trace(s, "bytecode {\n");
35368
13
        if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len))
35369
0
            goto fail;
35370
13
        bc_read_trace(s, "}\n");
35371
13
    }
35372
13
    if (b->has_debug) {
35373
        /* read optional debug information */
35374
13
        bc_read_trace(s, "debug {\n");
35375
13
        if (bc_get_atom(s, &b->debug.filename))
35376
0
            goto fail;
35377
13
        if (bc_get_leb128_int(s, &b->debug.line_num))
35378
0
            goto fail;
35379
13
        if (bc_get_leb128_int(s, &b->debug.pc2line_len))
35380
0
            goto fail;
35381
13
        if (b->debug.pc2line_len) {
35382
7
            b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len);
35383
7
            if (!b->debug.pc2line_buf)
35384
0
                goto fail;
35385
7
            if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len))
35386
0
                goto fail;
35387
7
        }
35388
#ifdef DUMP_READ_OBJECT
35389
        bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n");
35390
#endif
35391
13
        bc_read_trace(s, "}\n");
35392
13
    }
35393
13
    if (b->cpool_count != 0) {
35394
3
        bc_read_trace(s, "cpool {\n");
35395
60
        for(i = 0; i < b->cpool_count; i++) {
35396
57
            JSValue val;
35397
57
            val = JS_ReadObjectRec(s);
35398
57
            if (JS_IsException(val))
35399
0
                goto fail;
35400
57
            b->cpool[i] = val;
35401
57
        }
35402
3
        bc_read_trace(s, "}\n");
35403
3
    }
35404
13
    b->realm = JS_DupContext(ctx);
35405
13
    return obj;
35406
0
 fail:
35407
0
    JS_FreeValue(ctx, obj);
35408
0
    return JS_EXCEPTION;
35409
13
}
35410
35411
static JSValue JS_ReadModule(BCReaderState *s)
35412
2
{
35413
2
    JSContext *ctx = s->ctx;
35414
2
    JSValue obj;
35415
2
    JSModuleDef *m = NULL;
35416
2
    JSAtom module_name;
35417
2
    int i;
35418
2
    uint8_t v8;
35419
    
35420
2
    if (bc_get_atom(s, &module_name))
35421
0
        goto fail;
35422
#ifdef DUMP_READ_OBJECT
35423
    bc_read_trace(s, "name: "); print_atom(s->ctx, module_name); printf("\n");
35424
#endif
35425
2
    m = js_new_module_def(ctx, module_name);
35426
2
    if (!m)
35427
0
        goto fail;
35428
2
    obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
35429
2
    if (bc_get_leb128_int(s, &m->req_module_entries_count))
35430
0
        goto fail;
35431
2
    if (m->req_module_entries_count != 0) {
35432
0
        m->req_module_entries_size = m->req_module_entries_count;
35433
0
        m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size);
35434
0
        if (!m->req_module_entries)
35435
0
            goto fail;
35436
0
        for(i = 0; i < m->req_module_entries_count; i++) {
35437
0
            JSReqModuleEntry *rme = &m->req_module_entries[i];
35438
0
            if (bc_get_atom(s, &rme->module_name))
35439
0
                goto fail;
35440
0
        }
35441
0
    }
35442
35443
2
    if (bc_get_leb128_int(s, &m->export_entries_count))
35444
0
        goto fail;
35445
2
    if (m->export_entries_count != 0) {
35446
0
        m->export_entries_size = m->export_entries_count;
35447
0
        m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size);
35448
0
        if (!m->export_entries)
35449
0
            goto fail;
35450
0
        for(i = 0; i < m->export_entries_count; i++) {
35451
0
            JSExportEntry *me = &m->export_entries[i];
35452
0
            if (bc_get_u8(s, &v8))
35453
0
                goto fail;
35454
0
            me->export_type = v8;
35455
0
            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
35456
0
                if (bc_get_leb128_int(s, &me->u.local.var_idx))
35457
0
                    goto fail;
35458
0
            } else {
35459
0
                if (bc_get_leb128_int(s, &me->u.req_module_idx))
35460
0
                    goto fail;
35461
0
                if (bc_get_atom(s, &me->local_name))
35462
0
                    goto fail;
35463
0
            }
35464
0
            if (bc_get_atom(s, &me->export_name))
35465
0
                goto fail;
35466
0
        }
35467
0
    }
35468
35469
2
    if (bc_get_leb128_int(s, &m->star_export_entries_count))
35470
0
        goto fail;
35471
2
    if (m->star_export_entries_count != 0) {
35472
0
        m->star_export_entries_size = m->star_export_entries_count;
35473
0
        m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size);
35474
0
        if (!m->star_export_entries)
35475
0
            goto fail;
35476
0
        for(i = 0; i < m->star_export_entries_count; i++) {
35477
0
            JSStarExportEntry *se = &m->star_export_entries[i];
35478
0
            if (bc_get_leb128_int(s, &se->req_module_idx))
35479
0
                goto fail;
35480
0
        }
35481
0
    }
35482
35483
2
    if (bc_get_leb128_int(s, &m->import_entries_count))
35484
0
        goto fail;
35485
2
    if (m->import_entries_count != 0) {
35486
0
        m->import_entries_size = m->import_entries_count;
35487
0
        m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size);
35488
0
        if (!m->import_entries)
35489
0
            goto fail;
35490
0
        for(i = 0; i < m->import_entries_count; i++) {
35491
0
            JSImportEntry *mi = &m->import_entries[i];
35492
0
            if (bc_get_leb128_int(s, &mi->var_idx))
35493
0
                goto fail;
35494
0
            if (bc_get_atom(s, &mi->import_name))
35495
0
                goto fail;
35496
0
            if (bc_get_leb128_int(s, &mi->req_module_idx))
35497
0
                goto fail;
35498
0
        }
35499
0
    }
35500
35501
2
    m->func_obj = JS_ReadObjectRec(s);
35502
2
    if (JS_IsException(m->func_obj))
35503
0
        goto fail;
35504
2
    return obj;
35505
0
 fail:
35506
0
    if (m) {
35507
0
        js_free_module_def(ctx, m);
35508
0
    }
35509
0
    return JS_EXCEPTION;
35510
2
}
35511
35512
static JSValue JS_ReadObjectTag(BCReaderState *s)
35513
0
{
35514
0
    JSContext *ctx = s->ctx;
35515
0
    JSValue obj;
35516
0
    uint32_t prop_count, i;
35517
0
    JSAtom atom;
35518
0
    JSValue val;
35519
0
    int ret;
35520
    
35521
0
    obj = JS_NewObject(ctx);
35522
0
    if (BC_add_object_ref(s, obj))
35523
0
        goto fail;
35524
0
    if (bc_get_leb128(s, &prop_count))
35525
0
        goto fail;
35526
0
    for(i = 0; i < prop_count; i++) {
35527
0
        if (bc_get_atom(s, &atom))
35528
0
            goto fail;
35529
#ifdef DUMP_READ_OBJECT
35530
        bc_read_trace(s, "propname: "); print_atom(s->ctx, atom); printf("\n");
35531
#endif
35532
0
        val = JS_ReadObjectRec(s);
35533
0
        if (JS_IsException(val)) {
35534
0
            JS_FreeAtom(ctx, atom);
35535
0
            goto fail;
35536
0
        }
35537
0
        ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E);
35538
0
        JS_FreeAtom(ctx, atom);
35539
0
        if (ret < 0)
35540
0
            goto fail;
35541
0
    }
35542
0
    return obj;
35543
0
 fail:
35544
0
    JS_FreeValue(ctx, obj);
35545
0
    return JS_EXCEPTION;
35546
0
}
35547
35548
static JSValue JS_ReadArray(BCReaderState *s, int tag)
35549
0
{
35550
0
    JSContext *ctx = s->ctx;
35551
0
    JSValue obj;
35552
0
    uint32_t len, i;
35553
0
    JSValue val;
35554
0
    int ret, prop_flags;
35555
0
    BOOL is_template;
35556
35557
0
    obj = JS_NewArray(ctx);
35558
0
    if (BC_add_object_ref(s, obj))
35559
0
        goto fail;
35560
0
    is_template = (tag == BC_TAG_TEMPLATE_OBJECT);
35561
0
    if (bc_get_leb128(s, &len))
35562
0
        goto fail;
35563
0
    for(i = 0; i < len; i++) {
35564
0
        val = JS_ReadObjectRec(s);
35565
0
        if (JS_IsException(val))
35566
0
            goto fail;
35567
0
        if (is_template)
35568
0
            prop_flags = JS_PROP_ENUMERABLE;
35569
0
        else
35570
0
            prop_flags = JS_PROP_C_W_E;
35571
0
        ret = JS_DefinePropertyValueUint32(ctx, obj, i, val,
35572
0
                                           prop_flags);
35573
0
        if (ret < 0)
35574
0
            goto fail;
35575
0
    }
35576
0
    if (is_template) {
35577
0
        val = JS_ReadObjectRec(s);
35578
0
        if (JS_IsException(val))
35579
0
            goto fail;
35580
0
        if (!JS_IsUndefined(val)) {
35581
0
            ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0);
35582
0
            if (ret < 0)
35583
0
                goto fail;
35584
0
        }
35585
0
        JS_PreventExtensions(ctx, obj);
35586
0
    }
35587
0
    return obj;
35588
0
 fail:
35589
0
    JS_FreeValue(ctx, obj);
35590
0
    return JS_EXCEPTION;
35591
0
}
35592
35593
static JSValue JS_ReadTypedArray(BCReaderState *s)
35594
0
{
35595
0
    JSContext *ctx = s->ctx;
35596
0
    JSValue obj = JS_UNDEFINED, array_buffer = JS_UNDEFINED;
35597
0
    uint8_t array_tag;
35598
0
    JSValueConst args[3];
35599
0
    uint32_t offset, len, idx;
35600
    
35601
0
    if (bc_get_u8(s, &array_tag))
35602
0
        return JS_EXCEPTION;
35603
0
    if (array_tag >= JS_TYPED_ARRAY_COUNT)
35604
0
        return JS_ThrowTypeError(ctx, "invalid typed array");
35605
0
    if (bc_get_leb128(s, &len))
35606
0
        return JS_EXCEPTION;
35607
0
    if (bc_get_leb128(s, &offset))
35608
0
        return JS_EXCEPTION;
35609
    /* XXX: this hack could be avoided if the typed array could be
35610
       created before the array buffer */
35611
0
    idx = s->objects_count;
35612
0
    if (BC_add_object_ref1(s, NULL))
35613
0
        goto fail;
35614
0
    array_buffer = JS_ReadObjectRec(s);
35615
0
    if (JS_IsException(array_buffer))
35616
0
        return JS_EXCEPTION;
35617
0
    if (!js_get_array_buffer(ctx, array_buffer)) {
35618
0
        JS_FreeValue(ctx, array_buffer);
35619
0
        return JS_EXCEPTION;
35620
0
    }
35621
0
    args[0] = array_buffer;
35622
0
    args[1] = JS_NewInt64(ctx, offset);
35623
0
    args[2] = JS_NewInt64(ctx, len);
35624
0
    obj = js_typed_array_constructor(ctx, JS_UNDEFINED,
35625
0
                                     3, args,
35626
0
                                     JS_CLASS_UINT8C_ARRAY + array_tag);
35627
0
    if (JS_IsException(obj))
35628
0
        goto fail;
35629
0
    if (s->allow_reference) {
35630
0
        s->objects[idx] = JS_VALUE_GET_OBJ(obj);
35631
0
    }
35632
0
    JS_FreeValue(ctx, array_buffer);
35633
0
    return obj;
35634
0
 fail:
35635
0
    JS_FreeValue(ctx, array_buffer);
35636
0
    JS_FreeValue(ctx, obj);
35637
0
    return JS_EXCEPTION;
35638
0
}
35639
35640
static JSValue JS_ReadArrayBuffer(BCReaderState *s)
35641
0
{
35642
0
    JSContext *ctx = s->ctx;
35643
0
    uint32_t byte_length;
35644
0
    JSValue obj;
35645
    
35646
0
    if (bc_get_leb128(s, &byte_length))
35647
0
        return JS_EXCEPTION;
35648
0
    if (unlikely(s->buf_end - s->ptr < byte_length)) {
35649
0
        bc_read_error_end(s);
35650
0
        return JS_EXCEPTION;
35651
0
    }
35652
0
    obj = JS_NewArrayBufferCopy(ctx, s->ptr, byte_length);
35653
0
    if (JS_IsException(obj))
35654
0
        goto fail;
35655
0
    if (BC_add_object_ref(s, obj))
35656
0
        goto fail;
35657
0
    s->ptr += byte_length;
35658
0
    return obj;
35659
0
 fail:
35660
0
    JS_FreeValue(ctx, obj);
35661
0
    return JS_EXCEPTION;
35662
0
}
35663
35664
static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s)
35665
0
{
35666
0
    JSContext *ctx = s->ctx;
35667
0
    uint32_t byte_length;
35668
0
    uint8_t *data_ptr;
35669
0
    JSValue obj;
35670
0
    uint64_t u64;
35671
    
35672
0
    if (bc_get_leb128(s, &byte_length))
35673
0
        return JS_EXCEPTION;
35674
0
    if (bc_get_u64(s, &u64))
35675
0
        return JS_EXCEPTION;
35676
0
    data_ptr = (uint8_t *)(uintptr_t)u64;
35677
    /* the SharedArrayBuffer is cloned */
35678
0
    obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED, byte_length,
35679
0
                                       JS_CLASS_SHARED_ARRAY_BUFFER,
35680
0
                                       data_ptr,
35681
0
                                       NULL, NULL, FALSE);
35682
0
    if (JS_IsException(obj))
35683
0
        goto fail;
35684
0
    if (BC_add_object_ref(s, obj))
35685
0
        goto fail;
35686
0
    return obj;
35687
0
 fail:
35688
0
    JS_FreeValue(ctx, obj);
35689
0
    return JS_EXCEPTION;
35690
0
}
35691
35692
static JSValue JS_ReadDate(BCReaderState *s)
35693
0
{
35694
0
    JSContext *ctx = s->ctx;
35695
0
    JSValue val, obj = JS_UNDEFINED;
35696
35697
0
    val = JS_ReadObjectRec(s);
35698
0
    if (JS_IsException(val))
35699
0
        goto fail;
35700
0
    if (!JS_IsNumber(val)) {
35701
0
        JS_ThrowTypeError(ctx, "Number tag expected for date");
35702
0
        goto fail;
35703
0
    }
35704
0
    obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_DATE],
35705
0
                                 JS_CLASS_DATE);
35706
0
    if (JS_IsException(obj))
35707
0
        goto fail;
35708
0
    if (BC_add_object_ref(s, obj))
35709
0
        goto fail;
35710
0
    JS_SetObjectData(ctx, obj, val);
35711
0
    return obj;
35712
0
 fail:
35713
0
    JS_FreeValue(ctx, val);
35714
0
    JS_FreeValue(ctx, obj);
35715
0
    return JS_EXCEPTION;
35716
0
}
35717
35718
static JSValue JS_ReadObjectValue(BCReaderState *s)
35719
0
{
35720
0
    JSContext *ctx = s->ctx;
35721
0
    JSValue val, obj = JS_UNDEFINED;
35722
35723
0
    val = JS_ReadObjectRec(s);
35724
0
    if (JS_IsException(val))
35725
0
        goto fail;
35726
0
    obj = JS_ToObject(ctx, val);
35727
0
    if (JS_IsException(obj))
35728
0
        goto fail;
35729
0
    if (BC_add_object_ref(s, obj))
35730
0
        goto fail;
35731
0
    JS_FreeValue(ctx, val);
35732
0
    return obj;
35733
0
 fail:
35734
0
    JS_FreeValue(ctx, val);
35735
0
    JS_FreeValue(ctx, obj);
35736
0
    return JS_EXCEPTION;
35737
0
}
35738
35739
static JSValue JS_ReadObjectRec(BCReaderState *s)
35740
61
{
35741
61
    JSContext *ctx = s->ctx;
35742
61
    uint8_t tag;
35743
61
    JSValue obj = JS_UNDEFINED;
35744
35745
61
    if (js_check_stack_overflow(ctx->rt, 0))
35746
0
        return JS_ThrowStackOverflow(ctx);
35747
35748
61
    if (bc_get_u8(s, &tag))
35749
0
        return JS_EXCEPTION;
35750
35751
61
    bc_read_trace(s, "%s {\n", bc_tag_str[tag]);
35752
35753
61
    switch(tag) {
35754
0
    case BC_TAG_NULL:
35755
0
        obj = JS_NULL;
35756
0
        break;
35757
0
    case BC_TAG_UNDEFINED:
35758
0
        obj = JS_UNDEFINED;
35759
0
        break;
35760
0
    case BC_TAG_BOOL_FALSE:
35761
0
    case BC_TAG_BOOL_TRUE:
35762
0
        obj = JS_NewBool(ctx, tag - BC_TAG_BOOL_FALSE);
35763
0
        break;
35764
0
    case BC_TAG_INT32:
35765
0
        {
35766
0
            int32_t val;
35767
0
            if (bc_get_sleb128(s, &val))
35768
0
                return JS_EXCEPTION;
35769
0
            bc_read_trace(s, "%d\n", val);
35770
0
            obj = JS_NewInt32(ctx, val);
35771
0
        }
35772
0
        break;
35773
10
    case BC_TAG_FLOAT64:
35774
10
        {
35775
10
            JSFloat64Union u;
35776
10
            if (bc_get_u64(s, &u.u64))
35777
0
                return JS_EXCEPTION;
35778
10
            bc_read_trace(s, "%g\n", u.d);
35779
10
            obj = __JS_NewFloat64(ctx, u.d);
35780
10
        }
35781
0
        break;
35782
14
    case BC_TAG_STRING:
35783
14
        {
35784
14
            JSString *p;
35785
14
            p = JS_ReadString(s);
35786
14
            if (!p)
35787
0
                return JS_EXCEPTION;
35788
14
            obj = JS_MKPTR(JS_TAG_STRING, p);
35789
14
        }
35790
0
        break;
35791
13
    case BC_TAG_FUNCTION_BYTECODE:
35792
13
        if (!s->allow_bytecode)
35793
0
            goto invalid_tag;
35794
13
        obj = JS_ReadFunctionTag(s);
35795
13
        break;
35796
2
    case BC_TAG_MODULE:
35797
2
        if (!s->allow_bytecode)
35798
0
            goto invalid_tag;
35799
2
        obj = JS_ReadModule(s);
35800
2
        break;
35801
0
    case BC_TAG_OBJECT:
35802
0
        obj = JS_ReadObjectTag(s);
35803
0
        break;
35804
0
    case BC_TAG_ARRAY:
35805
0
    case BC_TAG_TEMPLATE_OBJECT:
35806
0
        obj = JS_ReadArray(s, tag);
35807
0
        break;
35808
0
    case BC_TAG_TYPED_ARRAY:
35809
0
        obj = JS_ReadTypedArray(s);
35810
0
        break;
35811
0
    case BC_TAG_ARRAY_BUFFER:
35812
0
        obj = JS_ReadArrayBuffer(s);
35813
0
        break;
35814
0
    case BC_TAG_SHARED_ARRAY_BUFFER:
35815
0
        if (!s->allow_sab || !ctx->rt->sab_funcs.sab_dup)
35816
0
            goto invalid_tag;
35817
0
        obj = JS_ReadSharedArrayBuffer(s);
35818
0
        break;
35819
0
    case BC_TAG_DATE:
35820
0
        obj = JS_ReadDate(s);
35821
0
        break;
35822
0
    case BC_TAG_OBJECT_VALUE:
35823
0
        obj = JS_ReadObjectValue(s);
35824
0
        break;
35825
0
#ifdef CONFIG_BIGNUM
35826
22
    case BC_TAG_BIG_INT:
35827
22
    case BC_TAG_BIG_FLOAT:
35828
22
    case BC_TAG_BIG_DECIMAL:
35829
22
        obj = JS_ReadBigNum(s, tag);
35830
22
        break;
35831
0
#endif
35832
0
    case BC_TAG_OBJECT_REFERENCE:
35833
0
        {
35834
0
            uint32_t val;
35835
0
            if (!s->allow_reference)
35836
0
                return JS_ThrowSyntaxError(ctx, "object references are not allowed");
35837
0
            if (bc_get_leb128(s, &val))
35838
0
                return JS_EXCEPTION;
35839
0
            bc_read_trace(s, "%u\n", val);
35840
0
            if (val >= s->objects_count) {
35841
0
                return JS_ThrowSyntaxError(ctx, "invalid object reference (%u >= %u)",
35842
0
                                           val, s->objects_count);
35843
0
            }
35844
0
            obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, s->objects[val]));
35845
0
        }
35846
0
        break;
35847
0
    default:
35848
0
    invalid_tag:
35849
0
        return JS_ThrowSyntaxError(ctx, "invalid tag (tag=%d pos=%u)",
35850
0
                                   tag, (unsigned int)(s->ptr - s->buf_start));
35851
61
    }
35852
61
    bc_read_trace(s, "}\n");
35853
61
    return obj;
35854
61
}
35855
35856
static int JS_ReadObjectAtoms(BCReaderState *s)
35857
2
{
35858
2
    uint8_t v8;
35859
2
    JSString *p;
35860
2
    int i;
35861
2
    JSAtom atom;
35862
35863
2
    if (bc_get_u8(s, &v8))
35864
0
        return -1;
35865
    /* XXX: could support byte swapped input */
35866
2
    if (v8 != BC_VERSION) {
35867
0
        JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)",
35868
0
                            v8, BC_VERSION);
35869
0
        return -1;
35870
0
    }
35871
2
    if (bc_get_leb128(s, &s->idx_to_atom_count))
35872
0
        return -1;
35873
35874
2
    bc_read_trace(s, "%d atom indexes {\n", s->idx_to_atom_count);
35875
35876
2
    if (s->idx_to_atom_count != 0) {
35877
2
        s->idx_to_atom = js_mallocz(s->ctx, s->idx_to_atom_count *
35878
2
                                    sizeof(s->idx_to_atom[0]));
35879
2
        if (!s->idx_to_atom)
35880
0
            return s->error_state = -1;
35881
2
    }
35882
101
    for(i = 0; i < s->idx_to_atom_count; i++) {
35883
99
        p = JS_ReadString(s);
35884
99
        if (!p)
35885
0
            return -1;
35886
99
        atom = JS_NewAtomStr(s->ctx, p);
35887
99
        if (atom == JS_ATOM_NULL)
35888
0
            return s->error_state = -1;
35889
99
        s->idx_to_atom[i] = atom;
35890
99
        if (s->is_rom_data && (atom != (i + s->first_atom)))
35891
0
            s->is_rom_data = FALSE; /* atoms must be relocated */
35892
99
    }
35893
2
    bc_read_trace(s, "}\n");
35894
2
    return 0;
35895
2
}
35896
35897
static void bc_reader_free(BCReaderState *s)
35898
2
{
35899
2
    int i;
35900
2
    if (s->idx_to_atom) {
35901
101
        for(i = 0; i < s->idx_to_atom_count; i++) {
35902
99
            JS_FreeAtom(s->ctx, s->idx_to_atom[i]);
35903
99
        }
35904
2
        js_free(s->ctx, s->idx_to_atom);
35905
2
    }
35906
2
    js_free(s->ctx, s->objects);
35907
2
}
35908
35909
JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
35910
                       int flags)
35911
2
{
35912
2
    BCReaderState ss, *s = &ss;
35913
2
    JSValue obj;
35914
35915
2
    ctx->binary_object_count += 1;
35916
2
    ctx->binary_object_size += buf_len;
35917
35918
2
    memset(s, 0, sizeof(*s));
35919
2
    s->ctx = ctx;
35920
2
    s->buf_start = buf;
35921
2
    s->buf_end = buf + buf_len;
35922
2
    s->ptr = buf;
35923
2
    s->allow_bytecode = ((flags & JS_READ_OBJ_BYTECODE) != 0);
35924
2
    s->is_rom_data = ((flags & JS_READ_OBJ_ROM_DATA) != 0);
35925
2
    s->allow_sab = ((flags & JS_READ_OBJ_SAB) != 0);
35926
2
    s->allow_reference = ((flags & JS_READ_OBJ_REFERENCE) != 0);
35927
2
    if (s->allow_bytecode)
35928
2
        s->first_atom = JS_ATOM_END;
35929
0
    else
35930
0
        s->first_atom = 1;
35931
2
    if (JS_ReadObjectAtoms(s)) {
35932
0
        obj = JS_EXCEPTION;
35933
2
    } else {
35934
2
        obj = JS_ReadObjectRec(s);
35935
2
    }
35936
2
    bc_reader_free(s);
35937
2
    return obj;
35938
2
}
35939
35940
/*******************************************************************/
35941
/* runtime functions & objects */
35942
35943
static JSValue js_string_constructor(JSContext *ctx, JSValueConst this_val,
35944
                                     int argc, JSValueConst *argv);
35945
static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst this_val,
35946
                                      int argc, JSValueConst *argv);
35947
static JSValue js_number_constructor(JSContext *ctx, JSValueConst this_val,
35948
                                     int argc, JSValueConst *argv);
35949
35950
static int check_function(JSContext *ctx, JSValueConst obj)
35951
327k
{
35952
327k
    if (likely(JS_IsFunction(ctx, obj)))
35953
327k
        return 0;
35954
0
    JS_ThrowTypeError(ctx, "not a function");
35955
0
    return -1;
35956
327k
}
35957
35958
static int check_exception_free(JSContext *ctx, JSValue obj)
35959
0
{
35960
0
    JS_FreeValue(ctx, obj);
35961
0
    return JS_IsException(obj);
35962
0
}
35963
35964
static JSAtom find_atom(JSContext *ctx, const char *name)
35965
829
{
35966
829
    JSAtom atom;
35967
829
    int len;
35968
35969
829
    if (*name == '[') {
35970
88
        name++;
35971
88
        len = strlen(name) - 1;
35972
        /* We assume 8 bit non null strings, which is the case for these
35973
           symbols */
35974
636
        for(atom = JS_ATOM_Symbol_toPrimitive; atom < JS_ATOM_END; atom++) {
35975
636
            JSAtomStruct *p = ctx->rt->atom_array[atom];
35976
636
            JSString *str = p;
35977
636
            if (str->len == len && !memcmp(str->u.str8, name, len))
35978
88
                return JS_DupAtom(ctx, atom);
35979
636
        }
35980
0
        abort();
35981
741
    } else {
35982
741
        atom = JS_NewAtom(ctx, name);
35983
741
    }
35984
741
    return atom;
35985
829
}
35986
35987
static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
35988
                                               JSAtom atom, void *opaque)
35989
31
{
35990
31
    const JSCFunctionListEntry *e = opaque;
35991
31
    JSValue val;
35992
35993
31
    switch(e->def_type) {
35994
31
    case JS_DEF_CFUNC:
35995
31
        val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
35996
31
                               e->name, e->u.func.length, e->u.func.cproto, e->magic);
35997
31
        break;
35998
0
    case JS_DEF_PROP_STRING:
35999
0
        val = JS_NewAtomString(ctx, e->u.str);
36000
0
        break;
36001
0
    case JS_DEF_OBJECT:
36002
0
        val = JS_NewObject(ctx);
36003
0
        JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
36004
0
        break;
36005
0
    default:
36006
0
        abort();
36007
31
    }
36008
31
    return val;
36009
31
}
36010
36011
static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
36012
                                          JSAtom atom,
36013
                                          const JSCFunctionListEntry *e)
36014
809
{
36015
809
    JSValue val;
36016
809
    int prop_flags = e->prop_flags;
36017
36018
809
    switch(e->def_type) {
36019
20
    case JS_DEF_ALIAS: /* using autoinit for aliases is not safe */
36020
20
        {
36021
20
            JSAtom atom1 = find_atom(ctx, e->u.alias.name);
36022
20
            switch (e->u.alias.base) {
36023
16
            case -1:
36024
16
                val = JS_GetProperty(ctx, obj, atom1);
36025
16
                break;
36026
4
            case 0:
36027
4
                val = JS_GetProperty(ctx, ctx->global_obj, atom1);
36028
4
                break;
36029
0
            case 1:
36030
0
                val = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], atom1);
36031
0
                break;
36032
0
            default:
36033
0
                abort();
36034
20
            }
36035
20
            JS_FreeAtom(ctx, atom1);
36036
20
            if (atom == JS_ATOM_Symbol_toPrimitive) {
36037
                /* Symbol.toPrimitive functions are not writable */
36038
0
                prop_flags = JS_PROP_CONFIGURABLE;
36039
20
            } else if (atom == JS_ATOM_Symbol_hasInstance) {
36040
                /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
36041
0
                prop_flags = 0;
36042
0
            }
36043
20
        }
36044
0
        break;
36045
647
    case JS_DEF_CFUNC:
36046
647
        if (atom == JS_ATOM_Symbol_toPrimitive) {
36047
            /* Symbol.toPrimitive functions are not writable */
36048
4
            prop_flags = JS_PROP_CONFIGURABLE;
36049
643
        } else if (atom == JS_ATOM_Symbol_hasInstance) {
36050
            /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
36051
2
            prop_flags = 0;
36052
2
        }
36053
647
        JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
36054
647
                                  (void *)e, prop_flags);
36055
647
        return 0;
36056
32
    case JS_DEF_CGETSET: /* XXX: use autoinit again ? */
36057
64
    case JS_DEF_CGETSET_MAGIC:
36058
64
        {
36059
64
            JSValue getter, setter;
36060
64
            char buf[64];
36061
36062
64
            getter = JS_UNDEFINED;
36063
64
            if (e->u.getset.get.generic) {
36064
64
                snprintf(buf, sizeof(buf), "get %s", e->name);
36065
64
                getter = JS_NewCFunction2(ctx, e->u.getset.get.generic,
36066
64
                                          buf, 0, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_getter_magic : JS_CFUNC_getter,
36067
64
                                          e->magic);
36068
64
            }
36069
64
            setter = JS_UNDEFINED;
36070
64
            if (e->u.getset.set.generic) {
36071
2
                snprintf(buf, sizeof(buf), "set %s", e->name);
36072
2
                setter = JS_NewCFunction2(ctx, e->u.getset.set.generic,
36073
2
                                          buf, 1, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_setter_magic : JS_CFUNC_setter,
36074
2
                                          e->magic);
36075
2
            }
36076
64
            JS_DefinePropertyGetSet(ctx, obj, atom, getter, setter, prop_flags);
36077
64
            return 0;
36078
32
        }
36079
0
        break;
36080
2
    case JS_DEF_PROP_INT32:
36081
2
        val = JS_NewInt32(ctx, e->u.i32);
36082
2
        break;
36083
0
    case JS_DEF_PROP_INT64:
36084
0
        val = JS_NewInt64(ctx, e->u.i64);
36085
0
        break;
36086
20
    case JS_DEF_PROP_DOUBLE:
36087
20
        val = __JS_NewFloat64(ctx, e->u.f64);
36088
20
        break;
36089
2
    case JS_DEF_PROP_UNDEFINED:
36090
2
        val = JS_UNDEFINED;
36091
2
        break;
36092
46
    case JS_DEF_PROP_STRING:
36093
54
    case JS_DEF_OBJECT:
36094
54
        JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
36095
54
                                  (void *)e, prop_flags);
36096
54
        return 0;
36097
0
    default:
36098
0
        abort();
36099
809
    }
36100
44
    JS_DefinePropertyValue(ctx, obj, atom, val, prop_flags);
36101
44
    return 0;
36102
809
}
36103
36104
void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
36105
                                const JSCFunctionListEntry *tab, int len)
36106
109
{
36107
109
    int i;
36108
36109
918
    for (i = 0; i < len; i++) {
36110
809
        const JSCFunctionListEntry *e = &tab[i];
36111
809
        JSAtom atom = find_atom(ctx, e->name);
36112
809
        JS_InstantiateFunctionListItem(ctx, obj, atom, e);
36113
809
        JS_FreeAtom(ctx, atom);
36114
809
    }
36115
109
}
36116
36117
int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,
36118
                           const JSCFunctionListEntry *tab, int len)
36119
0
{
36120
0
    int i;
36121
0
    for(i = 0; i < len; i++) {
36122
0
        if (JS_AddModuleExport(ctx, m, tab[i].name))
36123
0
            return -1;
36124
0
    }
36125
0
    return 0;
36126
0
}
36127
36128
int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
36129
                           const JSCFunctionListEntry *tab, int len)
36130
0
{
36131
0
    int i;
36132
0
    JSValue val;
36133
36134
0
    for(i = 0; i < len; i++) {
36135
0
        const JSCFunctionListEntry *e = &tab[i];
36136
0
        switch(e->def_type) {
36137
0
        case JS_DEF_CFUNC:
36138
0
            val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
36139
0
                                   e->name, e->u.func.length, e->u.func.cproto, e->magic);
36140
0
            break;
36141
0
        case JS_DEF_PROP_STRING:
36142
0
            val = JS_NewString(ctx, e->u.str);
36143
0
            break;
36144
0
        case JS_DEF_PROP_INT32:
36145
0
            val = JS_NewInt32(ctx, e->u.i32);
36146
0
            break;
36147
0
        case JS_DEF_PROP_INT64:
36148
0
            val = JS_NewInt64(ctx, e->u.i64);
36149
0
            break;
36150
0
        case JS_DEF_PROP_DOUBLE:
36151
0
            val = __JS_NewFloat64(ctx, e->u.f64);
36152
0
            break;
36153
0
        case JS_DEF_OBJECT:
36154
0
            val = JS_NewObject(ctx);
36155
0
            JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
36156
0
            break;
36157
0
        default:
36158
0
            abort();
36159
0
        }
36160
0
        if (JS_SetModuleExport(ctx, m, e->name, val))
36161
0
            return -1;
36162
0
    }
36163
0
    return 0;
36164
0
}
36165
36166
/* Note: 'func_obj' is not necessarily a constructor */
36167
static void JS_SetConstructor2(JSContext *ctx,
36168
                               JSValueConst func_obj,
36169
                               JSValueConst proto,
36170
                               int proto_flags, int ctor_flags)
36171
88
{
36172
88
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype,
36173
88
                           JS_DupValue(ctx, proto), proto_flags);
36174
88
    JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
36175
88
                           JS_DupValue(ctx, func_obj),
36176
88
                           ctor_flags);
36177
88
    set_cycle_flag(ctx, func_obj);
36178
88
    set_cycle_flag(ctx, proto);
36179
88
}
36180
36181
void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, 
36182
                       JSValueConst proto)
36183
78
{
36184
78
    JS_SetConstructor2(ctx, func_obj, proto,
36185
78
                       0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
36186
78
}
36187
36188
static void JS_NewGlobalCConstructor2(JSContext *ctx,
36189
                                      JSValue func_obj,
36190
                                      const char *name,
36191
                                      JSValueConst proto)
36192
76
{
36193
76
    JS_DefinePropertyValueStr(ctx, ctx->global_obj, name,
36194
76
                           JS_DupValue(ctx, func_obj),
36195
76
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
36196
76
    JS_SetConstructor(ctx, func_obj, proto);
36197
76
    JS_FreeValue(ctx, func_obj);
36198
76
}
36199
36200
static JSValueConst JS_NewGlobalCConstructor(JSContext *ctx, const char *name,
36201
                                             JSCFunction *func, int length,
36202
                                             JSValueConst proto)
36203
18
{
36204
18
    JSValue func_obj;
36205
18
    func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor_or_func, 0);
36206
18
    JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
36207
18
    return func_obj;
36208
18
}
36209
36210
static JSValueConst JS_NewGlobalCConstructorOnly(JSContext *ctx, const char *name,
36211
                                                 JSCFunction *func, int length,
36212
                                                 JSValueConst proto)
36213
6
{
36214
6
    JSValue func_obj;
36215
6
    func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor, 0);
36216
6
    JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
36217
6
    return func_obj;
36218
6
}
36219
36220
static JSValue js_global_eval(JSContext *ctx, JSValueConst this_val,
36221
                              int argc, JSValueConst *argv)
36222
0
{
36223
0
    return JS_EvalObject(ctx, ctx->global_obj, argv[0], JS_EVAL_TYPE_INDIRECT, -1);
36224
0
}
36225
36226
static JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val,
36227
                               int argc, JSValueConst *argv)
36228
0
{
36229
0
    double d;
36230
36231
    /* XXX: does this work for bigfloat? */
36232
0
    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
36233
0
        return JS_EXCEPTION;
36234
0
    return JS_NewBool(ctx, isnan(d));
36235
0
}
36236
36237
static JSValue js_global_isFinite(JSContext *ctx, JSValueConst this_val,
36238
                                  int argc, JSValueConst *argv)
36239
0
{
36240
0
    BOOL res;
36241
0
    double d;
36242
0
    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
36243
0
        return JS_EXCEPTION;
36244
0
    res = isfinite(d);
36245
0
    return JS_NewBool(ctx, res);
36246
0
}
36247
36248
/* Object class */
36249
36250
static JSValue JS_ToObject(JSContext *ctx, JSValueConst val)
36251
369k
{
36252
369k
    int tag = JS_VALUE_GET_NORM_TAG(val);
36253
369k
    JSValue obj;
36254
36255
369k
    switch(tag) {
36256
0
    default:
36257
0
    case JS_TAG_NULL:
36258
0
    case JS_TAG_UNDEFINED:
36259
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
36260
369k
    case JS_TAG_OBJECT:
36261
369k
    case JS_TAG_EXCEPTION:
36262
369k
        return JS_DupValue(ctx, val);
36263
0
#ifdef CONFIG_BIGNUM
36264
0
    case JS_TAG_BIG_INT:
36265
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
36266
0
        goto set_value;
36267
0
    case JS_TAG_BIG_FLOAT:
36268
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT);
36269
0
        goto set_value;
36270
0
    case JS_TAG_BIG_DECIMAL:
36271
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_DECIMAL);
36272
0
        goto set_value;
36273
0
#endif
36274
0
    case JS_TAG_INT:
36275
0
    case JS_TAG_FLOAT64:
36276
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
36277
0
        goto set_value;
36278
8
    case JS_TAG_STRING:
36279
        /* XXX: should call the string constructor */
36280
8
        {
36281
8
            JSString *p1 = JS_VALUE_GET_STRING(val);
36282
8
            obj = JS_NewObjectClass(ctx, JS_CLASS_STRING);
36283
8
            JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
36284
8
        }
36285
8
        goto set_value;
36286
20
    case JS_TAG_BOOL:
36287
20
        obj = JS_NewObjectClass(ctx, JS_CLASS_BOOLEAN);
36288
20
        goto set_value;
36289
0
    case JS_TAG_SYMBOL:
36290
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_SYMBOL);
36291
28
    set_value:
36292
28
        if (!JS_IsException(obj))
36293
28
            JS_SetObjectData(ctx, obj, JS_DupValue(ctx, val));
36294
28
        return obj;
36295
369k
    }
36296
369k
}
36297
36298
static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val)
36299
3
{
36300
3
    JSValue obj = JS_ToObject(ctx, val);
36301
3
    JS_FreeValue(ctx, val);
36302
3
    return obj;
36303
3
}
36304
36305
static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
36306
                          JSValueConst desc)
36307
0
{
36308
0
    JSValue val, getter, setter;
36309
0
    int flags;
36310
36311
0
    if (!JS_IsObject(desc)) {
36312
0
        JS_ThrowTypeErrorNotAnObject(ctx);
36313
0
        return -1;
36314
0
    }
36315
0
    flags = 0;
36316
0
    val = JS_UNDEFINED;
36317
0
    getter = JS_UNDEFINED;
36318
0
    setter = JS_UNDEFINED;
36319
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_configurable)) {
36320
0
        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable);
36321
0
        if (JS_IsException(prop))
36322
0
            goto fail;
36323
0
        flags |= JS_PROP_HAS_CONFIGURABLE;
36324
0
        if (JS_ToBoolFree(ctx, prop))
36325
0
            flags |= JS_PROP_CONFIGURABLE;
36326
0
    }
36327
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_writable)) {
36328
0
        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable);
36329
0
        if (JS_IsException(prop))
36330
0
            goto fail;
36331
0
        flags |= JS_PROP_HAS_WRITABLE;
36332
0
        if (JS_ToBoolFree(ctx, prop))
36333
0
            flags |= JS_PROP_WRITABLE;
36334
0
    }
36335
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_enumerable)) {
36336
0
        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable);
36337
0
        if (JS_IsException(prop))
36338
0
            goto fail;
36339
0
        flags |= JS_PROP_HAS_ENUMERABLE;
36340
0
        if (JS_ToBoolFree(ctx, prop))
36341
0
            flags |= JS_PROP_ENUMERABLE;
36342
0
    }
36343
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_value)) {
36344
0
        flags |= JS_PROP_HAS_VALUE;
36345
0
        val = JS_GetProperty(ctx, desc, JS_ATOM_value);
36346
0
        if (JS_IsException(val))
36347
0
            goto fail;
36348
0
    }
36349
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_get)) {
36350
0
        flags |= JS_PROP_HAS_GET;
36351
0
        getter = JS_GetProperty(ctx, desc, JS_ATOM_get);
36352
0
        if (JS_IsException(getter) ||
36353
0
            !(JS_IsUndefined(getter) || JS_IsFunction(ctx, getter))) {
36354
0
            JS_ThrowTypeError(ctx, "invalid getter");
36355
0
            goto fail;
36356
0
        }
36357
0
    }
36358
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_set)) {
36359
0
        flags |= JS_PROP_HAS_SET;
36360
0
        setter = JS_GetProperty(ctx, desc, JS_ATOM_set);
36361
0
        if (JS_IsException(setter) ||
36362
0
            !(JS_IsUndefined(setter) || JS_IsFunction(ctx, setter))) {
36363
0
            JS_ThrowTypeError(ctx, "invalid setter");
36364
0
            goto fail;
36365
0
        }
36366
0
    }
36367
0
    if ((flags & (JS_PROP_HAS_SET | JS_PROP_HAS_GET)) &&
36368
0
        (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE))) {
36369
0
        JS_ThrowTypeError(ctx, "cannot have setter/getter and value or writable");
36370
0
        goto fail;
36371
0
    }
36372
0
    d->flags = flags;
36373
0
    d->value = val;
36374
0
    d->getter = getter;
36375
0
    d->setter = setter;
36376
0
    return 0;
36377
0
 fail:
36378
0
    JS_FreeValue(ctx, val);
36379
0
    JS_FreeValue(ctx, getter);
36380
0
    JS_FreeValue(ctx, setter);
36381
0
    return -1;
36382
0
}
36383
36384
static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
36385
                                             JSAtom prop, JSValueConst desc,
36386
                                             int flags)
36387
0
{
36388
0
    JSPropertyDescriptor d;
36389
0
    int ret;
36390
36391
0
    if (js_obj_to_desc(ctx, &d, desc) < 0)
36392
0
        return -1;
36393
36394
0
    ret = JS_DefineProperty(ctx, obj, prop,
36395
0
                            d.value, d.getter, d.setter, d.flags | flags);
36396
0
    js_free_desc(ctx, &d);
36397
0
    return ret;
36398
0
}
36399
36400
static __exception int JS_ObjectDefineProperties(JSContext *ctx,
36401
                                                 JSValueConst obj,
36402
                                                 JSValueConst properties)
36403
0
{
36404
0
    JSValue props, desc;
36405
0
    JSObject *p;
36406
0
    JSPropertyEnum *atoms;
36407
0
    uint32_t len, i;
36408
0
    int ret = -1;
36409
36410
0
    if (!JS_IsObject(obj)) {
36411
0
        JS_ThrowTypeErrorNotAnObject(ctx);
36412
0
        return -1;
36413
0
    }
36414
0
    desc = JS_UNDEFINED;
36415
0
    props = JS_ToObject(ctx, properties);
36416
0
    if (JS_IsException(props))
36417
0
        return -1;
36418
0
    p = JS_VALUE_GET_OBJ(props);
36419
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) < 0)
36420
0
        goto exception;
36421
0
    for(i = 0; i < len; i++) {
36422
0
        JS_FreeValue(ctx, desc);
36423
0
        desc = JS_GetProperty(ctx, props, atoms[i].atom);
36424
0
        if (JS_IsException(desc))
36425
0
            goto exception;
36426
0
        if (JS_DefinePropertyDesc(ctx, obj, atoms[i].atom, desc, JS_PROP_THROW) < 0)
36427
0
            goto exception;
36428
0
    }
36429
0
    ret = 0;
36430
36431
0
exception:
36432
0
    js_free_prop_enum(ctx, atoms, len);
36433
0
    JS_FreeValue(ctx, props);
36434
0
    JS_FreeValue(ctx, desc);
36435
0
    return ret;
36436
0
}
36437
36438
static JSValue js_object_constructor(JSContext *ctx, JSValueConst new_target,
36439
                                     int argc, JSValueConst *argv)
36440
0
{
36441
0
    JSValue ret;
36442
0
    if (!JS_IsUndefined(new_target) &&
36443
0
        JS_VALUE_GET_OBJ(new_target) !=
36444
0
        JS_VALUE_GET_OBJ(JS_GetActiveFunction(ctx))) {
36445
0
        ret = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
36446
0
    } else {
36447
0
        int tag = JS_VALUE_GET_NORM_TAG(argv[0]);
36448
0
        switch(tag) {
36449
0
        case JS_TAG_NULL:
36450
0
        case JS_TAG_UNDEFINED:
36451
0
            ret = JS_NewObject(ctx);
36452
0
            break;
36453
0
        default:
36454
0
            ret = JS_ToObject(ctx, argv[0]);
36455
0
            break;
36456
0
        }
36457
0
    }
36458
0
    return ret;
36459
0
}
36460
36461
static JSValue js_object_create(JSContext *ctx, JSValueConst this_val,
36462
                                int argc, JSValueConst *argv)
36463
0
{
36464
0
    JSValueConst proto, props;
36465
0
    JSValue obj;
36466
36467
0
    proto = argv[0];
36468
0
    if (!JS_IsObject(proto) && !JS_IsNull(proto))
36469
0
        return JS_ThrowTypeError(ctx, "not a prototype");
36470
0
    obj = JS_NewObjectProto(ctx, proto);
36471
0
    if (JS_IsException(obj))
36472
0
        return JS_EXCEPTION;
36473
0
    props = argv[1];
36474
0
    if (!JS_IsUndefined(props)) {
36475
0
        if (JS_ObjectDefineProperties(ctx, obj, props)) {
36476
0
            JS_FreeValue(ctx, obj);
36477
0
            return JS_EXCEPTION;
36478
0
        }
36479
0
    }
36480
0
    return obj;
36481
0
}
36482
36483
static JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val,
36484
                                        int argc, JSValueConst *argv, int magic)
36485
0
{
36486
0
    JSValueConst val;
36487
36488
0
    val = argv[0];
36489
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) {
36490
        /* ES6 feature non compatible with ES5.1: primitive types are
36491
           accepted */
36492
0
        if (magic || JS_VALUE_GET_TAG(val) == JS_TAG_NULL ||
36493
0
            JS_VALUE_GET_TAG(val) == JS_TAG_UNDEFINED)
36494
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
36495
0
    }
36496
0
    return JS_GetPrototype(ctx, val);
36497
0
}
36498
36499
static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
36500
                                        int argc, JSValueConst *argv)
36501
0
{
36502
0
    JSValueConst obj;
36503
0
    obj = argv[0];
36504
0
    if (JS_SetPrototypeInternal(ctx, obj, argv[1], TRUE) < 0)
36505
0
        return JS_EXCEPTION;
36506
0
    return JS_DupValue(ctx, obj);
36507
0
}
36508
36509
/* magic = 1 if called as Reflect.defineProperty */
36510
static JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val,
36511
                                        int argc, JSValueConst *argv, int magic)
36512
0
{
36513
0
    JSValueConst obj, prop, desc;
36514
0
    int ret, flags;
36515
0
    JSAtom atom;
36516
36517
0
    obj = argv[0];
36518
0
    prop = argv[1];
36519
0
    desc = argv[2];
36520
36521
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
36522
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
36523
0
    atom = JS_ValueToAtom(ctx, prop);
36524
0
    if (unlikely(atom == JS_ATOM_NULL))
36525
0
        return JS_EXCEPTION;
36526
0
    flags = 0;
36527
0
    if (!magic)
36528
0
        flags |= JS_PROP_THROW;
36529
0
    ret = JS_DefinePropertyDesc(ctx, obj, atom, desc, flags);
36530
0
    JS_FreeAtom(ctx, atom);
36531
0
    if (ret < 0) {
36532
0
        return JS_EXCEPTION;
36533
0
    } else if (magic) {
36534
0
        return JS_NewBool(ctx, ret);
36535
0
    } else {
36536
0
        return JS_DupValue(ctx, obj);
36537
0
    }
36538
0
}
36539
36540
static JSValue js_object_defineProperties(JSContext *ctx, JSValueConst this_val,
36541
                                          int argc, JSValueConst *argv)
36542
0
{
36543
    // defineProperties(obj, properties)
36544
0
    JSValueConst obj = argv[0];
36545
36546
0
    if (JS_ObjectDefineProperties(ctx, obj, argv[1]))
36547
0
        return JS_EXCEPTION;
36548
0
    else
36549
0
        return JS_DupValue(ctx, obj);
36550
0
}
36551
36552
/* magic = 1 if called as __defineSetter__ */
36553
static JSValue js_object___defineGetter__(JSContext *ctx, JSValueConst this_val,
36554
                                          int argc, JSValueConst *argv, int magic)
36555
0
{
36556
0
    JSValue obj;
36557
0
    JSValueConst prop, value, get, set;
36558
0
    int ret, flags;
36559
0
    JSAtom atom;
36560
36561
0
    prop = argv[0];
36562
0
    value = argv[1];
36563
36564
0
    obj = JS_ToObject(ctx, this_val);
36565
0
    if (JS_IsException(obj))
36566
0
        return JS_EXCEPTION;
36567
36568
0
    if (check_function(ctx, value)) {
36569
0
        JS_FreeValue(ctx, obj);
36570
0
        return JS_EXCEPTION;
36571
0
    }
36572
0
    atom = JS_ValueToAtom(ctx, prop);
36573
0
    if (unlikely(atom == JS_ATOM_NULL)) {
36574
0
        JS_FreeValue(ctx, obj);
36575
0
        return JS_EXCEPTION;
36576
0
    }
36577
0
    flags = JS_PROP_THROW |
36578
0
        JS_PROP_HAS_ENUMERABLE | JS_PROP_ENUMERABLE |
36579
0
        JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE;
36580
0
    if (magic) {
36581
0
        get = JS_UNDEFINED;
36582
0
        set = value;
36583
0
        flags |= JS_PROP_HAS_SET;
36584
0
    } else {
36585
0
        get = value;
36586
0
        set = JS_UNDEFINED;
36587
0
        flags |= JS_PROP_HAS_GET;
36588
0
    }
36589
0
    ret = JS_DefineProperty(ctx, obj, atom, JS_UNDEFINED, get, set, flags);
36590
0
    JS_FreeValue(ctx, obj);
36591
0
    JS_FreeAtom(ctx, atom);
36592
0
    if (ret < 0) {
36593
0
        return JS_EXCEPTION;
36594
0
    } else {
36595
0
        return JS_UNDEFINED;
36596
0
    }
36597
0
}
36598
36599
static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst this_val,
36600
                                                  int argc, JSValueConst *argv, int magic)
36601
0
{
36602
0
    JSValueConst prop;
36603
0
    JSAtom atom;
36604
0
    JSValue ret, obj;
36605
0
    JSPropertyDescriptor desc;
36606
0
    int res, flags;
36607
36608
0
    if (magic) {
36609
        /* Reflect.getOwnPropertyDescriptor case */
36610
0
        if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
36611
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
36612
0
        obj = JS_DupValue(ctx, argv[0]);
36613
0
    } else {
36614
0
        obj = JS_ToObject(ctx, argv[0]);
36615
0
        if (JS_IsException(obj))
36616
0
            return obj;
36617
0
    }
36618
0
    prop = argv[1];
36619
0
    atom = JS_ValueToAtom(ctx, prop);
36620
0
    if (unlikely(atom == JS_ATOM_NULL))
36621
0
        goto exception;
36622
0
    ret = JS_UNDEFINED;
36623
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
36624
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), atom);
36625
0
        if (res < 0)
36626
0
            goto exception;
36627
0
        if (res) {
36628
0
            ret = JS_NewObject(ctx);
36629
0
            if (JS_IsException(ret))
36630
0
                goto exception1;
36631
0
            flags = JS_PROP_C_W_E | JS_PROP_THROW;
36632
0
            if (desc.flags & JS_PROP_GETSET) {
36633
0
                if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, desc.getter), flags) < 0
36634
0
                ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, desc.setter), flags) < 0)
36635
0
                    goto exception1;
36636
0
            } else {
36637
0
                if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, desc.value), flags) < 0
36638
0
                ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
36639
0
                                           JS_NewBool(ctx, (desc.flags & JS_PROP_WRITABLE) != 0), flags) < 0)
36640
0
                    goto exception1;
36641
0
            }
36642
0
            if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
36643
0
                                       JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0), flags) < 0
36644
0
            ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
36645
0
                                       JS_NewBool(ctx, (desc.flags & JS_PROP_CONFIGURABLE) != 0), flags) < 0)
36646
0
                goto exception1;
36647
0
            js_free_desc(ctx, &desc);
36648
0
        }
36649
0
    }
36650
0
    JS_FreeAtom(ctx, atom);
36651
0
    JS_FreeValue(ctx, obj);
36652
0
    return ret;
36653
36654
0
exception1:
36655
0
    js_free_desc(ctx, &desc);
36656
0
    JS_FreeValue(ctx, ret);
36657
0
exception:
36658
0
    JS_FreeAtom(ctx, atom);
36659
0
    JS_FreeValue(ctx, obj);
36660
0
    return JS_EXCEPTION;
36661
0
}
36662
36663
static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst this_val,
36664
                                                   int argc, JSValueConst *argv)
36665
0
{
36666
    //getOwnPropertyDescriptors(obj)
36667
0
    JSValue obj, r;
36668
0
    JSObject *p;
36669
0
    JSPropertyEnum *props;
36670
0
    uint32_t len, i;
36671
36672
0
    r = JS_UNDEFINED;
36673
0
    obj = JS_ToObject(ctx, argv[0]);
36674
0
    if (JS_IsException(obj))
36675
0
        return JS_EXCEPTION;
36676
36677
0
    p = JS_VALUE_GET_OBJ(obj);
36678
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p,
36679
0
                               JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
36680
0
        goto exception;
36681
0
    r = JS_NewObject(ctx);
36682
0
    if (JS_IsException(r))
36683
0
        goto exception;
36684
0
    for(i = 0; i < len; i++) {
36685
0
        JSValue atomValue, desc;
36686
0
        JSValueConst args[2];
36687
36688
0
        atomValue = JS_AtomToValue(ctx, props[i].atom);
36689
0
        if (JS_IsException(atomValue))
36690
0
            goto exception;
36691
0
        args[0] = obj;
36692
0
        args[1] = atomValue;
36693
0
        desc = js_object_getOwnPropertyDescriptor(ctx, JS_UNDEFINED, 2, args, 0);
36694
0
        JS_FreeValue(ctx, atomValue);
36695
0
        if (JS_IsException(desc))
36696
0
            goto exception;
36697
0
        if (!JS_IsUndefined(desc)) {
36698
0
            if (JS_DefinePropertyValue(ctx, r, props[i].atom, desc,
36699
0
                                       JS_PROP_C_W_E | JS_PROP_THROW) < 0)
36700
0
                goto exception;
36701
0
        }
36702
0
    }
36703
0
    js_free_prop_enum(ctx, props, len);
36704
0
    JS_FreeValue(ctx, obj);
36705
0
    return r;
36706
36707
0
exception:
36708
0
    js_free_prop_enum(ctx, props, len);
36709
0
    JS_FreeValue(ctx, obj);
36710
0
    JS_FreeValue(ctx, r);
36711
0
    return JS_EXCEPTION;
36712
0
}
36713
36714
static JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValueConst obj1,
36715
                                       int flags, int kind)
36716
0
{
36717
0
    JSValue obj, r, val, key, value;
36718
0
    JSObject *p;
36719
0
    JSPropertyEnum *atoms;
36720
0
    uint32_t len, i, j;
36721
36722
0
    r = JS_UNDEFINED;
36723
0
    val = JS_UNDEFINED;
36724
0
    obj = JS_ToObject(ctx, obj1);
36725
0
    if (JS_IsException(obj))
36726
0
        return JS_EXCEPTION;
36727
0
    p = JS_VALUE_GET_OBJ(obj);
36728
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, flags & ~JS_GPN_ENUM_ONLY))
36729
0
        goto exception;
36730
0
    r = JS_NewArray(ctx);
36731
0
    if (JS_IsException(r))
36732
0
        goto exception;
36733
0
    for(j = i = 0; i < len; i++) {
36734
0
        JSAtom atom = atoms[i].atom;
36735
0
        if (flags & JS_GPN_ENUM_ONLY) {
36736
0
            JSPropertyDescriptor desc;
36737
0
            int res;
36738
36739
            /* Check if property is still enumerable */
36740
0
            res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
36741
0
            if (res < 0)
36742
0
                goto exception;
36743
0
            if (!res)
36744
0
                continue;
36745
0
            js_free_desc(ctx, &desc);
36746
0
            if (!(desc.flags & JS_PROP_ENUMERABLE))
36747
0
                continue;
36748
0
        }
36749
0
        switch(kind) {
36750
0
        default:
36751
0
        case JS_ITERATOR_KIND_KEY:
36752
0
            val = JS_AtomToValue(ctx, atom);
36753
0
            if (JS_IsException(val))
36754
0
                goto exception;
36755
0
            break;
36756
0
        case JS_ITERATOR_KIND_VALUE:
36757
0
            val = JS_GetProperty(ctx, obj, atom);
36758
0
            if (JS_IsException(val))
36759
0
                goto exception;
36760
0
            break;
36761
0
        case JS_ITERATOR_KIND_KEY_AND_VALUE:
36762
0
            val = JS_NewArray(ctx);
36763
0
            if (JS_IsException(val))
36764
0
                goto exception;
36765
0
            key = JS_AtomToValue(ctx, atom);
36766
0
            if (JS_IsException(key))
36767
0
                goto exception1;
36768
0
            if (JS_CreateDataPropertyUint32(ctx, val, 0, key, JS_PROP_THROW) < 0)
36769
0
                goto exception1;
36770
0
            value = JS_GetProperty(ctx, obj, atom);
36771
0
            if (JS_IsException(value))
36772
0
                goto exception1;
36773
0
            if (JS_CreateDataPropertyUint32(ctx, val, 1, value, JS_PROP_THROW) < 0)
36774
0
                goto exception1;
36775
0
            break;
36776
0
        }
36777
0
        if (JS_CreateDataPropertyUint32(ctx, r, j++, val, 0) < 0)
36778
0
            goto exception;
36779
0
    }
36780
0
    goto done;
36781
36782
0
exception1:
36783
0
    JS_FreeValue(ctx, val);
36784
0
exception:
36785
0
    JS_FreeValue(ctx, r);
36786
0
    r = JS_EXCEPTION;
36787
0
done:
36788
0
    js_free_prop_enum(ctx, atoms, len);
36789
0
    JS_FreeValue(ctx, obj);
36790
0
    return r;
36791
0
}
36792
36793
static JSValue js_object_getOwnPropertyNames(JSContext *ctx, JSValueConst this_val,
36794
                                             int argc, JSValueConst *argv)
36795
0
{
36796
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
36797
0
                                   JS_GPN_STRING_MASK, JS_ITERATOR_KIND_KEY);
36798
0
}
36799
36800
static JSValue js_object_getOwnPropertySymbols(JSContext *ctx, JSValueConst this_val,
36801
                                             int argc, JSValueConst *argv)
36802
0
{
36803
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
36804
0
                                   JS_GPN_SYMBOL_MASK, JS_ITERATOR_KIND_KEY);
36805
0
}
36806
36807
static JSValue js_object_keys(JSContext *ctx, JSValueConst this_val,
36808
                              int argc, JSValueConst *argv, int kind)
36809
0
{
36810
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
36811
0
                                   JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK, kind);
36812
0
}
36813
36814
static JSValue js_object_isExtensible(JSContext *ctx, JSValueConst this_val,
36815
                                      int argc, JSValueConst *argv, int reflect)
36816
0
{
36817
0
    JSValueConst obj;
36818
0
    int ret;
36819
36820
0
    obj = argv[0];
36821
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
36822
0
        if (reflect)
36823
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
36824
0
        else
36825
0
            return JS_FALSE;
36826
0
    }
36827
0
    ret = JS_IsExtensible(ctx, obj);
36828
0
    if (ret < 0)
36829
0
        return JS_EXCEPTION;
36830
0
    else
36831
0
        return JS_NewBool(ctx, ret);
36832
0
}
36833
36834
static JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val,
36835
                                           int argc, JSValueConst *argv, int reflect)
36836
0
{
36837
0
    JSValueConst obj;
36838
0
    int ret;
36839
36840
0
    obj = argv[0];
36841
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
36842
0
        if (reflect)
36843
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
36844
0
        else
36845
0
            return JS_DupValue(ctx, obj);
36846
0
    }
36847
0
    ret = JS_PreventExtensions(ctx, obj);
36848
0
    if (ret < 0)
36849
0
        return JS_EXCEPTION;
36850
0
    if (reflect) {
36851
0
        return JS_NewBool(ctx, ret);
36852
0
    } else {
36853
0
        if (!ret)
36854
0
            return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
36855
0
        return JS_DupValue(ctx, obj);
36856
0
    }
36857
0
}
36858
36859
static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,
36860
                                        int argc, JSValueConst *argv)
36861
0
{
36862
0
    JSValue obj;
36863
0
    JSAtom atom;
36864
0
    JSObject *p;
36865
0
    BOOL ret;
36866
36867
0
    atom = JS_ValueToAtom(ctx, argv[0]); /* must be done first */
36868
0
    if (unlikely(atom == JS_ATOM_NULL))
36869
0
        return JS_EXCEPTION;
36870
0
    obj = JS_ToObject(ctx, this_val);
36871
0
    if (JS_IsException(obj)) {
36872
0
        JS_FreeAtom(ctx, atom);
36873
0
        return obj;
36874
0
    }
36875
0
    p = JS_VALUE_GET_OBJ(obj);
36876
0
    ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
36877
0
    JS_FreeAtom(ctx, atom);
36878
0
    JS_FreeValue(ctx, obj);
36879
0
    if (ret < 0)
36880
0
        return JS_EXCEPTION;
36881
0
    else
36882
0
        return JS_NewBool(ctx, ret);
36883
0
}
36884
36885
static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val,
36886
                                int argc, JSValueConst *argv)
36887
0
{
36888
0
    JSValue obj;
36889
0
    JSAtom atom;
36890
0
    JSObject *p;
36891
0
    BOOL ret;
36892
36893
0
    obj = JS_ToObject(ctx, argv[0]);
36894
0
    if (JS_IsException(obj))
36895
0
        return obj;
36896
0
    atom = JS_ValueToAtom(ctx, argv[1]);
36897
0
    if (unlikely(atom == JS_ATOM_NULL)) {
36898
0
        JS_FreeValue(ctx, obj);
36899
0
        return JS_EXCEPTION;
36900
0
    }
36901
0
    p = JS_VALUE_GET_OBJ(obj);
36902
0
    ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
36903
0
    JS_FreeAtom(ctx, atom);
36904
0
    JS_FreeValue(ctx, obj);
36905
0
    if (ret < 0)
36906
0
        return JS_EXCEPTION;
36907
0
    else
36908
0
        return JS_NewBool(ctx, ret);
36909
0
}
36910
36911
static JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val,
36912
                                 int argc, JSValueConst *argv)
36913
225k
{
36914
225k
    return JS_ToObject(ctx, this_val);
36915
225k
}
36916
36917
static JSValue js_object_toString(JSContext *ctx, JSValueConst this_val,
36918
                                  int argc, JSValueConst *argv)
36919
143k
{
36920
143k
    JSValue obj, tag;
36921
143k
    int is_array;
36922
143k
    JSAtom atom;
36923
143k
    JSObject *p;
36924
36925
143k
    if (JS_IsNull(this_val)) {
36926
0
        tag = JS_NewString(ctx, "Null");
36927
143k
    } else if (JS_IsUndefined(this_val)) {
36928
0
        tag = JS_NewString(ctx, "Undefined");
36929
143k
    } else {
36930
143k
        obj = JS_ToObject(ctx, this_val);
36931
143k
        if (JS_IsException(obj))
36932
0
            return obj;
36933
143k
        is_array = JS_IsArray(ctx, obj);
36934
143k
        if (is_array < 0) {
36935
0
            JS_FreeValue(ctx, obj);
36936
0
            return JS_EXCEPTION;
36937
0
        }
36938
143k
        if (is_array) {
36939
0
            atom = JS_ATOM_Array;
36940
143k
        } else if (JS_IsFunction(ctx, obj)) {
36941
0
            atom = JS_ATOM_Function;
36942
143k
        } else {
36943
143k
            p = JS_VALUE_GET_OBJ(obj);
36944
143k
            switch(p->class_id) {
36945
0
            case JS_CLASS_STRING:
36946
0
            case JS_CLASS_ARGUMENTS:
36947
0
            case JS_CLASS_MAPPED_ARGUMENTS:
36948
0
            case JS_CLASS_ERROR:
36949
0
            case JS_CLASS_BOOLEAN:
36950
0
            case JS_CLASS_NUMBER:
36951
0
            case JS_CLASS_DATE:
36952
0
            case JS_CLASS_REGEXP:
36953
0
                atom = ctx->rt->class_array[p->class_id].class_name;
36954
0
                break;
36955
143k
            default:
36956
143k
                atom = JS_ATOM_Object;
36957
143k
                break;
36958
143k
            }
36959
143k
        }
36960
143k
        tag = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_toStringTag);
36961
143k
        JS_FreeValue(ctx, obj);
36962
143k
        if (JS_IsException(tag))
36963
0
            return JS_EXCEPTION;
36964
143k
        if (!JS_IsString(tag)) {
36965
143k
            JS_FreeValue(ctx, tag);
36966
143k
            tag = JS_AtomToString(ctx, atom);
36967
143k
        }
36968
143k
    }
36969
143k
    return JS_ConcatString3(ctx, "[object ", tag, "]");
36970
143k
}
36971
36972
static JSValue js_object_toLocaleString(JSContext *ctx, JSValueConst this_val,
36973
                                        int argc, JSValueConst *argv)
36974
0
{
36975
0
    return JS_Invoke(ctx, this_val, JS_ATOM_toString, 0, NULL);
36976
0
}
36977
36978
static JSValue js_object_assign(JSContext *ctx, JSValueConst this_val,
36979
                                int argc, JSValueConst *argv)
36980
0
{
36981
    // Object.assign(obj, source1)
36982
0
    JSValue obj, s;
36983
0
    int i;
36984
36985
0
    s = JS_UNDEFINED;
36986
0
    obj = JS_ToObject(ctx, argv[0]);
36987
0
    if (JS_IsException(obj))
36988
0
        goto exception;
36989
0
    for (i = 1; i < argc; i++) {
36990
0
        if (!JS_IsNull(argv[i]) && !JS_IsUndefined(argv[i])) {
36991
0
            s = JS_ToObject(ctx, argv[i]);
36992
0
            if (JS_IsException(s))
36993
0
                goto exception;
36994
0
            if (JS_CopyDataProperties(ctx, obj, s, JS_UNDEFINED, TRUE))
36995
0
                goto exception;
36996
0
            JS_FreeValue(ctx, s);
36997
0
        }
36998
0
    }
36999
0
    return obj;
37000
0
exception:
37001
0
    JS_FreeValue(ctx, obj);
37002
0
    JS_FreeValue(ctx, s);
37003
0
    return JS_EXCEPTION;
37004
0
}
37005
37006
static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val,
37007
                              int argc, JSValueConst *argv, int freeze_flag)
37008
2
{
37009
2
    JSValueConst obj = argv[0];
37010
2
    JSObject *p;
37011
2
    JSPropertyEnum *props;
37012
2
    uint32_t len, i;
37013
2
    int flags, desc_flags, res;
37014
37015
2
    if (!JS_IsObject(obj))
37016
0
        return JS_DupValue(ctx, obj);
37017
37018
2
    res = JS_PreventExtensions(ctx, obj);
37019
2
    if (res < 0)
37020
0
        return JS_EXCEPTION;
37021
2
    if (!res) {
37022
0
        return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
37023
0
    }
37024
    
37025
2
    p = JS_VALUE_GET_OBJ(obj);
37026
2
    flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
37027
2
    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
37028
0
        return JS_EXCEPTION;
37029
37030
6
    for(i = 0; i < len; i++) {
37031
4
        JSPropertyDescriptor desc;
37032
4
        JSAtom prop = props[i].atom;
37033
37034
4
        desc_flags = JS_PROP_THROW | JS_PROP_HAS_CONFIGURABLE;
37035
4
        if (freeze_flag) {
37036
4
            res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
37037
4
            if (res < 0)
37038
0
                goto exception;
37039
4
            if (res) {
37040
4
                if (desc.flags & JS_PROP_WRITABLE)
37041
0
                    desc_flags |= JS_PROP_HAS_WRITABLE;
37042
4
                js_free_desc(ctx, &desc);
37043
4
            }
37044
4
        }
37045
4
        if (JS_DefineProperty(ctx, obj, prop, JS_UNDEFINED,
37046
4
                              JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0)
37047
0
            goto exception;
37048
4
    }
37049
2
    js_free_prop_enum(ctx, props, len);
37050
2
    return JS_DupValue(ctx, obj);
37051
37052
0
 exception:
37053
0
    js_free_prop_enum(ctx, props, len);
37054
0
    return JS_EXCEPTION;
37055
2
}
37056
37057
static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val,
37058
                                  int argc, JSValueConst *argv, int is_frozen)
37059
0
{
37060
0
    JSValueConst obj = argv[0];
37061
0
    JSObject *p;
37062
0
    JSPropertyEnum *props;
37063
0
    uint32_t len, i;
37064
0
    int flags, res;
37065
    
37066
0
    if (!JS_IsObject(obj))
37067
0
        return JS_TRUE;
37068
37069
0
    p = JS_VALUE_GET_OBJ(obj);
37070
0
    flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
37071
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
37072
0
        return JS_EXCEPTION;
37073
37074
0
    for(i = 0; i < len; i++) {
37075
0
        JSPropertyDescriptor desc;
37076
0
        JSAtom prop = props[i].atom;
37077
37078
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
37079
0
        if (res < 0)
37080
0
            goto exception;
37081
0
        if (res) {
37082
0
            js_free_desc(ctx, &desc);
37083
0
            if ((desc.flags & JS_PROP_CONFIGURABLE)
37084
0
            ||  (is_frozen && (desc.flags & JS_PROP_WRITABLE))) {
37085
0
                res = FALSE;
37086
0
                goto done;
37087
0
            }
37088
0
        }
37089
0
    }
37090
0
    res = JS_IsExtensible(ctx, obj);
37091
0
    if (res < 0)
37092
0
        return JS_EXCEPTION;
37093
0
    res ^= 1;
37094
0
done:        
37095
0
    js_free_prop_enum(ctx, props, len);
37096
0
    return JS_NewBool(ctx, res);
37097
37098
0
exception:
37099
0
    js_free_prop_enum(ctx, props, len);
37100
0
    return JS_EXCEPTION;
37101
0
}
37102
37103
static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val,
37104
                                     int argc, JSValueConst *argv)
37105
0
{
37106
0
    JSValue obj, iter, next_method = JS_UNDEFINED;
37107
0
    JSValueConst iterable;
37108
0
    BOOL done;
37109
37110
    /*  RequireObjectCoercible() not necessary because it is tested in
37111
        JS_GetIterator() by JS_GetProperty() */
37112
0
    iterable = argv[0];
37113
37114
0
    obj = JS_NewObject(ctx);
37115
0
    if (JS_IsException(obj))
37116
0
        return obj;
37117
    
37118
0
    iter = JS_GetIterator(ctx, iterable, FALSE);
37119
0
    if (JS_IsException(iter))
37120
0
        goto fail;
37121
0
    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
37122
0
    if (JS_IsException(next_method))
37123
0
        goto fail;
37124
    
37125
0
    for(;;) {
37126
0
        JSValue key, value, item;
37127
0
        item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
37128
0
        if (JS_IsException(item))
37129
0
            goto fail;
37130
0
        if (done) {
37131
0
            JS_FreeValue(ctx, item);
37132
0
            break;
37133
0
        }
37134
        
37135
0
        key = JS_UNDEFINED;
37136
0
        value = JS_UNDEFINED;
37137
0
        if (!JS_IsObject(item)) {
37138
0
            JS_ThrowTypeErrorNotAnObject(ctx);
37139
0
            goto fail1;
37140
0
        }
37141
0
        key = JS_GetPropertyUint32(ctx, item, 0);
37142
0
        if (JS_IsException(key))
37143
0
            goto fail1;
37144
0
        value = JS_GetPropertyUint32(ctx, item, 1);
37145
0
        if (JS_IsException(value)) {
37146
0
            JS_FreeValue(ctx, key);
37147
0
            goto fail1;
37148
0
        }
37149
0
        if (JS_DefinePropertyValueValue(ctx, obj, key, value,
37150
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0) {
37151
0
        fail1:
37152
0
            JS_FreeValue(ctx, item);
37153
0
            goto fail;
37154
0
        }
37155
0
        JS_FreeValue(ctx, item);
37156
0
    }
37157
0
    JS_FreeValue(ctx, next_method);
37158
0
    JS_FreeValue(ctx, iter);
37159
0
    return obj;
37160
0
 fail:
37161
0
    if (JS_IsObject(iter)) {
37162
        /* close the iterator object, preserving pending exception */
37163
0
        JS_IteratorClose(ctx, iter, TRUE);
37164
0
    }
37165
0
    JS_FreeValue(ctx, next_method);
37166
0
    JS_FreeValue(ctx, iter);
37167
0
    JS_FreeValue(ctx, obj);
37168
0
    return JS_EXCEPTION;
37169
0
}
37170
37171
#if 0
37172
/* Note: corresponds to ECMA spec: CreateDataPropertyOrThrow() */
37173
static JSValue js_object___setOwnProperty(JSContext *ctx, JSValueConst this_val,
37174
                                          int argc, JSValueConst *argv)
37175
{
37176
    int ret;
37177
    ret = JS_DefinePropertyValueValue(ctx, argv[0], JS_DupValue(ctx, argv[1]),
37178
                                      JS_DupValue(ctx, argv[2]),
37179
                                      JS_PROP_C_W_E | JS_PROP_THROW);
37180
    if (ret < 0)
37181
        return JS_EXCEPTION;
37182
    else
37183
        return JS_NewBool(ctx, ret);
37184
}
37185
37186
static JSValue js_object___toObject(JSContext *ctx, JSValueConst this_val,
37187
                                    int argc, JSValueConst *argv)
37188
{
37189
    return JS_ToObject(ctx, argv[0]);
37190
}
37191
37192
static JSValue js_object___toPrimitive(JSContext *ctx, JSValueConst this_val,
37193
                                       int argc, JSValueConst *argv)
37194
{
37195
    int hint = HINT_NONE;
37196
37197
    if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_INT)
37198
        hint = JS_VALUE_GET_INT(argv[1]);
37199
37200
    return JS_ToPrimitive(ctx, argv[0], hint);
37201
}
37202
#endif
37203
37204
/* return an empty string if not an object */
37205
static JSValue js_object___getClass(JSContext *ctx, JSValueConst this_val,
37206
                                    int argc, JSValueConst *argv)
37207
0
{
37208
0
    JSAtom atom;
37209
0
    JSObject *p;
37210
0
    uint32_t tag;
37211
0
    int class_id;
37212
37213
0
    tag = JS_VALUE_GET_NORM_TAG(argv[0]);
37214
0
    if (tag == JS_TAG_OBJECT) {
37215
0
        p = JS_VALUE_GET_OBJ(argv[0]);
37216
0
        class_id = p->class_id;
37217
0
        if (class_id == JS_CLASS_PROXY && JS_IsFunction(ctx, argv[0]))
37218
0
            class_id = JS_CLASS_BYTECODE_FUNCTION;
37219
0
        atom = ctx->rt->class_array[class_id].class_name;
37220
0
    } else {
37221
0
        atom = JS_ATOM_empty_string;
37222
0
    }
37223
0
    return JS_AtomToString(ctx, atom);
37224
0
}
37225
37226
static JSValue js_object_is(JSContext *ctx, JSValueConst this_val,
37227
                            int argc, JSValueConst *argv)
37228
0
{
37229
0
    return JS_NewBool(ctx, js_same_value(ctx, argv[0], argv[1]));
37230
0
}
37231
37232
#if 0
37233
static JSValue js_object___getObjectData(JSContext *ctx, JSValueConst this_val,
37234
                                         int argc, JSValueConst *argv)
37235
{
37236
    return JS_GetObjectData(ctx, argv[0]);
37237
}
37238
37239
static JSValue js_object___setObjectData(JSContext *ctx, JSValueConst this_val,
37240
                                         int argc, JSValueConst *argv)
37241
{
37242
    if (JS_SetObjectData(ctx, argv[0], JS_DupValue(ctx, argv[1])))
37243
        return JS_EXCEPTION;
37244
    return JS_DupValue(ctx, argv[1]);
37245
}
37246
37247
static JSValue js_object___toPropertyKey(JSContext *ctx, JSValueConst this_val,
37248
                                         int argc, JSValueConst *argv)
37249
{
37250
    return JS_ToPropertyKey(ctx, argv[0]);
37251
}
37252
37253
static JSValue js_object___isObject(JSContext *ctx, JSValueConst this_val,
37254
                                    int argc, JSValueConst *argv)
37255
{
37256
    return JS_NewBool(ctx, JS_IsObject(argv[0]));
37257
}
37258
37259
static JSValue js_object___isSameValueZero(JSContext *ctx, JSValueConst this_val,
37260
                                           int argc, JSValueConst *argv)
37261
{
37262
    return JS_NewBool(ctx, js_same_value_zero(ctx, argv[0], argv[1]));
37263
}
37264
37265
static JSValue js_object___isConstructor(JSContext *ctx, JSValueConst this_val,
37266
                                         int argc, JSValueConst *argv)
37267
{
37268
    return JS_NewBool(ctx, JS_IsConstructor(ctx, argv[0]));
37269
}
37270
#endif
37271
37272
static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj,
37273
                                     JSValueConst defaultConstructor)
37274
0
{
37275
0
    JSValue ctor, species;
37276
37277
0
    if (!JS_IsObject(obj))
37278
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
37279
0
    ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
37280
0
    if (JS_IsException(ctor))
37281
0
        return ctor;
37282
0
    if (JS_IsUndefined(ctor))
37283
0
        return JS_DupValue(ctx, defaultConstructor);
37284
0
    if (!JS_IsObject(ctor)) {
37285
0
        JS_FreeValue(ctx, ctor);
37286
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
37287
0
    }
37288
0
    species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
37289
0
    JS_FreeValue(ctx, ctor);
37290
0
    if (JS_IsException(species))
37291
0
        return species;
37292
0
    if (JS_IsUndefined(species) || JS_IsNull(species))
37293
0
        return JS_DupValue(ctx, defaultConstructor);
37294
0
    if (!JS_IsConstructor(ctx, species)) {
37295
0
        JS_FreeValue(ctx, species);
37296
0
        return JS_ThrowTypeError(ctx, "not a constructor");
37297
0
    }
37298
0
    return species;
37299
0
}
37300
37301
#if 0
37302
static JSValue js_object___speciesConstructor(JSContext *ctx, JSValueConst this_val,
37303
                                              int argc, JSValueConst *argv)
37304
{
37305
    return JS_SpeciesConstructor(ctx, argv[0], argv[1]);
37306
}
37307
#endif
37308
37309
static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val)
37310
0
{
37311
0
    JSValue val, ret;
37312
37313
0
    val = JS_ToObject(ctx, this_val);
37314
0
    if (JS_IsException(val))
37315
0
        return val;
37316
0
    ret = JS_GetPrototype(ctx, val);
37317
0
    JS_FreeValue(ctx, val);
37318
0
    return ret;
37319
0
}
37320
37321
static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val,
37322
                                       JSValueConst proto)
37323
0
{
37324
0
    if (JS_IsUndefined(this_val) || JS_IsNull(this_val))
37325
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
37326
0
    if (!JS_IsObject(proto) && !JS_IsNull(proto))
37327
0
        return JS_UNDEFINED;
37328
0
    if (JS_SetPrototypeInternal(ctx, this_val, proto, TRUE) < 0)
37329
0
        return JS_EXCEPTION;
37330
0
    else
37331
0
        return JS_UNDEFINED;
37332
0
}
37333
37334
static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val,
37335
                                       int argc, JSValueConst *argv)
37336
0
{
37337
0
    JSValue obj, v1;
37338
0
    JSValueConst v;
37339
0
    int res;
37340
37341
0
    v = argv[0];
37342
0
    if (!JS_IsObject(v))
37343
0
        return JS_FALSE;
37344
0
    obj = JS_ToObject(ctx, this_val);
37345
0
    if (JS_IsException(obj))
37346
0
        return JS_EXCEPTION;
37347
0
    v1 = JS_DupValue(ctx, v);
37348
0
    for(;;) {
37349
0
        v1 = JS_GetPrototypeFree(ctx, v1);
37350
0
        if (JS_IsException(v1))
37351
0
            goto exception;
37352
0
        if (JS_IsNull(v1)) {
37353
0
            res = FALSE;
37354
0
            break;
37355
0
        }
37356
0
        if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) {
37357
0
            res = TRUE;
37358
0
            break;
37359
0
        }
37360
        /* avoid infinite loop (possible with proxies) */
37361
0
        if (js_poll_interrupts(ctx))
37362
0
            goto exception;
37363
0
    }
37364
0
    JS_FreeValue(ctx, v1);
37365
0
    JS_FreeValue(ctx, obj);
37366
0
    return JS_NewBool(ctx, res);
37367
37368
0
exception:
37369
0
    JS_FreeValue(ctx, v1);
37370
0
    JS_FreeValue(ctx, obj);
37371
0
    return JS_EXCEPTION;
37372
0
}
37373
37374
static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_val,
37375
                                              int argc, JSValueConst *argv)
37376
0
{
37377
0
    JSValue obj, res = JS_EXCEPTION;
37378
0
    JSAtom prop = JS_ATOM_NULL;
37379
0
    JSPropertyDescriptor desc;
37380
0
    int has_prop;
37381
37382
0
    obj = JS_ToObject(ctx, this_val);
37383
0
    if (JS_IsException(obj))
37384
0
        goto exception;
37385
0
    prop = JS_ValueToAtom(ctx, argv[0]);
37386
0
    if (unlikely(prop == JS_ATOM_NULL))
37387
0
        goto exception;
37388
37389
0
    has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
37390
0
    if (has_prop < 0)
37391
0
        goto exception;
37392
0
    if (has_prop) {
37393
0
        res = JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0);
37394
0
        js_free_desc(ctx, &desc);
37395
0
    } else {
37396
0
        res = JS_FALSE;
37397
0
    }
37398
37399
0
exception:
37400
0
    JS_FreeAtom(ctx, prop);
37401
0
    JS_FreeValue(ctx, obj);
37402
0
    return res;
37403
0
}
37404
37405
static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val,
37406
                                          int argc, JSValueConst *argv, int setter)
37407
0
{
37408
0
    JSValue obj, res = JS_EXCEPTION;
37409
0
    JSAtom prop = JS_ATOM_NULL;
37410
0
    JSPropertyDescriptor desc;
37411
0
    int has_prop;
37412
37413
0
    obj = JS_ToObject(ctx, this_val);
37414
0
    if (JS_IsException(obj))
37415
0
        goto exception;
37416
0
    prop = JS_ValueToAtom(ctx, argv[0]);
37417
0
    if (unlikely(prop == JS_ATOM_NULL))
37418
0
        goto exception;
37419
37420
0
    for (;;) {
37421
0
        has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
37422
0
        if (has_prop < 0)
37423
0
            goto exception;
37424
0
        if (has_prop) {
37425
0
            if (desc.flags & JS_PROP_GETSET)
37426
0
                res = JS_DupValue(ctx, setter ? desc.setter : desc.getter);
37427
0
            else
37428
0
                res = JS_UNDEFINED;
37429
0
            js_free_desc(ctx, &desc);
37430
0
            break;
37431
0
        }
37432
0
        obj = JS_GetPrototypeFree(ctx, obj);
37433
0
        if (JS_IsException(obj))
37434
0
            goto exception;
37435
0
        if (JS_IsNull(obj)) {
37436
0
            res = JS_UNDEFINED;
37437
0
            break;
37438
0
        }
37439
        /* avoid infinite loop (possible with proxies) */
37440
0
        if (js_poll_interrupts(ctx))
37441
0
            goto exception;
37442
0
    }
37443
37444
0
exception:
37445
0
    JS_FreeAtom(ctx, prop);
37446
0
    JS_FreeValue(ctx, obj);
37447
0
    return res;
37448
0
}
37449
37450
static const JSCFunctionListEntry js_object_funcs[] = {
37451
    JS_CFUNC_DEF("create", 2, js_object_create ),
37452
    JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 0 ),
37453
    JS_CFUNC_DEF("setPrototypeOf", 2, js_object_setPrototypeOf ),
37454
    JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 0 ),
37455
    JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties ),
37456
    JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames ),
37457
    JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols ),
37458
    JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY ),
37459
    JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ),
37460
    JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ),
37461
    JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 0 ),
37462
    JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 0 ),
37463
    JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 0 ),
37464
    JS_CFUNC_DEF("getOwnPropertyDescriptors", 1, js_object_getOwnPropertyDescriptors ),
37465
    JS_CFUNC_DEF("is", 2, js_object_is ),
37466
    JS_CFUNC_DEF("assign", 2, js_object_assign ),
37467
    JS_CFUNC_MAGIC_DEF("seal", 1, js_object_seal, 0 ),
37468
    JS_CFUNC_MAGIC_DEF("freeze", 1, js_object_seal, 1 ),
37469
    JS_CFUNC_MAGIC_DEF("isSealed", 1, js_object_isSealed, 0 ),
37470
    JS_CFUNC_MAGIC_DEF("isFrozen", 1, js_object_isSealed, 1 ),
37471
    JS_CFUNC_DEF("__getClass", 1, js_object___getClass ),
37472
    //JS_CFUNC_DEF("__isObject", 1, js_object___isObject ),
37473
    //JS_CFUNC_DEF("__isConstructor", 1, js_object___isConstructor ),
37474
    //JS_CFUNC_DEF("__toObject", 1, js_object___toObject ),
37475
    //JS_CFUNC_DEF("__setOwnProperty", 3, js_object___setOwnProperty ),
37476
    //JS_CFUNC_DEF("__toPrimitive", 2, js_object___toPrimitive ),
37477
    //JS_CFUNC_DEF("__toPropertyKey", 1, js_object___toPropertyKey ),
37478
    //JS_CFUNC_DEF("__speciesConstructor", 2, js_object___speciesConstructor ),
37479
    //JS_CFUNC_DEF("__isSameValueZero", 2, js_object___isSameValueZero ),
37480
    //JS_CFUNC_DEF("__getObjectData", 1, js_object___getObjectData ),
37481
    //JS_CFUNC_DEF("__setObjectData", 2, js_object___setObjectData ),
37482
    JS_CFUNC_DEF("fromEntries", 1, js_object_fromEntries ),
37483
    JS_CFUNC_DEF("hasOwn", 2, js_object_hasOwn ),
37484
};
37485
37486
static const JSCFunctionListEntry js_object_proto_funcs[] = {
37487
    JS_CFUNC_DEF("toString", 0, js_object_toString ),
37488
    JS_CFUNC_DEF("toLocaleString", 0, js_object_toLocaleString ),
37489
    JS_CFUNC_DEF("valueOf", 0, js_object_valueOf ),
37490
    JS_CFUNC_DEF("hasOwnProperty", 1, js_object_hasOwnProperty ),
37491
    JS_CFUNC_DEF("isPrototypeOf", 1, js_object_isPrototypeOf ),
37492
    JS_CFUNC_DEF("propertyIsEnumerable", 1, js_object_propertyIsEnumerable ),
37493
    JS_CGETSET_DEF("__proto__", js_object_get___proto__, js_object_set___proto__ ),
37494
    JS_CFUNC_MAGIC_DEF("__defineGetter__", 2, js_object___defineGetter__, 0 ),
37495
    JS_CFUNC_MAGIC_DEF("__defineSetter__", 2, js_object___defineGetter__, 1 ),
37496
    JS_CFUNC_MAGIC_DEF("__lookupGetter__", 1, js_object___lookupGetter__, 0 ),
37497
    JS_CFUNC_MAGIC_DEF("__lookupSetter__", 1, js_object___lookupGetter__, 1 ),
37498
};
37499
37500
/* Function class */
37501
37502
static JSValue js_function_proto(JSContext *ctx, JSValueConst this_val,
37503
                                 int argc, JSValueConst *argv)
37504
0
{
37505
0
    return JS_UNDEFINED;
37506
0
}
37507
37508
/* XXX: add a specific eval mode so that Function("}), ({") is rejected */
37509
static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target,
37510
                                       int argc, JSValueConst *argv, int magic)
37511
0
{
37512
0
    JSFunctionKindEnum func_kind = magic;
37513
0
    int i, n, ret;
37514
0
    JSValue s, proto, obj = JS_UNDEFINED;
37515
0
    StringBuffer b_s, *b = &b_s;
37516
37517
0
    string_buffer_init(ctx, b, 0);
37518
0
    string_buffer_putc8(b, '(');
37519
    
37520
0
    if (func_kind == JS_FUNC_ASYNC || func_kind == JS_FUNC_ASYNC_GENERATOR) {
37521
0
        string_buffer_puts8(b, "async ");
37522
0
    }
37523
0
    string_buffer_puts8(b, "function");
37524
37525
0
    if (func_kind == JS_FUNC_GENERATOR || func_kind == JS_FUNC_ASYNC_GENERATOR) {
37526
0
        string_buffer_putc8(b, '*');
37527
0
    }
37528
0
    string_buffer_puts8(b, " anonymous(");
37529
37530
0
    n = argc - 1;
37531
0
    for(i = 0; i < n; i++) {
37532
0
        if (i != 0) {
37533
0
            string_buffer_putc8(b, ',');
37534
0
        }
37535
0
        if (string_buffer_concat_value(b, argv[i]))
37536
0
            goto fail;
37537
0
    }
37538
0
    string_buffer_puts8(b, "\n) {\n");
37539
0
    if (n >= 0) {
37540
0
        if (string_buffer_concat_value(b, argv[n]))
37541
0
            goto fail;
37542
0
    }
37543
0
    string_buffer_puts8(b, "\n})");
37544
0
    s = string_buffer_end(b);
37545
0
    if (JS_IsException(s))
37546
0
        goto fail1;
37547
37548
0
    obj = JS_EvalObject(ctx, ctx->global_obj, s, JS_EVAL_TYPE_INDIRECT, -1);
37549
0
    JS_FreeValue(ctx, s);
37550
0
    if (JS_IsException(obj))
37551
0
        goto fail1;
37552
0
    if (!JS_IsUndefined(new_target)) {
37553
        /* set the prototype */
37554
0
        proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
37555
0
        if (JS_IsException(proto))
37556
0
            goto fail1;
37557
0
        if (!JS_IsObject(proto)) {
37558
0
            JSContext *realm;
37559
0
            JS_FreeValue(ctx, proto);
37560
0
            realm = JS_GetFunctionRealm(ctx, new_target);
37561
0
            if (!realm)
37562
0
                goto fail1;
37563
0
            proto = JS_DupValue(ctx, realm->class_proto[func_kind_to_class_id[func_kind]]);
37564
0
        }
37565
0
        ret = JS_SetPrototypeInternal(ctx, obj, proto, TRUE);
37566
0
        JS_FreeValue(ctx, proto);
37567
0
        if (ret < 0)
37568
0
            goto fail1;
37569
0
    }
37570
0
    return obj;
37571
37572
0
 fail:
37573
0
    string_buffer_free(b);
37574
0
 fail1:
37575
0
    JS_FreeValue(ctx, obj);
37576
0
    return JS_EXCEPTION;
37577
0
}
37578
37579
static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
37580
                                       JSValueConst obj)
37581
2
{
37582
2
    JSValue len_val;
37583
2
    len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
37584
2
    if (JS_IsException(len_val)) {
37585
0
        *pres = 0;
37586
0
        return -1;
37587
0
    }
37588
2
    return JS_ToUint32Free(ctx, pres, len_val);
37589
2
}
37590
37591
static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
37592
                                       JSValueConst obj)
37593
9
{
37594
9
    JSValue len_val;
37595
9
    len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
37596
9
    if (JS_IsException(len_val)) {
37597
0
        *pres = 0;
37598
0
        return -1;
37599
0
    }
37600
9
    return JS_ToLengthFree(ctx, pres, len_val);
37601
9
}
37602
37603
static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len)
37604
0
{
37605
0
    uint32_t i;
37606
0
    for(i = 0; i < len; i++) {
37607
0
        JS_FreeValue(ctx, tab[i]);
37608
0
    }
37609
0
    js_free(ctx, tab);
37610
0
}
37611
37612
/* XXX: should use ValueArray */
37613
static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
37614
                               JSValueConst array_arg)
37615
0
{
37616
0
    uint32_t len, i;
37617
0
    JSValue *tab, ret;
37618
0
    JSObject *p;
37619
37620
0
    if (JS_VALUE_GET_TAG(array_arg) != JS_TAG_OBJECT) {
37621
0
        JS_ThrowTypeError(ctx, "not a object");
37622
0
        return NULL;
37623
0
    }
37624
0
    if (js_get_length32(ctx, &len, array_arg))
37625
0
        return NULL;
37626
0
    if (len > JS_MAX_LOCAL_VARS) {
37627
0
        JS_ThrowInternalError(ctx, "too many arguments");
37628
0
        return NULL;
37629
0
    }
37630
    /* avoid allocating 0 bytes */
37631
0
    tab = js_mallocz(ctx, sizeof(tab[0]) * max_uint32(1, len));
37632
0
    if (!tab)
37633
0
        return NULL;
37634
0
    p = JS_VALUE_GET_OBJ(array_arg);
37635
0
    if ((p->class_id == JS_CLASS_ARRAY || p->class_id == JS_CLASS_ARGUMENTS) &&
37636
0
        p->fast_array &&
37637
0
        len == p->u.array.count) {
37638
0
        for(i = 0; i < len; i++) {
37639
0
            tab[i] = JS_DupValue(ctx, p->u.array.u.values[i]);
37640
0
        }
37641
0
    } else {
37642
0
        for(i = 0; i < len; i++) {
37643
0
            ret = JS_GetPropertyUint32(ctx, array_arg, i);
37644
0
            if (JS_IsException(ret)) {
37645
0
                free_arg_list(ctx, tab, i);
37646
0
                return NULL;
37647
0
            }
37648
0
            tab[i] = ret;
37649
0
        }
37650
0
    }
37651
0
    *plen = len;
37652
0
    return tab;
37653
0
}
37654
37655
/* magic value: 0 = normal apply, 1 = apply for constructor, 2 =
37656
   Reflect.apply */
37657
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
37658
                                 int argc, JSValueConst *argv, int magic)
37659
0
{
37660
0
    JSValueConst this_arg, array_arg;
37661
0
    uint32_t len;
37662
0
    JSValue *tab, ret;
37663
37664
0
    if (check_function(ctx, this_val))
37665
0
        return JS_EXCEPTION;
37666
0
    this_arg = argv[0];
37667
0
    array_arg = argv[1];
37668
0
    if ((JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED ||
37669
0
         JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) && magic != 2) {
37670
0
        return JS_Call(ctx, this_val, this_arg, 0, NULL);
37671
0
    }
37672
0
    tab = build_arg_list(ctx, &len, array_arg);
37673
0
    if (!tab)
37674
0
        return JS_EXCEPTION;
37675
0
    if (magic & 1) {
37676
0
        ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab);
37677
0
    } else {
37678
0
        ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab);
37679
0
    }
37680
0
    free_arg_list(ctx, tab, len);
37681
0
    return ret;
37682
0
}
37683
37684
static JSValue js_function_call(JSContext *ctx, JSValueConst this_val,
37685
                                int argc, JSValueConst *argv)
37686
0
{
37687
0
    if (argc <= 0) {
37688
0
        return JS_Call(ctx, this_val, JS_UNDEFINED, 0, NULL);
37689
0
    } else {
37690
0
        return JS_Call(ctx, this_val, argv[0], argc - 1, argv + 1);
37691
0
    }
37692
0
}
37693
37694
static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val,
37695
                                int argc, JSValueConst *argv)
37696
0
{
37697
0
    JSBoundFunction *bf;
37698
0
    JSValue func_obj, name1, len_val;
37699
0
    JSObject *p;
37700
0
    int arg_count, i, ret;
37701
37702
0
    if (check_function(ctx, this_val))
37703
0
        return JS_EXCEPTION;
37704
37705
0
    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
37706
0
                                 JS_CLASS_BOUND_FUNCTION);
37707
0
    if (JS_IsException(func_obj))
37708
0
        return JS_EXCEPTION;
37709
0
    p = JS_VALUE_GET_OBJ(func_obj);
37710
0
    p->is_constructor = JS_IsConstructor(ctx, this_val);
37711
0
    arg_count = max_int(0, argc - 1);
37712
0
    bf = js_malloc(ctx, sizeof(*bf) + arg_count * sizeof(JSValue));
37713
0
    if (!bf)
37714
0
        goto exception;
37715
0
    bf->func_obj = JS_DupValue(ctx, this_val);
37716
0
    bf->this_val = JS_DupValue(ctx, argv[0]);
37717
0
    bf->argc = arg_count;
37718
0
    for(i = 0; i < arg_count; i++) {
37719
0
        bf->argv[i] = JS_DupValue(ctx, argv[i + 1]);
37720
0
    }
37721
0
    p->u.bound_function = bf;
37722
37723
    /* XXX: the spec could be simpler by only using GetOwnProperty */
37724
0
    ret = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_length);
37725
0
    if (ret < 0)
37726
0
        goto exception;
37727
0
    if (!ret) {
37728
0
        len_val = JS_NewInt32(ctx, 0);
37729
0
    } else {
37730
0
        len_val = JS_GetProperty(ctx, this_val, JS_ATOM_length);
37731
0
        if (JS_IsException(len_val))
37732
0
            goto exception;
37733
0
        if (JS_VALUE_GET_TAG(len_val) == JS_TAG_INT) {
37734
            /* most common case */
37735
0
            int len1 = JS_VALUE_GET_INT(len_val);
37736
0
            if (len1 <= arg_count)
37737
0
                len1 = 0;
37738
0
            else
37739
0
                len1 -= arg_count;
37740
0
            len_val = JS_NewInt32(ctx, len1);
37741
0
        } else if (JS_VALUE_GET_NORM_TAG(len_val) == JS_TAG_FLOAT64) {
37742
0
            double d = JS_VALUE_GET_FLOAT64(len_val);
37743
0
            if (isnan(d)) {
37744
0
                d = 0.0;
37745
0
            } else {
37746
0
                d = trunc(d);
37747
0
                if (d <= (double)arg_count)
37748
0
                    d = 0.0;
37749
0
                else
37750
0
                    d -= (double)arg_count; /* also converts -0 to +0 */
37751
0
            }
37752
0
            len_val = JS_NewFloat64(ctx, d);
37753
0
        } else {
37754
0
            JS_FreeValue(ctx, len_val);
37755
0
            len_val = JS_NewInt32(ctx, 0);
37756
0
        }
37757
0
    }
37758
0
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length,
37759
0
                           len_val, JS_PROP_CONFIGURABLE);
37760
37761
0
    name1 = JS_GetProperty(ctx, this_val, JS_ATOM_name);
37762
0
    if (JS_IsException(name1))
37763
0
        goto exception;
37764
0
    if (!JS_IsString(name1)) {
37765
0
        JS_FreeValue(ctx, name1);
37766
0
        name1 = JS_AtomToString(ctx, JS_ATOM_empty_string);
37767
0
    }
37768
0
    name1 = JS_ConcatString3(ctx, "bound ", name1, "");
37769
0
    if (JS_IsException(name1))
37770
0
        goto exception;
37771
0
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name1,
37772
0
                           JS_PROP_CONFIGURABLE);
37773
0
    return func_obj;
37774
0
 exception:
37775
0
    JS_FreeValue(ctx, func_obj);
37776
0
    return JS_EXCEPTION;
37777
0
}
37778
37779
static JSValue js_function_toString(JSContext *ctx, JSValueConst this_val,
37780
                                    int argc, JSValueConst *argv)
37781
81.9k
{
37782
81.9k
    JSObject *p;
37783
81.9k
    JSFunctionKindEnum func_kind = JS_FUNC_NORMAL;
37784
37785
81.9k
    if (check_function(ctx, this_val))
37786
0
        return JS_EXCEPTION;
37787
37788
81.9k
    p = JS_VALUE_GET_OBJ(this_val);
37789
81.9k
    if (js_class_has_bytecode(p->class_id)) {
37790
81.9k
        JSFunctionBytecode *b = p->u.func.function_bytecode;
37791
81.9k
        if (b->has_debug && b->debug.source) {
37792
33
            return JS_NewStringLen(ctx, b->debug.source, b->debug.source_len);
37793
33
        }
37794
81.9k
        func_kind = b->func_kind;
37795
81.9k
    }
37796
81.9k
    {
37797
81.9k
        JSValue name;
37798
81.9k
        const char *pref, *suff;
37799
37800
81.9k
        switch(func_kind) {
37801
0
        default:
37802
40.9k
        case JS_FUNC_NORMAL:
37803
40.9k
            pref = "function ";
37804
40.9k
            break;
37805
40.9k
        case JS_FUNC_GENERATOR:
37806
40.9k
            pref = "function *";
37807
40.9k
            break;
37808
0
        case JS_FUNC_ASYNC:
37809
0
            pref = "async function ";
37810
0
            break;
37811
0
        case JS_FUNC_ASYNC_GENERATOR:
37812
0
            pref = "async function *";
37813
0
            break;
37814
81.9k
        }
37815
81.9k
        suff = "() {\n    [native code]\n}";
37816
81.9k
        name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
37817
81.9k
        if (JS_IsUndefined(name))
37818
0
            name = JS_AtomToString(ctx, JS_ATOM_empty_string);
37819
81.9k
        return JS_ConcatString3(ctx, pref, name, suff);
37820
81.9k
    }
37821
81.9k
}
37822
37823
static JSValue js_function_hasInstance(JSContext *ctx, JSValueConst this_val,
37824
                                       int argc, JSValueConst *argv)
37825
0
{
37826
0
    int ret;
37827
0
    ret = JS_OrdinaryIsInstanceOf(ctx, argv[0], this_val);
37828
0
    if (ret < 0)
37829
0
        return JS_EXCEPTION;
37830
0
    else
37831
0
        return JS_NewBool(ctx, ret);
37832
0
}
37833
37834
static const JSCFunctionListEntry js_function_proto_funcs[] = {
37835
    JS_CFUNC_DEF("call", 1, js_function_call ),
37836
    JS_CFUNC_MAGIC_DEF("apply", 2, js_function_apply, 0 ),
37837
    JS_CFUNC_DEF("bind", 1, js_function_bind ),
37838
    JS_CFUNC_DEF("toString", 0, js_function_toString ),
37839
    JS_CFUNC_DEF("[Symbol.hasInstance]", 1, js_function_hasInstance ),
37840
    JS_CGETSET_DEF("fileName", js_function_proto_fileName, NULL ),
37841
    JS_CGETSET_DEF("lineNumber", js_function_proto_lineNumber, NULL ),
37842
};
37843
37844
/* Error class */
37845
37846
static JSValue iterator_to_array(JSContext *ctx, JSValueConst items)
37847
0
{
37848
0
    JSValue iter, next_method = JS_UNDEFINED;
37849
0
    JSValue v, r = JS_UNDEFINED;
37850
0
    int64_t k;
37851
0
    BOOL done;
37852
    
37853
0
    iter = JS_GetIterator(ctx, items, FALSE);
37854
0
    if (JS_IsException(iter))
37855
0
        goto exception;
37856
0
    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
37857
0
    if (JS_IsException(next_method))
37858
0
        goto exception;
37859
0
    r = JS_NewArray(ctx);
37860
0
    if (JS_IsException(r))
37861
0
        goto exception;
37862
0
    for (k = 0;; k++) {
37863
0
        v = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
37864
0
        if (JS_IsException(v))
37865
0
            goto exception_close;
37866
0
        if (done)
37867
0
            break;
37868
0
        if (JS_DefinePropertyValueInt64(ctx, r, k, v,
37869
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
37870
0
            goto exception_close;
37871
0
    }
37872
0
 done:
37873
0
    JS_FreeValue(ctx, next_method);
37874
0
    JS_FreeValue(ctx, iter);
37875
0
    return r;
37876
0
 exception_close:
37877
0
    JS_IteratorClose(ctx, iter, TRUE);
37878
0
 exception:
37879
0
    JS_FreeValue(ctx, r);
37880
0
    r = JS_EXCEPTION;
37881
0
    goto done;
37882
0
}
37883
37884
static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
37885
                                    int argc, JSValueConst *argv, int magic)
37886
0
{
37887
0
    JSValue obj, msg, proto;
37888
0
    JSValueConst message;
37889
37890
0
    if (JS_IsUndefined(new_target))
37891
0
        new_target = JS_GetActiveFunction(ctx);
37892
0
    proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
37893
0
    if (JS_IsException(proto))
37894
0
        return proto;
37895
0
    if (!JS_IsObject(proto)) {
37896
0
        JSContext *realm;
37897
0
        JSValueConst proto1;
37898
        
37899
0
        JS_FreeValue(ctx, proto);
37900
0
        realm = JS_GetFunctionRealm(ctx, new_target);
37901
0
        if (!realm)
37902
0
            return JS_EXCEPTION;
37903
0
        if (magic < 0) {
37904
0
            proto1 = realm->class_proto[JS_CLASS_ERROR];
37905
0
        } else {
37906
0
            proto1 = realm->native_error_proto[magic];
37907
0
        }
37908
0
        proto = JS_DupValue(ctx, proto1);
37909
0
    }
37910
0
    obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_ERROR);
37911
0
    JS_FreeValue(ctx, proto);
37912
0
    if (JS_IsException(obj))
37913
0
        return obj;
37914
0
    if (magic == JS_AGGREGATE_ERROR) {
37915
0
        message = argv[1];
37916
0
    } else {
37917
0
        message = argv[0];
37918
0
    }
37919
37920
0
    if (!JS_IsUndefined(message)) {
37921
0
        msg = JS_ToString(ctx, message);
37922
0
        if (unlikely(JS_IsException(msg)))
37923
0
            goto exception;
37924
0
        JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg,
37925
0
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
37926
0
    }
37927
37928
0
    if (magic == JS_AGGREGATE_ERROR) {
37929
0
        JSValue error_list = iterator_to_array(ctx, argv[0]);
37930
0
        if (JS_IsException(error_list))
37931
0
            goto exception;
37932
0
        JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, error_list,
37933
0
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
37934
0
    }
37935
37936
    /* skip the Error() function in the backtrace */
37937
0
    build_backtrace(ctx, obj, NULL, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
37938
0
    return obj;
37939
0
 exception:
37940
0
    JS_FreeValue(ctx, obj);
37941
0
    return JS_EXCEPTION;
37942
0
}
37943
37944
static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
37945
                                 int argc, JSValueConst *argv)
37946
1
{
37947
1
    JSValue name, msg;
37948
37949
1
    if (!JS_IsObject(this_val))
37950
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
37951
1
    name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
37952
1
    if (JS_IsUndefined(name))
37953
0
        name = JS_AtomToString(ctx, JS_ATOM_Error);
37954
1
    else
37955
1
        name = JS_ToStringFree(ctx, name);
37956
1
    if (JS_IsException(name))
37957
0
        return JS_EXCEPTION;
37958
37959
1
    msg = JS_GetProperty(ctx, this_val, JS_ATOM_message);
37960
1
    if (JS_IsUndefined(msg))
37961
0
        msg = JS_AtomToString(ctx, JS_ATOM_empty_string);
37962
1
    else
37963
1
        msg = JS_ToStringFree(ctx, msg);
37964
1
    if (JS_IsException(msg)) {
37965
0
        JS_FreeValue(ctx, name);
37966
0
        return JS_EXCEPTION;
37967
0
    }
37968
1
    if (!JS_IsEmptyString(name) && !JS_IsEmptyString(msg))
37969
1
        name = JS_ConcatString3(ctx, "", name, ": ");
37970
1
    return JS_ConcatString(ctx, name, msg);
37971
1
}
37972
37973
static const JSCFunctionListEntry js_error_proto_funcs[] = {
37974
    JS_CFUNC_DEF("toString", 0, js_error_toString ),
37975
    JS_PROP_STRING_DEF("name", "Error", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
37976
    JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
37977
};
37978
37979
/* AggregateError */
37980
37981
/* used by C code. */
37982
static JSValue js_aggregate_error_constructor(JSContext *ctx,
37983
                                              JSValueConst errors)
37984
0
{
37985
0
    JSValue obj;
37986
    
37987
0
    obj = JS_NewObjectProtoClass(ctx,
37988
0
                                 ctx->native_error_proto[JS_AGGREGATE_ERROR],
37989
0
                                 JS_CLASS_ERROR);
37990
0
    if (JS_IsException(obj))
37991
0
        return obj;
37992
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, JS_DupValue(ctx, errors),
37993
0
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
37994
0
    return obj;
37995
0
}
37996
37997
/* Array */
37998
37999
static int JS_CopySubArray(JSContext *ctx,
38000
                           JSValueConst obj, int64_t to_pos,
38001
                           int64_t from_pos, int64_t count, int dir)
38002
0
{
38003
0
    JSObject *p;
38004
0
    int64_t i, from, to, len;
38005
0
    JSValue val;
38006
0
    int fromPresent;
38007
38008
0
    p = NULL;
38009
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
38010
0
        p = JS_VALUE_GET_OBJ(obj);
38011
0
        if (p->class_id != JS_CLASS_ARRAY || !p->fast_array) {
38012
0
            p = NULL;
38013
0
        }
38014
0
    }
38015
38016
0
    for (i = 0; i < count; ) {
38017
0
        if (dir < 0) {
38018
0
            from = from_pos + count - i - 1;
38019
0
            to = to_pos + count - i - 1;
38020
0
        } else {
38021
0
            from = from_pos + i;
38022
0
            to = to_pos + i;
38023
0
        }
38024
0
        if (p && p->fast_array &&
38025
0
            from >= 0 && from < (len = p->u.array.count)  &&
38026
0
            to >= 0 && to < len) {
38027
0
            int64_t l, j;
38028
            /* Fast path for fast arrays. Since we don't look at the
38029
               prototype chain, we can optimize only the cases where
38030
               all the elements are present in the array. */
38031
0
            l = count - i;
38032
0
            if (dir < 0) {
38033
0
                l = min_int64(l, from + 1);
38034
0
                l = min_int64(l, to + 1);
38035
0
                for(j = 0; j < l; j++) {
38036
0
                    set_value(ctx, &p->u.array.u.values[to - j],
38037
0
                              JS_DupValue(ctx, p->u.array.u.values[from - j]));
38038
0
                }
38039
0
            } else {
38040
0
                l = min_int64(l, len - from);
38041
0
                l = min_int64(l, len - to);
38042
0
                for(j = 0; j < l; j++) {
38043
0
                    set_value(ctx, &p->u.array.u.values[to + j],
38044
0
                              JS_DupValue(ctx, p->u.array.u.values[from + j]));
38045
0
                }
38046
0
            }
38047
0
            i += l;
38048
0
        } else {
38049
0
            fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
38050
0
            if (fromPresent < 0)
38051
0
                goto exception;
38052
            
38053
0
            if (fromPresent) {
38054
0
                if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)
38055
0
                    goto exception;
38056
0
            } else {
38057
0
                if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0)
38058
0
                    goto exception;
38059
0
            }
38060
0
            i++;
38061
0
        }
38062
0
    }
38063
0
    return 0;
38064
38065
0
 exception:
38066
0
    return -1;
38067
0
}
38068
38069
static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target,
38070
                                    int argc, JSValueConst *argv)
38071
122k
{
38072
122k
    JSValue obj;
38073
122k
    int i;
38074
38075
122k
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_ARRAY);
38076
122k
    if (JS_IsException(obj))
38077
1
        return obj;
38078
122k
    if (argc == 1 && JS_IsNumber(argv[0])) {
38079
81.9k
        uint32_t len;
38080
81.9k
        if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]), TRUE))
38081
0
            goto fail;
38082
81.9k
        if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0)
38083
0
            goto fail;
38084
81.9k
    } else {
38085
40.9k
        for(i = 0; i < argc; i++) {
38086
0
            if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0)
38087
0
                goto fail;
38088
0
        }
38089
40.9k
    }
38090
122k
    return obj;
38091
0
fail:
38092
0
    JS_FreeValue(ctx, obj);
38093
0
    return JS_EXCEPTION;
38094
122k
}
38095
38096
static JSValue js_array_from(JSContext *ctx, JSValueConst this_val,
38097
                             int argc, JSValueConst *argv)
38098
0
{
38099
    // from(items, mapfn = void 0, this_arg = void 0)
38100
0
    JSValueConst items = argv[0], mapfn, this_arg;
38101
0
    JSValueConst args[2];
38102
0
    JSValue stack[2];
38103
0
    JSValue iter, r, v, v2, arrayLike;
38104
0
    int64_t k, len;
38105
0
    int done, mapping;
38106
38107
0
    mapping = FALSE;
38108
0
    mapfn = JS_UNDEFINED;
38109
0
    this_arg = JS_UNDEFINED;
38110
0
    r = JS_UNDEFINED;
38111
0
    arrayLike = JS_UNDEFINED;
38112
0
    stack[0] = JS_UNDEFINED;
38113
0
    stack[1] = JS_UNDEFINED;
38114
38115
0
    if (argc > 1) {
38116
0
        mapfn = argv[1];
38117
0
        if (!JS_IsUndefined(mapfn)) {
38118
0
            if (check_function(ctx, mapfn))
38119
0
                goto exception;
38120
0
            mapping = 1;
38121
0
            if (argc > 2)
38122
0
                this_arg = argv[2];
38123
0
        }
38124
0
    }
38125
0
    iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
38126
0
    if (JS_IsException(iter))
38127
0
        goto exception;
38128
0
    if (!JS_IsUndefined(iter)) {
38129
0
        JS_FreeValue(ctx, iter);
38130
0
        if (JS_IsConstructor(ctx, this_val))
38131
0
            r = JS_CallConstructor(ctx, this_val, 0, NULL);
38132
0
        else
38133
0
            r = JS_NewArray(ctx);
38134
0
        if (JS_IsException(r))
38135
0
            goto exception;
38136
0
        stack[0] = JS_DupValue(ctx, items);
38137
0
        if (js_for_of_start(ctx, &stack[1], FALSE))
38138
0
            goto exception;
38139
0
        for (k = 0;; k++) {
38140
0
            v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done);
38141
0
            if (JS_IsException(v))
38142
0
                goto exception_close;
38143
0
            if (done)
38144
0
                break;
38145
0
            if (mapping) {
38146
0
                args[0] = v;
38147
0
                args[1] = JS_NewInt32(ctx, k);
38148
0
                v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
38149
0
                JS_FreeValue(ctx, v);
38150
0
                v = v2;
38151
0
                if (JS_IsException(v))
38152
0
                    goto exception_close;
38153
0
            }
38154
0
            if (JS_DefinePropertyValueInt64(ctx, r, k, v,
38155
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38156
0
                goto exception_close;
38157
0
        }
38158
0
    } else {
38159
0
        arrayLike = JS_ToObject(ctx, items);
38160
0
        if (JS_IsException(arrayLike))
38161
0
            goto exception;
38162
0
        if (js_get_length64(ctx, &len, arrayLike) < 0)
38163
0
            goto exception;
38164
0
        v = JS_NewInt64(ctx, len);
38165
0
        args[0] = v;
38166
0
        if (JS_IsConstructor(ctx, this_val)) {
38167
0
            r = JS_CallConstructor(ctx, this_val, 1, args);
38168
0
        } else {
38169
0
            r = js_array_constructor(ctx, JS_UNDEFINED, 1, args);
38170
0
        }
38171
0
        JS_FreeValue(ctx, v);
38172
0
        if (JS_IsException(r))
38173
0
            goto exception;
38174
0
        for(k = 0; k < len; k++) {
38175
0
            v = JS_GetPropertyInt64(ctx, arrayLike, k);
38176
0
            if (JS_IsException(v))
38177
0
                goto exception;
38178
0
            if (mapping) {
38179
0
                args[0] = v;
38180
0
                args[1] = JS_NewInt32(ctx, k);
38181
0
                v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
38182
0
                JS_FreeValue(ctx, v);
38183
0
                v = v2;
38184
0
                if (JS_IsException(v))
38185
0
                    goto exception;
38186
0
            }
38187
0
            if (JS_DefinePropertyValueInt64(ctx, r, k, v,
38188
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38189
0
                goto exception;
38190
0
        }
38191
0
    }
38192
0
    if (JS_SetProperty(ctx, r, JS_ATOM_length, JS_NewUint32(ctx, k)) < 0)
38193
0
        goto exception;
38194
0
    goto done;
38195
38196
0
 exception_close:
38197
0
    if (!JS_IsUndefined(stack[0]))
38198
0
        JS_IteratorClose(ctx, stack[0], TRUE);
38199
0
 exception:
38200
0
    JS_FreeValue(ctx, r);
38201
0
    r = JS_EXCEPTION;
38202
0
 done:
38203
0
    JS_FreeValue(ctx, arrayLike);
38204
0
    JS_FreeValue(ctx, stack[0]);
38205
0
    JS_FreeValue(ctx, stack[1]);
38206
0
    return r;
38207
0
}
38208
38209
static JSValue js_array_of(JSContext *ctx, JSValueConst this_val,
38210
                           int argc, JSValueConst *argv)
38211
0
{
38212
0
    JSValue obj, args[1];
38213
0
    int i;
38214
38215
0
    if (JS_IsConstructor(ctx, this_val)) {
38216
0
        args[0] = JS_NewInt32(ctx, argc);
38217
0
        obj = JS_CallConstructor(ctx, this_val, 1, (JSValueConst *)args);
38218
0
    } else {
38219
0
        obj = JS_NewArray(ctx);
38220
0
    }
38221
0
    if (JS_IsException(obj))
38222
0
        return JS_EXCEPTION;
38223
0
    for(i = 0; i < argc; i++) {
38224
0
        if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i]),
38225
0
                                        JS_PROP_THROW) < 0) {
38226
0
            goto fail;
38227
0
        }
38228
0
    }
38229
0
    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, argc)) < 0) {
38230
0
    fail:
38231
0
        JS_FreeValue(ctx, obj);
38232
0
        return JS_EXCEPTION;
38233
0
    }
38234
0
    return obj;
38235
0
}
38236
38237
static JSValue js_array_isArray(JSContext *ctx, JSValueConst this_val,
38238
                                int argc, JSValueConst *argv)
38239
0
{
38240
0
    int ret;
38241
0
    ret = JS_IsArray(ctx, argv[0]);
38242
0
    if (ret < 0)
38243
0
        return JS_EXCEPTION;
38244
0
    else
38245
0
        return JS_NewBool(ctx, ret);
38246
0
}
38247
38248
static JSValue js_get_this(JSContext *ctx,
38249
                           JSValueConst this_val)
38250
0
{
38251
0
    return JS_DupValue(ctx, this_val);
38252
0
}
38253
38254
static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj,
38255
                                     JSValueConst len_val)
38256
0
{
38257
0
    JSValue ctor, ret, species;
38258
0
    int res;
38259
0
    JSContext *realm;
38260
    
38261
0
    res = JS_IsArray(ctx, obj);
38262
0
    if (res < 0)
38263
0
        return JS_EXCEPTION;
38264
0
    if (!res)
38265
0
        return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
38266
0
    ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
38267
0
    if (JS_IsException(ctor))
38268
0
        return ctor;
38269
0
    if (JS_IsConstructor(ctx, ctor)) {
38270
        /* legacy web compatibility */
38271
0
        realm = JS_GetFunctionRealm(ctx, ctor);
38272
0
        if (!realm) {
38273
0
            JS_FreeValue(ctx, ctor);
38274
0
            return JS_EXCEPTION;
38275
0
        }
38276
0
        if (realm != ctx &&
38277
0
            js_same_value(ctx, ctor, realm->array_ctor)) {
38278
0
            JS_FreeValue(ctx, ctor);
38279
0
            ctor = JS_UNDEFINED;
38280
0
        }
38281
0
    }
38282
0
    if (JS_IsObject(ctor)) {
38283
0
        species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
38284
0
        JS_FreeValue(ctx, ctor);
38285
0
        if (JS_IsException(species))
38286
0
            return species;
38287
0
        ctor = species;
38288
0
        if (JS_IsNull(ctor))
38289
0
            ctor = JS_UNDEFINED;
38290
0
    }
38291
0
    if (JS_IsUndefined(ctor)) {
38292
0
        return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
38293
0
    } else {
38294
0
        ret = JS_CallConstructor(ctx, ctor, 1, &len_val);
38295
0
        JS_FreeValue(ctx, ctor);
38296
0
        return ret;
38297
0
    }
38298
0
}
38299
38300
static const JSCFunctionListEntry js_array_funcs[] = {
38301
    JS_CFUNC_DEF("isArray", 1, js_array_isArray ),
38302
    JS_CFUNC_DEF("from", 1, js_array_from ),
38303
    JS_CFUNC_DEF("of", 0, js_array_of ),
38304
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
38305
};
38306
38307
static int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj)
38308
0
{
38309
0
    JSValue val;
38310
38311
0
    if (!JS_IsObject(obj))
38312
0
        return FALSE;
38313
0
    val = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_isConcatSpreadable);
38314
0
    if (JS_IsException(val))
38315
0
        return -1;
38316
0
    if (!JS_IsUndefined(val))
38317
0
        return JS_ToBoolFree(ctx, val);
38318
0
    return JS_IsArray(ctx, obj);
38319
0
}
38320
38321
static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val,
38322
                               int argc, JSValueConst *argv)
38323
0
{
38324
0
    JSValue obj, arr, val;
38325
0
    JSValueConst e;
38326
0
    int64_t len, k, n;
38327
0
    int i, res;
38328
38329
0
    arr = JS_UNDEFINED;
38330
0
    obj = JS_ToObject(ctx, this_val);
38331
0
    if (JS_IsException(obj))
38332
0
        goto exception;
38333
38334
0
    arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
38335
0
    if (JS_IsException(arr))
38336
0
        goto exception;
38337
0
    n = 0;
38338
0
    for (i = -1; i < argc; i++) {
38339
0
        if (i < 0)
38340
0
            e = obj;
38341
0
        else
38342
0
            e = argv[i];
38343
38344
0
        res = JS_isConcatSpreadable(ctx, e);
38345
0
        if (res < 0)
38346
0
            goto exception;
38347
0
        if (res) {
38348
0
            if (js_get_length64(ctx, &len, e))
38349
0
                goto exception;
38350
0
            if (n + len > MAX_SAFE_INTEGER) {
38351
0
                JS_ThrowTypeError(ctx, "Array loo long");
38352
0
                goto exception;
38353
0
            }
38354
0
            for (k = 0; k < len; k++, n++) {
38355
0
                res = JS_TryGetPropertyInt64(ctx, e, k, &val);
38356
0
                if (res < 0)
38357
0
                    goto exception;
38358
0
                if (res) {
38359
0
                    if (JS_DefinePropertyValueInt64(ctx, arr, n, val,
38360
0
                                                    JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38361
0
                        goto exception;
38362
0
                }
38363
0
            }
38364
0
        } else {
38365
0
            if (n >= MAX_SAFE_INTEGER) {
38366
0
                JS_ThrowTypeError(ctx, "Array loo long");
38367
0
                goto exception;
38368
0
            }
38369
0
            if (JS_DefinePropertyValueInt64(ctx, arr, n, JS_DupValue(ctx, e),
38370
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38371
0
                goto exception;
38372
0
            n++;
38373
0
        }
38374
0
    }
38375
0
    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
38376
0
        goto exception;
38377
38378
0
    JS_FreeValue(ctx, obj);
38379
0
    return arr;
38380
38381
0
exception:
38382
0
    JS_FreeValue(ctx, arr);
38383
0
    JS_FreeValue(ctx, obj);
38384
0
    return JS_EXCEPTION;
38385
0
}
38386
38387
0
#define special_every    0
38388
0
#define special_some     1
38389
#define special_forEach  2
38390
0
#define special_map      3
38391
0
#define special_filter   4
38392
0
#define special_TA       8
38393
38394
static int js_typed_array_get_length_internal(JSContext *ctx, JSValueConst obj);
38395
38396
static JSValue js_typed_array___speciesCreate(JSContext *ctx,
38397
                                              JSValueConst this_val,
38398
                                              int argc, JSValueConst *argv);
38399
38400
static JSValue js_array_every(JSContext *ctx, JSValueConst this_val,
38401
                              int argc, JSValueConst *argv, int special)
38402
0
{
38403
0
    JSValue obj, val, index_val, res, ret;
38404
0
    JSValueConst args[3];
38405
0
    JSValueConst func, this_arg;
38406
0
    int64_t len, k, n;
38407
0
    int present;
38408
38409
0
    ret = JS_UNDEFINED;
38410
0
    val = JS_UNDEFINED;
38411
0
    if (special & special_TA) {
38412
0
        obj = JS_DupValue(ctx, this_val);
38413
0
        len = js_typed_array_get_length_internal(ctx, obj);
38414
0
        if (len < 0)
38415
0
            goto exception;
38416
0
    } else {
38417
0
        obj = JS_ToObject(ctx, this_val);
38418
0
        if (js_get_length64(ctx, &len, obj))
38419
0
            goto exception;
38420
0
    }
38421
0
    func = argv[0];
38422
0
    this_arg = JS_UNDEFINED;
38423
0
    if (argc > 1)
38424
0
        this_arg = argv[1];
38425
        
38426
0
    if (check_function(ctx, func))
38427
0
        goto exception;
38428
38429
0
    switch (special) {
38430
0
    case special_every:
38431
0
    case special_every | special_TA:
38432
0
        ret = JS_TRUE;
38433
0
        break;
38434
0
    case special_some:
38435
0
    case special_some | special_TA:
38436
0
        ret = JS_FALSE;
38437
0
        break;
38438
0
    case special_map:
38439
        /* XXX: JS_ArraySpeciesCreate should take int64_t */
38440
0
        ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt64(ctx, len));
38441
0
        if (JS_IsException(ret))
38442
0
            goto exception;
38443
0
        break;
38444
0
    case special_filter:
38445
0
        ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
38446
0
        if (JS_IsException(ret))
38447
0
            goto exception;
38448
0
        break;
38449
0
    case special_map | special_TA:
38450
0
        args[0] = obj;
38451
0
        args[1] = JS_NewInt32(ctx, len);
38452
0
        ret = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
38453
0
        if (JS_IsException(ret))
38454
0
            goto exception;
38455
0
        break;
38456
0
    case special_filter | special_TA:
38457
0
        ret = JS_NewArray(ctx);
38458
0
        if (JS_IsException(ret))
38459
0
            goto exception;
38460
0
        break;
38461
0
    }
38462
0
    n = 0;
38463
38464
0
    for(k = 0; k < len; k++) {
38465
0
        if (special & special_TA) {
38466
0
            val = JS_GetPropertyInt64(ctx, obj, k);
38467
0
            if (JS_IsException(val))
38468
0
                goto exception;
38469
0
            present = TRUE;
38470
0
        } else {
38471
0
            present = JS_TryGetPropertyInt64(ctx, obj, k, &val);
38472
0
            if (present < 0)
38473
0
                goto exception;
38474
0
        }
38475
0
        if (present) {
38476
0
            index_val = JS_NewInt64(ctx, k);
38477
0
            if (JS_IsException(index_val))
38478
0
                goto exception;
38479
0
            args[0] = val;
38480
0
            args[1] = index_val;
38481
0
            args[2] = obj;
38482
0
            res = JS_Call(ctx, func, this_arg, 3, args);
38483
0
            JS_FreeValue(ctx, index_val);
38484
0
            if (JS_IsException(res))
38485
0
                goto exception;
38486
0
            switch (special) {
38487
0
            case special_every:
38488
0
            case special_every | special_TA:
38489
0
                if (!JS_ToBoolFree(ctx, res)) {
38490
0
                    ret = JS_FALSE;
38491
0
                    goto done;
38492
0
                }
38493
0
                break;
38494
0
            case special_some:
38495
0
            case special_some | special_TA:
38496
0
                if (JS_ToBoolFree(ctx, res)) {
38497
0
                    ret = JS_TRUE;
38498
0
                    goto done;
38499
0
                }
38500
0
                break;
38501
0
            case special_map:
38502
0
                if (JS_DefinePropertyValueInt64(ctx, ret, k, res,
38503
0
                                                JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38504
0
                    goto exception;
38505
0
                break;
38506
0
            case special_map | special_TA:
38507
0
                if (JS_SetPropertyValue(ctx, ret, JS_NewInt32(ctx, k), res, JS_PROP_THROW) < 0)
38508
0
                    goto exception;
38509
0
                break;
38510
0
            case special_filter:
38511
0
            case special_filter | special_TA:
38512
0
                if (JS_ToBoolFree(ctx, res)) {
38513
0
                    if (JS_DefinePropertyValueInt64(ctx, ret, n++, JS_DupValue(ctx, val),
38514
0
                                                    JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38515
0
                        goto exception;
38516
0
                }
38517
0
                break;
38518
0
            default:
38519
0
                JS_FreeValue(ctx, res);
38520
0
                break;
38521
0
            }
38522
0
            JS_FreeValue(ctx, val);
38523
0
            val = JS_UNDEFINED;
38524
0
        }
38525
0
    }
38526
0
done:
38527
0
    if (special == (special_filter | special_TA)) {
38528
0
        JSValue arr;
38529
0
        args[0] = obj;
38530
0
        args[1] = JS_NewInt32(ctx, n);
38531
0
        arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
38532
0
        if (JS_IsException(arr))
38533
0
            goto exception;
38534
0
        args[0] = ret;
38535
0
        res = JS_Invoke(ctx, arr, JS_ATOM_set, 1, args);
38536
0
        if (check_exception_free(ctx, res))
38537
0
            goto exception;
38538
0
        JS_FreeValue(ctx, ret);
38539
0
        ret = arr;
38540
0
    }
38541
0
    JS_FreeValue(ctx, val);
38542
0
    JS_FreeValue(ctx, obj);
38543
0
    return ret;
38544
38545
0
exception:
38546
0
    JS_FreeValue(ctx, ret);
38547
0
    JS_FreeValue(ctx, val);
38548
0
    JS_FreeValue(ctx, obj);
38549
0
    return JS_EXCEPTION;
38550
0
}
38551
38552
#define special_reduce       0
38553
0
#define special_reduceRight  1
38554
38555
static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val,
38556
                               int argc, JSValueConst *argv, int special)
38557
0
{
38558
0
    JSValue obj, val, index_val, acc, acc1;
38559
0
    JSValueConst args[4];
38560
0
    JSValueConst func;
38561
0
    int64_t len, k, k1;
38562
0
    int present;
38563
38564
0
    acc = JS_UNDEFINED;
38565
0
    val = JS_UNDEFINED;
38566
0
    if (special & special_TA) {
38567
0
        obj = JS_DupValue(ctx, this_val);
38568
0
        len = js_typed_array_get_length_internal(ctx, obj);
38569
0
        if (len < 0)
38570
0
            goto exception;
38571
0
    } else {
38572
0
        obj = JS_ToObject(ctx, this_val);
38573
0
        if (js_get_length64(ctx, &len, obj))
38574
0
            goto exception;
38575
0
    }
38576
0
    func = argv[0];
38577
38578
0
    if (check_function(ctx, func))
38579
0
        goto exception;
38580
38581
0
    k = 0;
38582
0
    if (argc > 1) {
38583
0
        acc = JS_DupValue(ctx, argv[1]);
38584
0
    } else {
38585
0
        for(;;) {
38586
0
            if (k >= len) {
38587
0
                JS_ThrowTypeError(ctx, "empty array");
38588
0
                goto exception;
38589
0
            }
38590
0
            k1 = (special & special_reduceRight) ? len - k - 1 : k;
38591
0
            k++;
38592
0
            if (special & special_TA) {
38593
0
                acc = JS_GetPropertyInt64(ctx, obj, k1);
38594
0
                if (JS_IsException(acc))
38595
0
                    goto exception;
38596
0
                break;
38597
0
            } else {
38598
0
                present = JS_TryGetPropertyInt64(ctx, obj, k1, &acc);
38599
0
                if (present < 0)
38600
0
                    goto exception;
38601
0
                if (present)
38602
0
                    break;
38603
0
            }
38604
0
        }
38605
0
    }
38606
0
    for (; k < len; k++) {
38607
0
        k1 = (special & special_reduceRight) ? len - k - 1 : k;
38608
0
        if (special & special_TA) {
38609
0
            val = JS_GetPropertyInt64(ctx, obj, k1);
38610
0
            if (JS_IsException(val))
38611
0
                goto exception;
38612
0
            present = TRUE;
38613
0
        } else {
38614
0
            present = JS_TryGetPropertyInt64(ctx, obj, k1, &val);
38615
0
            if (present < 0)
38616
0
                goto exception;
38617
0
        }
38618
0
        if (present) {
38619
0
            index_val = JS_NewInt64(ctx, k1);
38620
0
            if (JS_IsException(index_val))
38621
0
                goto exception;
38622
0
            args[0] = acc;
38623
0
            args[1] = val;
38624
0
            args[2] = index_val;
38625
0
            args[3] = obj;
38626
0
            acc1 = JS_Call(ctx, func, JS_UNDEFINED, 4, args);
38627
0
            JS_FreeValue(ctx, index_val);
38628
0
            JS_FreeValue(ctx, val);
38629
0
            val = JS_UNDEFINED;
38630
0
            if (JS_IsException(acc1))
38631
0
                goto exception;
38632
0
            JS_FreeValue(ctx, acc);
38633
0
            acc = acc1;
38634
0
        }
38635
0
    }
38636
0
    JS_FreeValue(ctx, obj);
38637
0
    return acc;
38638
38639
0
exception:
38640
0
    JS_FreeValue(ctx, acc);
38641
0
    JS_FreeValue(ctx, val);
38642
0
    JS_FreeValue(ctx, obj);
38643
0
    return JS_EXCEPTION;
38644
0
}
38645
38646
static JSValue js_array_fill(JSContext *ctx, JSValueConst this_val,
38647
                             int argc, JSValueConst *argv)
38648
0
{
38649
0
    JSValue obj;
38650
0
    int64_t len, start, end;
38651
38652
0
    obj = JS_ToObject(ctx, this_val);
38653
0
    if (js_get_length64(ctx, &len, obj))
38654
0
        goto exception;
38655
38656
0
    start = 0;
38657
0
    if (argc > 1 && !JS_IsUndefined(argv[1])) {
38658
0
        if (JS_ToInt64Clamp(ctx, &start, argv[1], 0, len, len))
38659
0
            goto exception;
38660
0
    }
38661
38662
0
    end = len;
38663
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
38664
0
        if (JS_ToInt64Clamp(ctx, &end, argv[2], 0, len, len))
38665
0
            goto exception;
38666
0
    }
38667
38668
    /* XXX: should special case fast arrays */
38669
0
    while (start < end) {
38670
0
        if (JS_SetPropertyInt64(ctx, obj, start,
38671
0
                                JS_DupValue(ctx, argv[0])) < 0)
38672
0
            goto exception;
38673
0
        start++;
38674
0
    }
38675
0
    return obj;
38676
38677
0
 exception:
38678
0
    JS_FreeValue(ctx, obj);
38679
0
    return JS_EXCEPTION;
38680
0
}
38681
38682
static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val,
38683
                                 int argc, JSValueConst *argv)
38684
0
{
38685
0
    JSValue obj, val;
38686
0
    int64_t len, n, res;
38687
0
    JSValue *arrp;
38688
0
    uint32_t count;
38689
38690
0
    obj = JS_ToObject(ctx, this_val);
38691
0
    if (js_get_length64(ctx, &len, obj))
38692
0
        goto exception;
38693
38694
0
    res = FALSE;
38695
0
    if (len > 0) {
38696
0
        n = 0;
38697
0
        if (argc > 1) {
38698
0
            if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
38699
0
                goto exception;
38700
0
        }
38701
0
        if (js_get_fast_array(ctx, obj, &arrp, &count)) {
38702
0
            for (; n < count; n++) {
38703
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),
38704
0
                                  JS_DupValue(ctx, arrp[n]),
38705
0
                                  JS_EQ_SAME_VALUE_ZERO)) {
38706
0
                    res = TRUE;
38707
0
                    goto done;
38708
0
                }
38709
0
            }
38710
0
        }
38711
0
        for (; n < len; n++) {
38712
0
            val = JS_GetPropertyInt64(ctx, obj, n);
38713
0
            if (JS_IsException(val))
38714
0
                goto exception;
38715
0
            if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val,
38716
0
                              JS_EQ_SAME_VALUE_ZERO)) {
38717
0
                res = TRUE;
38718
0
                break;
38719
0
            }
38720
0
        }
38721
0
    }
38722
0
 done:
38723
0
    JS_FreeValue(ctx, obj);
38724
0
    return JS_NewBool(ctx, res);
38725
38726
0
 exception:
38727
0
    JS_FreeValue(ctx, obj);
38728
0
    return JS_EXCEPTION;
38729
0
}
38730
38731
static JSValue js_array_indexOf(JSContext *ctx, JSValueConst this_val,
38732
                                int argc, JSValueConst *argv)
38733
0
{
38734
0
    JSValue obj, val;
38735
0
    int64_t len, n, res;
38736
0
    JSValue *arrp;
38737
0
    uint32_t count;
38738
38739
0
    obj = JS_ToObject(ctx, this_val);
38740
0
    if (js_get_length64(ctx, &len, obj))
38741
0
        goto exception;
38742
38743
0
    res = -1;
38744
0
    if (len > 0) {
38745
0
        n = 0;
38746
0
        if (argc > 1) {
38747
0
            if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
38748
0
                goto exception;
38749
0
        }
38750
0
        if (js_get_fast_array(ctx, obj, &arrp, &count)) {
38751
0
            for (; n < count; n++) {
38752
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),
38753
0
                                  JS_DupValue(ctx, arrp[n]), JS_EQ_STRICT)) {
38754
0
                    res = n;
38755
0
                    goto done;
38756
0
                }
38757
0
            }
38758
0
        }
38759
0
        for (; n < len; n++) {
38760
0
            int present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
38761
0
            if (present < 0)
38762
0
                goto exception;
38763
0
            if (present) {
38764
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
38765
0
                    res = n;
38766
0
                    break;
38767
0
                }
38768
0
            }
38769
0
        }
38770
0
    }
38771
0
 done:
38772
0
    JS_FreeValue(ctx, obj);
38773
0
    return JS_NewInt64(ctx, res);
38774
38775
0
 exception:
38776
0
    JS_FreeValue(ctx, obj);
38777
0
    return JS_EXCEPTION;
38778
0
}
38779
38780
static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val,
38781
                                    int argc, JSValueConst *argv)
38782
0
{
38783
0
    JSValue obj, val;
38784
0
    int64_t len, n, res;
38785
0
    int present;
38786
38787
0
    obj = JS_ToObject(ctx, this_val);
38788
0
    if (js_get_length64(ctx, &len, obj))
38789
0
        goto exception;
38790
38791
0
    res = -1;
38792
0
    if (len > 0) {
38793
0
        n = len - 1;
38794
0
        if (argc > 1) {
38795
0
            if (JS_ToInt64Clamp(ctx, &n, argv[1], -1, len - 1, len))
38796
0
                goto exception;
38797
0
        }
38798
        /* XXX: should special case fast arrays */
38799
0
        for (; n >= 0; n--) {
38800
0
            present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
38801
0
            if (present < 0)
38802
0
                goto exception;
38803
0
            if (present) {
38804
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
38805
0
                    res = n;
38806
0
                    break;
38807
0
                }
38808
0
            }
38809
0
        }
38810
0
    }
38811
0
    JS_FreeValue(ctx, obj);
38812
0
    return JS_NewInt64(ctx, res);
38813
38814
0
 exception:
38815
0
    JS_FreeValue(ctx, obj);
38816
0
    return JS_EXCEPTION;
38817
0
}
38818
38819
static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
38820
                             int argc, JSValueConst *argv, int findIndex)
38821
0
{
38822
0
    JSValueConst func, this_arg;
38823
0
    JSValueConst args[3];
38824
0
    JSValue obj, val, index_val, res;
38825
0
    int64_t len, k;
38826
38827
0
    index_val = JS_UNDEFINED;
38828
0
    val = JS_UNDEFINED;
38829
0
    obj = JS_ToObject(ctx, this_val);
38830
0
    if (js_get_length64(ctx, &len, obj))
38831
0
        goto exception;
38832
38833
0
    func = argv[0];
38834
0
    if (check_function(ctx, func))
38835
0
        goto exception;
38836
38837
0
    this_arg = JS_UNDEFINED;
38838
0
    if (argc > 1)
38839
0
        this_arg = argv[1];
38840
38841
0
    for(k = 0; k < len; k++) {
38842
0
        index_val = JS_NewInt64(ctx, k);
38843
0
        if (JS_IsException(index_val))
38844
0
            goto exception;
38845
0
        val = JS_GetPropertyValue(ctx, obj, index_val);
38846
0
        if (JS_IsException(val))
38847
0
            goto exception;
38848
0
        args[0] = val;
38849
0
        args[1] = index_val;
38850
0
        args[2] = this_val;
38851
0
        res = JS_Call(ctx, func, this_arg, 3, args);
38852
0
        if (JS_IsException(res))
38853
0
            goto exception;
38854
0
        if (JS_ToBoolFree(ctx, res)) {
38855
0
            if (findIndex) {
38856
0
                JS_FreeValue(ctx, val);
38857
0
                JS_FreeValue(ctx, obj);
38858
0
                return index_val;
38859
0
            } else {
38860
0
                JS_FreeValue(ctx, index_val);
38861
0
                JS_FreeValue(ctx, obj);
38862
0
                return val;
38863
0
            }
38864
0
        }
38865
0
        JS_FreeValue(ctx, val);
38866
0
        JS_FreeValue(ctx, index_val);
38867
0
    }
38868
0
    JS_FreeValue(ctx, obj);
38869
0
    if (findIndex)
38870
0
        return JS_NewInt32(ctx, -1);
38871
0
    else
38872
0
        return JS_UNDEFINED;
38873
38874
0
exception:
38875
0
    JS_FreeValue(ctx, index_val);
38876
0
    JS_FreeValue(ctx, val);
38877
0
    JS_FreeValue(ctx, obj);
38878
0
    return JS_EXCEPTION;
38879
0
}
38880
38881
static JSValue js_array_toString(JSContext *ctx, JSValueConst this_val,
38882
                                 int argc, JSValueConst *argv)
38883
9
{
38884
9
    JSValue obj, method, ret;
38885
38886
9
    obj = JS_ToObject(ctx, this_val);
38887
9
    if (JS_IsException(obj))
38888
0
        return JS_EXCEPTION;
38889
9
    method = JS_GetProperty(ctx, obj, JS_ATOM_join);
38890
9
    if (JS_IsException(method)) {
38891
0
        ret = JS_EXCEPTION;
38892
0
    } else
38893
9
    if (!JS_IsFunction(ctx, method)) {
38894
        /* Use intrinsic Object.prototype.toString */
38895
0
        JS_FreeValue(ctx, method);
38896
0
        ret = js_object_toString(ctx, obj, 0, NULL);
38897
9
    } else {
38898
9
        ret = JS_CallFree(ctx, method, obj, 0, NULL);
38899
9
    }
38900
9
    JS_FreeValue(ctx, obj);
38901
9
    return ret;
38902
9
}
38903
38904
static JSValue js_array_join(JSContext *ctx, JSValueConst this_val,
38905
                             int argc, JSValueConst *argv, int toLocaleString)
38906
9
{
38907
9
    JSValue obj, sep = JS_UNDEFINED, el;
38908
9
    StringBuffer b_s, *b = &b_s;
38909
9
    JSString *p = NULL;
38910
9
    int64_t i, n;
38911
9
    int c;
38912
38913
9
    obj = JS_ToObject(ctx, this_val);
38914
9
    if (js_get_length64(ctx, &n, obj))
38915
0
        goto exception;
38916
38917
9
    c = ',';    /* default separator */
38918
9
    if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
38919
0
        sep = JS_ToString(ctx, argv[0]);
38920
0
        if (JS_IsException(sep))
38921
0
            goto exception;
38922
0
        p = JS_VALUE_GET_STRING(sep);
38923
0
        if (p->len == 1 && !p->is_wide_char)
38924
0
            c = p->u.str8[0];
38925
0
        else
38926
0
            c = -1;
38927
0
    }
38928
9
    string_buffer_init(ctx, b, 0);
38929
38930
152k
    for(i = 0; i < n; i++) {
38931
152k
        if (i > 0) {
38932
152k
            if (c >= 0) {
38933
152k
                string_buffer_putc8(b, c);
38934
152k
            } else {
38935
0
                string_buffer_concat(b, p, 0, p->len);
38936
0
            }
38937
152k
        }
38938
152k
        el = JS_GetPropertyUint32(ctx, obj, i);
38939
152k
        if (JS_IsException(el))
38940
0
            goto fail;
38941
152k
        if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
38942
152k
            if (toLocaleString) {
38943
0
                el = JS_ToLocaleStringFree(ctx, el);
38944
0
            }
38945
152k
            if (string_buffer_concat_value_free(b, el))
38946
0
                goto fail;
38947
152k
        }
38948
152k
    }
38949
9
    JS_FreeValue(ctx, sep);
38950
9
    JS_FreeValue(ctx, obj);
38951
9
    return string_buffer_end(b);
38952
38953
0
fail:
38954
0
    string_buffer_free(b);
38955
0
    JS_FreeValue(ctx, sep);
38956
0
exception:
38957
0
    JS_FreeValue(ctx, obj);
38958
0
    return JS_EXCEPTION;
38959
0
}
38960
38961
static JSValue js_array_pop(JSContext *ctx, JSValueConst this_val,
38962
                            int argc, JSValueConst *argv, int shift)
38963
0
{
38964
0
    JSValue obj, res = JS_UNDEFINED;
38965
0
    int64_t len, newLen;
38966
0
    JSValue *arrp;
38967
0
    uint32_t count32;
38968
38969
0
    obj = JS_ToObject(ctx, this_val);
38970
0
    if (js_get_length64(ctx, &len, obj))
38971
0
        goto exception;
38972
0
    newLen = 0;
38973
0
    if (len > 0) {
38974
0
        newLen = len - 1;
38975
        /* Special case fast arrays */
38976
0
        if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
38977
0
            JSObject *p = JS_VALUE_GET_OBJ(obj);
38978
0
            if (shift) {
38979
0
                res = arrp[0];
38980
0
                memmove(arrp, arrp + 1, (count32 - 1) * sizeof(*arrp));
38981
0
                p->u.array.count--;
38982
0
            } else {
38983
0
                res = arrp[count32 - 1];
38984
0
                p->u.array.count--;
38985
0
            }
38986
0
        } else {
38987
0
            if (shift) {
38988
0
                res = JS_GetPropertyInt64(ctx, obj, 0);
38989
0
                if (JS_IsException(res))
38990
0
                    goto exception;
38991
0
                if (JS_CopySubArray(ctx, obj, 0, 1, len - 1, +1))
38992
0
                    goto exception;
38993
0
            } else {
38994
0
                res = JS_GetPropertyInt64(ctx, obj, newLen);
38995
0
                if (JS_IsException(res))
38996
0
                    goto exception;
38997
0
            }
38998
0
            if (JS_DeletePropertyInt64(ctx, obj, newLen, JS_PROP_THROW) < 0)
38999
0
                goto exception;
39000
0
        }
39001
0
    }
39002
0
    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
39003
0
        goto exception;
39004
39005
0
    JS_FreeValue(ctx, obj);
39006
0
    return res;
39007
39008
0
 exception:
39009
0
    JS_FreeValue(ctx, res);
39010
0
    JS_FreeValue(ctx, obj);
39011
0
    return JS_EXCEPTION;
39012
0
}
39013
39014
static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
39015
                             int argc, JSValueConst *argv, int unshift)
39016
0
{
39017
0
    JSValue obj;
39018
0
    int i;
39019
0
    int64_t len, from, newLen;
39020
39021
0
    obj = JS_ToObject(ctx, this_val);
39022
0
    if (js_get_length64(ctx, &len, obj))
39023
0
        goto exception;
39024
0
    newLen = len + argc;
39025
0
    if (newLen > MAX_SAFE_INTEGER) {
39026
0
        JS_ThrowTypeError(ctx, "Array loo long");
39027
0
        goto exception;
39028
0
    }
39029
0
    from = len;
39030
0
    if (unshift && argc > 0) {
39031
0
        if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
39032
0
            goto exception;
39033
0
        from = 0;
39034
0
    }
39035
0
    for(i = 0; i < argc; i++) {
39036
0
        if (JS_SetPropertyInt64(ctx, obj, from + i,
39037
0
                                JS_DupValue(ctx, argv[i])) < 0)
39038
0
            goto exception;
39039
0
    }
39040
0
    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
39041
0
        goto exception;
39042
39043
0
    JS_FreeValue(ctx, obj);
39044
0
    return JS_NewInt64(ctx, newLen);
39045
39046
0
 exception:
39047
0
    JS_FreeValue(ctx, obj);
39048
0
    return JS_EXCEPTION;
39049
0
}
39050
39051
static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val,
39052
                                int argc, JSValueConst *argv)
39053
0
{
39054
0
    JSValue obj, lval, hval;
39055
0
    JSValue *arrp;
39056
0
    int64_t len, l, h;
39057
0
    int l_present, h_present;
39058
0
    uint32_t count32;
39059
39060
0
    lval = JS_UNDEFINED;
39061
0
    obj = JS_ToObject(ctx, this_val);
39062
0
    if (js_get_length64(ctx, &len, obj))
39063
0
        goto exception;
39064
39065
    /* Special case fast arrays */
39066
0
    if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
39067
0
        uint32_t ll, hh;
39068
39069
0
        if (count32 > 1) {
39070
0
            for (ll = 0, hh = count32 - 1; ll < hh; ll++, hh--) {
39071
0
                lval = arrp[ll];
39072
0
                arrp[ll] = arrp[hh];
39073
0
                arrp[hh] = lval;
39074
0
            }
39075
0
        }
39076
0
        return obj;
39077
0
    }
39078
39079
0
    for (l = 0, h = len - 1; l < h; l++, h--) {
39080
0
        l_present = JS_TryGetPropertyInt64(ctx, obj, l, &lval);
39081
0
        if (l_present < 0)
39082
0
            goto exception;
39083
0
        h_present = JS_TryGetPropertyInt64(ctx, obj, h, &hval);
39084
0
        if (h_present < 0)
39085
0
            goto exception;
39086
0
        if (h_present) {
39087
0
            if (JS_SetPropertyInt64(ctx, obj, l, hval) < 0)
39088
0
                goto exception;
39089
39090
0
            if (l_present) {
39091
0
                if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
39092
0
                    lval = JS_UNDEFINED;
39093
0
                    goto exception;
39094
0
                }
39095
0
                lval = JS_UNDEFINED;
39096
0
            } else {
39097
0
                if (JS_DeletePropertyInt64(ctx, obj, h, JS_PROP_THROW) < 0)
39098
0
                    goto exception;
39099
0
            }
39100
0
        } else {
39101
0
            if (l_present) {
39102
0
                if (JS_DeletePropertyInt64(ctx, obj, l, JS_PROP_THROW) < 0)
39103
0
                    goto exception;
39104
0
                if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
39105
0
                    lval = JS_UNDEFINED;
39106
0
                    goto exception;
39107
0
                }
39108
0
                lval = JS_UNDEFINED;
39109
0
            }
39110
0
        }
39111
0
    }
39112
0
    return obj;
39113
39114
0
 exception:
39115
0
    JS_FreeValue(ctx, lval);
39116
0
    JS_FreeValue(ctx, obj);
39117
0
    return JS_EXCEPTION;
39118
0
}
39119
39120
static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
39121
                              int argc, JSValueConst *argv, int splice)
39122
0
{
39123
0
    JSValue obj, arr, val, len_val;
39124
0
    int64_t len, start, k, final, n, count, del_count, new_len;
39125
0
    int kPresent;
39126
0
    JSValue *arrp;
39127
0
    uint32_t count32, i, item_count;
39128
39129
0
    arr = JS_UNDEFINED;
39130
0
    obj = JS_ToObject(ctx, this_val);
39131
0
    if (js_get_length64(ctx, &len, obj))
39132
0
        goto exception;
39133
39134
0
    if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
39135
0
        goto exception;
39136
39137
0
    if (splice) {
39138
0
        if (argc == 0) {
39139
0
            item_count = 0;
39140
0
            del_count = 0;
39141
0
        } else
39142
0
        if (argc == 1) {
39143
0
            item_count = 0;
39144
0
            del_count = len - start;
39145
0
        } else {
39146
0
            item_count = argc - 2;
39147
0
            if (JS_ToInt64Clamp(ctx, &del_count, argv[1], 0, len - start, 0))
39148
0
                goto exception;
39149
0
        }
39150
0
        if (len + item_count - del_count > MAX_SAFE_INTEGER) {
39151
0
            JS_ThrowTypeError(ctx, "Array loo long");
39152
0
            goto exception;
39153
0
        }
39154
0
        count = del_count;
39155
0
    } else {
39156
0
        item_count = 0; /* avoid warning */
39157
0
        final = len;
39158
0
        if (!JS_IsUndefined(argv[1])) {
39159
0
            if (JS_ToInt64Clamp(ctx, &final, argv[1], 0, len, len))
39160
0
                goto exception;
39161
0
        }
39162
0
        count = max_int64(final - start, 0);
39163
0
    }
39164
0
    len_val = JS_NewInt64(ctx, count);
39165
0
    arr = JS_ArraySpeciesCreate(ctx, obj, len_val);
39166
0
    JS_FreeValue(ctx, len_val);
39167
0
    if (JS_IsException(arr))
39168
0
        goto exception;
39169
39170
0
    k = start;
39171
0
    final = start + count;
39172
0
    n = 0;
39173
    /* The fast array test on arr ensures that
39174
       JS_CreateDataPropertyUint32() won't modify obj in case arr is
39175
       an exotic object */
39176
    /* Special case fast arrays */
39177
0
    if (js_get_fast_array(ctx, obj, &arrp, &count32) &&
39178
0
        js_is_fast_array(ctx, arr)) {
39179
        /* XXX: should share code with fast array constructor */
39180
0
        for (; k < final && k < count32; k++, n++) {
39181
0
            if (JS_CreateDataPropertyUint32(ctx, arr, n, JS_DupValue(ctx, arrp[k]), JS_PROP_THROW) < 0)
39182
0
                goto exception;
39183
0
        }
39184
0
    }
39185
    /* Copy the remaining elements if any (handle case of inherited properties) */
39186
0
    for (; k < final; k++, n++) {
39187
0
        kPresent = JS_TryGetPropertyInt64(ctx, obj, k, &val);
39188
0
        if (kPresent < 0)
39189
0
            goto exception;
39190
0
        if (kPresent) {
39191
0
            if (JS_CreateDataPropertyUint32(ctx, arr, n, val, JS_PROP_THROW) < 0)
39192
0
                goto exception;
39193
0
        }
39194
0
    }
39195
0
    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
39196
0
        goto exception;
39197
39198
0
    if (splice) {
39199
0
        new_len = len + item_count - del_count;
39200
0
        if (item_count != del_count) {
39201
0
            if (JS_CopySubArray(ctx, obj, start + item_count,
39202
0
                                start + del_count, len - (start + del_count),
39203
0
                                item_count <= del_count ? +1 : -1) < 0)
39204
0
                goto exception;
39205
39206
0
            for (k = len; k-- > new_len; ) {
39207
0
                if (JS_DeletePropertyInt64(ctx, obj, k, JS_PROP_THROW) < 0)
39208
0
                    goto exception;
39209
0
            }
39210
0
        }
39211
0
        for (i = 0; i < item_count; i++) {
39212
0
            if (JS_SetPropertyInt64(ctx, obj, start + i, JS_DupValue(ctx, argv[i + 2])) < 0)
39213
0
                goto exception;
39214
0
        }
39215
0
        if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, new_len)) < 0)
39216
0
            goto exception;
39217
0
    }
39218
0
    JS_FreeValue(ctx, obj);
39219
0
    return arr;
39220
39221
0
 exception:
39222
0
    JS_FreeValue(ctx, obj);
39223
0
    JS_FreeValue(ctx, arr);
39224
0
    return JS_EXCEPTION;
39225
0
}
39226
39227
static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val,
39228
                                   int argc, JSValueConst *argv)
39229
0
{
39230
0
    JSValue obj;
39231
0
    int64_t len, from, to, final, count;
39232
39233
0
    obj = JS_ToObject(ctx, this_val);
39234
0
    if (js_get_length64(ctx, &len, obj))
39235
0
        goto exception;
39236
39237
0
    if (JS_ToInt64Clamp(ctx, &to, argv[0], 0, len, len))
39238
0
        goto exception;
39239
39240
0
    if (JS_ToInt64Clamp(ctx, &from, argv[1], 0, len, len))
39241
0
        goto exception;
39242
39243
0
    final = len;
39244
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
39245
0
        if (JS_ToInt64Clamp(ctx, &final, argv[2], 0, len, len))
39246
0
            goto exception;
39247
0
    }
39248
39249
0
    count = min_int64(final - from, len - to);
39250
39251
0
    if (JS_CopySubArray(ctx, obj, to, from, count,
39252
0
                        (from < to && to < from + count) ? -1 : +1))
39253
0
        goto exception;
39254
39255
0
    return obj;
39256
39257
0
 exception:
39258
0
    JS_FreeValue(ctx, obj);
39259
0
    return JS_EXCEPTION;
39260
0
}
39261
39262
static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
39263
                                   JSValueConst source, int64_t sourceLen,
39264
                                   int64_t targetIndex, int depth,
39265
                                   JSValueConst mapperFunction,
39266
                                   JSValueConst thisArg)
39267
0
{
39268
0
    JSValue element;
39269
0
    int64_t sourceIndex, elementLen;
39270
0
    int present, is_array;
39271
39272
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
39273
0
        JS_ThrowStackOverflow(ctx);
39274
0
        return -1;
39275
0
    }
39276
39277
0
    for (sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
39278
0
        present = JS_TryGetPropertyInt64(ctx, source, sourceIndex, &element);
39279
0
        if (present < 0)
39280
0
            return -1;
39281
0
        if (!present)
39282
0
            continue;
39283
0
        if (!JS_IsUndefined(mapperFunction)) {
39284
0
            JSValueConst args[3] = { element, JS_NewInt64(ctx, sourceIndex), source };
39285
0
            element = JS_Call(ctx, mapperFunction, thisArg, 3, args);
39286
0
            JS_FreeValue(ctx, (JSValue)args[0]);
39287
0
            JS_FreeValue(ctx, (JSValue)args[1]);
39288
0
            if (JS_IsException(element))
39289
0
                return -1;
39290
0
        }
39291
0
        if (depth > 0) {
39292
0
            is_array = JS_IsArray(ctx, element);
39293
0
            if (is_array < 0)
39294
0
                goto fail;
39295
0
            if (is_array) {
39296
0
                if (js_get_length64(ctx, &elementLen, element) < 0)
39297
0
                    goto fail;
39298
0
                targetIndex = JS_FlattenIntoArray(ctx, target, element,
39299
0
                                                  elementLen, targetIndex,
39300
0
                                                  depth - 1,
39301
0
                                                  JS_UNDEFINED, JS_UNDEFINED);
39302
0
                if (targetIndex < 0)
39303
0
                    goto fail;
39304
0
                JS_FreeValue(ctx, element);
39305
0
                continue;
39306
0
            }
39307
0
        }
39308
0
        if (targetIndex >= MAX_SAFE_INTEGER) {
39309
0
            JS_ThrowTypeError(ctx, "Array too long");
39310
0
            goto fail;
39311
0
        }
39312
0
        if (JS_DefinePropertyValueInt64(ctx, target, targetIndex, element,
39313
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
39314
0
            return -1;
39315
0
        targetIndex++;
39316
0
    }
39317
0
    return targetIndex;
39318
39319
0
fail:
39320
0
    JS_FreeValue(ctx, element);
39321
0
    return -1;
39322
0
}
39323
39324
static JSValue js_array_flatten(JSContext *ctx, JSValueConst this_val,
39325
                                int argc, JSValueConst *argv, int map)
39326
0
{
39327
0
    JSValue obj, arr;
39328
0
    JSValueConst mapperFunction, thisArg;
39329
0
    int64_t sourceLen;
39330
0
    int depthNum;
39331
39332
0
    arr = JS_UNDEFINED;
39333
0
    obj = JS_ToObject(ctx, this_val);
39334
0
    if (js_get_length64(ctx, &sourceLen, obj))
39335
0
        goto exception;
39336
39337
0
    depthNum = 1;
39338
0
    mapperFunction = JS_UNDEFINED;
39339
0
    thisArg = JS_UNDEFINED;
39340
0
    if (map) {
39341
0
        mapperFunction = argv[0];
39342
0
        if (argc > 1) {
39343
0
            thisArg = argv[1];
39344
0
        }
39345
0
        if (check_function(ctx, mapperFunction))
39346
0
            goto exception;
39347
0
    } else {
39348
0
        if (argc > 0 && !JS_IsUndefined(argv[0])) {
39349
0
            if (JS_ToInt32Sat(ctx, &depthNum, argv[0]) < 0)
39350
0
                goto exception;
39351
0
        }
39352
0
    }
39353
0
    arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
39354
0
    if (JS_IsException(arr))
39355
0
        goto exception;
39356
0
    if (JS_FlattenIntoArray(ctx, arr, obj, sourceLen, 0, depthNum,
39357
0
                            mapperFunction, thisArg) < 0)
39358
0
        goto exception;
39359
0
    JS_FreeValue(ctx, obj);
39360
0
    return arr;
39361
39362
0
exception:
39363
0
    JS_FreeValue(ctx, obj);
39364
0
    JS_FreeValue(ctx, arr);
39365
0
    return JS_EXCEPTION;
39366
0
}
39367
39368
/* Array sort */
39369
39370
typedef struct ValueSlot {
39371
    JSValue val;
39372
    JSString *str;
39373
    int64_t pos;
39374
} ValueSlot;
39375
39376
struct array_sort_context {
39377
    JSContext *ctx;
39378
    int exception;
39379
    int has_method;
39380
    JSValueConst method;
39381
};
39382
39383
0
static int js_array_cmp_generic(const void *a, const void *b, void *opaque) {
39384
0
    struct array_sort_context *psc = opaque;
39385
0
    JSContext *ctx = psc->ctx;
39386
0
    JSValueConst argv[2];
39387
0
    JSValue res;
39388
0
    ValueSlot *ap = (ValueSlot *)(void *)a;
39389
0
    ValueSlot *bp = (ValueSlot *)(void *)b;
39390
0
    int cmp;
39391
39392
0
    if (psc->exception)
39393
0
        return 0;
39394
39395
0
    if (psc->has_method) {
39396
        /* custom sort function is specified as returning 0 for identical
39397
         * objects: avoid method call overhead.
39398
         */
39399
0
        if (!memcmp(&ap->val, &bp->val, sizeof(ap->val)))
39400
0
            goto cmp_same;
39401
0
        argv[0] = ap->val;
39402
0
        argv[1] = bp->val;
39403
0
        res = JS_Call(ctx, psc->method, JS_UNDEFINED, 2, argv);
39404
0
        if (JS_IsException(res))
39405
0
            goto exception;
39406
0
        if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
39407
0
            int val = JS_VALUE_GET_INT(res);
39408
0
            cmp = (val > 0) - (val < 0);
39409
0
        } else {
39410
0
            double val;
39411
0
            if (JS_ToFloat64Free(ctx, &val, res) < 0)
39412
0
                goto exception;
39413
0
            cmp = (val > 0) - (val < 0);
39414
0
        }
39415
0
    } else {
39416
        /* Not supposed to bypass ToString even for identical objects as
39417
         * tested in test262/test/built-ins/Array/prototype/sort/bug_596_1.js
39418
         */
39419
0
        if (!ap->str) {
39420
0
            JSValue str = JS_ToString(ctx, ap->val);
39421
0
            if (JS_IsException(str))
39422
0
                goto exception;
39423
0
            ap->str = JS_VALUE_GET_STRING(str);
39424
0
        }
39425
0
        if (!bp->str) {
39426
0
            JSValue str = JS_ToString(ctx, bp->val);
39427
0
            if (JS_IsException(str))
39428
0
                goto exception;
39429
0
            bp->str = JS_VALUE_GET_STRING(str);
39430
0
        }
39431
0
        cmp = js_string_compare(ctx, ap->str, bp->str);
39432
0
    }
39433
0
    if (cmp != 0)
39434
0
        return cmp;
39435
0
cmp_same:
39436
    /* make sort stable: compare array offsets */
39437
0
    return (ap->pos > bp->pos) - (ap->pos < bp->pos);
39438
39439
0
exception:
39440
0
    psc->exception = 1;
39441
0
    return 0;
39442
0
}
39443
39444
static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val,
39445
                             int argc, JSValueConst *argv)
39446
0
{
39447
0
    struct array_sort_context asc = { ctx, 0, 0, argv[0] };
39448
0
    JSValue obj = JS_UNDEFINED;
39449
0
    ValueSlot *array = NULL;
39450
0
    size_t array_size = 0, pos = 0, n = 0;
39451
0
    int64_t i, len, undefined_count = 0;
39452
0
    int present;
39453
39454
0
    if (!JS_IsUndefined(asc.method)) {
39455
0
        if (check_function(ctx, asc.method))
39456
0
            goto exception;
39457
0
        asc.has_method = 1;
39458
0
    }
39459
0
    obj = JS_ToObject(ctx, this_val);
39460
0
    if (js_get_length64(ctx, &len, obj))
39461
0
        goto exception;
39462
39463
    /* XXX: should special case fast arrays */
39464
0
    for (i = 0; i < len; i++) {
39465
0
        if (pos >= array_size) {
39466
0
            size_t new_size, slack;
39467
0
            ValueSlot *new_array;
39468
0
            new_size = (array_size + (array_size >> 1) + 31) & ~15;
39469
0
            new_array = js_realloc2(ctx, array, new_size * sizeof(*array), &slack);
39470
0
            if (new_array == NULL)
39471
0
                goto exception;
39472
0
            new_size += slack / sizeof(*new_array);
39473
0
            array = new_array;
39474
0
            array_size = new_size;
39475
0
        }
39476
0
        present = JS_TryGetPropertyInt64(ctx, obj, i, &array[pos].val);
39477
0
        if (present < 0)
39478
0
            goto exception;
39479
0
        if (present == 0)
39480
0
            continue;
39481
0
        if (JS_IsUndefined(array[pos].val)) {
39482
0
            undefined_count++;
39483
0
            continue;
39484
0
        }
39485
0
        array[pos].str = NULL;
39486
0
        array[pos].pos = i;
39487
0
        pos++;
39488
0
    }
39489
0
    rqsort(array, pos, sizeof(*array), js_array_cmp_generic, &asc);
39490
0
    if (asc.exception)
39491
0
        goto exception;
39492
39493
    /* XXX: should special case fast arrays */
39494
0
    while (n < pos) {
39495
0
        if (array[n].str)
39496
0
            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
39497
0
        if (array[n].pos == n) {
39498
0
            JS_FreeValue(ctx, array[n].val);
39499
0
        } else {
39500
0
            if (JS_SetPropertyInt64(ctx, obj, n, array[n].val) < 0) {
39501
0
                n++;
39502
0
                goto exception;
39503
0
            }
39504
0
        }
39505
0
        n++;
39506
0
    }
39507
0
    js_free(ctx, array);
39508
0
    for (i = n; undefined_count-- > 0; i++) {
39509
0
        if (JS_SetPropertyInt64(ctx, obj, i, JS_UNDEFINED) < 0)
39510
0
            goto fail;
39511
0
    }
39512
0
    for (; i < len; i++) {
39513
0
        if (JS_DeletePropertyInt64(ctx, obj, i, JS_PROP_THROW) < 0)
39514
0
            goto fail;
39515
0
    }
39516
0
    return obj;
39517
39518
0
exception:
39519
0
    for (; n < pos; n++) {
39520
0
        JS_FreeValue(ctx, array[n].val);
39521
0
        if (array[n].str)
39522
0
            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
39523
0
    }
39524
0
    js_free(ctx, array);
39525
0
fail:
39526
0
    JS_FreeValue(ctx, obj);
39527
0
    return JS_EXCEPTION;
39528
0
}
39529
39530
typedef struct JSArrayIteratorData {
39531
    JSValue obj;
39532
    JSIteratorKindEnum kind;
39533
    uint32_t idx;
39534
} JSArrayIteratorData;
39535
39536
static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val)
39537
3
{
39538
3
    JSObject *p = JS_VALUE_GET_OBJ(val);
39539
3
    JSArrayIteratorData *it = p->u.array_iterator_data;
39540
3
    if (it) {
39541
3
        JS_FreeValueRT(rt, it->obj);
39542
3
        js_free_rt(rt, it);
39543
3
    }
39544
3
}
39545
39546
static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
39547
                                   JS_MarkFunc *mark_func)
39548
0
{
39549
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
39550
0
    JSArrayIteratorData *it = p->u.array_iterator_data;
39551
0
    if (it) {
39552
0
        JS_MarkValue(rt, it->obj, mark_func);
39553
0
    }
39554
0
}
39555
39556
static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab)
39557
0
{
39558
0
    JSValue obj;
39559
0
    int i;
39560
39561
0
    obj = JS_NewArray(ctx);
39562
0
    if (JS_IsException(obj))
39563
0
        return JS_EXCEPTION;
39564
0
    for(i = 0; i < len; i++) {
39565
0
        if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, tab[i]), 0) < 0) {
39566
0
            JS_FreeValue(ctx, obj);
39567
0
            return JS_EXCEPTION;
39568
0
        }
39569
0
    }
39570
0
    return obj;
39571
0
}
39572
39573
static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
39574
                                        int argc, JSValueConst *argv, int magic)
39575
3
{
39576
3
    JSValue enum_obj, arr;
39577
3
    JSArrayIteratorData *it;
39578
3
    JSIteratorKindEnum kind;
39579
3
    int class_id;
39580
39581
3
    kind = magic & 3;
39582
3
    if (magic & 4) {
39583
        /* string iterator case */
39584
3
        arr = JS_ToStringCheckObject(ctx, this_val);
39585
3
        class_id = JS_CLASS_STRING_ITERATOR;
39586
3
    } else {
39587
0
        arr = JS_ToObject(ctx, this_val);
39588
0
        class_id = JS_CLASS_ARRAY_ITERATOR;
39589
0
    }
39590
3
    if (JS_IsException(arr))
39591
0
        goto fail;
39592
3
    enum_obj = JS_NewObjectClass(ctx, class_id);
39593
3
    if (JS_IsException(enum_obj))
39594
0
        goto fail;
39595
3
    it = js_malloc(ctx, sizeof(*it));
39596
3
    if (!it)
39597
0
        goto fail1;
39598
3
    it->obj = arr;
39599
3
    it->kind = kind;
39600
3
    it->idx = 0;
39601
3
    JS_SetOpaque(enum_obj, it);
39602
3
    return enum_obj;
39603
0
 fail1:
39604
0
    JS_FreeValue(ctx, enum_obj);
39605
0
 fail:
39606
0
    JS_FreeValue(ctx, arr);
39607
0
    return JS_EXCEPTION;
39608
0
}
39609
39610
static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
39611
                                      int argc, JSValueConst *argv,
39612
                                      BOOL *pdone, int magic)
39613
0
{
39614
0
    JSArrayIteratorData *it;
39615
0
    uint32_t len, idx;
39616
0
    JSValue val, obj;
39617
0
    JSObject *p;
39618
39619
0
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_ITERATOR);
39620
0
    if (!it)
39621
0
        goto fail1;
39622
0
    if (JS_IsUndefined(it->obj))
39623
0
        goto done;
39624
0
    p = JS_VALUE_GET_OBJ(it->obj);
39625
0
    if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
39626
0
        p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
39627
0
        if (typed_array_is_detached(ctx, p)) {
39628
0
            JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
39629
0
            goto fail1;
39630
0
        }
39631
0
        len = p->u.array.count;
39632
0
    } else {
39633
0
        if (js_get_length32(ctx, &len, it->obj)) {
39634
0
        fail1:
39635
0
            *pdone = FALSE;
39636
0
            return JS_EXCEPTION;
39637
0
        }
39638
0
    }
39639
0
    idx = it->idx;
39640
0
    if (idx >= len) {
39641
0
        JS_FreeValue(ctx, it->obj);
39642
0
        it->obj = JS_UNDEFINED;
39643
0
    done:
39644
0
        *pdone = TRUE;
39645
0
        return JS_UNDEFINED;
39646
0
    }
39647
0
    it->idx = idx + 1;
39648
0
    *pdone = FALSE;
39649
0
    if (it->kind == JS_ITERATOR_KIND_KEY) {
39650
0
        return JS_NewUint32(ctx, idx);
39651
0
    } else {
39652
0
        val = JS_GetPropertyUint32(ctx, it->obj, idx);
39653
0
        if (JS_IsException(val))
39654
0
            return JS_EXCEPTION;
39655
0
        if (it->kind == JS_ITERATOR_KIND_VALUE) {
39656
0
            return val;
39657
0
        } else {
39658
0
            JSValueConst args[2];
39659
0
            JSValue num;
39660
0
            num = JS_NewUint32(ctx, idx);
39661
0
            args[0] = num;
39662
0
            args[1] = val;
39663
0
            obj = js_create_array(ctx, 2, args);
39664
0
            JS_FreeValue(ctx, val);
39665
0
            JS_FreeValue(ctx, num);
39666
0
            return obj;
39667
0
        }
39668
0
    }
39669
0
}
39670
39671
static JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val,
39672
                                          int argc, JSValueConst *argv)
39673
0
{
39674
0
    return JS_DupValue(ctx, this_val);
39675
0
}
39676
39677
static const JSCFunctionListEntry js_iterator_proto_funcs[] = {
39678
    JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator ),
39679
};
39680
39681
static const JSCFunctionListEntry js_array_proto_funcs[] = {
39682
    JS_CFUNC_DEF("concat", 1, js_array_concat ),
39683
    JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every ),
39684
    JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some ),
39685
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach ),
39686
    JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map ),
39687
    JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter ),
39688
    JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ),
39689
    JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ),
39690
    JS_CFUNC_DEF("fill", 1, js_array_fill ),
39691
    JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, 0 ),
39692
    JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, 1 ),
39693
    JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ),
39694
    JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ),
39695
    JS_CFUNC_DEF("includes", 1, js_array_includes ),
39696
    JS_CFUNC_MAGIC_DEF("join", 1, js_array_join, 0 ),
39697
    JS_CFUNC_DEF("toString", 0, js_array_toString ),
39698
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_array_join, 1 ),
39699
    JS_CFUNC_MAGIC_DEF("pop", 0, js_array_pop, 0 ),
39700
    JS_CFUNC_MAGIC_DEF("push", 1, js_array_push, 0 ),
39701
    JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1 ),
39702
    JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ),
39703
    JS_CFUNC_DEF("reverse", 0, js_array_reverse ),
39704
    JS_CFUNC_DEF("sort", 1, js_array_sort ),
39705
    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ),
39706
    JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ),
39707
    JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ),
39708
    JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ),
39709
    JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ),
39710
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ),
39711
    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
39712
    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ),
39713
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
39714
};
39715
39716
static const JSCFunctionListEntry js_array_iterator_proto_funcs[] = {
39717
    JS_ITERATOR_NEXT_DEF("next", 0, js_array_iterator_next, 0 ),
39718
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Array Iterator", JS_PROP_CONFIGURABLE ),
39719
};
39720
39721
/* Number */
39722
39723
static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
39724
                                     int argc, JSValueConst *argv)
39725
0
{
39726
0
    JSValue val, obj;
39727
0
    if (argc == 0) {
39728
0
        val = JS_NewInt32(ctx, 0);
39729
0
    } else {
39730
0
        val = JS_ToNumeric(ctx, argv[0]);
39731
0
        if (JS_IsException(val))
39732
0
            return val;
39733
0
        switch(JS_VALUE_GET_TAG(val)) {
39734
0
#ifdef CONFIG_BIGNUM
39735
0
        case JS_TAG_BIG_INT:
39736
0
        case JS_TAG_BIG_FLOAT:
39737
0
            {
39738
0
                JSBigFloat *p = JS_VALUE_GET_PTR(val);
39739
0
                double d;
39740
0
                bf_get_float64(&p->num, &d, BF_RNDN);
39741
0
                JS_FreeValue(ctx, val);
39742
0
                val = __JS_NewFloat64(ctx, d);
39743
0
            }
39744
0
            break;
39745
0
        case JS_TAG_BIG_DECIMAL:
39746
0
            val = JS_ToStringFree(ctx, val);
39747
0
            if (JS_IsException(val))
39748
0
                return val;
39749
0
            val = JS_ToNumberFree(ctx, val);
39750
0
            if (JS_IsException(val))
39751
0
                return val;
39752
0
            break;
39753
0
#endif
39754
0
        default:
39755
0
            break;
39756
0
        }
39757
0
    }
39758
0
    if (!JS_IsUndefined(new_target)) {
39759
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);
39760
0
        if (!JS_IsException(obj))
39761
0
            JS_SetObjectData(ctx, obj, val);
39762
0
        return obj;
39763
0
    } else {
39764
0
        return val;
39765
0
    }
39766
0
}
39767
39768
#if 0
39769
static JSValue js_number___toInteger(JSContext *ctx, JSValueConst this_val,
39770
                                     int argc, JSValueConst *argv)
39771
{
39772
    return JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[0]));
39773
}
39774
39775
static JSValue js_number___toLength(JSContext *ctx, JSValueConst this_val,
39776
                                    int argc, JSValueConst *argv)
39777
{
39778
    int64_t v;
39779
    if (JS_ToLengthFree(ctx, &v, JS_DupValue(ctx, argv[0])))
39780
        return JS_EXCEPTION;
39781
    return JS_NewInt64(ctx, v);
39782
}
39783
#endif
39784
39785
static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,
39786
                               int argc, JSValueConst *argv)
39787
0
{
39788
0
    if (!JS_IsNumber(argv[0]))
39789
0
        return JS_FALSE;
39790
0
    return js_global_isNaN(ctx, this_val, argc, argv);
39791
0
}
39792
39793
static JSValue js_number_isFinite(JSContext *ctx, JSValueConst this_val,
39794
                                  int argc, JSValueConst *argv)
39795
0
{
39796
0
    if (!JS_IsNumber(argv[0]))
39797
0
        return JS_FALSE;
39798
0
    return js_global_isFinite(ctx, this_val, argc, argv);
39799
0
}
39800
39801
static JSValue js_number_isInteger(JSContext *ctx, JSValueConst this_val,
39802
                                   int argc, JSValueConst *argv)
39803
0
{
39804
0
    int ret;
39805
0
    ret = JS_NumberIsInteger(ctx, argv[0]);
39806
0
    if (ret < 0)
39807
0
        return JS_EXCEPTION;
39808
0
    else
39809
0
        return JS_NewBool(ctx, ret);
39810
0
}
39811
39812
static JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val,
39813
                                       int argc, JSValueConst *argv)
39814
0
{
39815
0
    double d;
39816
0
    if (!JS_IsNumber(argv[0]))
39817
0
        return JS_FALSE;
39818
0
    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
39819
0
        return JS_EXCEPTION;
39820
0
    return JS_NewBool(ctx, is_safe_integer(d));
39821
0
}
39822
39823
static const JSCFunctionListEntry js_number_funcs[] = {
39824
    /* global ParseInt and parseFloat should be defined already or delayed */
39825
    JS_ALIAS_BASE_DEF("parseInt", "parseInt", 0 ),
39826
    JS_ALIAS_BASE_DEF("parseFloat", "parseFloat", 0 ),
39827
    JS_CFUNC_DEF("isNaN", 1, js_number_isNaN ),
39828
    JS_CFUNC_DEF("isFinite", 1, js_number_isFinite ),
39829
    JS_CFUNC_DEF("isInteger", 1, js_number_isInteger ),
39830
    JS_CFUNC_DEF("isSafeInteger", 1, js_number_isSafeInteger ),
39831
    JS_PROP_DOUBLE_DEF("MAX_VALUE", 1.7976931348623157e+308, 0 ),
39832
    JS_PROP_DOUBLE_DEF("MIN_VALUE", 5e-324, 0 ),
39833
    JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
39834
    JS_PROP_DOUBLE_DEF("NEGATIVE_INFINITY", -INFINITY, 0 ),
39835
    JS_PROP_DOUBLE_DEF("POSITIVE_INFINITY", INFINITY, 0 ),
39836
    JS_PROP_DOUBLE_DEF("EPSILON", 2.220446049250313e-16, 0 ), /* ES6 */
39837
    JS_PROP_DOUBLE_DEF("MAX_SAFE_INTEGER", 9007199254740991.0, 0 ), /* ES6 */
39838
    JS_PROP_DOUBLE_DEF("MIN_SAFE_INTEGER", -9007199254740991.0, 0 ), /* ES6 */
39839
    //JS_CFUNC_DEF("__toInteger", 1, js_number___toInteger ),
39840
    //JS_CFUNC_DEF("__toLength", 1, js_number___toLength ),
39841
};
39842
39843
static JSValue js_thisNumberValue(JSContext *ctx, JSValueConst this_val)
39844
0
{
39845
0
    if (JS_IsNumber(this_val))
39846
0
        return JS_DupValue(ctx, this_val);
39847
39848
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
39849
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
39850
0
        if (p->class_id == JS_CLASS_NUMBER) {
39851
0
            if (JS_IsNumber(p->u.object_data))
39852
0
                return JS_DupValue(ctx, p->u.object_data);
39853
0
        }
39854
0
    }
39855
0
    return JS_ThrowTypeError(ctx, "not a number");
39856
0
}
39857
39858
static JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val,
39859
                                 int argc, JSValueConst *argv)
39860
0
{
39861
0
    return js_thisNumberValue(ctx, this_val);
39862
0
}
39863
39864
static int js_get_radix(JSContext *ctx, JSValueConst val)
39865
0
{
39866
0
    int radix;
39867
0
    if (JS_ToInt32Sat(ctx, &radix, val))
39868
0
        return -1;
39869
0
    if (radix < 2 || radix > 36) {
39870
0
        JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
39871
0
        return -1;
39872
0
    }
39873
0
    return radix;
39874
0
}
39875
39876
static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
39877
                                  int argc, JSValueConst *argv, int magic)
39878
0
{
39879
0
    JSValue val;
39880
0
    int base;
39881
0
    double d;
39882
39883
0
    val = js_thisNumberValue(ctx, this_val);
39884
0
    if (JS_IsException(val))
39885
0
        return val;
39886
0
    if (magic || JS_IsUndefined(argv[0])) {
39887
0
        base = 10;
39888
0
    } else {
39889
0
        base = js_get_radix(ctx, argv[0]);
39890
0
        if (base < 0)
39891
0
            goto fail;
39892
0
    }
39893
0
    if (JS_ToFloat64Free(ctx, &d, val))
39894
0
        return JS_EXCEPTION;
39895
0
    return js_dtoa(ctx, d, base, 0, JS_DTOA_VAR_FORMAT);
39896
0
 fail:
39897
0
    JS_FreeValue(ctx, val);
39898
0
    return JS_EXCEPTION;
39899
0
}
39900
39901
static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
39902
                                 int argc, JSValueConst *argv)
39903
0
{
39904
0
    JSValue val;
39905
0
    int f;
39906
0
    double d;
39907
39908
0
    val = js_thisNumberValue(ctx, this_val);
39909
0
    if (JS_IsException(val))
39910
0
        return val;
39911
0
    if (JS_ToFloat64Free(ctx, &d, val))
39912
0
        return JS_EXCEPTION;
39913
0
    if (JS_ToInt32Sat(ctx, &f, argv[0]))
39914
0
        return JS_EXCEPTION;
39915
0
    if (f < 0 || f > 100)
39916
0
        return JS_ThrowRangeError(ctx, "invalid number of digits");
39917
0
    if (fabs(d) >= 1e21) {
39918
0
        return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d));
39919
0
    } else {
39920
0
        return js_dtoa(ctx, d, 10, f, JS_DTOA_FRAC_FORMAT);
39921
0
    }
39922
0
}
39923
39924
static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
39925
                                       int argc, JSValueConst *argv)
39926
0
{
39927
0
    JSValue val;
39928
0
    int f, flags;
39929
0
    double d;
39930
39931
0
    val = js_thisNumberValue(ctx, this_val);
39932
0
    if (JS_IsException(val))
39933
0
        return val;
39934
0
    if (JS_ToFloat64Free(ctx, &d, val))
39935
0
        return JS_EXCEPTION;
39936
0
    if (JS_ToInt32Sat(ctx, &f, argv[0]))
39937
0
        return JS_EXCEPTION;
39938
0
    if (!isfinite(d)) {
39939
0
        return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
39940
0
    }
39941
0
    if (JS_IsUndefined(argv[0])) {
39942
0
        flags = 0;
39943
0
        f = 0;
39944
0
    } else {
39945
0
        if (f < 0 || f > 100)
39946
0
            return JS_ThrowRangeError(ctx, "invalid number of digits");
39947
0
        f++;
39948
0
        flags = JS_DTOA_FIXED_FORMAT;
39949
0
    }
39950
0
    return js_dtoa(ctx, d, 10, f, flags | JS_DTOA_FORCE_EXP);
39951
0
}
39952
39953
static JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,
39954
                                     int argc, JSValueConst *argv)
39955
0
{
39956
0
    JSValue val;
39957
0
    int p;
39958
0
    double d;
39959
39960
0
    val = js_thisNumberValue(ctx, this_val);
39961
0
    if (JS_IsException(val))
39962
0
        return val;
39963
0
    if (JS_ToFloat64Free(ctx, &d, val))
39964
0
        return JS_EXCEPTION;
39965
0
    if (JS_IsUndefined(argv[0]))
39966
0
        goto to_string;
39967
0
    if (JS_ToInt32Sat(ctx, &p, argv[0]))
39968
0
        return JS_EXCEPTION;
39969
0
    if (!isfinite(d)) {
39970
0
    to_string:
39971
0
        return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
39972
0
    }
39973
0
    if (p < 1 || p > 100)
39974
0
        return JS_ThrowRangeError(ctx, "invalid number of digits");
39975
0
    return js_dtoa(ctx, d, 10, p, JS_DTOA_FIXED_FORMAT);
39976
0
}
39977
39978
static const JSCFunctionListEntry js_number_proto_funcs[] = {
39979
    JS_CFUNC_DEF("toExponential", 1, js_number_toExponential ),
39980
    JS_CFUNC_DEF("toFixed", 1, js_number_toFixed ),
39981
    JS_CFUNC_DEF("toPrecision", 1, js_number_toPrecision ),
39982
    JS_CFUNC_MAGIC_DEF("toString", 1, js_number_toString, 0 ),
39983
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_number_toString, 1 ),
39984
    JS_CFUNC_DEF("valueOf", 0, js_number_valueOf ),
39985
};
39986
39987
static JSValue js_parseInt(JSContext *ctx, JSValueConst this_val,
39988
                           int argc, JSValueConst *argv)
39989
0
{
39990
0
    const char *str, *p;
39991
0
    int radix, flags;
39992
0
    JSValue ret;
39993
39994
0
    str = JS_ToCString(ctx, argv[0]);
39995
0
    if (!str)
39996
0
        return JS_EXCEPTION;
39997
0
    if (JS_ToInt32(ctx, &radix, argv[1])) {
39998
0
        JS_FreeCString(ctx, str);
39999
0
        return JS_EXCEPTION;
40000
0
    }
40001
0
    if (radix != 0 && (radix < 2 || radix > 36)) {
40002
0
        ret = JS_NAN;
40003
0
    } else {
40004
0
        p = str;
40005
0
        p += skip_spaces(p);
40006
0
        flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN;
40007
0
        ret = js_atof(ctx, p, NULL, radix, flags);
40008
0
    }
40009
0
    JS_FreeCString(ctx, str);
40010
0
    return ret;
40011
0
}
40012
40013
static JSValue js_parseFloat(JSContext *ctx, JSValueConst this_val,
40014
                             int argc, JSValueConst *argv)
40015
0
{
40016
0
    const char *str, *p;
40017
0
    JSValue ret;
40018
40019
0
    str = JS_ToCString(ctx, argv[0]);
40020
0
    if (!str)
40021
0
        return JS_EXCEPTION;
40022
0
    p = str;
40023
0
    p += skip_spaces(p);
40024
0
    ret = js_atof(ctx, p, NULL, 10, 0);
40025
0
    JS_FreeCString(ctx, str);
40026
0
    return ret;
40027
0
}
40028
40029
/* Boolean */
40030
static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst new_target,
40031
                                     int argc, JSValueConst *argv)
40032
0
{
40033
0
    JSValue val, obj;
40034
0
    val = JS_NewBool(ctx, JS_ToBool(ctx, argv[0]));
40035
0
    if (!JS_IsUndefined(new_target)) {
40036
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_BOOLEAN);
40037
0
        if (!JS_IsException(obj))
40038
0
            JS_SetObjectData(ctx, obj, val);
40039
0
        return obj;
40040
0
    } else {
40041
0
        return val;
40042
0
    }
40043
0
}
40044
40045
static JSValue js_thisBooleanValue(JSContext *ctx, JSValueConst this_val)
40046
0
{
40047
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_BOOL)
40048
0
        return JS_DupValue(ctx, this_val);
40049
40050
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
40051
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
40052
0
        if (p->class_id == JS_CLASS_BOOLEAN) {
40053
0
            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_BOOL)
40054
0
                return p->u.object_data;
40055
0
        }
40056
0
    }
40057
0
    return JS_ThrowTypeError(ctx, "not a boolean");
40058
0
}
40059
40060
static JSValue js_boolean_toString(JSContext *ctx, JSValueConst this_val,
40061
                                   int argc, JSValueConst *argv)
40062
0
{
40063
0
    JSValue val = js_thisBooleanValue(ctx, this_val);
40064
0
    if (JS_IsException(val))
40065
0
        return val;
40066
0
    return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
40067
0
                       JS_ATOM_true : JS_ATOM_false);
40068
0
}
40069
40070
static JSValue js_boolean_valueOf(JSContext *ctx, JSValueConst this_val,
40071
                                  int argc, JSValueConst *argv)
40072
0
{
40073
0
    return js_thisBooleanValue(ctx, this_val);
40074
0
}
40075
40076
static const JSCFunctionListEntry js_boolean_proto_funcs[] = {
40077
    JS_CFUNC_DEF("toString", 0, js_boolean_toString ),
40078
    JS_CFUNC_DEF("valueOf", 0, js_boolean_valueOf ),
40079
};
40080
40081
/* String */
40082
40083
static int js_string_get_own_property(JSContext *ctx,
40084
                                      JSPropertyDescriptor *desc,
40085
                                      JSValueConst obj, JSAtom prop)
40086
343k
{
40087
343k
    JSObject *p;
40088
343k
    JSString *p1;
40089
343k
    uint32_t idx, ch;
40090
40091
    /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
40092
343k
    if (__JS_AtomIsTaggedInt(prop)) {
40093
343k
        p = JS_VALUE_GET_OBJ(obj);
40094
343k
        if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
40095
343k
            p1 = JS_VALUE_GET_STRING(p->u.object_data);
40096
343k
            idx = __JS_AtomToUInt32(prop);
40097
343k
            if (idx < p1->len) {
40098
343k
                if (desc) {
40099
343k
                    if (p1->is_wide_char)
40100
343k
                        ch = p1->u.str16[idx];
40101
0
                    else
40102
0
                        ch = p1->u.str8[idx];
40103
343k
                    desc->flags = JS_PROP_ENUMERABLE;
40104
343k
                    desc->value = js_new_string_char(ctx, ch);
40105
343k
                    desc->getter = JS_UNDEFINED;
40106
343k
                    desc->setter = JS_UNDEFINED;
40107
343k
                }
40108
343k
                return TRUE;
40109
343k
            }
40110
343k
        }
40111
343k
    }
40112
0
    return FALSE;
40113
343k
}
40114
40115
static int js_string_define_own_property(JSContext *ctx,
40116
                                         JSValueConst this_obj,
40117
                                         JSAtom prop, JSValueConst val,
40118
                                         JSValueConst getter,
40119
                                         JSValueConst setter, int flags)
40120
16
{
40121
16
    uint32_t idx;
40122
16
    JSObject *p;
40123
16
    JSString *p1, *p2;
40124
    
40125
16
    if (__JS_AtomIsTaggedInt(prop)) {
40126
0
        idx = __JS_AtomToUInt32(prop);
40127
0
        p = JS_VALUE_GET_OBJ(this_obj);
40128
0
        if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING)
40129
0
            goto def;
40130
0
        p1 = JS_VALUE_GET_STRING(p->u.object_data);
40131
0
        if (idx >= p1->len)
40132
0
            goto def;
40133
0
        if (!check_define_prop_flags(JS_PROP_ENUMERABLE, flags))
40134
0
            goto fail;
40135
        /* check that the same value is configured */
40136
0
        if (flags & JS_PROP_HAS_VALUE) {
40137
0
            if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
40138
0
                goto fail;
40139
0
            p2 = JS_VALUE_GET_STRING(val);
40140
0
            if (p2->len != 1)
40141
0
                goto fail;
40142
0
            if (string_get(p1, idx) != string_get(p2, 0)) {
40143
0
            fail:
40144
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
40145
0
            }
40146
0
        }
40147
0
        return TRUE;
40148
16
    } else {
40149
16
    def:
40150
16
        return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
40151
16
                                 flags | JS_PROP_NO_EXOTIC);
40152
16
    }
40153
16
}
40154
40155
static int js_string_delete_property(JSContext *ctx,
40156
                                     JSValueConst obj, JSAtom prop)
40157
0
{
40158
0
    uint32_t idx;
40159
40160
0
    if (__JS_AtomIsTaggedInt(prop)) {
40161
0
        idx = __JS_AtomToUInt32(prop);
40162
0
        if (idx < js_string_obj_get_length(ctx, obj)) {
40163
0
            return FALSE;
40164
0
        }
40165
0
    }
40166
0
    return TRUE;
40167
0
}
40168
40169
static const JSClassExoticMethods js_string_exotic_methods = {
40170
    .get_own_property = js_string_get_own_property,
40171
    .define_own_property = js_string_define_own_property,
40172
    .delete_property = js_string_delete_property,
40173
};
40174
40175
static JSValue js_string_constructor(JSContext *ctx, JSValueConst new_target,
40176
                                     int argc, JSValueConst *argv)
40177
0
{
40178
0
    JSValue val, obj;
40179
0
    if (argc == 0) {
40180
0
        val = JS_AtomToString(ctx, JS_ATOM_empty_string);
40181
0
    } else {
40182
0
        if (JS_IsUndefined(new_target) && JS_IsSymbol(argv[0])) {
40183
0
            JSAtomStruct *p = JS_VALUE_GET_PTR(argv[0]);
40184
0
            val = JS_ConcatString3(ctx, "Symbol(", JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p)), ")");
40185
0
        } else {
40186
0
            val = JS_ToString(ctx, argv[0]);
40187
0
        }
40188
0
        if (JS_IsException(val))
40189
0
            return val;
40190
0
    }
40191
0
    if (!JS_IsUndefined(new_target)) {
40192
0
        JSString *p1 = JS_VALUE_GET_STRING(val);
40193
40194
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING);
40195
0
        if (!JS_IsException(obj)) {
40196
0
            JS_SetObjectData(ctx, obj, val);
40197
0
            JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
40198
0
        }
40199
0
        return obj;
40200
0
    } else {
40201
0
        return val;
40202
0
    }
40203
0
}
40204
40205
static JSValue js_thisStringValue(JSContext *ctx, JSValueConst this_val)
40206
0
{
40207
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING)
40208
0
        return JS_DupValue(ctx, this_val);
40209
40210
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
40211
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
40212
0
        if (p->class_id == JS_CLASS_STRING) {
40213
0
            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING)
40214
0
                return JS_DupValue(ctx, p->u.object_data);
40215
0
        }
40216
0
    }
40217
0
    return JS_ThrowTypeError(ctx, "not a string");
40218
0
}
40219
40220
static JSValue js_string_fromCharCode(JSContext *ctx, JSValueConst this_val,
40221
                                      int argc, JSValueConst *argv)
40222
0
{
40223
0
    int i;
40224
0
    StringBuffer b_s, *b = &b_s;
40225
40226
0
    string_buffer_init(ctx, b, argc);
40227
40228
0
    for(i = 0; i < argc; i++) {
40229
0
        int32_t c;
40230
0
        if (JS_ToInt32(ctx, &c, argv[i]) || string_buffer_putc16(b, c & 0xffff)) {
40231
0
            string_buffer_free(b);
40232
0
            return JS_EXCEPTION;
40233
0
        }
40234
0
    }
40235
0
    return string_buffer_end(b);
40236
0
}
40237
40238
static JSValue js_string_fromCodePoint(JSContext *ctx, JSValueConst this_val,
40239
                                       int argc, JSValueConst *argv)
40240
0
{
40241
0
    double d;
40242
0
    int i, c;
40243
0
    StringBuffer b_s, *b = &b_s;
40244
40245
    /* XXX: could pre-compute string length if all arguments are JS_TAG_INT */
40246
40247
0
    if (string_buffer_init(ctx, b, argc))
40248
0
        goto fail;
40249
0
    for(i = 0; i < argc; i++) {
40250
0
        if (JS_VALUE_GET_TAG(argv[i]) == JS_TAG_INT) {
40251
0
            c = JS_VALUE_GET_INT(argv[i]);
40252
0
            if (c < 0 || c > 0x10ffff)
40253
0
                goto range_error;
40254
0
        } else {
40255
0
            if (JS_ToFloat64(ctx, &d, argv[i]))
40256
0
                goto fail;
40257
0
            if (d < 0 || d > 0x10ffff || (c = (int)d) != d)
40258
0
                goto range_error;
40259
0
        }
40260
0
        if (string_buffer_putc(b, c))
40261
0
            goto fail;
40262
0
    }
40263
0
    return string_buffer_end(b);
40264
40265
0
 range_error:
40266
0
    JS_ThrowRangeError(ctx, "invalid code point");
40267
0
 fail:
40268
0
    string_buffer_free(b);
40269
0
    return JS_EXCEPTION;
40270
0
}
40271
40272
static JSValue js_string_raw(JSContext *ctx, JSValueConst this_val,
40273
                             int argc, JSValueConst *argv)
40274
0
{
40275
    // raw(temp,...a)
40276
0
    JSValue cooked, val, raw;
40277
0
    StringBuffer b_s, *b = &b_s;
40278
0
    int64_t i, n;
40279
40280
0
    string_buffer_init(ctx, b, 0);
40281
0
    raw = JS_UNDEFINED;
40282
0
    cooked = JS_ToObject(ctx, argv[0]);
40283
0
    if (JS_IsException(cooked))
40284
0
        goto exception;
40285
0
    raw = JS_ToObjectFree(ctx, JS_GetProperty(ctx, cooked, JS_ATOM_raw));
40286
0
    if (JS_IsException(raw))
40287
0
        goto exception;
40288
0
    if (js_get_length64(ctx, &n, raw) < 0)
40289
0
        goto exception;
40290
        
40291
0
    for (i = 0; i < n; i++) {
40292
0
        val = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, raw, i));
40293
0
        if (JS_IsException(val))
40294
0
            goto exception;
40295
0
        string_buffer_concat_value_free(b, val);
40296
0
        if (i < n - 1 && i + 1 < argc) {
40297
0
            if (string_buffer_concat_value(b, argv[i + 1]))
40298
0
                goto exception;
40299
0
        }
40300
0
    }
40301
0
    JS_FreeValue(ctx, cooked);
40302
0
    JS_FreeValue(ctx, raw);
40303
0
    return string_buffer_end(b);
40304
40305
0
exception:
40306
0
    JS_FreeValue(ctx, cooked);
40307
0
    JS_FreeValue(ctx, raw);
40308
0
    string_buffer_free(b);
40309
0
    return JS_EXCEPTION;
40310
0
}
40311
40312
/* only used in test262 */
40313
JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
40314
                                 int argc, JSValueConst *argv)
40315
0
{
40316
0
    uint32_t start, end, i, n;
40317
0
    StringBuffer b_s, *b = &b_s;
40318
40319
0
    if (JS_ToUint32(ctx, &start, argv[0]) ||
40320
0
        JS_ToUint32(ctx, &end, argv[1]))
40321
0
        return JS_EXCEPTION;
40322
0
    end = min_uint32(end, 0x10ffff + 1);
40323
40324
0
    if (start > end) {
40325
0
        start = end;
40326
0
    }
40327
0
    n = end - start;
40328
0
    if (end > 0x10000) {
40329
0
        n += end - max_uint32(start, 0x10000);
40330
0
    }
40331
0
    if (string_buffer_init2(ctx, b, n, end >= 0x100))
40332
0
        return JS_EXCEPTION;
40333
0
    for(i = start; i < end; i++) {
40334
0
        string_buffer_putc(b, i);
40335
0
    }
40336
0
    return string_buffer_end(b);
40337
0
}
40338
40339
#if 0
40340
static JSValue js_string___isSpace(JSContext *ctx, JSValueConst this_val,
40341
                                   int argc, JSValueConst *argv)
40342
{
40343
    int c;
40344
    if (JS_ToInt32(ctx, &c, argv[0]))
40345
        return JS_EXCEPTION;
40346
    return JS_NewBool(ctx, lre_is_space(c));
40347
}
40348
#endif
40349
40350
static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val,
40351
                                     int argc, JSValueConst *argv)
40352
0
{
40353
0
    JSValue val, ret;
40354
0
    JSString *p;
40355
0
    int idx, c;
40356
40357
0
    val = JS_ToStringCheckObject(ctx, this_val);
40358
0
    if (JS_IsException(val))
40359
0
        return val;
40360
0
    p = JS_VALUE_GET_STRING(val);
40361
0
    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
40362
0
        JS_FreeValue(ctx, val);
40363
0
        return JS_EXCEPTION;
40364
0
    }
40365
0
    if (idx < 0 || idx >= p->len) {
40366
0
        ret = JS_NAN;
40367
0
    } else {
40368
0
        if (p->is_wide_char)
40369
0
            c = p->u.str16[idx];
40370
0
        else
40371
0
            c = p->u.str8[idx];
40372
0
        ret = JS_NewInt32(ctx, c);
40373
0
    }
40374
0
    JS_FreeValue(ctx, val);
40375
0
    return ret;
40376
0
}
40377
40378
static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val,
40379
                                int argc, JSValueConst *argv)
40380
0
{
40381
0
    JSValue val, ret;
40382
0
    JSString *p;
40383
0
    int idx, c;
40384
40385
0
    val = JS_ToStringCheckObject(ctx, this_val);
40386
0
    if (JS_IsException(val))
40387
0
        return val;
40388
0
    p = JS_VALUE_GET_STRING(val);
40389
0
    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
40390
0
        JS_FreeValue(ctx, val);
40391
0
        return JS_EXCEPTION;
40392
0
    }
40393
0
    if (idx < 0 || idx >= p->len) {
40394
0
        ret = js_new_string8(ctx, NULL, 0);
40395
0
    } else {
40396
0
        if (p->is_wide_char)
40397
0
            c = p->u.str16[idx];
40398
0
        else
40399
0
            c = p->u.str8[idx];
40400
0
        ret = js_new_string_char(ctx, c);
40401
0
    }
40402
0
    JS_FreeValue(ctx, val);
40403
0
    return ret;
40404
0
}
40405
40406
static JSValue js_string_codePointAt(JSContext *ctx, JSValueConst this_val,
40407
                                     int argc, JSValueConst *argv)
40408
0
{
40409
0
    JSValue val, ret;
40410
0
    JSString *p;
40411
0
    int idx, c;
40412
40413
0
    val = JS_ToStringCheckObject(ctx, this_val);
40414
0
    if (JS_IsException(val))
40415
0
        return val;
40416
0
    p = JS_VALUE_GET_STRING(val);
40417
0
    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
40418
0
        JS_FreeValue(ctx, val);
40419
0
        return JS_EXCEPTION;
40420
0
    }
40421
0
    if (idx < 0 || idx >= p->len) {
40422
0
        ret = JS_UNDEFINED;
40423
0
    } else {
40424
0
        c = string_getc(p, &idx);
40425
0
        ret = JS_NewInt32(ctx, c);
40426
0
    }
40427
0
    JS_FreeValue(ctx, val);
40428
0
    return ret;
40429
0
}
40430
40431
static JSValue js_string_concat(JSContext *ctx, JSValueConst this_val,
40432
                                int argc, JSValueConst *argv)
40433
0
{
40434
0
    JSValue r;
40435
0
    int i;
40436
40437
    /* XXX: Use more efficient method */
40438
    /* XXX: This method is OK if r has a single refcount */
40439
    /* XXX: should use string_buffer? */
40440
0
    r = JS_ToStringCheckObject(ctx, this_val);
40441
0
    for (i = 0; i < argc; i++) {
40442
0
        if (JS_IsException(r))
40443
0
            break;
40444
0
        r = JS_ConcatString(ctx, r, JS_DupValue(ctx, argv[i]));
40445
0
    }
40446
0
    return r;
40447
0
}
40448
40449
static int string_cmp(JSString *p1, JSString *p2, int x1, int x2, int len)
40450
11.3k
{
40451
11.3k
    int i, c1, c2;
40452
26.3k
    for (i = 0; i < len; i++) {
40453
26.3k
        if ((c1 = string_get(p1, x1 + i)) != (c2 = string_get(p2, x2 + i)))
40454
11.3k
            return c1 - c2;
40455
26.3k
    }
40456
0
    return 0;
40457
11.3k
}
40458
40459
static int string_indexof_char(JSString *p, int c, int from)
40460
11.3k
{
40461
    /* assuming 0 <= from <= p->len */
40462
11.3k
    int i, len = p->len;
40463
11.3k
    if (p->is_wide_char) {
40464
262k
        for (i = from; i < len; i++) {
40465
262k
            if (p->u.str16[i] == c)
40466
11.3k
                return i;
40467
262k
        }
40468
11.3k
    } else {
40469
2
        if ((c & ~0xff) == 0) {
40470
20
            for (i = from; i < len; i++) {
40471
18
                if (p->u.str8[i] == (uint8_t)c)
40472
0
                    return i;
40473
18
            }
40474
2
        }
40475
2
    }
40476
4
    return -1;
40477
11.3k
}
40478
40479
static int string_indexof(JSString *p1, JSString *p2, int from)
40480
100k
{
40481
    /* assuming 0 <= from <= p1->len */
40482
100k
    int c, i, j, len1 = p1->len, len2 = p2->len;
40483
100k
    if (len2 == 0)
40484
100k
        return from;
40485
11.3k
    for (i = from, c = string_get(p2, 0); i + len2 <= len1; i = j + 1) {
40486
11.3k
        j = string_indexof_char(p1, c, i);
40487
11.3k
        if (j < 0 || j + len2 > len1)
40488
4
            break;
40489
11.3k
        if (!string_cmp(p1, p2, j + 1, 1, len2 - 1))
40490
0
            return j;
40491
11.3k
    }
40492
4
    return -1;
40493
4
}
40494
40495
static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode)
40496
0
{
40497
0
    if (!unicode || index >= p->len || !p->is_wide_char) {
40498
0
        index++;
40499
0
    } else {
40500
0
        int index32 = (int)index;
40501
0
        string_getc(p, &index32);
40502
0
        index = index32;
40503
0
    }
40504
0
    return index;
40505
0
}
40506
40507
static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val,
40508
                                 int argc, JSValueConst *argv, int lastIndexOf)
40509
0
{
40510
0
    JSValue str, v;
40511
0
    int i, len, v_len, pos, start, stop, ret, inc;
40512
0
    JSString *p;
40513
0
    JSString *p1;
40514
40515
0
    str = JS_ToStringCheckObject(ctx, this_val);
40516
0
    if (JS_IsException(str))
40517
0
        return str;
40518
0
    v = JS_ToString(ctx, argv[0]);
40519
0
    if (JS_IsException(v))
40520
0
        goto fail;
40521
0
    p = JS_VALUE_GET_STRING(str);
40522
0
    p1 = JS_VALUE_GET_STRING(v);
40523
0
    len = p->len;
40524
0
    v_len = p1->len;
40525
0
    if (lastIndexOf) {
40526
0
        pos = len - v_len;
40527
0
        if (argc > 1) {
40528
0
            double d;
40529
0
            if (JS_ToFloat64(ctx, &d, argv[1]))
40530
0
                goto fail;
40531
0
            if (!isnan(d)) {
40532
0
                if (d <= 0)
40533
0
                    pos = 0;
40534
0
                else if (d < pos)
40535
0
                    pos = d;
40536
0
            }
40537
0
        }
40538
0
        start = pos;
40539
0
        stop = 0;
40540
0
        inc = -1;
40541
0
    } else {
40542
0
        pos = 0;
40543
0
        if (argc > 1) {
40544
0
            if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
40545
0
                goto fail;
40546
0
        }
40547
0
        start = pos;
40548
0
        stop = len - v_len;
40549
0
        inc = 1;
40550
0
    }
40551
0
    ret = -1;
40552
0
    if (len >= v_len && inc * (stop - start) >= 0) {
40553
0
        for (i = start;; i += inc) {
40554
0
            if (!string_cmp(p, p1, i, 0, v_len)) {
40555
0
                ret = i;
40556
0
                break;
40557
0
            }
40558
0
            if (i == stop)
40559
0
                break;
40560
0
        }
40561
0
    }
40562
0
    JS_FreeValue(ctx, str);
40563
0
    JS_FreeValue(ctx, v);
40564
0
    return JS_NewInt32(ctx, ret);
40565
40566
0
fail:
40567
0
    JS_FreeValue(ctx, str);
40568
0
    JS_FreeValue(ctx, v);
40569
0
    return JS_EXCEPTION;
40570
0
}
40571
40572
/* return < 0 if exception or TRUE/FALSE */
40573
static int js_is_regexp(JSContext *ctx, JSValueConst obj);
40574
40575
static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val,
40576
                                  int argc, JSValueConst *argv, int magic)
40577
0
{
40578
0
    JSValue str, v = JS_UNDEFINED;
40579
0
    int i, len, v_len, pos, start, stop, ret;
40580
0
    JSString *p;
40581
0
    JSString *p1;
40582
40583
0
    str = JS_ToStringCheckObject(ctx, this_val);
40584
0
    if (JS_IsException(str))
40585
0
        return str;
40586
0
    ret = js_is_regexp(ctx, argv[0]);
40587
0
    if (ret) {
40588
0
        if (ret > 0)
40589
0
            JS_ThrowTypeError(ctx, "regex not supported");
40590
0
        goto fail;
40591
0
    }
40592
0
    v = JS_ToString(ctx, argv[0]);
40593
0
    if (JS_IsException(v))
40594
0
        goto fail;
40595
0
    p = JS_VALUE_GET_STRING(str);
40596
0
    p1 = JS_VALUE_GET_STRING(v);
40597
0
    len = p->len;
40598
0
    v_len = p1->len;
40599
0
    pos = (magic == 2) ? len : 0;
40600
0
    if (argc > 1 && !JS_IsUndefined(argv[1])) {
40601
0
        if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
40602
0
            goto fail;
40603
0
    }
40604
0
    len -= v_len;
40605
0
    ret = 0;
40606
0
    if (magic == 0) {
40607
0
        start = pos;
40608
0
        stop = len;
40609
0
    } else {
40610
0
        if (magic == 1) {
40611
0
            if (pos > len)
40612
0
                goto done;
40613
0
        } else {
40614
0
            pos -= v_len;
40615
0
        }
40616
0
        start = stop = pos;
40617
0
    }
40618
0
    if (start >= 0 && start <= stop) {
40619
0
        for (i = start;; i++) {
40620
0
            if (!string_cmp(p, p1, i, 0, v_len)) {
40621
0
                ret = 1;
40622
0
                break;
40623
0
            }
40624
0
            if (i == stop)
40625
0
                break;
40626
0
        }
40627
0
    }
40628
0
 done:
40629
0
    JS_FreeValue(ctx, str);
40630
0
    JS_FreeValue(ctx, v);
40631
0
    return JS_NewBool(ctx, ret);
40632
40633
0
fail:
40634
0
    JS_FreeValue(ctx, str);
40635
0
    JS_FreeValue(ctx, v);
40636
0
    return JS_EXCEPTION;
40637
0
}
40638
40639
static int check_regexp_g_flag(JSContext *ctx, JSValueConst regexp)
40640
0
{
40641
0
    int ret;
40642
0
    JSValue flags;
40643
    
40644
0
    ret = js_is_regexp(ctx, regexp);
40645
0
    if (ret < 0)
40646
0
        return -1;
40647
0
    if (ret) {
40648
0
        flags = JS_GetProperty(ctx, regexp, JS_ATOM_flags);
40649
0
        if (JS_IsException(flags))
40650
0
            return -1;
40651
0
        if (JS_IsUndefined(flags) || JS_IsNull(flags)) {
40652
0
            JS_ThrowTypeError(ctx, "cannot convert to object");
40653
0
            return -1;
40654
0
        }
40655
0
        flags = JS_ToStringFree(ctx, flags);
40656
0
        if (JS_IsException(flags))
40657
0
            return -1;
40658
0
        ret = string_indexof_char(JS_VALUE_GET_STRING(flags), 'g', 0);
40659
0
        JS_FreeValue(ctx, flags);
40660
0
        if (ret < 0) {
40661
0
            JS_ThrowTypeError(ctx, "regexp must have the 'g' flag");
40662
0
            return -1;
40663
0
        }
40664
0
    }
40665
0
    return 0;
40666
0
}
40667
40668
static JSValue js_string_match(JSContext *ctx, JSValueConst this_val,
40669
                               int argc, JSValueConst *argv, int atom)
40670
0
{
40671
    // match(rx), search(rx), matchAll(rx)
40672
    // atom is JS_ATOM_Symbol_match, JS_ATOM_Symbol_search, or JS_ATOM_Symbol_matchAll
40673
0
    JSValueConst O = this_val, regexp = argv[0], args[2];
40674
0
    JSValue matcher, S, rx, result, str;
40675
0
    int args_len;
40676
40677
0
    if (JS_IsUndefined(O) || JS_IsNull(O))
40678
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
40679
40680
0
    if (!JS_IsUndefined(regexp) && !JS_IsNull(regexp)) {
40681
0
        matcher = JS_GetProperty(ctx, regexp, atom);
40682
0
        if (JS_IsException(matcher))
40683
0
            return JS_EXCEPTION;
40684
0
        if (atom == JS_ATOM_Symbol_matchAll) {
40685
0
            if (check_regexp_g_flag(ctx, regexp) < 0) {
40686
0
                JS_FreeValue(ctx, matcher);
40687
0
                return JS_EXCEPTION;
40688
0
            }
40689
0
        }
40690
0
        if (!JS_IsUndefined(matcher) && !JS_IsNull(matcher)) {
40691
0
            return JS_CallFree(ctx, matcher, regexp, 1, &O);
40692
0
        }
40693
0
    }
40694
0
    S = JS_ToString(ctx, O);
40695
0
    if (JS_IsException(S))
40696
0
        return JS_EXCEPTION;
40697
0
    args_len = 1;
40698
0
    args[0] = regexp;
40699
0
    str = JS_UNDEFINED;
40700
0
    if (atom == JS_ATOM_Symbol_matchAll) {
40701
0
        str = JS_NewString(ctx, "g");
40702
0
        if (JS_IsException(str))
40703
0
            goto fail;
40704
0
        args[args_len++] = (JSValueConst)str;
40705
0
    }
40706
0
    rx = JS_CallConstructor(ctx, ctx->regexp_ctor, args_len, args);
40707
0
    JS_FreeValue(ctx, str);
40708
0
    if (JS_IsException(rx)) {
40709
0
    fail:
40710
0
        JS_FreeValue(ctx, S);
40711
0
        return JS_EXCEPTION;
40712
0
    }
40713
0
    result = JS_InvokeFree(ctx, rx, atom, 1, (JSValueConst *)&S);
40714
0
    JS_FreeValue(ctx, S);
40715
0
    return result;
40716
0
}
40717
40718
static JSValue js_string___GetSubstitution(JSContext *ctx, JSValueConst this_val,
40719
                                           int argc, JSValueConst *argv)
40720
2
{
40721
    // GetSubstitution(matched, str, position, captures, namedCaptures, rep)
40722
2
    JSValueConst matched, str, captures, namedCaptures, rep;
40723
2
    JSValue capture, name, s;
40724
2
    uint32_t position, len, matched_len, captures_len;
40725
2
    int i, j, j0, k, k1;
40726
2
    int c, c1;
40727
2
    StringBuffer b_s, *b = &b_s;
40728
2
    JSString *sp, *rp;
40729
40730
2
    matched = argv[0];
40731
2
    str = argv[1];
40732
2
    captures = argv[3];
40733
2
    namedCaptures = argv[4];
40734
2
    rep = argv[5];
40735
40736
2
    if (!JS_IsString(rep) || !JS_IsString(str))
40737
0
        return JS_ThrowTypeError(ctx, "not a string");
40738
40739
2
    sp = JS_VALUE_GET_STRING(str);
40740
2
    rp = JS_VALUE_GET_STRING(rep);
40741
40742
2
    string_buffer_init(ctx, b, 0);
40743
40744
2
    captures_len = 0;
40745
2
    if (!JS_IsUndefined(captures)) {
40746
0
        if (js_get_length32(ctx, &captures_len, captures))
40747
0
            goto exception;
40748
0
    }
40749
2
    if (js_get_length32(ctx, &matched_len, matched))
40750
0
        goto exception;
40751
2
    if (JS_ToUint32(ctx, &position, argv[2]) < 0)
40752
0
        goto exception;
40753
40754
2
    len = rp->len;
40755
2
    i = 0;
40756
2
    for(;;) {
40757
2
        j = string_indexof_char(rp, '$', i);
40758
2
        if (j < 0 || j + 1 >= len)
40759
2
            break;
40760
0
        string_buffer_concat(b, rp, i, j);
40761
0
        j0 = j++;
40762
0
        c = string_get(rp, j++);
40763
0
        if (c == '$') {
40764
0
            string_buffer_putc8(b, '$');
40765
0
        } else if (c == '&') {
40766
0
            if (string_buffer_concat_value(b, matched))
40767
0
                goto exception;
40768
0
        } else if (c == '`') {
40769
0
            string_buffer_concat(b, sp, 0, position);
40770
0
        } else if (c == '\'') {
40771
0
            string_buffer_concat(b, sp, position + matched_len, sp->len);
40772
0
        } else if (c >= '0' && c <= '9') {
40773
0
            k = c - '0';
40774
0
            if (j < len) {
40775
0
                c1 = string_get(rp, j);
40776
0
                if (c1 >= '0' && c1 <= '9') {
40777
                    /* This behavior is specified in ES6 and refined in ECMA 2019 */
40778
                    /* ECMA 2019 does not have the extra test, but
40779
                       Test262 S15.5.4.11_A3_T1..3 require this behavior */
40780
0
                    k1 = k * 10 + c1 - '0';
40781
0
                    if (k1 >= 1 && k1 < captures_len) {
40782
0
                        k = k1;
40783
0
                        j++;
40784
0
                    }
40785
0
                }
40786
0
            }
40787
0
            if (k >= 1 && k < captures_len) {
40788
0
                s = JS_GetPropertyInt64(ctx, captures, k);
40789
0
                if (JS_IsException(s))
40790
0
                    goto exception;
40791
0
                if (!JS_IsUndefined(s)) {
40792
0
                    if (string_buffer_concat_value_free(b, s))
40793
0
                        goto exception;
40794
0
                }
40795
0
            } else {
40796
0
                goto norep;
40797
0
            }
40798
0
        } else if (c == '<' && !JS_IsUndefined(namedCaptures)) {
40799
0
            k = string_indexof_char(rp, '>', j);
40800
0
            if (k < 0)
40801
0
                goto norep;
40802
0
            name = js_sub_string(ctx, rp, j, k);
40803
0
            if (JS_IsException(name))
40804
0
                goto exception;
40805
0
            capture = JS_GetPropertyValue(ctx, namedCaptures, name);
40806
0
            if (JS_IsException(capture))
40807
0
                goto exception;
40808
0
            if (!JS_IsUndefined(capture)) {
40809
0
                if (string_buffer_concat_value_free(b, capture))
40810
0
                    goto exception;
40811
0
            }
40812
0
            j = k + 1;
40813
0
        } else {
40814
0
        norep:
40815
0
            string_buffer_concat(b, rp, j0, j);
40816
0
        }
40817
0
        i = j;
40818
0
    }
40819
2
    string_buffer_concat(b, rp, i, rp->len);
40820
2
    return string_buffer_end(b);
40821
0
exception:
40822
0
    string_buffer_free(b);
40823
0
    return JS_EXCEPTION;
40824
2
}
40825
40826
static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val,
40827
                                 int argc, JSValueConst *argv,
40828
                                 int is_replaceAll)
40829
6
{
40830
    // replace(rx, rep)
40831
6
    JSValueConst O = this_val, searchValue = argv[0], replaceValue = argv[1];
40832
6
    JSValueConst args[6];
40833
6
    JSValue str, search_str, replaceValue_str, repl_str;
40834
6
    JSString *sp, *searchp;
40835
6
    StringBuffer b_s, *b = &b_s;
40836
6
    int pos, functionalReplace, endOfLastMatch;
40837
6
    BOOL is_first;
40838
40839
6
    if (JS_IsUndefined(O) || JS_IsNull(O))
40840
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
40841
40842
6
    search_str = JS_UNDEFINED;
40843
6
    replaceValue_str = JS_UNDEFINED;
40844
6
    repl_str = JS_UNDEFINED;
40845
40846
6
    if (!JS_IsUndefined(searchValue) && !JS_IsNull(searchValue)) {
40847
6
        JSValue replacer;
40848
6
        if (is_replaceAll) {
40849
0
            if (check_regexp_g_flag(ctx, searchValue) < 0)
40850
0
                return JS_EXCEPTION;
40851
0
        }
40852
6
        replacer = JS_GetProperty(ctx, searchValue, JS_ATOM_Symbol_replace);
40853
6
        if (JS_IsException(replacer))
40854
0
            return JS_EXCEPTION;
40855
6
        if (!JS_IsUndefined(replacer) && !JS_IsNull(replacer)) {
40856
0
            args[0] = O;
40857
0
            args[1] = replaceValue;
40858
0
            return JS_CallFree(ctx, replacer, searchValue, 2, args);
40859
0
        }
40860
6
    }
40861
6
    string_buffer_init(ctx, b, 0);
40862
40863
6
    str = JS_ToString(ctx, O);
40864
6
    if (JS_IsException(str))
40865
0
        goto exception;
40866
6
    search_str = JS_ToString(ctx, searchValue);
40867
6
    if (JS_IsException(search_str))
40868
0
        goto exception;
40869
6
    functionalReplace = JS_IsFunction(ctx, replaceValue);
40870
6
    if (!functionalReplace) {
40871
6
        replaceValue_str = JS_ToString(ctx, replaceValue);
40872
6
        if (JS_IsException(replaceValue_str))
40873
0
            goto exception;
40874
6
    }
40875
40876
6
    sp = JS_VALUE_GET_STRING(str);
40877
6
    searchp = JS_VALUE_GET_STRING(search_str);
40878
6
    endOfLastMatch = 0;
40879
6
    is_first = TRUE;
40880
6
    for(;;) {
40881
6
        if (unlikely(searchp->len == 0)) {
40882
2
            if (is_first)
40883
2
                pos = 0;
40884
0
            else if (endOfLastMatch >= sp->len)
40885
0
                pos = -1;
40886
0
            else
40887
0
                pos = endOfLastMatch + 1;
40888
4
        } else {
40889
4
            pos = string_indexof(sp, searchp, endOfLastMatch);
40890
4
        }
40891
6
        if (pos < 0) {
40892
4
            if (is_first) {
40893
4
                string_buffer_free(b);
40894
4
                JS_FreeValue(ctx, search_str);
40895
4
                JS_FreeValue(ctx, replaceValue_str);
40896
4
                return str;
40897
4
            } else {
40898
0
                break;
40899
0
            }
40900
4
        }
40901
2
        if (functionalReplace) {
40902
0
            args[0] = search_str;
40903
0
            args[1] = JS_NewInt32(ctx, pos);
40904
0
            args[2] = str;
40905
0
            repl_str = JS_ToStringFree(ctx, JS_Call(ctx, replaceValue, JS_UNDEFINED, 3, args));
40906
2
        } else {
40907
2
            args[0] = search_str;
40908
2
            args[1] = str;
40909
2
            args[2] = JS_NewInt32(ctx, pos);
40910
2
            args[3] = JS_UNDEFINED;
40911
2
            args[4] = JS_UNDEFINED;
40912
2
            args[5] = replaceValue_str;
40913
2
            repl_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
40914
2
        }
40915
2
        if (JS_IsException(repl_str))
40916
0
            goto exception;
40917
        
40918
2
        string_buffer_concat(b, sp, endOfLastMatch, pos);
40919
2
        string_buffer_concat_value_free(b, repl_str);
40920
2
        endOfLastMatch = pos + searchp->len;
40921
2
        is_first = FALSE;
40922
2
        if (!is_replaceAll)
40923
2
            break;
40924
2
    }
40925
2
    string_buffer_concat(b, sp, endOfLastMatch, sp->len);
40926
2
    JS_FreeValue(ctx, search_str);
40927
2
    JS_FreeValue(ctx, replaceValue_str);
40928
2
    JS_FreeValue(ctx, str);
40929
2
    return string_buffer_end(b);
40930
40931
0
exception:
40932
0
    string_buffer_free(b);
40933
0
    JS_FreeValue(ctx, search_str);
40934
0
    JS_FreeValue(ctx, replaceValue_str);
40935
0
    JS_FreeValue(ctx, str);
40936
0
    return JS_EXCEPTION;
40937
6
}
40938
40939
static JSValue js_string_split(JSContext *ctx, JSValueConst this_val,
40940
                               int argc, JSValueConst *argv)
40941
1
{
40942
    // split(sep, limit)
40943
1
    JSValueConst O = this_val, separator = argv[0], limit = argv[1];
40944
1
    JSValueConst args[2];
40945
1
    JSValue S, A, R, T;
40946
1
    uint32_t lim, lengthA;
40947
1
    int64_t p, q, s, r, e;
40948
1
    JSString *sp, *rp;
40949
40950
1
    if (JS_IsUndefined(O) || JS_IsNull(O))
40951
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
40952
40953
1
    S = JS_UNDEFINED;
40954
1
    A = JS_UNDEFINED;
40955
1
    R = JS_UNDEFINED;
40956
40957
1
    if (!JS_IsUndefined(separator) && !JS_IsNull(separator)) {
40958
1
        JSValue splitter;
40959
1
        splitter = JS_GetProperty(ctx, separator, JS_ATOM_Symbol_split);
40960
1
        if (JS_IsException(splitter))
40961
0
            return JS_EXCEPTION;
40962
1
        if (!JS_IsUndefined(splitter) && !JS_IsNull(splitter)) {
40963
0
            args[0] = O;
40964
0
            args[1] = limit;
40965
0
            return JS_CallFree(ctx, splitter, separator, 2, args);
40966
0
        }
40967
1
    }
40968
1
    S = JS_ToString(ctx, O);
40969
1
    if (JS_IsException(S))
40970
0
        goto exception;
40971
1
    A = JS_NewArray(ctx);
40972
1
    if (JS_IsException(A))
40973
0
        goto exception;
40974
1
    lengthA = 0;
40975
1
    if (JS_IsUndefined(limit)) {
40976
1
        lim = 0xffffffff;
40977
1
    } else {
40978
0
        if (JS_ToUint32(ctx, &lim, limit) < 0)
40979
0
            goto exception;
40980
0
    }
40981
1
    sp = JS_VALUE_GET_STRING(S);
40982
1
    s = sp->len;
40983
1
    R = JS_ToString(ctx, separator);
40984
1
    if (JS_IsException(R))
40985
0
        goto exception;
40986
1
    rp = JS_VALUE_GET_STRING(R);
40987
1
    r = rp->len;
40988
1
    p = 0;
40989
1
    if (lim == 0)
40990
0
        goto done;
40991
1
    if (JS_IsUndefined(separator))
40992
0
        goto add_tail;
40993
1
    if (s == 0) {
40994
0
        if (r != 0)
40995
0
            goto add_tail;
40996
0
        goto done;
40997
0
    }
40998
1
    q = p;
40999
100k
    for (q = p; (q += !r) <= s - r - !r; q = p = e + r) {
41000
100k
        e = string_indexof(sp, rp, q);
41001
100k
        if (e < 0)
41002
0
            break;
41003
100k
        T = js_sub_string(ctx, sp, p, e);
41004
100k
        if (JS_IsException(T))
41005
0
            goto exception;
41006
100k
        if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T, 0) < 0)
41007
0
            goto exception;
41008
100k
        if (lengthA == lim)
41009
0
            goto done;
41010
100k
    }
41011
1
add_tail:
41012
1
    T = js_sub_string(ctx, sp, p, s);
41013
1
    if (JS_IsException(T))
41014
0
        goto exception;
41015
1
    if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T,0 ) < 0)
41016
0
        goto exception;
41017
1
done:
41018
1
    JS_FreeValue(ctx, S);
41019
1
    JS_FreeValue(ctx, R);
41020
1
    return A;
41021
41022
0
exception:
41023
0
    JS_FreeValue(ctx, A);
41024
0
    JS_FreeValue(ctx, S);
41025
0
    JS_FreeValue(ctx, R);
41026
0
    return JS_EXCEPTION;
41027
1
}
41028
41029
static JSValue js_string_substring(JSContext *ctx, JSValueConst this_val,
41030
                                   int argc, JSValueConst *argv)
41031
0
{
41032
0
    JSValue str, ret;
41033
0
    int a, b, start, end;
41034
0
    JSString *p;
41035
41036
0
    str = JS_ToStringCheckObject(ctx, this_val);
41037
0
    if (JS_IsException(str))
41038
0
        return str;
41039
0
    p = JS_VALUE_GET_STRING(str);
41040
0
    if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, p->len, 0)) {
41041
0
        JS_FreeValue(ctx, str);
41042
0
        return JS_EXCEPTION;
41043
0
    }
41044
0
    b = p->len;
41045
0
    if (!JS_IsUndefined(argv[1])) {
41046
0
        if (JS_ToInt32Clamp(ctx, &b, argv[1], 0, p->len, 0)) {
41047
0
            JS_FreeValue(ctx, str);
41048
0
            return JS_EXCEPTION;
41049
0
        }
41050
0
    }
41051
0
    if (a < b) {
41052
0
        start = a;
41053
0
        end = b;
41054
0
    } else {
41055
0
        start = b;
41056
0
        end = a;
41057
0
    }
41058
0
    ret = js_sub_string(ctx, p, start, end);
41059
0
    JS_FreeValue(ctx, str);
41060
0
    return ret;
41061
0
}
41062
41063
static JSValue js_string_substr(JSContext *ctx, JSValueConst this_val,
41064
                                int argc, JSValueConst *argv)
41065
0
{
41066
0
    JSValue str, ret;
41067
0
    int a, len, n;
41068
0
    JSString *p;
41069
41070
0
    str = JS_ToStringCheckObject(ctx, this_val);
41071
0
    if (JS_IsException(str))
41072
0
        return str;
41073
0
    p = JS_VALUE_GET_STRING(str);
41074
0
    len = p->len;
41075
0
    if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, len, len)) {
41076
0
        JS_FreeValue(ctx, str);
41077
0
        return JS_EXCEPTION;
41078
0
    }
41079
0
    n = len - a;
41080
0
    if (!JS_IsUndefined(argv[1])) {
41081
0
        if (JS_ToInt32Clamp(ctx, &n, argv[1], 0, len - a, 0)) {
41082
0
            JS_FreeValue(ctx, str);
41083
0
            return JS_EXCEPTION;
41084
0
        }
41085
0
    }
41086
0
    ret = js_sub_string(ctx, p, a, a + n);
41087
0
    JS_FreeValue(ctx, str);
41088
0
    return ret;
41089
0
}
41090
41091
static JSValue js_string_slice(JSContext *ctx, JSValueConst this_val,
41092
                               int argc, JSValueConst *argv)
41093
0
{
41094
0
    JSValue str, ret;
41095
0
    int len, start, end;
41096
0
    JSString *p;
41097
41098
0
    str = JS_ToStringCheckObject(ctx, this_val);
41099
0
    if (JS_IsException(str))
41100
0
        return str;
41101
0
    p = JS_VALUE_GET_STRING(str);
41102
0
    len = p->len;
41103
0
    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) {
41104
0
        JS_FreeValue(ctx, str);
41105
0
        return JS_EXCEPTION;
41106
0
    }
41107
0
    end = len;
41108
0
    if (!JS_IsUndefined(argv[1])) {
41109
0
        if (JS_ToInt32Clamp(ctx, &end, argv[1], 0, len, len)) {
41110
0
            JS_FreeValue(ctx, str);
41111
0
            return JS_EXCEPTION;
41112
0
        }
41113
0
    }
41114
0
    ret = js_sub_string(ctx, p, start, max_int(end, start));
41115
0
    JS_FreeValue(ctx, str);
41116
0
    return ret;
41117
0
}
41118
41119
static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val,
41120
                             int argc, JSValueConst *argv, int padEnd)
41121
0
{
41122
0
    JSValue str, v = JS_UNDEFINED;
41123
0
    StringBuffer b_s, *b = &b_s;
41124
0
    JSString *p, *p1 = NULL;
41125
0
    int n, len, c = ' ';
41126
41127
0
    str = JS_ToStringCheckObject(ctx, this_val);
41128
0
    if (JS_IsException(str))
41129
0
        goto fail1;
41130
0
    if (JS_ToInt32Sat(ctx, &n, argv[0]))
41131
0
        goto fail2;
41132
0
    p = JS_VALUE_GET_STRING(str);
41133
0
    len = p->len;
41134
0
    if (len >= n)
41135
0
        return str;
41136
0
    if (argc > 1 && !JS_IsUndefined(argv[1])) {
41137
0
        v = JS_ToString(ctx, argv[1]);
41138
0
        if (JS_IsException(v))
41139
0
            goto fail2;
41140
0
        p1 = JS_VALUE_GET_STRING(v);
41141
0
        if (p1->len == 0) {
41142
0
            JS_FreeValue(ctx, v);
41143
0
            return str;
41144
0
        }
41145
0
        if (p1->len == 1) {
41146
0
            c = string_get(p1, 0);
41147
0
            p1 = NULL;
41148
0
        }
41149
0
    }
41150
0
    if (n > JS_STRING_LEN_MAX) {
41151
0
        JS_ThrowInternalError(ctx, "string too long");
41152
0
        goto fail2;
41153
0
    }
41154
0
    if (string_buffer_init(ctx, b, n))
41155
0
        goto fail3;
41156
0
    n -= len;
41157
0
    if (padEnd) {
41158
0
        if (string_buffer_concat(b, p, 0, len))
41159
0
            goto fail;
41160
0
    }
41161
0
    if (p1) {
41162
0
        while (n > 0) {
41163
0
            int chunk = min_int(n, p1->len);
41164
0
            if (string_buffer_concat(b, p1, 0, chunk))
41165
0
                goto fail;
41166
0
            n -= chunk;
41167
0
        }
41168
0
    } else {
41169
0
        if (string_buffer_fill(b, c, n))
41170
0
            goto fail;
41171
0
    }
41172
0
    if (!padEnd) {
41173
0
        if (string_buffer_concat(b, p, 0, len))
41174
0
            goto fail;
41175
0
    }
41176
0
    JS_FreeValue(ctx, v);
41177
0
    JS_FreeValue(ctx, str);
41178
0
    return string_buffer_end(b);
41179
41180
0
fail:
41181
0
    string_buffer_free(b);
41182
0
fail3:
41183
0
    JS_FreeValue(ctx, v);
41184
0
fail2:
41185
0
    JS_FreeValue(ctx, str);
41186
0
fail1:
41187
0
    return JS_EXCEPTION;
41188
0
}
41189
41190
static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val,
41191
                                int argc, JSValueConst *argv)
41192
0
{
41193
0
    JSValue str;
41194
0
    StringBuffer b_s, *b = &b_s;
41195
0
    JSString *p;
41196
0
    int64_t val;
41197
0
    int n, len;
41198
41199
0
    str = JS_ToStringCheckObject(ctx, this_val);
41200
0
    if (JS_IsException(str))
41201
0
        goto fail;
41202
0
    if (JS_ToInt64Sat(ctx, &val, argv[0]))
41203
0
        goto fail;
41204
0
    if (val < 0 || val > 2147483647) {
41205
0
        JS_ThrowRangeError(ctx, "invalid repeat count");
41206
0
        goto fail;
41207
0
    }
41208
0
    n = val;
41209
0
    p = JS_VALUE_GET_STRING(str);
41210
0
    len = p->len;
41211
0
    if (len == 0 || n == 1)
41212
0
        return str;
41213
0
    if (val * len > JS_STRING_LEN_MAX) {
41214
0
        JS_ThrowInternalError(ctx, "string too long");
41215
0
        goto fail;
41216
0
    }
41217
0
    if (string_buffer_init2(ctx, b, n * len, p->is_wide_char))
41218
0
        goto fail;
41219
0
    if (len == 1) {
41220
0
        string_buffer_fill(b, string_get(p, 0), n);
41221
0
    } else {
41222
0
        while (n-- > 0) {
41223
0
            string_buffer_concat(b, p, 0, len);
41224
0
        }
41225
0
    }
41226
0
    JS_FreeValue(ctx, str);
41227
0
    return string_buffer_end(b);
41228
41229
0
fail:
41230
0
    JS_FreeValue(ctx, str);
41231
0
    return JS_EXCEPTION;
41232
0
}
41233
41234
static JSValue js_string_trim(JSContext *ctx, JSValueConst this_val,
41235
                              int argc, JSValueConst *argv, int magic)
41236
0
{
41237
0
    JSValue str, ret;
41238
0
    int a, b, len;
41239
0
    JSString *p;
41240
41241
0
    str = JS_ToStringCheckObject(ctx, this_val);
41242
0
    if (JS_IsException(str))
41243
0
        return str;
41244
0
    p = JS_VALUE_GET_STRING(str);
41245
0
    a = 0;
41246
0
    b = len = p->len;
41247
0
    if (magic & 1) {
41248
0
        while (a < len && lre_is_space(string_get(p, a)))
41249
0
            a++;
41250
0
    }
41251
0
    if (magic & 2) {
41252
0
        while (b > a && lre_is_space(string_get(p, b - 1)))
41253
0
            b--;
41254
0
    }
41255
0
    ret = js_sub_string(ctx, p, a, b);
41256
0
    JS_FreeValue(ctx, str);
41257
0
    return ret;
41258
0
}
41259
41260
static JSValue js_string___quote(JSContext *ctx, JSValueConst this_val,
41261
                                 int argc, JSValueConst *argv)
41262
0
{
41263
0
    return JS_ToQuotedString(ctx, this_val);
41264
0
}
41265
41266
/* return 0 if before the first char */
41267
static int string_prevc(JSString *p, int *pidx)
41268
0
{
41269
0
    int idx, c, c1;
41270
41271
0
    idx = *pidx;
41272
0
    if (idx <= 0)
41273
0
        return 0;
41274
0
    idx--;
41275
0
    if (p->is_wide_char) {
41276
0
        c = p->u.str16[idx];
41277
0
        if (c >= 0xdc00 && c < 0xe000 && idx > 0) {
41278
0
            c1 = p->u.str16[idx - 1];
41279
0
            if (c1 >= 0xd800 && c1 <= 0xdc00) {
41280
0
                c = (((c1 & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000;
41281
0
                idx--;
41282
0
            }
41283
0
        }
41284
0
    } else {
41285
0
        c = p->u.str8[idx];
41286
0
    }
41287
0
    *pidx = idx;
41288
0
    return c;
41289
0
}
41290
41291
static BOOL test_final_sigma(JSString *p, int sigma_pos)
41292
0
{
41293
0
    int k, c1;
41294
41295
    /* before C: skip case ignorable chars and check there is
41296
       a cased letter */
41297
0
    k = sigma_pos;
41298
0
    for(;;) {
41299
0
        c1 = string_prevc(p, &k);
41300
0
        if (!lre_is_case_ignorable(c1))
41301
0
            break;
41302
0
    }
41303
0
    if (!lre_is_cased(c1))
41304
0
        return FALSE;
41305
41306
    /* after C: skip case ignorable chars and check there is
41307
       no cased letter */
41308
0
    k = sigma_pos + 1;
41309
0
    for(;;) {
41310
0
        if (k >= p->len)
41311
0
            return TRUE;
41312
0
        c1 = string_getc(p, &k);
41313
0
        if (!lre_is_case_ignorable(c1))
41314
0
            break;
41315
0
    }
41316
0
    return !lre_is_cased(c1);
41317
0
}
41318
41319
static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
41320
                                       int argc, JSValueConst *argv)
41321
0
{
41322
0
    JSValue a, b;
41323
0
    int cmp;
41324
41325
0
    a = JS_ToStringCheckObject(ctx, this_val);
41326
0
    if (JS_IsException(a))
41327
0
        return JS_EXCEPTION;
41328
0
    b = JS_ToString(ctx, argv[0]);
41329
0
    if (JS_IsException(b)) {
41330
0
        JS_FreeValue(ctx, a);
41331
0
        return JS_EXCEPTION;
41332
0
    }
41333
0
    cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b));
41334
0
    JS_FreeValue(ctx, a);
41335
0
    JS_FreeValue(ctx, b);
41336
0
    return JS_NewInt32(ctx, cmp);
41337
0
}
41338
41339
static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val,
41340
                                     int argc, JSValueConst *argv, int to_lower)
41341
0
{
41342
0
    JSValue val;
41343
0
    StringBuffer b_s, *b = &b_s;
41344
0
    JSString *p;
41345
0
    int i, c, j, l;
41346
0
    uint32_t res[LRE_CC_RES_LEN_MAX];
41347
41348
0
    val = JS_ToStringCheckObject(ctx, this_val);
41349
0
    if (JS_IsException(val))
41350
0
        return val;
41351
0
    p = JS_VALUE_GET_STRING(val);
41352
0
    if (p->len == 0)
41353
0
        return val;
41354
0
    if (string_buffer_init(ctx, b, p->len))
41355
0
        goto fail;
41356
0
    for(i = 0; i < p->len;) {
41357
0
        c = string_getc(p, &i);
41358
0
        if (c == 0x3a3 && to_lower && test_final_sigma(p, i - 1)) {
41359
0
            res[0] = 0x3c2; /* final sigma */
41360
0
            l = 1;
41361
0
        } else {
41362
0
            l = lre_case_conv(res, c, to_lower);
41363
0
        }
41364
0
        for(j = 0; j < l; j++) {
41365
0
            if (string_buffer_putc(b, res[j]))
41366
0
                goto fail;
41367
0
        }
41368
0
    }
41369
0
    JS_FreeValue(ctx, val);
41370
0
    return string_buffer_end(b);
41371
0
 fail:
41372
0
    JS_FreeValue(ctx, val);
41373
0
    string_buffer_free(b);
41374
0
    return JS_EXCEPTION;
41375
0
}
41376
41377
#ifdef CONFIG_ALL_UNICODE
41378
41379
/* return (-1, NULL) if exception, otherwise (len, buf) */
41380
static int JS_ToUTF32String(JSContext *ctx, uint32_t **pbuf, JSValueConst val1)
41381
0
{
41382
0
    JSValue val;
41383
0
    JSString *p;
41384
0
    uint32_t *buf;
41385
0
    int i, j, len;
41386
41387
0
    val = JS_ToString(ctx, val1);
41388
0
    if (JS_IsException(val))
41389
0
        return -1;
41390
0
    p = JS_VALUE_GET_STRING(val);
41391
0
    len = p->len;
41392
    /* UTF32 buffer length is len minus the number of correct surrogates pairs */
41393
0
    buf = js_malloc(ctx, sizeof(buf[0]) * max_int(len, 1));
41394
0
    if (!buf) {
41395
0
        JS_FreeValue(ctx, val);
41396
0
        goto fail;
41397
0
    }
41398
0
    for(i = j = 0; i < len;)
41399
0
        buf[j++] = string_getc(p, &i);
41400
0
    JS_FreeValue(ctx, val);
41401
0
    *pbuf = buf;
41402
0
    return j;
41403
0
 fail:
41404
0
    *pbuf = NULL;
41405
0
    return -1;
41406
0
}
41407
41408
static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len)
41409
0
{
41410
0
    int i;
41411
0
    StringBuffer b_s, *b = &b_s;
41412
0
    if (string_buffer_init(ctx, b, len))
41413
0
        return JS_EXCEPTION;
41414
0
    for(i = 0; i < len; i++) {
41415
0
        if (string_buffer_putc(b, buf[i]))
41416
0
            goto fail;
41417
0
    }
41418
0
    return string_buffer_end(b);
41419
0
 fail:
41420
0
    string_buffer_free(b);
41421
0
    return JS_EXCEPTION;
41422
0
}
41423
41424
static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val,
41425
                                   int argc, JSValueConst *argv)
41426
0
{
41427
0
    const char *form, *p;
41428
0
    size_t form_len;
41429
0
    int is_compat, buf_len, out_len;
41430
0
    UnicodeNormalizationEnum n_type;
41431
0
    JSValue val;
41432
0
    uint32_t *buf, *out_buf;
41433
41434
0
    val = JS_ToStringCheckObject(ctx, this_val);
41435
0
    if (JS_IsException(val))
41436
0
        return val;
41437
0
    buf_len = JS_ToUTF32String(ctx, &buf, val);
41438
0
    JS_FreeValue(ctx, val);
41439
0
    if (buf_len < 0)
41440
0
        return JS_EXCEPTION;
41441
41442
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
41443
0
        n_type = UNICODE_NFC;
41444
0
    } else {
41445
0
        form = JS_ToCStringLen(ctx, &form_len, argv[0]);
41446
0
        if (!form)
41447
0
            goto fail1;
41448
0
        p = form;
41449
0
        if (p[0] != 'N' || p[1] != 'F')
41450
0
            goto bad_form;
41451
0
        p += 2;
41452
0
        is_compat = FALSE;
41453
0
        if (*p == 'K') {
41454
0
            is_compat = TRUE;
41455
0
            p++;
41456
0
        }
41457
0
        if (*p == 'C' || *p == 'D') {
41458
0
            n_type = UNICODE_NFC + is_compat * 2 + (*p - 'C');
41459
0
            if ((p + 1 - form) != form_len)
41460
0
                goto bad_form;
41461
0
        } else {
41462
0
        bad_form:
41463
0
            JS_FreeCString(ctx, form);
41464
0
            JS_ThrowRangeError(ctx, "bad normalization form");
41465
0
        fail1:
41466
0
            js_free(ctx, buf);
41467
0
            return JS_EXCEPTION;
41468
0
        }
41469
0
        JS_FreeCString(ctx, form);
41470
0
    }
41471
41472
0
    out_len = unicode_normalize(&out_buf, buf, buf_len, n_type,
41473
0
                                ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
41474
0
    js_free(ctx, buf);
41475
0
    if (out_len < 0)
41476
0
        return JS_EXCEPTION;
41477
0
    val = JS_NewUTF32String(ctx, out_buf, out_len);
41478
0
    js_free(ctx, out_buf);
41479
0
    return val;
41480
0
}
41481
#endif /* CONFIG_ALL_UNICODE */
41482
41483
/* also used for String.prototype.valueOf */
41484
static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val,
41485
                                  int argc, JSValueConst *argv)
41486
0
{
41487
0
    return js_thisStringValue(ctx, this_val);
41488
0
}
41489
41490
#if 0
41491
static JSValue js_string___toStringCheckObject(JSContext *ctx, JSValueConst this_val,
41492
                                               int argc, JSValueConst *argv)
41493
{
41494
    return JS_ToStringCheckObject(ctx, argv[0]);
41495
}
41496
41497
static JSValue js_string___toString(JSContext *ctx, JSValueConst this_val,
41498
                                    int argc, JSValueConst *argv)
41499
{
41500
    return JS_ToString(ctx, argv[0]);
41501
}
41502
41503
static JSValue js_string___advanceStringIndex(JSContext *ctx, JSValueConst
41504
                                              this_val,
41505
                                              int argc, JSValueConst *argv)
41506
{
41507
    JSValue str;
41508
    int idx;
41509
    BOOL is_unicode;
41510
    JSString *p;
41511
41512
    str = JS_ToString(ctx, argv[0]);
41513
    if (JS_IsException(str))
41514
        return str;
41515
    if (JS_ToInt32Sat(ctx, &idx, argv[1])) {
41516
        JS_FreeValue(ctx, str);
41517
        return JS_EXCEPTION;
41518
    }
41519
    is_unicode = JS_ToBool(ctx, argv[2]);
41520
    p = JS_VALUE_GET_STRING(str);
41521
    if (!is_unicode || (unsigned)idx >= p->len || !p->is_wide_char) {
41522
        idx++;
41523
    } else {
41524
        string_getc(p, &idx);
41525
    }
41526
    JS_FreeValue(ctx, str);
41527
    return JS_NewInt32(ctx, idx);
41528
}
41529
#endif
41530
41531
/* String Iterator */
41532
41533
static JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val,
41534
                                       int argc, JSValueConst *argv,
41535
                                       BOOL *pdone, int magic)
41536
53.0k
{
41537
53.0k
    JSArrayIteratorData *it;
41538
53.0k
    uint32_t idx, c, start;
41539
53.0k
    JSString *p;
41540
41541
53.0k
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_STRING_ITERATOR);
41542
53.0k
    if (!it) {
41543
0
        *pdone = FALSE;
41544
0
        return JS_EXCEPTION;
41545
0
    }
41546
53.0k
    if (JS_IsUndefined(it->obj))
41547
0
        goto done;
41548
53.0k
    p = JS_VALUE_GET_STRING(it->obj);
41549
53.0k
    idx = it->idx;
41550
53.0k
    if (idx >= p->len) {
41551
2
        JS_FreeValue(ctx, it->obj);
41552
2
        it->obj = JS_UNDEFINED;
41553
2
    done:
41554
2
        *pdone = TRUE;
41555
2
        return JS_UNDEFINED;
41556
2
    }
41557
41558
53.0k
    start = idx;
41559
53.0k
    c = string_getc(p, (int *)&idx);
41560
53.0k
    it->idx = idx;
41561
53.0k
    *pdone = FALSE;
41562
53.0k
    if (c <= 0xffff) {
41563
53.0k
        return js_new_string_char(ctx, c);
41564
53.0k
    } else {
41565
0
        return js_new_string16(ctx, p->u.str16 + start, 2);
41566
0
    }
41567
53.0k
}
41568
41569
/* ES6 Annex B 2.3.2 etc. */
41570
enum {
41571
    magic_string_anchor,
41572
    magic_string_big,
41573
    magic_string_blink,
41574
    magic_string_bold,
41575
    magic_string_fixed,
41576
    magic_string_fontcolor,
41577
    magic_string_fontsize,
41578
    magic_string_italics,
41579
    magic_string_link,
41580
    magic_string_small,
41581
    magic_string_strike,
41582
    magic_string_sub,
41583
    magic_string_sup,
41584
};
41585
41586
static JSValue js_string_CreateHTML(JSContext *ctx, JSValueConst this_val,
41587
                                    int argc, JSValueConst *argv, int magic)
41588
0
{
41589
0
    JSValue str;
41590
0
    const JSString *p;
41591
0
    StringBuffer b_s, *b = &b_s;
41592
0
    static struct { const char *tag, *attr; } const defs[] = {
41593
0
        { "a", "name" }, { "big", NULL }, { "blink", NULL }, { "b", NULL },
41594
0
        { "tt", NULL }, { "font", "color" }, { "font", "size" }, { "i", NULL },
41595
0
        { "a", "href" }, { "small", NULL }, { "strike", NULL }, 
41596
0
        { "sub", NULL }, { "sup", NULL },
41597
0
    };
41598
41599
0
    str = JS_ToStringCheckObject(ctx, this_val);
41600
0
    if (JS_IsException(str))
41601
0
        return JS_EXCEPTION;
41602
0
    string_buffer_init(ctx, b, 7);
41603
0
    string_buffer_putc8(b, '<');
41604
0
    string_buffer_puts8(b, defs[magic].tag);
41605
0
    if (defs[magic].attr) {
41606
        // r += " " + attr + "=\"" + value + "\"";
41607
0
        JSValue value;
41608
0
        int i;
41609
41610
0
        string_buffer_putc8(b, ' ');
41611
0
        string_buffer_puts8(b, defs[magic].attr);
41612
0
        string_buffer_puts8(b, "=\"");
41613
0
        value = JS_ToStringCheckObject(ctx, argv[0]);
41614
0
        if (JS_IsException(value)) {
41615
0
            JS_FreeValue(ctx, str);
41616
0
            string_buffer_free(b);
41617
0
            return JS_EXCEPTION;
41618
0
        }
41619
0
        p = JS_VALUE_GET_STRING(value);
41620
0
        for (i = 0; i < p->len; i++) {
41621
0
            int c = string_get(p, i);
41622
0
            if (c == '"') {
41623
0
                string_buffer_puts8(b, "&quot;");
41624
0
            } else {
41625
0
                string_buffer_putc16(b, c);
41626
0
            }
41627
0
        }
41628
0
        JS_FreeValue(ctx, value);
41629
0
        string_buffer_putc8(b, '\"');
41630
0
    }
41631
    // return r + ">" + str + "</" + tag + ">";
41632
0
    string_buffer_putc8(b, '>');
41633
0
    string_buffer_concat_value_free(b, str);
41634
0
    string_buffer_puts8(b, "</");
41635
0
    string_buffer_puts8(b, defs[magic].tag);
41636
0
    string_buffer_putc8(b, '>');
41637
0
    return string_buffer_end(b);
41638
0
}
41639
41640
static const JSCFunctionListEntry js_string_funcs[] = {
41641
    JS_CFUNC_DEF("fromCharCode", 1, js_string_fromCharCode ),
41642
    JS_CFUNC_DEF("fromCodePoint", 1, js_string_fromCodePoint ),
41643
    JS_CFUNC_DEF("raw", 1, js_string_raw ),
41644
    //JS_CFUNC_DEF("__toString", 1, js_string___toString ),
41645
    //JS_CFUNC_DEF("__isSpace", 1, js_string___isSpace ),
41646
    //JS_CFUNC_DEF("__toStringCheckObject", 1, js_string___toStringCheckObject ),
41647
    //JS_CFUNC_DEF("__advanceStringIndex", 3, js_string___advanceStringIndex ),
41648
    //JS_CFUNC_DEF("__GetSubstitution", 6, js_string___GetSubstitution ),
41649
};
41650
41651
static const JSCFunctionListEntry js_string_proto_funcs[] = {
41652
    JS_PROP_INT32_DEF("length", 0, JS_PROP_CONFIGURABLE ),
41653
    JS_CFUNC_DEF("charCodeAt", 1, js_string_charCodeAt ),
41654
    JS_CFUNC_DEF("charAt", 1, js_string_charAt ),
41655
    JS_CFUNC_DEF("concat", 1, js_string_concat ),
41656
    JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ),
41657
    JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0 ),
41658
    JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1 ),
41659
    JS_CFUNC_MAGIC_DEF("includes", 1, js_string_includes, 0 ),
41660
    JS_CFUNC_MAGIC_DEF("endsWith", 1, js_string_includes, 2 ),
41661
    JS_CFUNC_MAGIC_DEF("startsWith", 1, js_string_includes, 1 ),
41662
    JS_CFUNC_MAGIC_DEF("match", 1, js_string_match, JS_ATOM_Symbol_match ),
41663
    JS_CFUNC_MAGIC_DEF("matchAll", 1, js_string_match, JS_ATOM_Symbol_matchAll ),
41664
    JS_CFUNC_MAGIC_DEF("search", 1, js_string_match, JS_ATOM_Symbol_search ),
41665
    JS_CFUNC_DEF("split", 2, js_string_split ),
41666
    JS_CFUNC_DEF("substring", 2, js_string_substring ),
41667
    JS_CFUNC_DEF("substr", 2, js_string_substr ),
41668
    JS_CFUNC_DEF("slice", 2, js_string_slice ),
41669
    JS_CFUNC_DEF("repeat", 1, js_string_repeat ),
41670
    JS_CFUNC_MAGIC_DEF("replace", 2, js_string_replace, 0 ),
41671
    JS_CFUNC_MAGIC_DEF("replaceAll", 2, js_string_replace, 1 ),
41672
    JS_CFUNC_MAGIC_DEF("padEnd", 1, js_string_pad, 1 ),
41673
    JS_CFUNC_MAGIC_DEF("padStart", 1, js_string_pad, 0 ),
41674
    JS_CFUNC_MAGIC_DEF("trim", 0, js_string_trim, 3 ),
41675
    JS_CFUNC_MAGIC_DEF("trimEnd", 0, js_string_trim, 2 ),
41676
    JS_ALIAS_DEF("trimRight", "trimEnd" ),
41677
    JS_CFUNC_MAGIC_DEF("trimStart", 0, js_string_trim, 1 ),
41678
    JS_ALIAS_DEF("trimLeft", "trimStart" ),
41679
    JS_CFUNC_DEF("toString", 0, js_string_toString ),
41680
    JS_CFUNC_DEF("valueOf", 0, js_string_toString ),
41681
    JS_CFUNC_DEF("__quote", 1, js_string___quote ),
41682
    JS_CFUNC_DEF("localeCompare", 1, js_string_localeCompare ),
41683
    JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ),
41684
    JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ),
41685
    JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ),
41686
    JS_CFUNC_MAGIC_DEF("toLocaleUpperCase", 0, js_string_toLowerCase, 0 ),
41687
    JS_CFUNC_MAGIC_DEF("[Symbol.iterator]", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE | 4 ),
41688
    /* ES6 Annex B 2.3.2 etc. */
41689
    JS_CFUNC_MAGIC_DEF("anchor", 1, js_string_CreateHTML, magic_string_anchor ),
41690
    JS_CFUNC_MAGIC_DEF("big", 0, js_string_CreateHTML, magic_string_big ),
41691
    JS_CFUNC_MAGIC_DEF("blink", 0, js_string_CreateHTML, magic_string_blink ),
41692
    JS_CFUNC_MAGIC_DEF("bold", 0, js_string_CreateHTML, magic_string_bold ),
41693
    JS_CFUNC_MAGIC_DEF("fixed", 0, js_string_CreateHTML, magic_string_fixed ),
41694
    JS_CFUNC_MAGIC_DEF("fontcolor", 1, js_string_CreateHTML, magic_string_fontcolor ),
41695
    JS_CFUNC_MAGIC_DEF("fontsize", 1, js_string_CreateHTML, magic_string_fontsize ),
41696
    JS_CFUNC_MAGIC_DEF("italics", 0, js_string_CreateHTML, magic_string_italics ),
41697
    JS_CFUNC_MAGIC_DEF("link", 1, js_string_CreateHTML, magic_string_link ),
41698
    JS_CFUNC_MAGIC_DEF("small", 0, js_string_CreateHTML, magic_string_small ),
41699
    JS_CFUNC_MAGIC_DEF("strike", 0, js_string_CreateHTML, magic_string_strike ),
41700
    JS_CFUNC_MAGIC_DEF("sub", 0, js_string_CreateHTML, magic_string_sub ),
41701
    JS_CFUNC_MAGIC_DEF("sup", 0, js_string_CreateHTML, magic_string_sup ),
41702
};
41703
41704
static const JSCFunctionListEntry js_string_iterator_proto_funcs[] = {
41705
    JS_ITERATOR_NEXT_DEF("next", 0, js_string_iterator_next, 0 ),
41706
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "String Iterator", JS_PROP_CONFIGURABLE ),
41707
};
41708
41709
#ifdef CONFIG_ALL_UNICODE
41710
static const JSCFunctionListEntry js_string_proto_normalize[] = {
41711
    JS_CFUNC_DEF("normalize", 0, js_string_normalize ),
41712
};
41713
#endif
41714
41715
void JS_AddIntrinsicStringNormalize(JSContext *ctx)
41716
2
{
41717
2
#ifdef CONFIG_ALL_UNICODE
41718
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_normalize,
41719
2
                               countof(js_string_proto_normalize));
41720
2
#endif
41721
2
}
41722
41723
/* Math */
41724
41725
/* precondition: a and b are not NaN */
41726
static double js_fmin(double a, double b)
41727
0
{
41728
0
    if (a == 0 && b == 0) {
41729
0
        JSFloat64Union a1, b1;
41730
0
        a1.d = a;
41731
0
        b1.d = b;
41732
0
        a1.u64 |= b1.u64;
41733
0
        return a1.d;
41734
0
    } else {
41735
0
        return fmin(a, b);
41736
0
    }
41737
0
}
41738
41739
/* precondition: a and b are not NaN */
41740
static double js_fmax(double a, double b)
41741
0
{
41742
0
    if (a == 0 && b == 0) {
41743
0
        JSFloat64Union a1, b1;
41744
0
        a1.d = a;
41745
0
        b1.d = b;
41746
0
        a1.u64 &= b1.u64;
41747
0
        return a1.d;
41748
0
    } else {
41749
0
        return fmax(a, b);
41750
0
    }
41751
0
}
41752
41753
static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
41754
                               int argc, JSValueConst *argv, int magic)
41755
0
{
41756
0
    BOOL is_max = magic;
41757
0
    double r, a;
41758
0
    int i;
41759
0
    uint32_t tag;
41760
41761
0
    if (unlikely(argc == 0)) {
41762
0
        return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
41763
0
    }
41764
41765
0
    tag = JS_VALUE_GET_TAG(argv[0]);
41766
0
    if (tag == JS_TAG_INT) {
41767
0
        int a1, r1 = JS_VALUE_GET_INT(argv[0]);
41768
0
        for(i = 1; i < argc; i++) {
41769
0
            tag = JS_VALUE_GET_TAG(argv[i]);
41770
0
            if (tag != JS_TAG_INT) {
41771
0
                r = r1;
41772
0
                goto generic_case;
41773
0
            }
41774
0
            a1 = JS_VALUE_GET_INT(argv[i]);
41775
0
            if (is_max)
41776
0
                r1 = max_int(r1, a1);
41777
0
            else
41778
0
                r1 = min_int(r1, a1);
41779
41780
0
        }
41781
0
        return JS_NewInt32(ctx, r1);
41782
0
    } else {
41783
0
        if (JS_ToFloat64(ctx, &r, argv[0]))
41784
0
            return JS_EXCEPTION;
41785
0
        i = 1;
41786
0
    generic_case:
41787
0
        while (i < argc) {
41788
0
            if (JS_ToFloat64(ctx, &a, argv[i]))
41789
0
                return JS_EXCEPTION;
41790
0
            if (!isnan(r)) {
41791
0
                if (isnan(a)) {
41792
0
                    r = a;
41793
0
                } else {
41794
0
                    if (is_max)
41795
0
                        r = js_fmax(r, a);
41796
0
                    else
41797
0
                        r = js_fmin(r, a);
41798
0
                }
41799
0
            }
41800
0
            i++;
41801
0
        }
41802
0
        return JS_NewFloat64(ctx, r);
41803
0
    }
41804
0
}
41805
41806
static double js_math_sign(double a)
41807
0
{
41808
0
    if (isnan(a) || a == 0.0)
41809
0
        return a;
41810
0
    if (a < 0)
41811
0
        return -1;
41812
0
    else
41813
0
        return 1;
41814
0
}
41815
41816
static double js_math_round(double a)
41817
0
{
41818
0
    JSFloat64Union u;
41819
0
    uint64_t frac_mask, one;
41820
0
    unsigned int e, s;
41821
41822
0
    u.d = a;
41823
0
    e = (u.u64 >> 52) & 0x7ff;
41824
0
    if (e < 1023) {
41825
        /* abs(a) < 1 */
41826
0
        if (e == (1023 - 1) && u.u64 != 0xbfe0000000000000) {
41827
            /* abs(a) > 0.5 or a = 0.5: return +/-1.0 */
41828
0
            u.u64 = (u.u64 & ((uint64_t)1 << 63)) | ((uint64_t)1023 << 52);
41829
0
        } else {
41830
            /* return +/-0.0 */
41831
0
            u.u64 &= (uint64_t)1 << 63;
41832
0
        }
41833
0
    } else if (e < (1023 + 52)) {
41834
0
        s = u.u64 >> 63;
41835
0
        one = (uint64_t)1 << (52 - (e - 1023));
41836
0
        frac_mask = one - 1;
41837
0
        u.u64 += (one >> 1) - s;
41838
0
        u.u64 &= ~frac_mask; /* truncate to an integer */
41839
0
    }
41840
    /* otherwise: abs(a) >= 2^52, or NaN, +/-Infinity: no change */
41841
0
    return u.d;
41842
0
}
41843
41844
static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
41845
                             int argc, JSValueConst *argv)
41846
0
{
41847
0
    double r, a;
41848
0
    int i;
41849
41850
0
    r = 0;
41851
0
    if (argc > 0) {
41852
0
        if (JS_ToFloat64(ctx, &r, argv[0]))
41853
0
            return JS_EXCEPTION;
41854
0
        if (argc == 1) {
41855
0
            r = fabs(r);
41856
0
        } else {
41857
            /* use the built-in function to minimize precision loss */
41858
0
            for (i = 1; i < argc; i++) {
41859
0
                if (JS_ToFloat64(ctx, &a, argv[i]))
41860
0
                    return JS_EXCEPTION;
41861
0
                r = hypot(r, a);
41862
0
            }
41863
0
        }
41864
0
    }
41865
0
    return JS_NewFloat64(ctx, r);
41866
0
}
41867
41868
static double js_math_fround(double a)
41869
0
{
41870
0
    return (float)a;
41871
0
}
41872
41873
static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,
41874
                            int argc, JSValueConst *argv)
41875
0
{
41876
0
    int a, b;
41877
41878
0
    if (JS_ToInt32(ctx, &a, argv[0]))
41879
0
        return JS_EXCEPTION;
41880
0
    if (JS_ToInt32(ctx, &b, argv[1]))
41881
0
        return JS_EXCEPTION;
41882
    /* purposely ignoring overflow */
41883
0
    return JS_NewInt32(ctx, a * b);
41884
0
}
41885
41886
static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
41887
                             int argc, JSValueConst *argv)
41888
0
{
41889
0
    uint32_t a, r;
41890
41891
0
    if (JS_ToUint32(ctx, &a, argv[0]))
41892
0
        return JS_EXCEPTION;
41893
0
    if (a == 0)
41894
0
        r = 32;
41895
0
    else
41896
0
        r = clz32(a);
41897
0
    return JS_NewInt32(ctx, r);
41898
0
}
41899
41900
/* xorshift* random number generator by Marsaglia */
41901
static uint64_t xorshift64star(uint64_t *pstate)
41902
0
{
41903
0
    uint64_t x;
41904
0
    x = *pstate;
41905
0
    x ^= x >> 12;
41906
0
    x ^= x << 25;
41907
0
    x ^= x >> 27;
41908
0
    *pstate = x;
41909
0
    return x * 0x2545F4914F6CDD1D;
41910
0
}
41911
41912
static void js_random_init(JSContext *ctx)
41913
2
{
41914
2
    struct timeval tv;
41915
2
    gettimeofday(&tv, NULL);
41916
2
    ctx->random_state = ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
41917
    /* the state must be non zero */
41918
2
    if (ctx->random_state == 0)
41919
0
        ctx->random_state = 1;
41920
2
}
41921
41922
static JSValue js_math_random(JSContext *ctx, JSValueConst this_val,
41923
                              int argc, JSValueConst *argv)
41924
0
{
41925
0
    JSFloat64Union u;
41926
0
    uint64_t v;
41927
41928
0
    v = xorshift64star(&ctx->random_state);
41929
    /* 1.0 <= u.d < 2 */
41930
0
    u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12);
41931
0
    return __JS_NewFloat64(ctx, u.d - 1.0);
41932
0
}
41933
41934
static const JSCFunctionListEntry js_math_funcs[] = {
41935
    JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
41936
    JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
41937
    JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ),
41938
    JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ),
41939
    JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ),
41940
    JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),
41941
    JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt ),
41942
41943
    JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, acos ),
41944
    JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, asin ),
41945
    JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, atan ),
41946
    JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, atan2 ),
41947
    JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, cos ),
41948
    JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, exp ),
41949
    JS_CFUNC_SPECIAL_DEF("log", 1, f_f, log ),
41950
    JS_CFUNC_SPECIAL_DEF("pow", 2, f_f_f, js_pow ),
41951
    JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, sin ),
41952
    JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, tan ),
41953
    /* ES6 */
41954
    JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, trunc ),
41955
    JS_CFUNC_SPECIAL_DEF("sign", 1, f_f, js_math_sign ),
41956
    JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, cosh ),
41957
    JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, sinh ),
41958
    JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, tanh ),
41959
    JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, acosh ),
41960
    JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, asinh ),
41961
    JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, atanh ),
41962
    JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, expm1 ),
41963
    JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, log1p ),
41964
    JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2 ),
41965
    JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, log10 ),
41966
    JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, cbrt ),
41967
    JS_CFUNC_DEF("hypot", 2, js_math_hypot ),
41968
    JS_CFUNC_DEF("random", 0, js_math_random ),
41969
    JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround ),
41970
    JS_CFUNC_DEF("imul", 2, js_math_imul ),
41971
    JS_CFUNC_DEF("clz32", 1, js_math_clz32 ),
41972
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Math", JS_PROP_CONFIGURABLE ),
41973
    JS_PROP_DOUBLE_DEF("E", 2.718281828459045, 0 ),
41974
    JS_PROP_DOUBLE_DEF("LN10", 2.302585092994046, 0 ),
41975
    JS_PROP_DOUBLE_DEF("LN2", 0.6931471805599453, 0 ),
41976
    JS_PROP_DOUBLE_DEF("LOG2E", 1.4426950408889634, 0 ),
41977
    JS_PROP_DOUBLE_DEF("LOG10E", 0.4342944819032518, 0 ),
41978
    JS_PROP_DOUBLE_DEF("PI", 3.141592653589793, 0 ),
41979
    JS_PROP_DOUBLE_DEF("SQRT1_2", 0.7071067811865476, 0 ),
41980
    JS_PROP_DOUBLE_DEF("SQRT2", 1.4142135623730951, 0 ),
41981
};
41982
41983
static const JSCFunctionListEntry js_math_obj[] = {
41984
    JS_OBJECT_DEF("Math", js_math_funcs, countof(js_math_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
41985
};
41986
41987
/* Date */
41988
41989
#if 0
41990
/* OS dependent: return the UTC time in ms since 1970. */
41991
static JSValue js___date_now(JSContext *ctx, JSValueConst this_val,
41992
                             int argc, JSValueConst *argv)
41993
{
41994
    int64_t d;
41995
    struct timeval tv;
41996
    gettimeofday(&tv, NULL);
41997
    d = (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
41998
    return JS_NewInt64(ctx, d);
41999
}
42000
#endif
42001
42002
/* OS dependent: return the UTC time in microseconds since 1970. */
42003
static JSValue js___date_clock(JSContext *ctx, JSValueConst this_val,
42004
                               int argc, JSValueConst *argv)
42005
0
{
42006
0
    int64_t d;
42007
0
    struct timeval tv;
42008
0
    gettimeofday(&tv, NULL);
42009
0
    d = (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
42010
0
    return JS_NewInt64(ctx, d);
42011
0
}
42012
42013
/* OS dependent. d = argv[0] is in ms from 1970. Return the difference
42014
   between UTC time and local time 'd' in minutes */
42015
0
static int getTimezoneOffset(int64_t time) {
42016
#if defined(_WIN32)
42017
    /* XXX: TODO */
42018
    return 0;
42019
#else
42020
0
    time_t ti;
42021
0
    struct tm tm;
42022
42023
0
    time /= 1000; /* convert to seconds */
42024
0
    if (sizeof(time_t) == 4) {
42025
        /* on 32-bit systems, we need to clamp the time value to the
42026
           range of `time_t`. This is better than truncating values to
42027
           32 bits and hopefully provides the same result as 64-bit
42028
           implementation of localtime_r.
42029
         */
42030
0
        if ((time_t)-1 < 0) {
42031
0
            if (time < INT32_MIN) {
42032
0
                time = INT32_MIN;
42033
0
            } else if (time > INT32_MAX) {
42034
0
                time = INT32_MAX;
42035
0
            }
42036
0
        } else {
42037
0
            if (time < 0) {
42038
0
                time = 0;
42039
0
            } else if (time > UINT32_MAX) {
42040
0
                time = UINT32_MAX;
42041
0
            }
42042
0
        }
42043
0
    }
42044
0
    ti = time;
42045
0
    localtime_r(&ti, &tm);
42046
0
    return -tm.tm_gmtoff / 60;
42047
0
#endif
42048
0
}
42049
42050
#if 0
42051
static JSValue js___date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
42052
                                           int argc, JSValueConst *argv)
42053
{
42054
    double dd;
42055
42056
    if (JS_ToFloat64(ctx, &dd, argv[0]))
42057
        return JS_EXCEPTION;
42058
    if (isnan(dd))
42059
        return __JS_NewFloat64(ctx, dd);
42060
    else
42061
        return JS_NewInt32(ctx, getTimezoneOffset((int64_t)dd));
42062
}
42063
42064
static JSValue js_get_prototype_from_ctor(JSContext *ctx, JSValueConst ctor,
42065
                                          JSValueConst def_proto)
42066
{
42067
    JSValue proto;
42068
    proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
42069
    if (JS_IsException(proto))
42070
        return proto;
42071
    if (!JS_IsObject(proto)) {
42072
        JS_FreeValue(ctx, proto);
42073
        proto = JS_DupValue(ctx, def_proto);
42074
    }
42075
    return proto;
42076
}
42077
42078
/* create a new date object */
42079
static JSValue js___date_create(JSContext *ctx, JSValueConst this_val,
42080
                                int argc, JSValueConst *argv)
42081
{
42082
    JSValue obj, proto;
42083
    proto = js_get_prototype_from_ctor(ctx, argv[0], argv[1]);
42084
    if (JS_IsException(proto))
42085
        return proto;
42086
    obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_DATE);
42087
    JS_FreeValue(ctx, proto);
42088
    if (!JS_IsException(obj))
42089
        JS_SetObjectData(ctx, obj, JS_DupValue(ctx, argv[2]));
42090
    return obj;
42091
}
42092
#endif
42093
42094
/* RegExp */
42095
42096
static void js_regexp_finalizer(JSRuntime *rt, JSValue val)
42097
5
{
42098
5
    JSObject *p = JS_VALUE_GET_OBJ(val);
42099
5
    JSRegExp *re = &p->u.regexp;
42100
5
    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->bytecode));
42101
5
    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->pattern));
42102
5
}
42103
42104
/* create a string containing the RegExp bytecode */
42105
static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
42106
                                 JSValueConst flags)
42107
67
{
42108
67
    const char *str;
42109
67
    int re_flags, mask;
42110
67
    uint8_t *re_bytecode_buf;
42111
67
    size_t i, len;
42112
67
    int re_bytecode_len;
42113
67
    JSValue ret;
42114
67
    char error_msg[64];
42115
42116
67
    re_flags = 0;
42117
67
    if (!JS_IsUndefined(flags)) {
42118
67
        str = JS_ToCStringLen(ctx, &len, flags);
42119
67
        if (!str)
42120
0
            return JS_EXCEPTION;
42121
        /* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */
42122
71
        for (i = 0; i < len; i++) {
42123
4
            switch(str[i]) {
42124
4
            case 'g':
42125
4
                mask = LRE_FLAG_GLOBAL;
42126
4
                break;
42127
0
            case 'i':
42128
0
                mask = LRE_FLAG_IGNORECASE;
42129
0
                break;
42130
0
            case 'm':
42131
0
                mask = LRE_FLAG_MULTILINE;
42132
0
                break;
42133
0
            case 's':
42134
0
                mask = LRE_FLAG_DOTALL;
42135
0
                break;
42136
0
            case 'u':
42137
0
                mask = LRE_FLAG_UTF16;
42138
0
                break;
42139
0
            case 'y':
42140
0
                mask = LRE_FLAG_STICKY;
42141
0
                break;
42142
0
            default:
42143
0
                goto bad_flags;
42144
4
            }
42145
4
            if ((re_flags & mask) != 0) {
42146
0
            bad_flags:
42147
0
                JS_FreeCString(ctx, str);
42148
0
                return JS_ThrowSyntaxError(ctx, "invalid regular expression flags");
42149
0
            }
42150
4
            re_flags |= mask;
42151
4
        }
42152
67
        JS_FreeCString(ctx, str);
42153
67
    }
42154
42155
67
    str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & LRE_FLAG_UTF16));
42156
67
    if (!str)
42157
0
        return JS_EXCEPTION;
42158
67
    re_bytecode_buf = lre_compile(&re_bytecode_len, error_msg,
42159
67
                                  sizeof(error_msg), str, len, re_flags, ctx);
42160
67
    JS_FreeCString(ctx, str);
42161
67
    if (!re_bytecode_buf) {
42162
0
        JS_ThrowSyntaxError(ctx, "%s", error_msg);
42163
0
        return JS_EXCEPTION;
42164
0
    }
42165
42166
67
    ret = js_new_string8(ctx, re_bytecode_buf, re_bytecode_len);
42167
67
    js_free(ctx, re_bytecode_buf);
42168
67
    return ret;
42169
67
}
42170
42171
/* create a RegExp object from a string containing the RegExp bytecode
42172
   and the source pattern */
42173
static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
42174
                                              JSValue pattern, JSValue bc)
42175
5
{
42176
5
    JSValue obj;
42177
5
    JSObject *p;
42178
5
    JSRegExp *re;
42179
42180
    /* sanity check */
42181
5
    if (JS_VALUE_GET_TAG(bc) != JS_TAG_STRING ||
42182
5
        JS_VALUE_GET_TAG(pattern) != JS_TAG_STRING) {
42183
0
        JS_ThrowTypeError(ctx, "string expected");
42184
0
    fail:
42185
0
        JS_FreeValue(ctx, bc);
42186
0
        JS_FreeValue(ctx, pattern);
42187
0
        return JS_EXCEPTION;
42188
0
    }
42189
42190
5
    obj = js_create_from_ctor(ctx, ctor, JS_CLASS_REGEXP);
42191
5
    if (JS_IsException(obj))
42192
0
        goto fail;
42193
5
    p = JS_VALUE_GET_OBJ(obj);
42194
5
    re = &p->u.regexp;
42195
5
    re->pattern = JS_VALUE_GET_STRING(pattern);
42196
5
    re->bytecode = JS_VALUE_GET_STRING(bc);
42197
5
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0),
42198
5
                           JS_PROP_WRITABLE);
42199
5
    return obj;
42200
5
}
42201
42202
static JSRegExp *js_get_regexp(JSContext *ctx, JSValueConst obj, BOOL throw_error)
42203
0
{
42204
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
42205
0
        JSObject *p = JS_VALUE_GET_OBJ(obj);
42206
0
        if (p->class_id == JS_CLASS_REGEXP)
42207
0
            return &p->u.regexp;
42208
0
    }
42209
0
    if (throw_error) {
42210
0
        JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
42211
0
    }
42212
0
    return NULL;
42213
0
}
42214
42215
/* return < 0 if exception or TRUE/FALSE */
42216
static int js_is_regexp(JSContext *ctx, JSValueConst obj)
42217
0
{
42218
0
    JSValue m;
42219
42220
0
    if (!JS_IsObject(obj))
42221
0
        return FALSE;
42222
0
    m = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_match);
42223
0
    if (JS_IsException(m))
42224
0
        return -1;
42225
0
    if (!JS_IsUndefined(m))
42226
0
        return JS_ToBoolFree(ctx, m);
42227
0
    return js_get_regexp(ctx, obj, FALSE) != NULL;
42228
0
}
42229
42230
static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target,
42231
                                     int argc, JSValueConst *argv)
42232
0
{
42233
0
    JSValue pattern, flags, bc, val;
42234
0
    JSValueConst pat, flags1;
42235
0
    JSRegExp *re;
42236
0
    int pat_is_regexp;
42237
42238
0
    pat = argv[0];
42239
0
    flags1 = argv[1];
42240
0
    pat_is_regexp = js_is_regexp(ctx, pat);
42241
0
    if (pat_is_regexp < 0)
42242
0
        return JS_EXCEPTION;
42243
0
    if (JS_IsUndefined(new_target)) {
42244
        /* called as a function */
42245
0
        new_target = JS_GetActiveFunction(ctx);
42246
0
        if (pat_is_regexp && JS_IsUndefined(flags1)) {
42247
0
            JSValue ctor;
42248
0
            BOOL res;
42249
0
            ctor = JS_GetProperty(ctx, pat, JS_ATOM_constructor);
42250
0
            if (JS_IsException(ctor))
42251
0
                return ctor;
42252
0
            res = js_same_value(ctx, ctor, new_target);
42253
0
            JS_FreeValue(ctx, ctor);
42254
0
            if (res)
42255
0
                return JS_DupValue(ctx, pat);
42256
0
        }
42257
0
    }
42258
0
    re = js_get_regexp(ctx, pat, FALSE);
42259
0
    if (re) {
42260
0
        pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
42261
0
        if (JS_IsUndefined(flags1)) {
42262
0
            bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
42263
0
            goto no_compilation;
42264
0
        } else {
42265
0
            flags = JS_ToString(ctx, flags1);
42266
0
            if (JS_IsException(flags))
42267
0
                goto fail;
42268
0
        }
42269
0
    } else {
42270
0
        flags = JS_UNDEFINED;
42271
0
        if (pat_is_regexp) {
42272
0
            pattern = JS_GetProperty(ctx, pat, JS_ATOM_source);
42273
0
            if (JS_IsException(pattern))
42274
0
                goto fail;
42275
0
            if (JS_IsUndefined(flags1)) {
42276
0
                flags = JS_GetProperty(ctx, pat, JS_ATOM_flags);
42277
0
                if (JS_IsException(flags))
42278
0
                    goto fail;
42279
0
            } else {
42280
0
                flags = JS_DupValue(ctx, flags1);
42281
0
            }
42282
0
        } else {
42283
0
            pattern = JS_DupValue(ctx, pat);
42284
0
            flags = JS_DupValue(ctx, flags1);
42285
0
        }
42286
0
        if (JS_IsUndefined(pattern)) {
42287
0
            pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
42288
0
        } else {
42289
0
            val = pattern;
42290
0
            pattern = JS_ToString(ctx, val);
42291
0
            JS_FreeValue(ctx, val);
42292
0
            if (JS_IsException(pattern))
42293
0
                goto fail;
42294
0
        }
42295
0
    }
42296
0
    bc = js_compile_regexp(ctx, pattern, flags);
42297
0
    if (JS_IsException(bc))
42298
0
        goto fail;
42299
0
    JS_FreeValue(ctx, flags);
42300
0
 no_compilation:
42301
0
    return js_regexp_constructor_internal(ctx, new_target, pattern, bc);
42302
0
 fail:
42303
0
    JS_FreeValue(ctx, pattern);
42304
0
    JS_FreeValue(ctx, flags);
42305
0
    return JS_EXCEPTION;
42306
0
}
42307
42308
static JSValue js_regexp_compile(JSContext *ctx, JSValueConst this_val,
42309
                                 int argc, JSValueConst *argv)
42310
0
{
42311
0
    JSRegExp *re1, *re;
42312
0
    JSValueConst pattern1, flags1;
42313
0
    JSValue bc, pattern;
42314
42315
0
    re = js_get_regexp(ctx, this_val, TRUE);
42316
0
    if (!re)
42317
0
        return JS_EXCEPTION;
42318
0
    pattern1 = argv[0];
42319
0
    flags1 = argv[1];
42320
0
    re1 = js_get_regexp(ctx, pattern1, FALSE);
42321
0
    if (re1) {
42322
0
        if (!JS_IsUndefined(flags1))
42323
0
            return JS_ThrowTypeError(ctx, "flags must be undefined");
42324
0
        pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->pattern));
42325
0
        bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->bytecode));
42326
0
    } else {
42327
0
        bc = JS_UNDEFINED;
42328
0
        if (JS_IsUndefined(pattern1))
42329
0
            pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
42330
0
        else
42331
0
            pattern = JS_ToString(ctx, pattern1);
42332
0
        if (JS_IsException(pattern))
42333
0
            goto fail;
42334
0
        bc = js_compile_regexp(ctx, pattern, flags1);
42335
0
        if (JS_IsException(bc))
42336
0
            goto fail;
42337
0
    }
42338
0
    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
42339
0
    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
42340
0
    re->pattern = JS_VALUE_GET_STRING(pattern);
42341
0
    re->bytecode = JS_VALUE_GET_STRING(bc);
42342
0
    if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
42343
0
                       JS_NewInt32(ctx, 0)) < 0)
42344
0
        return JS_EXCEPTION;
42345
0
    return JS_DupValue(ctx, this_val);
42346
0
 fail:
42347
0
    JS_FreeValue(ctx, pattern);
42348
0
    JS_FreeValue(ctx, bc);
42349
0
    return JS_EXCEPTION;
42350
0
}
42351
42352
#if 0
42353
static JSValue js_regexp_get___source(JSContext *ctx, JSValueConst this_val)
42354
{
42355
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
42356
    if (!re)
42357
        return JS_EXCEPTION;
42358
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
42359
}
42360
42361
static JSValue js_regexp_get___flags(JSContext *ctx, JSValueConst this_val)
42362
{
42363
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
42364
    int flags;
42365
42366
    if (!re)
42367
        return JS_EXCEPTION;
42368
    flags = lre_get_flags(re->bytecode->u.str8);
42369
    return JS_NewInt32(ctx, flags);
42370
}
42371
#endif
42372
42373
static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val)
42374
0
{
42375
0
    JSRegExp *re;
42376
0
    JSString *p;
42377
0
    StringBuffer b_s, *b = &b_s;
42378
0
    int i, n, c, c2, bra;
42379
42380
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
42381
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
42382
42383
0
    if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
42384
0
        goto empty_regex;
42385
42386
0
    re = js_get_regexp(ctx, this_val, TRUE);
42387
0
    if (!re)
42388
0
        return JS_EXCEPTION;
42389
42390
0
    p = re->pattern;
42391
42392
0
    if (p->len == 0) {
42393
0
    empty_regex:
42394
0
        return JS_NewString(ctx, "(?:)");
42395
0
    }    
42396
0
    string_buffer_init2(ctx, b, p->len, p->is_wide_char);
42397
42398
    /* Escape '/' and newline sequences as needed */
42399
0
    bra = 0;
42400
0
    for (i = 0, n = p->len; i < n;) {
42401
0
        c2 = -1;
42402
0
        switch (c = string_get(p, i++)) {
42403
0
        case '\\':
42404
0
            if (i < n)
42405
0
                c2 = string_get(p, i++);
42406
0
            break;
42407
0
        case ']':
42408
0
            bra = 0;
42409
0
            break;
42410
0
        case '[':
42411
0
            if (!bra) {
42412
0
                if (i < n && string_get(p, i) == ']')
42413
0
                    c2 = string_get(p, i++);
42414
0
                bra = 1;
42415
0
            }
42416
0
            break;
42417
0
        case '\n':
42418
0
            c = '\\';
42419
0
            c2 = 'n';
42420
0
            break;
42421
0
        case '\r':
42422
0
            c = '\\';
42423
0
            c2 = 'r';
42424
0
            break;
42425
0
        case '/':
42426
0
            if (!bra) {
42427
0
                c = '\\';
42428
0
                c2 = '/';
42429
0
            }
42430
0
            break;
42431
0
        }
42432
0
        string_buffer_putc16(b, c);
42433
0
        if (c2 >= 0)
42434
0
            string_buffer_putc16(b, c2);
42435
0
    }
42436
0
    return string_buffer_end(b);
42437
0
}
42438
42439
static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mask)
42440
0
{
42441
0
    JSRegExp *re;
42442
0
    int flags;
42443
42444
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
42445
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
42446
42447
0
    re = js_get_regexp(ctx, this_val, FALSE);
42448
0
    if (!re) {
42449
0
        if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
42450
0
            return JS_UNDEFINED;
42451
0
        else
42452
0
            return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
42453
0
    }
42454
    
42455
0
    flags = lre_get_flags(re->bytecode->u.str8);
42456
0
    return JS_NewBool(ctx, (flags & mask) != 0);
42457
0
}
42458
42459
static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val)
42460
0
{
42461
0
    char str[8], *p = str;
42462
0
    int res;
42463
42464
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
42465
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
42466
42467
0
    res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_global));
42468
0
    if (res < 0)
42469
0
        goto exception;
42470
0
    if (res)
42471
0
        *p++ = 'g';
42472
0
    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "ignoreCase"));
42473
0
    if (res < 0)
42474
0
        goto exception;
42475
0
    if (res)
42476
0
        *p++ = 'i';
42477
0
    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "multiline"));
42478
0
    if (res < 0)
42479
0
        goto exception;
42480
0
    if (res)
42481
0
        *p++ = 'm';
42482
0
    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "dotAll"));
42483
0
    if (res < 0)
42484
0
        goto exception;
42485
0
    if (res)
42486
0
        *p++ = 's';
42487
0
    res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_unicode));
42488
0
    if (res < 0)
42489
0
        goto exception;
42490
0
    if (res)
42491
0
        *p++ = 'u';
42492
0
    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "sticky"));
42493
0
    if (res < 0)
42494
0
        goto exception;
42495
0
    if (res)
42496
0
        *p++ = 'y';
42497
0
    return JS_NewStringLen(ctx, str, p - str);
42498
42499
0
exception:
42500
0
    return JS_EXCEPTION;
42501
0
}
42502
42503
static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,
42504
                                  int argc, JSValueConst *argv)
42505
0
{
42506
0
    JSValue pattern, flags;
42507
0
    StringBuffer b_s, *b = &b_s;
42508
42509
0
    if (!JS_IsObject(this_val))
42510
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
42511
42512
0
    string_buffer_init(ctx, b, 0);
42513
0
    string_buffer_putc8(b, '/');
42514
0
    pattern = JS_GetProperty(ctx, this_val, JS_ATOM_source);
42515
0
    if (string_buffer_concat_value_free(b, pattern))
42516
0
        goto fail;
42517
0
    string_buffer_putc8(b, '/');
42518
0
    flags = JS_GetProperty(ctx, this_val, JS_ATOM_flags);
42519
0
    if (string_buffer_concat_value_free(b, flags))
42520
0
        goto fail;
42521
0
    return string_buffer_end(b);
42522
42523
0
fail:
42524
0
    string_buffer_free(b);
42525
0
    return JS_EXCEPTION;
42526
0
}
42527
42528
BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size)
42529
43.2k
{
42530
43.2k
    JSContext *ctx = opaque;
42531
43.2k
    return js_check_stack_overflow(ctx->rt, alloca_size);
42532
43.2k
}
42533
42534
void *lre_realloc(void *opaque, void *ptr, size_t size)
42535
154k
{
42536
154k
    JSContext *ctx = opaque;
42537
    /* No JS exception is raised here */
42538
154k
    return js_realloc_rt(ctx->rt, ptr, size);
42539
154k
}
42540
42541
static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
42542
                              int argc, JSValueConst *argv)
42543
0
{
42544
0
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
42545
0
    JSString *str;
42546
0
    JSValue str_val, obj, val, groups = JS_UNDEFINED;
42547
0
    uint8_t *re_bytecode;
42548
0
    int ret;
42549
0
    uint8_t **capture, *str_buf;
42550
0
    int capture_count, shift, i, re_flags;
42551
0
    int64_t last_index;
42552
0
    const char *group_name_ptr;
42553
42554
0
    if (!re)
42555
0
        return JS_EXCEPTION;
42556
0
    str_val = JS_ToString(ctx, argv[0]);
42557
0
    if (JS_IsException(str_val))
42558
0
        return str_val;
42559
0
    val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
42560
0
    if (JS_IsException(val) ||
42561
0
        JS_ToLengthFree(ctx, &last_index, val)) {
42562
0
        JS_FreeValue(ctx, str_val);
42563
0
        return JS_EXCEPTION;
42564
0
    }
42565
0
    re_bytecode = re->bytecode->u.str8;
42566
0
    re_flags = lre_get_flags(re_bytecode);
42567
0
    if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
42568
0
        last_index = 0;
42569
0
    }
42570
0
    str = JS_VALUE_GET_STRING(str_val);
42571
0
    capture_count = lre_get_capture_count(re_bytecode);
42572
0
    capture = NULL;
42573
0
    if (capture_count > 0) {
42574
0
        capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
42575
0
        if (!capture) {
42576
0
            JS_FreeValue(ctx, str_val);
42577
0
            return JS_EXCEPTION;
42578
0
        }
42579
0
    }
42580
0
    shift = str->is_wide_char;
42581
0
    str_buf = str->u.str8;
42582
0
    if (last_index > str->len) {
42583
0
        ret = 2;
42584
0
    } else {
42585
0
        ret = lre_exec(capture, re_bytecode,
42586
0
                       str_buf, last_index, str->len,
42587
0
                       shift, ctx);
42588
0
    }
42589
0
    obj = JS_NULL;
42590
0
    if (ret != 1) {
42591
0
        if (ret >= 0) {
42592
0
            if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
42593
0
                if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
42594
0
                                   JS_NewInt32(ctx, 0)) < 0)
42595
0
                    goto fail;
42596
0
            }
42597
0
        } else {
42598
0
            JS_ThrowInternalError(ctx, "out of memory in regexp execution");
42599
0
            goto fail;
42600
0
        }
42601
0
        JS_FreeValue(ctx, str_val);
42602
0
    } else {
42603
0
        int prop_flags;
42604
0
        if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
42605
0
            if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
42606
0
                               JS_NewInt32(ctx, (capture[1] - str_buf) >> shift)) < 0)
42607
0
                goto fail;
42608
0
        }
42609
0
        obj = JS_NewArray(ctx);
42610
0
        if (JS_IsException(obj))
42611
0
            goto fail;
42612
0
        prop_flags = JS_PROP_C_W_E | JS_PROP_THROW;
42613
0
        group_name_ptr = lre_get_groupnames(re_bytecode);
42614
0
        if (group_name_ptr) {
42615
0
            groups = JS_NewObjectProto(ctx, JS_NULL);
42616
0
            if (JS_IsException(groups))
42617
0
                goto fail;
42618
0
        }
42619
42620
0
        for(i = 0; i < capture_count; i++) {
42621
0
            int start, end;
42622
0
            JSValue val;
42623
0
            if (capture[2 * i] == NULL ||
42624
0
                capture[2 * i + 1] == NULL) {
42625
0
                val = JS_UNDEFINED;
42626
0
            } else {
42627
0
                start = (capture[2 * i] - str_buf) >> shift;
42628
0
                end = (capture[2 * i + 1] - str_buf) >> shift;
42629
0
                val = js_sub_string(ctx, str, start, end);
42630
0
                if (JS_IsException(val))
42631
0
                    goto fail;
42632
0
            }
42633
0
            if (group_name_ptr && i > 0) {
42634
0
                if (*group_name_ptr) {
42635
0
                    if (JS_DefinePropertyValueStr(ctx, groups, group_name_ptr,
42636
0
                                                  JS_DupValue(ctx, val),
42637
0
                                                  prop_flags) < 0) {
42638
0
                        JS_FreeValue(ctx, val);
42639
0
                        goto fail;
42640
0
                    }
42641
0
                }
42642
0
                group_name_ptr += strlen(group_name_ptr) + 1;
42643
0
            }
42644
0
            if (JS_DefinePropertyValueUint32(ctx, obj, i, val, prop_flags) < 0)
42645
0
                goto fail;
42646
0
        }
42647
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_groups,
42648
0
                                   groups, prop_flags) < 0)
42649
0
            goto fail;
42650
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index,
42651
0
                                   JS_NewInt32(ctx, (capture[0] - str_buf) >> shift), prop_flags) < 0)
42652
0
            goto fail;
42653
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, str_val, prop_flags) < 0)
42654
0
            goto fail1;
42655
0
    }
42656
0
    js_free(ctx, capture);
42657
0
    return obj;
42658
0
fail:
42659
0
    JS_FreeValue(ctx, groups);
42660
0
    JS_FreeValue(ctx, str_val);
42661
0
fail1:
42662
0
    JS_FreeValue(ctx, obj);
42663
0
    js_free(ctx, capture);
42664
0
    return JS_EXCEPTION;
42665
0
}
42666
42667
/* delete portions of a string that match a given regex */
42668
static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueConst arg)
42669
0
{
42670
0
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
42671
0
    JSString *str;
42672
0
    JSValue str_val, val;
42673
0
    uint8_t *re_bytecode;
42674
0
    int ret;
42675
0
    uint8_t **capture, *str_buf;
42676
0
    int capture_count, shift, re_flags;
42677
0
    int next_src_pos, start, end;
42678
0
    int64_t last_index;
42679
0
    StringBuffer b_s, *b = &b_s;
42680
42681
0
    if (!re)
42682
0
        return JS_EXCEPTION;
42683
42684
0
    string_buffer_init(ctx, b, 0);
42685
42686
0
    capture = NULL;
42687
0
    str_val = JS_ToString(ctx, arg);
42688
0
    if (JS_IsException(str_val))
42689
0
        goto fail;
42690
0
    str = JS_VALUE_GET_STRING(str_val);
42691
0
    re_bytecode = re->bytecode->u.str8;
42692
0
    re_flags = lre_get_flags(re_bytecode);
42693
0
    if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
42694
0
        last_index = 0;
42695
0
    } else {
42696
0
        val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
42697
0
        if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val))
42698
0
            goto fail;
42699
0
    }
42700
0
    capture_count = lre_get_capture_count(re_bytecode);
42701
0
    if (capture_count > 0) {
42702
0
        capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
42703
0
        if (!capture)
42704
0
            goto fail;
42705
0
    }
42706
0
    shift = str->is_wide_char;
42707
0
    str_buf = str->u.str8;
42708
0
    next_src_pos = 0;
42709
0
    for (;;) {
42710
0
        if (last_index > str->len)
42711
0
            break;
42712
42713
0
        ret = lre_exec(capture, re_bytecode,
42714
0
                       str_buf, last_index, str->len, shift, ctx);
42715
0
        if (ret != 1) {
42716
0
            if (ret >= 0) {
42717
0
                if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
42718
0
                    if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
42719
0
                                       JS_NewInt32(ctx, 0)) < 0)
42720
0
                        goto fail;
42721
0
                }
42722
0
            } else {
42723
0
                JS_ThrowInternalError(ctx, "out of memory in regexp execution");
42724
0
                goto fail;
42725
0
            }
42726
0
            break;
42727
0
        }
42728
0
        start = (capture[0] - str_buf) >> shift;
42729
0
        end = (capture[1] - str_buf) >> shift;
42730
0
        last_index = end;
42731
0
        if (next_src_pos < start) {
42732
0
            if (string_buffer_concat(b, str, next_src_pos, start))
42733
0
                goto fail;
42734
0
        }
42735
0
        next_src_pos = end;
42736
0
        if (!(re_flags & LRE_FLAG_GLOBAL)) {
42737
0
            if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
42738
0
                               JS_NewInt32(ctx, end)) < 0)
42739
0
                goto fail;
42740
0
            break;
42741
0
        }
42742
0
        if (end == start) {
42743
0
            if (!(re_flags & LRE_FLAG_UTF16) || (unsigned)end >= str->len || !str->is_wide_char) {
42744
0
                end++;
42745
0
            } else {
42746
0
                string_getc(str, &end);
42747
0
            }
42748
0
        }
42749
0
        last_index = end;
42750
0
    }
42751
0
    if (string_buffer_concat(b, str, next_src_pos, str->len))
42752
0
        goto fail;
42753
0
    JS_FreeValue(ctx, str_val);
42754
0
    js_free(ctx, capture);
42755
0
    return string_buffer_end(b);
42756
0
fail:
42757
0
    JS_FreeValue(ctx, str_val);
42758
0
    js_free(ctx, capture);
42759
0
    string_buffer_free(b);
42760
0
    return JS_EXCEPTION;
42761
0
}
42762
42763
static JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s)
42764
0
{
42765
0
    JSValue method, ret;
42766
42767
0
    method = JS_GetProperty(ctx, r, JS_ATOM_exec);
42768
0
    if (JS_IsException(method))
42769
0
        return method;
42770
0
    if (JS_IsFunction(ctx, method)) {
42771
0
        ret = JS_CallFree(ctx, method, r, 1, &s);
42772
0
        if (JS_IsException(ret))
42773
0
            return ret;
42774
0
        if (!JS_IsObject(ret) && !JS_IsNull(ret)) {
42775
0
            JS_FreeValue(ctx, ret);
42776
0
            return JS_ThrowTypeError(ctx, "RegExp exec method must return an object or null");
42777
0
        }
42778
0
        return ret;
42779
0
    }
42780
0
    JS_FreeValue(ctx, method);
42781
0
    return js_regexp_exec(ctx, r, 1, &s);
42782
0
}
42783
42784
#if 0
42785
static JSValue js_regexp___RegExpExec(JSContext *ctx, JSValueConst this_val,
42786
                                      int argc, JSValueConst *argv)
42787
{
42788
    return JS_RegExpExec(ctx, argv[0], argv[1]);
42789
}
42790
static JSValue js_regexp___RegExpDelete(JSContext *ctx, JSValueConst this_val,
42791
                                        int argc, JSValueConst *argv)
42792
{
42793
    return JS_RegExpDelete(ctx, argv[0], argv[1]);
42794
}
42795
#endif
42796
42797
static JSValue js_regexp_test(JSContext *ctx, JSValueConst this_val,
42798
                              int argc, JSValueConst *argv)
42799
0
{
42800
0
    JSValue val;
42801
0
    BOOL ret;
42802
42803
0
    val = JS_RegExpExec(ctx, this_val, argv[0]);
42804
0
    if (JS_IsException(val))
42805
0
        return JS_EXCEPTION;
42806
0
    ret = !JS_IsNull(val);
42807
0
    JS_FreeValue(ctx, val);
42808
0
    return JS_NewBool(ctx, ret);
42809
0
}
42810
42811
static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
42812
                                      int argc, JSValueConst *argv)
42813
0
{
42814
    // [Symbol.match](str)
42815
0
    JSValueConst rx = this_val;
42816
0
    JSValue A, S, result, matchStr;
42817
0
    int global, n, fullUnicode, isEmpty;
42818
0
    JSString *p;
42819
42820
0
    if (!JS_IsObject(rx))
42821
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
42822
42823
0
    A = JS_UNDEFINED;
42824
0
    result = JS_UNDEFINED;
42825
0
    matchStr = JS_UNDEFINED;
42826
0
    S = JS_ToString(ctx, argv[0]);
42827
0
    if (JS_IsException(S))
42828
0
        goto exception;
42829
42830
0
    global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global));
42831
0
    if (global < 0)
42832
0
        goto exception;
42833
42834
0
    if (!global) {
42835
0
        A = JS_RegExpExec(ctx, rx, S);
42836
0
    } else {
42837
0
        fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
42838
0
        if (fullUnicode < 0)
42839
0
            goto exception;
42840
42841
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
42842
0
            goto exception;
42843
0
        A = JS_NewArray(ctx);
42844
0
        if (JS_IsException(A))
42845
0
            goto exception;
42846
0
        n = 0;
42847
0
        for(;;) {
42848
0
            JS_FreeValue(ctx, result);
42849
0
            result = JS_RegExpExec(ctx, rx, S);
42850
0
            if (JS_IsException(result))
42851
0
                goto exception;
42852
0
            if (JS_IsNull(result))
42853
0
                break;
42854
0
            matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
42855
0
            if (JS_IsException(matchStr))
42856
0
                goto exception;
42857
0
            isEmpty = JS_IsEmptyString(matchStr);
42858
0
            if (JS_SetPropertyInt64(ctx, A, n++, matchStr) < 0)
42859
0
                goto exception;
42860
0
            if (isEmpty) {
42861
0
                int64_t thisIndex, nextIndex;
42862
0
                if (JS_ToLengthFree(ctx, &thisIndex,
42863
0
                                    JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
42864
0
                    goto exception;
42865
0
                p = JS_VALUE_GET_STRING(S);
42866
0
                nextIndex = string_advance_index(p, thisIndex, fullUnicode);
42867
0
                if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
42868
0
                    goto exception;
42869
0
            }
42870
0
        }
42871
0
        if (n == 0) {
42872
0
            JS_FreeValue(ctx, A);
42873
0
            A = JS_NULL;
42874
0
        }
42875
0
    }
42876
0
    JS_FreeValue(ctx, result);
42877
0
    JS_FreeValue(ctx, S);
42878
0
    return A;
42879
42880
0
exception:
42881
0
    JS_FreeValue(ctx, A);
42882
0
    JS_FreeValue(ctx, result);
42883
0
    JS_FreeValue(ctx, S);
42884
0
    return JS_EXCEPTION;
42885
0
}
42886
42887
typedef struct JSRegExpStringIteratorData {
42888
    JSValue iterating_regexp;
42889
    JSValue iterated_string;
42890
    BOOL global;
42891
    BOOL unicode;
42892
    BOOL done;
42893
} JSRegExpStringIteratorData;
42894
42895
static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val)
42896
0
{
42897
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
42898
0
    JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
42899
0
    if (it) {
42900
0
        JS_FreeValueRT(rt, it->iterating_regexp);
42901
0
        JS_FreeValueRT(rt, it->iterated_string);
42902
0
        js_free_rt(rt, it);
42903
0
    }
42904
0
}
42905
42906
static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
42907
                                           JS_MarkFunc *mark_func)
42908
0
{
42909
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
42910
0
    JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
42911
0
    if (it) {
42912
0
        JS_MarkValue(rt, it->iterating_regexp, mark_func);
42913
0
        JS_MarkValue(rt, it->iterated_string, mark_func);
42914
0
    }
42915
0
}
42916
42917
static JSValue js_regexp_string_iterator_next(JSContext *ctx,
42918
                                              JSValueConst this_val,
42919
                                              int argc, JSValueConst *argv,
42920
                                              BOOL *pdone, int magic)
42921
0
{
42922
0
    JSRegExpStringIteratorData *it;
42923
0
    JSValueConst R, S;
42924
0
    JSValue matchStr = JS_UNDEFINED, match = JS_UNDEFINED;
42925
0
    JSString *sp;
42926
42927
0
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_REGEXP_STRING_ITERATOR);
42928
0
    if (!it)
42929
0
        goto exception;
42930
0
    if (it->done) {
42931
0
        *pdone = TRUE;
42932
0
        return JS_UNDEFINED;
42933
0
    }
42934
0
    R = it->iterating_regexp;
42935
0
    S = it->iterated_string;
42936
0
    match = JS_RegExpExec(ctx, R, S);
42937
0
    if (JS_IsException(match))
42938
0
        goto exception;
42939
0
    if (JS_IsNull(match)) {
42940
0
        it->done = TRUE;
42941
0
        *pdone = TRUE;
42942
0
        return JS_UNDEFINED;
42943
0
    } else if (it->global) {
42944
0
        matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, match, 0));
42945
0
        if (JS_IsException(matchStr))
42946
0
            goto exception;
42947
0
        if (JS_IsEmptyString(matchStr)) {
42948
0
            int64_t thisIndex, nextIndex;
42949
0
            if (JS_ToLengthFree(ctx, &thisIndex,
42950
0
                                JS_GetProperty(ctx, R, JS_ATOM_lastIndex)) < 0)
42951
0
                goto exception;
42952
0
            sp = JS_VALUE_GET_STRING(S);
42953
0
            nextIndex = string_advance_index(sp, thisIndex, it->unicode);
42954
0
            if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex,
42955
0
                               JS_NewInt64(ctx, nextIndex)) < 0)
42956
0
                goto exception;
42957
0
        }
42958
0
        JS_FreeValue(ctx, matchStr);
42959
0
    } else {
42960
0
        it->done = TRUE;
42961
0
    }
42962
0
    *pdone = FALSE;
42963
0
    return match;
42964
0
 exception:
42965
0
    JS_FreeValue(ctx, match);
42966
0
    JS_FreeValue(ctx, matchStr);
42967
0
    *pdone = FALSE;
42968
0
    return JS_EXCEPTION;
42969
0
}
42970
42971
static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,
42972
                                         int argc, JSValueConst *argv)
42973
0
{
42974
    // [Symbol.matchAll](str)
42975
0
    JSValueConst R = this_val;
42976
0
    JSValue S, C, flags, matcher, iter;
42977
0
    JSValueConst args[2];
42978
0
    JSString *strp;
42979
0
    int64_t lastIndex;
42980
0
    JSRegExpStringIteratorData *it;
42981
    
42982
0
    if (!JS_IsObject(R))
42983
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
42984
42985
0
    C = JS_UNDEFINED;
42986
0
    flags = JS_UNDEFINED;
42987
0
    matcher = JS_UNDEFINED;
42988
0
    iter = JS_UNDEFINED;
42989
    
42990
0
    S = JS_ToString(ctx, argv[0]);
42991
0
    if (JS_IsException(S))
42992
0
        goto exception;
42993
0
    C = JS_SpeciesConstructor(ctx, R, ctx->regexp_ctor);
42994
0
    if (JS_IsException(C))
42995
0
        goto exception;
42996
0
    flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, R, JS_ATOM_flags));
42997
0
    if (JS_IsException(flags))
42998
0
        goto exception;
42999
0
    args[0] = R;
43000
0
    args[1] = flags;
43001
0
    matcher = JS_CallConstructor(ctx, C, 2, args);
43002
0
    if (JS_IsException(matcher))
43003
0
        goto exception;
43004
0
    if (JS_ToLengthFree(ctx, &lastIndex,
43005
0
                        JS_GetProperty(ctx, R, JS_ATOM_lastIndex)))
43006
0
        goto exception;
43007
0
    if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex,
43008
0
                       JS_NewInt64(ctx, lastIndex)) < 0)
43009
0
        goto exception;
43010
    
43011
0
    iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR);
43012
0
    if (JS_IsException(iter))
43013
0
        goto exception;
43014
0
    it = js_malloc(ctx, sizeof(*it));
43015
0
    if (!it)
43016
0
        goto exception;
43017
0
    it->iterating_regexp = matcher;
43018
0
    it->iterated_string = S;
43019
0
    strp = JS_VALUE_GET_STRING(flags);
43020
0
    it->global = string_indexof_char(strp, 'g', 0) >= 0;
43021
0
    it->unicode = string_indexof_char(strp, 'u', 0) >= 0;
43022
0
    it->done = FALSE;
43023
0
    JS_SetOpaque(iter, it);
43024
43025
0
    JS_FreeValue(ctx, C);
43026
0
    JS_FreeValue(ctx, flags);
43027
0
    return iter;
43028
0
 exception:
43029
0
    JS_FreeValue(ctx, S);
43030
0
    JS_FreeValue(ctx, C);
43031
0
    JS_FreeValue(ctx, flags);
43032
0
    JS_FreeValue(ctx, matcher);
43033
0
    JS_FreeValue(ctx, iter);
43034
0
    return JS_EXCEPTION;
43035
0
}
43036
43037
typedef struct ValueBuffer {
43038
    JSContext *ctx;
43039
    JSValue *arr;
43040
    JSValue def[4];
43041
    int len;
43042
    int size;
43043
    int error_status;
43044
} ValueBuffer;
43045
43046
static int value_buffer_init(JSContext *ctx, ValueBuffer *b)
43047
0
{
43048
0
    b->ctx = ctx;
43049
0
    b->len = 0;
43050
0
    b->size = 4;
43051
0
    b->error_status = 0;
43052
0
    b->arr = b->def;
43053
0
    return 0;
43054
0
}
43055
43056
static void value_buffer_free(ValueBuffer *b)
43057
0
{
43058
0
    while (b->len > 0)
43059
0
        JS_FreeValue(b->ctx, b->arr[--b->len]);
43060
0
    if (b->arr != b->def)
43061
0
        js_free(b->ctx, b->arr);
43062
0
    b->arr = b->def;
43063
0
    b->size = 4;
43064
0
}
43065
43066
static int value_buffer_append(ValueBuffer *b, JSValue val)
43067
0
{
43068
0
    if (b->error_status)
43069
0
        return -1;
43070
43071
0
    if (b->len >= b->size) {
43072
0
        int new_size = (b->len + (b->len >> 1) + 31) & ~16;
43073
0
        size_t slack;
43074
0
        JSValue *new_arr;
43075
43076
0
        if (b->arr == b->def) {
43077
0
            new_arr = js_realloc2(b->ctx, NULL, sizeof(*b->arr) * new_size, &slack);
43078
0
            if (new_arr)
43079
0
                memcpy(new_arr, b->def, sizeof b->def);
43080
0
        } else {
43081
0
            new_arr = js_realloc2(b->ctx, b->arr, sizeof(*b->arr) * new_size, &slack);
43082
0
        }
43083
0
        if (!new_arr) {
43084
0
            value_buffer_free(b);
43085
0
            JS_FreeValue(b->ctx, val);
43086
0
            b->error_status = -1;
43087
0
            return -1;
43088
0
        }
43089
0
        new_size += slack / sizeof(*new_arr);
43090
0
        b->arr = new_arr;
43091
0
        b->size = new_size;
43092
0
    }
43093
0
    b->arr[b->len++] = val;
43094
0
    return 0;
43095
0
}
43096
43097
static int js_is_standard_regexp(JSContext *ctx, JSValueConst rx)
43098
0
{
43099
0
    JSValue val;
43100
0
    int res;
43101
43102
0
    val = JS_GetProperty(ctx, rx, JS_ATOM_constructor);
43103
0
    if (JS_IsException(val))
43104
0
        return -1;
43105
    // rx.constructor === RegExp
43106
0
    res = js_same_value(ctx, val, ctx->regexp_ctor);
43107
0
    JS_FreeValue(ctx, val);
43108
0
    if (res) {
43109
0
        val = JS_GetProperty(ctx, rx, JS_ATOM_exec);
43110
0
        if (JS_IsException(val))
43111
0
            return -1;
43112
        // rx.exec === RE_exec
43113
0
        res = JS_IsCFunction(ctx, val, js_regexp_exec, 0);
43114
0
        JS_FreeValue(ctx, val);
43115
0
    }
43116
0
    return res;
43117
0
}
43118
43119
static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
43120
                                        int argc, JSValueConst *argv)
43121
0
{
43122
    // [Symbol.replace](str, rep)
43123
0
    JSValueConst rx = this_val, rep = argv[1];
43124
0
    JSValueConst args[6];
43125
0
    JSValue str, rep_val, matched, tab, rep_str, namedCaptures, res;
43126
0
    JSString *sp, *rp;
43127
0
    StringBuffer b_s, *b = &b_s;
43128
0
    ValueBuffer v_b, *results = &v_b;
43129
0
    int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode;
43130
0
    uint32_t nCaptures;
43131
0
    int64_t position;
43132
43133
0
    if (!JS_IsObject(rx))
43134
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
43135
43136
0
    string_buffer_init(ctx, b, 0);
43137
0
    value_buffer_init(ctx, results);
43138
43139
0
    rep_val = JS_UNDEFINED;
43140
0
    matched = JS_UNDEFINED;
43141
0
    tab = JS_UNDEFINED;
43142
0
    rep_str = JS_UNDEFINED;
43143
0
    namedCaptures = JS_UNDEFINED;
43144
43145
0
    str = JS_ToString(ctx, argv[0]);
43146
0
    if (JS_IsException(str))
43147
0
        goto exception;
43148
        
43149
0
    sp = JS_VALUE_GET_STRING(str);
43150
0
    rp = NULL;
43151
0
    functionalReplace = JS_IsFunction(ctx, rep);
43152
0
    if (!functionalReplace) {
43153
0
        rep_val = JS_ToString(ctx, rep);
43154
0
        if (JS_IsException(rep_val))
43155
0
            goto exception;
43156
0
        rp = JS_VALUE_GET_STRING(rep_val);
43157
0
    }
43158
0
    fullUnicode = 0;
43159
0
    is_global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global));
43160
0
    if (is_global < 0)
43161
0
        goto exception;
43162
0
    if (is_global) {
43163
0
        fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
43164
0
        if (fullUnicode < 0)
43165
0
            goto exception;
43166
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
43167
0
            goto exception;
43168
0
    }
43169
43170
0
    if (rp && rp->len == 0 && is_global && js_is_standard_regexp(ctx, rx)) {
43171
        /* use faster version for simple cases */
43172
0
        res = JS_RegExpDelete(ctx, rx, str);
43173
0
        goto done;
43174
0
    }
43175
0
    for(;;) {
43176
0
        JSValue result;
43177
0
        result = JS_RegExpExec(ctx, rx, str);
43178
0
        if (JS_IsException(result))
43179
0
            goto exception;
43180
0
        if (JS_IsNull(result))
43181
0
            break;
43182
0
        if (value_buffer_append(results, result) < 0)
43183
0
            goto exception;
43184
0
        if (!is_global)
43185
0
            break;
43186
0
        JS_FreeValue(ctx, matched);
43187
0
        matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
43188
0
        if (JS_IsException(matched))
43189
0
            goto exception;
43190
0
        if (JS_IsEmptyString(matched)) {
43191
            /* always advance of at least one char */
43192
0
            int64_t thisIndex, nextIndex;
43193
0
            if (JS_ToLengthFree(ctx, &thisIndex, JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
43194
0
                goto exception;
43195
0
            nextIndex = string_advance_index(sp, thisIndex, fullUnicode);
43196
0
            if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
43197
0
                goto exception;
43198
0
        }
43199
0
    }
43200
0
    nextSourcePosition = 0;
43201
0
    for(j = 0; j < results->len; j++) {
43202
0
        JSValueConst result;
43203
0
        result = results->arr[j];
43204
0
        if (js_get_length32(ctx, &nCaptures, result) < 0)
43205
0
            goto exception;
43206
0
        JS_FreeValue(ctx, matched);
43207
0
        matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
43208
0
        if (JS_IsException(matched))
43209
0
            goto exception;
43210
0
        if (JS_ToLengthFree(ctx, &position, JS_GetProperty(ctx, result, JS_ATOM_index)))
43211
0
            goto exception;
43212
0
        if (position > sp->len)
43213
0
            position = sp->len;
43214
0
        else if (position < 0)
43215
0
            position = 0;
43216
        /* ignore substition if going backward (can happen
43217
           with custom regexp object) */
43218
0
        JS_FreeValue(ctx, tab);
43219
0
        tab = JS_NewArray(ctx);
43220
0
        if (JS_IsException(tab))
43221
0
            goto exception;
43222
0
        if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched),
43223
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43224
0
            goto exception;
43225
0
        for(n = 1; n < nCaptures; n++) {
43226
0
            JSValue capN;
43227
0
            capN = JS_GetPropertyInt64(ctx, result, n);
43228
0
            if (JS_IsException(capN))
43229
0
                goto exception;
43230
0
            if (!JS_IsUndefined(capN)) {
43231
0
                capN = JS_ToStringFree(ctx, capN);
43232
0
                if (JS_IsException(capN))
43233
0
                    goto exception;
43234
0
            }
43235
0
            if (JS_DefinePropertyValueInt64(ctx, tab, n, capN,
43236
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43237
0
                goto exception;
43238
0
        }
43239
0
        JS_FreeValue(ctx, namedCaptures);
43240
0
        namedCaptures = JS_GetProperty(ctx, result, JS_ATOM_groups);
43241
0
        if (JS_IsException(namedCaptures))
43242
0
            goto exception;
43243
0
        if (functionalReplace) {
43244
0
            if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43245
0
                goto exception;
43246
0
            if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43247
0
                goto exception;
43248
0
            if (!JS_IsUndefined(namedCaptures)) {
43249
0
                if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43250
0
                    goto exception;
43251
0
            }
43252
0
            args[0] = JS_UNDEFINED;
43253
0
            args[1] = tab;
43254
0
            JS_FreeValue(ctx, rep_str);
43255
0
            rep_str = JS_ToStringFree(ctx, js_function_apply(ctx, rep, 2, args, 0));
43256
0
        } else {
43257
0
            JSValue namedCaptures1;
43258
0
            if (!JS_IsUndefined(namedCaptures)) {
43259
0
                namedCaptures1 = JS_ToObject(ctx, namedCaptures);
43260
0
                if (JS_IsException(namedCaptures1))
43261
0
                    goto exception;
43262
0
            } else {
43263
0
                namedCaptures1 = JS_UNDEFINED;
43264
0
            }
43265
0
            args[0] = matched;
43266
0
            args[1] = str;
43267
0
            args[2] = JS_NewInt32(ctx, position);
43268
0
            args[3] = tab;
43269
0
            args[4] = namedCaptures1;
43270
0
            args[5] = rep_val;
43271
0
            JS_FreeValue(ctx, rep_str);
43272
0
            rep_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
43273
0
            JS_FreeValue(ctx, namedCaptures1);
43274
0
        }
43275
0
        if (JS_IsException(rep_str))
43276
0
            goto exception;
43277
0
        if (position >= nextSourcePosition) {
43278
0
            string_buffer_concat(b, sp, nextSourcePosition, position);
43279
0
            string_buffer_concat_value(b, rep_str);
43280
0
            nextSourcePosition = position + JS_VALUE_GET_STRING(matched)->len;
43281
0
        }
43282
0
    }
43283
0
    string_buffer_concat(b, sp, nextSourcePosition, sp->len);
43284
0
    res = string_buffer_end(b);
43285
0
    goto done1;
43286
43287
0
exception:
43288
0
    res = JS_EXCEPTION;
43289
0
done:
43290
0
    string_buffer_free(b);
43291
0
done1:
43292
0
    value_buffer_free(results);
43293
0
    JS_FreeValue(ctx, rep_val);
43294
0
    JS_FreeValue(ctx, matched);
43295
0
    JS_FreeValue(ctx, tab);
43296
0
    JS_FreeValue(ctx, rep_str);
43297
0
    JS_FreeValue(ctx, namedCaptures);
43298
0
    JS_FreeValue(ctx, str);
43299
0
    return res;
43300
0
}
43301
43302
static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val,
43303
                                       int argc, JSValueConst *argv)
43304
0
{
43305
0
    JSValueConst rx = this_val;
43306
0
    JSValue str, previousLastIndex, currentLastIndex, result, index;
43307
43308
0
    if (!JS_IsObject(rx))
43309
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
43310
43311
0
    result = JS_UNDEFINED;
43312
0
    currentLastIndex = JS_UNDEFINED;
43313
0
    previousLastIndex = JS_UNDEFINED;
43314
0
    str = JS_ToString(ctx, argv[0]);
43315
0
    if (JS_IsException(str))
43316
0
        goto exception;
43317
43318
0
    previousLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
43319
0
    if (JS_IsException(previousLastIndex))
43320
0
        goto exception;
43321
43322
0
    if (!js_same_value(ctx, previousLastIndex, JS_NewInt32(ctx, 0))) {
43323
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) {
43324
0
            goto exception;
43325
0
        }
43326
0
    }
43327
0
    result = JS_RegExpExec(ctx, rx, str);
43328
0
    if (JS_IsException(result))
43329
0
        goto exception;
43330
0
    currentLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
43331
0
    if (JS_IsException(currentLastIndex))
43332
0
        goto exception;
43333
0
    if (js_same_value(ctx, currentLastIndex, previousLastIndex)) {
43334
0
        JS_FreeValue(ctx, previousLastIndex);
43335
0
    } else {
43336
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) {
43337
0
            previousLastIndex = JS_UNDEFINED;
43338
0
            goto exception;
43339
0
        }
43340
0
    }
43341
0
    JS_FreeValue(ctx, str);
43342
0
    JS_FreeValue(ctx, currentLastIndex);
43343
43344
0
    if (JS_IsNull(result)) {
43345
0
        return JS_NewInt32(ctx, -1);
43346
0
    } else {
43347
0
        index = JS_GetProperty(ctx, result, JS_ATOM_index);
43348
0
        JS_FreeValue(ctx, result);
43349
0
        return index;
43350
0
    }
43351
43352
0
exception:
43353
0
    JS_FreeValue(ctx, result);
43354
0
    JS_FreeValue(ctx, str);
43355
0
    JS_FreeValue(ctx, currentLastIndex);
43356
0
    JS_FreeValue(ctx, previousLastIndex);
43357
0
    return JS_EXCEPTION;
43358
0
}
43359
43360
static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
43361
                                       int argc, JSValueConst *argv)
43362
0
{
43363
    // [Symbol.split](str, limit)
43364
0
    JSValueConst rx = this_val;
43365
0
    JSValueConst args[2];
43366
0
    JSValue str, ctor, splitter, A, flags, z, sub;
43367
0
    JSString *strp;
43368
0
    uint32_t lim, size, p, q;
43369
0
    int unicodeMatching;
43370
0
    int64_t lengthA, e, numberOfCaptures, i;
43371
43372
0
    if (!JS_IsObject(rx))
43373
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
43374
43375
0
    ctor = JS_UNDEFINED;
43376
0
    splitter = JS_UNDEFINED;
43377
0
    A = JS_UNDEFINED;
43378
0
    flags = JS_UNDEFINED;
43379
0
    z = JS_UNDEFINED;
43380
0
    str = JS_ToString(ctx, argv[0]);
43381
0
    if (JS_IsException(str))
43382
0
        goto exception;
43383
0
    ctor = JS_SpeciesConstructor(ctx, rx, ctx->regexp_ctor);
43384
0
    if (JS_IsException(ctor))
43385
0
        goto exception;
43386
0
    flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_flags));
43387
0
    if (JS_IsException(flags))
43388
0
        goto exception;
43389
0
    strp = JS_VALUE_GET_STRING(flags);
43390
0
    unicodeMatching = string_indexof_char(strp, 'u', 0) >= 0;
43391
0
    if (string_indexof_char(strp, 'y', 0) < 0) {
43392
0
        flags = JS_ConcatString3(ctx, "", flags, "y");
43393
0
        if (JS_IsException(flags))
43394
0
            goto exception;
43395
0
    }
43396
0
    args[0] = rx;
43397
0
    args[1] = flags;
43398
0
    splitter = JS_CallConstructor(ctx, ctor, 2, args);
43399
0
    if (JS_IsException(splitter))
43400
0
        goto exception;
43401
0
    A = JS_NewArray(ctx);
43402
0
    if (JS_IsException(A))
43403
0
        goto exception;
43404
0
    lengthA = 0;
43405
0
    if (JS_IsUndefined(argv[1])) {
43406
0
        lim = 0xffffffff;
43407
0
    } else {
43408
0
        if (JS_ToUint32(ctx, &lim, argv[1]) < 0)
43409
0
            goto exception;
43410
0
        if (lim == 0)
43411
0
            goto done;
43412
0
    }
43413
0
    strp = JS_VALUE_GET_STRING(str);
43414
0
    p = q = 0;
43415
0
    size = strp->len;
43416
0
    if (size == 0) {
43417
0
        z = JS_RegExpExec(ctx, splitter, str);
43418
0
        if (JS_IsException(z))
43419
0
            goto exception;
43420
0
        if (JS_IsNull(z))
43421
0
            goto add_tail;
43422
0
        goto done;
43423
0
    }
43424
0
    while (q < size) {
43425
0
        if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0)
43426
0
            goto exception;
43427
0
        JS_FreeValue(ctx, z);    
43428
0
        z = JS_RegExpExec(ctx, splitter, str);
43429
0
        if (JS_IsException(z))
43430
0
            goto exception;
43431
0
        if (JS_IsNull(z)) {
43432
0
            q = string_advance_index(strp, q, unicodeMatching);
43433
0
        } else {
43434
0
            if (JS_ToLengthFree(ctx, &e, JS_GetProperty(ctx, splitter, JS_ATOM_lastIndex)))
43435
0
                goto exception;
43436
0
            if (e > size)
43437
0
                e = size;
43438
0
            if (e == p) {
43439
0
                q = string_advance_index(strp, q, unicodeMatching);
43440
0
            } else {
43441
0
                sub = js_sub_string(ctx, strp, p, q);
43442
0
                if (JS_IsException(sub))
43443
0
                    goto exception;
43444
0
                if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub,
43445
0
                                                JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43446
0
                    goto exception;
43447
0
                if (lengthA == lim)
43448
0
                    goto done;
43449
0
                p = e;
43450
0
                if (js_get_length64(ctx, &numberOfCaptures, z))
43451
0
                    goto exception;
43452
0
                for(i = 1; i < numberOfCaptures; i++) {
43453
0
                    sub = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, z, i));
43454
0
                    if (JS_IsException(sub))
43455
0
                        goto exception;
43456
0
                    if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43457
0
                        goto exception;
43458
0
                    if (lengthA == lim)
43459
0
                        goto done;
43460
0
                }
43461
0
                q = p;
43462
0
            }
43463
0
        }
43464
0
    }
43465
0
add_tail:
43466
0
    if (p > size)
43467
0
        p = size;
43468
0
    sub = js_sub_string(ctx, strp, p, size);
43469
0
    if (JS_IsException(sub))
43470
0
        goto exception;
43471
0
    if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
43472
0
        goto exception;
43473
0
    goto done;
43474
0
exception:
43475
0
    JS_FreeValue(ctx, A);
43476
0
    A = JS_EXCEPTION;
43477
0
done:
43478
0
    JS_FreeValue(ctx, str);
43479
0
    JS_FreeValue(ctx, ctor);
43480
0
    JS_FreeValue(ctx, splitter);
43481
0
    JS_FreeValue(ctx, flags);
43482
0
    JS_FreeValue(ctx, z);    
43483
0
    return A;
43484
0
}
43485
43486
static const JSCFunctionListEntry js_regexp_funcs[] = {
43487
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
43488
    //JS_CFUNC_DEF("__RegExpExec", 2, js_regexp___RegExpExec ),
43489
    //JS_CFUNC_DEF("__RegExpDelete", 2, js_regexp___RegExpDelete ),
43490
};
43491
43492
static const JSCFunctionListEntry js_regexp_proto_funcs[] = {
43493
    JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ),
43494
    JS_CGETSET_DEF("source", js_regexp_get_source, NULL ),
43495
    JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, 1 ),
43496
    JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, 2 ),
43497
    JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, 4 ),
43498
    JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, 8 ),
43499
    JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, 16 ),
43500
    JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, 32 ),
43501
    JS_CFUNC_DEF("exec", 1, js_regexp_exec ),
43502
    JS_CFUNC_DEF("compile", 2, js_regexp_compile ),
43503
    JS_CFUNC_DEF("test", 1, js_regexp_test ),
43504
    JS_CFUNC_DEF("toString", 0, js_regexp_toString ),
43505
    JS_CFUNC_DEF("[Symbol.replace]", 2, js_regexp_Symbol_replace ),
43506
    JS_CFUNC_DEF("[Symbol.match]", 1, js_regexp_Symbol_match ),
43507
    JS_CFUNC_DEF("[Symbol.matchAll]", 1, js_regexp_Symbol_matchAll ),
43508
    JS_CFUNC_DEF("[Symbol.search]", 1, js_regexp_Symbol_search ),
43509
    JS_CFUNC_DEF("[Symbol.split]", 2, js_regexp_Symbol_split ),
43510
    //JS_CGETSET_DEF("__source", js_regexp_get___source, NULL ),
43511
    //JS_CGETSET_DEF("__flags", js_regexp_get___flags, NULL ),
43512
};
43513
43514
static const JSCFunctionListEntry js_regexp_string_iterator_proto_funcs[] = {
43515
    JS_ITERATOR_NEXT_DEF("next", 0, js_regexp_string_iterator_next, 0 ),
43516
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "RegExp String Iterator", JS_PROP_CONFIGURABLE ),
43517
};
43518
43519
void JS_AddIntrinsicRegExpCompiler(JSContext *ctx)
43520
2
{
43521
2
    ctx->compile_regexp = js_compile_regexp;
43522
2
}
43523
43524
void JS_AddIntrinsicRegExp(JSContext *ctx)
43525
2
{
43526
2
    JSValueConst obj;
43527
43528
2
    JS_AddIntrinsicRegExpCompiler(ctx);
43529
43530
2
    ctx->class_proto[JS_CLASS_REGEXP] = JS_NewObject(ctx);
43531
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP], js_regexp_proto_funcs,
43532
2
                               countof(js_regexp_proto_funcs));
43533
2
    obj = JS_NewGlobalCConstructor(ctx, "RegExp", js_regexp_constructor, 2,
43534
2
                                   ctx->class_proto[JS_CLASS_REGEXP]);
43535
2
    ctx->regexp_ctor = JS_DupValue(ctx, obj);
43536
2
    JS_SetPropertyFunctionList(ctx, obj, js_regexp_funcs, countof(js_regexp_funcs));
43537
43538
2
    ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR] =
43539
2
        JS_NewObjectProto(ctx, ctx->iterator_proto);
43540
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR],
43541
2
                               js_regexp_string_iterator_proto_funcs,
43542
2
                               countof(js_regexp_string_iterator_proto_funcs));
43543
2
}
43544
43545
/* JSON */
43546
43547
static int json_parse_expect(JSParseState *s, int tok)
43548
0
{
43549
0
    if (s->token.val != tok) {
43550
        /* XXX: dump token correctly in all cases */
43551
0
        return js_parse_error(s, "expecting '%c'", tok);
43552
0
    }
43553
0
    return json_next_token(s);
43554
0
}
43555
43556
static JSValue json_parse_value(JSParseState *s)
43557
0
{
43558
0
    JSContext *ctx = s->ctx;
43559
0
    JSValue val = JS_NULL;
43560
0
    int ret;
43561
43562
0
    switch(s->token.val) {
43563
0
    case '{':
43564
0
        {
43565
0
            JSValue prop_val;
43566
0
            JSAtom prop_name;
43567
            
43568
0
            if (json_next_token(s))
43569
0
                goto fail;
43570
0
            val = JS_NewObject(ctx);
43571
0
            if (JS_IsException(val))
43572
0
                goto fail;
43573
0
            if (s->token.val != '}') {
43574
0
                for(;;) {
43575
0
                    if (s->token.val == TOK_STRING) {
43576
0
                        prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);
43577
0
                        if (prop_name == JS_ATOM_NULL)
43578
0
                            goto fail;
43579
0
                    } else if (s->ext_json && s->token.val == TOK_IDENT) {
43580
0
                        prop_name = JS_DupAtom(ctx, s->token.u.ident.atom);
43581
0
                    } else {
43582
0
                        js_parse_error(s, "expecting property name");
43583
0
                        goto fail;
43584
0
                    }
43585
0
                    if (json_next_token(s))
43586
0
                        goto fail1;
43587
0
                    if (json_parse_expect(s, ':'))
43588
0
                        goto fail1;
43589
0
                    prop_val = json_parse_value(s);
43590
0
                    if (JS_IsException(prop_val)) {
43591
0
                    fail1:
43592
0
                        JS_FreeAtom(ctx, prop_name);
43593
0
                        goto fail;
43594
0
                    }
43595
0
                    ret = JS_DefinePropertyValue(ctx, val, prop_name,
43596
0
                                                 prop_val, JS_PROP_C_W_E);
43597
0
                    JS_FreeAtom(ctx, prop_name);
43598
0
                    if (ret < 0)
43599
0
                        goto fail;
43600
43601
0
                    if (s->token.val != ',')
43602
0
                        break;
43603
0
                    if (json_next_token(s))
43604
0
                        goto fail;
43605
0
                    if (s->ext_json && s->token.val == '}')
43606
0
                        break;
43607
0
                }
43608
0
            }
43609
0
            if (json_parse_expect(s, '}'))
43610
0
                goto fail;
43611
0
        }
43612
0
        break;
43613
0
    case '[':
43614
0
        {
43615
0
            JSValue el;
43616
0
            uint32_t idx;
43617
43618
0
            if (json_next_token(s))
43619
0
                goto fail;
43620
0
            val = JS_NewArray(ctx);
43621
0
            if (JS_IsException(val))
43622
0
                goto fail;
43623
0
            if (s->token.val != ']') {
43624
0
                idx = 0;
43625
0
                for(;;) {
43626
0
                    el = json_parse_value(s);
43627
0
                    if (JS_IsException(el))
43628
0
                        goto fail;
43629
0
                    ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E);
43630
0
                    if (ret < 0)
43631
0
                        goto fail;
43632
0
                    if (s->token.val != ',')
43633
0
                        break;
43634
0
                    if (json_next_token(s))
43635
0
                        goto fail;
43636
0
                    idx++;
43637
0
                    if (s->ext_json && s->token.val == ']')
43638
0
                        break;
43639
0
                }
43640
0
            }
43641
0
            if (json_parse_expect(s, ']'))
43642
0
                goto fail;
43643
0
        }
43644
0
        break;
43645
0
    case TOK_STRING:
43646
0
        val = JS_DupValue(ctx, s->token.u.str.str);
43647
0
        if (json_next_token(s))
43648
0
            goto fail;
43649
0
        break;
43650
0
    case TOK_NUMBER:
43651
0
        val = s->token.u.num.val;
43652
0
        if (json_next_token(s))
43653
0
            goto fail;
43654
0
        break;
43655
0
    case TOK_IDENT:
43656
0
        if (s->token.u.ident.atom == JS_ATOM_false ||
43657
0
            s->token.u.ident.atom == JS_ATOM_true) {
43658
0
            val = JS_NewBool(ctx, (s->token.u.ident.atom == JS_ATOM_true));
43659
0
        } else if (s->token.u.ident.atom == JS_ATOM_null) {
43660
0
            val = JS_NULL;
43661
0
        } else {
43662
0
            goto def_token;
43663
0
        }
43664
0
        if (json_next_token(s))
43665
0
            goto fail;
43666
0
        break;
43667
0
    default:
43668
0
    def_token:
43669
0
        if (s->token.val == TOK_EOF) {
43670
0
            js_parse_error(s, "unexpected end of input");
43671
0
        } else {
43672
0
            js_parse_error(s, "unexpected token: '%.*s'",
43673
0
                           (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
43674
0
        }
43675
0
        goto fail;
43676
0
    }
43677
0
    return val;
43678
0
 fail:
43679
0
    JS_FreeValue(ctx, val);
43680
0
    return JS_EXCEPTION;
43681
0
}
43682
43683
JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
43684
                      const char *filename, int flags)
43685
0
{
43686
0
    JSParseState s1, *s = &s1;
43687
0
    JSValue val = JS_UNDEFINED;
43688
43689
0
    js_parse_init(ctx, s, buf, buf_len, filename);
43690
0
    s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);
43691
0
    if (json_next_token(s))
43692
0
        goto fail;
43693
0
    val = json_parse_value(s);
43694
0
    if (JS_IsException(val))
43695
0
        goto fail;
43696
0
    if (s->token.val != TOK_EOF) {
43697
0
        if (js_parse_error(s, "unexpected data at the end"))
43698
0
            goto fail;
43699
0
    }
43700
0
    return val;
43701
0
 fail:
43702
0
    JS_FreeValue(ctx, val);
43703
0
    free_token(s, &s->token);
43704
0
    return JS_EXCEPTION;
43705
0
}
43706
43707
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
43708
                     const char *filename)
43709
0
{
43710
0
    return JS_ParseJSON2(ctx, buf, buf_len, filename, 0); 
43711
0
}
43712
43713
static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
43714
                                         JSAtom name, JSValueConst reviver)
43715
0
{
43716
0
    JSValue val, new_el, name_val, res;
43717
0
    JSValueConst args[2];
43718
0
    int ret, is_array;
43719
0
    uint32_t i, len = 0;
43720
0
    JSAtom prop;
43721
0
    JSPropertyEnum *atoms = NULL;
43722
43723
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
43724
0
        return JS_ThrowStackOverflow(ctx);
43725
0
    }
43726
43727
0
    val = JS_GetProperty(ctx, holder, name);
43728
0
    if (JS_IsException(val))
43729
0
        return val;
43730
0
    if (JS_IsObject(val)) {
43731
0
        is_array = JS_IsArray(ctx, val);
43732
0
        if (is_array < 0)
43733
0
            goto fail;
43734
0
        if (is_array) {
43735
0
            if (js_get_length32(ctx, &len, val))
43736
0
                goto fail;
43737
0
        } else {
43738
0
            ret = JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, JS_VALUE_GET_OBJ(val), JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
43739
0
            if (ret < 0)
43740
0
                goto fail;
43741
0
        }
43742
0
        for(i = 0; i < len; i++) {
43743
0
            if (is_array) {
43744
0
                prop = JS_NewAtomUInt32(ctx, i);
43745
0
                if (prop == JS_ATOM_NULL)
43746
0
                    goto fail;
43747
0
            } else {
43748
0
                prop = JS_DupAtom(ctx, atoms[i].atom);
43749
0
            }
43750
0
            new_el = internalize_json_property(ctx, val, prop, reviver);
43751
0
            if (JS_IsException(new_el)) {
43752
0
                JS_FreeAtom(ctx, prop);
43753
0
                goto fail;
43754
0
            }
43755
0
            if (JS_IsUndefined(new_el)) {
43756
0
                ret = JS_DeleteProperty(ctx, val, prop, 0);
43757
0
            } else {
43758
0
                ret = JS_DefinePropertyValue(ctx, val, prop, new_el, JS_PROP_C_W_E);
43759
0
            }
43760
0
            JS_FreeAtom(ctx, prop);
43761
0
            if (ret < 0)
43762
0
                goto fail;
43763
0
        }
43764
0
    }
43765
0
    js_free_prop_enum(ctx, atoms, len);
43766
0
    atoms = NULL;
43767
0
    name_val = JS_AtomToValue(ctx, name);
43768
0
    if (JS_IsException(name_val))
43769
0
        goto fail;
43770
0
    args[0] = name_val;
43771
0
    args[1] = val;
43772
0
    res = JS_Call(ctx, reviver, holder, 2, args);
43773
0
    JS_FreeValue(ctx, name_val);
43774
0
    JS_FreeValue(ctx, val);
43775
0
    return res;
43776
0
 fail:
43777
0
    js_free_prop_enum(ctx, atoms, len);
43778
0
    JS_FreeValue(ctx, val);
43779
0
    return JS_EXCEPTION;
43780
0
}
43781
43782
static JSValue js_json_parse(JSContext *ctx, JSValueConst this_val,
43783
                             int argc, JSValueConst *argv)
43784
0
{
43785
0
    JSValue obj, root;
43786
0
    JSValueConst reviver;
43787
0
    const char *str;
43788
0
    size_t len;
43789
43790
0
    str = JS_ToCStringLen(ctx, &len, argv[0]);
43791
0
    if (!str)
43792
0
        return JS_EXCEPTION;
43793
0
    obj = JS_ParseJSON(ctx, str, len, "<input>");
43794
0
    JS_FreeCString(ctx, str);
43795
0
    if (JS_IsException(obj))
43796
0
        return obj;
43797
0
    if (argc > 1 && JS_IsFunction(ctx, argv[1])) {
43798
0
        reviver = argv[1];
43799
0
        root = JS_NewObject(ctx);
43800
0
        if (JS_IsException(root)) {
43801
0
            JS_FreeValue(ctx, obj);
43802
0
            return JS_EXCEPTION;
43803
0
        }
43804
0
        if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj,
43805
0
                                   JS_PROP_C_W_E) < 0) {
43806
0
            JS_FreeValue(ctx, root);
43807
0
            return JS_EXCEPTION;
43808
0
        }
43809
0
        obj = internalize_json_property(ctx, root, JS_ATOM_empty_string,
43810
0
                                        reviver);
43811
0
        JS_FreeValue(ctx, root);
43812
0
    }
43813
0
    return obj;
43814
0
}
43815
43816
typedef struct JSONStringifyContext {
43817
    JSValueConst replacer_func;
43818
    JSValue stack;
43819
    JSValue property_list;
43820
    JSValue gap;
43821
    JSValue empty;
43822
    StringBuffer *b;
43823
} JSONStringifyContext;
43824
43825
0
static JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) {
43826
0
    JSValue r = JS_ToQuotedString(ctx, val);
43827
0
    JS_FreeValue(ctx, val);
43828
0
    return r;
43829
0
}
43830
43831
static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
43832
                             JSValueConst holder, JSValue val, JSValueConst key)
43833
0
{
43834
0
    JSValue v;
43835
0
    JSValueConst args[2];
43836
43837
0
    if (JS_IsObject(val)
43838
0
#ifdef CONFIG_BIGNUM
43839
0
    ||  JS_IsBigInt(ctx, val)   /* XXX: probably useless */
43840
0
#endif
43841
0
        ) {
43842
0
            JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);
43843
0
            if (JS_IsException(f))
43844
0
                goto exception;
43845
0
            if (JS_IsFunction(ctx, f)) {
43846
0
                v = JS_CallFree(ctx, f, val, 1, &key);
43847
0
                JS_FreeValue(ctx, val);
43848
0
                val = v;
43849
0
                if (JS_IsException(val))
43850
0
                    goto exception;
43851
0
            } else {
43852
0
                JS_FreeValue(ctx, f);
43853
0
            }
43854
0
        }
43855
43856
0
    if (!JS_IsUndefined(jsc->replacer_func)) {
43857
0
        args[0] = key;
43858
0
        args[1] = val;
43859
0
        v = JS_Call(ctx, jsc->replacer_func, holder, 2, args);
43860
0
        JS_FreeValue(ctx, val);
43861
0
        val = v;
43862
0
        if (JS_IsException(val))
43863
0
            goto exception;
43864
0
    }
43865
43866
0
    switch (JS_VALUE_GET_NORM_TAG(val)) {
43867
0
    case JS_TAG_OBJECT:
43868
0
        if (JS_IsFunction(ctx, val))
43869
0
            break;
43870
0
    case JS_TAG_STRING:
43871
0
    case JS_TAG_INT:
43872
0
    case JS_TAG_FLOAT64:
43873
0
#ifdef CONFIG_BIGNUM
43874
0
    case JS_TAG_BIG_FLOAT:
43875
0
#endif
43876
0
    case JS_TAG_BOOL:
43877
0
    case JS_TAG_NULL:
43878
0
#ifdef CONFIG_BIGNUM
43879
0
    case JS_TAG_BIG_INT:
43880
0
#endif
43881
0
    case JS_TAG_EXCEPTION:
43882
0
        return val;
43883
0
    default:
43884
0
        break;
43885
0
    }
43886
0
    JS_FreeValue(ctx, val);
43887
0
    return JS_UNDEFINED;
43888
43889
0
exception:
43890
0
    JS_FreeValue(ctx, val);
43891
0
    return JS_EXCEPTION;
43892
0
}
43893
43894
static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
43895
                          JSValueConst holder, JSValue val,
43896
                          JSValueConst indent)
43897
0
{
43898
0
    JSValue indent1, sep, sep1, tab, v, prop;
43899
0
    JSObject *p;
43900
0
    int64_t i, len;
43901
0
    int cl, ret;
43902
0
    BOOL has_content;
43903
    
43904
0
    indent1 = JS_UNDEFINED;
43905
0
    sep = JS_UNDEFINED;
43906
0
    sep1 = JS_UNDEFINED;
43907
0
    tab = JS_UNDEFINED;
43908
0
    prop = JS_UNDEFINED;
43909
43910
0
    switch (JS_VALUE_GET_NORM_TAG(val)) {
43911
0
    case JS_TAG_OBJECT:
43912
0
        p = JS_VALUE_GET_OBJ(val);
43913
0
        cl = p->class_id;
43914
0
        if (cl == JS_CLASS_STRING) {
43915
0
            val = JS_ToStringFree(ctx, val);
43916
0
            if (JS_IsException(val))
43917
0
                goto exception;
43918
0
            val = JS_ToQuotedStringFree(ctx, val);
43919
0
            if (JS_IsException(val))
43920
0
                goto exception;
43921
0
            return string_buffer_concat_value_free(jsc->b, val);
43922
0
        } else if (cl == JS_CLASS_NUMBER) {
43923
0
            val = JS_ToNumberFree(ctx, val);
43924
0
            if (JS_IsException(val))
43925
0
                goto exception;
43926
0
            return string_buffer_concat_value_free(jsc->b, val);
43927
0
        } else if (cl == JS_CLASS_BOOLEAN) {
43928
0
            ret = string_buffer_concat_value(jsc->b, p->u.object_data);
43929
0
            JS_FreeValue(ctx, val);
43930
0
            return ret;
43931
0
        }
43932
0
#ifdef CONFIG_BIGNUM
43933
0
        else if (cl == JS_CLASS_BIG_FLOAT) {
43934
0
            return string_buffer_concat_value_free(jsc->b, val);
43935
0
        } else if (cl == JS_CLASS_BIG_INT) {
43936
0
            JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
43937
0
            goto exception;
43938
0
        }
43939
0
#endif
43940
0
        v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val);
43941
0
        if (JS_IsException(v))
43942
0
            goto exception;
43943
0
        if (JS_ToBoolFree(ctx, v)) {
43944
0
            JS_ThrowTypeError(ctx, "circular reference");
43945
0
            goto exception;
43946
0
        }
43947
0
        indent1 = JS_ConcatString(ctx, JS_DupValue(ctx, indent), JS_DupValue(ctx, jsc->gap));
43948
0
        if (JS_IsException(indent1))
43949
0
            goto exception;
43950
0
        if (!JS_IsEmptyString(jsc->gap)) {
43951
0
            sep = JS_ConcatString3(ctx, "\n", JS_DupValue(ctx, indent1), "");
43952
0
            if (JS_IsException(sep))
43953
0
                goto exception;
43954
0
            sep1 = JS_NewString(ctx, " ");
43955
0
            if (JS_IsException(sep1))
43956
0
                goto exception;
43957
0
        } else {
43958
0
            sep = JS_DupValue(ctx, jsc->empty);
43959
0
            sep1 = JS_DupValue(ctx, jsc->empty);
43960
0
        }
43961
0
        v = js_array_push(ctx, jsc->stack, 1, (JSValueConst *)&val, 0);
43962
0
        if (check_exception_free(ctx, v))
43963
0
            goto exception;
43964
0
        ret = JS_IsArray(ctx, val);
43965
0
        if (ret < 0)
43966
0
            goto exception;
43967
0
        if (ret) {
43968
0
            if (js_get_length64(ctx, &len, val))
43969
0
                goto exception;
43970
0
            string_buffer_putc8(jsc->b, '[');
43971
0
            for(i = 0; i < len; i++) {
43972
0
                if (i > 0)
43973
0
                    string_buffer_putc8(jsc->b, ',');
43974
0
                string_buffer_concat_value(jsc->b, sep);
43975
0
                v = JS_GetPropertyInt64(ctx, val, i);
43976
0
                if (JS_IsException(v))
43977
0
                    goto exception;
43978
                /* XXX: could do this string conversion only when needed */
43979
0
                prop = JS_ToStringFree(ctx, JS_NewInt64(ctx, i));
43980
0
                if (JS_IsException(prop))
43981
0
                    goto exception;
43982
0
                v = js_json_check(ctx, jsc, val, v, prop);
43983
0
                JS_FreeValue(ctx, prop);
43984
0
                prop = JS_UNDEFINED;
43985
0
                if (JS_IsException(v))
43986
0
                    goto exception;
43987
0
                if (JS_IsUndefined(v))
43988
0
                    v = JS_NULL;
43989
0
                if (js_json_to_str(ctx, jsc, val, v, indent1))
43990
0
                    goto exception;
43991
0
            }
43992
0
            if (len > 0 && !JS_IsEmptyString(jsc->gap)) {
43993
0
                string_buffer_putc8(jsc->b, '\n');
43994
0
                string_buffer_concat_value(jsc->b, indent);
43995
0
            }
43996
0
            string_buffer_putc8(jsc->b, ']');
43997
0
        } else {
43998
0
            if (!JS_IsUndefined(jsc->property_list))
43999
0
                tab = JS_DupValue(ctx, jsc->property_list);
44000
0
            else
44001
0
                tab = js_object_keys(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val, JS_ITERATOR_KIND_KEY);
44002
0
            if (JS_IsException(tab))
44003
0
                goto exception;
44004
0
            if (js_get_length64(ctx, &len, tab))
44005
0
                goto exception;
44006
0
            string_buffer_putc8(jsc->b, '{');
44007
0
            has_content = FALSE;
44008
0
            for(i = 0; i < len; i++) {
44009
0
                JS_FreeValue(ctx, prop);
44010
0
                prop = JS_GetPropertyInt64(ctx, tab, i);
44011
0
                if (JS_IsException(prop))
44012
0
                    goto exception;
44013
0
                v = JS_GetPropertyValue(ctx, val, JS_DupValue(ctx, prop));
44014
0
                if (JS_IsException(v))
44015
0
                    goto exception;
44016
0
                v = js_json_check(ctx, jsc, val, v, prop);
44017
0
                if (JS_IsException(v))
44018
0
                    goto exception;
44019
0
                if (!JS_IsUndefined(v)) {
44020
0
                    if (has_content)
44021
0
                        string_buffer_putc8(jsc->b, ',');
44022
0
                    prop = JS_ToQuotedStringFree(ctx, prop);
44023
0
                    if (JS_IsException(prop)) {
44024
0
                        JS_FreeValue(ctx, v);
44025
0
                        goto exception;
44026
0
                    }
44027
0
                    string_buffer_concat_value(jsc->b, sep);
44028
0
                    string_buffer_concat_value(jsc->b, prop);
44029
0
                    string_buffer_putc8(jsc->b, ':');
44030
0
                    string_buffer_concat_value(jsc->b, sep1);
44031
0
                    if (js_json_to_str(ctx, jsc, val, v, indent1))
44032
0
                        goto exception;
44033
0
                    has_content = TRUE;
44034
0
                }
44035
0
            }
44036
0
            if (has_content && JS_VALUE_GET_STRING(jsc->gap)->len != 0) {
44037
0
                string_buffer_putc8(jsc->b, '\n');
44038
0
                string_buffer_concat_value(jsc->b, indent);
44039
0
            }
44040
0
            string_buffer_putc8(jsc->b, '}');
44041
0
        }
44042
0
        if (check_exception_free(ctx, js_array_pop(ctx, jsc->stack, 0, NULL, 0)))
44043
0
            goto exception;
44044
0
        JS_FreeValue(ctx, val);
44045
0
        JS_FreeValue(ctx, tab);
44046
0
        JS_FreeValue(ctx, sep);
44047
0
        JS_FreeValue(ctx, sep1);
44048
0
        JS_FreeValue(ctx, indent1);
44049
0
        JS_FreeValue(ctx, prop);
44050
0
        return 0;
44051
0
    case JS_TAG_STRING:
44052
0
        val = JS_ToQuotedStringFree(ctx, val);
44053
0
        if (JS_IsException(val))
44054
0
            goto exception;
44055
0
        goto concat_value;
44056
0
    case JS_TAG_FLOAT64:
44057
0
        if (!isfinite(JS_VALUE_GET_FLOAT64(val))) {
44058
0
            val = JS_NULL;
44059
0
        }
44060
0
        goto concat_value;
44061
0
    case JS_TAG_INT:
44062
0
#ifdef CONFIG_BIGNUM
44063
0
    case JS_TAG_BIG_FLOAT:
44064
0
#endif
44065
0
    case JS_TAG_BOOL:
44066
0
    case JS_TAG_NULL:
44067
0
    concat_value:
44068
0
        return string_buffer_concat_value_free(jsc->b, val);
44069
0
#ifdef CONFIG_BIGNUM
44070
0
    case JS_TAG_BIG_INT:
44071
0
        JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
44072
0
        goto exception;
44073
0
#endif
44074
0
    default:
44075
0
        JS_FreeValue(ctx, val);
44076
0
        return 0;
44077
0
    }
44078
    
44079
0
exception:
44080
0
    JS_FreeValue(ctx, val);
44081
0
    JS_FreeValue(ctx, tab);
44082
0
    JS_FreeValue(ctx, sep);
44083
0
    JS_FreeValue(ctx, sep1);
44084
0
    JS_FreeValue(ctx, indent1);
44085
0
    JS_FreeValue(ctx, prop);
44086
0
    return -1;
44087
0
}
44088
44089
JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
44090
                         JSValueConst replacer, JSValueConst space0)
44091
0
{
44092
0
    StringBuffer b_s;
44093
0
    JSONStringifyContext jsc_s, *jsc = &jsc_s;
44094
0
    JSValue val, v, space, ret, wrapper;
44095
0
    int res;
44096
0
    int64_t i, j, n;
44097
44098
0
    jsc->replacer_func = JS_UNDEFINED;
44099
0
    jsc->stack = JS_UNDEFINED;
44100
0
    jsc->property_list = JS_UNDEFINED;
44101
0
    jsc->gap = JS_UNDEFINED;
44102
0
    jsc->b = &b_s;
44103
0
    jsc->empty = JS_AtomToString(ctx, JS_ATOM_empty_string);
44104
0
    ret = JS_UNDEFINED;
44105
0
    wrapper = JS_UNDEFINED;
44106
44107
0
    string_buffer_init(ctx, jsc->b, 0);
44108
0
    jsc->stack = JS_NewArray(ctx);
44109
0
    if (JS_IsException(jsc->stack))
44110
0
        goto exception;
44111
0
    if (JS_IsFunction(ctx, replacer)) {
44112
0
        jsc->replacer_func = replacer;
44113
0
    } else {
44114
0
        res = JS_IsArray(ctx, replacer);
44115
0
        if (res < 0)
44116
0
            goto exception;
44117
0
        if (res) {
44118
            /* XXX: enumeration is not fully correct */
44119
0
            jsc->property_list = JS_NewArray(ctx);
44120
0
            if (JS_IsException(jsc->property_list))
44121
0
                goto exception;
44122
0
            if (js_get_length64(ctx, &n, replacer))
44123
0
                goto exception;
44124
0
            for (i = j = 0; i < n; i++) {
44125
0
                JSValue present;
44126
0
                v = JS_GetPropertyInt64(ctx, replacer, i);
44127
0
                if (JS_IsException(v))
44128
0
                    goto exception;
44129
0
                if (JS_IsObject(v)) {
44130
0
                    JSObject *p = JS_VALUE_GET_OBJ(v);
44131
0
                    if (p->class_id == JS_CLASS_STRING ||
44132
0
                        p->class_id == JS_CLASS_NUMBER) {
44133
0
                        v = JS_ToStringFree(ctx, v);
44134
0
                        if (JS_IsException(v))
44135
0
                            goto exception;
44136
0
                    } else {
44137
0
                        JS_FreeValue(ctx, v);
44138
0
                        continue;
44139
0
                    }
44140
0
                } else if (JS_IsNumber(v)) {
44141
0
                    v = JS_ToStringFree(ctx, v);
44142
0
                    if (JS_IsException(v))
44143
0
                        goto exception;
44144
0
                } else if (!JS_IsString(v)) {
44145
0
                    JS_FreeValue(ctx, v);
44146
0
                    continue;
44147
0
                }
44148
0
                present = js_array_includes(ctx, jsc->property_list,
44149
0
                                            1, (JSValueConst *)&v);
44150
0
                if (JS_IsException(present)) {
44151
0
                    JS_FreeValue(ctx, v);
44152
0
                    goto exception;
44153
0
                }
44154
0
                if (!JS_ToBoolFree(ctx, present)) {
44155
0
                    JS_SetPropertyInt64(ctx, jsc->property_list, j++, v);
44156
0
                } else {
44157
0
                    JS_FreeValue(ctx, v);
44158
0
                }
44159
0
            }
44160
0
        }
44161
0
    }
44162
0
    space = JS_DupValue(ctx, space0);
44163
0
    if (JS_IsObject(space)) {
44164
0
        JSObject *p = JS_VALUE_GET_OBJ(space);
44165
0
        if (p->class_id == JS_CLASS_NUMBER) {
44166
0
            space = JS_ToNumberFree(ctx, space);
44167
0
        } else if (p->class_id == JS_CLASS_STRING) {
44168
0
            space = JS_ToStringFree(ctx, space);
44169
0
        }
44170
0
        if (JS_IsException(space)) {
44171
0
            JS_FreeValue(ctx, space);
44172
0
            goto exception;
44173
0
        }
44174
0
    }
44175
0
    if (JS_IsNumber(space)) {
44176
0
        int n;
44177
0
        if (JS_ToInt32Clamp(ctx, &n, space, 0, 10, 0))
44178
0
            goto exception;
44179
0
        jsc->gap = JS_NewStringLen(ctx, "          ", n);
44180
0
    } else if (JS_IsString(space)) {
44181
0
        JSString *p = JS_VALUE_GET_STRING(space);
44182
0
        jsc->gap = js_sub_string(ctx, p, 0, min_int(p->len, 10));
44183
0
    } else {
44184
0
        jsc->gap = JS_DupValue(ctx, jsc->empty);
44185
0
    }
44186
0
    JS_FreeValue(ctx, space);
44187
0
    if (JS_IsException(jsc->gap))
44188
0
        goto exception;
44189
0
    wrapper = JS_NewObject(ctx);
44190
0
    if (JS_IsException(wrapper))
44191
0
        goto exception;
44192
0
    if (JS_DefinePropertyValue(ctx, wrapper, JS_ATOM_empty_string,
44193
0
                               JS_DupValue(ctx, obj), JS_PROP_C_W_E) < 0)
44194
0
        goto exception;
44195
0
    val = JS_DupValue(ctx, obj);
44196
                           
44197
0
    val = js_json_check(ctx, jsc, wrapper, val, jsc->empty);
44198
0
    if (JS_IsException(val))
44199
0
        goto exception;
44200
0
    if (JS_IsUndefined(val)) {
44201
0
        ret = JS_UNDEFINED;
44202
0
        goto done1;
44203
0
    }
44204
0
    if (js_json_to_str(ctx, jsc, wrapper, val, jsc->empty))
44205
0
        goto exception;
44206
44207
0
    ret = string_buffer_end(jsc->b);
44208
0
    goto done;
44209
44210
0
exception:
44211
0
    ret = JS_EXCEPTION;
44212
0
done1:
44213
0
    string_buffer_free(jsc->b);
44214
0
done:
44215
0
    JS_FreeValue(ctx, wrapper);
44216
0
    JS_FreeValue(ctx, jsc->empty);
44217
0
    JS_FreeValue(ctx, jsc->gap);
44218
0
    JS_FreeValue(ctx, jsc->property_list);
44219
0
    JS_FreeValue(ctx, jsc->stack);
44220
0
    return ret;
44221
0
}
44222
44223
static JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val,
44224
                                 int argc, JSValueConst *argv)
44225
0
{
44226
    // stringify(val, replacer, space)
44227
0
    return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]);
44228
0
}
44229
44230
static const JSCFunctionListEntry js_json_funcs[] = {
44231
    JS_CFUNC_DEF("parse", 2, js_json_parse ),
44232
    JS_CFUNC_DEF("stringify", 3, js_json_stringify ),
44233
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "JSON", JS_PROP_CONFIGURABLE ),
44234
};
44235
44236
static const JSCFunctionListEntry js_json_obj[] = {
44237
    JS_OBJECT_DEF("JSON", js_json_funcs, countof(js_json_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
44238
};
44239
44240
void JS_AddIntrinsicJSON(JSContext *ctx)
44241
2
{
44242
    /* add JSON as autoinit object */
44243
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_json_obj, countof(js_json_obj));
44244
2
}
44245
44246
/* Reflect */
44247
44248
static JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val,
44249
                                int argc, JSValueConst *argv)
44250
0
{
44251
0
    return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2);
44252
0
}
44253
44254
static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
44255
                                    int argc, JSValueConst *argv)
44256
0
{
44257
0
    JSValueConst func, array_arg, new_target;
44258
0
    JSValue *tab, ret;
44259
0
    uint32_t len;
44260
44261
0
    func = argv[0];
44262
0
    array_arg = argv[1];
44263
0
    if (argc > 2) {
44264
0
        new_target = argv[2];
44265
0
        if (!JS_IsConstructor(ctx, new_target))
44266
0
            return JS_ThrowTypeError(ctx, "not a constructor");
44267
0
    } else {
44268
0
        new_target = func;
44269
0
    }
44270
0
    tab = build_arg_list(ctx, &len, array_arg);
44271
0
    if (!tab)
44272
0
        return JS_EXCEPTION;
44273
0
    ret = JS_CallConstructor2(ctx, func, new_target, len, (JSValueConst *)tab);
44274
0
    free_arg_list(ctx, tab, len);
44275
0
    return ret;
44276
0
}
44277
44278
static JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val,
44279
                                         int argc, JSValueConst *argv)
44280
0
{
44281
0
    JSValueConst obj;
44282
0
    JSAtom atom;
44283
0
    int ret;
44284
44285
0
    obj = argv[0];
44286
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
44287
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44288
0
    atom = JS_ValueToAtom(ctx, argv[1]);
44289
0
    if (unlikely(atom == JS_ATOM_NULL))
44290
0
        return JS_EXCEPTION;
44291
0
    ret = JS_DeleteProperty(ctx, obj, atom, 0);
44292
0
    JS_FreeAtom(ctx, atom);
44293
0
    if (ret < 0)
44294
0
        return JS_EXCEPTION;
44295
0
    else
44296
0
        return JS_NewBool(ctx, ret);
44297
0
}
44298
44299
static JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val,
44300
                              int argc, JSValueConst *argv)
44301
0
{
44302
0
    JSValueConst obj, prop, receiver;
44303
0
    JSAtom atom;
44304
0
    JSValue ret;
44305
44306
0
    obj = argv[0];
44307
0
    prop = argv[1];
44308
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
44309
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44310
0
    if (argc > 2)
44311
0
        receiver = argv[2];
44312
0
    else
44313
0
        receiver = obj;
44314
0
    atom = JS_ValueToAtom(ctx, prop);
44315
0
    if (unlikely(atom == JS_ATOM_NULL))
44316
0
        return JS_EXCEPTION;
44317
0
    ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, FALSE);
44318
0
    JS_FreeAtom(ctx, atom);
44319
0
    return ret;
44320
0
}
44321
44322
static JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val,
44323
                              int argc, JSValueConst *argv)
44324
0
{
44325
0
    JSValueConst obj, prop;
44326
0
    JSAtom atom;
44327
0
    int ret;
44328
44329
0
    obj = argv[0];
44330
0
    prop = argv[1];
44331
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
44332
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44333
0
    atom = JS_ValueToAtom(ctx, prop);
44334
0
    if (unlikely(atom == JS_ATOM_NULL))
44335
0
        return JS_EXCEPTION;
44336
0
    ret = JS_HasProperty(ctx, obj, atom);
44337
0
    JS_FreeAtom(ctx, atom);
44338
0
    if (ret < 0)
44339
0
        return JS_EXCEPTION;
44340
0
    else
44341
0
        return JS_NewBool(ctx, ret);
44342
0
}
44343
44344
static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
44345
                              int argc, JSValueConst *argv)
44346
0
{
44347
0
    JSValueConst obj, prop, val, receiver;
44348
0
    int ret;
44349
0
    JSAtom atom;
44350
44351
0
    obj = argv[0];
44352
0
    prop = argv[1];
44353
0
    val = argv[2];
44354
0
    if (argc > 3)
44355
0
        receiver = argv[3];
44356
0
    else
44357
0
        receiver = obj;
44358
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
44359
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44360
0
    atom = JS_ValueToAtom(ctx, prop);
44361
0
    if (unlikely(atom == JS_ATOM_NULL))
44362
0
        return JS_EXCEPTION;
44363
0
    ret = JS_SetPropertyGeneric(ctx, obj, atom,
44364
0
                                JS_DupValue(ctx, val), receiver, 0);
44365
0
    JS_FreeAtom(ctx, atom);
44366
0
    if (ret < 0)
44367
0
        return JS_EXCEPTION;
44368
0
    else
44369
0
        return JS_NewBool(ctx, ret);
44370
0
}
44371
44372
static JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
44373
                                         int argc, JSValueConst *argv)
44374
0
{
44375
0
    int ret;
44376
0
    ret = JS_SetPrototypeInternal(ctx, argv[0], argv[1], FALSE);
44377
0
    if (ret < 0)
44378
0
        return JS_EXCEPTION;
44379
0
    else
44380
0
        return JS_NewBool(ctx, ret);
44381
0
}
44382
44383
static JSValue js_reflect_ownKeys(JSContext *ctx, JSValueConst this_val,
44384
                                  int argc, JSValueConst *argv)
44385
0
{
44386
0
    if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
44387
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44388
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
44389
0
                                   JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK,
44390
0
                                   JS_ITERATOR_KIND_KEY);
44391
0
}
44392
44393
static const JSCFunctionListEntry js_reflect_funcs[] = {
44394
    JS_CFUNC_DEF("apply", 3, js_reflect_apply ),
44395
    JS_CFUNC_DEF("construct", 2, js_reflect_construct ),
44396
    JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 1 ),
44397
    JS_CFUNC_DEF("deleteProperty", 2, js_reflect_deleteProperty ),
44398
    JS_CFUNC_DEF("get", 2, js_reflect_get ),
44399
    JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 1 ),
44400
    JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 1 ),
44401
    JS_CFUNC_DEF("has", 2, js_reflect_has ),
44402
    JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 1 ),
44403
    JS_CFUNC_DEF("ownKeys", 1, js_reflect_ownKeys ),
44404
    JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 1 ),
44405
    JS_CFUNC_DEF("set", 3, js_reflect_set ),
44406
    JS_CFUNC_DEF("setPrototypeOf", 2, js_reflect_setPrototypeOf ),
44407
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Reflect", JS_PROP_CONFIGURABLE ),
44408
};
44409
44410
static const JSCFunctionListEntry js_reflect_obj[] = {
44411
    JS_OBJECT_DEF("Reflect", js_reflect_funcs, countof(js_reflect_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
44412
};
44413
44414
/* Proxy */
44415
44416
static void js_proxy_finalizer(JSRuntime *rt, JSValue val)
44417
0
{
44418
0
    JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
44419
0
    if (s) {
44420
0
        JS_FreeValueRT(rt, s->target);
44421
0
        JS_FreeValueRT(rt, s->handler);
44422
0
        js_free_rt(rt, s);
44423
0
    }
44424
0
}
44425
44426
static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
44427
                          JS_MarkFunc *mark_func)
44428
0
{
44429
0
    JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
44430
0
    if (s) {
44431
0
        JS_MarkValue(rt, s->target, mark_func);
44432
0
        JS_MarkValue(rt, s->handler, mark_func);
44433
0
    }
44434
0
}
44435
44436
static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx)
44437
0
{
44438
0
    return JS_ThrowTypeError(ctx, "revoked proxy");
44439
0
}
44440
44441
static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod,
44442
                                     JSValueConst obj, JSAtom name)
44443
0
{
44444
0
    JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
44445
0
    JSValue method;
44446
44447
    /* safer to test recursion in all proxy methods */
44448
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
44449
0
        JS_ThrowStackOverflow(ctx);
44450
0
        return NULL;
44451
0
    }
44452
    
44453
    /* 's' should never be NULL */
44454
0
    if (s->is_revoked) {
44455
0
        JS_ThrowTypeErrorRevokedProxy(ctx);
44456
0
        return NULL;
44457
0
    }
44458
0
    method = JS_GetProperty(ctx, s->handler, name);
44459
0
    if (JS_IsException(method))
44460
0
        return NULL;
44461
0
    if (JS_IsNull(method))
44462
0
        method = JS_UNDEFINED;
44463
0
    *pmethod = method;
44464
0
    return s;
44465
0
}
44466
44467
static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
44468
0
{
44469
0
    JSProxyData *s;
44470
0
    JSValue method, ret, proto1;
44471
0
    int res;
44472
44473
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_getPrototypeOf);
44474
0
    if (!s)
44475
0
        return JS_EXCEPTION;
44476
0
    if (JS_IsUndefined(method))
44477
0
        return JS_GetPrototype(ctx, s->target);
44478
0
    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
44479
0
    if (JS_IsException(ret))
44480
0
        return ret;
44481
0
    if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL &&
44482
0
        JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
44483
0
        goto fail;
44484
0
    }
44485
0
    res = JS_IsExtensible(ctx, s->target);
44486
0
    if (res < 0) {
44487
0
        JS_FreeValue(ctx, ret);
44488
0
        return JS_EXCEPTION;
44489
0
    }
44490
0
    if (!res) {
44491
        /* check invariant */
44492
0
        proto1 = JS_GetPrototype(ctx, s->target);
44493
0
        if (JS_IsException(proto1)) {
44494
0
            JS_FreeValue(ctx, ret);
44495
0
            return JS_EXCEPTION;
44496
0
        }
44497
0
        if (JS_VALUE_GET_OBJ(proto1) != JS_VALUE_GET_OBJ(ret)) {
44498
0
            JS_FreeValue(ctx, proto1);
44499
0
        fail:
44500
0
            JS_FreeValue(ctx, ret);
44501
0
            return JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
44502
0
        }
44503
0
        JS_FreeValue(ctx, proto1);
44504
0
    }
44505
0
    return ret;
44506
0
}
44507
44508
static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
44509
                                   JSValueConst proto_val, BOOL throw_flag)
44510
0
{
44511
0
    JSProxyData *s;
44512
0
    JSValue method, ret, proto1;
44513
0
    JSValueConst args[2];
44514
0
    BOOL res;
44515
0
    int res2;
44516
44517
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_setPrototypeOf);
44518
0
    if (!s)
44519
0
        return -1;
44520
0
    if (JS_IsUndefined(method))
44521
0
        return JS_SetPrototypeInternal(ctx, s->target, proto_val, throw_flag);
44522
0
    args[0] = s->target;
44523
0
    args[1] = proto_val;
44524
0
    ret = JS_CallFree(ctx, method, s->handler, 2, args);
44525
0
    if (JS_IsException(ret))
44526
0
        return -1;
44527
0
    res = JS_ToBoolFree(ctx, ret);
44528
0
    if (!res) {
44529
0
        if (throw_flag) {
44530
0
            JS_ThrowTypeError(ctx, "proxy: bad prototype");
44531
0
            return -1;
44532
0
        } else {
44533
0
            return FALSE;
44534
0
        }
44535
0
    }
44536
0
    res2 = JS_IsExtensible(ctx, s->target);
44537
0
    if (res2 < 0)
44538
0
        return -1;
44539
0
    if (!res2) {
44540
0
        proto1 = JS_GetPrototype(ctx, s->target);
44541
0
        if (JS_IsException(proto1))
44542
0
            return -1;
44543
0
        if (JS_VALUE_GET_OBJ(proto_val) != JS_VALUE_GET_OBJ(proto1)) {
44544
0
            JS_FreeValue(ctx, proto1);
44545
0
            JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
44546
0
            return -1;
44547
0
        }
44548
0
        JS_FreeValue(ctx, proto1);
44549
0
    }
44550
0
    return TRUE;
44551
0
}
44552
44553
static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj)
44554
0
{
44555
0
    JSProxyData *s;
44556
0
    JSValue method, ret;
44557
0
    BOOL res;
44558
0
    int res2;
44559
44560
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_isExtensible);
44561
0
    if (!s)
44562
0
        return -1;
44563
0
    if (JS_IsUndefined(method))
44564
0
        return JS_IsExtensible(ctx, s->target);
44565
0
    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
44566
0
    if (JS_IsException(ret))
44567
0
        return -1;
44568
0
    res = JS_ToBoolFree(ctx, ret);
44569
0
    res2 = JS_IsExtensible(ctx, s->target);
44570
0
    if (res2 < 0)
44571
0
        return res2;
44572
0
    if (res != res2) {
44573
0
        JS_ThrowTypeError(ctx, "proxy: inconsistent isExtensible");
44574
0
        return -1;
44575
0
    }
44576
0
    return res;
44577
0
}
44578
44579
static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj)
44580
0
{
44581
0
    JSProxyData *s;
44582
0
    JSValue method, ret;
44583
0
    BOOL res;
44584
0
    int res2;
44585
44586
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_preventExtensions);
44587
0
    if (!s)
44588
0
        return -1;
44589
0
    if (JS_IsUndefined(method))
44590
0
        return JS_PreventExtensions(ctx, s->target);
44591
0
    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
44592
0
    if (JS_IsException(ret))
44593
0
        return -1;
44594
0
    res = JS_ToBoolFree(ctx, ret);
44595
0
    if (res) {
44596
0
        res2 = JS_IsExtensible(ctx, s->target);
44597
0
        if (res2 < 0)
44598
0
            return res2;
44599
0
        if (res2) {
44600
0
            JS_ThrowTypeError(ctx, "proxy: inconsistent preventExtensions");
44601
0
            return -1;
44602
0
        }
44603
0
    }
44604
0
    return res;
44605
0
}
44606
44607
static int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
44608
0
{
44609
0
    JSProxyData *s;
44610
0
    JSValue method, ret1, atom_val;
44611
0
    int ret, res;
44612
0
    JSObject *p;
44613
0
    JSValueConst args[2];
44614
0
    BOOL res2;
44615
44616
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_has);
44617
0
    if (!s)
44618
0
        return -1;
44619
0
    if (JS_IsUndefined(method))
44620
0
        return JS_HasProperty(ctx, s->target, atom);
44621
0
    atom_val = JS_AtomToValue(ctx, atom);
44622
0
    if (JS_IsException(atom_val)) {
44623
0
        JS_FreeValue(ctx, method);
44624
0
        return -1;
44625
0
    }
44626
0
    args[0] = s->target;
44627
0
    args[1] = atom_val;
44628
0
    ret1 = JS_CallFree(ctx, method, s->handler, 2, args);
44629
0
    JS_FreeValue(ctx, atom_val);
44630
0
    if (JS_IsException(ret1))
44631
0
        return -1;
44632
0
    ret = JS_ToBoolFree(ctx, ret1);
44633
0
    if (!ret) {
44634
0
        JSPropertyDescriptor desc;
44635
0
        p = JS_VALUE_GET_OBJ(s->target);
44636
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
44637
0
        if (res < 0)
44638
0
            return -1;
44639
0
        if (res) {
44640
0
            res2 = !(desc.flags & JS_PROP_CONFIGURABLE);
44641
0
            js_free_desc(ctx, &desc);
44642
0
            if (res2 || !p->extensible) {
44643
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent has");
44644
0
                return -1;
44645
0
            }
44646
0
        }
44647
0
    }
44648
0
    return ret;
44649
0
}
44650
44651
static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,
44652
                            JSValueConst receiver)
44653
0
{
44654
0
    JSProxyData *s;
44655
0
    JSValue method, ret, atom_val;
44656
0
    int res;
44657
0
    JSValueConst args[3];
44658
0
    JSPropertyDescriptor desc;
44659
44660
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_get);
44661
0
    if (!s)
44662
0
        return JS_EXCEPTION;
44663
    /* Note: recursion is possible thru the prototype of s->target */
44664
0
    if (JS_IsUndefined(method))
44665
0
        return JS_GetPropertyInternal(ctx, s->target, atom, receiver, FALSE);
44666
0
    atom_val = JS_AtomToValue(ctx, atom);
44667
0
    if (JS_IsException(atom_val)) {
44668
0
        JS_FreeValue(ctx, method);
44669
0
        return JS_EXCEPTION;
44670
0
    }
44671
0
    args[0] = s->target;
44672
0
    args[1] = atom_val;
44673
0
    args[2] = receiver;
44674
0
    ret = JS_CallFree(ctx, method, s->handler, 3, args);
44675
0
    JS_FreeValue(ctx, atom_val);
44676
0
    if (JS_IsException(ret))
44677
0
        return JS_EXCEPTION;
44678
0
    res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
44679
0
    if (res < 0)
44680
0
        return JS_EXCEPTION;
44681
0
    if (res) {
44682
0
        if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
44683
0
            if (!js_same_value(ctx, desc.value, ret)) {
44684
0
                goto fail;
44685
0
            }
44686
0
        } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET) {
44687
0
            if (JS_IsUndefined(desc.getter) && !JS_IsUndefined(ret)) {
44688
0
            fail:
44689
0
                js_free_desc(ctx, &desc);
44690
0
                JS_FreeValue(ctx, ret);
44691
0
                return JS_ThrowTypeError(ctx, "proxy: inconsistent get");
44692
0
            }
44693
0
        }
44694
0
        js_free_desc(ctx, &desc);
44695
0
    }
44696
0
    return ret;
44697
0
}
44698
44699
static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
44700
                        JSValueConst value, JSValueConst receiver, int flags)
44701
0
{
44702
0
    JSProxyData *s;
44703
0
    JSValue method, ret1, atom_val;
44704
0
    int ret, res;
44705
0
    JSValueConst args[4];
44706
44707
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_set);
44708
0
    if (!s)
44709
0
        return -1;
44710
0
    if (JS_IsUndefined(method)) {
44711
0
        return JS_SetPropertyGeneric(ctx, s->target, atom,
44712
0
                                     JS_DupValue(ctx, value), receiver,
44713
0
                                     flags);
44714
0
    }
44715
0
    atom_val = JS_AtomToValue(ctx, atom);
44716
0
    if (JS_IsException(atom_val)) {
44717
0
        JS_FreeValue(ctx, method);
44718
0
        return -1;
44719
0
    }
44720
0
    args[0] = s->target;
44721
0
    args[1] = atom_val;
44722
0
    args[2] = value;
44723
0
    args[3] = receiver;
44724
0
    ret1 = JS_CallFree(ctx, method, s->handler, 4, args);
44725
0
    JS_FreeValue(ctx, atom_val);
44726
0
    if (JS_IsException(ret1))
44727
0
        return -1;
44728
0
    ret = JS_ToBoolFree(ctx, ret1);
44729
0
    if (ret) {
44730
0
        JSPropertyDescriptor desc;
44731
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
44732
0
        if (res < 0)
44733
0
            return -1;
44734
0
        if (res) {
44735
0
            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
44736
0
                if (!js_same_value(ctx, desc.value, value)) {
44737
0
                    goto fail;
44738
0
                }
44739
0
            } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET && JS_IsUndefined(desc.setter)) {
44740
0
                fail:
44741
0
                    js_free_desc(ctx, &desc);
44742
0
                    JS_ThrowTypeError(ctx, "proxy: inconsistent set");
44743
0
                    return -1;
44744
0
            }
44745
0
            js_free_desc(ctx, &desc);
44746
0
        }
44747
0
    } else {
44748
0
        if ((flags & JS_PROP_THROW) ||
44749
0
            ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
44750
0
            JS_ThrowTypeError(ctx, "proxy: cannot set property");
44751
0
            return -1;
44752
0
        }
44753
0
    }
44754
0
    return ret;
44755
0
}
44756
44757
static JSValue js_create_desc(JSContext *ctx, JSValueConst val,
44758
                              JSValueConst getter, JSValueConst setter,
44759
                              int flags)
44760
0
{
44761
0
    JSValue ret;
44762
0
    ret = JS_NewObject(ctx);
44763
0
    if (JS_IsException(ret))
44764
0
        return ret;
44765
0
    if (flags & JS_PROP_HAS_GET) {
44766
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, getter),
44767
0
                               JS_PROP_C_W_E);
44768
0
    }
44769
0
    if (flags & JS_PROP_HAS_SET) {
44770
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, setter),
44771
0
                               JS_PROP_C_W_E);
44772
0
    }
44773
0
    if (flags & JS_PROP_HAS_VALUE) {
44774
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, val),
44775
0
                               JS_PROP_C_W_E);
44776
0
    }
44777
0
    if (flags & JS_PROP_HAS_WRITABLE) {
44778
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
44779
0
                               JS_NewBool(ctx, (flags & JS_PROP_WRITABLE) != 0),
44780
0
                               JS_PROP_C_W_E);
44781
0
    }
44782
0
    if (flags & JS_PROP_HAS_ENUMERABLE) {
44783
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
44784
0
                               JS_NewBool(ctx, (flags & JS_PROP_ENUMERABLE) != 0),
44785
0
                               JS_PROP_C_W_E);
44786
0
    }
44787
0
    if (flags & JS_PROP_HAS_CONFIGURABLE) {
44788
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
44789
0
                               JS_NewBool(ctx, (flags & JS_PROP_CONFIGURABLE) != 0),
44790
0
                               JS_PROP_C_W_E);
44791
0
    }
44792
0
    return ret;
44793
0
}
44794
44795
static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc,
44796
                                     JSValueConst obj, JSAtom prop)
44797
0
{
44798
0
    JSProxyData *s;
44799
0
    JSValue method, trap_result_obj, prop_val;
44800
0
    int res, target_desc_ret, ret;
44801
0
    JSObject *p;
44802
0
    JSValueConst args[2];
44803
0
    JSPropertyDescriptor result_desc, target_desc;
44804
44805
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_getOwnPropertyDescriptor);
44806
0
    if (!s)
44807
0
        return -1;
44808
0
    p = JS_VALUE_GET_OBJ(s->target);
44809
0
    if (JS_IsUndefined(method)) {
44810
0
        return JS_GetOwnPropertyInternal(ctx, pdesc, p, prop);
44811
0
    }
44812
0
    prop_val = JS_AtomToValue(ctx, prop);
44813
0
    if (JS_IsException(prop_val)) {
44814
0
        JS_FreeValue(ctx, method);
44815
0
        return -1;
44816
0
    }
44817
0
    args[0] = s->target;
44818
0
    args[1] = prop_val;
44819
0
    trap_result_obj = JS_CallFree(ctx, method, s->handler, 2, args);
44820
0
    JS_FreeValue(ctx, prop_val);
44821
0
    if (JS_IsException(trap_result_obj))
44822
0
        return -1;
44823
0
    if (!JS_IsObject(trap_result_obj) && !JS_IsUndefined(trap_result_obj)) {
44824
0
        JS_FreeValue(ctx, trap_result_obj);
44825
0
        goto fail;
44826
0
    }
44827
0
    target_desc_ret = JS_GetOwnPropertyInternal(ctx, &target_desc, p, prop);
44828
0
    if (target_desc_ret < 0) {
44829
0
        JS_FreeValue(ctx, trap_result_obj);
44830
0
        return -1;
44831
0
    }
44832
0
    if (target_desc_ret)
44833
0
        js_free_desc(ctx, &target_desc);
44834
0
    if (JS_IsUndefined(trap_result_obj)) {
44835
0
        if (target_desc_ret) {
44836
0
            if (!(target_desc.flags & JS_PROP_CONFIGURABLE) || !p->extensible)
44837
0
                goto fail;
44838
0
        }
44839
0
        ret = FALSE;
44840
0
    } else {
44841
0
        int flags1, extensible_target;
44842
0
        extensible_target = JS_IsExtensible(ctx, s->target);
44843
0
        if (extensible_target < 0) {
44844
0
            JS_FreeValue(ctx, trap_result_obj);
44845
0
            return -1;
44846
0
        }
44847
0
        res = js_obj_to_desc(ctx, &result_desc, trap_result_obj);
44848
0
        JS_FreeValue(ctx, trap_result_obj);
44849
0
        if (res < 0)
44850
0
            return -1;
44851
        
44852
0
        if (target_desc_ret) {
44853
            /* convert result_desc.flags to defineProperty flags */
44854
0
            flags1 = result_desc.flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE;
44855
0
            if (result_desc.flags & JS_PROP_GETSET)
44856
0
                flags1 |= JS_PROP_HAS_GET | JS_PROP_HAS_SET;
44857
0
            else
44858
0
                flags1 |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE;
44859
            /* XXX: not complete check: need to compare value &
44860
               getter/setter as in defineproperty */
44861
0
            if (!check_define_prop_flags(target_desc.flags, flags1))
44862
0
                goto fail1;
44863
0
        } else {
44864
0
            if (!extensible_target)
44865
0
                goto fail1;
44866
0
        }
44867
0
        if (!(result_desc.flags & JS_PROP_CONFIGURABLE)) {
44868
0
            if (!target_desc_ret || (target_desc.flags & JS_PROP_CONFIGURABLE))
44869
0
                goto fail1;
44870
0
            if ((result_desc.flags &
44871
0
                 (JS_PROP_GETSET | JS_PROP_WRITABLE)) == 0 &&
44872
0
                target_desc_ret &&
44873
0
                (target_desc.flags & JS_PROP_WRITABLE) != 0) {
44874
                /* proxy-missing-checks */
44875
0
            fail1:
44876
0
                js_free_desc(ctx, &result_desc);
44877
0
            fail:
44878
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent getOwnPropertyDescriptor");
44879
0
                return -1;
44880
0
            }
44881
0
        }
44882
0
        ret = TRUE;
44883
0
        if (pdesc) {
44884
0
            *pdesc = result_desc;
44885
0
        } else {
44886
0
            js_free_desc(ctx, &result_desc);
44887
0
        }
44888
0
    }
44889
0
    return ret;
44890
0
}
44891
44892
static int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj,
44893
                                        JSAtom prop, JSValueConst val,
44894
                                        JSValueConst getter, JSValueConst setter,
44895
                                        int flags)
44896
0
{
44897
0
    JSProxyData *s;
44898
0
    JSValue method, ret1, prop_val, desc_val;
44899
0
    int res, ret;
44900
0
    JSObject *p;
44901
0
    JSValueConst args[3];
44902
0
    JSPropertyDescriptor desc;
44903
0
    BOOL setting_not_configurable;
44904
44905
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_defineProperty);
44906
0
    if (!s)
44907
0
        return -1;
44908
0
    if (JS_IsUndefined(method)) {
44909
0
        return JS_DefineProperty(ctx, s->target, prop, val, getter, setter, flags);
44910
0
    }
44911
0
    prop_val = JS_AtomToValue(ctx, prop);
44912
0
    if (JS_IsException(prop_val)) {
44913
0
        JS_FreeValue(ctx, method);
44914
0
        return -1;
44915
0
    }
44916
0
    desc_val = js_create_desc(ctx, val, getter, setter, flags);
44917
0
    if (JS_IsException(desc_val)) {
44918
0
        JS_FreeValue(ctx, prop_val);
44919
0
        JS_FreeValue(ctx, method);
44920
0
        return -1;
44921
0
    }
44922
0
    args[0] = s->target;
44923
0
    args[1] = prop_val;
44924
0
    args[2] = desc_val;
44925
0
    ret1 = JS_CallFree(ctx, method, s->handler, 3, args);
44926
0
    JS_FreeValue(ctx, prop_val);
44927
0
    JS_FreeValue(ctx, desc_val);
44928
0
    if (JS_IsException(ret1))
44929
0
        return -1;
44930
0
    ret = JS_ToBoolFree(ctx, ret1);
44931
0
    if (!ret) {
44932
0
        if (flags & JS_PROP_THROW) {
44933
0
            JS_ThrowTypeError(ctx, "proxy: defineProperty exception");
44934
0
            return -1;
44935
0
        } else {
44936
0
            return 0;
44937
0
        }
44938
0
    }
44939
0
    p = JS_VALUE_GET_OBJ(s->target);
44940
0
    res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
44941
0
    if (res < 0)
44942
0
        return -1;
44943
0
    setting_not_configurable = ((flags & (JS_PROP_HAS_CONFIGURABLE |
44944
0
                                          JS_PROP_CONFIGURABLE)) ==
44945
0
                                JS_PROP_HAS_CONFIGURABLE);
44946
0
    if (!res) {
44947
0
        if (!p->extensible || setting_not_configurable)
44948
0
            goto fail;
44949
0
    } else {
44950
0
        if (!check_define_prop_flags(desc.flags, flags) ||
44951
0
            ((desc.flags & JS_PROP_CONFIGURABLE) && setting_not_configurable)) {
44952
0
            goto fail1;
44953
0
        }
44954
0
        if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
44955
0
            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) ==
44956
0
                JS_PROP_GETSET) {
44957
0
                if ((flags & JS_PROP_HAS_GET) &&
44958
0
                    !js_same_value(ctx, getter, desc.getter)) {
44959
0
                    goto fail1;
44960
0
                }
44961
0
                if ((flags & JS_PROP_HAS_SET) &&
44962
0
                    !js_same_value(ctx, setter, desc.setter)) {
44963
0
                    goto fail1;
44964
0
                }
44965
0
            }
44966
0
        } else if (flags & JS_PROP_HAS_VALUE) {
44967
0
            if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) ==
44968
0
                JS_PROP_WRITABLE && !(flags & JS_PROP_WRITABLE)) {
44969
                /* missing-proxy-check feature */
44970
0
                goto fail1;
44971
0
            } else if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
44972
0
                !js_same_value(ctx, val, desc.value)) {
44973
0
                goto fail1;
44974
0
            }
44975
0
        }
44976
0
        if (flags & JS_PROP_HAS_WRITABLE) {
44977
0
            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE |
44978
0
                               JS_PROP_WRITABLE)) == JS_PROP_WRITABLE) {
44979
                /* proxy-missing-checks */
44980
0
            fail1:
44981
0
                js_free_desc(ctx, &desc);
44982
0
            fail:
44983
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent defineProperty");
44984
0
                return -1;
44985
0
            }
44986
0
        }
44987
0
        js_free_desc(ctx, &desc);
44988
0
    }
44989
0
    return 1;
44990
0
}
44991
44992
static int js_proxy_delete_property(JSContext *ctx, JSValueConst obj,
44993
                                    JSAtom atom)
44994
0
{
44995
0
    JSProxyData *s;
44996
0
    JSValue method, ret, atom_val;
44997
0
    int res, res2, is_extensible;
44998
0
    JSValueConst args[2];
44999
45000
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_deleteProperty);
45001
0
    if (!s)
45002
0
        return -1;
45003
0
    if (JS_IsUndefined(method)) {
45004
0
        return JS_DeleteProperty(ctx, s->target, atom, 0);
45005
0
    }
45006
0
    atom_val = JS_AtomToValue(ctx, atom);;
45007
0
    if (JS_IsException(atom_val)) {
45008
0
        JS_FreeValue(ctx, method);
45009
0
        return -1;
45010
0
    }
45011
0
    args[0] = s->target;
45012
0
    args[1] = atom_val;
45013
0
    ret = JS_CallFree(ctx, method, s->handler, 2, args);
45014
0
    JS_FreeValue(ctx, atom_val);
45015
0
    if (JS_IsException(ret))
45016
0
        return -1;
45017
0
    res = JS_ToBoolFree(ctx, ret);
45018
0
    if (res) {
45019
0
        JSPropertyDescriptor desc;
45020
0
        res2 = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
45021
0
        if (res2 < 0)
45022
0
            return -1;
45023
0
        if (res2) {
45024
0
            if (!(desc.flags & JS_PROP_CONFIGURABLE))
45025
0
                goto fail;
45026
0
            is_extensible = JS_IsExtensible(ctx, s->target);
45027
0
            if (is_extensible < 0)
45028
0
                goto fail1;
45029
0
            if (!is_extensible) {
45030
                /* proxy-missing-checks */
45031
0
            fail:
45032
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent deleteProperty");
45033
0
            fail1:
45034
0
                js_free_desc(ctx, &desc);
45035
0
                return -1;
45036
0
            }
45037
0
            js_free_desc(ctx, &desc);
45038
0
        }
45039
0
    }
45040
0
    return res;
45041
0
}
45042
45043
/* return the index of the property or -1 if not found */
45044
static int find_prop_key(const JSPropertyEnum *tab, int n, JSAtom atom)
45045
0
{
45046
0
    int i;
45047
0
    for(i = 0; i < n; i++) {
45048
0
        if (tab[i].atom == atom)
45049
0
            return i;
45050
0
    }
45051
0
    return -1;
45052
0
}
45053
45054
static int js_proxy_get_own_property_names(JSContext *ctx,
45055
                                           JSPropertyEnum **ptab,
45056
                                           uint32_t *plen,
45057
                                           JSValueConst obj)
45058
0
{
45059
0
    JSProxyData *s;
45060
0
    JSValue method, prop_array, val;
45061
0
    uint32_t len, i, len2;
45062
0
    JSPropertyEnum *tab, *tab2;
45063
0
    JSAtom atom;
45064
0
    JSPropertyDescriptor desc;
45065
0
    int res, is_extensible, idx;
45066
45067
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_ownKeys);
45068
0
    if (!s)
45069
0
        return -1;
45070
0
    if (JS_IsUndefined(method)) {
45071
0
        return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
45072
0
                                      JS_VALUE_GET_OBJ(s->target),
45073
0
                                      JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK);
45074
0
    }
45075
0
    prop_array = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
45076
0
    if (JS_IsException(prop_array))
45077
0
        return -1;
45078
0
    tab = NULL;
45079
0
    len = 0;
45080
0
    tab2 = NULL;
45081
0
    len2 = 0;
45082
0
    if (js_get_length32(ctx, &len, prop_array))
45083
0
        goto fail;
45084
0
    if (len > 0) {
45085
0
        tab = js_mallocz(ctx, sizeof(tab[0]) * len);
45086
0
        if (!tab)
45087
0
            goto fail;
45088
0
    }
45089
0
    for(i = 0; i < len; i++) {
45090
0
        val = JS_GetPropertyUint32(ctx, prop_array, i);
45091
0
        if (JS_IsException(val))
45092
0
            goto fail;
45093
0
        if (!JS_IsString(val) && !JS_IsSymbol(val)) {
45094
0
            JS_FreeValue(ctx, val);
45095
0
            JS_ThrowTypeError(ctx, "proxy: properties must be strings or symbols");
45096
0
            goto fail;
45097
0
        }
45098
0
        atom = JS_ValueToAtom(ctx, val);
45099
0
        JS_FreeValue(ctx, val);
45100
0
        if (atom == JS_ATOM_NULL)
45101
0
            goto fail;
45102
0
        tab[i].atom = atom;
45103
0
        tab[i].is_enumerable = FALSE; /* XXX: redundant? */
45104
0
    }
45105
45106
    /* check duplicate properties (XXX: inefficient, could store the
45107
     * properties an a temporary object to use the hash) */
45108
0
    for(i = 1; i < len; i++) {
45109
0
        if (find_prop_key(tab, i, tab[i].atom) >= 0) {
45110
0
            JS_ThrowTypeError(ctx, "proxy: duplicate property");
45111
0
            goto fail;
45112
0
        }
45113
0
    }
45114
45115
0
    is_extensible = JS_IsExtensible(ctx, s->target);
45116
0
    if (is_extensible < 0)
45117
0
        goto fail;
45118
45119
    /* check if there are non configurable properties */
45120
0
    if (s->is_revoked) {
45121
0
        JS_ThrowTypeErrorRevokedProxy(ctx);
45122
0
        goto fail;
45123
0
    }
45124
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &tab2, &len2, JS_VALUE_GET_OBJ(s->target),
45125
0
                               JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
45126
0
        goto fail;
45127
0
    for(i = 0; i < len2; i++) {
45128
0
        if (s->is_revoked) {
45129
0
            JS_ThrowTypeErrorRevokedProxy(ctx);
45130
0
            goto fail;
45131
0
        }
45132
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target),
45133
0
                                tab2[i].atom);
45134
0
        if (res < 0)
45135
0
            goto fail;
45136
0
        if (res) {  /* safety, property should be found */
45137
0
            js_free_desc(ctx, &desc);
45138
0
            if (!(desc.flags & JS_PROP_CONFIGURABLE) || !is_extensible) {
45139
0
                idx = find_prop_key(tab, len, tab2[i].atom);
45140
0
                if (idx < 0) {
45141
0
                    JS_ThrowTypeError(ctx, "proxy: target property must be present in proxy ownKeys");
45142
0
                    goto fail;
45143
0
                }
45144
                /* mark the property as found */
45145
0
                if (!is_extensible)
45146
0
                    tab[idx].is_enumerable = TRUE;
45147
0
            }
45148
0
        }
45149
0
    }
45150
0
    if (!is_extensible) {
45151
        /* check that all property in 'tab' were checked */
45152
0
        for(i = 0; i < len; i++) {
45153
0
            if (!tab[i].is_enumerable) {
45154
0
                JS_ThrowTypeError(ctx, "proxy: property not present in target were returned by non extensible proxy");
45155
0
                goto fail;
45156
0
            }
45157
0
        }
45158
0
    }
45159
45160
0
    js_free_prop_enum(ctx, tab2, len2);
45161
0
    JS_FreeValue(ctx, prop_array);
45162
0
    *ptab = tab;
45163
0
    *plen = len;
45164
0
    return 0;
45165
0
 fail:
45166
0
    js_free_prop_enum(ctx, tab2, len2);
45167
0
    js_free_prop_enum(ctx, tab, len);
45168
0
    JS_FreeValue(ctx, prop_array);
45169
0
    return -1;
45170
0
}
45171
45172
static JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj,
45173
                                         JSValueConst new_target,
45174
                                         int argc, JSValueConst *argv)
45175
0
{
45176
0
    JSProxyData *s;
45177
0
    JSValue method, arg_array, ret;
45178
0
    JSValueConst args[3];
45179
45180
0
    s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_construct);
45181
0
    if (!s)
45182
0
        return JS_EXCEPTION;
45183
0
    if (!JS_IsConstructor(ctx, s->target))
45184
0
        return JS_ThrowTypeError(ctx, "not a constructor");
45185
0
    if (JS_IsUndefined(method))
45186
0
        return JS_CallConstructor2(ctx, s->target, new_target, argc, argv);
45187
0
    arg_array = js_create_array(ctx, argc, argv);
45188
0
    if (JS_IsException(arg_array)) {
45189
0
        ret = JS_EXCEPTION;
45190
0
        goto fail;
45191
0
    }
45192
0
    args[0] = s->target;
45193
0
    args[1] = arg_array;
45194
0
    args[2] = new_target;
45195
0
    ret = JS_Call(ctx, method, s->handler, 3, args);
45196
0
    if (!JS_IsException(ret) && JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
45197
0
        JS_FreeValue(ctx, ret);
45198
0
        ret = JS_ThrowTypeErrorNotAnObject(ctx);
45199
0
    }
45200
0
 fail:
45201
0
    JS_FreeValue(ctx, method);
45202
0
    JS_FreeValue(ctx, arg_array);
45203
0
    return ret;
45204
0
}
45205
45206
static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,
45207
                             JSValueConst this_obj,
45208
                             int argc, JSValueConst *argv, int flags)
45209
0
{
45210
0
    JSProxyData *s;
45211
0
    JSValue method, arg_array, ret;
45212
0
    JSValueConst args[3];
45213
45214
0
    if (flags & JS_CALL_FLAG_CONSTRUCTOR)
45215
0
        return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv);
45216
    
45217
0
    s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_apply);
45218
0
    if (!s)
45219
0
        return JS_EXCEPTION;
45220
0
    if (!s->is_func) {
45221
0
        JS_FreeValue(ctx, method);
45222
0
        return JS_ThrowTypeError(ctx, "not a function");
45223
0
    }
45224
0
    if (JS_IsUndefined(method))
45225
0
        return JS_Call(ctx, s->target, this_obj, argc, argv);
45226
0
    arg_array = js_create_array(ctx, argc, argv);
45227
0
    if (JS_IsException(arg_array)) {
45228
0
        ret = JS_EXCEPTION;
45229
0
        goto fail;
45230
0
    }
45231
0
    args[0] = s->target;
45232
0
    args[1] = this_obj;
45233
0
    args[2] = arg_array;
45234
0
    ret = JS_Call(ctx, method, s->handler, 3, args);
45235
0
 fail:
45236
0
    JS_FreeValue(ctx, method);
45237
0
    JS_FreeValue(ctx, arg_array);
45238
0
    return ret;
45239
0
}
45240
45241
static int js_proxy_isArray(JSContext *ctx, JSValueConst obj)
45242
0
{
45243
0
    JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
45244
0
    if (!s)
45245
0
        return FALSE;
45246
0
    if (s->is_revoked) {
45247
0
        JS_ThrowTypeErrorRevokedProxy(ctx);
45248
0
        return -1;
45249
0
    }
45250
0
    return JS_IsArray(ctx, s->target);
45251
0
}
45252
45253
static const JSClassExoticMethods js_proxy_exotic_methods = {
45254
    .get_own_property = js_proxy_get_own_property,
45255
    .define_own_property = js_proxy_define_own_property,
45256
    .delete_property = js_proxy_delete_property,
45257
    .get_own_property_names = js_proxy_get_own_property_names,
45258
    .has_property = js_proxy_has,
45259
    .get_property = js_proxy_get,
45260
    .set_property = js_proxy_set,
45261
};
45262
45263
static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val,
45264
                                    int argc, JSValueConst *argv)
45265
0
{
45266
0
    JSValueConst target, handler;
45267
0
    JSValue obj;
45268
0
    JSProxyData *s;
45269
45270
0
    target = argv[0];
45271
0
    handler = argv[1];
45272
0
    if (JS_VALUE_GET_TAG(target) != JS_TAG_OBJECT ||
45273
0
        JS_VALUE_GET_TAG(handler) != JS_TAG_OBJECT)
45274
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45275
45276
0
    obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_PROXY);
45277
0
    if (JS_IsException(obj))
45278
0
        return obj;
45279
0
    s = js_malloc(ctx, sizeof(JSProxyData));
45280
0
    if (!s) {
45281
0
        JS_FreeValue(ctx, obj);
45282
0
        return JS_EXCEPTION;
45283
0
    }
45284
0
    s->target = JS_DupValue(ctx, target);
45285
0
    s->handler = JS_DupValue(ctx, handler);
45286
0
    s->is_func = JS_IsFunction(ctx, target);
45287
0
    s->is_revoked = FALSE;
45288
0
    JS_SetOpaque(obj, s);
45289
0
    JS_SetConstructorBit(ctx, obj, JS_IsConstructor(ctx, target));
45290
0
    return obj;
45291
0
}
45292
45293
static JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val,
45294
                               int argc, JSValueConst *argv, int magic,
45295
                               JSValue *func_data)
45296
0
{
45297
0
    JSProxyData *s = JS_GetOpaque(func_data[0], JS_CLASS_PROXY);
45298
0
    if (s) {
45299
        /* We do not free the handler and target in case they are
45300
           referenced as constants in the C call stack */
45301
0
        s->is_revoked = TRUE;
45302
0
        JS_FreeValue(ctx, func_data[0]);
45303
0
        func_data[0] = JS_NULL;
45304
0
    }
45305
0
    return JS_UNDEFINED;
45306
0
}
45307
45308
static JSValue js_proxy_revoke_constructor(JSContext *ctx,
45309
                                           JSValueConst proxy_obj)
45310
0
{
45311
0
    return JS_NewCFunctionData(ctx, js_proxy_revoke, 0, 0, 1, &proxy_obj);
45312
0
}
45313
45314
static JSValue js_proxy_revocable(JSContext *ctx, JSValueConst this_val,
45315
                                 int argc, JSValueConst *argv)
45316
0
{
45317
0
    JSValue proxy_obj, revoke_obj = JS_UNDEFINED, obj;
45318
45319
0
    proxy_obj = js_proxy_constructor(ctx, JS_UNDEFINED, argc, argv);
45320
0
    if (JS_IsException(proxy_obj))
45321
0
        goto fail;
45322
0
    revoke_obj = js_proxy_revoke_constructor(ctx, proxy_obj);
45323
0
    if (JS_IsException(revoke_obj))
45324
0
        goto fail;
45325
0
    obj = JS_NewObject(ctx);
45326
0
    if (JS_IsException(obj))
45327
0
        goto fail;
45328
    // XXX: exceptions?
45329
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_proxy, proxy_obj, JS_PROP_C_W_E);
45330
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_revoke, revoke_obj, JS_PROP_C_W_E);
45331
0
    return obj;
45332
0
 fail:
45333
0
    JS_FreeValue(ctx, proxy_obj);
45334
0
    JS_FreeValue(ctx, revoke_obj);
45335
0
    return JS_EXCEPTION;
45336
0
}
45337
45338
static const JSCFunctionListEntry js_proxy_funcs[] = {
45339
    JS_CFUNC_DEF("revocable", 2, js_proxy_revocable ),
45340
};
45341
45342
static const JSClassShortDef js_proxy_class_def[] = {
45343
    { JS_ATOM_Object, js_proxy_finalizer, js_proxy_mark }, /* JS_CLASS_PROXY */
45344
};
45345
45346
void JS_AddIntrinsicProxy(JSContext *ctx)
45347
2
{
45348
2
    JSRuntime *rt = ctx->rt;
45349
2
    JSValue obj1;
45350
45351
2
    if (!JS_IsRegisteredClass(rt, JS_CLASS_PROXY)) {
45352
2
        init_class_range(rt, js_proxy_class_def, JS_CLASS_PROXY,
45353
2
                         countof(js_proxy_class_def));
45354
2
        rt->class_array[JS_CLASS_PROXY].exotic = &js_proxy_exotic_methods;
45355
2
        rt->class_array[JS_CLASS_PROXY].call = js_proxy_call;
45356
2
    }
45357
45358
2
    obj1 = JS_NewCFunction2(ctx, js_proxy_constructor, "Proxy", 2,
45359
2
                            JS_CFUNC_constructor, 0);
45360
2
    JS_SetConstructorBit(ctx, obj1, TRUE);
45361
2
    JS_SetPropertyFunctionList(ctx, obj1, js_proxy_funcs,
45362
2
                               countof(js_proxy_funcs));
45363
2
    JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Proxy",
45364
2
                              obj1, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
45365
2
}
45366
45367
/* Symbol */
45368
45369
static JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target,
45370
                                     int argc, JSValueConst *argv)
45371
0
{
45372
0
    JSValue str;
45373
0
    JSString *p;
45374
45375
0
    if (!JS_IsUndefined(new_target))
45376
0
        return JS_ThrowTypeError(ctx, "not a constructor");
45377
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
45378
0
        p = NULL;
45379
0
    } else {
45380
0
        str = JS_ToString(ctx, argv[0]);
45381
0
        if (JS_IsException(str))
45382
0
            return JS_EXCEPTION;
45383
0
        p = JS_VALUE_GET_STRING(str);
45384
0
    }
45385
0
    return JS_NewSymbol(ctx, p, JS_ATOM_TYPE_SYMBOL);
45386
0
}
45387
45388
static JSValue js_thisSymbolValue(JSContext *ctx, JSValueConst this_val)
45389
0
{
45390
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_SYMBOL)
45391
0
        return JS_DupValue(ctx, this_val);
45392
45393
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
45394
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
45395
0
        if (p->class_id == JS_CLASS_SYMBOL) {
45396
0
            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_SYMBOL)
45397
0
                return JS_DupValue(ctx, p->u.object_data);
45398
0
        }
45399
0
    }
45400
0
    return JS_ThrowTypeError(ctx, "not a symbol");
45401
0
}
45402
45403
static JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val,
45404
                                  int argc, JSValueConst *argv)
45405
0
{
45406
0
    JSValue val, ret;
45407
0
    val = js_thisSymbolValue(ctx, this_val);
45408
0
    if (JS_IsException(val))
45409
0
        return val;
45410
    /* XXX: use JS_ToStringInternal() with a flags */
45411
0
    ret = js_string_constructor(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val);
45412
0
    JS_FreeValue(ctx, val);
45413
0
    return ret;
45414
0
}
45415
45416
static JSValue js_symbol_valueOf(JSContext *ctx, JSValueConst this_val,
45417
                                 int argc, JSValueConst *argv)
45418
0
{
45419
0
    return js_thisSymbolValue(ctx, this_val);
45420
0
}
45421
45422
static JSValue js_symbol_get_description(JSContext *ctx, JSValueConst this_val)
45423
0
{
45424
0
    JSValue val, ret;
45425
0
    JSAtomStruct *p;
45426
45427
0
    val = js_thisSymbolValue(ctx, this_val);
45428
0
    if (JS_IsException(val))
45429
0
        return val;
45430
0
    p = JS_VALUE_GET_PTR(val);
45431
0
    if (p->len == 0 && p->is_wide_char != 0) {
45432
0
        ret = JS_UNDEFINED;
45433
0
    } else {
45434
0
        ret = JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p));
45435
0
    }
45436
0
    JS_FreeValue(ctx, val);
45437
0
    return ret;
45438
0
}
45439
45440
static const JSCFunctionListEntry js_symbol_proto_funcs[] = {
45441
    JS_CFUNC_DEF("toString", 0, js_symbol_toString ),
45442
    JS_CFUNC_DEF("valueOf", 0, js_symbol_valueOf ),
45443
    // XXX: should have writable: false
45444
    JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_symbol_valueOf ),
45445
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Symbol", JS_PROP_CONFIGURABLE ),
45446
    JS_CGETSET_DEF("description", js_symbol_get_description, NULL ),
45447
};
45448
45449
static JSValue js_symbol_for(JSContext *ctx, JSValueConst this_val,
45450
                             int argc, JSValueConst *argv)
45451
0
{
45452
0
    JSValue str;
45453
45454
0
    str = JS_ToString(ctx, argv[0]);
45455
0
    if (JS_IsException(str))
45456
0
        return JS_EXCEPTION;
45457
0
    return JS_NewSymbol(ctx, JS_VALUE_GET_STRING(str), JS_ATOM_TYPE_GLOBAL_SYMBOL);
45458
0
}
45459
45460
static JSValue js_symbol_keyFor(JSContext *ctx, JSValueConst this_val,
45461
                                int argc, JSValueConst *argv)
45462
0
{
45463
0
    JSAtomStruct *p;
45464
45465
0
    if (!JS_IsSymbol(argv[0]))
45466
0
        return JS_ThrowTypeError(ctx, "not a symbol");
45467
0
    p = JS_VALUE_GET_PTR(argv[0]);
45468
0
    if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL)
45469
0
        return JS_UNDEFINED;
45470
0
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
45471
0
}
45472
45473
static const JSCFunctionListEntry js_symbol_funcs[] = {
45474
    JS_CFUNC_DEF("for", 1, js_symbol_for ),
45475
    JS_CFUNC_DEF("keyFor", 1, js_symbol_keyFor ),
45476
};
45477
45478
/* Set/Map/WeakSet/WeakMap */
45479
45480
typedef struct JSMapRecord {
45481
    int ref_count; /* used during enumeration to avoid freeing the record */
45482
    BOOL empty; /* TRUE if the record is deleted */
45483
    struct JSMapState *map;
45484
    struct JSMapRecord *next_weak_ref;
45485
    struct list_head link;
45486
    struct list_head hash_link;
45487
    JSValue key;
45488
    JSValue value;
45489
} JSMapRecord;
45490
45491
typedef struct JSMapState {
45492
    BOOL is_weak; /* TRUE if WeakSet/WeakMap */
45493
    struct list_head records; /* list of JSMapRecord.link */
45494
    uint32_t record_count;
45495
    struct list_head *hash_table;
45496
    uint32_t hash_size; /* must be a power of two */
45497
    uint32_t record_count_threshold; /* count at which a hash table
45498
                                        resize is needed */
45499
} JSMapState;
45500
45501
0
#define MAGIC_SET (1 << 0)
45502
0
#define MAGIC_WEAK (1 << 1)
45503
45504
static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
45505
                                  int argc, JSValueConst *argv, int magic)
45506
0
{
45507
0
    JSMapState *s;
45508
0
    JSValue obj, adder = JS_UNDEFINED, iter = JS_UNDEFINED, next_method = JS_UNDEFINED;
45509
0
    JSValueConst arr;
45510
0
    BOOL is_set, is_weak;
45511
45512
0
    is_set = magic & MAGIC_SET;
45513
0
    is_weak = ((magic & MAGIC_WEAK) != 0);
45514
0
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_MAP + magic);
45515
0
    if (JS_IsException(obj))
45516
0
        return JS_EXCEPTION;
45517
0
    s = js_mallocz(ctx, sizeof(*s));
45518
0
    if (!s)
45519
0
        goto fail;
45520
0
    init_list_head(&s->records);
45521
0
    s->is_weak = is_weak;
45522
0
    JS_SetOpaque(obj, s);
45523
0
    s->hash_size = 1;
45524
0
    s->hash_table = js_malloc(ctx, sizeof(s->hash_table[0]) * s->hash_size);
45525
0
    if (!s->hash_table)
45526
0
        goto fail;
45527
0
    init_list_head(&s->hash_table[0]);
45528
0
    s->record_count_threshold = 4;
45529
45530
0
    arr = JS_UNDEFINED;
45531
0
    if (argc > 0)
45532
0
        arr = argv[0];
45533
0
    if (!JS_IsUndefined(arr) && !JS_IsNull(arr)) {
45534
0
        JSValue item, ret;
45535
0
        BOOL done;
45536
45537
0
        adder = JS_GetProperty(ctx, obj, is_set ? JS_ATOM_add : JS_ATOM_set);
45538
0
        if (JS_IsException(adder))
45539
0
            goto fail;
45540
0
        if (!JS_IsFunction(ctx, adder)) {
45541
0
            JS_ThrowTypeError(ctx, "set/add is not a function");
45542
0
            goto fail;
45543
0
        }
45544
45545
0
        iter = JS_GetIterator(ctx, arr, FALSE);
45546
0
        if (JS_IsException(iter))
45547
0
            goto fail;
45548
0
        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
45549
0
        if (JS_IsException(next_method))
45550
0
            goto fail;
45551
45552
0
        for(;;) {
45553
0
            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
45554
0
            if (JS_IsException(item))
45555
0
                goto fail;
45556
0
            if (done) {
45557
0
                JS_FreeValue(ctx, item);
45558
0
                break;
45559
0
            }
45560
0
            if (is_set) {
45561
0
                ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item);
45562
0
                if (JS_IsException(ret)) {
45563
0
                    JS_FreeValue(ctx, item);
45564
0
                    goto fail;
45565
0
                }
45566
0
            } else {
45567
0
                JSValue key, value;
45568
0
                JSValueConst args[2];
45569
0
                key = JS_UNDEFINED;
45570
0
                value = JS_UNDEFINED;
45571
0
                if (!JS_IsObject(item)) {
45572
0
                    JS_ThrowTypeErrorNotAnObject(ctx);
45573
0
                    goto fail1;
45574
0
                }
45575
0
                key = JS_GetPropertyUint32(ctx, item, 0);
45576
0
                if (JS_IsException(key))
45577
0
                    goto fail1;
45578
0
                value = JS_GetPropertyUint32(ctx, item, 1);
45579
0
                if (JS_IsException(value))
45580
0
                    goto fail1;
45581
0
                args[0] = key;
45582
0
                args[1] = value;
45583
0
                ret = JS_Call(ctx, adder, obj, 2, args);
45584
0
                if (JS_IsException(ret)) {
45585
0
                fail1:
45586
0
                    JS_FreeValue(ctx, item);
45587
0
                    JS_FreeValue(ctx, key);
45588
0
                    JS_FreeValue(ctx, value);
45589
0
                    goto fail;
45590
0
                }
45591
0
                JS_FreeValue(ctx, key);
45592
0
                JS_FreeValue(ctx, value);
45593
0
            }
45594
0
            JS_FreeValue(ctx, ret);
45595
0
            JS_FreeValue(ctx, item);
45596
0
        }
45597
0
        JS_FreeValue(ctx, next_method);
45598
0
        JS_FreeValue(ctx, iter);
45599
0
        JS_FreeValue(ctx, adder);
45600
0
    }
45601
0
    return obj;
45602
0
 fail:
45603
0
    if (JS_IsObject(iter)) {
45604
        /* close the iterator object, preserving pending exception */
45605
0
        JS_IteratorClose(ctx, iter, TRUE);
45606
0
    }
45607
0
    JS_FreeValue(ctx, next_method);
45608
0
    JS_FreeValue(ctx, iter);
45609
0
    JS_FreeValue(ctx, adder);
45610
0
    JS_FreeValue(ctx, obj);
45611
0
    return JS_EXCEPTION;
45612
0
}
45613
45614
/* XXX: could normalize strings to speed up comparison */
45615
static JSValueConst map_normalize_key(JSContext *ctx, JSValueConst key)
45616
0
{
45617
0
    uint32_t tag = JS_VALUE_GET_TAG(key);
45618
    /* convert -0.0 to +0.0 */
45619
0
    if (JS_TAG_IS_FLOAT64(tag) && JS_VALUE_GET_FLOAT64(key) == 0.0) {
45620
0
        key = JS_NewInt32(ctx, 0);
45621
0
    }
45622
0
    return key;
45623
0
}
45624
45625
/* XXX: better hash ? */
45626
static uint32_t map_hash_key(JSContext *ctx, JSValueConst key)
45627
0
{
45628
0
    uint32_t tag = JS_VALUE_GET_NORM_TAG(key);
45629
0
    uint32_t h;
45630
0
    double d;
45631
0
    JSFloat64Union u;
45632
45633
0
    switch(tag) {
45634
0
    case JS_TAG_BOOL:
45635
0
        h = JS_VALUE_GET_INT(key);
45636
0
        break;
45637
0
    case JS_TAG_STRING:
45638
0
        h = hash_string(JS_VALUE_GET_STRING(key), 0);
45639
0
        break;
45640
0
    case JS_TAG_OBJECT:
45641
0
    case JS_TAG_SYMBOL:
45642
0
        h = (uintptr_t)JS_VALUE_GET_PTR(key) * 3163;
45643
0
        break;
45644
0
    case JS_TAG_INT:
45645
0
        d = JS_VALUE_GET_INT(key) * 3163;
45646
0
        goto hash_float64;
45647
0
    case JS_TAG_FLOAT64:
45648
0
        d = JS_VALUE_GET_FLOAT64(key);
45649
        /* normalize the NaN */
45650
0
        if (isnan(d))
45651
0
            d = JS_FLOAT64_NAN;
45652
0
    hash_float64:
45653
0
        u.d = d;
45654
0
        h = (u.u32[0] ^ u.u32[1]) * 3163;
45655
0
        break;
45656
0
    default:
45657
0
        h = 0; /* XXX: bignum support */
45658
0
        break;
45659
0
    }
45660
0
    h ^= tag;
45661
0
    return h;
45662
0
}
45663
45664
static JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s,
45665
                                    JSValueConst key)
45666
0
{
45667
0
    struct list_head *el;
45668
0
    JSMapRecord *mr;
45669
0
    uint32_t h;
45670
0
    h = map_hash_key(ctx, key) & (s->hash_size - 1);
45671
0
    list_for_each(el, &s->hash_table[h]) {
45672
0
        mr = list_entry(el, JSMapRecord, hash_link);
45673
0
        if (js_same_value_zero(ctx, mr->key, key))
45674
0
            return mr;
45675
0
    }
45676
0
    return NULL;
45677
0
}
45678
45679
static void map_hash_resize(JSContext *ctx, JSMapState *s)
45680
0
{
45681
0
    uint32_t new_hash_size, i, h;
45682
0
    size_t slack;
45683
0
    struct list_head *new_hash_table, *el;
45684
0
    JSMapRecord *mr;
45685
45686
    /* XXX: no reporting of memory allocation failure */
45687
0
    if (s->hash_size == 1)
45688
0
        new_hash_size = 4;
45689
0
    else
45690
0
        new_hash_size = s->hash_size * 2;
45691
0
    new_hash_table = js_realloc2(ctx, s->hash_table,
45692
0
                                 sizeof(new_hash_table[0]) * new_hash_size, &slack);
45693
0
    if (!new_hash_table)
45694
0
        return;
45695
0
    new_hash_size += slack / sizeof(*new_hash_table);
45696
45697
0
    for(i = 0; i < new_hash_size; i++)
45698
0
        init_list_head(&new_hash_table[i]);
45699
45700
0
    list_for_each(el, &s->records) {
45701
0
        mr = list_entry(el, JSMapRecord, link);
45702
0
        if (!mr->empty) {
45703
0
            h = map_hash_key(ctx, mr->key) & (new_hash_size - 1);
45704
0
            list_add_tail(&mr->hash_link, &new_hash_table[h]);
45705
0
        }
45706
0
    }
45707
0
    s->hash_table = new_hash_table;
45708
0
    s->hash_size = new_hash_size;
45709
0
    s->record_count_threshold = new_hash_size * 2;
45710
0
}
45711
45712
static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
45713
                                   JSValueConst key)
45714
0
{
45715
0
    uint32_t h;
45716
0
    JSMapRecord *mr;
45717
45718
0
    mr = js_malloc(ctx, sizeof(*mr));
45719
0
    if (!mr)
45720
0
        return NULL;
45721
0
    mr->ref_count = 1;
45722
0
    mr->map = s;
45723
0
    mr->empty = FALSE;
45724
0
    if (s->is_weak) {
45725
0
        JSObject *p = JS_VALUE_GET_OBJ(key);
45726
        /* Add the weak reference */
45727
0
        mr->next_weak_ref = p->first_weak_ref;
45728
0
        p->first_weak_ref = mr;
45729
0
    } else {
45730
0
        JS_DupValue(ctx, key);
45731
0
    }
45732
0
    mr->key = (JSValue)key;
45733
0
    h = map_hash_key(ctx, key) & (s->hash_size - 1);
45734
0
    list_add_tail(&mr->hash_link, &s->hash_table[h]);
45735
0
    list_add_tail(&mr->link, &s->records);
45736
0
    s->record_count++;
45737
0
    if (s->record_count >= s->record_count_threshold) {
45738
0
        map_hash_resize(ctx, s);
45739
0
    }
45740
0
    return mr;
45741
0
}
45742
45743
/* Remove the weak reference from the object weak
45744
   reference list. we don't use a doubly linked list to
45745
   save space, assuming a given object has few weak
45746
       references to it */
45747
static void delete_weak_ref(JSRuntime *rt, JSMapRecord *mr)
45748
0
{
45749
0
    JSMapRecord **pmr, *mr1;
45750
0
    JSObject *p;
45751
45752
0
    p = JS_VALUE_GET_OBJ(mr->key);
45753
0
    pmr = &p->first_weak_ref;
45754
0
    for(;;) {
45755
0
        mr1 = *pmr;
45756
0
        assert(mr1 != NULL);
45757
0
        if (mr1 == mr)
45758
0
            break;
45759
0
        pmr = &mr1->next_weak_ref;
45760
0
    }
45761
0
    *pmr = mr1->next_weak_ref;
45762
0
}
45763
45764
static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr)
45765
0
{
45766
0
    if (mr->empty)
45767
0
        return;
45768
0
    list_del(&mr->hash_link);
45769
0
    if (s->is_weak) {
45770
0
        delete_weak_ref(rt, mr);
45771
0
    } else {
45772
0
        JS_FreeValueRT(rt, mr->key);
45773
0
    }
45774
0
    JS_FreeValueRT(rt, mr->value);
45775
0
    if (--mr->ref_count == 0) {
45776
0
        list_del(&mr->link);
45777
0
        js_free_rt(rt, mr);
45778
0
    } else {
45779
        /* keep a zombie record for iterators */
45780
0
        mr->empty = TRUE;
45781
0
        mr->key = JS_UNDEFINED;
45782
0
        mr->value = JS_UNDEFINED;
45783
0
    }
45784
0
    s->record_count--;
45785
0
}
45786
45787
static void map_decref_record(JSRuntime *rt, JSMapRecord *mr)
45788
0
{
45789
0
    if (--mr->ref_count == 0) {
45790
        /* the record can be safely removed */
45791
0
        assert(mr->empty);
45792
0
        list_del(&mr->link);
45793
0
        js_free_rt(rt, mr);
45794
0
    }
45795
0
}
45796
45797
static void reset_weak_ref(JSRuntime *rt, JSObject *p)
45798
0
{
45799
0
    JSMapRecord *mr, *mr_next;
45800
0
    JSMapState *s;
45801
    
45802
    /* first pass to remove the records from the WeakMap/WeakSet
45803
       lists */
45804
0
    for(mr = p->first_weak_ref; mr != NULL; mr = mr->next_weak_ref) {
45805
0
        s = mr->map;
45806
0
        assert(s->is_weak);
45807
0
        assert(!mr->empty); /* no iterator on WeakMap/WeakSet */
45808
0
        list_del(&mr->hash_link);
45809
0
        list_del(&mr->link);
45810
0
    }
45811
    
45812
    /* second pass to free the values to avoid modifying the weak
45813
       reference list while traversing it. */
45814
0
    for(mr = p->first_weak_ref; mr != NULL; mr = mr_next) {
45815
0
        mr_next = mr->next_weak_ref;
45816
0
        JS_FreeValueRT(rt, mr->value);
45817
0
        js_free_rt(rt, mr);
45818
0
    }
45819
45820
0
    p->first_weak_ref = NULL; /* fail safe */
45821
0
}
45822
45823
static JSValue js_map_set(JSContext *ctx, JSValueConst this_val,
45824
                          int argc, JSValueConst *argv, int magic)
45825
0
{
45826
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45827
0
    JSMapRecord *mr;
45828
0
    JSValueConst key, value;
45829
45830
0
    if (!s)
45831
0
        return JS_EXCEPTION;
45832
0
    key = map_normalize_key(ctx, argv[0]);
45833
0
    if (s->is_weak && !JS_IsObject(key))
45834
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45835
0
    if (magic & MAGIC_SET)
45836
0
        value = JS_UNDEFINED;
45837
0
    else
45838
0
        value = argv[1];
45839
0
    mr = map_find_record(ctx, s, key);
45840
0
    if (mr) {
45841
0
        JS_FreeValue(ctx, mr->value);
45842
0
    } else {
45843
0
        mr = map_add_record(ctx, s, key);
45844
0
        if (!mr)
45845
0
            return JS_EXCEPTION;
45846
0
    }
45847
0
    mr->value = JS_DupValue(ctx, value);
45848
0
    return JS_DupValue(ctx, this_val);
45849
0
}
45850
45851
static JSValue js_map_get(JSContext *ctx, JSValueConst this_val,
45852
                          int argc, JSValueConst *argv, int magic)
45853
0
{
45854
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45855
0
    JSMapRecord *mr;
45856
0
    JSValueConst key;
45857
45858
0
    if (!s)
45859
0
        return JS_EXCEPTION;
45860
0
    key = map_normalize_key(ctx, argv[0]);
45861
0
    mr = map_find_record(ctx, s, key);
45862
0
    if (!mr)
45863
0
        return JS_UNDEFINED;
45864
0
    else
45865
0
        return JS_DupValue(ctx, mr->value);
45866
0
}
45867
45868
static JSValue js_map_has(JSContext *ctx, JSValueConst this_val,
45869
                          int argc, JSValueConst *argv, int magic)
45870
0
{
45871
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45872
0
    JSMapRecord *mr;
45873
0
    JSValueConst key;
45874
45875
0
    if (!s)
45876
0
        return JS_EXCEPTION;
45877
0
    key = map_normalize_key(ctx, argv[0]);
45878
0
    mr = map_find_record(ctx, s, key);
45879
0
    return JS_NewBool(ctx, (mr != NULL));
45880
0
}
45881
45882
static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val,
45883
                             int argc, JSValueConst *argv, int magic)
45884
0
{
45885
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45886
0
    JSMapRecord *mr;
45887
0
    JSValueConst key;
45888
45889
0
    if (!s)
45890
0
        return JS_EXCEPTION;
45891
0
    key = map_normalize_key(ctx, argv[0]);
45892
0
    mr = map_find_record(ctx, s, key);
45893
0
    if (!mr)
45894
0
        return JS_FALSE;
45895
0
    map_delete_record(ctx->rt, s, mr);
45896
0
    return JS_TRUE;
45897
0
}
45898
45899
static JSValue js_map_clear(JSContext *ctx, JSValueConst this_val,
45900
                            int argc, JSValueConst *argv, int magic)
45901
0
{
45902
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45903
0
    struct list_head *el, *el1;
45904
0
    JSMapRecord *mr;
45905
45906
0
    if (!s)
45907
0
        return JS_EXCEPTION;
45908
0
    list_for_each_safe(el, el1, &s->records) {
45909
0
        mr = list_entry(el, JSMapRecord, link);
45910
0
        map_delete_record(ctx->rt, s, mr);
45911
0
    }
45912
0
    return JS_UNDEFINED;
45913
0
}
45914
45915
static JSValue js_map_get_size(JSContext *ctx, JSValueConst this_val, int magic)
45916
0
{
45917
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45918
0
    if (!s)
45919
0
        return JS_EXCEPTION;
45920
0
    return JS_NewUint32(ctx, s->record_count);
45921
0
}
45922
45923
static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,
45924
                              int argc, JSValueConst *argv, int magic)
45925
0
{
45926
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
45927
0
    JSValueConst func, this_arg;
45928
0
    JSValue ret, args[3];
45929
0
    struct list_head *el;
45930
0
    JSMapRecord *mr;
45931
45932
0
    if (!s)
45933
0
        return JS_EXCEPTION;
45934
0
    func = argv[0];
45935
0
    if (argc > 1)
45936
0
        this_arg = argv[1];
45937
0
    else
45938
0
        this_arg = JS_UNDEFINED;
45939
0
    if (check_function(ctx, func))
45940
0
        return JS_EXCEPTION;
45941
    /* Note: the list can be modified while traversing it, but the
45942
       current element is locked */
45943
0
    el = s->records.next;
45944
0
    while (el != &s->records) {
45945
0
        mr = list_entry(el, JSMapRecord, link);
45946
0
        if (!mr->empty) {
45947
0
            mr->ref_count++;
45948
            /* must duplicate in case the record is deleted */
45949
0
            args[1] = JS_DupValue(ctx, mr->key);
45950
0
            if (magic)
45951
0
                args[0] = args[1];
45952
0
            else
45953
0
                args[0] = JS_DupValue(ctx, mr->value);
45954
0
            args[2] = (JSValue)this_val;
45955
0
            ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args);
45956
0
            JS_FreeValue(ctx, args[0]);
45957
0
            if (!magic)
45958
0
                JS_FreeValue(ctx, args[1]);
45959
0
            el = el->next;
45960
0
            map_decref_record(ctx->rt, mr);
45961
0
            if (JS_IsException(ret))
45962
0
                return ret;
45963
0
            JS_FreeValue(ctx, ret);
45964
0
        } else {
45965
0
            el = el->next;
45966
0
        }
45967
0
    }
45968
0
    return JS_UNDEFINED;
45969
0
}
45970
45971
static void js_map_finalizer(JSRuntime *rt, JSValue val)
45972
0
{
45973
0
    JSObject *p;
45974
0
    JSMapState *s;
45975
0
    struct list_head *el, *el1;
45976
0
    JSMapRecord *mr;
45977
45978
0
    p = JS_VALUE_GET_OBJ(val);
45979
0
    s = p->u.map_state;
45980
0
    if (s) {
45981
        /* if the object is deleted we are sure that no iterator is
45982
           using it */
45983
0
        list_for_each_safe(el, el1, &s->records) {
45984
0
            mr = list_entry(el, JSMapRecord, link);
45985
0
            if (!mr->empty) {
45986
0
                if (s->is_weak)
45987
0
                    delete_weak_ref(rt, mr);
45988
0
                else
45989
0
                    JS_FreeValueRT(rt, mr->key);
45990
0
                JS_FreeValueRT(rt, mr->value);
45991
0
            }
45992
0
            js_free_rt(rt, mr);
45993
0
        }
45994
0
        js_free_rt(rt, s->hash_table);
45995
0
        js_free_rt(rt, s);
45996
0
    }
45997
0
}
45998
45999
static void js_map_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
46000
0
{
46001
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
46002
0
    JSMapState *s;
46003
0
    struct list_head *el;
46004
0
    JSMapRecord *mr;
46005
46006
0
    s = p->u.map_state;
46007
0
    if (s) {
46008
0
        list_for_each(el, &s->records) {
46009
0
            mr = list_entry(el, JSMapRecord, link);
46010
0
            if (!s->is_weak)
46011
0
                JS_MarkValue(rt, mr->key, mark_func);
46012
0
            JS_MarkValue(rt, mr->value, mark_func);
46013
0
        }
46014
0
    }
46015
0
}
46016
46017
/* Map Iterator */
46018
46019
typedef struct JSMapIteratorData {
46020
    JSValue obj;
46021
    JSIteratorKindEnum kind;
46022
    JSMapRecord *cur_record;
46023
} JSMapIteratorData;
46024
46025
static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val)
46026
0
{
46027
0
    JSObject *p;
46028
0
    JSMapIteratorData *it;
46029
46030
0
    p = JS_VALUE_GET_OBJ(val);
46031
0
    it = p->u.map_iterator_data;
46032
0
    if (it) {
46033
        /* During the GC sweep phase the Map finalizer may be
46034
           called before the Map iterator finalizer */
46035
0
        if (JS_IsLiveObject(rt, it->obj) && it->cur_record) {
46036
0
            map_decref_record(rt, it->cur_record);
46037
0
        }
46038
0
        JS_FreeValueRT(rt, it->obj);
46039
0
        js_free_rt(rt, it);
46040
0
    }
46041
0
}
46042
46043
static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
46044
                                 JS_MarkFunc *mark_func)
46045
0
{
46046
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
46047
0
    JSMapIteratorData *it;
46048
0
    it = p->u.map_iterator_data;
46049
0
    if (it) {
46050
        /* the record is already marked by the object */
46051
0
        JS_MarkValue(rt, it->obj, mark_func);
46052
0
    }
46053
0
}
46054
46055
static JSValue js_create_map_iterator(JSContext *ctx, JSValueConst this_val,
46056
                                      int argc, JSValueConst *argv, int magic)
46057
0
{
46058
0
    JSIteratorKindEnum kind;
46059
0
    JSMapState *s;
46060
0
    JSMapIteratorData *it;
46061
0
    JSValue enum_obj;
46062
46063
0
    kind = magic >> 2;
46064
0
    magic &= 3;
46065
0
    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
46066
0
    if (!s)
46067
0
        return JS_EXCEPTION;
46068
0
    enum_obj = JS_NewObjectClass(ctx, JS_CLASS_MAP_ITERATOR + magic);
46069
0
    if (JS_IsException(enum_obj))
46070
0
        goto fail;
46071
0
    it = js_malloc(ctx, sizeof(*it));
46072
0
    if (!it) {
46073
0
        JS_FreeValue(ctx, enum_obj);
46074
0
        goto fail;
46075
0
    }
46076
0
    it->obj = JS_DupValue(ctx, this_val);
46077
0
    it->kind = kind;
46078
0
    it->cur_record = NULL;
46079
0
    JS_SetOpaque(enum_obj, it);
46080
0
    return enum_obj;
46081
0
 fail:
46082
0
    return JS_EXCEPTION;
46083
0
}
46084
46085
static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val,
46086
                                    int argc, JSValueConst *argv,
46087
                                    BOOL *pdone, int magic)
46088
0
{
46089
0
    JSMapIteratorData *it;
46090
0
    JSMapState *s;
46091
0
    JSMapRecord *mr;
46092
0
    struct list_head *el;
46093
46094
0
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP_ITERATOR + magic);
46095
0
    if (!it) {
46096
0
        *pdone = FALSE;
46097
0
        return JS_EXCEPTION;
46098
0
    }
46099
0
    if (JS_IsUndefined(it->obj))
46100
0
        goto done;
46101
0
    s = JS_GetOpaque(it->obj, JS_CLASS_MAP + magic);
46102
0
    assert(s != NULL);
46103
0
    if (!it->cur_record) {
46104
0
        el = s->records.next;
46105
0
    } else {
46106
0
        mr = it->cur_record;
46107
0
        el = mr->link.next;
46108
0
        map_decref_record(ctx->rt, mr); /* the record can be freed here */
46109
0
    }
46110
0
    for(;;) {
46111
0
        if (el == &s->records) {
46112
            /* no more record  */
46113
0
            it->cur_record = NULL;
46114
0
            JS_FreeValue(ctx, it->obj);
46115
0
            it->obj = JS_UNDEFINED;
46116
0
        done:
46117
            /* end of enumeration */
46118
0
            *pdone = TRUE;
46119
0
            return JS_UNDEFINED;
46120
0
        }
46121
0
        mr = list_entry(el, JSMapRecord, link);
46122
0
        if (!mr->empty)
46123
0
            break;
46124
        /* get the next record */
46125
0
        el = mr->link.next;
46126
0
    }
46127
46128
    /* lock the record so that it won't be freed */
46129
0
    mr->ref_count++;
46130
0
    it->cur_record = mr;
46131
0
    *pdone = FALSE;
46132
46133
0
    if (it->kind == JS_ITERATOR_KIND_KEY) {
46134
0
        return JS_DupValue(ctx, mr->key);
46135
0
    } else {
46136
0
        JSValueConst args[2];
46137
0
        args[0] = mr->key;
46138
0
        if (magic)
46139
0
            args[1] = mr->key;
46140
0
        else
46141
0
            args[1] = mr->value;
46142
0
        if (it->kind == JS_ITERATOR_KIND_VALUE) {
46143
0
            return JS_DupValue(ctx, args[1]);
46144
0
        } else {
46145
0
            return js_create_array(ctx, 2, args);
46146
0
        }
46147
0
    }
46148
0
}
46149
46150
static const JSCFunctionListEntry js_map_funcs[] = {
46151
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
46152
};
46153
46154
static const JSCFunctionListEntry js_map_proto_funcs[] = {
46155
    JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, 0 ),
46156
    JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, 0 ),
46157
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, 0 ),
46158
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, 0 ),
46159
    JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, 0 ),
46160
    JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, 0),
46161
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, 0 ),
46162
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_VALUE << 2) | 0 ),
46163
    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | 0 ),
46164
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | 0 ),
46165
    JS_ALIAS_DEF("[Symbol.iterator]", "entries" ),
46166
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map", JS_PROP_CONFIGURABLE ),
46167
};
46168
46169
static const JSCFunctionListEntry js_map_iterator_proto_funcs[] = {
46170
    JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, 0 ),
46171
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map Iterator", JS_PROP_CONFIGURABLE ),
46172
};
46173
46174
static const JSCFunctionListEntry js_set_proto_funcs[] = {
46175
    JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET ),
46176
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET ),
46177
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET ),
46178
    JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, MAGIC_SET ),
46179
    JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, MAGIC_SET ),
46180
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, MAGIC_SET ),
46181
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | MAGIC_SET ),
46182
    JS_ALIAS_DEF("keys", "values" ),
46183
    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
46184
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | MAGIC_SET ),
46185
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set", JS_PROP_CONFIGURABLE ),
46186
};
46187
46188
static const JSCFunctionListEntry js_set_iterator_proto_funcs[] = {
46189
    JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, MAGIC_SET ),
46190
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set Iterator", JS_PROP_CONFIGURABLE ),
46191
};
46192
46193
static const JSCFunctionListEntry js_weak_map_proto_funcs[] = {
46194
    JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, MAGIC_WEAK ),
46195
    JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, MAGIC_WEAK ),
46196
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_WEAK ),
46197
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_WEAK ),
46198
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakMap", JS_PROP_CONFIGURABLE ),
46199
};
46200
46201
static const JSCFunctionListEntry js_weak_set_proto_funcs[] = {
46202
    JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET | MAGIC_WEAK ),
46203
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET | MAGIC_WEAK ),
46204
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET | MAGIC_WEAK ),
46205
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakSet", JS_PROP_CONFIGURABLE ),
46206
};
46207
46208
static const JSCFunctionListEntry * const js_map_proto_funcs_ptr[6] = {
46209
    js_map_proto_funcs,
46210
    js_set_proto_funcs,
46211
    js_weak_map_proto_funcs,
46212
    js_weak_set_proto_funcs,
46213
    js_map_iterator_proto_funcs,
46214
    js_set_iterator_proto_funcs,
46215
};
46216
46217
static const uint8_t js_map_proto_funcs_count[6] = {
46218
    countof(js_map_proto_funcs),
46219
    countof(js_set_proto_funcs),
46220
    countof(js_weak_map_proto_funcs),
46221
    countof(js_weak_set_proto_funcs),
46222
    countof(js_map_iterator_proto_funcs),
46223
    countof(js_set_iterator_proto_funcs),
46224
};
46225
46226
void JS_AddIntrinsicMapSet(JSContext *ctx)
46227
2
{
46228
2
    int i;
46229
2
    JSValue obj1;
46230
2
    char buf[ATOM_GET_STR_BUF_SIZE];
46231
46232
10
    for(i = 0; i < 4; i++) {
46233
8
        const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf),
46234
8
                                         JS_ATOM_Map + i);
46235
8
        ctx->class_proto[JS_CLASS_MAP + i] = JS_NewObject(ctx);
46236
8
        JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP + i],
46237
8
                                   js_map_proto_funcs_ptr[i],
46238
8
                                   js_map_proto_funcs_count[i]);
46239
8
        obj1 = JS_NewCFunctionMagic(ctx, js_map_constructor, name, 0,
46240
8
                                    JS_CFUNC_constructor_magic, i);
46241
8
        if (i < 2) {
46242
4
            JS_SetPropertyFunctionList(ctx, obj1, js_map_funcs,
46243
4
                                       countof(js_map_funcs));
46244
4
        }
46245
8
        JS_NewGlobalCConstructor2(ctx, obj1, name, ctx->class_proto[JS_CLASS_MAP + i]);
46246
8
    }
46247
46248
6
    for(i = 0; i < 2; i++) {
46249
4
        ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] =
46250
4
            JS_NewObjectProto(ctx, ctx->iterator_proto);
46251
4
        JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP_ITERATOR + i],
46252
4
                                   js_map_proto_funcs_ptr[i + 4],
46253
4
                                   js_map_proto_funcs_count[i + 4]);
46254
4
    }
46255
2
}
46256
46257
/* Generator */
46258
static const JSCFunctionListEntry js_generator_function_proto_funcs[] = {
46259
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "GeneratorFunction", JS_PROP_CONFIGURABLE),
46260
};
46261
46262
static const JSCFunctionListEntry js_generator_proto_funcs[] = {
46263
    JS_ITERATOR_NEXT_DEF("next", 1, js_generator_next, GEN_MAGIC_NEXT ),
46264
    JS_ITERATOR_NEXT_DEF("return", 1, js_generator_next, GEN_MAGIC_RETURN ),
46265
    JS_ITERATOR_NEXT_DEF("throw", 1, js_generator_next, GEN_MAGIC_THROW ),
46266
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Generator", JS_PROP_CONFIGURABLE),
46267
};
46268
46269
/* Promise */
46270
46271
typedef enum JSPromiseStateEnum {
46272
    JS_PROMISE_PENDING,
46273
    JS_PROMISE_FULFILLED,
46274
    JS_PROMISE_REJECTED,
46275
} JSPromiseStateEnum;
46276
46277
typedef struct JSPromiseData {
46278
    JSPromiseStateEnum promise_state;
46279
    /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */
46280
    struct list_head promise_reactions[2];
46281
    BOOL is_handled; /* Note: only useful to debug */
46282
    JSValue promise_result;
46283
} JSPromiseData;
46284
46285
typedef struct JSPromiseFunctionDataResolved {
46286
    int ref_count;
46287
    BOOL already_resolved;
46288
} JSPromiseFunctionDataResolved;
46289
46290
typedef struct JSPromiseFunctionData {
46291
    JSValue promise;
46292
    JSPromiseFunctionDataResolved *presolved;
46293
} JSPromiseFunctionData;
46294
46295
typedef struct JSPromiseReactionData {
46296
    struct list_head link; /* not used in promise_reaction_job */
46297
    JSValue resolving_funcs[2];
46298
    JSValue handler;
46299
} JSPromiseReactionData;
46300
46301
static int js_create_resolving_functions(JSContext *ctx, JSValue *args,
46302
                                         JSValueConst promise);
46303
46304
static void promise_reaction_data_free(JSRuntime *rt,
46305
                                       JSPromiseReactionData *rd)
46306
0
{
46307
0
    JS_FreeValueRT(rt, rd->resolving_funcs[0]);
46308
0
    JS_FreeValueRT(rt, rd->resolving_funcs[1]);
46309
0
    JS_FreeValueRT(rt, rd->handler);
46310
0
    js_free_rt(rt, rd);
46311
0
}
46312
46313
static JSValue promise_reaction_job(JSContext *ctx, int argc,
46314
                                    JSValueConst *argv)
46315
0
{
46316
0
    JSValueConst handler, arg, func;
46317
0
    JSValue res, res2;
46318
0
    BOOL is_reject;
46319
46320
0
    assert(argc == 5);
46321
0
    handler = argv[2];
46322
0
    is_reject = JS_ToBool(ctx, argv[3]);
46323
0
    arg = argv[4];
46324
#ifdef DUMP_PROMISE
46325
    printf("promise_reaction_job: is_reject=%d\n", is_reject);
46326
#endif
46327
46328
0
    if (JS_IsUndefined(handler)) {
46329
0
        if (is_reject) {
46330
0
            res = JS_Throw(ctx, JS_DupValue(ctx, arg));
46331
0
        } else {
46332
0
            res = JS_DupValue(ctx, arg);
46333
0
        }
46334
0
    } else {
46335
0
        res = JS_Call(ctx, handler, JS_UNDEFINED, 1, &arg);
46336
0
    }
46337
0
    is_reject = JS_IsException(res);
46338
0
    if (is_reject)
46339
0
        res = JS_GetException(ctx);
46340
0
    func = argv[is_reject];
46341
    /* as an extension, we support undefined as value to avoid
46342
       creating a dummy promise in the 'await' implementation of async
46343
       functions */
46344
0
    if (!JS_IsUndefined(func)) {
46345
0
        res2 = JS_Call(ctx, func, JS_UNDEFINED,
46346
0
                       1, (JSValueConst *)&res);
46347
0
    } else {
46348
0
        res2 = JS_UNDEFINED;
46349
0
    }
46350
0
    JS_FreeValue(ctx, res);
46351
46352
0
    return res2;
46353
0
}
46354
46355
void JS_SetHostPromiseRejectionTracker(JSRuntime *rt,
46356
                                       JSHostPromiseRejectionTracker *cb,
46357
                                       void *opaque)
46358
0
{
46359
0
    rt->host_promise_rejection_tracker = cb;
46360
0
    rt->host_promise_rejection_tracker_opaque = opaque;
46361
0
}
46362
46363
static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise,
46364
                                      JSValueConst value, BOOL is_reject)
46365
0
{
46366
0
    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
46367
0
    struct list_head *el, *el1;
46368
0
    JSPromiseReactionData *rd;
46369
0
    JSValueConst args[5];
46370
46371
0
    if (!s || s->promise_state != JS_PROMISE_PENDING)
46372
0
        return; /* should never happen */
46373
0
    set_value(ctx, &s->promise_result, JS_DupValue(ctx, value));
46374
0
    s->promise_state = JS_PROMISE_FULFILLED + is_reject;
46375
#ifdef DUMP_PROMISE
46376
    printf("fulfill_or_reject_promise: is_reject=%d\n", is_reject);
46377
#endif
46378
0
    if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
46379
0
        JSRuntime *rt = ctx->rt;
46380
0
        if (rt->host_promise_rejection_tracker) {
46381
0
            rt->host_promise_rejection_tracker(ctx, promise, value, FALSE,
46382
0
                                               rt->host_promise_rejection_tracker_opaque);
46383
0
        }
46384
0
    }
46385
46386
0
    list_for_each_safe(el, el1, &s->promise_reactions[is_reject]) {
46387
0
        rd = list_entry(el, JSPromiseReactionData, link);
46388
0
        args[0] = rd->resolving_funcs[0];
46389
0
        args[1] = rd->resolving_funcs[1];
46390
0
        args[2] = rd->handler;
46391
0
        args[3] = JS_NewBool(ctx, is_reject);
46392
0
        args[4] = value;
46393
0
        JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
46394
0
        list_del(&rd->link);
46395
0
        promise_reaction_data_free(ctx->rt, rd);
46396
0
    }
46397
46398
0
    list_for_each_safe(el, el1, &s->promise_reactions[1 - is_reject]) {
46399
0
        rd = list_entry(el, JSPromiseReactionData, link);
46400
0
        list_del(&rd->link);
46401
0
        promise_reaction_data_free(ctx->rt, rd);
46402
0
    }
46403
0
}
46404
46405
static void reject_promise(JSContext *ctx, JSValueConst promise,
46406
                           JSValueConst value)
46407
0
{
46408
0
    fulfill_or_reject_promise(ctx, promise, value, TRUE);
46409
0
}
46410
46411
static JSValue js_promise_resolve_thenable_job(JSContext *ctx,
46412
                                               int argc, JSValueConst *argv)
46413
0
{
46414
0
    JSValueConst promise, thenable, then;
46415
0
    JSValue args[2], res;
46416
46417
#ifdef DUMP_PROMISE
46418
    printf("js_promise_resolve_thenable_job\n");
46419
#endif
46420
0
    assert(argc == 3);
46421
0
    promise = argv[0];
46422
0
    thenable = argv[1];
46423
0
    then = argv[2];
46424
0
    if (js_create_resolving_functions(ctx, args, promise) < 0)
46425
0
        return JS_EXCEPTION;
46426
0
    res = JS_Call(ctx, then, thenable, 2, (JSValueConst *)args);
46427
0
    if (JS_IsException(res)) {
46428
0
        JSValue error = JS_GetException(ctx);
46429
0
        res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
46430
0
        JS_FreeValue(ctx, error);
46431
0
    }
46432
0
    JS_FreeValue(ctx, args[0]);
46433
0
    JS_FreeValue(ctx, args[1]);
46434
0
    return res;
46435
0
}
46436
46437
static void js_promise_resolve_function_free_resolved(JSRuntime *rt,
46438
                                                      JSPromiseFunctionDataResolved *sr)
46439
81.9k
{
46440
81.9k
    if (--sr->ref_count == 0) {
46441
0
        js_free_rt(rt, sr);
46442
0
    }
46443
81.9k
}
46444
46445
static int js_create_resolving_functions(JSContext *ctx,
46446
                                         JSValue *resolving_funcs,
46447
                                         JSValueConst promise)
46448
46449
81.9k
{
46450
81.9k
    JSValue obj;
46451
81.9k
    JSPromiseFunctionData *s;
46452
81.9k
    JSPromiseFunctionDataResolved *sr;
46453
81.9k
    int i, ret;
46454
46455
81.9k
    sr = js_malloc(ctx, sizeof(*sr));
46456
81.9k
    if (!sr)
46457
0
        return -1;
46458
81.9k
    sr->ref_count = 1;
46459
81.9k
    sr->already_resolved = FALSE; /* must be shared between the two functions */
46460
81.9k
    ret = 0;
46461
245k
    for(i = 0; i < 2; i++) {
46462
163k
        obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
46463
163k
                                     JS_CLASS_PROMISE_RESOLVE_FUNCTION + i);
46464
163k
        if (JS_IsException(obj))
46465
0
            goto fail;
46466
163k
        s = js_malloc(ctx, sizeof(*s));
46467
163k
        if (!s) {
46468
0
            JS_FreeValue(ctx, obj);
46469
0
        fail:
46470
46471
0
            if (i != 0)
46472
0
                JS_FreeValue(ctx, resolving_funcs[0]);
46473
0
            ret = -1;
46474
0
            break;
46475
0
        }
46476
163k
        sr->ref_count++;
46477
163k
        s->presolved = sr;
46478
163k
        s->promise = JS_DupValue(ctx, promise);
46479
163k
        JS_SetOpaque(obj, s);
46480
163k
        js_function_set_properties(ctx, obj, JS_ATOM_empty_string, 1);
46481
163k
        resolving_funcs[i] = obj;
46482
163k
    }
46483
81.9k
    js_promise_resolve_function_free_resolved(ctx->rt, sr);
46484
81.9k
    return ret;
46485
81.9k
}
46486
46487
static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val)
46488
0
{
46489
0
    JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
46490
0
    if (s) {
46491
0
        js_promise_resolve_function_free_resolved(rt, s->presolved);
46492
0
        JS_FreeValueRT(rt, s->promise);
46493
0
        js_free_rt(rt, s);
46494
0
    }
46495
0
}
46496
46497
static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
46498
                                             JS_MarkFunc *mark_func)
46499
1.33M
{
46500
1.33M
    JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
46501
1.33M
    if (s) {
46502
1.33M
        JS_MarkValue(rt, s->promise, mark_func);
46503
1.33M
    }
46504
1.33M
}
46505
46506
static JSValue js_promise_resolve_function_call(JSContext *ctx,
46507
                                                JSValueConst func_obj,
46508
                                                JSValueConst this_val,
46509
                                                int argc, JSValueConst *argv,
46510
                                                int flags)
46511
0
{
46512
0
    JSObject *p = JS_VALUE_GET_OBJ(func_obj);
46513
0
    JSPromiseFunctionData *s;
46514
0
    JSValueConst resolution, args[3];
46515
0
    JSValue then;
46516
0
    BOOL is_reject;
46517
46518
0
    s = p->u.promise_function_data;
46519
0
    if (!s || s->presolved->already_resolved)
46520
0
        return JS_UNDEFINED;
46521
0
    s->presolved->already_resolved = TRUE;
46522
0
    is_reject = p->class_id - JS_CLASS_PROMISE_RESOLVE_FUNCTION;
46523
0
    if (argc > 0)
46524
0
        resolution = argv[0];
46525
0
    else
46526
0
        resolution = JS_UNDEFINED;
46527
#ifdef DUMP_PROMISE
46528
    printf("js_promise_resolving_function_call: is_reject=%d resolution=", is_reject);
46529
    JS_DumpValue(ctx, resolution);
46530
    printf("\n");
46531
#endif
46532
0
    if (is_reject || !JS_IsObject(resolution)) {
46533
0
        goto done;
46534
0
    } else if (js_same_value(ctx, resolution, s->promise)) {
46535
0
        JS_ThrowTypeError(ctx, "promise self resolution");
46536
0
        goto fail_reject;
46537
0
    }
46538
0
    then = JS_GetProperty(ctx, resolution, JS_ATOM_then);
46539
0
    if (JS_IsException(then)) {
46540
0
        JSValue error;
46541
0
    fail_reject:
46542
0
        error = JS_GetException(ctx);
46543
0
        reject_promise(ctx, s->promise, error);
46544
0
        JS_FreeValue(ctx, error);
46545
0
    } else if (!JS_IsFunction(ctx, then)) {
46546
0
        JS_FreeValue(ctx, then);
46547
0
    done:
46548
0
        fulfill_or_reject_promise(ctx, s->promise, resolution, is_reject);
46549
0
    } else {
46550
0
        args[0] = s->promise;
46551
0
        args[1] = resolution;
46552
0
        args[2] = then;
46553
0
        JS_EnqueueJob(ctx, js_promise_resolve_thenable_job, 3, args);
46554
0
        JS_FreeValue(ctx, then);
46555
0
    }
46556
0
    return JS_UNDEFINED;
46557
0
}
46558
46559
static void js_promise_finalizer(JSRuntime *rt, JSValue val)
46560
0
{
46561
0
    JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
46562
0
    struct list_head *el, *el1;
46563
0
    int i;
46564
46565
0
    if (!s)
46566
0
        return;
46567
0
    for(i = 0; i < 2; i++) {
46568
0
        list_for_each_safe(el, el1, &s->promise_reactions[i]) {
46569
0
            JSPromiseReactionData *rd =
46570
0
                list_entry(el, JSPromiseReactionData, link);
46571
0
            promise_reaction_data_free(rt, rd);
46572
0
        }
46573
0
    }
46574
0
    JS_FreeValueRT(rt, s->promise_result);
46575
0
    js_free_rt(rt, s);
46576
0
}
46577
46578
static void js_promise_mark(JSRuntime *rt, JSValueConst val,
46579
                            JS_MarkFunc *mark_func)
46580
666k
{
46581
666k
    JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
46582
666k
    struct list_head *el;
46583
666k
    int i;
46584
46585
666k
    if (!s)
46586
0
        return;
46587
2.00M
    for(i = 0; i < 2; i++) {
46588
1.33M
        list_for_each(el, &s->promise_reactions[i]) {
46589
0
            JSPromiseReactionData *rd =
46590
0
                list_entry(el, JSPromiseReactionData, link);
46591
0
            JS_MarkValue(rt, rd->resolving_funcs[0], mark_func);
46592
0
            JS_MarkValue(rt, rd->resolving_funcs[1], mark_func);
46593
0
            JS_MarkValue(rt, rd->handler, mark_func);
46594
0
        }
46595
1.33M
    }
46596
666k
    JS_MarkValue(rt, s->promise_result, mark_func);
46597
666k
}
46598
46599
static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target,
46600
                                      int argc, JSValueConst *argv)
46601
81.9k
{
46602
81.9k
    JSValueConst executor;
46603
81.9k
    JSValue obj;
46604
81.9k
    JSPromiseData *s;
46605
81.9k
    JSValue args[2], ret;
46606
81.9k
    int i;
46607
46608
81.9k
    executor = argv[0];
46609
81.9k
    if (check_function(ctx, executor))
46610
0
        return JS_EXCEPTION;
46611
81.9k
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_PROMISE);
46612
81.9k
    if (JS_IsException(obj))
46613
0
        return JS_EXCEPTION;
46614
81.9k
    s = js_mallocz(ctx, sizeof(*s));
46615
81.9k
    if (!s)
46616
0
        goto fail;
46617
81.9k
    s->promise_state = JS_PROMISE_PENDING;
46618
81.9k
    s->is_handled = FALSE;
46619
245k
    for(i = 0; i < 2; i++)
46620
163k
        init_list_head(&s->promise_reactions[i]);
46621
81.9k
    s->promise_result = JS_UNDEFINED;
46622
81.9k
    JS_SetOpaque(obj, s);
46623
81.9k
    if (js_create_resolving_functions(ctx, args, obj))
46624
0
        goto fail;
46625
81.9k
    ret = JS_Call(ctx, executor, JS_UNDEFINED, 2, (JSValueConst *)args);
46626
81.9k
    if (JS_IsException(ret)) {
46627
0
        JSValue ret2, error;
46628
0
        error = JS_GetException(ctx);
46629
0
        ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
46630
0
        JS_FreeValue(ctx, error);
46631
0
        if (JS_IsException(ret2))
46632
0
            goto fail1;
46633
0
        JS_FreeValue(ctx, ret2);
46634
0
    }
46635
81.9k
    JS_FreeValue(ctx, ret);
46636
81.9k
    JS_FreeValue(ctx, args[0]);
46637
81.9k
    JS_FreeValue(ctx, args[1]);
46638
81.9k
    return obj;
46639
0
 fail1:
46640
0
    JS_FreeValue(ctx, args[0]);
46641
0
    JS_FreeValue(ctx, args[1]);
46642
0
 fail:
46643
0
    JS_FreeValue(ctx, obj);
46644
0
    return JS_EXCEPTION;
46645
0
}
46646
46647
static JSValue js_promise_executor(JSContext *ctx,
46648
                                   JSValueConst this_val,
46649
                                   int argc, JSValueConst *argv,
46650
                                   int magic, JSValue *func_data)
46651
81.9k
{
46652
81.9k
    int i;
46653
46654
245k
    for(i = 0; i < 2; i++) {
46655
163k
        if (!JS_IsUndefined(func_data[i]))
46656
0
            return JS_ThrowTypeError(ctx, "resolving function already set");
46657
163k
        func_data[i] = JS_DupValue(ctx, argv[i]);
46658
163k
    }
46659
81.9k
    return JS_UNDEFINED;
46660
81.9k
}
46661
46662
static JSValue js_promise_executor_new(JSContext *ctx)
46663
81.9k
{
46664
81.9k
    JSValueConst func_data[2];
46665
46666
81.9k
    func_data[0] = JS_UNDEFINED;
46667
81.9k
    func_data[1] = JS_UNDEFINED;
46668
81.9k
    return JS_NewCFunctionData(ctx, js_promise_executor, 2,
46669
81.9k
                               0, 2, func_data);
46670
81.9k
}
46671
46672
static JSValue js_new_promise_capability(JSContext *ctx,
46673
                                         JSValue *resolving_funcs,
46674
                                         JSValueConst ctor)
46675
81.9k
{
46676
81.9k
    JSValue executor, result_promise;
46677
81.9k
    JSCFunctionDataRecord *s;
46678
81.9k
    int i;
46679
46680
81.9k
    executor = js_promise_executor_new(ctx);
46681
81.9k
    if (JS_IsException(executor))
46682
0
        return executor;
46683
46684
81.9k
    if (JS_IsUndefined(ctor)) {
46685
81.9k
        result_promise = js_promise_constructor(ctx, ctor, 1,
46686
81.9k
                                                (JSValueConst *)&executor);
46687
81.9k
    } else {
46688
0
        result_promise = JS_CallConstructor(ctx, ctor, 1,
46689
0
                                            (JSValueConst *)&executor);
46690
0
    }
46691
81.9k
    if (JS_IsException(result_promise))
46692
0
        goto fail;
46693
81.9k
    s = JS_GetOpaque(executor, JS_CLASS_C_FUNCTION_DATA);
46694
245k
    for(i = 0; i < 2; i++) {
46695
163k
        if (check_function(ctx, s->data[i]))
46696
0
            goto fail;
46697
163k
    }
46698
245k
    for(i = 0; i < 2; i++)
46699
163k
        resolving_funcs[i] = JS_DupValue(ctx, s->data[i]);
46700
81.9k
    JS_FreeValue(ctx, executor);
46701
81.9k
    return result_promise;
46702
0
 fail:
46703
0
    JS_FreeValue(ctx, executor);
46704
0
    JS_FreeValue(ctx, result_promise);
46705
0
    return JS_EXCEPTION;
46706
81.9k
}
46707
46708
JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs)
46709
81.9k
{
46710
81.9k
    return js_new_promise_capability(ctx, resolving_funcs, JS_UNDEFINED);
46711
81.9k
}
46712
46713
static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
46714
                                  int argc, JSValueConst *argv, int magic)
46715
0
{
46716
0
    JSValue result_promise, resolving_funcs[2], ret;
46717
0
    BOOL is_reject = magic;
46718
46719
0
    if (!JS_IsObject(this_val))
46720
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
46721
0
    if (!is_reject && JS_GetOpaque(argv[0], JS_CLASS_PROMISE)) {
46722
0
        JSValue ctor;
46723
0
        BOOL is_same;
46724
0
        ctor = JS_GetProperty(ctx, argv[0], JS_ATOM_constructor);
46725
0
        if (JS_IsException(ctor))
46726
0
            return ctor;
46727
0
        is_same = js_same_value(ctx, ctor, this_val);
46728
0
        JS_FreeValue(ctx, ctor);
46729
0
        if (is_same)
46730
0
            return JS_DupValue(ctx, argv[0]);
46731
0
    }
46732
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
46733
0
    if (JS_IsException(result_promise))
46734
0
        return result_promise;
46735
0
    ret = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, argv);
46736
0
    JS_FreeValue(ctx, resolving_funcs[0]);
46737
0
    JS_FreeValue(ctx, resolving_funcs[1]);
46738
0
    if (JS_IsException(ret)) {
46739
0
        JS_FreeValue(ctx, result_promise);
46740
0
        return ret;
46741
0
    }
46742
0
    JS_FreeValue(ctx, ret);
46743
0
    return result_promise;
46744
0
}
46745
46746
#if 0
46747
static JSValue js_promise___newPromiseCapability(JSContext *ctx,
46748
                                                 JSValueConst this_val,
46749
                                                 int argc, JSValueConst *argv)
46750
{
46751
    JSValue result_promise, resolving_funcs[2], obj;
46752
    JSValueConst ctor;
46753
    ctor = argv[0];
46754
    if (!JS_IsObject(ctor))
46755
        return JS_ThrowTypeErrorNotAnObject(ctx);
46756
    result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
46757
    if (JS_IsException(result_promise))
46758
        return result_promise;
46759
    obj = JS_NewObject(ctx);
46760
    if (JS_IsException(obj)) {
46761
        JS_FreeValue(ctx, resolving_funcs[0]);
46762
        JS_FreeValue(ctx, resolving_funcs[1]);
46763
        JS_FreeValue(ctx, result_promise);
46764
        return JS_EXCEPTION;
46765
    }
46766
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_promise, result_promise, JS_PROP_C_W_E);
46767
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_resolve, resolving_funcs[0], JS_PROP_C_W_E);
46768
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1], JS_PROP_C_W_E);
46769
    return obj;
46770
}
46771
#endif
46772
46773
static __exception int remainingElementsCount_add(JSContext *ctx,
46774
                                                  JSValueConst resolve_element_env,
46775
                                                  int addend)
46776
0
{
46777
0
    JSValue val;
46778
0
    int remainingElementsCount;
46779
46780
0
    val = JS_GetPropertyUint32(ctx, resolve_element_env, 0);
46781
0
    if (JS_IsException(val))
46782
0
        return -1;
46783
0
    if (JS_ToInt32Free(ctx, &remainingElementsCount, val))
46784
0
        return -1;
46785
0
    remainingElementsCount += addend;
46786
0
    if (JS_SetPropertyUint32(ctx, resolve_element_env, 0,
46787
0
                             JS_NewInt32(ctx, remainingElementsCount)) < 0)
46788
0
        return -1;
46789
0
    return (remainingElementsCount == 0);
46790
0
}
46791
46792
#define PROMISE_MAGIC_all        0
46793
0
#define PROMISE_MAGIC_allSettled 1
46794
0
#define PROMISE_MAGIC_any        2
46795
46796
static JSValue js_promise_all_resolve_element(JSContext *ctx,
46797
                                              JSValueConst this_val,
46798
                                              int argc, JSValueConst *argv,
46799
                                              int magic,
46800
                                              JSValue *func_data)
46801
0
{
46802
0
    int resolve_type = magic & 3;
46803
0
    int is_reject = magic & 4;
46804
0
    BOOL alreadyCalled = JS_ToBool(ctx, func_data[0]);
46805
0
    JSValueConst values = func_data[2];
46806
0
    JSValueConst resolve = func_data[3];
46807
0
    JSValueConst resolve_element_env = func_data[4];
46808
0
    JSValue ret, obj;
46809
0
    int is_zero, index;
46810
    
46811
0
    if (JS_ToInt32(ctx, &index, func_data[1]))
46812
0
        return JS_EXCEPTION;
46813
0
    if (alreadyCalled)
46814
0
        return JS_UNDEFINED;
46815
0
    func_data[0] = JS_NewBool(ctx, TRUE);
46816
46817
0
    if (resolve_type == PROMISE_MAGIC_allSettled) {
46818
0
        JSValue str;
46819
        
46820
0
        obj = JS_NewObject(ctx);
46821
0
        if (JS_IsException(obj))
46822
0
            return JS_EXCEPTION;
46823
0
        str = JS_NewString(ctx, is_reject ? "rejected" : "fulfilled");
46824
0
        if (JS_IsException(str))
46825
0
            goto fail1;
46826
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_status,
46827
0
                                   str,
46828
0
                                   JS_PROP_C_W_E) < 0)
46829
0
            goto fail1;
46830
0
        if (JS_DefinePropertyValue(ctx, obj,
46831
0
                                   is_reject ? JS_ATOM_reason : JS_ATOM_value,
46832
0
                                   JS_DupValue(ctx, argv[0]),
46833
0
                                   JS_PROP_C_W_E) < 0) {
46834
0
        fail1:
46835
0
            JS_FreeValue(ctx, obj);
46836
0
            return JS_EXCEPTION;
46837
0
        }
46838
0
    } else {
46839
0
        obj = JS_DupValue(ctx, argv[0]);
46840
0
    }
46841
0
    if (JS_DefinePropertyValueUint32(ctx, values, index,
46842
0
                                     obj, JS_PROP_C_W_E) < 0)
46843
0
        return JS_EXCEPTION;
46844
    
46845
0
    is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
46846
0
    if (is_zero < 0)
46847
0
        return JS_EXCEPTION;
46848
0
    if (is_zero) {
46849
0
        if (resolve_type == PROMISE_MAGIC_any) {
46850
0
            JSValue error;
46851
0
            error = js_aggregate_error_constructor(ctx, values);
46852
0
            if (JS_IsException(error))
46853
0
                return JS_EXCEPTION;
46854
0
            ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&error);
46855
0
            JS_FreeValue(ctx, error);
46856
0
        } else {
46857
0
            ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values);
46858
0
        }
46859
0
        if (JS_IsException(ret))
46860
0
            return ret;
46861
0
        JS_FreeValue(ctx, ret);
46862
0
    }
46863
0
    return JS_UNDEFINED;
46864
0
}
46865
46866
/* magic = 0: Promise.all 1: Promise.allSettled */
46867
static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
46868
                              int argc, JSValueConst *argv, int magic)
46869
0
{
46870
0
    JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
46871
0
    JSValue next_method = JS_UNDEFINED, values = JS_UNDEFINED;
46872
0
    JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element;
46873
0
    JSValue promise_resolve = JS_UNDEFINED, iter = JS_UNDEFINED;
46874
0
    JSValueConst then_args[2], resolve_element_data[5];
46875
0
    BOOL done;
46876
0
    int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any);
46877
    
46878
0
    if (!JS_IsObject(this_val))
46879
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
46880
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
46881
0
    if (JS_IsException(result_promise))
46882
0
        return result_promise;
46883
0
    promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
46884
0
    if (JS_IsException(promise_resolve) ||
46885
0
        check_function(ctx, promise_resolve))
46886
0
        goto fail_reject;
46887
0
    iter = JS_GetIterator(ctx, argv[0], FALSE);
46888
0
    if (JS_IsException(iter)) {
46889
0
        JSValue error;
46890
0
    fail_reject:
46891
0
        error = JS_GetException(ctx);
46892
0
        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
46893
0
                       (JSValueConst *)&error);
46894
0
        JS_FreeValue(ctx, error);
46895
0
        if (JS_IsException(ret))
46896
0
            goto fail;
46897
0
        JS_FreeValue(ctx, ret);
46898
0
    } else {
46899
0
        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
46900
0
        if (JS_IsException(next_method))
46901
0
            goto fail_reject;
46902
0
        values = JS_NewArray(ctx);
46903
0
        if (JS_IsException(values))
46904
0
            goto fail_reject;
46905
0
        resolve_element_env = JS_NewArray(ctx);
46906
0
        if (JS_IsException(resolve_element_env))
46907
0
            goto fail_reject;
46908
        /* remainingElementsCount field */
46909
0
        if (JS_DefinePropertyValueUint32(ctx, resolve_element_env, 0,
46910
0
                                         JS_NewInt32(ctx, 1),
46911
0
                                         JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
46912
0
            goto fail_reject;
46913
        
46914
0
        index = 0;
46915
0
        for(;;) {
46916
            /* XXX: conformance: should close the iterator if error on 'done'
46917
               access, but not on 'value' access */
46918
0
            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
46919
0
            if (JS_IsException(item))
46920
0
                goto fail_reject;
46921
0
            if (done)
46922
0
                break;
46923
0
            next_promise = JS_Call(ctx, promise_resolve, 
46924
0
                                   this_val, 1, (JSValueConst *)&item);
46925
0
            JS_FreeValue(ctx, item);
46926
0
            if (JS_IsException(next_promise)) {
46927
0
            fail_reject1:
46928
0
                JS_IteratorClose(ctx, iter, TRUE);
46929
0
                goto fail_reject;
46930
0
            }
46931
0
            resolve_element_data[0] = JS_NewBool(ctx, FALSE);
46932
0
            resolve_element_data[1] = (JSValueConst)JS_NewInt32(ctx, index);
46933
0
            resolve_element_data[2] = values;
46934
0
            resolve_element_data[3] = resolving_funcs[is_promise_any];
46935
0
            resolve_element_data[4] = resolve_element_env;
46936
0
            resolve_element =
46937
0
                JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
46938
0
                                    magic, 5, resolve_element_data);
46939
0
            if (JS_IsException(resolve_element)) {
46940
0
                JS_FreeValue(ctx, next_promise);
46941
0
                goto fail_reject1;
46942
0
            }
46943
            
46944
0
            if (magic == PROMISE_MAGIC_allSettled) {
46945
0
                reject_element =
46946
0
                    JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
46947
0
                                        magic | 4, 5, resolve_element_data);
46948
0
                if (JS_IsException(reject_element)) {
46949
0
                    JS_FreeValue(ctx, next_promise);
46950
0
                    goto fail_reject1;
46951
0
                }
46952
0
            } else if (magic == PROMISE_MAGIC_any) {
46953
0
                if (JS_DefinePropertyValueUint32(ctx, values, index,
46954
0
                                                 JS_UNDEFINED, JS_PROP_C_W_E) < 0)
46955
0
                    goto fail_reject1;
46956
0
                reject_element = resolve_element;
46957
0
                resolve_element = JS_DupValue(ctx, resolving_funcs[0]);
46958
0
            } else {
46959
0
                reject_element = JS_DupValue(ctx, resolving_funcs[1]);
46960
0
            }
46961
46962
0
            if (remainingElementsCount_add(ctx, resolve_element_env, 1) < 0) {
46963
0
                JS_FreeValue(ctx, next_promise);
46964
0
                JS_FreeValue(ctx, resolve_element);
46965
0
                JS_FreeValue(ctx, reject_element);
46966
0
                goto fail_reject1;
46967
0
            }
46968
46969
0
            then_args[0] = resolve_element;
46970
0
            then_args[1] = reject_element;
46971
0
            ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2, then_args);
46972
0
            JS_FreeValue(ctx, resolve_element);
46973
0
            JS_FreeValue(ctx, reject_element);
46974
0
            if (check_exception_free(ctx, ret))
46975
0
                goto fail_reject1;
46976
0
            index++;
46977
0
        }
46978
46979
0
        is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
46980
0
        if (is_zero < 0)
46981
0
            goto fail_reject;
46982
0
        if (is_zero) {
46983
0
            if (magic == PROMISE_MAGIC_any) {
46984
0
                JSValue error;
46985
0
                error = js_aggregate_error_constructor(ctx, values);
46986
0
                if (JS_IsException(error))
46987
0
                    goto fail_reject;
46988
0
                JS_FreeValue(ctx, values);
46989
0
                values = error;
46990
0
            }
46991
0
            ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED,
46992
0
                          1, (JSValueConst *)&values);
46993
0
            if (check_exception_free(ctx, ret))
46994
0
                goto fail_reject;
46995
0
        }
46996
0
    }
46997
0
 done:
46998
0
    JS_FreeValue(ctx, promise_resolve);
46999
0
    JS_FreeValue(ctx, resolve_element_env);
47000
0
    JS_FreeValue(ctx, values);
47001
0
    JS_FreeValue(ctx, next_method);
47002
0
    JS_FreeValue(ctx, iter);
47003
0
    JS_FreeValue(ctx, resolving_funcs[0]);
47004
0
    JS_FreeValue(ctx, resolving_funcs[1]);
47005
0
    return result_promise;
47006
0
 fail:
47007
0
    JS_FreeValue(ctx, result_promise);
47008
0
    result_promise = JS_EXCEPTION;
47009
0
    goto done;
47010
0
}
47011
47012
static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
47013
                               int argc, JSValueConst *argv)
47014
0
{
47015
0
    JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
47016
0
    JSValue next_method = JS_UNDEFINED, iter = JS_UNDEFINED;
47017
0
    JSValue promise_resolve = JS_UNDEFINED;
47018
0
    BOOL done;
47019
47020
0
    if (!JS_IsObject(this_val))
47021
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
47022
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
47023
0
    if (JS_IsException(result_promise))
47024
0
        return result_promise;
47025
0
    promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
47026
0
    if (JS_IsException(promise_resolve) ||
47027
0
        check_function(ctx, promise_resolve))
47028
0
        goto fail_reject;
47029
0
    iter = JS_GetIterator(ctx, argv[0], FALSE);
47030
0
    if (JS_IsException(iter)) {
47031
0
        JSValue error;
47032
0
    fail_reject:
47033
0
        error = JS_GetException(ctx);
47034
0
        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
47035
0
                       (JSValueConst *)&error);
47036
0
        JS_FreeValue(ctx, error);
47037
0
        if (JS_IsException(ret))
47038
0
            goto fail;
47039
0
        JS_FreeValue(ctx, ret);
47040
0
    } else {
47041
0
        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
47042
0
        if (JS_IsException(next_method))
47043
0
            goto fail_reject;
47044
47045
0
        for(;;) {
47046
            /* XXX: conformance: should close the iterator if error on 'done'
47047
               access, but not on 'value' access */
47048
0
            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
47049
0
            if (JS_IsException(item))
47050
0
                goto fail_reject;
47051
0
            if (done)
47052
0
                break;
47053
0
            next_promise = JS_Call(ctx, promise_resolve,
47054
0
                                   this_val, 1, (JSValueConst *)&item);
47055
0
            JS_FreeValue(ctx, item);
47056
0
            if (JS_IsException(next_promise)) {
47057
0
            fail_reject1:
47058
0
                JS_IteratorClose(ctx, iter, TRUE);
47059
0
                goto fail_reject;
47060
0
            }
47061
0
            ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2,
47062
0
                                (JSValueConst *)resolving_funcs);
47063
0
            if (check_exception_free(ctx, ret))
47064
0
                goto fail_reject1;
47065
0
        }
47066
0
    }
47067
0
 done:
47068
0
    JS_FreeValue(ctx, promise_resolve);
47069
0
    JS_FreeValue(ctx, next_method);
47070
0
    JS_FreeValue(ctx, iter);
47071
0
    JS_FreeValue(ctx, resolving_funcs[0]);
47072
0
    JS_FreeValue(ctx, resolving_funcs[1]);
47073
0
    return result_promise;
47074
0
 fail:
47075
    //JS_FreeValue(ctx, next_method); // why not???
47076
0
    JS_FreeValue(ctx, result_promise);
47077
0
    result_promise = JS_EXCEPTION;
47078
0
    goto done;
47079
0
}
47080
47081
static __exception int perform_promise_then(JSContext *ctx,
47082
                                            JSValueConst promise,
47083
                                            JSValueConst *resolve_reject,
47084
                                            JSValueConst *cap_resolving_funcs)
47085
0
{
47086
0
    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
47087
0
    JSPromiseReactionData *rd_array[2], *rd;
47088
0
    int i, j;
47089
47090
0
    rd_array[0] = NULL;
47091
0
    rd_array[1] = NULL;
47092
0
    for(i = 0; i < 2; i++) {
47093
0
        JSValueConst handler;
47094
0
        rd = js_mallocz(ctx, sizeof(*rd));
47095
0
        if (!rd) {
47096
0
            if (i == 1)
47097
0
                promise_reaction_data_free(ctx->rt, rd_array[0]);
47098
0
            return -1;
47099
0
        }
47100
0
        for(j = 0; j < 2; j++)
47101
0
            rd->resolving_funcs[j] = JS_DupValue(ctx, cap_resolving_funcs[j]);
47102
0
        handler = resolve_reject[i];
47103
0
        if (!JS_IsFunction(ctx, handler))
47104
0
            handler = JS_UNDEFINED;
47105
0
        rd->handler = JS_DupValue(ctx, handler);
47106
0
        rd_array[i] = rd;
47107
0
    }
47108
47109
0
    if (s->promise_state == JS_PROMISE_PENDING) {
47110
0
        for(i = 0; i < 2; i++)
47111
0
            list_add_tail(&rd_array[i]->link, &s->promise_reactions[i]);
47112
0
    } else {
47113
0
        JSValueConst args[5];
47114
0
        if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
47115
0
            JSRuntime *rt = ctx->rt;
47116
0
            if (rt->host_promise_rejection_tracker) {
47117
0
                rt->host_promise_rejection_tracker(ctx, promise, s->promise_result,
47118
0
                                                   TRUE, rt->host_promise_rejection_tracker_opaque);
47119
0
            }
47120
0
        }
47121
0
        i = s->promise_state - JS_PROMISE_FULFILLED;
47122
0
        rd = rd_array[i];
47123
0
        args[0] = rd->resolving_funcs[0];
47124
0
        args[1] = rd->resolving_funcs[1];
47125
0
        args[2] = rd->handler;
47126
0
        args[3] = JS_NewBool(ctx, i);
47127
0
        args[4] = s->promise_result;
47128
0
        JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
47129
0
        for(i = 0; i < 2; i++)
47130
0
            promise_reaction_data_free(ctx->rt, rd_array[i]);
47131
0
    }
47132
0
    s->is_handled = TRUE;
47133
0
    return 0;
47134
0
}
47135
47136
static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
47137
                               int argc, JSValueConst *argv)
47138
0
{
47139
0
    JSValue ctor, result_promise, resolving_funcs[2];
47140
0
    JSPromiseData *s;
47141
0
    int i, ret;
47142
47143
0
    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_PROMISE);
47144
0
    if (!s)
47145
0
        return JS_EXCEPTION;
47146
47147
0
    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
47148
0
    if (JS_IsException(ctor))
47149
0
        return ctor;
47150
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
47151
0
    JS_FreeValue(ctx, ctor);
47152
0
    if (JS_IsException(result_promise))
47153
0
        return result_promise;
47154
0
    ret = perform_promise_then(ctx, this_val, argv,
47155
0
                               (JSValueConst *)resolving_funcs);
47156
0
    for(i = 0; i < 2; i++)
47157
0
        JS_FreeValue(ctx, resolving_funcs[i]);
47158
0
    if (ret) {
47159
0
        JS_FreeValue(ctx, result_promise);
47160
0
        return JS_EXCEPTION;
47161
0
    }
47162
0
    return result_promise;
47163
0
}
47164
47165
static JSValue js_promise_catch(JSContext *ctx, JSValueConst this_val,
47166
                                int argc, JSValueConst *argv)
47167
0
{
47168
0
    JSValueConst args[2];
47169
0
    args[0] = JS_UNDEFINED;
47170
0
    args[1] = argv[0];
47171
0
    return JS_Invoke(ctx, this_val, JS_ATOM_then, 2, args);
47172
0
}
47173
47174
static JSValue js_promise_finally_value_thunk(JSContext *ctx, JSValueConst this_val,
47175
                                              int argc, JSValueConst *argv,
47176
                                              int magic, JSValue *func_data)
47177
0
{
47178
0
    return JS_DupValue(ctx, func_data[0]);
47179
0
}
47180
47181
static JSValue js_promise_finally_thrower(JSContext *ctx, JSValueConst this_val,
47182
                                          int argc, JSValueConst *argv,
47183
                                          int magic, JSValue *func_data)
47184
0
{
47185
0
    return JS_Throw(ctx, JS_DupValue(ctx, func_data[0]));
47186
0
}
47187
47188
static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_val,
47189
                                            int argc, JSValueConst *argv,
47190
                                            int magic, JSValue *func_data)
47191
0
{
47192
0
    JSValueConst ctor = func_data[0];
47193
0
    JSValueConst onFinally = func_data[1];
47194
0
    JSValue res, promise, ret, then_func;
47195
47196
0
    res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL);
47197
0
    if (JS_IsException(res))
47198
0
        return res;
47199
0
    promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0);
47200
0
    JS_FreeValue(ctx, res);
47201
0
    if (JS_IsException(promise))
47202
0
        return promise;
47203
0
    if (magic == 0) {
47204
0
        then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0,
47205
0
                                        0, 1, argv);
47206
0
    } else {
47207
0
        then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 0,
47208
0
                                        0, 1, argv);
47209
0
    }
47210
0
    if (JS_IsException(then_func)) {
47211
0
        JS_FreeValue(ctx, promise);
47212
0
        return then_func;
47213
0
    }
47214
0
    ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, (JSValueConst *)&then_func);
47215
0
    JS_FreeValue(ctx, then_func);
47216
0
    return ret;
47217
0
}
47218
47219
static JSValue js_promise_finally(JSContext *ctx, JSValueConst this_val,
47220
                                  int argc, JSValueConst *argv)
47221
0
{
47222
0
    JSValueConst onFinally = argv[0];
47223
0
    JSValue ctor, ret;
47224
0
    JSValue then_funcs[2];
47225
0
    JSValueConst func_data[2];
47226
0
    int i;
47227
47228
0
    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
47229
0
    if (JS_IsException(ctor))
47230
0
        return ctor;
47231
0
    if (!JS_IsFunction(ctx, onFinally)) {
47232
0
        then_funcs[0] = JS_DupValue(ctx, onFinally);
47233
0
        then_funcs[1] = JS_DupValue(ctx, onFinally);
47234
0
    } else {
47235
0
        func_data[0] = ctor;
47236
0
        func_data[1] = onFinally;
47237
0
        for(i = 0; i < 2; i++) {
47238
0
            then_funcs[i] = JS_NewCFunctionData(ctx, js_promise_then_finally_func, 1, i, 2, func_data);
47239
0
            if (JS_IsException(then_funcs[i])) {
47240
0
                if (i == 1)
47241
0
                    JS_FreeValue(ctx, then_funcs[0]);
47242
0
                JS_FreeValue(ctx, ctor);
47243
0
                return JS_EXCEPTION;
47244
0
            }
47245
0
        }
47246
0
    }
47247
0
    JS_FreeValue(ctx, ctor);
47248
0
    ret = JS_Invoke(ctx, this_val, JS_ATOM_then, 2, (JSValueConst *)then_funcs);
47249
0
    JS_FreeValue(ctx, then_funcs[0]);
47250
0
    JS_FreeValue(ctx, then_funcs[1]);
47251
0
    return ret;
47252
0
}
47253
47254
static const JSCFunctionListEntry js_promise_funcs[] = {
47255
    JS_CFUNC_MAGIC_DEF("resolve", 1, js_promise_resolve, 0 ),
47256
    JS_CFUNC_MAGIC_DEF("reject", 1, js_promise_resolve, 1 ),
47257
    JS_CFUNC_MAGIC_DEF("all", 1, js_promise_all, PROMISE_MAGIC_all ),
47258
    JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ),
47259
    JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ),
47260
    JS_CFUNC_DEF("race", 1, js_promise_race ),
47261
    //JS_CFUNC_DEF("__newPromiseCapability", 1, js_promise___newPromiseCapability ),
47262
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
47263
};
47264
47265
static const JSCFunctionListEntry js_promise_proto_funcs[] = {
47266
    JS_CFUNC_DEF("then", 2, js_promise_then ),
47267
    JS_CFUNC_DEF("catch", 1, js_promise_catch ),
47268
    JS_CFUNC_DEF("finally", 1, js_promise_finally ),
47269
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Promise", JS_PROP_CONFIGURABLE ),
47270
};
47271
47272
/* AsyncFunction */
47273
static const JSCFunctionListEntry js_async_function_proto_funcs[] = {
47274
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncFunction", JS_PROP_CONFIGURABLE ),
47275
};
47276
47277
static JSValue js_async_from_sync_iterator_unwrap(JSContext *ctx,
47278
                                                  JSValueConst this_val,
47279
                                                  int argc, JSValueConst *argv,
47280
                                                  int magic, JSValue *func_data)
47281
0
{
47282
0
    return js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]),
47283
0
                                     JS_ToBool(ctx, func_data[0]));
47284
0
}
47285
47286
static JSValue js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx,
47287
                                                              BOOL done)
47288
0
{
47289
0
    JSValueConst func_data[1];
47290
47291
0
    func_data[0] = (JSValueConst)JS_NewBool(ctx, done);
47292
0
    return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_unwrap,
47293
0
                               1, 0, 1, func_data);
47294
0
}
47295
47296
/* AsyncIteratorPrototype */
47297
47298
static const JSCFunctionListEntry js_async_iterator_proto_funcs[] = {
47299
    JS_CFUNC_DEF("[Symbol.asyncIterator]", 0, js_iterator_proto_iterator ),
47300
};
47301
47302
/* AsyncFromSyncIteratorPrototype */
47303
47304
typedef struct JSAsyncFromSyncIteratorData {
47305
    JSValue sync_iter;
47306
    JSValue next_method;
47307
} JSAsyncFromSyncIteratorData;
47308
47309
static void js_async_from_sync_iterator_finalizer(JSRuntime *rt, JSValue val)
47310
0
{
47311
0
    JSAsyncFromSyncIteratorData *s =
47312
0
        JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
47313
0
    if (s) {
47314
0
        JS_FreeValueRT(rt, s->sync_iter);
47315
0
        JS_FreeValueRT(rt, s->next_method);
47316
0
        js_free_rt(rt, s);
47317
0
    }
47318
0
}
47319
47320
static void js_async_from_sync_iterator_mark(JSRuntime *rt, JSValueConst val,
47321
                                             JS_MarkFunc *mark_func)
47322
0
{
47323
0
    JSAsyncFromSyncIteratorData *s =
47324
0
        JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
47325
0
    if (s) {
47326
0
        JS_MarkValue(rt, s->sync_iter, mark_func);
47327
0
        JS_MarkValue(rt, s->next_method, mark_func);
47328
0
    }
47329
0
}
47330
47331
static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
47332
                                              JSValueConst sync_iter)
47333
0
{
47334
0
    JSValue async_iter, next_method;
47335
0
    JSAsyncFromSyncIteratorData *s;
47336
47337
0
    next_method = JS_GetProperty(ctx, sync_iter, JS_ATOM_next);
47338
0
    if (JS_IsException(next_method))
47339
0
        return JS_EXCEPTION;
47340
0
    async_iter = JS_NewObjectClass(ctx, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
47341
0
    if (JS_IsException(async_iter)) {
47342
0
        JS_FreeValue(ctx, next_method);
47343
0
        return async_iter;
47344
0
    }
47345
0
    s = js_mallocz(ctx, sizeof(*s));
47346
0
    if (!s) {
47347
0
        JS_FreeValue(ctx, async_iter);
47348
0
        JS_FreeValue(ctx, next_method);
47349
0
        return JS_EXCEPTION;
47350
0
    }
47351
0
    s->sync_iter = JS_DupValue(ctx, sync_iter);
47352
0
    s->next_method = next_method;
47353
0
    JS_SetOpaque(async_iter, s);
47354
0
    return async_iter;
47355
0
}
47356
47357
static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst this_val,
47358
                                                int argc, JSValueConst *argv,
47359
                                                int magic)
47360
0
{
47361
0
    JSValue promise, resolving_funcs[2], value, err, method;
47362
0
    JSAsyncFromSyncIteratorData *s;
47363
0
    int done;
47364
0
    int is_reject;
47365
47366
0
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
47367
0
    if (JS_IsException(promise))
47368
0
        return JS_EXCEPTION;
47369
0
    s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
47370
0
    if (!s) {
47371
0
        JS_ThrowTypeError(ctx, "not an Async-from-Sync Iterator");
47372
0
        goto reject;
47373
0
    }
47374
47375
0
    if (magic == GEN_MAGIC_NEXT) {
47376
0
        method = JS_DupValue(ctx, s->next_method);
47377
0
    } else {
47378
0
        method = JS_GetProperty(ctx, s->sync_iter,
47379
0
                                magic == GEN_MAGIC_RETURN ? JS_ATOM_return :
47380
0
                                JS_ATOM_throw);
47381
0
        if (JS_IsException(method))
47382
0
            goto reject;
47383
0
        if (JS_IsUndefined(method) || JS_IsNull(method)) {
47384
0
            if (magic == GEN_MAGIC_RETURN) {
47385
0
                err = js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]), TRUE);
47386
0
                is_reject = 0;
47387
0
            } else {
47388
0
                err = JS_DupValue(ctx, argv[0]);
47389
0
                is_reject = 1;
47390
0
            }
47391
0
            goto done_resolve;
47392
0
        }
47393
0
    }
47394
0
    value = JS_IteratorNext2(ctx, s->sync_iter, method,
47395
0
                             argc >= 1 ? 1 : 0, argv, &done);
47396
0
    JS_FreeValue(ctx, method);
47397
0
    if (JS_IsException(value))
47398
0
        goto reject;
47399
0
    if (done == 2) {
47400
0
        JSValue obj = value;
47401
0
        value = JS_IteratorGetCompleteValue(ctx, obj, &done);
47402
0
        JS_FreeValue(ctx, obj);
47403
0
        if (JS_IsException(value))
47404
0
            goto reject;
47405
0
    }
47406
47407
0
    if (JS_IsException(value)) {
47408
0
        JSValue res2;
47409
0
    reject:
47410
0
        err = JS_GetException(ctx);
47411
0
        is_reject = 1;
47412
0
    done_resolve:
47413
0
        res2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED,
47414
0
                       1, (JSValueConst *)&err);
47415
0
        JS_FreeValue(ctx, err);
47416
0
        JS_FreeValue(ctx, res2);
47417
0
        JS_FreeValue(ctx, resolving_funcs[0]);
47418
0
        JS_FreeValue(ctx, resolving_funcs[1]);
47419
0
        return promise;
47420
0
    }
47421
0
    {
47422
0
        JSValue value_wrapper_promise, resolve_reject[2];
47423
0
        int res;
47424
47425
0
        value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor,
47426
0
                                                   1, (JSValueConst *)&value, 0);
47427
0
        if (JS_IsException(value_wrapper_promise)) {
47428
0
            JS_FreeValue(ctx, value);
47429
0
            goto reject;
47430
0
        }
47431
47432
0
        resolve_reject[0] =
47433
0
            js_async_from_sync_iterator_unwrap_func_create(ctx, done);
47434
0
        if (JS_IsException(resolve_reject[0])) {
47435
0
            JS_FreeValue(ctx, value_wrapper_promise);
47436
0
            goto fail;
47437
0
        }
47438
0
        JS_FreeValue(ctx, value);
47439
0
        resolve_reject[1] = JS_UNDEFINED;
47440
47441
0
        res = perform_promise_then(ctx, value_wrapper_promise,
47442
0
                                   (JSValueConst *)resolve_reject,
47443
0
                                   (JSValueConst *)resolving_funcs);
47444
0
        JS_FreeValue(ctx, resolve_reject[0]);
47445
0
        JS_FreeValue(ctx, value_wrapper_promise);
47446
0
        JS_FreeValue(ctx, resolving_funcs[0]);
47447
0
        JS_FreeValue(ctx, resolving_funcs[1]);
47448
0
        if (res) {
47449
0
            JS_FreeValue(ctx, promise);
47450
0
            return JS_EXCEPTION;
47451
0
        }
47452
0
    }
47453
0
    return promise;
47454
0
 fail:
47455
0
    JS_FreeValue(ctx, value);
47456
0
    JS_FreeValue(ctx, resolving_funcs[0]);
47457
0
    JS_FreeValue(ctx, resolving_funcs[1]);
47458
0
    JS_FreeValue(ctx, promise);
47459
0
    return JS_EXCEPTION;
47460
0
}
47461
47462
static const JSCFunctionListEntry js_async_from_sync_iterator_proto_funcs[] = {
47463
    JS_CFUNC_MAGIC_DEF("next", 1, js_async_from_sync_iterator_next, GEN_MAGIC_NEXT ),
47464
    JS_CFUNC_MAGIC_DEF("return", 1, js_async_from_sync_iterator_next, GEN_MAGIC_RETURN ),
47465
    JS_CFUNC_MAGIC_DEF("throw", 1, js_async_from_sync_iterator_next, GEN_MAGIC_THROW ),
47466
};
47467
47468
/* AsyncGeneratorFunction */
47469
47470
static const JSCFunctionListEntry js_async_generator_function_proto_funcs[] = {
47471
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGeneratorFunction", JS_PROP_CONFIGURABLE ),
47472
};
47473
47474
/* AsyncGenerator prototype */
47475
47476
static const JSCFunctionListEntry js_async_generator_proto_funcs[] = {
47477
    JS_CFUNC_MAGIC_DEF("next", 1, js_async_generator_next, GEN_MAGIC_NEXT ),
47478
    JS_CFUNC_MAGIC_DEF("return", 1, js_async_generator_next, GEN_MAGIC_RETURN ),
47479
    JS_CFUNC_MAGIC_DEF("throw", 1, js_async_generator_next, GEN_MAGIC_THROW ),
47480
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGenerator", JS_PROP_CONFIGURABLE ),
47481
};
47482
47483
static JSClassShortDef const js_async_class_def[] = {
47484
    { JS_ATOM_Promise, js_promise_finalizer, js_promise_mark },                      /* JS_CLASS_PROMISE */
47485
    { JS_ATOM_PromiseResolveFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_RESOLVE_FUNCTION */
47486
    { JS_ATOM_PromiseRejectFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_REJECT_FUNCTION */
47487
    { JS_ATOM_AsyncFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_FUNCTION */
47488
    { JS_ATOM_AsyncFunctionResolve, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_RESOLVE */
47489
    { JS_ATOM_AsyncFunctionReject, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_REJECT */
47490
    { JS_ATOM_empty_string, js_async_from_sync_iterator_finalizer, js_async_from_sync_iterator_mark }, /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
47491
    { JS_ATOM_AsyncGeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_GENERATOR_FUNCTION */
47492
    { JS_ATOM_AsyncGenerator, js_async_generator_finalizer, js_async_generator_mark },  /* JS_CLASS_ASYNC_GENERATOR */
47493
};
47494
47495
void JS_AddIntrinsicPromise(JSContext *ctx)
47496
2
{
47497
2
    JSRuntime *rt = ctx->rt;
47498
2
    JSValue obj1;
47499
47500
2
    if (!JS_IsRegisteredClass(rt, JS_CLASS_PROMISE)) {
47501
2
        init_class_range(rt, js_async_class_def, JS_CLASS_PROMISE,
47502
2
                         countof(js_async_class_def));
47503
2
        rt->class_array[JS_CLASS_PROMISE_RESOLVE_FUNCTION].call = js_promise_resolve_function_call;
47504
2
        rt->class_array[JS_CLASS_PROMISE_REJECT_FUNCTION].call = js_promise_resolve_function_call;
47505
2
        rt->class_array[JS_CLASS_ASYNC_FUNCTION].call = js_async_function_call;
47506
2
        rt->class_array[JS_CLASS_ASYNC_FUNCTION_RESOLVE].call = js_async_function_resolve_call;
47507
2
        rt->class_array[JS_CLASS_ASYNC_FUNCTION_REJECT].call = js_async_function_resolve_call;
47508
2
        rt->class_array[JS_CLASS_ASYNC_GENERATOR_FUNCTION].call = js_async_generator_function_call;
47509
2
    }
47510
47511
    /* Promise */
47512
2
    ctx->class_proto[JS_CLASS_PROMISE] = JS_NewObject(ctx);
47513
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_PROMISE],
47514
2
                               js_promise_proto_funcs,
47515
2
                               countof(js_promise_proto_funcs));
47516
2
    obj1 = JS_NewCFunction2(ctx, js_promise_constructor, "Promise", 1,
47517
2
                            JS_CFUNC_constructor, 0);
47518
2
    ctx->promise_ctor = JS_DupValue(ctx, obj1);
47519
2
    JS_SetPropertyFunctionList(ctx, obj1,
47520
2
                               js_promise_funcs,
47521
2
                               countof(js_promise_funcs));
47522
2
    JS_NewGlobalCConstructor2(ctx, obj1, "Promise",
47523
2
                              ctx->class_proto[JS_CLASS_PROMISE]);
47524
47525
    /* AsyncFunction */
47526
2
    ctx->class_proto[JS_CLASS_ASYNC_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
47527
2
    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
47528
2
                            "AsyncFunction", 1,
47529
2
                            JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC,
47530
2
                            ctx->function_ctor);
47531
2
    JS_SetPropertyFunctionList(ctx,
47532
2
                               ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
47533
2
                               js_async_function_proto_funcs,
47534
2
                               countof(js_async_function_proto_funcs));
47535
2
    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
47536
2
                       0, JS_PROP_CONFIGURABLE);
47537
2
    JS_FreeValue(ctx, obj1);
47538
47539
    /* AsyncIteratorPrototype */
47540
2
    ctx->async_iterator_proto = JS_NewObject(ctx);
47541
2
    JS_SetPropertyFunctionList(ctx, ctx->async_iterator_proto,
47542
2
                               js_async_iterator_proto_funcs,
47543
2
                               countof(js_async_iterator_proto_funcs));
47544
47545
    /* AsyncFromSyncIteratorPrototype */
47546
2
    ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR] =
47547
2
        JS_NewObjectProto(ctx, ctx->async_iterator_proto);
47548
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR],
47549
2
                               js_async_from_sync_iterator_proto_funcs,
47550
2
                               countof(js_async_from_sync_iterator_proto_funcs));
47551
47552
    /* AsyncGeneratorPrototype */
47553
2
    ctx->class_proto[JS_CLASS_ASYNC_GENERATOR] =
47554
2
        JS_NewObjectProto(ctx, ctx->async_iterator_proto);
47555
2
    JS_SetPropertyFunctionList(ctx,
47556
2
                               ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
47557
2
                               js_async_generator_proto_funcs,
47558
2
                               countof(js_async_generator_proto_funcs));
47559
47560
    /* AsyncGeneratorFunction */
47561
2
    ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION] =
47562
2
        JS_NewObjectProto(ctx, ctx->function_proto);
47563
2
    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
47564
2
                            "AsyncGeneratorFunction", 1,
47565
2
                            JS_CFUNC_constructor_or_func_magic,
47566
2
                            JS_FUNC_ASYNC_GENERATOR,
47567
2
                            ctx->function_ctor);
47568
2
    JS_SetPropertyFunctionList(ctx,
47569
2
                               ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
47570
2
                               js_async_generator_function_proto_funcs,
47571
2
                               countof(js_async_generator_function_proto_funcs));
47572
2
    JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
47573
2
                       ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
47574
2
                       JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
47575
2
    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
47576
2
                       0, JS_PROP_CONFIGURABLE);
47577
2
    JS_FreeValue(ctx, obj1);
47578
2
}
47579
47580
/* URI handling */
47581
47582
0
static int string_get_hex(JSString *p, int k, int n) {
47583
0
    int c = 0, h;
47584
0
    while (n-- > 0) {
47585
0
        if ((h = from_hex(string_get(p, k++))) < 0)
47586
0
            return -1;
47587
0
        c = (c << 4) | h;
47588
0
    }
47589
0
    return c;
47590
0
}
47591
47592
0
static int isURIReserved(int c) {
47593
0
    return c < 0x100 && memchr(";/?:@&=+$,#", c, sizeof(";/?:@&=+$,#") - 1) != NULL;
47594
0
}
47595
47596
static int __attribute__((format(printf, 2, 3))) js_throw_URIError(JSContext *ctx, const char *fmt, ...)
47597
0
{
47598
0
    va_list ap;
47599
47600
0
    va_start(ap, fmt);
47601
0
    JS_ThrowError(ctx, JS_URI_ERROR, fmt, ap);
47602
0
    va_end(ap);
47603
0
    return -1;
47604
0
}
47605
47606
0
static int hex_decode(JSContext *ctx, JSString *p, int k) {
47607
0
    int c;
47608
47609
0
    if (k >= p->len || string_get(p, k) != '%')
47610
0
        return js_throw_URIError(ctx, "expecting %%");
47611
0
    if (k + 2 >= p->len || (c = string_get_hex(p, k + 1, 2)) < 0)
47612
0
        return js_throw_URIError(ctx, "expecting hex digit");
47613
47614
0
    return c;
47615
0
}
47616
47617
static JSValue js_global_decodeURI(JSContext *ctx, JSValueConst this_val,
47618
                                   int argc, JSValueConst *argv, int isComponent)
47619
0
{
47620
0
    JSValue str;
47621
0
    StringBuffer b_s, *b = &b_s;
47622
0
    JSString *p;
47623
0
    int k, c, c1, n, c_min;
47624
47625
0
    str = JS_ToString(ctx, argv[0]);
47626
0
    if (JS_IsException(str))
47627
0
        return str;
47628
47629
0
    string_buffer_init(ctx, b, 0);
47630
47631
0
    p = JS_VALUE_GET_STRING(str);
47632
0
    for (k = 0; k < p->len;) {
47633
0
        c = string_get(p, k);
47634
0
        if (c == '%') {
47635
0
            c = hex_decode(ctx, p, k);
47636
0
            if (c < 0)
47637
0
                goto fail;
47638
0
            k += 3;
47639
0
            if (c < 0x80) {
47640
0
                if (!isComponent && isURIReserved(c)) {
47641
0
                    c = '%';
47642
0
                    k -= 2;
47643
0
                }
47644
0
            } else {
47645
                /* Decode URI-encoded UTF-8 sequence */
47646
0
                if (c >= 0xc0 && c <= 0xdf) {
47647
0
                    n = 1;
47648
0
                    c_min = 0x80;
47649
0
                    c &= 0x1f;
47650
0
                } else if (c >= 0xe0 && c <= 0xef) {
47651
0
                    n = 2;
47652
0
                    c_min = 0x800;
47653
0
                    c &= 0xf;
47654
0
                } else if (c >= 0xf0 && c <= 0xf7) {
47655
0
                    n = 3;
47656
0
                    c_min = 0x10000;
47657
0
                    c &= 0x7;
47658
0
                } else {
47659
0
                    n = 0;
47660
0
                    c_min = 1;
47661
0
                    c = 0;
47662
0
                }
47663
0
                while (n-- > 0) {
47664
0
                    c1 = hex_decode(ctx, p, k);
47665
0
                    if (c1 < 0)
47666
0
                        goto fail;
47667
0
                    k += 3;
47668
0
                    if ((c1 & 0xc0) != 0x80) {
47669
0
                        c = 0;
47670
0
                        break;
47671
0
                    }
47672
0
                    c = (c << 6) | (c1 & 0x3f);
47673
0
                }
47674
0
                if (c < c_min || c > 0x10FFFF ||
47675
0
                    (c >= 0xd800 && c < 0xe000)) {
47676
0
                    js_throw_URIError(ctx, "malformed UTF-8");
47677
0
                    goto fail;
47678
0
                }
47679
0
            }
47680
0
        } else {
47681
0
            k++;
47682
0
        }
47683
0
        string_buffer_putc(b, c);
47684
0
    }
47685
0
    JS_FreeValue(ctx, str);
47686
0
    return string_buffer_end(b);
47687
47688
0
fail:
47689
0
    JS_FreeValue(ctx, str);
47690
0
    string_buffer_free(b);
47691
0
    return JS_EXCEPTION;
47692
0
}
47693
47694
0
static int isUnescaped(int c) {
47695
0
    static char const unescaped_chars[] =
47696
0
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
47697
0
        "abcdefghijklmnopqrstuvwxyz"
47698
0
        "0123456789"
47699
0
        "@*_+-./";
47700
0
    return c < 0x100 &&
47701
0
        memchr(unescaped_chars, c, sizeof(unescaped_chars) - 1);
47702
0
}
47703
47704
0
static int isURIUnescaped(int c, int isComponent) {
47705
0
    return c < 0x100 &&
47706
0
        ((c >= 0x61 && c <= 0x7a) ||
47707
0
         (c >= 0x41 && c <= 0x5a) ||
47708
0
         (c >= 0x30 && c <= 0x39) ||
47709
0
         memchr("-_.!~*'()", c, sizeof("-_.!~*'()") - 1) != NULL ||
47710
0
         (!isComponent && isURIReserved(c)));
47711
0
}
47712
47713
0
static int encodeURI_hex(StringBuffer *b, int c) {
47714
0
    uint8_t buf[6];
47715
0
    int n = 0;
47716
0
    const char *hex = "0123456789ABCDEF";
47717
47718
0
    buf[n++] = '%';
47719
0
    if (c >= 256) {
47720
0
        buf[n++] = 'u';
47721
0
        buf[n++] = hex[(c >> 12) & 15];
47722
0
        buf[n++] = hex[(c >>  8) & 15];
47723
0
    }
47724
0
    buf[n++] = hex[(c >> 4) & 15];
47725
0
    buf[n++] = hex[(c >> 0) & 15];
47726
0
    return string_buffer_write8(b, buf, n);
47727
0
}
47728
47729
static JSValue js_global_encodeURI(JSContext *ctx, JSValueConst this_val,
47730
                                   int argc, JSValueConst *argv,
47731
                                   int isComponent)
47732
0
{
47733
0
    JSValue str;
47734
0
    StringBuffer b_s, *b = &b_s;
47735
0
    JSString *p;
47736
0
    int k, c, c1;
47737
47738
0
    str = JS_ToString(ctx, argv[0]);
47739
0
    if (JS_IsException(str))
47740
0
        return str;
47741
47742
0
    p = JS_VALUE_GET_STRING(str);
47743
0
    string_buffer_init(ctx, b, p->len);
47744
0
    for (k = 0; k < p->len;) {
47745
0
        c = string_get(p, k);
47746
0
        k++;
47747
0
        if (isURIUnescaped(c, isComponent)) {
47748
0
            string_buffer_putc16(b, c);
47749
0
        } else {
47750
0
            if (c >= 0xdc00 && c <= 0xdfff) {
47751
0
                js_throw_URIError(ctx, "invalid character");
47752
0
                goto fail;
47753
0
            } else if (c >= 0xd800 && c <= 0xdbff) {
47754
0
                if (k >= p->len) {
47755
0
                    js_throw_URIError(ctx, "expecting surrogate pair");
47756
0
                    goto fail;
47757
0
                }
47758
0
                c1 = string_get(p, k);
47759
0
                k++;
47760
0
                if (c1 < 0xdc00 || c1 > 0xdfff) {
47761
0
                    js_throw_URIError(ctx, "expecting surrogate pair");
47762
0
                    goto fail;
47763
0
                }
47764
0
                c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
47765
0
            }
47766
0
            if (c < 0x80) {
47767
0
                encodeURI_hex(b, c);
47768
0
            } else {
47769
                /* XXX: use C UTF-8 conversion ? */
47770
0
                if (c < 0x800) {
47771
0
                    encodeURI_hex(b, (c >> 6) | 0xc0);
47772
0
                } else {
47773
0
                    if (c < 0x10000) {
47774
0
                        encodeURI_hex(b, (c >> 12) | 0xe0);
47775
0
                    } else {
47776
0
                        encodeURI_hex(b, (c >> 18) | 0xf0);
47777
0
                        encodeURI_hex(b, ((c >> 12) & 0x3f) | 0x80);
47778
0
                    }
47779
0
                    encodeURI_hex(b, ((c >> 6) & 0x3f) | 0x80);
47780
0
                }
47781
0
                encodeURI_hex(b, (c & 0x3f) | 0x80);
47782
0
            }
47783
0
        }
47784
0
    }
47785
0
    JS_FreeValue(ctx, str);
47786
0
    return string_buffer_end(b);
47787
47788
0
fail:
47789
0
    JS_FreeValue(ctx, str);
47790
0
    string_buffer_free(b);
47791
0
    return JS_EXCEPTION;
47792
0
}
47793
47794
static JSValue js_global_escape(JSContext *ctx, JSValueConst this_val,
47795
                                int argc, JSValueConst *argv)
47796
0
{
47797
0
    JSValue str;
47798
0
    StringBuffer b_s, *b = &b_s;
47799
0
    JSString *p;
47800
0
    int i, len, c;
47801
47802
0
    str = JS_ToString(ctx, argv[0]);
47803
0
    if (JS_IsException(str))
47804
0
        return str;
47805
47806
0
    p = JS_VALUE_GET_STRING(str);
47807
0
    string_buffer_init(ctx, b, p->len);
47808
0
    for (i = 0, len = p->len; i < len; i++) {
47809
0
        c = string_get(p, i);
47810
0
        if (isUnescaped(c)) {
47811
0
            string_buffer_putc16(b, c);
47812
0
        } else {
47813
0
            encodeURI_hex(b, c);
47814
0
        }
47815
0
    }
47816
0
    JS_FreeValue(ctx, str);
47817
0
    return string_buffer_end(b);
47818
0
}
47819
47820
static JSValue js_global_unescape(JSContext *ctx, JSValueConst this_val,
47821
                                  int argc, JSValueConst *argv)
47822
0
{
47823
0
    JSValue str;
47824
0
    StringBuffer b_s, *b = &b_s;
47825
0
    JSString *p;
47826
0
    int i, len, c, n;
47827
47828
0
    str = JS_ToString(ctx, argv[0]);
47829
0
    if (JS_IsException(str))
47830
0
        return str;
47831
47832
0
    string_buffer_init(ctx, b, 0);
47833
0
    p = JS_VALUE_GET_STRING(str);
47834
0
    for (i = 0, len = p->len; i < len; i++) {
47835
0
        c = string_get(p, i);
47836
0
        if (c == '%') {
47837
0
            if (i + 6 <= len
47838
0
            &&  string_get(p, i + 1) == 'u'
47839
0
            &&  (n = string_get_hex(p, i + 2, 4)) >= 0) {
47840
0
                c = n;
47841
0
                i += 6 - 1;
47842
0
            } else
47843
0
            if (i + 3 <= len
47844
0
            &&  (n = string_get_hex(p, i + 1, 2)) >= 0) {
47845
0
                c = n;
47846
0
                i += 3 - 1;
47847
0
            }
47848
0
        }
47849
0
        string_buffer_putc16(b, c);
47850
0
    }
47851
0
    JS_FreeValue(ctx, str);
47852
0
    return string_buffer_end(b);
47853
0
}
47854
47855
/* global object */
47856
47857
static const JSCFunctionListEntry js_global_funcs[] = {
47858
    JS_CFUNC_DEF("parseInt", 2, js_parseInt ),
47859
    JS_CFUNC_DEF("parseFloat", 1, js_parseFloat ),
47860
    JS_CFUNC_DEF("isNaN", 1, js_global_isNaN ),
47861
    JS_CFUNC_DEF("isFinite", 1, js_global_isFinite ),
47862
47863
    JS_CFUNC_MAGIC_DEF("decodeURI", 1, js_global_decodeURI, 0 ),
47864
    JS_CFUNC_MAGIC_DEF("decodeURIComponent", 1, js_global_decodeURI, 1 ),
47865
    JS_CFUNC_MAGIC_DEF("encodeURI", 1, js_global_encodeURI, 0 ),
47866
    JS_CFUNC_MAGIC_DEF("encodeURIComponent", 1, js_global_encodeURI, 1 ),
47867
    JS_CFUNC_DEF("escape", 1, js_global_escape ),
47868
    JS_CFUNC_DEF("unescape", 1, js_global_unescape ),
47869
    JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ),
47870
    JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
47871
    JS_PROP_UNDEFINED_DEF("undefined", 0 ),
47872
47873
    /* for the 'Date' implementation */
47874
    JS_CFUNC_DEF("__date_clock", 0, js___date_clock ),
47875
    //JS_CFUNC_DEF("__date_now", 0, js___date_now ),
47876
    //JS_CFUNC_DEF("__date_getTimezoneOffset", 1, js___date_getTimezoneOffset ),
47877
    //JS_CFUNC_DEF("__date_create", 3, js___date_create ),
47878
};
47879
47880
/* Date */
47881
47882
0
static int64_t math_mod(int64_t a, int64_t b) {
47883
    /* return positive modulo */
47884
0
    int64_t m = a % b;
47885
0
    return m + (m < 0) * b;
47886
0
}
47887
47888
0
static int64_t floor_div(int64_t a, int64_t b) {
47889
    /* integer division rounding toward -Infinity */
47890
0
    int64_t m = a % b;
47891
0
    return (a - (m + (m < 0) * b)) / b;
47892
0
}
47893
47894
static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
47895
                             int argc, JSValueConst *argv);
47896
47897
static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val)
47898
0
{
47899
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
47900
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
47901
0
        if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data))
47902
0
            return JS_ToFloat64(ctx, valp, p->u.object_data);
47903
0
    }
47904
0
    JS_ThrowTypeError(ctx, "not a Date object");
47905
0
    return -1;
47906
0
}
47907
47908
static JSValue JS_SetThisTimeValue(JSContext *ctx, JSValueConst this_val, double v)
47909
0
{
47910
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
47911
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
47912
0
        if (p->class_id == JS_CLASS_DATE) {
47913
0
            JS_FreeValue(ctx, p->u.object_data);
47914
0
            p->u.object_data = JS_NewFloat64(ctx, v);
47915
0
            return JS_DupValue(ctx, p->u.object_data);
47916
0
        }
47917
0
    }
47918
0
    return JS_ThrowTypeError(ctx, "not a Date object");
47919
0
}
47920
47921
0
static int64_t days_from_year(int64_t y) {
47922
0
    return 365 * (y - 1970) + floor_div(y - 1969, 4) -
47923
0
        floor_div(y - 1901, 100) + floor_div(y - 1601, 400);
47924
0
}
47925
47926
0
static int64_t days_in_year(int64_t y) {
47927
0
    return 365 + !(y % 4) - !(y % 100) + !(y % 400);
47928
0
}
47929
47930
/* return the year, update days */
47931
0
static int64_t year_from_days(int64_t *days) {
47932
0
    int64_t y, d1, nd, d = *days;
47933
0
    y = floor_div(d * 10000, 3652425) + 1970;
47934
    /* the initial approximation is very good, so only a few
47935
       iterations are necessary */
47936
0
    for(;;) {
47937
0
        d1 = d - days_from_year(y);
47938
0
        if (d1 < 0) {
47939
0
            y--;
47940
0
            d1 += days_in_year(y);
47941
0
        } else {
47942
0
            nd = days_in_year(y);
47943
0
            if (d1 < nd)
47944
0
                break;
47945
0
            d1 -= nd;
47946
0
            y++;
47947
0
        }
47948
0
    }
47949
0
    *days = d1;
47950
0
    return y;
47951
0
}
47952
47953
static int const month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
47954
static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
47955
static char const day_names[] = "SunMonTueWedThuFriSat";
47956
47957
static __exception int get_date_fields(JSContext *ctx, JSValueConst obj,
47958
                                       double fields[9], int is_local, int force)
47959
0
{
47960
0
    double dval;
47961
0
    int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0;
47962
47963
0
    if (JS_ThisTimeValue(ctx, &dval, obj))
47964
0
        return -1;
47965
47966
0
    if (isnan(dval)) {
47967
0
        if (!force)
47968
0
            return FALSE; /* NaN */
47969
0
        d = 0;        /* initialize all fields to 0 */
47970
0
    } else {
47971
0
        d = dval;
47972
0
        if (is_local) {
47973
0
            tz = -getTimezoneOffset(d);
47974
0
            d += tz * 60000;
47975
0
        }
47976
0
    }
47977
47978
    /* result is >= 0, we can use % */
47979
0
    h = math_mod(d, 86400000);
47980
0
    days = (d - h) / 86400000;
47981
0
    ms = h % 1000;
47982
0
    h = (h - ms) / 1000;
47983
0
    s = h % 60;
47984
0
    h = (h - s) / 60;
47985
0
    m = h % 60;
47986
0
    h = (h - m) / 60;
47987
0
    wd = math_mod(days + 4, 7); /* week day */
47988
0
    y = year_from_days(&days);
47989
47990
0
    for(i = 0; i < 11; i++) {
47991
0
        md = month_days[i];
47992
0
        if (i == 1)
47993
0
            md += days_in_year(y) - 365;
47994
0
        if (days < md)
47995
0
            break;
47996
0
        days -= md;
47997
0
    }
47998
0
    fields[0] = y;
47999
0
    fields[1] = i;
48000
0
    fields[2] = days + 1;
48001
0
    fields[3] = h;
48002
0
    fields[4] = m;
48003
0
    fields[5] = s;
48004
0
    fields[6] = ms;
48005
0
    fields[7] = wd;
48006
0
    fields[8] = tz;
48007
0
    return TRUE;
48008
0
}
48009
48010
0
static double time_clip(double t) {
48011
0
    if (t >= -8.64e15 && t <= 8.64e15)
48012
0
        return trunc(t) + 0.0;  /* convert -0 to +0 */
48013
0
    else
48014
0
        return NAN;
48015
0
}
48016
48017
/* The spec mandates the use of 'double' and it fixes the order
48018
   of the operations */
48019
0
static double set_date_fields(double fields[], int is_local) {
48020
0
    int64_t y;
48021
0
    double days, d, h, m1;
48022
0
    int i, m, md;
48023
    
48024
0
    m1 = fields[1];
48025
0
    m = fmod(m1, 12);
48026
0
    if (m < 0)
48027
0
        m += 12;
48028
0
    y = (int64_t)(fields[0] + floor(m1 / 12));
48029
0
    days = days_from_year(y);
48030
48031
0
    for(i = 0; i < m; i++) {
48032
0
        md = month_days[i];
48033
0
        if (i == 1)
48034
0
            md += days_in_year(y) - 365;
48035
0
        days += md;
48036
0
    }
48037
0
    days += fields[2] - 1;
48038
0
    h = fields[3] * 3600000 + fields[4] * 60000 + 
48039
0
        fields[5] * 1000 + fields[6];
48040
0
    d = days * 86400000 + h;
48041
0
    if (is_local)
48042
0
        d += getTimezoneOffset(d) * 60000;
48043
0
    return time_clip(d);
48044
0
}
48045
48046
static JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
48047
                              int argc, JSValueConst *argv, int magic)
48048
0
{
48049
    // get_date_field(obj, n, is_local)
48050
0
    double fields[9];
48051
0
    int res, n, is_local;
48052
48053
0
    is_local = magic & 0x0F;
48054
0
    n = (magic >> 4) & 0x0F;
48055
0
    res = get_date_fields(ctx, this_val, fields, is_local, 0);
48056
0
    if (res < 0)
48057
0
        return JS_EXCEPTION;
48058
0
    if (!res)
48059
0
        return JS_NAN;
48060
48061
0
    if (magic & 0x100) {    // getYear
48062
0
        fields[0] -= 1900;
48063
0
    }
48064
0
    return JS_NewFloat64(ctx, fields[n]);
48065
0
}
48066
48067
static JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
48068
                              int argc, JSValueConst *argv, int magic)
48069
0
{
48070
    // _field(obj, first_field, end_field, args, is_local)
48071
0
    double fields[9];
48072
0
    int res, first_field, end_field, is_local, i, n;
48073
0
    double d, a;
48074
48075
0
    d = NAN;
48076
0
    first_field = (magic >> 8) & 0x0F;
48077
0
    end_field = (magic >> 4) & 0x0F;
48078
0
    is_local = magic & 0x0F;
48079
48080
0
    res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0);
48081
0
    if (res < 0)
48082
0
        return JS_EXCEPTION;
48083
0
    if (res && argc > 0) {
48084
0
        n = end_field - first_field;
48085
0
        if (argc < n)
48086
0
            n = argc;
48087
0
        for(i = 0; i < n; i++) {
48088
0
            if (JS_ToFloat64(ctx, &a, argv[i]))
48089
0
                return JS_EXCEPTION;
48090
0
            if (!isfinite(a))
48091
0
                goto done;
48092
0
            fields[first_field + i] = trunc(a);
48093
0
        }
48094
0
        d = set_date_fields(fields, is_local);
48095
0
    }
48096
0
done:
48097
0
    return JS_SetThisTimeValue(ctx, this_val, d);
48098
0
}
48099
48100
/* fmt:
48101
   0: toUTCString: "Tue, 02 Jan 2018 23:04:46 GMT"
48102
   1: toString: "Wed Jan 03 2018 00:05:22 GMT+0100 (CET)"
48103
   2: toISOString: "2018-01-02T23:02:56.927Z"
48104
   3: toLocaleString: "1/2/2018, 11:40:40 PM"
48105
   part: 1=date, 2=time 3=all
48106
   XXX: should use a variant of strftime().
48107
 */
48108
static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
48109
                               int argc, JSValueConst *argv, int magic)
48110
0
{
48111
    // _string(obj, fmt, part)
48112
0
    char buf[64];
48113
0
    double fields[9];
48114
0
    int res, fmt, part, pos;
48115
0
    int y, mon, d, h, m, s, ms, wd, tz;
48116
48117
0
    fmt = (magic >> 4) & 0x0F;
48118
0
    part = magic & 0x0F;
48119
48120
0
    res = get_date_fields(ctx, this_val, fields, fmt & 1, 0);
48121
0
    if (res < 0)
48122
0
        return JS_EXCEPTION;
48123
0
    if (!res) {
48124
0
        if (fmt == 2)
48125
0
            return JS_ThrowRangeError(ctx, "Date value is NaN");
48126
0
        else
48127
0
            return JS_NewString(ctx, "Invalid Date");
48128
0
    }
48129
48130
0
    y = fields[0];
48131
0
    mon = fields[1];
48132
0
    d = fields[2];
48133
0
    h = fields[3];
48134
0
    m = fields[4];
48135
0
    s = fields[5];
48136
0
    ms = fields[6];
48137
0
    wd = fields[7];
48138
0
    tz = fields[8];
48139
48140
0
    pos = 0;
48141
48142
0
    if (part & 1) { /* date part */
48143
0
        switch(fmt) {
48144
0
        case 0:
48145
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48146
0
                            "%.3s, %02d %.3s %0*d ",
48147
0
                            day_names + wd * 3, d,
48148
0
                            month_names + mon * 3, 4 + (y < 0), y);
48149
0
            break;
48150
0
        case 1:
48151
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48152
0
                            "%.3s %.3s %02d %0*d",
48153
0
                            day_names + wd * 3,
48154
0
                            month_names + mon * 3, d, 4 + (y < 0), y);
48155
0
            if (part == 3) {
48156
0
                buf[pos++] = ' ';
48157
0
            }
48158
0
            break;
48159
0
        case 2:
48160
0
            if (y >= 0 && y <= 9999) {
48161
0
                pos += snprintf(buf + pos, sizeof(buf) - pos,
48162
0
                                "%04d", y);
48163
0
            } else {
48164
0
                pos += snprintf(buf + pos, sizeof(buf) - pos,
48165
0
                                "%+07d", y);
48166
0
            }
48167
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48168
0
                            "-%02d-%02dT", mon + 1, d);
48169
0
            break;
48170
0
        case 3:
48171
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48172
0
                            "%02d/%02d/%0*d", mon + 1, d, 4 + (y < 0), y);
48173
0
            if (part == 3) {
48174
0
                buf[pos++] = ',';
48175
0
                buf[pos++] = ' ';
48176
0
            }
48177
0
            break;
48178
0
        }
48179
0
    }
48180
0
    if (part & 2) { /* time part */
48181
0
        switch(fmt) {
48182
0
        case 0:
48183
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48184
0
                            "%02d:%02d:%02d GMT", h, m, s);
48185
0
            break;
48186
0
        case 1:
48187
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48188
0
                            "%02d:%02d:%02d GMT", h, m, s);
48189
0
            if (tz < 0) {
48190
0
                buf[pos++] = '-';
48191
0
                tz = -tz;
48192
0
            } else {
48193
0
                buf[pos++] = '+';
48194
0
            }
48195
            /* tz is >= 0, can use % */
48196
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48197
0
                            "%02d%02d", tz / 60, tz % 60);
48198
            /* XXX: tack the time zone code? */
48199
0
            break;
48200
0
        case 2:
48201
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48202
0
                            "%02d:%02d:%02d.%03dZ", h, m, s, ms);
48203
0
            break;
48204
0
        case 3:
48205
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
48206
0
                            "%02d:%02d:%02d %cM", (h + 1) % 12 - 1, m, s,
48207
0
                            (h < 12) ? 'A' : 'P');
48208
0
            break;
48209
0
        }
48210
0
    }
48211
0
    return JS_NewStringLen(ctx, buf, pos);
48212
0
}
48213
48214
/* OS dependent: return the UTC time in ms since 1970. */
48215
0
static int64_t date_now(void) {
48216
0
    struct timeval tv;
48217
0
    gettimeofday(&tv, NULL);
48218
0
    return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
48219
0
}
48220
48221
static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,
48222
                                   int argc, JSValueConst *argv)
48223
0
{
48224
    // Date(y, mon, d, h, m, s, ms)
48225
0
    JSValue rv;
48226
0
    int i, n;
48227
0
    double a, val;
48228
48229
0
    if (JS_IsUndefined(new_target)) {
48230
        /* invoked as function */
48231
0
        argc = 0;
48232
0
    }
48233
0
    n = argc;
48234
0
    if (n == 0) {
48235
0
        val = date_now();
48236
0
    } else if (n == 1) {
48237
0
        JSValue v, dv;
48238
0
        if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
48239
0
            JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
48240
0
            if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data)) {
48241
0
                if (JS_ToFloat64(ctx, &val, p->u.object_data))
48242
0
                    return JS_EXCEPTION;
48243
0
                val = time_clip(val);
48244
0
                goto has_val;
48245
0
            }
48246
0
        }
48247
0
        v = JS_ToPrimitive(ctx, argv[0], HINT_NONE);
48248
0
        if (JS_IsString(v)) {
48249
0
            dv = js_Date_parse(ctx, JS_UNDEFINED, 1, (JSValueConst *)&v);
48250
0
            JS_FreeValue(ctx, v);
48251
0
            if (JS_IsException(dv))
48252
0
                return JS_EXCEPTION;
48253
0
            if (JS_ToFloat64Free(ctx, &val, dv))
48254
0
                return JS_EXCEPTION;
48255
0
        } else {
48256
0
            if (JS_ToFloat64Free(ctx, &val, v))
48257
0
                return JS_EXCEPTION;
48258
0
        }
48259
0
        val = time_clip(val);
48260
0
    } else {
48261
0
        double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
48262
0
        if (n > 7)
48263
0
            n = 7;
48264
0
        for(i = 0; i < n; i++) {
48265
0
            if (JS_ToFloat64(ctx, &a, argv[i]))
48266
0
                return JS_EXCEPTION;
48267
0
            if (!isfinite(a))
48268
0
                break;
48269
0
            fields[i] = trunc(a);
48270
0
            if (i == 0 && fields[0] >= 0 && fields[0] < 100)
48271
0
                fields[0] += 1900;
48272
0
        }
48273
0
        val = (i == n) ? set_date_fields(fields, 1) : NAN;
48274
0
    }
48275
0
has_val:
48276
#if 0
48277
    JSValueConst args[3];
48278
    args[0] = new_target;
48279
    args[1] = ctx->class_proto[JS_CLASS_DATE];
48280
    args[2] = JS_NewFloat64(ctx, val);
48281
    rv = js___date_create(ctx, JS_UNDEFINED, 3, args);
48282
#else
48283
0
    rv = js_create_from_ctor(ctx, new_target, JS_CLASS_DATE);
48284
0
    if (!JS_IsException(rv))
48285
0
        JS_SetObjectData(ctx, rv, JS_NewFloat64(ctx, val));
48286
0
#endif
48287
0
    if (!JS_IsException(rv) && JS_IsUndefined(new_target)) {
48288
        /* invoked as a function, return (new Date()).toString(); */
48289
0
        JSValue s;
48290
0
        s = get_date_string(ctx, rv, 0, NULL, 0x13);
48291
0
        JS_FreeValue(ctx, rv);
48292
0
        rv = s;
48293
0
    }
48294
0
    return rv;
48295
0
}
48296
48297
static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,
48298
                           int argc, JSValueConst *argv)
48299
0
{
48300
    // UTC(y, mon, d, h, m, s, ms)
48301
0
    double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
48302
0
    int i, n;
48303
0
    double a;
48304
48305
0
    n = argc;
48306
0
    if (n == 0)
48307
0
        return JS_NAN;
48308
0
    if (n > 7)
48309
0
        n = 7;
48310
0
    for(i = 0; i < n; i++) {
48311
0
        if (JS_ToFloat64(ctx, &a, argv[i]))
48312
0
            return JS_EXCEPTION;
48313
0
        if (!isfinite(a))
48314
0
            return JS_NAN;
48315
0
        fields[i] = trunc(a);
48316
0
        if (i == 0 && fields[0] >= 0 && fields[0] < 100)
48317
0
            fields[0] += 1900;
48318
0
    }
48319
0
    return JS_NewFloat64(ctx, set_date_fields(fields, 0));
48320
0
}
48321
48322
0
static void string_skip_spaces(JSString *sp, int *pp) {
48323
0
    while (*pp < sp->len && string_get(sp, *pp) == ' ')
48324
0
        *pp += 1;
48325
0
}
48326
48327
0
static void string_skip_non_spaces(JSString *sp, int *pp) {
48328
0
    while (*pp < sp->len && string_get(sp, *pp) != ' ')
48329
0
        *pp += 1;
48330
0
}
48331
48332
/* parse a numeric field with an optional sign if accept_sign is TRUE */
48333
0
static int string_get_digits(JSString *sp, int *pp, int64_t *pval) {
48334
0
    int64_t v = 0;
48335
0
    int c, p = *pp, p_start;
48336
    
48337
0
    if (p >= sp->len)
48338
0
        return -1;
48339
0
    p_start = p;
48340
0
    while (p < sp->len) {
48341
0
        c = string_get(sp, p);
48342
0
        if (!(c >= '0' && c <= '9')) {
48343
0
            if (p == p_start)
48344
0
                return -1;
48345
0
            else
48346
0
                break;
48347
0
        }
48348
0
        v = v * 10 + c - '0';
48349
0
        p++;
48350
0
    }
48351
0
    *pval = v;
48352
0
    *pp = p;
48353
0
    return 0;
48354
0
}
48355
48356
0
static int string_get_signed_digits(JSString *sp, int *pp, int64_t *pval) {
48357
0
    int res, sgn, p = *pp;
48358
    
48359
0
    if (p >= sp->len)
48360
0
        return -1;
48361
48362
0
    sgn = string_get(sp, p);
48363
0
    if (sgn == '-' || sgn == '+')
48364
0
        p++;
48365
 
48366
0
    res = string_get_digits(sp, &p, pval);
48367
0
    if (res == 0 && sgn == '-')
48368
0
        *pval = -*pval;
48369
0
    *pp = p;
48370
0
    return res;
48371
0
}
48372
48373
/* parse a fixed width numeric field */
48374
0
static int string_get_fixed_width_digits(JSString *sp, int *pp, int n, int64_t *pval) {
48375
0
    int64_t v = 0;
48376
0
    int i, c, p = *pp;
48377
48378
0
    for(i = 0; i < n; i++) {
48379
0
        if (p >= sp->len)
48380
0
            return -1;
48381
0
        c = string_get(sp, p);
48382
0
        if (!(c >= '0' && c <= '9'))
48383
0
            return -1;
48384
0
        v = v * 10 + c - '0';
48385
0
        p++;
48386
0
    }
48387
0
    *pval = v;
48388
0
    *pp = p;
48389
0
    return 0;
48390
0
}
48391
48392
0
static int string_get_milliseconds(JSString *sp, int *pp, int64_t *pval) {
48393
    /* parse milliseconds as a fractional part, round to nearest */
48394
    /* XXX: the spec does not indicate which rounding should be used */
48395
0
    int mul = 1000, ms = 0, p = *pp, c, p_start;
48396
0
    if (p >= sp->len)
48397
0
        return -1;
48398
0
    p_start = p;
48399
0
    while (p < sp->len) {
48400
0
        c = string_get(sp, p);
48401
0
        if (!(c >= '0' && c <= '9')) {
48402
0
            if (p == p_start)
48403
0
                return -1;
48404
0
            else
48405
0
                break;
48406
0
        }
48407
0
        if (mul == 1 && c >= '5')
48408
0
            ms += 1;
48409
0
        ms += (c - '0') * (mul /= 10);
48410
0
        p++;
48411
0
    }
48412
0
    *pval = ms;
48413
0
    *pp = p;
48414
0
    return 0;
48415
0
}
48416
48417
48418
0
static int find_abbrev(JSString *sp, int p, const char *list, int count) {
48419
0
    int n, i;
48420
48421
0
    if (p + 3 <= sp->len) {
48422
0
        for (n = 0; n < count; n++) {
48423
0
            for (i = 0; i < 3; i++) {
48424
0
                if (string_get(sp, p + i) != month_names[n * 3 + i])
48425
0
                    goto next;
48426
0
            }
48427
0
            return n;
48428
0
        next:;
48429
0
        }
48430
0
    }
48431
0
    return -1;
48432
0
}
48433
48434
0
static int string_get_month(JSString *sp, int *pp, int64_t *pval) {
48435
0
    int n;
48436
48437
0
    string_skip_spaces(sp, pp);
48438
0
    n = find_abbrev(sp, *pp, month_names, 12);
48439
0
    if (n < 0)
48440
0
        return -1;
48441
48442
0
    *pval = n;
48443
0
    *pp += 3;
48444
0
    return 0;
48445
0
}
48446
48447
static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
48448
                             int argc, JSValueConst *argv)
48449
0
{
48450
    // parse(s)
48451
0
    JSValue s, rv;
48452
0
    int64_t fields[] = { 0, 1, 1, 0, 0, 0, 0 };
48453
0
    double fields1[7];
48454
0
    int64_t tz, hh, mm;
48455
0
    double d;
48456
0
    int p, i, c, sgn, l;
48457
0
    JSString *sp;
48458
0
    BOOL is_local;
48459
    
48460
0
    rv = JS_NAN;
48461
48462
0
    s = JS_ToString(ctx, argv[0]);
48463
0
    if (JS_IsException(s))
48464
0
        return JS_EXCEPTION;
48465
    
48466
0
    sp = JS_VALUE_GET_STRING(s);
48467
0
    p = 0;
48468
0
    if (p < sp->len && (((c = string_get(sp, p)) >= '0' && c <= '9') || c == '+' || c == '-')) {
48469
        /* ISO format */
48470
        /* year field can be negative */
48471
0
        if (string_get_signed_digits(sp, &p, &fields[0]))
48472
0
            goto done;
48473
48474
0
        for (i = 1; i < 7; i++) {
48475
0
            if (p >= sp->len)
48476
0
                break;
48477
0
            switch(i) {
48478
0
            case 1:
48479
0
            case 2:
48480
0
                c = '-';
48481
0
                break;
48482
0
            case 3:
48483
0
                c = 'T';
48484
0
                break;
48485
0
            case 4:
48486
0
            case 5:
48487
0
                c = ':';
48488
0
                break;
48489
0
            case 6:
48490
0
                c = '.';
48491
0
                break;
48492
0
            }
48493
0
            if (string_get(sp, p) != c)
48494
0
                break;
48495
0
            p++;
48496
0
            if (i == 6) {
48497
0
                if (string_get_milliseconds(sp, &p, &fields[i]))
48498
0
                    goto done;
48499
0
            } else {
48500
0
                if (string_get_digits(sp, &p, &fields[i]))
48501
0
                    goto done;
48502
0
            }
48503
0
        }
48504
        /* no time: UTC by default */
48505
0
        is_local = (i > 3);
48506
0
        fields[1] -= 1;
48507
48508
        /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
48509
0
        tz = 0;
48510
0
        if (p < sp->len) {
48511
0
            sgn = string_get(sp, p);
48512
0
            if (sgn == '+' || sgn == '-') {
48513
0
                p++;
48514
0
                l = sp->len - p;
48515
0
                if (l != 4 && l != 5)
48516
0
                    goto done;
48517
0
                if (string_get_fixed_width_digits(sp, &p, 2, &hh))
48518
0
                    goto done;
48519
0
                if (l == 5) {
48520
0
                    if (string_get(sp, p) != ':')
48521
0
                        goto done;
48522
0
                    p++;
48523
0
                }
48524
0
                if (string_get_fixed_width_digits(sp, &p, 2, &mm))
48525
0
                    goto done;
48526
0
                tz = hh * 60 + mm;
48527
0
                if (sgn == '-')
48528
0
                    tz = -tz;
48529
0
                is_local = FALSE;
48530
0
            } else if (sgn == 'Z') {
48531
0
                p++;
48532
0
                is_local = FALSE;
48533
0
            } else {
48534
0
                goto done;
48535
0
            }
48536
            /* error if extraneous characters */
48537
0
            if (p != sp->len)
48538
0
                goto done;
48539
0
        }
48540
0
    } else {
48541
        /* toString or toUTCString format */
48542
        /* skip the day of the week */
48543
0
        string_skip_non_spaces(sp, &p);
48544
0
        string_skip_spaces(sp, &p);
48545
0
        if (p >= sp->len)
48546
0
            goto done;
48547
0
        c = string_get(sp, p);
48548
0
        if (c >= '0' && c <= '9') {
48549
            /* day of month first */
48550
0
            if (string_get_digits(sp, &p, &fields[2]))
48551
0
                goto done;
48552
0
            if (string_get_month(sp, &p, &fields[1]))
48553
0
                goto done;
48554
0
        } else {
48555
            /* month first */
48556
0
            if (string_get_month(sp, &p, &fields[1]))
48557
0
                goto done;
48558
0
            string_skip_spaces(sp, &p);
48559
0
            if (string_get_digits(sp, &p, &fields[2]))
48560
0
                goto done;
48561
0
        }
48562
        /* year */
48563
0
        string_skip_spaces(sp, &p);
48564
0
        if (string_get_signed_digits(sp, &p, &fields[0]))
48565
0
            goto done;
48566
48567
        /* hour, min, seconds */
48568
0
        string_skip_spaces(sp, &p);
48569
0
        for(i = 0; i < 3; i++) {
48570
0
            if (i == 1 || i == 2) {
48571
0
                if (p >= sp->len)
48572
0
                    goto done;
48573
0
                if (string_get(sp, p) != ':')
48574
0
                    goto done;
48575
0
                p++;
48576
0
            }
48577
0
            if (string_get_digits(sp, &p, &fields[3 + i]))
48578
0
                goto done;
48579
0
        }
48580
        // XXX: parse optional milliseconds?
48581
48582
        /* parse the time zone offset if present: [+-]HHmm */
48583
0
        is_local = FALSE;
48584
0
        tz = 0;
48585
0
        for (tz = 0; p < sp->len; p++) {
48586
0
            sgn = string_get(sp, p);
48587
0
            if (sgn == '+' || sgn == '-') {
48588
0
                p++;
48589
0
                if (string_get_fixed_width_digits(sp, &p, 2, &hh))
48590
0
                    goto done;
48591
0
                if (string_get_fixed_width_digits(sp, &p, 2, &mm))
48592
0
                    goto done;
48593
0
                tz = hh * 60 + mm;
48594
0
                if (sgn == '-')
48595
0
                    tz = -tz;
48596
0
                break;
48597
0
            }
48598
0
        }
48599
0
    }
48600
0
    for(i = 0; i < 7; i++)
48601
0
        fields1[i] = fields[i];
48602
0
    d = set_date_fields(fields1, is_local) - tz * 60000;
48603
0
    rv = JS_NewFloat64(ctx, d);
48604
48605
0
done:
48606
0
    JS_FreeValue(ctx, s);
48607
0
    return rv;
48608
0
}
48609
48610
static JSValue js_Date_now(JSContext *ctx, JSValueConst this_val,
48611
                           int argc, JSValueConst *argv)
48612
0
{
48613
    // now()
48614
0
    return JS_NewInt64(ctx, date_now());
48615
0
}
48616
48617
static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val,
48618
                                          int argc, JSValueConst *argv)
48619
0
{
48620
    // Symbol_toPrimitive(hint)
48621
0
    JSValueConst obj = this_val;
48622
0
    JSAtom hint = JS_ATOM_NULL;
48623
0
    int hint_num;
48624
48625
0
    if (!JS_IsObject(obj))
48626
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
48627
48628
0
    if (JS_IsString(argv[0])) {
48629
0
        hint = JS_ValueToAtom(ctx, argv[0]);
48630
0
        if (hint == JS_ATOM_NULL)
48631
0
            return JS_EXCEPTION;
48632
0
        JS_FreeAtom(ctx, hint);
48633
0
    }
48634
0
    switch (hint) {
48635
0
    case JS_ATOM_number:
48636
0
#ifdef CONFIG_BIGNUM
48637
0
    case JS_ATOM_integer:
48638
0
#endif
48639
0
        hint_num = HINT_NUMBER;
48640
0
        break;
48641
0
    case JS_ATOM_string:
48642
0
    case JS_ATOM_default:
48643
0
        hint_num = HINT_STRING;
48644
0
        break;
48645
0
    default:
48646
0
        return JS_ThrowTypeError(ctx, "invalid hint");
48647
0
    }
48648
0
    return JS_ToPrimitive(ctx, obj, hint_num | HINT_FORCE_ORDINARY);
48649
0
}
48650
48651
static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
48652
                                         int argc, JSValueConst *argv)
48653
0
{
48654
    // getTimezoneOffset()
48655
0
    double v;
48656
48657
0
    if (JS_ThisTimeValue(ctx, &v, this_val))
48658
0
        return JS_EXCEPTION;
48659
0
    if (isnan(v))
48660
0
        return JS_NAN;
48661
0
    else
48662
0
        return JS_NewInt64(ctx, getTimezoneOffset((int64_t)trunc(v)));
48663
0
}
48664
48665
static JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val,
48666
                               int argc, JSValueConst *argv)
48667
0
{
48668
    // getTime()
48669
0
    double v;
48670
48671
0
    if (JS_ThisTimeValue(ctx, &v, this_val))
48672
0
        return JS_EXCEPTION;
48673
0
    return JS_NewFloat64(ctx, v);
48674
0
}
48675
48676
static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val,
48677
                               int argc, JSValueConst *argv)
48678
0
{
48679
    // setTime(v)
48680
0
    double v;
48681
48682
0
    if (JS_ThisTimeValue(ctx, &v, this_val) || JS_ToFloat64(ctx, &v, argv[0]))
48683
0
        return JS_EXCEPTION;
48684
0
    return JS_SetThisTimeValue(ctx, this_val, time_clip(v));
48685
0
}
48686
48687
static JSValue js_date_setYear(JSContext *ctx, JSValueConst this_val,
48688
                               int argc, JSValueConst *argv)
48689
0
{
48690
    // setYear(y)
48691
0
    double y;
48692
0
    JSValueConst args[1];
48693
48694
0
    if (JS_ThisTimeValue(ctx, &y, this_val) || JS_ToFloat64(ctx, &y, argv[0]))
48695
0
        return JS_EXCEPTION;
48696
0
    y = +y;
48697
0
    if (isfinite(y)) {
48698
0
        y = trunc(y);
48699
0
        if (y >= 0 && y < 100)
48700
0
            y += 1900;
48701
0
    }
48702
0
    args[0] = JS_NewFloat64(ctx, y);
48703
0
    return set_date_field(ctx, this_val, 1, args, 0x011);
48704
0
}
48705
48706
static JSValue js_date_toJSON(JSContext *ctx, JSValueConst this_val,
48707
                              int argc, JSValueConst *argv)
48708
0
{
48709
    // toJSON(key)
48710
0
    JSValue obj, tv, method, rv;
48711
0
    double d;
48712
48713
0
    rv = JS_EXCEPTION;
48714
0
    tv = JS_UNDEFINED;
48715
48716
0
    obj = JS_ToObject(ctx, this_val);
48717
0
    tv = JS_ToPrimitive(ctx, obj, HINT_NUMBER);
48718
0
    if (JS_IsException(tv))
48719
0
        goto exception;
48720
0
    if (JS_IsNumber(tv)) {
48721
0
        if (JS_ToFloat64(ctx, &d, tv) < 0)
48722
0
            goto exception;
48723
0
        if (!isfinite(d)) {
48724
0
            rv = JS_NULL;
48725
0
            goto done;
48726
0
        }
48727
0
    }
48728
0
    method = JS_GetPropertyStr(ctx, obj, "toISOString");
48729
0
    if (JS_IsException(method))
48730
0
        goto exception;
48731
0
    if (!JS_IsFunction(ctx, method)) {
48732
0
        JS_ThrowTypeError(ctx, "object needs toISOString method");
48733
0
        JS_FreeValue(ctx, method);
48734
0
        goto exception;
48735
0
    }
48736
0
    rv = JS_CallFree(ctx, method, obj, 0, NULL);
48737
0
exception:
48738
0
done:
48739
0
    JS_FreeValue(ctx, obj);
48740
0
    JS_FreeValue(ctx, tv);
48741
0
    return rv;
48742
0
}
48743
48744
static const JSCFunctionListEntry js_date_funcs[] = {
48745
    JS_CFUNC_DEF("now", 0, js_Date_now ),
48746
    JS_CFUNC_DEF("parse", 1, js_Date_parse ),
48747
    JS_CFUNC_DEF("UTC", 7, js_Date_UTC ),
48748
};
48749
48750
static const JSCFunctionListEntry js_date_proto_funcs[] = {
48751
    JS_CFUNC_DEF("valueOf", 0, js_date_getTime ),
48752
    JS_CFUNC_MAGIC_DEF("toString", 0, get_date_string, 0x13 ),
48753
    JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_date_Symbol_toPrimitive ),
48754
    JS_CFUNC_MAGIC_DEF("toUTCString", 0, get_date_string, 0x03 ),
48755
    JS_ALIAS_DEF("toGMTString", "toUTCString" ),
48756
    JS_CFUNC_MAGIC_DEF("toISOString", 0, get_date_string, 0x23 ),
48757
    JS_CFUNC_MAGIC_DEF("toDateString", 0, get_date_string, 0x11 ),
48758
    JS_CFUNC_MAGIC_DEF("toTimeString", 0, get_date_string, 0x12 ),
48759
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, get_date_string, 0x33 ),
48760
    JS_CFUNC_MAGIC_DEF("toLocaleDateString", 0, get_date_string, 0x31 ),
48761
    JS_CFUNC_MAGIC_DEF("toLocaleTimeString", 0, get_date_string, 0x32 ),
48762
    JS_CFUNC_DEF("getTimezoneOffset", 0, js_date_getTimezoneOffset ),
48763
    JS_CFUNC_DEF("getTime", 0, js_date_getTime ),
48764
    JS_CFUNC_MAGIC_DEF("getYear", 0, get_date_field, 0x101 ),
48765
    JS_CFUNC_MAGIC_DEF("getFullYear", 0, get_date_field, 0x01 ),
48766
    JS_CFUNC_MAGIC_DEF("getUTCFullYear", 0, get_date_field, 0x00 ),
48767
    JS_CFUNC_MAGIC_DEF("getMonth", 0, get_date_field, 0x11 ),
48768
    JS_CFUNC_MAGIC_DEF("getUTCMonth", 0, get_date_field, 0x10 ),
48769
    JS_CFUNC_MAGIC_DEF("getDate", 0, get_date_field, 0x21 ),
48770
    JS_CFUNC_MAGIC_DEF("getUTCDate", 0, get_date_field, 0x20 ),
48771
    JS_CFUNC_MAGIC_DEF("getHours", 0, get_date_field, 0x31 ),
48772
    JS_CFUNC_MAGIC_DEF("getUTCHours", 0, get_date_field, 0x30 ),
48773
    JS_CFUNC_MAGIC_DEF("getMinutes", 0, get_date_field, 0x41 ),
48774
    JS_CFUNC_MAGIC_DEF("getUTCMinutes", 0, get_date_field, 0x40 ),
48775
    JS_CFUNC_MAGIC_DEF("getSeconds", 0, get_date_field, 0x51 ),
48776
    JS_CFUNC_MAGIC_DEF("getUTCSeconds", 0, get_date_field, 0x50 ),
48777
    JS_CFUNC_MAGIC_DEF("getMilliseconds", 0, get_date_field, 0x61 ),
48778
    JS_CFUNC_MAGIC_DEF("getUTCMilliseconds", 0, get_date_field, 0x60 ),
48779
    JS_CFUNC_MAGIC_DEF("getDay", 0, get_date_field, 0x71 ),
48780
    JS_CFUNC_MAGIC_DEF("getUTCDay", 0, get_date_field, 0x70 ),
48781
    JS_CFUNC_DEF("setTime", 1, js_date_setTime ),
48782
    JS_CFUNC_MAGIC_DEF("setMilliseconds", 1, set_date_field, 0x671 ),
48783
    JS_CFUNC_MAGIC_DEF("setUTCMilliseconds", 1, set_date_field, 0x670 ),
48784
    JS_CFUNC_MAGIC_DEF("setSeconds", 2, set_date_field, 0x571 ),
48785
    JS_CFUNC_MAGIC_DEF("setUTCSeconds", 2, set_date_field, 0x570 ),
48786
    JS_CFUNC_MAGIC_DEF("setMinutes", 3, set_date_field, 0x471 ),
48787
    JS_CFUNC_MAGIC_DEF("setUTCMinutes", 3, set_date_field, 0x470 ),
48788
    JS_CFUNC_MAGIC_DEF("setHours", 4, set_date_field, 0x371 ),
48789
    JS_CFUNC_MAGIC_DEF("setUTCHours", 4, set_date_field, 0x370 ),
48790
    JS_CFUNC_MAGIC_DEF("setDate", 1, set_date_field, 0x231 ),
48791
    JS_CFUNC_MAGIC_DEF("setUTCDate", 1, set_date_field, 0x230 ),
48792
    JS_CFUNC_MAGIC_DEF("setMonth", 2, set_date_field, 0x131 ),
48793
    JS_CFUNC_MAGIC_DEF("setUTCMonth", 2, set_date_field, 0x130 ),
48794
    JS_CFUNC_DEF("setYear", 1, js_date_setYear ),
48795
    JS_CFUNC_MAGIC_DEF("setFullYear", 3, set_date_field, 0x031 ),
48796
    JS_CFUNC_MAGIC_DEF("setUTCFullYear", 3, set_date_field, 0x030 ),
48797
    JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ),
48798
};
48799
48800
void JS_AddIntrinsicDate(JSContext *ctx)
48801
2
{
48802
2
    JSValueConst obj;
48803
48804
    /* Date */
48805
2
    ctx->class_proto[JS_CLASS_DATE] = JS_NewObject(ctx);
48806
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATE], js_date_proto_funcs,
48807
2
                               countof(js_date_proto_funcs));
48808
2
    obj = JS_NewGlobalCConstructor(ctx, "Date", js_date_constructor, 7,
48809
2
                                   ctx->class_proto[JS_CLASS_DATE]);
48810
2
    JS_SetPropertyFunctionList(ctx, obj, js_date_funcs, countof(js_date_funcs));
48811
2
}
48812
48813
/* eval */
48814
48815
void JS_AddIntrinsicEval(JSContext *ctx)
48816
2
{
48817
2
    ctx->eval_internal = __JS_EvalInternal;
48818
2
}
48819
48820
#ifdef CONFIG_BIGNUM
48821
48822
/* Operators */
48823
48824
static void js_operator_set_finalizer(JSRuntime *rt, JSValue val)
48825
0
{
48826
0
    JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
48827
0
    int i, j;
48828
0
    JSBinaryOperatorDefEntry *ent;
48829
    
48830
0
    if (opset) {
48831
0
        for(i = 0; i < JS_OVOP_COUNT; i++) {
48832
0
            if (opset->self_ops[i])
48833
0
                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]));
48834
0
        }
48835
0
        for(j = 0; j < opset->left.count; j++) {
48836
0
            ent = &opset->left.tab[j];
48837
0
            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
48838
0
                if (ent->ops[i])
48839
0
                    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
48840
0
            }
48841
0
        }
48842
0
        js_free_rt(rt, opset->left.tab);
48843
0
        for(j = 0; j < opset->right.count; j++) {
48844
0
            ent = &opset->right.tab[j];
48845
0
            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
48846
0
                if (ent->ops[i])
48847
0
                    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
48848
0
            }
48849
0
        }
48850
0
        js_free_rt(rt, opset->right.tab);
48851
0
        js_free_rt(rt, opset);
48852
0
    }
48853
0
}
48854
48855
static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
48856
                                 JS_MarkFunc *mark_func)
48857
0
{
48858
0
    JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
48859
0
    int i, j;
48860
0
    JSBinaryOperatorDefEntry *ent;
48861
    
48862
0
    if (opset) {
48863
0
        for(i = 0; i < JS_OVOP_COUNT; i++) {
48864
0
            if (opset->self_ops[i])
48865
0
                JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]),
48866
0
                             mark_func);
48867
0
        }
48868
0
        for(j = 0; j < opset->left.count; j++) {
48869
0
            ent = &opset->left.tab[j];
48870
0
            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
48871
0
                if (ent->ops[i])
48872
0
                    JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
48873
0
                                 mark_func);
48874
0
            }
48875
0
        }
48876
0
        for(j = 0; j < opset->right.count; j++) {
48877
0
            ent = &opset->right.tab[j];
48878
0
            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
48879
0
                if (ent->ops[i])
48880
0
                    JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
48881
0
                                 mark_func);
48882
0
            }
48883
0
        }
48884
0
    }
48885
0
}
48886
48887
48888
/* create an OperatorSet object */
48889
static JSValue js_operators_create_internal(JSContext *ctx,
48890
                                            int argc, JSValueConst *argv,
48891
                                            BOOL is_primitive)
48892
0
{
48893
0
    JSValue opset_obj, prop, obj;
48894
0
    JSOperatorSetData *opset, *opset1;
48895
0
    JSBinaryOperatorDef *def;
48896
0
    JSValueConst arg;
48897
0
    int i, j;
48898
0
    JSBinaryOperatorDefEntry *new_tab;
48899
0
    JSBinaryOperatorDefEntry *ent;
48900
0
    uint32_t op_count;
48901
48902
0
    if (ctx->rt->operator_count == UINT32_MAX) {
48903
0
        return JS_ThrowTypeError(ctx, "too many operators");
48904
0
    }
48905
0
    opset_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_OPERATOR_SET);
48906
0
    if (JS_IsException(opset_obj))
48907
0
        goto fail;
48908
0
    opset = js_mallocz(ctx, sizeof(*opset));
48909
0
    if (!opset)
48910
0
        goto fail;
48911
0
    JS_SetOpaque(opset_obj, opset);
48912
0
    if (argc >= 1) {
48913
0
        arg = argv[0];
48914
        /* self operators */
48915
0
        for(i = 0; i < JS_OVOP_COUNT; i++) {
48916
0
            prop = JS_GetPropertyStr(ctx, arg, js_overloadable_operator_names[i]);
48917
0
            if (JS_IsException(prop))
48918
0
                goto fail;
48919
0
            if (!JS_IsUndefined(prop)) {
48920
0
                if (check_function(ctx, prop)) {
48921
0
                    JS_FreeValue(ctx, prop);
48922
0
                    goto fail;
48923
0
                }
48924
0
                opset->self_ops[i] = JS_VALUE_GET_OBJ(prop);
48925
0
            }
48926
0
        }
48927
0
    }
48928
    /* left & right operators */
48929
0
    for(j = 1; j < argc; j++) {
48930
0
        arg = argv[j];
48931
0
        prop = JS_GetPropertyStr(ctx, arg, "left");
48932
0
        if (JS_IsException(prop))
48933
0
            goto fail;
48934
0
        def = &opset->right;
48935
0
        if (JS_IsUndefined(prop)) {
48936
0
            prop = JS_GetPropertyStr(ctx, arg, "right");
48937
0
            if (JS_IsException(prop))
48938
0
                goto fail;
48939
0
            if (JS_IsUndefined(prop)) {
48940
0
                JS_ThrowTypeError(ctx, "left or right property must be present");
48941
0
                goto fail;
48942
0
            }
48943
0
            def = &opset->left;
48944
0
        }
48945
        /* get the operator set */
48946
0
        obj = JS_GetProperty(ctx, prop, JS_ATOM_prototype);
48947
0
        JS_FreeValue(ctx, prop);
48948
0
        if (JS_IsException(obj))
48949
0
            goto fail;
48950
0
        prop = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
48951
0
        JS_FreeValue(ctx, obj);
48952
0
        if (JS_IsException(prop))
48953
0
            goto fail;
48954
0
        opset1 = JS_GetOpaque2(ctx, prop, JS_CLASS_OPERATOR_SET);
48955
0
        if (!opset1) {
48956
0
            JS_FreeValue(ctx, prop);
48957
0
            goto fail;
48958
0
        }
48959
0
        op_count = opset1->operator_counter;
48960
0
        JS_FreeValue(ctx, prop);
48961
        
48962
        /* we assume there are few entries */
48963
0
        new_tab = js_realloc(ctx, def->tab,
48964
0
                             (def->count + 1) * sizeof(def->tab[0]));
48965
0
        if (!new_tab)
48966
0
            goto fail;
48967
0
        def->tab = new_tab;
48968
0
        def->count++;
48969
0
        ent = def->tab + def->count - 1;
48970
0
        memset(ent, 0, sizeof(def->tab[0]));
48971
0
        ent->operator_index = op_count;
48972
        
48973
0
        for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
48974
0
            prop = JS_GetPropertyStr(ctx, arg,
48975
0
                                     js_overloadable_operator_names[i]);
48976
0
            if (JS_IsException(prop))
48977
0
                goto fail;
48978
0
            if (!JS_IsUndefined(prop)) {
48979
0
                if (check_function(ctx, prop)) {
48980
0
                    JS_FreeValue(ctx, prop);
48981
0
                    goto fail;
48982
0
                }
48983
0
                ent->ops[i] = JS_VALUE_GET_OBJ(prop);
48984
0
            }
48985
0
        }
48986
0
    }
48987
0
    opset->is_primitive = is_primitive;
48988
0
    opset->operator_counter = ctx->rt->operator_count++;
48989
0
    return opset_obj;
48990
0
 fail:
48991
0
    JS_FreeValue(ctx, opset_obj);
48992
0
    return JS_EXCEPTION;
48993
0
}
48994
48995
static JSValue js_operators_create(JSContext *ctx, JSValueConst this_val,
48996
                                int argc, JSValueConst *argv)
48997
0
{
48998
0
    return js_operators_create_internal(ctx, argc, argv, FALSE);
48999
0
}
49000
49001
static JSValue js_operators_updateBigIntOperators(JSContext *ctx, JSValueConst this_val,
49002
                                                  int argc, JSValueConst *argv)
49003
0
{
49004
0
    JSValue opset_obj, prop;
49005
0
    JSOperatorSetData *opset;
49006
0
    const JSOverloadableOperatorEnum ops[2] = { JS_OVOP_DIV, JS_OVOP_POW };
49007
0
    JSOverloadableOperatorEnum op;
49008
0
    int i;
49009
    
49010
0
    opset_obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
49011
0
                               JS_ATOM_Symbol_operatorSet);
49012
0
    if (JS_IsException(opset_obj))
49013
0
        goto fail;
49014
0
    opset = JS_GetOpaque2(ctx, opset_obj, JS_CLASS_OPERATOR_SET);
49015
0
    if (!opset)
49016
0
        goto fail;
49017
0
    for(i = 0; i < countof(ops); i++) {
49018
0
        op = ops[i];
49019
0
        prop = JS_GetPropertyStr(ctx, argv[0],
49020
0
                                 js_overloadable_operator_names[op]);
49021
0
        if (JS_IsException(prop))
49022
0
            goto fail;
49023
0
        if (!JS_IsUndefined(prop)) {
49024
0
            if (!JS_IsNull(prop) && check_function(ctx, prop)) {
49025
0
                JS_FreeValue(ctx, prop);
49026
0
                goto fail;
49027
0
            }
49028
0
            if (opset->self_ops[op])
49029
0
                JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[op]));
49030
0
            if (JS_IsNull(prop)) {
49031
0
                opset->self_ops[op] = NULL;
49032
0
            } else {
49033
0
                opset->self_ops[op] = JS_VALUE_GET_PTR(prop);
49034
0
            }
49035
0
        }
49036
0
    }
49037
0
    JS_FreeValue(ctx, opset_obj);
49038
0
    return JS_UNDEFINED;
49039
0
 fail:
49040
0
    JS_FreeValue(ctx, opset_obj);
49041
0
    return JS_EXCEPTION;
49042
0
}
49043
49044
static int js_operators_set_default(JSContext *ctx, JSValueConst obj)
49045
0
{
49046
0
    JSValue opset_obj;
49047
49048
0
    if (!JS_IsObject(obj)) /* in case the prototype is not defined */
49049
0
        return 0;
49050
0
    opset_obj = js_operators_create_internal(ctx, 0, NULL, TRUE);
49051
0
    if (JS_IsException(opset_obj))
49052
0
        return -1;
49053
    /* cannot be modified by the user */
49054
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_operatorSet,
49055
0
                           opset_obj, 0);
49056
0
    return 0;
49057
0
}
49058
49059
static JSValue js_dummy_operators_ctor(JSContext *ctx, JSValueConst new_target,
49060
                                       int argc, JSValueConst *argv)
49061
0
{
49062
0
    return js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
49063
0
}
49064
49065
static JSValue js_global_operators(JSContext *ctx, JSValueConst this_val,
49066
                                   int argc, JSValueConst *argv)
49067
0
{
49068
0
    JSValue func_obj, proto, opset_obj;
49069
49070
0
    func_obj = JS_UNDEFINED;
49071
0
    proto = JS_NewObject(ctx);
49072
0
    if (JS_IsException(proto))
49073
0
        return JS_EXCEPTION;
49074
0
    opset_obj = js_operators_create_internal(ctx, argc, argv, FALSE);
49075
0
    if (JS_IsException(opset_obj))
49076
0
        goto fail;
49077
0
    JS_DefinePropertyValue(ctx, proto, JS_ATOM_Symbol_operatorSet,
49078
0
                           opset_obj, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
49079
0
    func_obj = JS_NewCFunction2(ctx, js_dummy_operators_ctor, "Operators",
49080
0
                                0, JS_CFUNC_constructor, 0);
49081
0
    if (JS_IsException(func_obj))
49082
0
        goto fail;
49083
0
    JS_SetConstructor2(ctx, func_obj, proto,
49084
0
                       0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
49085
0
    JS_FreeValue(ctx, proto);
49086
0
    return func_obj;
49087
0
 fail:
49088
0
    JS_FreeValue(ctx, proto);
49089
0
    JS_FreeValue(ctx, func_obj);
49090
0
    return JS_EXCEPTION;
49091
0
}
49092
49093
static const JSCFunctionListEntry js_operators_funcs[] = {
49094
    JS_CFUNC_DEF("create", 1, js_operators_create ),
49095
    JS_CFUNC_DEF("updateBigIntOperators", 2, js_operators_updateBigIntOperators ),
49096
};
49097
49098
/* must be called after all overloadable base types are initialized */
49099
void JS_AddIntrinsicOperators(JSContext *ctx)
49100
0
{
49101
0
    JSValue obj;
49102
49103
0
    ctx->allow_operator_overloading = TRUE;
49104
0
    obj = JS_NewCFunction(ctx, js_global_operators, "Operators", 1);
49105
0
    JS_SetPropertyFunctionList(ctx, obj,
49106
0
                               js_operators_funcs,
49107
0
                               countof(js_operators_funcs));
49108
0
    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Operators,
49109
0
                           obj,
49110
0
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
49111
    /* add default operatorSets */
49112
0
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BOOLEAN]);
49113
0
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_NUMBER]);
49114
0
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_STRING]);
49115
0
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_INT]);
49116
0
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT]);
49117
0
    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
49118
0
}
49119
49120
/* BigInt */
49121
49122
static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
49123
0
{
49124
0
    uint32_t tag;
49125
49126
0
 redo:
49127
0
    tag = JS_VALUE_GET_NORM_TAG(val);
49128
0
    switch(tag) {
49129
0
    case JS_TAG_INT:
49130
0
    case JS_TAG_BOOL:
49131
0
        val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));
49132
0
        break;
49133
0
    case JS_TAG_BIG_INT:
49134
0
        break;
49135
0
    case JS_TAG_FLOAT64:
49136
0
    case JS_TAG_BIG_FLOAT:
49137
0
        {
49138
0
            bf_t *a, a_s;
49139
            
49140
0
            a = JS_ToBigFloat(ctx, &a_s, val);
49141
0
            if (!bf_is_finite(a)) {
49142
0
                JS_FreeValue(ctx, val);
49143
0
                val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint");
49144
0
            } else {
49145
0
                JSValue val1 = JS_NewBigInt(ctx);
49146
0
                bf_t *r;
49147
0
                int ret;
49148
0
                if (JS_IsException(val1)) {
49149
0
                    JS_FreeValue(ctx, val);
49150
0
                    return JS_EXCEPTION;
49151
0
                }
49152
0
                r = JS_GetBigInt(val1);
49153
0
                ret = bf_set(r, a);
49154
0
                ret |= bf_rint(r, BF_RNDZ);
49155
0
                JS_FreeValue(ctx, val);
49156
0
                if (ret & BF_ST_MEM_ERROR) {
49157
0
                    JS_FreeValue(ctx, val1);
49158
0
                    val = JS_ThrowOutOfMemory(ctx);
49159
0
                } else if (ret & BF_ST_INEXACT) {
49160
0
                    JS_FreeValue(ctx, val1);
49161
0
                    val = JS_ThrowRangeError(ctx, "cannot convert to bigint: not an integer");
49162
0
                } else {
49163
0
                    val = JS_CompactBigInt(ctx, val1);
49164
0
                }
49165
0
            }
49166
0
            if (a == &a_s)
49167
0
                bf_delete(a);
49168
0
        }
49169
0
        break;
49170
0
    case JS_TAG_BIG_DECIMAL:
49171
0
        val = JS_ToStringFree(ctx, val);
49172
0
         if (JS_IsException(val))
49173
0
            break;
49174
0
        goto redo;
49175
0
    case JS_TAG_STRING:
49176
0
        val = JS_StringToBigIntErr(ctx, val);
49177
0
        break;
49178
0
    case JS_TAG_OBJECT:
49179
0
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
49180
0
        if (JS_IsException(val))
49181
0
            break;
49182
0
        goto redo;
49183
0
    case JS_TAG_NULL:
49184
0
    case JS_TAG_UNDEFINED:
49185
0
    default:
49186
0
        JS_FreeValue(ctx, val);
49187
0
        return JS_ThrowTypeError(ctx, "cannot convert to bigint");
49188
0
    }
49189
0
    return val;
49190
0
}
49191
49192
static JSValue js_bigint_constructor(JSContext *ctx,
49193
                                     JSValueConst new_target,
49194
                                     int argc, JSValueConst *argv)
49195
0
{
49196
0
    if (!JS_IsUndefined(new_target))
49197
0
        return JS_ThrowTypeError(ctx, "not a constructor");
49198
0
    return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
49199
0
}
49200
49201
static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
49202
0
{
49203
0
    if (JS_IsBigInt(ctx, this_val))
49204
0
        return JS_DupValue(ctx, this_val);
49205
49206
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
49207
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
49208
0
        if (p->class_id == JS_CLASS_BIG_INT) {
49209
0
            if (JS_IsBigInt(ctx, p->u.object_data))
49210
0
                return JS_DupValue(ctx, p->u.object_data);
49211
0
        }
49212
0
    }
49213
0
    return JS_ThrowTypeError(ctx, "not a bigint");
49214
0
}
49215
49216
static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val,
49217
                                  int argc, JSValueConst *argv)
49218
0
{
49219
0
    JSValue val;
49220
0
    int base;
49221
0
    JSValue ret;
49222
49223
0
    val = js_thisBigIntValue(ctx, this_val);
49224
0
    if (JS_IsException(val))
49225
0
        return val;
49226
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
49227
0
        base = 10;
49228
0
    } else {
49229
0
        base = js_get_radix(ctx, argv[0]);
49230
0
        if (base < 0)
49231
0
            goto fail;
49232
0
    }
49233
0
    ret = js_bigint_to_string1(ctx, val, base);
49234
0
    JS_FreeValue(ctx, val);
49235
0
    return ret;
49236
0
 fail:
49237
0
    JS_FreeValue(ctx, val);
49238
0
    return JS_EXCEPTION;
49239
0
}
49240
49241
static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val,
49242
                                 int argc, JSValueConst *argv)
49243
0
{
49244
0
    return js_thisBigIntValue(ctx, this_val);
49245
0
}
49246
49247
static JSValue js_bigint_div(JSContext *ctx,
49248
                              JSValueConst this_val,
49249
                              int argc, JSValueConst *argv, int magic)
49250
0
{
49251
0
    bf_t a_s, b_s, *a, *b, *r, *q;
49252
0
    int status;
49253
0
    JSValue q_val, r_val;
49254
    
49255
0
    q_val = JS_NewBigInt(ctx);
49256
0
    if (JS_IsException(q_val))
49257
0
        return JS_EXCEPTION;
49258
0
    r_val = JS_NewBigInt(ctx);
49259
0
    if (JS_IsException(r_val))
49260
0
        goto fail;
49261
0
    b = NULL;
49262
0
    a = JS_ToBigInt(ctx, &a_s, argv[0]);
49263
0
    if (!a)
49264
0
        goto fail;
49265
0
    b = JS_ToBigInt(ctx, &b_s, argv[1]);
49266
0
    if (!b) {
49267
0
        JS_FreeBigInt(ctx, a, &a_s);
49268
0
        goto fail;
49269
0
    }
49270
0
    q = JS_GetBigInt(q_val);
49271
0
    r = JS_GetBigInt(r_val);
49272
0
    status = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, magic & 0xf);
49273
0
    JS_FreeBigInt(ctx, a, &a_s);
49274
0
    JS_FreeBigInt(ctx, b, &b_s);
49275
0
    if (unlikely(status)) {
49276
0
        throw_bf_exception(ctx, status);
49277
0
        goto fail;
49278
0
    }
49279
0
    q_val = JS_CompactBigInt(ctx, q_val);
49280
0
    if (magic & 0x10) {
49281
0
        JSValue ret;
49282
0
        ret = JS_NewArray(ctx);
49283
0
        if (JS_IsException(ret))
49284
0
            goto fail;
49285
0
        JS_SetPropertyUint32(ctx, ret, 0, q_val);
49286
0
        JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, r_val));
49287
0
        return ret;
49288
0
    } else {
49289
0
        JS_FreeValue(ctx, r_val);
49290
0
        return q_val;
49291
0
    }
49292
0
 fail:
49293
0
    JS_FreeValue(ctx, q_val);
49294
0
    JS_FreeValue(ctx, r_val);
49295
0
    return JS_EXCEPTION;
49296
0
}
49297
49298
static JSValue js_bigint_sqrt(JSContext *ctx,
49299
                               JSValueConst this_val,
49300
                               int argc, JSValueConst *argv, int magic)
49301
0
{
49302
0
    bf_t a_s, *a, *r, *rem;
49303
0
    int status;
49304
0
    JSValue r_val, rem_val;
49305
    
49306
0
    r_val = JS_NewBigInt(ctx);
49307
0
    if (JS_IsException(r_val))
49308
0
        return JS_EXCEPTION;
49309
0
    rem_val = JS_NewBigInt(ctx);
49310
0
    if (JS_IsException(rem_val))
49311
0
        return JS_EXCEPTION;
49312
0
    r = JS_GetBigInt(r_val);
49313
0
    rem = JS_GetBigInt(rem_val);
49314
49315
0
    a = JS_ToBigInt(ctx, &a_s, argv[0]);
49316
0
    if (!a)
49317
0
        goto fail;
49318
0
    status = bf_sqrtrem(r, rem, a);
49319
0
    JS_FreeBigInt(ctx, a, &a_s);
49320
0
    if (unlikely(status & ~BF_ST_INEXACT)) {
49321
0
        throw_bf_exception(ctx, status);
49322
0
        goto fail;
49323
0
    }
49324
0
    r_val = JS_CompactBigInt(ctx, r_val);
49325
0
    if (magic) {
49326
0
        JSValue ret;
49327
0
        ret = JS_NewArray(ctx);
49328
0
        if (JS_IsException(ret))
49329
0
            goto fail;
49330
0
        JS_SetPropertyUint32(ctx, ret, 0, r_val);
49331
0
        JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, rem_val));
49332
0
        return ret;
49333
0
    } else {
49334
0
        JS_FreeValue(ctx, rem_val);
49335
0
        return r_val;
49336
0
    }
49337
0
 fail:
49338
0
    JS_FreeValue(ctx, r_val);
49339
0
    JS_FreeValue(ctx, rem_val);
49340
0
    return JS_EXCEPTION;
49341
0
}
49342
49343
static JSValue js_bigint_op1(JSContext *ctx,
49344
                              JSValueConst this_val,
49345
                              int argc, JSValueConst *argv,
49346
                              int magic)
49347
0
{
49348
0
    bf_t a_s, *a;
49349
0
    int64_t res;
49350
49351
0
    a = JS_ToBigInt(ctx, &a_s, argv[0]);
49352
0
    if (!a)
49353
0
        return JS_EXCEPTION;
49354
0
    switch(magic) {
49355
0
    case 0: /* floorLog2 */
49356
0
        if (a->sign || a->expn <= 0) {
49357
0
            res = -1;
49358
0
        } else {
49359
0
            res = a->expn - 1;
49360
0
        }
49361
0
        break;
49362
0
    case 1: /* ctz */
49363
0
        if (bf_is_zero(a)) {
49364
0
            res = -1;
49365
0
        } else {
49366
0
            res = bf_get_exp_min(a);
49367
0
        }
49368
0
        break;
49369
0
    default:
49370
0
        abort();
49371
0
    }
49372
0
    JS_FreeBigInt(ctx, a, &a_s);
49373
0
    return JS_NewBigInt64(ctx, res);
49374
0
}
49375
49376
static JSValue js_bigint_asUintN(JSContext *ctx,
49377
                                  JSValueConst this_val,
49378
                                  int argc, JSValueConst *argv, int asIntN)
49379
0
{
49380
0
    uint64_t bits;
49381
0
    bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s;
49382
0
    JSValue res;
49383
    
49384
0
    if (JS_ToIndex(ctx, &bits, argv[0]))
49385
0
        return JS_EXCEPTION;
49386
0
    res = JS_NewBigInt(ctx);
49387
0
    if (JS_IsException(res))
49388
0
        return JS_EXCEPTION;
49389
0
    r = JS_GetBigInt(res);
49390
0
    a = JS_ToBigInt(ctx, &a_s, argv[1]);
49391
0
    if (!a) {
49392
0
        JS_FreeValue(ctx, res);
49393
0
        return JS_EXCEPTION;
49394
0
    }
49395
    /* XXX: optimize */
49396
0
    r = JS_GetBigInt(res);
49397
0
    bf_init(ctx->bf_ctx, mask);
49398
0
    bf_set_ui(mask, 1);
49399
0
    bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
49400
0
    bf_add_si(mask, mask, -1, BF_PREC_INF, BF_RNDZ);
49401
0
    bf_logic_and(r, a, mask);
49402
0
    if (asIntN && bits != 0) {
49403
0
        bf_set_ui(mask, 1);
49404
0
        bf_mul_2exp(mask, bits - 1, BF_PREC_INF, BF_RNDZ);
49405
0
        if (bf_cmpu(r, mask) >= 0) {
49406
0
            bf_set_ui(mask, 1);
49407
0
            bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
49408
0
            bf_sub(r, r, mask, BF_PREC_INF, BF_RNDZ);
49409
0
        }
49410
0
    }
49411
0
    bf_delete(mask);
49412
0
    JS_FreeBigInt(ctx, a, &a_s);
49413
0
    return JS_CompactBigInt(ctx, res);
49414
0
}
49415
49416
static const JSCFunctionListEntry js_bigint_funcs[] = {
49417
    JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ),
49418
    JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ),
49419
    /* QuickJS extensions */
49420
    JS_CFUNC_MAGIC_DEF("tdiv", 2, js_bigint_div, BF_RNDZ ),
49421
    JS_CFUNC_MAGIC_DEF("fdiv", 2, js_bigint_div, BF_RNDD ),
49422
    JS_CFUNC_MAGIC_DEF("cdiv", 2, js_bigint_div, BF_RNDU ),
49423
    JS_CFUNC_MAGIC_DEF("ediv", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN ),
49424
    JS_CFUNC_MAGIC_DEF("tdivrem", 2, js_bigint_div, BF_RNDZ | 0x10 ),
49425
    JS_CFUNC_MAGIC_DEF("fdivrem", 2, js_bigint_div, BF_RNDD | 0x10 ),
49426
    JS_CFUNC_MAGIC_DEF("cdivrem", 2, js_bigint_div, BF_RNDU | 0x10 ),
49427
    JS_CFUNC_MAGIC_DEF("edivrem", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN | 0x10 ),
49428
    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigint_sqrt, 0 ),
49429
    JS_CFUNC_MAGIC_DEF("sqrtrem", 1, js_bigint_sqrt, 1 ),
49430
    JS_CFUNC_MAGIC_DEF("floorLog2", 1, js_bigint_op1, 0 ),
49431
    JS_CFUNC_MAGIC_DEF("ctz", 1, js_bigint_op1, 1 ),
49432
};
49433
49434
static const JSCFunctionListEntry js_bigint_proto_funcs[] = {
49435
    JS_CFUNC_DEF("toString", 0, js_bigint_toString ),
49436
    JS_CFUNC_DEF("valueOf", 0, js_bigint_valueOf ),
49437
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "BigInt", JS_PROP_CONFIGURABLE ),
49438
};
49439
49440
void JS_AddIntrinsicBigInt(JSContext *ctx)
49441
2
{
49442
2
    JSRuntime *rt = ctx->rt;
49443
2
    JSValueConst obj1;
49444
49445
2
    rt->bigint_ops.to_string = js_bigint_to_string;
49446
2
    rt->bigint_ops.from_string = js_string_to_bigint;
49447
2
    rt->bigint_ops.unary_arith = js_unary_arith_bigint;
49448
2
    rt->bigint_ops.binary_arith = js_binary_arith_bigint;
49449
2
    rt->bigint_ops.compare = js_compare_bigfloat;
49450
    
49451
2
    ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx);
49452
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
49453
2
                               js_bigint_proto_funcs,
49454
2
                               countof(js_bigint_proto_funcs));
49455
2
    obj1 = JS_NewGlobalCConstructor(ctx, "BigInt", js_bigint_constructor, 1,
49456
2
                                    ctx->class_proto[JS_CLASS_BIG_INT]);
49457
2
    JS_SetPropertyFunctionList(ctx, obj1, js_bigint_funcs,
49458
2
                               countof(js_bigint_funcs));
49459
2
}
49460
49461
/* BigFloat */
49462
49463
static JSValue js_thisBigFloatValue(JSContext *ctx, JSValueConst this_val)
49464
0
{
49465
0
    if (JS_IsBigFloat(this_val))
49466
0
        return JS_DupValue(ctx, this_val);
49467
49468
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
49469
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
49470
0
        if (p->class_id == JS_CLASS_BIG_FLOAT) {
49471
0
            if (JS_IsBigFloat(p->u.object_data))
49472
0
                return JS_DupValue(ctx, p->u.object_data);
49473
0
        }
49474
0
    }
49475
0
    return JS_ThrowTypeError(ctx, "not a bigfloat");
49476
0
}
49477
49478
static JSValue js_bigfloat_toString(JSContext *ctx, JSValueConst this_val,
49479
                                    int argc, JSValueConst *argv)
49480
0
{
49481
0
    JSValue val;
49482
0
    int base;
49483
0
    JSValue ret;
49484
49485
0
    val = js_thisBigFloatValue(ctx, this_val);
49486
0
    if (JS_IsException(val))
49487
0
        return val;
49488
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
49489
0
        base = 10;
49490
0
    } else {
49491
0
        base = js_get_radix(ctx, argv[0]);
49492
0
        if (base < 0)
49493
0
            goto fail;
49494
0
    }
49495
0
    ret = js_ftoa(ctx, val, base, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
49496
0
    JS_FreeValue(ctx, val);
49497
0
    return ret;
49498
0
 fail:
49499
0
    JS_FreeValue(ctx, val);
49500
0
    return JS_EXCEPTION;
49501
0
}
49502
49503
static JSValue js_bigfloat_valueOf(JSContext *ctx, JSValueConst this_val,
49504
                                   int argc, JSValueConst *argv)
49505
0
{
49506
0
    return js_thisBigFloatValue(ctx, this_val);
49507
0
}
49508
49509
static int bigfloat_get_rnd_mode(JSContext *ctx, JSValueConst val)
49510
0
{
49511
0
    int rnd_mode;
49512
0
    if (JS_ToInt32Sat(ctx, &rnd_mode, val))
49513
0
        return -1;
49514
0
    if (rnd_mode < BF_RNDN || rnd_mode > BF_RNDF) {
49515
0
        JS_ThrowRangeError(ctx, "invalid rounding mode");
49516
0
        return -1;
49517
0
    }
49518
0
    return rnd_mode;
49519
0
}
49520
49521
static JSValue js_bigfloat_toFixed(JSContext *ctx, JSValueConst this_val,
49522
                                 int argc, JSValueConst *argv)
49523
0
{
49524
0
    JSValue val, ret;
49525
0
    int64_t f;
49526
0
    int rnd_mode, radix;
49527
49528
0
    val = js_thisBigFloatValue(ctx, this_val);
49529
0
    if (JS_IsException(val))
49530
0
        return val;
49531
0
    if (JS_ToInt64Sat(ctx, &f, argv[0]))
49532
0
        goto fail;
49533
0
    if (f < 0 || f > BF_PREC_MAX) {
49534
0
        JS_ThrowRangeError(ctx, "invalid number of digits");
49535
0
        goto fail;
49536
0
    }
49537
0
    rnd_mode = BF_RNDNA;
49538
0
    radix = 10;
49539
    /* XXX: swap parameter order for rounding mode and radix */
49540
0
    if (argc > 1) {
49541
0
        rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
49542
0
        if (rnd_mode < 0)
49543
0
            goto fail;
49544
0
    }
49545
0
    if (argc > 2) {
49546
0
        radix = js_get_radix(ctx, argv[2]);
49547
0
        if (radix < 0)
49548
0
            goto fail;
49549
0
    }
49550
0
    ret = js_ftoa(ctx, val, radix, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
49551
0
    JS_FreeValue(ctx, val);
49552
0
    return ret;
49553
0
 fail:
49554
0
    JS_FreeValue(ctx, val);
49555
0
    return JS_EXCEPTION;
49556
0
}
49557
49558
static BOOL js_bigfloat_is_finite(JSContext *ctx, JSValueConst val)
49559
0
{
49560
0
    BOOL res;
49561
0
    uint32_t tag;
49562
49563
0
    tag = JS_VALUE_GET_NORM_TAG(val);
49564
0
    switch(tag) {
49565
0
    case JS_TAG_BIG_FLOAT:
49566
0
        {
49567
0
            JSBigFloat *p = JS_VALUE_GET_PTR(val);
49568
0
            res = bf_is_finite(&p->num);
49569
0
        }
49570
0
        break;
49571
0
    default:
49572
0
        res = FALSE;
49573
0
        break;
49574
0
    }
49575
0
    return res;
49576
0
}
49577
49578
static JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val,
49579
                                       int argc, JSValueConst *argv)
49580
0
{
49581
0
    JSValue val, ret;
49582
0
    int64_t f;
49583
0
    int rnd_mode, radix;
49584
49585
0
    val = js_thisBigFloatValue(ctx, this_val);
49586
0
    if (JS_IsException(val))
49587
0
        return val;
49588
0
    if (JS_ToInt64Sat(ctx, &f, argv[0]))
49589
0
        goto fail;
49590
0
    if (!js_bigfloat_is_finite(ctx, val)) {
49591
0
        ret = JS_ToString(ctx, val);
49592
0
    } else if (JS_IsUndefined(argv[0])) {
49593
0
        ret = js_ftoa(ctx, val, 10, 0,
49594
0
                      BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
49595
0
    } else {
49596
0
        if (f < 0 || f > BF_PREC_MAX) {
49597
0
            JS_ThrowRangeError(ctx, "invalid number of digits");
49598
0
            goto fail;
49599
0
        }
49600
0
        rnd_mode = BF_RNDNA;
49601
0
        radix = 10;
49602
0
        if (argc > 1) {
49603
0
            rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
49604
0
            if (rnd_mode < 0)
49605
0
                goto fail;
49606
0
        }
49607
0
        if (argc > 2) {
49608
0
            radix = js_get_radix(ctx, argv[2]);
49609
0
            if (radix < 0)
49610
0
                goto fail;
49611
0
        }
49612
0
        ret = js_ftoa(ctx, val, radix, f + 1,
49613
0
                      rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
49614
0
    }
49615
0
    JS_FreeValue(ctx, val);
49616
0
    return ret;
49617
0
 fail:
49618
0
    JS_FreeValue(ctx, val);
49619
0
    return JS_EXCEPTION;
49620
0
}
49621
49622
static JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val,
49623
                                     int argc, JSValueConst *argv)
49624
0
{
49625
0
    JSValue val, ret;
49626
0
    int64_t p;
49627
0
    int rnd_mode, radix;
49628
49629
0
    val = js_thisBigFloatValue(ctx, this_val);
49630
0
    if (JS_IsException(val))
49631
0
        return val;
49632
0
    if (JS_IsUndefined(argv[0]))
49633
0
        goto to_string;
49634
0
    if (JS_ToInt64Sat(ctx, &p, argv[0]))
49635
0
        goto fail;
49636
0
    if (!js_bigfloat_is_finite(ctx, val)) {
49637
0
    to_string:
49638
0
        ret = JS_ToString(ctx, this_val);
49639
0
    } else {
49640
0
        if (p < 1 || p > BF_PREC_MAX) {
49641
0
            JS_ThrowRangeError(ctx, "invalid number of digits");
49642
0
            goto fail;
49643
0
        }
49644
0
        rnd_mode = BF_RNDNA;
49645
0
        radix = 10;
49646
0
        if (argc > 1) {
49647
0
            rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
49648
0
            if (rnd_mode < 0)
49649
0
                goto fail;
49650
0
        }
49651
0
        if (argc > 2) {
49652
0
            radix = js_get_radix(ctx, argv[2]);
49653
0
            if (radix < 0)
49654
0
                goto fail;
49655
0
        }
49656
0
        ret = js_ftoa(ctx, val, radix, p, rnd_mode | BF_FTOA_FORMAT_FIXED);
49657
0
    }
49658
0
    JS_FreeValue(ctx, val);
49659
0
    return ret;
49660
0
 fail:
49661
0
    JS_FreeValue(ctx, val);
49662
0
    return JS_EXCEPTION;
49663
0
}
49664
49665
static const JSCFunctionListEntry js_bigfloat_proto_funcs[] = {
49666
    JS_CFUNC_DEF("toString", 0, js_bigfloat_toString ),
49667
    JS_CFUNC_DEF("valueOf", 0, js_bigfloat_valueOf ),
49668
    JS_CFUNC_DEF("toPrecision", 1, js_bigfloat_toPrecision ),
49669
    JS_CFUNC_DEF("toFixed", 1, js_bigfloat_toFixed ),
49670
    JS_CFUNC_DEF("toExponential", 1, js_bigfloat_toExponential ),
49671
};
49672
49673
static JSValue js_bigfloat_constructor(JSContext *ctx,
49674
                                       JSValueConst new_target,
49675
                                       int argc, JSValueConst *argv)
49676
0
{
49677
0
    JSValue val;
49678
0
    if (!JS_IsUndefined(new_target))
49679
0
        return JS_ThrowTypeError(ctx, "not a constructor");
49680
0
    if (argc == 0) {
49681
0
        bf_t *r;
49682
0
        val = JS_NewBigFloat(ctx);
49683
0
        if (JS_IsException(val))
49684
0
            return val;
49685
0
        r = JS_GetBigFloat(val);
49686
0
        bf_set_zero(r, 0);
49687
0
    } else {
49688
0
        val = JS_DupValue(ctx, argv[0]);
49689
0
    redo:
49690
0
        switch(JS_VALUE_GET_NORM_TAG(val)) {
49691
0
        case JS_TAG_BIG_FLOAT:
49692
0
            break;
49693
0
        case JS_TAG_FLOAT64:
49694
0
            {
49695
0
                bf_t *r;
49696
0
                double d = JS_VALUE_GET_FLOAT64(val);
49697
0
                val = JS_NewBigFloat(ctx);
49698
0
                if (JS_IsException(val))
49699
0
                    break;
49700
0
                r = JS_GetBigFloat(val);
49701
0
                if (bf_set_float64(r, d))
49702
0
                    goto fail;
49703
0
            }
49704
0
            break;
49705
0
        case JS_TAG_INT:
49706
0
            {
49707
0
                bf_t *r;
49708
0
                int32_t v = JS_VALUE_GET_INT(val);
49709
0
                val = JS_NewBigFloat(ctx);
49710
0
                if (JS_IsException(val))
49711
0
                    break;
49712
0
                r = JS_GetBigFloat(val);
49713
0
                if (bf_set_si(r, v))
49714
0
                    goto fail;
49715
0
            }
49716
0
            break;
49717
0
        case JS_TAG_BIG_INT:
49718
            /* We keep the full precision of the integer */
49719
0
            {
49720
0
                JSBigFloat *p = JS_VALUE_GET_PTR(val);
49721
0
                val = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
49722
0
            }
49723
0
            break;
49724
0
        case JS_TAG_BIG_DECIMAL:
49725
0
            val = JS_ToStringFree(ctx, val);
49726
0
            if (JS_IsException(val))
49727
0
                break;
49728
0
            goto redo;
49729
0
        case JS_TAG_STRING:
49730
0
            {
49731
0
                const char *str, *p;
49732
0
                size_t len;
49733
0
                int err;
49734
49735
0
                str = JS_ToCStringLen(ctx, &len, val);
49736
0
                JS_FreeValue(ctx, val);
49737
0
                if (!str)
49738
0
                    return JS_EXCEPTION;
49739
0
                p = str;
49740
0
                p += skip_spaces(p);
49741
0
                if ((p - str) == len) {
49742
0
                    bf_t *r;
49743
0
                    val = JS_NewBigFloat(ctx);
49744
0
                    if (JS_IsException(val))
49745
0
                        break;
49746
0
                    r = JS_GetBigFloat(val);
49747
0
                    bf_set_zero(r, 0);
49748
0
                    err = 0;
49749
0
                } else {
49750
0
                    val = js_atof(ctx, p, &p, 0, ATOD_ACCEPT_BIN_OCT |
49751
0
                                  ATOD_TYPE_BIG_FLOAT |
49752
0
                                  ATOD_ACCEPT_PREFIX_AFTER_SIGN);
49753
0
                    if (JS_IsException(val)) {
49754
0
                        JS_FreeCString(ctx, str);
49755
0
                        return JS_EXCEPTION;
49756
0
                    }
49757
0
                    p += skip_spaces(p);
49758
0
                    err = ((p - str) != len);
49759
0
                }
49760
0
                JS_FreeCString(ctx, str);
49761
0
                if (err) {
49762
0
                    JS_FreeValue(ctx, val);
49763
0
                    return JS_ThrowSyntaxError(ctx, "invalid bigfloat literal");
49764
0
                }
49765
0
            }
49766
0
            break;
49767
0
        case JS_TAG_OBJECT:
49768
0
            val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
49769
0
            if (JS_IsException(val))
49770
0
                break;
49771
0
            goto redo;
49772
0
        case JS_TAG_NULL:
49773
0
        case JS_TAG_UNDEFINED:
49774
0
        default:
49775
0
            JS_FreeValue(ctx, val);
49776
0
            return JS_ThrowTypeError(ctx, "cannot convert to bigfloat");
49777
0
        }
49778
0
    }
49779
0
    return val;
49780
0
 fail:
49781
0
    JS_FreeValue(ctx, val);
49782
0
    return JS_EXCEPTION;
49783
0
}
49784
49785
static JSValue js_bigfloat_get_const(JSContext *ctx,
49786
                                     JSValueConst this_val, int magic)
49787
0
{
49788
0
    bf_t *r;
49789
0
    JSValue val;
49790
0
    val = JS_NewBigFloat(ctx);
49791
0
    if (JS_IsException(val))
49792
0
        return val;
49793
0
    r = JS_GetBigFloat(val);
49794
0
    switch(magic) {
49795
0
    case 0: /* PI */
49796
0
        bf_const_pi(r, ctx->fp_env.prec, ctx->fp_env.flags);
49797
0
        break;
49798
0
    case 1: /* LN2 */
49799
0
        bf_const_log2(r, ctx->fp_env.prec, ctx->fp_env.flags);
49800
0
        break;
49801
0
    case 2: /* MIN_VALUE */
49802
0
    case 3: /* MAX_VALUE */
49803
0
        {
49804
0
            slimb_t e_range, e;
49805
0
            e_range = (limb_t)1 << (bf_get_exp_bits(ctx->fp_env.flags) - 1);
49806
0
            bf_set_ui(r, 1);
49807
0
            if (magic == 2) {
49808
0
                e = -e_range + 2;
49809
0
                if (ctx->fp_env.flags & BF_FLAG_SUBNORMAL)
49810
0
                    e -= ctx->fp_env.prec - 1;
49811
0
                bf_mul_2exp(r, e, ctx->fp_env.prec, ctx->fp_env.flags);
49812
0
            } else {
49813
0
                bf_mul_2exp(r, ctx->fp_env.prec, ctx->fp_env.prec,
49814
0
                            ctx->fp_env.flags);
49815
0
                bf_add_si(r, r, -1, ctx->fp_env.prec, ctx->fp_env.flags);
49816
0
                bf_mul_2exp(r, e_range - ctx->fp_env.prec, ctx->fp_env.prec,
49817
0
                            ctx->fp_env.flags);
49818
0
            }
49819
0
        }
49820
0
        break;
49821
0
    case 4: /* EPSILON */
49822
0
        bf_set_ui(r, 1);
49823
0
        bf_mul_2exp(r, 1 - ctx->fp_env.prec,
49824
0
                    ctx->fp_env.prec, ctx->fp_env.flags);
49825
0
        break;
49826
0
    default:
49827
0
        abort();
49828
0
    }
49829
0
    return val;
49830
0
}
49831
49832
static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val,
49833
                                      int argc, JSValueConst *argv)
49834
0
{
49835
0
    bf_t *a;
49836
0
    const char *str;
49837
0
    JSValue ret;
49838
0
    int radix;
49839
0
    JSFloatEnv *fe;
49840
49841
0
    str = JS_ToCString(ctx, argv[0]);
49842
0
    if (!str)
49843
0
        return JS_EXCEPTION;
49844
0
    if (JS_ToInt32(ctx, &radix, argv[1])) {
49845
0
    fail:
49846
0
        JS_FreeCString(ctx, str);
49847
0
        return JS_EXCEPTION;
49848
0
    }
49849
0
    if (radix != 0 && (radix < 2 || radix > 36)) {
49850
0
        JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
49851
0
        goto fail;
49852
0
    }
49853
0
    fe = &ctx->fp_env;
49854
0
    if (argc > 2) {
49855
0
        fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
49856
0
        if (!fe)
49857
0
            goto fail;
49858
0
    }
49859
0
    ret = JS_NewBigFloat(ctx);
49860
0
    if (JS_IsException(ret))
49861
0
        goto done;
49862
0
    a = JS_GetBigFloat(ret);
49863
    /* XXX: use js_atof() */
49864
0
    bf_atof(a, str, NULL, radix, fe->prec, fe->flags);
49865
0
 done:
49866
0
    JS_FreeCString(ctx, str);
49867
0
    return ret;
49868
0
}
49869
49870
static JSValue js_bigfloat_isFinite(JSContext *ctx, JSValueConst this_val,
49871
                                    int argc, JSValueConst *argv)
49872
0
{
49873
0
    JSValueConst val = argv[0];
49874
0
    JSBigFloat *p;
49875
    
49876
0
    if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)
49877
0
        return JS_FALSE;
49878
0
    p = JS_VALUE_GET_PTR(val);
49879
0
    return JS_NewBool(ctx, bf_is_finite(&p->num));
49880
0
}
49881
49882
static JSValue js_bigfloat_isNaN(JSContext *ctx, JSValueConst this_val,
49883
                                 int argc, JSValueConst *argv)
49884
0
{
49885
0
    JSValueConst val = argv[0];
49886
0
    JSBigFloat *p;
49887
    
49888
0
    if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)
49889
0
        return JS_FALSE;
49890
0
    p = JS_VALUE_GET_PTR(val);
49891
0
    return JS_NewBool(ctx, bf_is_nan(&p->num));
49892
0
}
49893
49894
enum {
49895
    MATH_OP_ABS,
49896
    MATH_OP_FLOOR,
49897
    MATH_OP_CEIL,
49898
    MATH_OP_ROUND,
49899
    MATH_OP_TRUNC,
49900
    MATH_OP_SQRT,
49901
    MATH_OP_FPROUND,
49902
    MATH_OP_ACOS,
49903
    MATH_OP_ASIN,
49904
    MATH_OP_ATAN,
49905
    MATH_OP_ATAN2,
49906
    MATH_OP_COS,
49907
    MATH_OP_EXP,
49908
    MATH_OP_LOG,
49909
    MATH_OP_POW,
49910
    MATH_OP_SIN,
49911
    MATH_OP_TAN,
49912
    MATH_OP_FMOD,
49913
    MATH_OP_REM,
49914
    MATH_OP_SIGN,
49915
49916
    MATH_OP_ADD,
49917
    MATH_OP_SUB,
49918
    MATH_OP_MUL,
49919
    MATH_OP_DIV,
49920
};
49921
49922
static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val,
49923
                           int argc, JSValueConst *argv, int magic)
49924
0
{
49925
0
    bf_t a_s, *a, *r;
49926
0
    JSFloatEnv *fe;
49927
0
    int rnd_mode;
49928
0
    JSValue op1, res;
49929
49930
0
    op1 = JS_ToNumeric(ctx, argv[0]);
49931
0
    if (JS_IsException(op1))
49932
0
        return op1;
49933
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
49934
0
    fe = &ctx->fp_env;
49935
0
    if (argc > 1) {
49936
0
        fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV);
49937
0
        if (!fe)
49938
0
            goto fail;
49939
0
    }
49940
0
    res = JS_NewBigFloat(ctx);
49941
0
    if (JS_IsException(res)) {
49942
0
    fail:
49943
0
        if (a == &a_s)
49944
0
            bf_delete(a);
49945
0
        JS_FreeValue(ctx, op1);
49946
0
        return JS_EXCEPTION;
49947
0
    }
49948
0
    r = JS_GetBigFloat(res);
49949
0
    switch (magic) {
49950
0
    case MATH_OP_ABS:
49951
0
        bf_set(r, a);
49952
0
        r->sign = 0;
49953
0
        break;
49954
0
    case MATH_OP_FLOOR:
49955
0
        rnd_mode = BF_RNDD;
49956
0
        goto rint;
49957
0
    case MATH_OP_CEIL:
49958
0
        rnd_mode = BF_RNDU;
49959
0
        goto rint;
49960
0
    case MATH_OP_ROUND:
49961
0
        rnd_mode = BF_RNDNA;
49962
0
        goto rint;
49963
0
    case MATH_OP_TRUNC:
49964
0
        rnd_mode = BF_RNDZ;
49965
0
    rint:
49966
0
        bf_set(r, a);
49967
0
        fe->status |= bf_rint(r, rnd_mode);
49968
0
        break;
49969
0
    case MATH_OP_SQRT:
49970
0
        fe->status |= bf_sqrt(r, a, fe->prec, fe->flags);
49971
0
        break;
49972
0
    case MATH_OP_FPROUND:
49973
0
        bf_set(r, a);
49974
0
        fe->status |= bf_round(r, fe->prec, fe->flags);
49975
0
        break;
49976
0
    case MATH_OP_ACOS:
49977
0
        fe->status |= bf_acos(r, a, fe->prec, fe->flags);
49978
0
        break;
49979
0
    case MATH_OP_ASIN:
49980
0
        fe->status |= bf_asin(r, a, fe->prec, fe->flags);
49981
0
        break;
49982
0
    case MATH_OP_ATAN:
49983
0
        fe->status |= bf_atan(r, a, fe->prec, fe->flags);
49984
0
        break;
49985
0
    case MATH_OP_COS:
49986
0
        fe->status |= bf_cos(r, a, fe->prec, fe->flags);
49987
0
        break;
49988
0
    case MATH_OP_EXP:
49989
0
        fe->status |= bf_exp(r, a, fe->prec, fe->flags);
49990
0
        break;
49991
0
    case MATH_OP_LOG:
49992
0
        fe->status |= bf_log(r, a, fe->prec, fe->flags);
49993
0
        break;
49994
0
    case MATH_OP_SIN:
49995
0
        fe->status |= bf_sin(r, a, fe->prec, fe->flags);
49996
0
        break;
49997
0
    case MATH_OP_TAN:
49998
0
        fe->status |= bf_tan(r, a, fe->prec, fe->flags);
49999
0
        break;
50000
0
    case MATH_OP_SIGN:
50001
0
        if (bf_is_nan(a) || bf_is_zero(a)) {
50002
0
            bf_set(r, a);
50003
0
        } else {
50004
0
            bf_set_si(r, 1 - 2 * a->sign);
50005
0
        }
50006
0
        break;
50007
0
    default:
50008
0
        abort();
50009
0
    }
50010
0
    if (a == &a_s)
50011
0
        bf_delete(a);
50012
0
    JS_FreeValue(ctx, op1);
50013
0
    return res;
50014
0
}
50015
50016
static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val,
50017
                            int argc, JSValueConst *argv, int magic)
50018
0
{
50019
0
    bf_t a_s, *a, b_s, *b, r_s, *r = &r_s;
50020
0
    JSFloatEnv *fe;
50021
0
    JSValue op1, op2, res;
50022
50023
0
    op1 = JS_ToNumeric(ctx, argv[0]);
50024
0
    if (JS_IsException(op1))
50025
0
        return op1;
50026
0
    op2 = JS_ToNumeric(ctx, argv[1]);
50027
0
    if (JS_IsException(op2)) {
50028
0
        JS_FreeValue(ctx, op1);
50029
0
        return op2;
50030
0
    }
50031
0
    a = JS_ToBigFloat(ctx, &a_s, op1);
50032
0
    b = JS_ToBigFloat(ctx, &b_s, op2);
50033
0
    fe = &ctx->fp_env;
50034
0
    if (argc > 2) {
50035
0
        fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
50036
0
        if (!fe)
50037
0
            goto fail;
50038
0
    }
50039
0
    res = JS_NewBigFloat(ctx);
50040
0
    if (JS_IsException(res)) {
50041
0
    fail:
50042
0
        if (a == &a_s)
50043
0
            bf_delete(a);
50044
0
        if (b == &b_s)
50045
0
            bf_delete(b);
50046
0
        JS_FreeValue(ctx, op1);
50047
0
        JS_FreeValue(ctx, op2);
50048
0
        return JS_EXCEPTION;
50049
0
    }
50050
0
    r = JS_GetBigFloat(res);
50051
0
    switch (magic) {
50052
0
    case MATH_OP_ATAN2:
50053
0
        fe->status |= bf_atan2(r, a, b, fe->prec, fe->flags);
50054
0
        break;
50055
0
    case MATH_OP_POW:
50056
0
        fe->status |= bf_pow(r, a, b, fe->prec, fe->flags | BF_POW_JS_QUIRKS);
50057
0
        break;
50058
0
    case MATH_OP_FMOD:
50059
0
        fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
50060
0
        break;
50061
0
    case MATH_OP_REM:
50062
0
        fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDN);
50063
0
        break;
50064
0
    case MATH_OP_ADD:
50065
0
        fe->status |= bf_add(r, a, b, fe->prec, fe->flags);
50066
0
        break;
50067
0
    case MATH_OP_SUB:
50068
0
        fe->status |= bf_sub(r, a, b, fe->prec, fe->flags);
50069
0
        break;
50070
0
    case MATH_OP_MUL:
50071
0
        fe->status |= bf_mul(r, a, b, fe->prec, fe->flags);
50072
0
        break;
50073
0
    case MATH_OP_DIV:
50074
0
        fe->status |= bf_div(r, a, b, fe->prec, fe->flags);
50075
0
        break;
50076
0
    default:
50077
0
        abort();
50078
0
    }
50079
0
    if (a == &a_s)
50080
0
        bf_delete(a);
50081
0
    if (b == &b_s)
50082
0
        bf_delete(b);
50083
0
    JS_FreeValue(ctx, op1);
50084
0
    JS_FreeValue(ctx, op2);
50085
0
    return res;
50086
0
}
50087
50088
static const JSCFunctionListEntry js_bigfloat_funcs[] = {
50089
    JS_CGETSET_MAGIC_DEF("PI", js_bigfloat_get_const, NULL, 0 ),
50090
    JS_CGETSET_MAGIC_DEF("LN2", js_bigfloat_get_const, NULL, 1 ),
50091
    JS_CGETSET_MAGIC_DEF("MIN_VALUE", js_bigfloat_get_const, NULL, 2 ),
50092
    JS_CGETSET_MAGIC_DEF("MAX_VALUE", js_bigfloat_get_const, NULL, 3 ),
50093
    JS_CGETSET_MAGIC_DEF("EPSILON", js_bigfloat_get_const, NULL, 4 ),
50094
    JS_CFUNC_DEF("parseFloat", 1, js_bigfloat_parseFloat ),
50095
    JS_CFUNC_DEF("isFinite", 1, js_bigfloat_isFinite ),
50096
    JS_CFUNC_DEF("isNaN", 1, js_bigfloat_isNaN ),
50097
    JS_CFUNC_MAGIC_DEF("abs", 1, js_bigfloat_fop, MATH_OP_ABS ),
50098
    JS_CFUNC_MAGIC_DEF("fpRound", 1, js_bigfloat_fop, MATH_OP_FPROUND ),
50099
    JS_CFUNC_MAGIC_DEF("floor", 1, js_bigfloat_fop, MATH_OP_FLOOR ),
50100
    JS_CFUNC_MAGIC_DEF("ceil", 1, js_bigfloat_fop, MATH_OP_CEIL ),
50101
    JS_CFUNC_MAGIC_DEF("round", 1, js_bigfloat_fop, MATH_OP_ROUND ),
50102
    JS_CFUNC_MAGIC_DEF("trunc", 1, js_bigfloat_fop, MATH_OP_TRUNC ),
50103
    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigfloat_fop, MATH_OP_SQRT ),
50104
    JS_CFUNC_MAGIC_DEF("acos", 1, js_bigfloat_fop, MATH_OP_ACOS ),
50105
    JS_CFUNC_MAGIC_DEF("asin", 1, js_bigfloat_fop, MATH_OP_ASIN ),
50106
    JS_CFUNC_MAGIC_DEF("atan", 1, js_bigfloat_fop, MATH_OP_ATAN ),
50107
    JS_CFUNC_MAGIC_DEF("atan2", 2, js_bigfloat_fop2, MATH_OP_ATAN2 ),
50108
    JS_CFUNC_MAGIC_DEF("cos", 1, js_bigfloat_fop, MATH_OP_COS ),
50109
    JS_CFUNC_MAGIC_DEF("exp", 1, js_bigfloat_fop, MATH_OP_EXP ),
50110
    JS_CFUNC_MAGIC_DEF("log", 1, js_bigfloat_fop, MATH_OP_LOG ),
50111
    JS_CFUNC_MAGIC_DEF("pow", 2, js_bigfloat_fop2, MATH_OP_POW ),
50112
    JS_CFUNC_MAGIC_DEF("sin", 1, js_bigfloat_fop, MATH_OP_SIN ),
50113
    JS_CFUNC_MAGIC_DEF("tan", 1, js_bigfloat_fop, MATH_OP_TAN ),
50114
    JS_CFUNC_MAGIC_DEF("sign", 1, js_bigfloat_fop, MATH_OP_SIGN ),
50115
    JS_CFUNC_MAGIC_DEF("add", 2, js_bigfloat_fop2, MATH_OP_ADD ),
50116
    JS_CFUNC_MAGIC_DEF("sub", 2, js_bigfloat_fop2, MATH_OP_SUB ),
50117
    JS_CFUNC_MAGIC_DEF("mul", 2, js_bigfloat_fop2, MATH_OP_MUL ),
50118
    JS_CFUNC_MAGIC_DEF("div", 2, js_bigfloat_fop2, MATH_OP_DIV ),
50119
    JS_CFUNC_MAGIC_DEF("fmod", 2, js_bigfloat_fop2, MATH_OP_FMOD ),
50120
    JS_CFUNC_MAGIC_DEF("remainder", 2, js_bigfloat_fop2, MATH_OP_REM ),
50121
};
50122
50123
/* FloatEnv */
50124
50125
static JSValue js_float_env_constructor(JSContext *ctx,
50126
                                        JSValueConst new_target,
50127
                                        int argc, JSValueConst *argv)
50128
0
{
50129
0
    JSValue obj;
50130
0
    JSFloatEnv *fe;
50131
0
    int64_t prec;
50132
0
    int flags, rndmode;
50133
50134
0
    prec = ctx->fp_env.prec;
50135
0
    flags = ctx->fp_env.flags;
50136
0
    if (!JS_IsUndefined(argv[0])) {
50137
0
        if (JS_ToInt64Sat(ctx, &prec, argv[0]))
50138
0
            return JS_EXCEPTION;
50139
0
        if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
50140
0
            return JS_ThrowRangeError(ctx, "invalid precision");
50141
0
        flags = BF_RNDN; /* RNDN, max exponent size, no subnormal */
50142
0
        if (argc > 1 && !JS_IsUndefined(argv[1])) {
50143
0
            if (JS_ToInt32Sat(ctx, &rndmode, argv[1]))
50144
0
                return JS_EXCEPTION;
50145
0
            if (rndmode < BF_RNDN || rndmode > BF_RNDF)
50146
0
                return JS_ThrowRangeError(ctx, "invalid rounding mode");
50147
0
            flags = rndmode;
50148
0
        }
50149
0
    }
50150
50151
0
    obj = JS_NewObjectClass(ctx, JS_CLASS_FLOAT_ENV);
50152
0
    if (JS_IsException(obj))
50153
0
        return JS_EXCEPTION;
50154
0
    fe = js_malloc(ctx, sizeof(*fe));
50155
0
    if (!fe)
50156
0
        return JS_EXCEPTION;
50157
0
    fe->prec = prec;
50158
0
    fe->flags = flags;
50159
0
    fe->status = 0;
50160
0
    JS_SetOpaque(obj, fe);
50161
0
    return obj;
50162
0
}
50163
50164
static void js_float_env_finalizer(JSRuntime *rt, JSValue val)
50165
0
{
50166
0
    JSFloatEnv *fe = JS_GetOpaque(val, JS_CLASS_FLOAT_ENV);
50167
0
    js_free_rt(rt, fe);
50168
0
}
50169
50170
static JSValue js_float_env_get_prec(JSContext *ctx, JSValueConst this_val)
50171
0
{
50172
0
    return JS_NewInt64(ctx, ctx->fp_env.prec);
50173
0
}
50174
50175
static JSValue js_float_env_get_expBits(JSContext *ctx, JSValueConst this_val)
50176
0
{
50177
0
    return JS_NewInt32(ctx, bf_get_exp_bits(ctx->fp_env.flags));
50178
0
}
50179
50180
static JSValue js_float_env_setPrec(JSContext *ctx,
50181
                                    JSValueConst this_val,
50182
                                    int argc, JSValueConst *argv)
50183
0
{
50184
0
    JSValueConst func;
50185
0
    int exp_bits, flags, saved_flags;
50186
0
    JSValue ret;
50187
0
    limb_t saved_prec;
50188
0
    int64_t prec;
50189
50190
0
    func = argv[0];
50191
0
    if (JS_ToInt64Sat(ctx, &prec, argv[1]))
50192
0
        return JS_EXCEPTION;
50193
0
    if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
50194
0
        return JS_ThrowRangeError(ctx, "invalid precision");
50195
0
    exp_bits = BF_EXP_BITS_MAX;
50196
50197
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
50198
0
        if (JS_ToInt32Sat(ctx, &exp_bits, argv[2]))
50199
0
            return JS_EXCEPTION;
50200
0
        if (exp_bits < BF_EXP_BITS_MIN || exp_bits > BF_EXP_BITS_MAX)
50201
0
            return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
50202
0
    }
50203
50204
0
    flags = BF_RNDN | BF_FLAG_SUBNORMAL | bf_set_exp_bits(exp_bits);
50205
50206
0
    saved_prec = ctx->fp_env.prec;
50207
0
    saved_flags = ctx->fp_env.flags;
50208
50209
0
    ctx->fp_env.prec = prec;
50210
0
    ctx->fp_env.flags = flags;
50211
50212
0
    ret = JS_Call(ctx, func, JS_UNDEFINED, 0, NULL);
50213
    /* always restore the floating point precision */
50214
0
    ctx->fp_env.prec = saved_prec;
50215
0
    ctx->fp_env.flags = saved_flags;
50216
0
    return ret;
50217
0
}
50218
50219
0
#define FE_PREC      (-1)
50220
0
#define FE_EXP       (-2)
50221
0
#define FE_RNDMODE   (-3)
50222
0
#define FE_SUBNORMAL (-4)
50223
50224
static JSValue js_float_env_proto_get_status(JSContext *ctx, JSValueConst this_val, int magic)
50225
0
{
50226
0
    JSFloatEnv *fe;
50227
0
    fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
50228
0
    if (!fe)
50229
0
        return JS_EXCEPTION;
50230
0
    switch(magic) {
50231
0
    case FE_PREC:
50232
0
        return JS_NewInt64(ctx, fe->prec);
50233
0
    case FE_EXP:
50234
0
        return JS_NewInt32(ctx, bf_get_exp_bits(fe->flags));
50235
0
    case FE_RNDMODE:
50236
0
        return JS_NewInt32(ctx, fe->flags & BF_RND_MASK);
50237
0
    case FE_SUBNORMAL:
50238
0
        return JS_NewBool(ctx, (fe->flags & BF_FLAG_SUBNORMAL) != 0);
50239
0
    default:
50240
0
        return JS_NewBool(ctx, (fe->status & magic) != 0);
50241
0
    }
50242
0
}
50243
50244
static JSValue js_float_env_proto_set_status(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic)
50245
0
{
50246
0
    JSFloatEnv *fe;
50247
0
    int b;
50248
0
    int64_t prec;
50249
50250
0
    fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
50251
0
    if (!fe)
50252
0
        return JS_EXCEPTION;
50253
0
    switch(magic) {
50254
0
    case FE_PREC:
50255
0
        if (JS_ToInt64Sat(ctx, &prec, val))
50256
0
            return JS_EXCEPTION;
50257
0
        if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
50258
0
            return JS_ThrowRangeError(ctx, "invalid precision");
50259
0
        fe->prec = prec;
50260
0
        break;
50261
0
    case FE_EXP:
50262
0
        if (JS_ToInt32Sat(ctx, &b, val))
50263
0
            return JS_EXCEPTION;
50264
0
        if (b < BF_EXP_BITS_MIN || b > BF_EXP_BITS_MAX)
50265
0
            return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
50266
0
        fe->flags = (fe->flags & ~(BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)) |
50267
0
            bf_set_exp_bits(b);
50268
0
        break;
50269
0
    case FE_RNDMODE:
50270
0
        b = bigfloat_get_rnd_mode(ctx, val);
50271
0
        if (b < 0)
50272
0
            return JS_EXCEPTION;
50273
0
        fe->flags = (fe->flags & ~BF_RND_MASK) | b;
50274
0
        break;
50275
0
    case FE_SUBNORMAL:
50276
0
        b = JS_ToBool(ctx, val);
50277
0
        fe->flags = (fe->flags & ~BF_FLAG_SUBNORMAL) | (b ? BF_FLAG_SUBNORMAL: 0);
50278
0
        break;
50279
0
    default:
50280
0
        b = JS_ToBool(ctx, val);
50281
0
        fe->status = (fe->status & ~magic) & ((-b) & magic);
50282
0
        break;
50283
0
    }
50284
0
    return JS_UNDEFINED;
50285
0
}
50286
50287
static JSValue js_float_env_clearStatus(JSContext *ctx,
50288
                                        JSValueConst this_val,
50289
                                        int argc, JSValueConst *argv)
50290
0
{
50291
0
    JSFloatEnv *fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
50292
0
    if (!fe)
50293
0
        return JS_EXCEPTION;
50294
0
    fe->status = 0;
50295
0
    return JS_UNDEFINED;
50296
0
}
50297
50298
static const JSCFunctionListEntry js_float_env_funcs[] = {
50299
    JS_CGETSET_DEF("prec", js_float_env_get_prec, NULL ),
50300
    JS_CGETSET_DEF("expBits", js_float_env_get_expBits, NULL ),
50301
    JS_CFUNC_DEF("setPrec", 2, js_float_env_setPrec ),
50302
    JS_PROP_INT32_DEF("RNDN", BF_RNDN, 0 ),
50303
    JS_PROP_INT32_DEF("RNDZ", BF_RNDZ, 0 ),
50304
    JS_PROP_INT32_DEF("RNDU", BF_RNDU, 0 ),
50305
    JS_PROP_INT32_DEF("RNDD", BF_RNDD, 0 ),
50306
    JS_PROP_INT32_DEF("RNDNA", BF_RNDNA, 0 ),
50307
    JS_PROP_INT32_DEF("RNDA", BF_RNDA, 0 ),
50308
    JS_PROP_INT32_DEF("RNDF", BF_RNDF, 0 ),
50309
    JS_PROP_INT32_DEF("precMin", BF_PREC_MIN, 0 ),
50310
    JS_PROP_INT64_DEF("precMax", BF_PREC_MAX, 0 ),
50311
    JS_PROP_INT32_DEF("expBitsMin", BF_EXP_BITS_MIN, 0 ),
50312
    JS_PROP_INT32_DEF("expBitsMax", BF_EXP_BITS_MAX, 0 ),
50313
};
50314
50315
static const JSCFunctionListEntry js_float_env_proto_funcs[] = {
50316
    JS_CGETSET_MAGIC_DEF("prec", js_float_env_proto_get_status,
50317
                         js_float_env_proto_set_status, FE_PREC ),
50318
    JS_CGETSET_MAGIC_DEF("expBits", js_float_env_proto_get_status,
50319
                         js_float_env_proto_set_status, FE_EXP ),
50320
    JS_CGETSET_MAGIC_DEF("rndMode", js_float_env_proto_get_status,
50321
                         js_float_env_proto_set_status, FE_RNDMODE ),
50322
    JS_CGETSET_MAGIC_DEF("subnormal", js_float_env_proto_get_status,
50323
                         js_float_env_proto_set_status, FE_SUBNORMAL ),
50324
    JS_CGETSET_MAGIC_DEF("invalidOperation", js_float_env_proto_get_status,
50325
                         js_float_env_proto_set_status, BF_ST_INVALID_OP ),
50326
    JS_CGETSET_MAGIC_DEF("divideByZero", js_float_env_proto_get_status,
50327
                         js_float_env_proto_set_status, BF_ST_DIVIDE_ZERO ),
50328
    JS_CGETSET_MAGIC_DEF("overflow", js_float_env_proto_get_status,
50329
                         js_float_env_proto_set_status, BF_ST_OVERFLOW ),
50330
    JS_CGETSET_MAGIC_DEF("underflow", js_float_env_proto_get_status,
50331
                         js_float_env_proto_set_status, BF_ST_UNDERFLOW ),
50332
    JS_CGETSET_MAGIC_DEF("inexact", js_float_env_proto_get_status,
50333
                         js_float_env_proto_set_status, BF_ST_INEXACT ),
50334
    JS_CFUNC_DEF("clearStatus", 0, js_float_env_clearStatus ),
50335
};
50336
50337
void JS_AddIntrinsicBigFloat(JSContext *ctx)
50338
0
{
50339
0
    JSRuntime *rt = ctx->rt;
50340
0
    JSValueConst obj1;
50341
    
50342
0
    rt->bigfloat_ops.to_string = js_bigfloat_to_string;
50343
0
    rt->bigfloat_ops.from_string = js_string_to_bigfloat;
50344
0
    rt->bigfloat_ops.unary_arith = js_unary_arith_bigfloat;
50345
0
    rt->bigfloat_ops.binary_arith = js_binary_arith_bigfloat;
50346
0
    rt->bigfloat_ops.compare = js_compare_bigfloat;
50347
0
    rt->bigfloat_ops.mul_pow10_to_float64 = js_mul_pow10_to_float64;
50348
0
    rt->bigfloat_ops.mul_pow10 = js_mul_pow10;
50349
    
50350
0
    ctx->class_proto[JS_CLASS_BIG_FLOAT] = JS_NewObject(ctx);
50351
0
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT],
50352
0
                               js_bigfloat_proto_funcs,
50353
0
                               countof(js_bigfloat_proto_funcs));
50354
0
    obj1 = JS_NewGlobalCConstructor(ctx, "BigFloat", js_bigfloat_constructor, 1,
50355
0
                                    ctx->class_proto[JS_CLASS_BIG_FLOAT]);
50356
0
    JS_SetPropertyFunctionList(ctx, obj1, js_bigfloat_funcs,
50357
0
                               countof(js_bigfloat_funcs));
50358
50359
0
    ctx->class_proto[JS_CLASS_FLOAT_ENV] = JS_NewObject(ctx);
50360
0
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FLOAT_ENV],
50361
0
                               js_float_env_proto_funcs,
50362
0
                               countof(js_float_env_proto_funcs));
50363
0
    obj1 = JS_NewGlobalCConstructorOnly(ctx, "BigFloatEnv",
50364
0
                                        js_float_env_constructor, 1,
50365
0
                                        ctx->class_proto[JS_CLASS_FLOAT_ENV]);
50366
0
    JS_SetPropertyFunctionList(ctx, obj1, js_float_env_funcs,
50367
0
                               countof(js_float_env_funcs));
50368
0
}
50369
50370
/* BigDecimal */
50371
50372
static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
50373
                                   BOOL allow_null_or_undefined)
50374
0
{
50375
0
 redo:
50376
0
    switch(JS_VALUE_GET_NORM_TAG(val)) {
50377
0
    case JS_TAG_BIG_DECIMAL:
50378
0
        break;
50379
0
    case JS_TAG_NULL:
50380
0
        if (!allow_null_or_undefined)
50381
0
            goto fail;
50382
        /* fall thru */
50383
0
    case JS_TAG_BOOL:
50384
0
    case JS_TAG_INT:
50385
0
        {
50386
0
            bfdec_t *r;
50387
0
            int32_t v = JS_VALUE_GET_INT(val);
50388
50389
0
            val = JS_NewBigDecimal(ctx);
50390
0
            if (JS_IsException(val))
50391
0
                break;
50392
0
            r = JS_GetBigDecimal(val);
50393
0
            if (bfdec_set_si(r, v)) {
50394
0
                JS_FreeValue(ctx, val);
50395
0
                val = JS_EXCEPTION;
50396
0
                break;
50397
0
            }
50398
0
        }
50399
0
        break;
50400
0
    case JS_TAG_FLOAT64:
50401
0
    case JS_TAG_BIG_INT:
50402
0
    case JS_TAG_BIG_FLOAT:
50403
0
        val = JS_ToStringFree(ctx, val);
50404
0
        if (JS_IsException(val))
50405
0
            break;
50406
0
        goto redo;
50407
0
    case JS_TAG_STRING:
50408
0
        {
50409
0
            const char *str, *p;
50410
0
            size_t len;
50411
0
            int err;
50412
50413
0
            str = JS_ToCStringLen(ctx, &len, val);
50414
0
            JS_FreeValue(ctx, val);
50415
0
            if (!str)
50416
0
                return JS_EXCEPTION;
50417
0
            p = str;
50418
0
            p += skip_spaces(p);
50419
0
            if ((p - str) == len) {
50420
0
                bfdec_t *r;
50421
0
                val = JS_NewBigDecimal(ctx);
50422
0
                if (JS_IsException(val))
50423
0
                    break;
50424
0
                r = JS_GetBigDecimal(val);
50425
0
                bfdec_set_zero(r, 0);
50426
0
                err = 0;
50427
0
            } else {
50428
0
                val = js_atof(ctx, p, &p, 0, ATOD_TYPE_BIG_DECIMAL);
50429
0
                if (JS_IsException(val)) {
50430
0
                    JS_FreeCString(ctx, str);
50431
0
                    return JS_EXCEPTION;
50432
0
                }
50433
0
                p += skip_spaces(p);
50434
0
                err = ((p - str) != len);
50435
0
            }
50436
0
            JS_FreeCString(ctx, str);
50437
0
            if (err) {
50438
0
                JS_FreeValue(ctx, val);
50439
0
                return JS_ThrowSyntaxError(ctx, "invalid bigdecimal literal");
50440
0
            }
50441
0
        }
50442
0
        break;
50443
0
    case JS_TAG_OBJECT:
50444
0
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
50445
0
        if (JS_IsException(val))
50446
0
            break;
50447
0
        goto redo;
50448
0
    case JS_TAG_UNDEFINED:
50449
0
        {
50450
0
            bfdec_t *r;
50451
0
            if (!allow_null_or_undefined)
50452
0
                goto fail;
50453
0
            val = JS_NewBigDecimal(ctx);
50454
0
            if (JS_IsException(val))
50455
0
                break;
50456
0
            r = JS_GetBigDecimal(val);
50457
0
            bfdec_set_nan(r);
50458
0
        }
50459
0
        break;
50460
0
    default:
50461
0
    fail:
50462
0
        JS_FreeValue(ctx, val);
50463
0
        return JS_ThrowTypeError(ctx, "cannot convert to bigdecimal");
50464
0
    }
50465
0
    return val;
50466
0
}
50467
50468
static JSValue js_bigdecimal_constructor(JSContext *ctx,
50469
                                         JSValueConst new_target,
50470
                                         int argc, JSValueConst *argv)
50471
0
{
50472
0
    JSValue val;
50473
0
    if (!JS_IsUndefined(new_target))
50474
0
        return JS_ThrowTypeError(ctx, "not a constructor");
50475
0
    if (argc == 0) {
50476
0
        bfdec_t *r;
50477
0
        val = JS_NewBigDecimal(ctx);
50478
0
        if (JS_IsException(val))
50479
0
            return val;
50480
0
        r = JS_GetBigDecimal(val);
50481
0
        bfdec_set_zero(r, 0);
50482
0
    } else {
50483
0
        val = JS_ToBigDecimalFree(ctx, JS_DupValue(ctx, argv[0]), FALSE);
50484
0
    }
50485
0
    return val;
50486
0
}
50487
50488
static JSValue js_thisBigDecimalValue(JSContext *ctx, JSValueConst this_val)
50489
0
{
50490
0
    if (JS_IsBigDecimal(this_val))
50491
0
        return JS_DupValue(ctx, this_val);
50492
50493
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
50494
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
50495
0
        if (p->class_id == JS_CLASS_BIG_DECIMAL) {
50496
0
            if (JS_IsBigDecimal(p->u.object_data))
50497
0
                return JS_DupValue(ctx, p->u.object_data);
50498
0
        }
50499
0
    }
50500
0
    return JS_ThrowTypeError(ctx, "not a bigdecimal");
50501
0
}
50502
50503
static JSValue js_bigdecimal_toString(JSContext *ctx, JSValueConst this_val,
50504
                                      int argc, JSValueConst *argv)
50505
0
{
50506
0
    JSValue val;
50507
50508
0
    val = js_thisBigDecimalValue(ctx, this_val);
50509
0
    if (JS_IsException(val))
50510
0
        return val;
50511
0
    return JS_ToStringFree(ctx, val);
50512
0
}
50513
50514
static JSValue js_bigdecimal_valueOf(JSContext *ctx, JSValueConst this_val,
50515
                                   int argc, JSValueConst *argv)
50516
0
{
50517
0
    return js_thisBigDecimalValue(ctx, this_val);
50518
0
}
50519
50520
static int js_bigdecimal_get_rnd_mode(JSContext *ctx, JSValueConst obj)
50521
0
{
50522
0
    const char *str;
50523
0
    size_t size;
50524
0
    int rnd_mode;
50525
    
50526
0
    str = JS_ToCStringLen(ctx, &size, obj);
50527
0
    if (!str)
50528
0
        return -1;
50529
0
    if (strlen(str) != size)
50530
0
        goto invalid_rounding_mode;
50531
0
    if (!strcmp(str, "floor")) {
50532
0
        rnd_mode = BF_RNDD;
50533
0
    } else if (!strcmp(str, "ceiling")) {
50534
0
        rnd_mode = BF_RNDU;
50535
0
    } else if (!strcmp(str, "down")) {
50536
0
        rnd_mode = BF_RNDZ;
50537
0
    } else if (!strcmp(str, "up")) {
50538
0
        rnd_mode = BF_RNDA;
50539
0
    } else if (!strcmp(str, "half-even")) {
50540
0
        rnd_mode = BF_RNDN;
50541
0
    } else if (!strcmp(str, "half-up")) {
50542
0
        rnd_mode = BF_RNDNA;
50543
0
    } else {
50544
0
    invalid_rounding_mode:
50545
0
        JS_FreeCString(ctx, str);
50546
0
        JS_ThrowTypeError(ctx, "invalid rounding mode");
50547
0
        return -1;
50548
0
    }
50549
0
    JS_FreeCString(ctx, str);
50550
0
    return rnd_mode;
50551
0
}
50552
50553
typedef struct {
50554
    int64_t prec;
50555
    bf_flags_t flags;
50556
} BigDecimalEnv;
50557
50558
static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe,
50559
                                 JSValueConst obj)
50560
0
{
50561
0
    JSValue prop;
50562
0
    int64_t val;
50563
0
    BOOL has_prec;
50564
0
    int rnd_mode;
50565
    
50566
0
    if (!JS_IsObject(obj)) {
50567
0
        JS_ThrowTypeErrorNotAnObject(ctx);
50568
0
        return -1;
50569
0
    }
50570
0
    prop = JS_GetProperty(ctx, obj, JS_ATOM_roundingMode);
50571
0
    if (JS_IsException(prop))
50572
0
        return -1;
50573
0
    rnd_mode = js_bigdecimal_get_rnd_mode(ctx, prop);
50574
0
    JS_FreeValue(ctx, prop);
50575
0
    if (rnd_mode < 0)
50576
0
        return -1;
50577
0
    fe->flags = rnd_mode;
50578
    
50579
0
    prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits);
50580
0
    if (JS_IsException(prop))
50581
0
        return -1;
50582
0
    has_prec = FALSE;
50583
0
    if (!JS_IsUndefined(prop)) {
50584
0
        if (JS_ToInt64SatFree(ctx, &val, prop))
50585
0
            return -1;
50586
0
        if (val < 1 || val > BF_PREC_MAX)
50587
0
            goto invalid_precision;
50588
0
        fe->prec = val;
50589
0
        has_prec = TRUE;
50590
0
    }
50591
50592
0
    prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumFractionDigits);
50593
0
    if (JS_IsException(prop))
50594
0
        return -1;
50595
0
    if (!JS_IsUndefined(prop)) {
50596
0
        if (has_prec) {
50597
0
            JS_FreeValue(ctx, prop);
50598
0
            JS_ThrowTypeError(ctx, "cannot provide both maximumSignificantDigits and maximumFractionDigits");
50599
0
            return -1;
50600
0
        }
50601
0
        if (JS_ToInt64SatFree(ctx, &val, prop))
50602
0
            return -1;
50603
0
        if (val < 0 || val > BF_PREC_MAX) {
50604
0
        invalid_precision:
50605
0
            JS_ThrowTypeError(ctx, "invalid precision");
50606
0
            return -1;
50607
0
        }
50608
0
        fe->prec = val;
50609
0
        fe->flags |= BF_FLAG_RADPNT_PREC;
50610
0
        has_prec = TRUE;
50611
0
    }
50612
0
    if (!has_prec) {
50613
0
        JS_ThrowTypeError(ctx, "precision must be present");
50614
0
        return -1;
50615
0
    }
50616
0
    return 0;
50617
0
}
50618
50619
50620
static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val,
50621
                                 int argc, JSValueConst *argv, int magic)
50622
0
{
50623
0
    bfdec_t *a, *b, r_s, *r = &r_s;
50624
0
    JSValue op1, op2, res;
50625
0
    BigDecimalEnv fe_s, *fe = &fe_s;
50626
0
    int op_count, ret;
50627
50628
0
    if (magic == MATH_OP_SQRT ||
50629
0
        magic == MATH_OP_ROUND)
50630
0
        op_count = 1;
50631
0
    else
50632
0
        op_count = 2;
50633
    
50634
0
    op1 = JS_ToNumeric(ctx, argv[0]);
50635
0
    if (JS_IsException(op1))
50636
0
        return op1;
50637
0
    a = JS_ToBigDecimal(ctx, op1);
50638
0
    if (!a) {
50639
0
        JS_FreeValue(ctx, op1);
50640
0
        return JS_EXCEPTION;
50641
0
    }
50642
0
    if (op_count >= 2) {
50643
0
        op2 = JS_ToNumeric(ctx, argv[1]);
50644
0
        if (JS_IsException(op2)) {
50645
0
            JS_FreeValue(ctx, op1);
50646
0
            return op2;
50647
0
        }
50648
0
        b = JS_ToBigDecimal(ctx, op2);
50649
0
        if (!b)
50650
0
            goto fail;
50651
0
    } else {
50652
0
        op2 = JS_UNDEFINED;
50653
0
        b = NULL;
50654
0
    }
50655
0
    fe->flags = BF_RNDZ;
50656
0
    fe->prec = BF_PREC_INF;
50657
0
    if (op_count < argc) {
50658
0
        if (js_bigdecimal_get_env(ctx, fe, argv[op_count]))
50659
0
            goto fail;
50660
0
    }
50661
50662
0
    res = JS_NewBigDecimal(ctx);
50663
0
    if (JS_IsException(res)) {
50664
0
    fail:
50665
0
        JS_FreeValue(ctx, op1);
50666
0
        JS_FreeValue(ctx, op2);
50667
0
        return JS_EXCEPTION;
50668
0
    }
50669
0
    r = JS_GetBigDecimal(res);
50670
0
    switch (magic) {
50671
0
    case MATH_OP_ADD:
50672
0
        ret = bfdec_add(r, a, b, fe->prec, fe->flags);
50673
0
        break;
50674
0
    case MATH_OP_SUB:
50675
0
        ret = bfdec_sub(r, a, b, fe->prec, fe->flags);
50676
0
        break;
50677
0
    case MATH_OP_MUL:
50678
0
        ret = bfdec_mul(r, a, b, fe->prec, fe->flags);
50679
0
        break;
50680
0
    case MATH_OP_DIV:
50681
0
        ret = bfdec_div(r, a, b, fe->prec, fe->flags);
50682
0
        break;
50683
0
    case MATH_OP_FMOD:
50684
0
        ret = bfdec_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
50685
0
        break;
50686
0
    case MATH_OP_SQRT:
50687
0
        ret = bfdec_sqrt(r, a, fe->prec, fe->flags);
50688
0
        break;
50689
0
    case MATH_OP_ROUND:
50690
0
        ret = bfdec_set(r, a);
50691
0
        if (!(ret & BF_ST_MEM_ERROR))
50692
0
            ret = bfdec_round(r, fe->prec, fe->flags);
50693
0
        break;
50694
0
    default:
50695
0
        abort();
50696
0
    }
50697
0
    JS_FreeValue(ctx, op1);
50698
0
    JS_FreeValue(ctx, op2);
50699
0
    ret &= BF_ST_MEM_ERROR | BF_ST_DIVIDE_ZERO | BF_ST_INVALID_OP |
50700
0
        BF_ST_OVERFLOW;
50701
0
    if (ret != 0) {
50702
0
        JS_FreeValue(ctx, res);
50703
0
        return throw_bf_exception(ctx, ret);
50704
0
    } else {
50705
0
        return res;
50706
0
    }
50707
0
}
50708
50709
static JSValue js_bigdecimal_toFixed(JSContext *ctx, JSValueConst this_val,
50710
                                 int argc, JSValueConst *argv)
50711
0
{
50712
0
    JSValue val, ret;
50713
0
    int64_t f;
50714
0
    int rnd_mode;
50715
50716
0
    val = js_thisBigDecimalValue(ctx, this_val);
50717
0
    if (JS_IsException(val))
50718
0
        return val;
50719
0
    if (JS_ToInt64Sat(ctx, &f, argv[0]))
50720
0
        goto fail;
50721
0
    if (f < 0 || f > BF_PREC_MAX) {
50722
0
        JS_ThrowRangeError(ctx, "invalid number of digits");
50723
0
        goto fail;
50724
0
    }
50725
0
    rnd_mode = BF_RNDNA;
50726
0
    if (argc > 1) {
50727
0
        rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
50728
0
        if (rnd_mode < 0)
50729
0
            goto fail;
50730
0
    }
50731
0
    ret = js_bigdecimal_to_string1(ctx, val, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
50732
0
    JS_FreeValue(ctx, val);
50733
0
    return ret;
50734
0
 fail:
50735
0
    JS_FreeValue(ctx, val);
50736
0
    return JS_EXCEPTION;
50737
0
}
50738
50739
static JSValue js_bigdecimal_toExponential(JSContext *ctx, JSValueConst this_val,
50740
                                       int argc, JSValueConst *argv)
50741
0
{
50742
0
    JSValue val, ret;
50743
0
    int64_t f;
50744
0
    int rnd_mode;
50745
50746
0
    val = js_thisBigDecimalValue(ctx, this_val);
50747
0
    if (JS_IsException(val))
50748
0
        return val;
50749
0
    if (JS_ToInt64Sat(ctx, &f, argv[0]))
50750
0
        goto fail;
50751
0
    if (JS_IsUndefined(argv[0])) {
50752
0
        ret = js_bigdecimal_to_string1(ctx, val, 0,
50753
0
                  BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
50754
0
    } else {
50755
0
        if (f < 0 || f > BF_PREC_MAX) {
50756
0
            JS_ThrowRangeError(ctx, "invalid number of digits");
50757
0
            goto fail;
50758
0
        }
50759
0
        rnd_mode = BF_RNDNA;
50760
0
        if (argc > 1) {
50761
0
            rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
50762
0
            if (rnd_mode < 0)
50763
0
                goto fail;
50764
0
        }
50765
0
        ret = js_bigdecimal_to_string1(ctx, val, f + 1,
50766
0
                      rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
50767
0
    }
50768
0
    JS_FreeValue(ctx, val);
50769
0
    return ret;
50770
0
 fail:
50771
0
    JS_FreeValue(ctx, val);
50772
0
    return JS_EXCEPTION;
50773
0
}
50774
50775
static JSValue js_bigdecimal_toPrecision(JSContext *ctx, JSValueConst this_val,
50776
                                     int argc, JSValueConst *argv)
50777
0
{
50778
0
    JSValue val, ret;
50779
0
    int64_t p;
50780
0
    int rnd_mode;
50781
50782
0
    val = js_thisBigDecimalValue(ctx, this_val);
50783
0
    if (JS_IsException(val))
50784
0
        return val;
50785
0
    if (JS_IsUndefined(argv[0])) {
50786
0
        return JS_ToStringFree(ctx, val);
50787
0
    }
50788
0
    if (JS_ToInt64Sat(ctx, &p, argv[0]))
50789
0
        goto fail;
50790
0
    if (p < 1 || p > BF_PREC_MAX) {
50791
0
        JS_ThrowRangeError(ctx, "invalid number of digits");
50792
0
        goto fail;
50793
0
    }
50794
0
    rnd_mode = BF_RNDNA;
50795
0
    if (argc > 1) {
50796
0
        rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
50797
0
        if (rnd_mode < 0)
50798
0
            goto fail;
50799
0
    }
50800
0
    ret = js_bigdecimal_to_string1(ctx, val, p,
50801
0
                                   rnd_mode | BF_FTOA_FORMAT_FIXED);
50802
0
    JS_FreeValue(ctx, val);
50803
0
    return ret;
50804
0
 fail:
50805
0
    JS_FreeValue(ctx, val);
50806
0
    return JS_EXCEPTION;
50807
0
}
50808
50809
static const JSCFunctionListEntry js_bigdecimal_proto_funcs[] = {
50810
    JS_CFUNC_DEF("toString", 0, js_bigdecimal_toString ),
50811
    JS_CFUNC_DEF("valueOf", 0, js_bigdecimal_valueOf ),
50812
    JS_CFUNC_DEF("toPrecision", 1, js_bigdecimal_toPrecision ),
50813
    JS_CFUNC_DEF("toFixed", 1, js_bigdecimal_toFixed ),
50814
    JS_CFUNC_DEF("toExponential", 1, js_bigdecimal_toExponential ),
50815
};
50816
50817
static const JSCFunctionListEntry js_bigdecimal_funcs[] = {
50818
    JS_CFUNC_MAGIC_DEF("add", 2, js_bigdecimal_fop, MATH_OP_ADD ),
50819
    JS_CFUNC_MAGIC_DEF("sub", 2, js_bigdecimal_fop, MATH_OP_SUB ),
50820
    JS_CFUNC_MAGIC_DEF("mul", 2, js_bigdecimal_fop, MATH_OP_MUL ),
50821
    JS_CFUNC_MAGIC_DEF("div", 2, js_bigdecimal_fop, MATH_OP_DIV ),
50822
    JS_CFUNC_MAGIC_DEF("mod", 2, js_bigdecimal_fop, MATH_OP_FMOD ),
50823
    JS_CFUNC_MAGIC_DEF("round", 1, js_bigdecimal_fop, MATH_OP_ROUND ),
50824
    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigdecimal_fop, MATH_OP_SQRT ),
50825
};
50826
50827
void JS_AddIntrinsicBigDecimal(JSContext *ctx)
50828
0
{
50829
0
    JSRuntime *rt = ctx->rt;
50830
0
    JSValueConst obj1;
50831
50832
0
    rt->bigdecimal_ops.to_string = js_bigdecimal_to_string;
50833
0
    rt->bigdecimal_ops.from_string = js_string_to_bigdecimal;
50834
0
    rt->bigdecimal_ops.unary_arith = js_unary_arith_bigdecimal;
50835
0
    rt->bigdecimal_ops.binary_arith = js_binary_arith_bigdecimal;
50836
0
    rt->bigdecimal_ops.compare = js_compare_bigdecimal;
50837
50838
0
    ctx->class_proto[JS_CLASS_BIG_DECIMAL] = JS_NewObject(ctx);
50839
0
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL],
50840
0
                               js_bigdecimal_proto_funcs,
50841
0
                               countof(js_bigdecimal_proto_funcs));
50842
0
    obj1 = JS_NewGlobalCConstructor(ctx, "BigDecimal",
50843
0
                                    js_bigdecimal_constructor, 1,
50844
0
                                    ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
50845
0
    JS_SetPropertyFunctionList(ctx, obj1, js_bigdecimal_funcs,
50846
0
                               countof(js_bigdecimal_funcs));
50847
0
}
50848
50849
void JS_EnableBignumExt(JSContext *ctx, BOOL enable)
50850
0
{
50851
0
    ctx->bignum_ext = enable;
50852
0
}
50853
50854
#endif /* CONFIG_BIGNUM */
50855
50856
static const char * const native_error_name[JS_NATIVE_ERROR_COUNT] = {
50857
    "EvalError", "RangeError", "ReferenceError",
50858
    "SyntaxError", "TypeError", "URIError",
50859
    "InternalError", "AggregateError",
50860
};
50861
50862
/* Minimum amount of objects to be able to compile code and display
50863
   error messages. No JSAtom should be allocated by this function. */
50864
static void JS_AddIntrinsicBasicObjects(JSContext *ctx)
50865
3
{
50866
3
    JSValue proto;
50867
3
    int i;
50868
50869
3
    ctx->class_proto[JS_CLASS_OBJECT] = JS_NewObjectProto(ctx, JS_NULL);
50870
3
    ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, "", 0,
50871
3
                                           JS_CFUNC_generic, 0,
50872
3
                                           ctx->class_proto[JS_CLASS_OBJECT]);
50873
3
    ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = JS_DupValue(ctx, ctx->function_proto);
50874
3
    ctx->class_proto[JS_CLASS_ERROR] = JS_NewObject(ctx);
50875
#if 0
50876
    /* these are auto-initialized from js_error_proto_funcs,
50877
       but delaying might be a problem */
50878
    JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_name,
50879
                           JS_AtomToString(ctx, JS_ATOM_Error),
50880
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
50881
    JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_message,
50882
                           JS_AtomToString(ctx, JS_ATOM_empty_string),
50883
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
50884
#endif
50885
3
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ERROR],
50886
3
                               js_error_proto_funcs,
50887
3
                               countof(js_error_proto_funcs));
50888
50889
27
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
50890
24
        proto = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ERROR]);
50891
24
        JS_DefinePropertyValue(ctx, proto, JS_ATOM_name,
50892
24
                               JS_NewAtomString(ctx, native_error_name[i]),
50893
24
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
50894
24
        JS_DefinePropertyValue(ctx, proto, JS_ATOM_message,
50895
24
                               JS_AtomToString(ctx, JS_ATOM_empty_string),
50896
24
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
50897
24
        ctx->native_error_proto[i] = proto;
50898
24
    }
50899
50900
    /* the array prototype is an array */
50901
3
    ctx->class_proto[JS_CLASS_ARRAY] =
50902
3
        JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
50903
3
                               JS_CLASS_ARRAY);
50904
50905
3
    ctx->array_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]),
50906
3
                                     JS_PROP_INITIAL_HASH_SIZE, 1);
50907
3
    add_shape_property(ctx, &ctx->array_shape, NULL,
50908
3
                       JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH);
50909
50910
    /* XXX: could test it on first context creation to ensure that no
50911
       new atoms are created in JS_AddIntrinsicBasicObjects(). It is
50912
       necessary to avoid useless renumbering of atoms after
50913
       JS_EvalBinary() if it is done just after
50914
       JS_AddIntrinsicBasicObjects(). */
50915
    //    assert(ctx->rt->atom_count == JS_ATOM_END);
50916
3
}
50917
50918
void JS_AddIntrinsicBaseObjects(JSContext *ctx)
50919
2
{
50920
2
    int i;
50921
2
    JSValueConst obj, number_obj;
50922
2
    JSValue obj1;
50923
50924
2
    ctx->throw_type_error = JS_NewCFunction(ctx, js_throw_type_error, NULL, 0);
50925
50926
    /* add caller and arguments properties to throw a TypeError */
50927
2
    obj1 = JS_NewCFunction(ctx, js_function_proto_caller, NULL, 0);
50928
2
    JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_caller, JS_UNDEFINED,
50929
2
                      obj1, ctx->throw_type_error,
50930
2
                      JS_PROP_HAS_GET | JS_PROP_HAS_SET |
50931
2
                      JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
50932
2
    JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_arguments, JS_UNDEFINED,
50933
2
                      obj1, ctx->throw_type_error,
50934
2
                      JS_PROP_HAS_GET | JS_PROP_HAS_SET |
50935
2
                      JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
50936
2
    JS_FreeValue(ctx, obj1);
50937
2
    JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, (JSValueConst *)&ctx->throw_type_error, 1));
50938
50939
2
    ctx->global_obj = JS_NewObject(ctx);
50940
2
    ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL);
50941
50942
    /* Object */
50943
2
    obj = JS_NewGlobalCConstructor(ctx, "Object", js_object_constructor, 1,
50944
2
                                   ctx->class_proto[JS_CLASS_OBJECT]);
50945
2
    JS_SetPropertyFunctionList(ctx, obj, js_object_funcs, countof(js_object_funcs));
50946
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_OBJECT],
50947
2
                               js_object_proto_funcs, countof(js_object_proto_funcs));
50948
50949
    /* Function */
50950
2
    JS_SetPropertyFunctionList(ctx, ctx->function_proto, js_function_proto_funcs, countof(js_function_proto_funcs));
50951
2
    ctx->function_ctor = JS_NewCFunctionMagic(ctx, js_function_constructor,
50952
2
                                              "Function", 1, JS_CFUNC_constructor_or_func_magic,
50953
2
                                              JS_FUNC_NORMAL);
50954
2
    JS_NewGlobalCConstructor2(ctx, JS_DupValue(ctx, ctx->function_ctor), "Function",
50955
2
                              ctx->function_proto);
50956
50957
    /* Error */
50958
2
    obj1 = JS_NewCFunctionMagic(ctx, js_error_constructor,
50959
2
                                "Error", 1, JS_CFUNC_constructor_or_func_magic, -1);
50960
2
    JS_NewGlobalCConstructor2(ctx, obj1,
50961
2
                              "Error", ctx->class_proto[JS_CLASS_ERROR]);
50962
50963
18
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
50964
16
        JSValue func_obj;
50965
16
        int n_args;
50966
16
        n_args = 1 + (i == JS_AGGREGATE_ERROR);
50967
16
        func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_error_constructor,
50968
16
                                    native_error_name[i], n_args,
50969
16
                                    JS_CFUNC_constructor_or_func_magic, i, obj1);
50970
16
        JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i],
50971
16
                                  ctx->native_error_proto[i]);
50972
16
    }
50973
50974
    /* Iterator prototype */
50975
2
    ctx->iterator_proto = JS_NewObject(ctx);
50976
2
    JS_SetPropertyFunctionList(ctx, ctx->iterator_proto,
50977
2
                               js_iterator_proto_funcs,
50978
2
                               countof(js_iterator_proto_funcs));
50979
50980
    /* Array */
50981
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY],
50982
2
                               js_array_proto_funcs,
50983
2
                               countof(js_array_proto_funcs));
50984
50985
2
    obj = JS_NewGlobalCConstructor(ctx, "Array", js_array_constructor, 1,
50986
2
                                   ctx->class_proto[JS_CLASS_ARRAY]);
50987
2
    ctx->array_ctor = JS_DupValue(ctx, obj);
50988
2
    JS_SetPropertyFunctionList(ctx, obj, js_array_funcs,
50989
2
                               countof(js_array_funcs));
50990
50991
    /* XXX: create auto_initializer */
50992
2
    {
50993
        /* initialize Array.prototype[Symbol.unscopables] */
50994
2
        char const unscopables[] = "copyWithin" "\0" "entries" "\0" "fill" "\0" "find" "\0"
50995
2
            "findIndex" "\0" "flat" "\0" "flatMap" "\0" "includes" "\0" "keys" "\0" "values" "\0";
50996
2
        const char *p = unscopables;
50997
2
        obj1 = JS_NewObjectProto(ctx, JS_NULL);
50998
22
        for(p = unscopables; *p; p += strlen(p) + 1) {
50999
20
            JS_DefinePropertyValueStr(ctx, obj1, p, JS_TRUE, JS_PROP_C_W_E);
51000
20
        }
51001
2
        JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ARRAY],
51002
2
                               JS_ATOM_Symbol_unscopables, obj1,
51003
2
                               JS_PROP_CONFIGURABLE);
51004
2
    }
51005
51006
    /* needed to initialize arguments[Symbol.iterator] */
51007
2
    ctx->array_proto_values =
51008
2
        JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_values);
51009
51010
2
    ctx->class_proto[JS_CLASS_ARRAY_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
51011
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_ITERATOR],
51012
2
                               js_array_iterator_proto_funcs,
51013
2
                               countof(js_array_iterator_proto_funcs));
51014
51015
    /* parseFloat and parseInteger must be defined before Number
51016
       because of the Number.parseFloat and Number.parseInteger
51017
       aliases */
51018
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_global_funcs,
51019
2
                               countof(js_global_funcs));
51020
51021
    /* Number */
51022
2
    ctx->class_proto[JS_CLASS_NUMBER] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
51023
2
                                                               JS_CLASS_NUMBER);
51024
2
    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_NUMBER], JS_NewInt32(ctx, 0));
51025
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_NUMBER],
51026
2
                               js_number_proto_funcs,
51027
2
                               countof(js_number_proto_funcs));
51028
2
    number_obj = JS_NewGlobalCConstructor(ctx, "Number", js_number_constructor, 1,
51029
2
                                          ctx->class_proto[JS_CLASS_NUMBER]);
51030
2
    JS_SetPropertyFunctionList(ctx, number_obj, js_number_funcs, countof(js_number_funcs));
51031
51032
    /* Boolean */
51033
2
    ctx->class_proto[JS_CLASS_BOOLEAN] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
51034
2
                                                                JS_CLASS_BOOLEAN);
51035
2
    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], JS_NewBool(ctx, FALSE));
51036
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], js_boolean_proto_funcs,
51037
2
                               countof(js_boolean_proto_funcs));
51038
2
    JS_NewGlobalCConstructor(ctx, "Boolean", js_boolean_constructor, 1,
51039
2
                             ctx->class_proto[JS_CLASS_BOOLEAN]);
51040
51041
    /* String */
51042
2
    ctx->class_proto[JS_CLASS_STRING] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
51043
2
                                                               JS_CLASS_STRING);
51044
2
    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_STRING], JS_AtomToString(ctx, JS_ATOM_empty_string));
51045
2
    obj = JS_NewGlobalCConstructor(ctx, "String", js_string_constructor, 1,
51046
2
                                   ctx->class_proto[JS_CLASS_STRING]);
51047
2
    JS_SetPropertyFunctionList(ctx, obj, js_string_funcs,
51048
2
                               countof(js_string_funcs));
51049
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_funcs,
51050
2
                               countof(js_string_proto_funcs));
51051
51052
2
    ctx->class_proto[JS_CLASS_STRING_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
51053
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING_ITERATOR],
51054
2
                               js_string_iterator_proto_funcs,
51055
2
                               countof(js_string_iterator_proto_funcs));
51056
51057
    /* Math: create as autoinit object */
51058
2
    js_random_init(ctx);
51059
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_math_obj, countof(js_math_obj));
51060
51061
    /* ES6 Reflect: create as autoinit object */
51062
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_reflect_obj, countof(js_reflect_obj));
51063
51064
    /* ES6 Symbol */
51065
2
    ctx->class_proto[JS_CLASS_SYMBOL] = JS_NewObject(ctx);
51066
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SYMBOL], js_symbol_proto_funcs,
51067
2
                               countof(js_symbol_proto_funcs));
51068
2
    obj = JS_NewGlobalCConstructor(ctx, "Symbol", js_symbol_constructor, 0,
51069
2
                                   ctx->class_proto[JS_CLASS_SYMBOL]);
51070
2
    JS_SetPropertyFunctionList(ctx, obj, js_symbol_funcs,
51071
2
                               countof(js_symbol_funcs));
51072
30
    for(i = JS_ATOM_Symbol_toPrimitive; i < JS_ATOM_END; i++) {
51073
28
        char buf[ATOM_GET_STR_BUF_SIZE];
51074
28
        const char *str, *p;
51075
28
        str = JS_AtomGetStr(ctx, buf, sizeof(buf), i);
51076
        /* skip "Symbol." */
51077
28
        p = strchr(str, '.');
51078
28
        if (p)
51079
28
            str = p + 1;
51080
28
        JS_DefinePropertyValueStr(ctx, obj, str, JS_AtomToValue(ctx, i), 0);
51081
28
    }
51082
51083
    /* ES6 Generator */
51084
2
    ctx->class_proto[JS_CLASS_GENERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
51085
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_GENERATOR],
51086
2
                               js_generator_proto_funcs,
51087
2
                               countof(js_generator_proto_funcs));
51088
51089
2
    ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
51090
2
    obj1 = JS_NewCFunctionMagic(ctx, js_function_constructor,
51091
2
                                "GeneratorFunction", 1,
51092
2
                                JS_CFUNC_constructor_or_func_magic, JS_FUNC_GENERATOR);
51093
2
    JS_SetPropertyFunctionList(ctx,
51094
2
                               ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
51095
2
                               js_generator_function_proto_funcs,
51096
2
                               countof(js_generator_function_proto_funcs));
51097
2
    JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
51098
2
                       ctx->class_proto[JS_CLASS_GENERATOR],
51099
2
                       JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
51100
2
    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
51101
2
                       0, JS_PROP_CONFIGURABLE);
51102
2
    JS_FreeValue(ctx, obj1);
51103
51104
    /* global properties */
51105
2
    ctx->eval_obj = JS_NewCFunction(ctx, js_global_eval, "eval", 1);
51106
2
    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_eval,
51107
2
                           JS_DupValue(ctx, ctx->eval_obj),
51108
2
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
51109
51110
2
    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_globalThis,
51111
2
                           JS_DupValue(ctx, ctx->global_obj),
51112
2
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
51113
2
}
51114
51115
/* Typed Arrays */
51116
51117
static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = {
51118
    0, 0, 0, 1, 1, 2, 2,
51119
#ifdef CONFIG_BIGNUM
51120
    3, 3, /* BigInt64Array, BigUint64Array */
51121
#endif
51122
    2, 3
51123
};
51124
51125
static JSValue js_array_buffer_constructor3(JSContext *ctx,
51126
                                            JSValueConst new_target,
51127
                                            uint64_t len, JSClassID class_id,
51128
                                            uint8_t *buf,
51129
                                            JSFreeArrayBufferDataFunc *free_func,
51130
                                            void *opaque, BOOL alloc_flag)
51131
0
{
51132
0
    JSRuntime *rt = ctx->rt;
51133
0
    JSValue obj;
51134
0
    JSArrayBuffer *abuf = NULL;
51135
51136
0
    obj = js_create_from_ctor(ctx, new_target, class_id);
51137
0
    if (JS_IsException(obj))
51138
0
        return obj;
51139
    /* XXX: we are currently limited to 2 GB */
51140
0
    if (len > INT32_MAX) {
51141
0
        JS_ThrowRangeError(ctx, "invalid array buffer length");
51142
0
        goto fail;
51143
0
    }
51144
0
    abuf = js_malloc(ctx, sizeof(*abuf));
51145
0
    if (!abuf)
51146
0
        goto fail;
51147
0
    abuf->byte_length = len;
51148
0
    if (alloc_flag) {
51149
0
        if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
51150
0
            rt->sab_funcs.sab_alloc) {
51151
0
            abuf->data = rt->sab_funcs.sab_alloc(rt->sab_funcs.sab_opaque,
51152
0
                                                 max_int(len, 1));
51153
0
            if (!abuf->data)
51154
0
                goto fail;
51155
0
            memset(abuf->data, 0, len);
51156
0
        } else {
51157
            /* the allocation must be done after the object creation */
51158
0
            abuf->data = js_mallocz(ctx, max_int(len, 1));
51159
0
            if (!abuf->data)
51160
0
                goto fail;
51161
0
        }
51162
0
    } else {
51163
0
        if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
51164
0
            rt->sab_funcs.sab_dup) {
51165
0
            rt->sab_funcs.sab_dup(rt->sab_funcs.sab_opaque, buf);
51166
0
        }
51167
0
        abuf->data = buf;
51168
0
    }
51169
0
    init_list_head(&abuf->array_list);
51170
0
    abuf->detached = FALSE;
51171
0
    abuf->shared = (class_id == JS_CLASS_SHARED_ARRAY_BUFFER);
51172
0
    abuf->opaque = opaque;
51173
0
    abuf->free_func = free_func;
51174
0
    if (alloc_flag && buf)
51175
0
        memcpy(abuf->data, buf, len);
51176
0
    JS_SetOpaque(obj, abuf);
51177
0
    return obj;
51178
0
 fail:
51179
0
    JS_FreeValue(ctx, obj);
51180
0
    js_free(ctx, abuf);
51181
0
    return JS_EXCEPTION;
51182
0
}
51183
51184
static void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr)
51185
0
{
51186
0
    js_free_rt(rt, ptr);
51187
0
}
51188
51189
static JSValue js_array_buffer_constructor2(JSContext *ctx,
51190
                                            JSValueConst new_target,
51191
                                            uint64_t len, JSClassID class_id)
51192
0
{
51193
0
    return js_array_buffer_constructor3(ctx, new_target, len, class_id,
51194
0
                                        NULL, js_array_buffer_free, NULL,
51195
0
                                        TRUE);
51196
0
}
51197
51198
static JSValue js_array_buffer_constructor1(JSContext *ctx,
51199
                                            JSValueConst new_target,
51200
                                            uint64_t len)
51201
0
{
51202
0
    return js_array_buffer_constructor2(ctx, new_target, len,
51203
0
                                        JS_CLASS_ARRAY_BUFFER);
51204
0
}
51205
51206
JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
51207
                          JSFreeArrayBufferDataFunc *free_func, void *opaque,
51208
                          BOOL is_shared)
51209
0
{
51210
0
    return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len,
51211
0
                                        is_shared ? JS_CLASS_SHARED_ARRAY_BUFFER : JS_CLASS_ARRAY_BUFFER,
51212
0
                                        buf, free_func, opaque, FALSE);
51213
0
}
51214
51215
/* create a new ArrayBuffer of length 'len' and copy 'buf' to it */
51216
JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len)
51217
0
{
51218
0
    return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len,
51219
0
                                        JS_CLASS_ARRAY_BUFFER,
51220
0
                                        (uint8_t *)buf,
51221
0
                                        js_array_buffer_free, NULL,
51222
0
                                        TRUE);
51223
0
}
51224
51225
static JSValue js_array_buffer_constructor(JSContext *ctx,
51226
                                           JSValueConst new_target,
51227
                                           int argc, JSValueConst *argv)
51228
0
{
51229
0
    uint64_t len;
51230
0
    if (JS_ToIndex(ctx, &len, argv[0]))
51231
0
        return JS_EXCEPTION;
51232
0
    return js_array_buffer_constructor1(ctx, new_target, len);
51233
0
}
51234
51235
static JSValue js_shared_array_buffer_constructor(JSContext *ctx,
51236
                                                  JSValueConst new_target,
51237
                                                  int argc, JSValueConst *argv)
51238
0
{
51239
0
    uint64_t len;
51240
0
    if (JS_ToIndex(ctx, &len, argv[0]))
51241
0
        return JS_EXCEPTION;
51242
0
    return js_array_buffer_constructor2(ctx, new_target, len,
51243
0
                                        JS_CLASS_SHARED_ARRAY_BUFFER);
51244
0
}
51245
51246
/* also used for SharedArrayBuffer */
51247
static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val)
51248
0
{
51249
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
51250
0
    JSArrayBuffer *abuf = p->u.array_buffer;
51251
0
    if (abuf) {
51252
        /* The ArrayBuffer finalizer may be called before the typed
51253
           array finalizers using it, so abuf->array_list is not
51254
           necessarily empty. */
51255
        // assert(list_empty(&abuf->array_list));
51256
0
        if (abuf->shared && rt->sab_funcs.sab_free) {
51257
0
            rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data);
51258
0
        } else {
51259
0
            if (abuf->free_func)
51260
0
                abuf->free_func(rt, abuf->opaque, abuf->data);
51261
0
        }
51262
0
        js_free_rt(rt, abuf);
51263
0
    }
51264
0
}
51265
51266
static JSValue js_array_buffer_isView(JSContext *ctx,
51267
                                      JSValueConst this_val,
51268
                                      int argc, JSValueConst *argv)
51269
0
{
51270
0
    JSObject *p;
51271
0
    BOOL res;
51272
0
    res = FALSE;
51273
0
    if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
51274
0
        p = JS_VALUE_GET_OBJ(argv[0]);
51275
0
        if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
51276
0
            p->class_id <= JS_CLASS_DATAVIEW) {
51277
0
            res = TRUE;
51278
0
        }
51279
0
    }
51280
0
    return JS_NewBool(ctx, res);
51281
0
}
51282
51283
static const JSCFunctionListEntry js_array_buffer_funcs[] = {
51284
    JS_CFUNC_DEF("isView", 1, js_array_buffer_isView ),
51285
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
51286
};
51287
51288
static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx)
51289
0
{
51290
0
    return JS_ThrowTypeError(ctx, "ArrayBuffer is detached");
51291
0
}
51292
51293
static JSValue js_array_buffer_get_byteLength(JSContext *ctx,
51294
                                              JSValueConst this_val,
51295
                                              int class_id)
51296
0
{
51297
0
    JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);
51298
0
    if (!abuf)
51299
0
        return JS_EXCEPTION;
51300
    /* return 0 if detached */
51301
0
    return JS_NewUint32(ctx, abuf->byte_length);
51302
0
}
51303
51304
void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
51305
0
{
51306
0
    JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);
51307
0
    struct list_head *el;
51308
51309
0
    if (!abuf || abuf->detached)
51310
0
        return;
51311
0
    if (abuf->free_func)
51312
0
        abuf->free_func(ctx->rt, abuf->opaque, abuf->data);
51313
0
    abuf->data = NULL;
51314
0
    abuf->byte_length = 0;
51315
0
    abuf->detached = TRUE;
51316
51317
0
    list_for_each(el, &abuf->array_list) {
51318
0
        JSTypedArray *ta;
51319
0
        JSObject *p;
51320
51321
0
        ta = list_entry(el, JSTypedArray, link);
51322
0
        p = ta->obj;
51323
        /* Note: the typed array length and offset fields are not modified */
51324
0
        if (p->class_id != JS_CLASS_DATAVIEW) {
51325
0
            p->u.array.count = 0;
51326
0
            p->u.array.u.ptr = NULL;
51327
0
        }
51328
0
    }
51329
0
}
51330
51331
/* get an ArrayBuffer or SharedArrayBuffer */
51332
static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj)
51333
0
{
51334
0
    JSObject *p;
51335
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
51336
0
        goto fail;
51337
0
    p = JS_VALUE_GET_OBJ(obj);
51338
0
    if (p->class_id != JS_CLASS_ARRAY_BUFFER &&
51339
0
        p->class_id != JS_CLASS_SHARED_ARRAY_BUFFER) {
51340
0
    fail:
51341
0
        JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_ARRAY_BUFFER);
51342
0
        return NULL;
51343
0
    }
51344
0
    return p->u.array_buffer;
51345
0
}
51346
51347
/* return NULL if exception. WARNING: any JS call can detach the
51348
   buffer and render the returned pointer invalid */
51349
uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj)
51350
0
{
51351
0
    JSArrayBuffer *abuf = js_get_array_buffer(ctx, obj);
51352
0
    if (!abuf)
51353
0
        goto fail;
51354
0
    if (abuf->detached) {
51355
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51356
0
        goto fail;
51357
0
    }
51358
0
    *psize = abuf->byte_length;
51359
0
    return abuf->data;
51360
0
 fail:
51361
0
    *psize = 0;
51362
0
    return NULL;
51363
0
}
51364
51365
static JSValue js_array_buffer_slice(JSContext *ctx,
51366
                                     JSValueConst this_val,
51367
                                     int argc, JSValueConst *argv, int class_id)
51368
0
{
51369
0
    JSArrayBuffer *abuf, *new_abuf;
51370
0
    int64_t len, start, end, new_len;
51371
0
    JSValue ctor, new_obj;
51372
51373
0
    abuf = JS_GetOpaque2(ctx, this_val, class_id);
51374
0
    if (!abuf)
51375
0
        return JS_EXCEPTION;
51376
0
    if (abuf->detached)
51377
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51378
0
    len = abuf->byte_length;
51379
51380
0
    if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
51381
0
        return JS_EXCEPTION;
51382
51383
0
    end = len;
51384
0
    if (!JS_IsUndefined(argv[1])) {
51385
0
        if (JS_ToInt64Clamp(ctx, &end, argv[1], 0, len, len))
51386
0
            return JS_EXCEPTION;
51387
0
    }
51388
0
    new_len = max_int64(end - start, 0);
51389
0
    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
51390
0
    if (JS_IsException(ctor))
51391
0
        return ctor;
51392
0
    if (JS_IsUndefined(ctor)) {
51393
0
        new_obj = js_array_buffer_constructor2(ctx, JS_UNDEFINED, new_len,
51394
0
                                               class_id);
51395
0
    } else {
51396
0
        JSValue args[1];
51397
0
        args[0] = JS_NewInt64(ctx, new_len);
51398
0
        new_obj = JS_CallConstructor(ctx, ctor, 1, (JSValueConst *)args);
51399
0
        JS_FreeValue(ctx, ctor);
51400
0
        JS_FreeValue(ctx, args[0]);
51401
0
    }
51402
0
    if (JS_IsException(new_obj))
51403
0
        return new_obj;
51404
0
    new_abuf = JS_GetOpaque2(ctx, new_obj, class_id);
51405
0
    if (!new_abuf)
51406
0
        goto fail;
51407
0
    if (js_same_value(ctx, new_obj, this_val)) {
51408
0
        JS_ThrowTypeError(ctx, "cannot use identical ArrayBuffer");
51409
0
        goto fail;
51410
0
    }
51411
0
    if (new_abuf->detached) {
51412
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51413
0
        goto fail;
51414
0
    }
51415
0
    if (new_abuf->byte_length < new_len) {
51416
0
        JS_ThrowTypeError(ctx, "new ArrayBuffer is too small");
51417
0
        goto fail;
51418
0
    }
51419
    /* must test again because of side effects */
51420
0
    if (abuf->detached) {
51421
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51422
0
        goto fail;
51423
0
    }
51424
0
    memcpy(new_abuf->data, abuf->data + start, new_len);
51425
0
    return new_obj;
51426
0
 fail:
51427
0
    JS_FreeValue(ctx, new_obj);
51428
0
    return JS_EXCEPTION;
51429
0
}
51430
51431
static const JSCFunctionListEntry js_array_buffer_proto_funcs[] = {
51432
    JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_ARRAY_BUFFER ),
51433
    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_ARRAY_BUFFER ),
51434
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "ArrayBuffer", JS_PROP_CONFIGURABLE ),
51435
};
51436
51437
/* SharedArrayBuffer */
51438
51439
static const JSCFunctionListEntry js_shared_array_buffer_funcs[] = {
51440
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
51441
};
51442
51443
static const JSCFunctionListEntry js_shared_array_buffer_proto_funcs[] = {
51444
    JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),
51445
    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_SHARED_ARRAY_BUFFER ),
51446
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "SharedArrayBuffer", JS_PROP_CONFIGURABLE ),
51447
};
51448
51449
static JSObject *get_typed_array(JSContext *ctx,
51450
                                 JSValueConst this_val,
51451
                                 int is_dataview)
51452
0
{
51453
0
    JSObject *p;
51454
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
51455
0
        goto fail;
51456
0
    p = JS_VALUE_GET_OBJ(this_val);
51457
0
    if (is_dataview) {
51458
0
        if (p->class_id != JS_CLASS_DATAVIEW)
51459
0
            goto fail;
51460
0
    } else {
51461
0
        if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&
51462
0
              p->class_id <= JS_CLASS_FLOAT64_ARRAY)) {
51463
0
        fail:
51464
0
            JS_ThrowTypeError(ctx, "not a %s", is_dataview ? "DataView" : "TypedArray");
51465
0
            return NULL;
51466
0
        }
51467
0
    }
51468
0
    return p;
51469
0
}
51470
51471
/* WARNING: 'p' must be a typed array */
51472
static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p)
51473
0
{
51474
0
    JSTypedArray *ta = p->u.typed_array;
51475
0
    JSArrayBuffer *abuf = ta->buffer->u.array_buffer;
51476
    /* XXX: could simplify test by ensuring that
51477
       p->u.array.u.ptr is NULL iff it is detached */
51478
0
    return abuf->detached;
51479
0
}
51480
51481
/* WARNING: 'p' must be a typed array. Works even if the array buffer
51482
   is detached */
51483
static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p)
51484
0
{
51485
0
    JSTypedArray *ta = p->u.typed_array;
51486
0
    int size_log2 = typed_array_size_log2(p->class_id);
51487
0
    return ta->length >> size_log2;
51488
0
}
51489
51490
static int validate_typed_array(JSContext *ctx, JSValueConst this_val)
51491
0
{
51492
0
    JSObject *p;
51493
0
    p = get_typed_array(ctx, this_val, 0);
51494
0
    if (!p)
51495
0
        return -1;
51496
0
    if (typed_array_is_detached(ctx, p)) {
51497
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51498
0
        return -1;
51499
0
    }
51500
0
    return 0;
51501
0
}
51502
51503
static JSValue js_typed_array_get_length(JSContext *ctx,
51504
                                         JSValueConst this_val)
51505
0
{
51506
0
    JSObject *p;
51507
0
    p = get_typed_array(ctx, this_val, 0);
51508
0
    if (!p)
51509
0
        return JS_EXCEPTION;
51510
0
    return JS_NewInt32(ctx, p->u.array.count);
51511
0
}
51512
51513
static JSValue js_typed_array_get_buffer(JSContext *ctx,
51514
                                         JSValueConst this_val, int is_dataview)
51515
0
{
51516
0
    JSObject *p;
51517
0
    JSTypedArray *ta;
51518
0
    p = get_typed_array(ctx, this_val, is_dataview);
51519
0
    if (!p)
51520
0
        return JS_EXCEPTION;
51521
0
    ta = p->u.typed_array;
51522
0
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
51523
0
}
51524
51525
static JSValue js_typed_array_get_byteLength(JSContext *ctx,
51526
                                             JSValueConst this_val,
51527
                                             int is_dataview)
51528
0
{
51529
0
    JSObject *p;
51530
0
    JSTypedArray *ta;
51531
0
    p = get_typed_array(ctx, this_val, is_dataview);
51532
0
    if (!p)
51533
0
        return JS_EXCEPTION;
51534
0
    if (typed_array_is_detached(ctx, p)) {
51535
0
        if (is_dataview) {
51536
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51537
0
        } else {
51538
0
            return JS_NewInt32(ctx, 0);
51539
0
        }
51540
0
    }
51541
0
    ta = p->u.typed_array;
51542
0
    return JS_NewInt32(ctx, ta->length);
51543
0
}
51544
51545
static JSValue js_typed_array_get_byteOffset(JSContext *ctx,
51546
                                             JSValueConst this_val,
51547
                                             int is_dataview)
51548
0
{
51549
0
    JSObject *p;
51550
0
    JSTypedArray *ta;
51551
0
    p = get_typed_array(ctx, this_val, is_dataview);
51552
0
    if (!p)
51553
0
        return JS_EXCEPTION;
51554
0
    if (typed_array_is_detached(ctx, p)) {
51555
0
        if (is_dataview) {
51556
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51557
0
        } else {
51558
0
            return JS_NewInt32(ctx, 0);
51559
0
        }
51560
0
    }
51561
0
    ta = p->u.typed_array;
51562
0
    return JS_NewInt32(ctx, ta->offset);
51563
0
}
51564
51565
/* Return the buffer associated to the typed array or an exception if
51566
   it is not a typed array or if the buffer is detached. pbyte_offset,
51567
   pbyte_length or pbytes_per_element can be NULL. */
51568
JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
51569
                               size_t *pbyte_offset,
51570
                               size_t *pbyte_length,
51571
                               size_t *pbytes_per_element)
51572
0
{
51573
0
    JSObject *p;
51574
0
    JSTypedArray *ta;
51575
0
    p = get_typed_array(ctx, obj, FALSE);
51576
0
    if (!p)
51577
0
        return JS_EXCEPTION;
51578
0
    if (typed_array_is_detached(ctx, p))
51579
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51580
0
    ta = p->u.typed_array;
51581
0
    if (pbyte_offset)
51582
0
        *pbyte_offset = ta->offset;
51583
0
    if (pbyte_length)
51584
0
        *pbyte_length = ta->length;
51585
0
    if (pbytes_per_element) {
51586
0
        *pbytes_per_element = 1 << typed_array_size_log2(p->class_id);
51587
0
    }
51588
0
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
51589
0
}
51590
                               
51591
static JSValue js_typed_array_get_toStringTag(JSContext *ctx,
51592
                                              JSValueConst this_val)
51593
0
{
51594
0
    JSObject *p;
51595
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
51596
0
        return JS_UNDEFINED;
51597
0
    p = JS_VALUE_GET_OBJ(this_val);
51598
0
    if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&
51599
0
          p->class_id <= JS_CLASS_FLOAT64_ARRAY))
51600
0
        return JS_UNDEFINED;
51601
0
    return JS_AtomToString(ctx, ctx->rt->class_array[p->class_id].class_name);
51602
0
}
51603
51604
static JSValue js_typed_array_set_internal(JSContext *ctx,
51605
                                           JSValueConst dst,
51606
                                           JSValueConst src,
51607
                                           JSValueConst off)
51608
0
{
51609
0
    JSObject *p;
51610
0
    JSObject *src_p;
51611
0
    uint32_t i;
51612
0
    int64_t src_len, offset;
51613
0
    JSValue val, src_obj = JS_UNDEFINED;
51614
51615
0
    p = get_typed_array(ctx, dst, 0);
51616
0
    if (!p)
51617
0
        goto fail;
51618
0
    if (JS_ToInt64Sat(ctx, &offset, off))
51619
0
        goto fail;
51620
0
    if (offset < 0)
51621
0
        goto range_error;
51622
0
    if (typed_array_is_detached(ctx, p)) {
51623
0
    detached:
51624
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51625
0
        goto fail;
51626
0
    }
51627
0
    src_obj = JS_ToObject(ctx, src);
51628
0
    if (JS_IsException(src_obj))
51629
0
        goto fail;
51630
0
    src_p = JS_VALUE_GET_OBJ(src_obj);
51631
0
    if (src_p->class_id >= JS_CLASS_UINT8C_ARRAY &&
51632
0
        src_p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
51633
0
        JSTypedArray *dest_ta = p->u.typed_array;
51634
0
        JSArrayBuffer *dest_abuf = dest_ta->buffer->u.array_buffer;
51635
0
        JSTypedArray *src_ta = src_p->u.typed_array;
51636
0
        JSArrayBuffer *src_abuf = src_ta->buffer->u.array_buffer;
51637
0
        int shift = typed_array_size_log2(p->class_id);
51638
51639
0
        if (src_abuf->detached)
51640
0
            goto detached;
51641
51642
0
        src_len = src_p->u.array.count;
51643
0
        if (offset > (int64_t)(p->u.array.count - src_len))
51644
0
            goto range_error;
51645
51646
        /* copying between typed objects */
51647
0
        if (src_p->class_id == p->class_id) {
51648
            /* same type, use memmove */
51649
0
            memmove(dest_abuf->data + dest_ta->offset + (offset << shift),
51650
0
                    src_abuf->data + src_ta->offset, src_len << shift);
51651
0
            goto done;
51652
0
        }
51653
0
        if (dest_abuf->data == src_abuf->data) {
51654
            /* copying between the same buffer using different types of mappings
51655
               would require a temporary buffer */
51656
0
        }
51657
        /* otherwise, default behavior is slow but correct */
51658
0
    } else {
51659
0
        if (js_get_length64(ctx, &src_len, src_obj))
51660
0
            goto fail;
51661
0
        if (offset > (int64_t)(p->u.array.count - src_len)) {
51662
0
        range_error:
51663
0
            JS_ThrowRangeError(ctx, "invalid array length");
51664
0
            goto fail;
51665
0
        }
51666
0
    }
51667
0
    for(i = 0; i < src_len; i++) {
51668
0
        val = JS_GetPropertyUint32(ctx, src_obj, i);
51669
0
        if (JS_IsException(val))
51670
0
            goto fail;
51671
0
        if (JS_SetPropertyUint32(ctx, dst, offset + i, val) < 0)
51672
0
            goto fail;
51673
0
    }
51674
0
done:
51675
0
    JS_FreeValue(ctx, src_obj);
51676
0
    return JS_UNDEFINED;
51677
0
fail:
51678
0
    JS_FreeValue(ctx, src_obj);
51679
0
    return JS_EXCEPTION;
51680
0
}
51681
51682
static JSValue js_typed_array_set(JSContext *ctx,
51683
                                  JSValueConst this_val,
51684
                                  int argc, JSValueConst *argv)
51685
0
{
51686
0
    JSValueConst offset = JS_UNDEFINED;
51687
0
    if (argc > 1) {
51688
0
        offset = argv[1];
51689
0
    }
51690
0
    return js_typed_array_set_internal(ctx, this_val, argv[0], offset);
51691
0
}
51692
51693
static JSValue js_create_typed_array_iterator(JSContext *ctx, JSValueConst this_val,
51694
                                              int argc, JSValueConst *argv, int magic)
51695
0
{
51696
0
    if (validate_typed_array(ctx, this_val))
51697
0
        return JS_EXCEPTION;
51698
0
    return js_create_array_iterator(ctx, this_val, argc, argv, magic);
51699
0
}
51700
51701
/* return < 0 if exception */
51702
static int js_typed_array_get_length_internal(JSContext *ctx,
51703
                                              JSValueConst obj)
51704
0
{
51705
0
    JSObject *p;
51706
0
    p = get_typed_array(ctx, obj, 0);
51707
0
    if (!p)
51708
0
        return -1;
51709
0
    if (typed_array_is_detached(ctx, p)) {
51710
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51711
0
        return -1;
51712
0
    }
51713
0
    return p->u.array.count;
51714
0
}
51715
51716
#if 0
51717
/* validate a typed array and return its length */
51718
static JSValue js_typed_array___getLength(JSContext *ctx,
51719
                                          JSValueConst this_val,
51720
                                          int argc, JSValueConst *argv)
51721
{
51722
    BOOL ignore_detached = JS_ToBool(ctx, argv[1]);
51723
51724
    if (ignore_detached) {
51725
        return js_typed_array_get_length(ctx, argv[0]);
51726
    } else {
51727
        int len;
51728
        len = js_typed_array_get_length_internal(ctx, argv[0]);
51729
        if (len < 0)
51730
            return JS_EXCEPTION;
51731
        return JS_NewInt32(ctx, len);
51732
    }
51733
}
51734
#endif
51735
51736
static JSValue js_typed_array_create(JSContext *ctx, JSValueConst ctor,
51737
                                     int argc, JSValueConst *argv)
51738
0
{
51739
0
    JSValue ret;
51740
0
    int new_len;
51741
0
    int64_t len;
51742
51743
0
    ret = JS_CallConstructor(ctx, ctor, argc, argv);
51744
0
    if (JS_IsException(ret))
51745
0
        return ret;
51746
    /* validate the typed array */
51747
0
    new_len = js_typed_array_get_length_internal(ctx, ret);
51748
0
    if (new_len < 0)
51749
0
        goto fail;
51750
0
    if (argc == 1) {
51751
        /* ensure that it is large enough */
51752
0
        if (JS_ToLengthFree(ctx, &len, JS_DupValue(ctx, argv[0])))
51753
0
            goto fail;
51754
0
        if (new_len < len) {
51755
0
            JS_ThrowTypeError(ctx, "TypedArray length is too small");
51756
0
        fail:
51757
0
            JS_FreeValue(ctx, ret);
51758
0
            return JS_EXCEPTION;
51759
0
        }
51760
0
    }
51761
0
    return ret;
51762
0
}
51763
51764
#if 0
51765
static JSValue js_typed_array___create(JSContext *ctx,
51766
                                       JSValueConst this_val,
51767
                                       int argc, JSValueConst *argv)
51768
{
51769
    return js_typed_array_create(ctx, argv[0], max_int(argc - 1, 0), argv + 1);
51770
}
51771
#endif
51772
51773
static JSValue js_typed_array___speciesCreate(JSContext *ctx,
51774
                                              JSValueConst this_val,
51775
                                              int argc, JSValueConst *argv)
51776
0
{
51777
0
    JSValueConst obj;
51778
0
    JSObject *p;
51779
0
    JSValue ctor, ret;
51780
0
    int argc1;
51781
51782
0
    obj = argv[0];
51783
0
    p = get_typed_array(ctx, obj, 0);
51784
0
    if (!p)
51785
0
        return JS_EXCEPTION;
51786
0
    ctor = JS_SpeciesConstructor(ctx, obj, JS_UNDEFINED);
51787
0
    if (JS_IsException(ctor))
51788
0
        return ctor;
51789
0
    argc1 = max_int(argc - 1, 0);
51790
0
    if (JS_IsUndefined(ctor)) {
51791
0
        ret = js_typed_array_constructor(ctx, JS_UNDEFINED, argc1, argv + 1,
51792
0
                                         p->class_id);
51793
0
    } else {
51794
0
        ret = js_typed_array_create(ctx, ctor, argc1, argv + 1);
51795
0
        JS_FreeValue(ctx, ctor);
51796
0
    }
51797
0
    return ret;
51798
0
}
51799
51800
static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val,
51801
                                   int argc, JSValueConst *argv)
51802
0
{
51803
    // from(items, mapfn = void 0, this_arg = void 0)
51804
0
    JSValueConst items = argv[0], mapfn, this_arg;
51805
0
    JSValueConst args[2];
51806
0
    JSValue stack[2];
51807
0
    JSValue iter, arr, r, v, v2;
51808
0
    int64_t k, len;
51809
0
    int done, mapping;
51810
51811
0
    mapping = FALSE;
51812
0
    mapfn = JS_UNDEFINED;
51813
0
    this_arg = JS_UNDEFINED;
51814
0
    r = JS_UNDEFINED;
51815
0
    arr = JS_UNDEFINED;
51816
0
    stack[0] = JS_UNDEFINED;
51817
0
    stack[1] = JS_UNDEFINED;
51818
51819
0
    if (argc > 1) {
51820
0
        mapfn = argv[1];
51821
0
        if (!JS_IsUndefined(mapfn)) {
51822
0
            if (check_function(ctx, mapfn))
51823
0
                goto exception;
51824
0
            mapping = 1;
51825
0
            if (argc > 2)
51826
0
                this_arg = argv[2];
51827
0
        }
51828
0
    }
51829
0
    iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
51830
0
    if (JS_IsException(iter))
51831
0
        goto exception;
51832
0
    if (!JS_IsUndefined(iter)) {
51833
0
        JS_FreeValue(ctx, iter);
51834
0
        arr = JS_NewArray(ctx);
51835
0
        if (JS_IsException(arr))
51836
0
            goto exception;
51837
0
        stack[0] = JS_DupValue(ctx, items);
51838
0
        if (js_for_of_start(ctx, &stack[1], FALSE))
51839
0
            goto exception;
51840
0
        for (k = 0;; k++) {
51841
0
            v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done);
51842
0
            if (JS_IsException(v))
51843
0
                goto exception_close;
51844
0
            if (done)
51845
0
                break;
51846
0
            if (JS_DefinePropertyValueInt64(ctx, arr, k, v, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
51847
0
                goto exception_close;
51848
0
        }
51849
0
    } else {
51850
0
        arr = JS_ToObject(ctx, items);
51851
0
        if (JS_IsException(arr))
51852
0
            goto exception;
51853
0
    }
51854
0
    if (js_get_length64(ctx, &len, arr) < 0)
51855
0
        goto exception;
51856
0
    v = JS_NewInt64(ctx, len);
51857
0
    args[0] = v;
51858
0
    r = js_typed_array_create(ctx, this_val, 1, args);
51859
0
    JS_FreeValue(ctx, v);
51860
0
    if (JS_IsException(r))
51861
0
        goto exception;
51862
0
    for(k = 0; k < len; k++) {
51863
0
        v = JS_GetPropertyInt64(ctx, arr, k);
51864
0
        if (JS_IsException(v))
51865
0
            goto exception;
51866
0
        if (mapping) {
51867
0
            args[0] = v;
51868
0
            args[1] = JS_NewInt32(ctx, k);
51869
0
            v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
51870
0
            JS_FreeValue(ctx, v);
51871
0
            v = v2;
51872
0
            if (JS_IsException(v))
51873
0
                goto exception;
51874
0
        }
51875
0
        if (JS_SetPropertyInt64(ctx, r, k, v) < 0)
51876
0
            goto exception;
51877
0
    }
51878
0
    goto done;
51879
51880
0
 exception_close:
51881
0
    if (!JS_IsUndefined(stack[0]))
51882
0
        JS_IteratorClose(ctx, stack[0], TRUE);
51883
0
 exception:
51884
0
    JS_FreeValue(ctx, r);
51885
0
    r = JS_EXCEPTION;
51886
0
 done:
51887
0
    JS_FreeValue(ctx, arr);
51888
0
    JS_FreeValue(ctx, stack[0]);
51889
0
    JS_FreeValue(ctx, stack[1]);
51890
0
    return r;
51891
0
}
51892
51893
static JSValue js_typed_array_of(JSContext *ctx, JSValueConst this_val,
51894
                                 int argc, JSValueConst *argv)
51895
0
{
51896
0
    JSValue obj;
51897
0
    JSValueConst args[1];
51898
0
    int i;
51899
51900
0
    args[0] = JS_NewInt32(ctx, argc);
51901
0
    obj = js_typed_array_create(ctx, this_val, 1, args);
51902
0
    if (JS_IsException(obj))
51903
0
        return obj;
51904
51905
0
    for(i = 0; i < argc; i++) {
51906
0
        if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0) {
51907
0
            JS_FreeValue(ctx, obj);
51908
0
            return JS_EXCEPTION;
51909
0
        }
51910
0
    }
51911
0
    return obj;
51912
0
}
51913
51914
static JSValue js_typed_array_copyWithin(JSContext *ctx, JSValueConst this_val,
51915
                                         int argc, JSValueConst *argv)
51916
0
{
51917
0
    JSObject *p;
51918
0
    int len, to, from, final, count, shift;
51919
51920
0
    len = js_typed_array_get_length_internal(ctx, this_val);
51921
0
    if (len < 0)
51922
0
        return JS_EXCEPTION;
51923
51924
0
    if (JS_ToInt32Clamp(ctx, &to, argv[0], 0, len, len))
51925
0
        return JS_EXCEPTION;
51926
51927
0
    if (JS_ToInt32Clamp(ctx, &from, argv[1], 0, len, len))
51928
0
        return JS_EXCEPTION;
51929
51930
0
    final = len;
51931
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
51932
0
        if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
51933
0
            return JS_EXCEPTION;
51934
0
    }
51935
51936
0
    count = min_int(final - from, len - to);
51937
0
    if (count > 0) {
51938
0
        p = JS_VALUE_GET_OBJ(this_val);
51939
0
        if (typed_array_is_detached(ctx, p))
51940
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
51941
0
        shift = typed_array_size_log2(p->class_id);
51942
0
        memmove(p->u.array.u.uint8_ptr + (to << shift),
51943
0
                p->u.array.u.uint8_ptr + (from << shift),
51944
0
                count << shift);
51945
0
    }
51946
0
    return JS_DupValue(ctx, this_val);
51947
0
}
51948
51949
static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val,
51950
                                   int argc, JSValueConst *argv)
51951
0
{
51952
0
    JSObject *p;
51953
0
    int len, k, final, shift;
51954
0
    uint64_t v64;
51955
51956
0
    len = js_typed_array_get_length_internal(ctx, this_val);
51957
0
    if (len < 0)
51958
0
        return JS_EXCEPTION;
51959
0
    p = JS_VALUE_GET_OBJ(this_val);
51960
51961
0
    if (p->class_id == JS_CLASS_UINT8C_ARRAY) {
51962
0
        int32_t v;
51963
0
        if (JS_ToUint8ClampFree(ctx, &v, JS_DupValue(ctx, argv[0])))
51964
0
            return JS_EXCEPTION;
51965
0
        v64 = v;
51966
0
    } else if (p->class_id <= JS_CLASS_UINT32_ARRAY) {
51967
0
        uint32_t v;
51968
0
        if (JS_ToUint32(ctx, &v, argv[0]))
51969
0
            return JS_EXCEPTION;
51970
0
        v64 = v;
51971
0
    } else
51972
0
#ifdef CONFIG_BIGNUM
51973
0
    if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
51974
0
        if (JS_ToBigInt64(ctx, (int64_t *)&v64, argv[0]))
51975
0
            return JS_EXCEPTION;
51976
0
    } else
51977
0
#endif
51978
0
    {
51979
0
        double d;
51980
0
        if (JS_ToFloat64(ctx, &d, argv[0]))
51981
0
            return JS_EXCEPTION;
51982
0
        if (p->class_id == JS_CLASS_FLOAT32_ARRAY) {
51983
0
            union {
51984
0
                float f;
51985
0
                uint32_t u32;
51986
0
            } u;
51987
0
            u.f = d;
51988
0
            v64 = u.u32;
51989
0
        } else {
51990
0
            JSFloat64Union u;
51991
0
            u.d = d;
51992
0
            v64 = u.u64;
51993
0
        }
51994
0
    }
51995
51996
0
    k = 0;
51997
0
    if (argc > 1) {
51998
0
        if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
51999
0
            return JS_EXCEPTION;
52000
0
    }
52001
52002
0
    final = len;
52003
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
52004
0
        if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
52005
0
            return JS_EXCEPTION;
52006
0
    }
52007
52008
0
    if (typed_array_is_detached(ctx, p))
52009
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
52010
    
52011
0
    shift = typed_array_size_log2(p->class_id);
52012
0
    switch(shift) {
52013
0
    case 0:
52014
0
        if (k < final) {
52015
0
            memset(p->u.array.u.uint8_ptr + k, v64, final - k);
52016
0
        }
52017
0
        break;
52018
0
    case 1:
52019
0
        for(; k < final; k++) {
52020
0
            p->u.array.u.uint16_ptr[k] = v64;
52021
0
        }
52022
0
        break;
52023
0
    case 2:
52024
0
        for(; k < final; k++) {
52025
0
            p->u.array.u.uint32_ptr[k] = v64;
52026
0
        }
52027
0
        break;
52028
0
    case 3:
52029
0
        for(; k < final; k++) {
52030
0
            p->u.array.u.uint64_ptr[k] = v64;
52031
0
        }
52032
0
        break;
52033
0
    default:
52034
0
        abort();
52035
0
    }
52036
0
    return JS_DupValue(ctx, this_val);
52037
0
}
52038
52039
static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
52040
                                   int argc, JSValueConst *argv, int findIndex)
52041
0
{
52042
0
    JSValueConst func, this_arg;
52043
0
    JSValueConst args[3];
52044
0
    JSValue val, index_val, res;
52045
0
    int len, k;
52046
52047
0
    val = JS_UNDEFINED;
52048
0
    len = js_typed_array_get_length_internal(ctx, this_val);
52049
0
    if (len < 0)
52050
0
        goto exception;
52051
52052
0
    func = argv[0];
52053
0
    if (check_function(ctx, func))
52054
0
        goto exception;
52055
52056
0
    this_arg = JS_UNDEFINED;
52057
0
    if (argc > 1)
52058
0
        this_arg = argv[1];
52059
52060
0
    for(k = 0; k < len; k++) {
52061
0
        index_val = JS_NewInt32(ctx, k);
52062
0
        val = JS_GetPropertyValue(ctx, this_val, index_val);
52063
0
        if (JS_IsException(val))
52064
0
            goto exception;
52065
0
        args[0] = val;
52066
0
        args[1] = index_val;
52067
0
        args[2] = this_val;
52068
0
        res = JS_Call(ctx, func, this_arg, 3, args);
52069
0
        if (JS_IsException(res))
52070
0
            goto exception;
52071
0
        if (JS_ToBoolFree(ctx, res)) {
52072
0
            if (findIndex) {
52073
0
                JS_FreeValue(ctx, val);
52074
0
                return index_val;
52075
0
            } else {
52076
0
                return val;
52077
0
            }
52078
0
        }
52079
0
        JS_FreeValue(ctx, val);
52080
0
    }
52081
0
    if (findIndex)
52082
0
        return JS_NewInt32(ctx, -1);
52083
0
    else
52084
0
        return JS_UNDEFINED;
52085
52086
0
exception:
52087
0
    JS_FreeValue(ctx, val);
52088
0
    return JS_EXCEPTION;
52089
0
}
52090
52091
#define special_indexOf 0
52092
0
#define special_lastIndexOf 1
52093
0
#define special_includes -1
52094
52095
static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
52096
                                      int argc, JSValueConst *argv, int special)
52097
0
{
52098
0
    JSObject *p;
52099
0
    int len, tag, is_int, is_bigint, k, stop, inc, res = -1;
52100
0
    int64_t v64;
52101
0
    double d;
52102
0
    float f;
52103
52104
0
    len = js_typed_array_get_length_internal(ctx, this_val);
52105
0
    if (len < 0)
52106
0
        goto exception;
52107
0
    if (len == 0)
52108
0
        goto done;
52109
52110
0
    if (special == special_lastIndexOf) {
52111
0
        k = len - 1;
52112
0
        if (argc > 1) {
52113
0
            if (JS_ToFloat64(ctx, &d, argv[1]))
52114
0
                goto exception;
52115
0
            if (isnan(d)) {
52116
0
                k = 0;
52117
0
            } else {
52118
0
                if (d >= 0) {
52119
0
                    if (d < k) {
52120
0
                        k = d;
52121
0
                    }
52122
0
                } else {
52123
0
                    d += len;
52124
0
                    if (d < 0)
52125
0
                        goto done;
52126
0
                    k = d;
52127
0
                }
52128
0
            }
52129
0
        }
52130
0
        stop = -1;
52131
0
        inc = -1;
52132
0
    } else {
52133
0
        k = 0;
52134
0
        if (argc > 1) {
52135
0
            if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
52136
0
                goto exception;
52137
0
        }
52138
0
        stop = len;
52139
0
        inc = 1;
52140
0
    }
52141
52142
0
    p = JS_VALUE_GET_OBJ(this_val);
52143
    /* if the array was detached, no need to go further (but no
52144
       exception is raised) */
52145
0
    if (typed_array_is_detached(ctx, p)) {
52146
        /* "includes" scans all the properties, so "undefined" can match */
52147
0
        if (special == special_includes && JS_IsUndefined(argv[0]) && len > 0)
52148
0
            res = 0;
52149
0
        goto done;
52150
0
    }
52151
    
52152
0
    is_bigint = 0;
52153
0
    is_int = 0; /* avoid warning */
52154
0
    v64 = 0; /* avoid warning */
52155
0
    tag = JS_VALUE_GET_NORM_TAG(argv[0]);
52156
0
    if (tag == JS_TAG_INT) {
52157
0
        is_int = 1;
52158
0
        v64 = JS_VALUE_GET_INT(argv[0]);
52159
0
        d = v64;
52160
0
    } else
52161
0
    if (tag == JS_TAG_FLOAT64) {
52162
0
        d = JS_VALUE_GET_FLOAT64(argv[0]);
52163
0
        v64 = d;
52164
0
        is_int = (v64 == d);
52165
0
    } else
52166
0
#ifdef CONFIG_BIGNUM
52167
0
    if (tag == JS_TAG_BIG_INT) {
52168
0
        JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]);
52169
        
52170
0
        if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {
52171
0
            if (bf_get_int64(&v64, &p1->num, 0) != 0)
52172
0
                goto done;
52173
0
        } else if (p->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
52174
0
            if (bf_get_uint64((uint64_t *)&v64, &p1->num) != 0)
52175
0
                goto done;
52176
0
        } else {
52177
0
            goto done;
52178
0
        }
52179
0
        d = 0;
52180
0
        is_bigint = 1;
52181
0
    } else
52182
0
#endif
52183
0
    {
52184
0
        goto done;
52185
0
    }
52186
52187
0
    switch (p->class_id) {
52188
0
    case JS_CLASS_INT8_ARRAY:
52189
0
        if (is_int && (int8_t)v64 == v64)
52190
0
            goto scan8;
52191
0
        break;
52192
0
    case JS_CLASS_UINT8C_ARRAY:
52193
0
    case JS_CLASS_UINT8_ARRAY:
52194
0
        if (is_int && (uint8_t)v64 == v64) {
52195
0
            const uint8_t *pv, *pp;
52196
0
            uint16_t v;
52197
0
        scan8:
52198
0
            pv = p->u.array.u.uint8_ptr;
52199
0
            v = v64;
52200
0
            if (inc > 0) {
52201
0
                pp = memchr(pv + k, v, len - k);
52202
0
                if (pp)
52203
0
                    res = pp - pv;
52204
0
            } else {
52205
0
                for (; k != stop; k += inc) {
52206
0
                    if (pv[k] == v) {
52207
0
                        res = k;
52208
0
                        break;
52209
0
                    }
52210
0
                }
52211
0
            }
52212
0
        }
52213
0
        break;
52214
0
    case JS_CLASS_INT16_ARRAY:
52215
0
        if (is_int && (int16_t)v64 == v64)
52216
0
            goto scan16;
52217
0
        break;
52218
0
    case JS_CLASS_UINT16_ARRAY:
52219
0
        if (is_int && (uint16_t)v64 == v64) {
52220
0
            const uint16_t *pv;
52221
0
            uint16_t v;
52222
0
        scan16:
52223
0
            pv = p->u.array.u.uint16_ptr;
52224
0
            v = v64;
52225
0
            for (; k != stop; k += inc) {
52226
0
                if (pv[k] == v) {
52227
0
                    res = k;
52228
0
                    break;
52229
0
                }
52230
0
            }
52231
0
        }
52232
0
        break;
52233
0
    case JS_CLASS_INT32_ARRAY:
52234
0
        if (is_int && (int32_t)v64 == v64)
52235
0
            goto scan32;
52236
0
        break;
52237
0
    case JS_CLASS_UINT32_ARRAY:
52238
0
        if (is_int && (uint32_t)v64 == v64) {
52239
0
            const uint32_t *pv;
52240
0
            uint32_t v;
52241
0
        scan32:
52242
0
            pv = p->u.array.u.uint32_ptr;
52243
0
            v = v64;
52244
0
            for (; k != stop; k += inc) {
52245
0
                if (pv[k] == v) {
52246
0
                    res = k;
52247
0
                    break;
52248
0
                }
52249
0
            }
52250
0
        }
52251
0
        break;
52252
0
    case JS_CLASS_FLOAT32_ARRAY:
52253
0
        if (is_bigint)
52254
0
            break;
52255
0
        if (isnan(d)) {
52256
0
            const float *pv = p->u.array.u.float_ptr;
52257
            /* special case: indexOf returns -1, includes finds NaN */
52258
0
            if (special != special_includes)
52259
0
                goto done;
52260
0
            for (; k != stop; k += inc) {
52261
0
                if (isnan(pv[k])) {
52262
0
                    res = k;
52263
0
                    break;
52264
0
                }
52265
0
            }
52266
0
        } else if ((f = (float)d) == d) {
52267
0
            const float *pv = p->u.array.u.float_ptr;
52268
0
            for (; k != stop; k += inc) {
52269
0
                if (pv[k] == f) {
52270
0
                    res = k;
52271
0
                    break;
52272
0
                }
52273
0
            }
52274
0
        }
52275
0
        break;
52276
0
    case JS_CLASS_FLOAT64_ARRAY:
52277
0
        if (is_bigint)
52278
0
            break;
52279
0
        if (isnan(d)) {
52280
0
            const double *pv = p->u.array.u.double_ptr;
52281
            /* special case: indexOf returns -1, includes finds NaN */
52282
0
            if (special != special_includes)
52283
0
                goto done;
52284
0
            for (; k != stop; k += inc) {
52285
0
                if (isnan(pv[k])) {
52286
0
                    res = k;
52287
0
                    break;
52288
0
                }
52289
0
            }
52290
0
        } else {
52291
0
            const double *pv = p->u.array.u.double_ptr;
52292
0
            for (; k != stop; k += inc) {
52293
0
                if (pv[k] == d) {
52294
0
                    res = k;
52295
0
                    break;
52296
0
                }
52297
0
            }
52298
0
        }
52299
0
        break;
52300
0
#ifdef CONFIG_BIGNUM
52301
0
    case JS_CLASS_BIG_INT64_ARRAY:
52302
0
        if (is_bigint || (is_math_mode(ctx) && is_int &&
52303
0
                          v64 >= -MAX_SAFE_INTEGER &&
52304
0
                          v64 <= MAX_SAFE_INTEGER)) {
52305
0
            goto scan64;
52306
0
        }
52307
0
        break;
52308
0
    case JS_CLASS_BIG_UINT64_ARRAY:
52309
0
        if (is_bigint || (is_math_mode(ctx) && is_int &&
52310
0
                          v64 >= 0 && v64 <= MAX_SAFE_INTEGER)) {
52311
0
            const uint64_t *pv;
52312
0
            uint64_t v;
52313
0
        scan64:
52314
0
            pv = p->u.array.u.uint64_ptr;
52315
0
            v = v64;
52316
0
            for (; k != stop; k += inc) {
52317
0
                if (pv[k] == v) {
52318
0
                    res = k;
52319
0
                    break;
52320
0
                }
52321
0
            }
52322
0
        }
52323
0
        break;
52324
0
#endif
52325
0
    }
52326
52327
0
done:
52328
0
    if (special == special_includes)
52329
0
        return JS_NewBool(ctx, res >= 0);
52330
0
    else
52331
0
        return JS_NewInt32(ctx, res);
52332
52333
0
exception:
52334
0
    return JS_EXCEPTION;
52335
0
}
52336
52337
static JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val,
52338
                                   int argc, JSValueConst *argv, int toLocaleString)
52339
0
{
52340
0
    JSValue sep = JS_UNDEFINED, el;
52341
0
    StringBuffer b_s, *b = &b_s;
52342
0
    JSString *p = NULL;
52343
0
    int i, n;
52344
0
    int c;
52345
52346
0
    n = js_typed_array_get_length_internal(ctx, this_val);
52347
0
    if (n < 0)
52348
0
        goto exception;
52349
52350
0
    c = ',';    /* default separator */
52351
0
    if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
52352
0
        sep = JS_ToString(ctx, argv[0]);
52353
0
        if (JS_IsException(sep))
52354
0
            goto exception;
52355
0
        p = JS_VALUE_GET_STRING(sep);
52356
0
        if (p->len == 1 && !p->is_wide_char)
52357
0
            c = p->u.str8[0];
52358
0
        else
52359
0
            c = -1;
52360
0
    }
52361
0
    string_buffer_init(ctx, b, 0);
52362
52363
    /* XXX: optimize with direct access */
52364
0
    for(i = 0; i < n; i++) {
52365
0
        if (i > 0) {
52366
0
            if (c >= 0) {
52367
0
                if (string_buffer_putc8(b, c))
52368
0
                    goto fail;
52369
0
            } else {
52370
0
                if (string_buffer_concat(b, p, 0, p->len))
52371
0
                    goto fail;
52372
0
            }
52373
0
        }
52374
0
        el = JS_GetPropertyUint32(ctx, this_val, i);
52375
        /* Can return undefined for example if the typed array is detached */
52376
0
        if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
52377
0
            if (JS_IsException(el))
52378
0
                goto fail;
52379
0
            if (toLocaleString) {
52380
0
                el = JS_ToLocaleStringFree(ctx, el);
52381
0
            }
52382
0
            if (string_buffer_concat_value_free(b, el))
52383
0
                goto fail;
52384
0
        }
52385
0
    }
52386
0
    JS_FreeValue(ctx, sep);
52387
0
    return string_buffer_end(b);
52388
52389
0
fail:
52390
0
    string_buffer_free(b);
52391
0
    JS_FreeValue(ctx, sep);
52392
0
exception:
52393
0
    return JS_EXCEPTION;
52394
0
}
52395
52396
static JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val,
52397
                                      int argc, JSValueConst *argv)
52398
0
{
52399
0
    JSObject *p;
52400
0
    int len;
52401
52402
0
    len = js_typed_array_get_length_internal(ctx, this_val);
52403
0
    if (len < 0)
52404
0
        return JS_EXCEPTION;
52405
0
    if (len > 0) {
52406
0
        p = JS_VALUE_GET_OBJ(this_val);
52407
0
        switch (typed_array_size_log2(p->class_id)) {
52408
0
        case 0:
52409
0
            {
52410
0
                uint8_t *p1 = p->u.array.u.uint8_ptr;
52411
0
                uint8_t *p2 = p1 + len - 1;
52412
0
                while (p1 < p2) {
52413
0
                    uint8_t v = *p1;
52414
0
                    *p1++ = *p2;
52415
0
                    *p2-- = v;
52416
0
                }
52417
0
            }
52418
0
            break;
52419
0
        case 1:
52420
0
            {
52421
0
                uint16_t *p1 = p->u.array.u.uint16_ptr;
52422
0
                uint16_t *p2 = p1 + len - 1;
52423
0
                while (p1 < p2) {
52424
0
                    uint16_t v = *p1;
52425
0
                    *p1++ = *p2;
52426
0
                    *p2-- = v;
52427
0
                }
52428
0
            }
52429
0
            break;
52430
0
        case 2:
52431
0
            {
52432
0
                uint32_t *p1 = p->u.array.u.uint32_ptr;
52433
0
                uint32_t *p2 = p1 + len - 1;
52434
0
                while (p1 < p2) {
52435
0
                    uint32_t v = *p1;
52436
0
                    *p1++ = *p2;
52437
0
                    *p2-- = v;
52438
0
                }
52439
0
            }
52440
0
            break;
52441
0
        case 3:
52442
0
            {
52443
0
                uint64_t *p1 = p->u.array.u.uint64_ptr;
52444
0
                uint64_t *p2 = p1 + len - 1;
52445
0
                while (p1 < p2) {
52446
0
                    uint64_t v = *p1;
52447
0
                    *p1++ = *p2;
52448
0
                    *p2-- = v;
52449
0
                }
52450
0
            }
52451
0
            break;
52452
0
        default:
52453
0
            abort();
52454
0
        }
52455
0
    }
52456
0
    return JS_DupValue(ctx, this_val);
52457
0
}
52458
52459
static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val,
52460
                                    int argc, JSValueConst *argv)
52461
0
{
52462
0
    JSValueConst args[2];
52463
0
    JSValue arr, val;
52464
0
    JSObject *p, *p1;
52465
0
    int n, len, start, final, count, shift;
52466
52467
0
    arr = JS_UNDEFINED;
52468
0
    len = js_typed_array_get_length_internal(ctx, this_val);
52469
0
    if (len < 0)
52470
0
        goto exception;
52471
52472
0
    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
52473
0
        goto exception;
52474
0
    final = len;
52475
0
    if (!JS_IsUndefined(argv[1])) {
52476
0
        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
52477
0
            goto exception;
52478
0
    }
52479
0
    count = max_int(final - start, 0);
52480
52481
0
    p = get_typed_array(ctx, this_val, 0);
52482
0
    if (p == NULL)
52483
0
        goto exception;
52484
0
    shift = typed_array_size_log2(p->class_id);
52485
52486
0
    args[0] = this_val;
52487
0
    args[1] = JS_NewInt32(ctx, count);
52488
0
    arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
52489
0
    if (JS_IsException(arr))
52490
0
        goto exception;
52491
52492
0
    if (count > 0) {
52493
0
        if (validate_typed_array(ctx, this_val)
52494
0
        ||  validate_typed_array(ctx, arr))
52495
0
            goto exception;
52496
52497
0
        p1 = get_typed_array(ctx, arr, 0);
52498
0
        if (p1 != NULL && p->class_id == p1->class_id &&
52499
0
            typed_array_get_length(ctx, p1) >= count &&
52500
0
            typed_array_get_length(ctx, p) >= start + count) {
52501
0
            memcpy(p1->u.array.u.uint8_ptr,
52502
0
                   p->u.array.u.uint8_ptr + (start << shift),
52503
0
                   count << shift);
52504
0
        } else {
52505
0
            for (n = 0; n < count; n++) {
52506
0
                val = JS_GetPropertyValue(ctx, this_val, JS_NewInt32(ctx, start + n));
52507
0
                if (JS_IsException(val))
52508
0
                    goto exception;
52509
0
                if (JS_SetPropertyValue(ctx, arr, JS_NewInt32(ctx, n), val,
52510
0
                                        JS_PROP_THROW) < 0)
52511
0
                    goto exception;
52512
0
            }
52513
0
        }
52514
0
    }
52515
0
    return arr;
52516
52517
0
 exception:
52518
0
    JS_FreeValue(ctx, arr);
52519
0
    return JS_EXCEPTION;
52520
0
}
52521
52522
static JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val,
52523
                                       int argc, JSValueConst *argv)
52524
0
{
52525
0
    JSValueConst args[4];
52526
0
    JSValue arr, byteOffset, ta_buffer;
52527
0
    JSObject *p;
52528
0
    int len, start, final, count, shift, offset;
52529
52530
0
    p = get_typed_array(ctx, this_val, 0);
52531
0
    if (!p)
52532
0
        goto exception;
52533
0
    len = p->u.array.count;
52534
0
    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
52535
0
        goto exception;
52536
52537
0
    final = len;
52538
0
    if (!JS_IsUndefined(argv[1])) {
52539
0
        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
52540
0
            goto exception;
52541
0
    }
52542
0
    count = max_int(final - start, 0);
52543
0
    byteOffset = js_typed_array_get_byteOffset(ctx, this_val, 0);
52544
0
    if (JS_IsException(byteOffset))
52545
0
        goto exception;
52546
0
    shift = typed_array_size_log2(p->class_id);
52547
0
    offset = JS_VALUE_GET_INT(byteOffset) + (start << shift);
52548
0
    JS_FreeValue(ctx, byteOffset);
52549
0
    ta_buffer = js_typed_array_get_buffer(ctx, this_val, 0);
52550
0
    if (JS_IsException(ta_buffer))
52551
0
        goto exception;
52552
0
    args[0] = this_val;
52553
0
    args[1] = ta_buffer;
52554
0
    args[2] = JS_NewInt32(ctx, offset);
52555
0
    args[3] = JS_NewInt32(ctx, count);
52556
0
    arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 4, args);
52557
0
    JS_FreeValue(ctx, ta_buffer);
52558
0
    return arr;
52559
52560
0
 exception:
52561
0
    return JS_EXCEPTION;
52562
0
}
52563
52564
/* TypedArray.prototype.sort */
52565
52566
static int js_cmp_doubles(double x, double y)
52567
0
{
52568
0
    if (isnan(x))    return isnan(y) ? 0 : +1;
52569
0
    if (isnan(y))    return -1;
52570
0
    if (x < y)       return -1;
52571
0
    if (x > y)       return 1;
52572
0
    if (x != 0)      return 0;
52573
0
    if (signbit(x))  return signbit(y) ? 0 : -1;
52574
0
    else             return signbit(y) ? 1 : 0;
52575
0
}
52576
52577
0
static int js_TA_cmp_int8(const void *a, const void *b, void *opaque) {
52578
0
    return *(const int8_t *)a - *(const int8_t *)b;
52579
0
}
52580
52581
0
static int js_TA_cmp_uint8(const void *a, const void *b, void *opaque) {
52582
0
    return *(const uint8_t *)a - *(const uint8_t *)b;
52583
0
}
52584
52585
0
static int js_TA_cmp_int16(const void *a, const void *b, void *opaque) {
52586
0
    return *(const int16_t *)a - *(const int16_t *)b;
52587
0
}
52588
52589
0
static int js_TA_cmp_uint16(const void *a, const void *b, void *opaque) {
52590
0
    return *(const uint16_t *)a - *(const uint16_t *)b;
52591
0
}
52592
52593
0
static int js_TA_cmp_int32(const void *a, const void *b, void *opaque) {
52594
0
    int32_t x = *(const int32_t *)a;
52595
0
    int32_t y = *(const int32_t *)b;
52596
0
    return (y < x) - (y > x);
52597
0
}
52598
52599
0
static int js_TA_cmp_uint32(const void *a, const void *b, void *opaque) {
52600
0
    uint32_t x = *(const uint32_t *)a;
52601
0
    uint32_t y = *(const uint32_t *)b;
52602
0
    return (y < x) - (y > x);
52603
0
}
52604
52605
#ifdef CONFIG_BIGNUM
52606
0
static int js_TA_cmp_int64(const void *a, const void *b, void *opaque) {
52607
0
    int64_t x = *(const int64_t *)a;
52608
0
    int64_t y = *(const int64_t *)b;
52609
0
    return (y < x) - (y > x);
52610
0
}
52611
52612
0
static int js_TA_cmp_uint64(const void *a, const void *b, void *opaque) {
52613
0
    uint64_t x = *(const uint64_t *)a;
52614
0
    uint64_t y = *(const uint64_t *)b;
52615
0
    return (y < x) - (y > x);
52616
0
}
52617
#endif
52618
52619
0
static int js_TA_cmp_float32(const void *a, const void *b, void *opaque) {
52620
0
    return js_cmp_doubles(*(const float *)a, *(const float *)b);
52621
0
}
52622
52623
0
static int js_TA_cmp_float64(const void *a, const void *b, void *opaque) {
52624
0
    return js_cmp_doubles(*(const double *)a, *(const double *)b);
52625
0
}
52626
52627
0
static JSValue js_TA_get_int8(JSContext *ctx, const void *a) {
52628
0
    return JS_NewInt32(ctx, *(const int8_t *)a);
52629
0
}
52630
52631
0
static JSValue js_TA_get_uint8(JSContext *ctx, const void *a) {
52632
0
    return JS_NewInt32(ctx, *(const uint8_t *)a);
52633
0
}
52634
52635
0
static JSValue js_TA_get_int16(JSContext *ctx, const void *a) {
52636
0
    return JS_NewInt32(ctx, *(const int16_t *)a);
52637
0
}
52638
52639
0
static JSValue js_TA_get_uint16(JSContext *ctx, const void *a) {
52640
0
    return JS_NewInt32(ctx, *(const uint16_t *)a);
52641
0
}
52642
52643
0
static JSValue js_TA_get_int32(JSContext *ctx, const void *a) {
52644
0
    return JS_NewInt32(ctx, *(const int32_t *)a);
52645
0
}
52646
52647
0
static JSValue js_TA_get_uint32(JSContext *ctx, const void *a) {
52648
0
    return JS_NewUint32(ctx, *(const uint32_t *)a);
52649
0
}
52650
52651
#ifdef CONFIG_BIGNUM
52652
0
static JSValue js_TA_get_int64(JSContext *ctx, const void *a) {
52653
0
    return JS_NewBigInt64(ctx, *(int64_t *)a);
52654
0
}
52655
52656
0
static JSValue js_TA_get_uint64(JSContext *ctx, const void *a) {
52657
0
    return JS_NewBigUint64(ctx, *(uint64_t *)a);
52658
0
}
52659
#endif
52660
52661
0
static JSValue js_TA_get_float32(JSContext *ctx, const void *a) {
52662
0
    return __JS_NewFloat64(ctx, *(const float *)a);
52663
0
}
52664
52665
0
static JSValue js_TA_get_float64(JSContext *ctx, const void *a) {
52666
0
    return __JS_NewFloat64(ctx, *(const double *)a);
52667
0
}
52668
52669
struct TA_sort_context {
52670
    JSContext *ctx;
52671
    int exception;
52672
    JSValueConst arr;
52673
    JSValueConst cmp;
52674
    JSValue (*getfun)(JSContext *ctx, const void *a);
52675
    uint8_t *array_ptr; /* cannot change unless the array is detached */
52676
    int elt_size;
52677
};
52678
52679
0
static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) {
52680
0
    struct TA_sort_context *psc = opaque;
52681
0
    JSContext *ctx = psc->ctx;
52682
0
    uint32_t a_idx, b_idx;
52683
0
    JSValueConst argv[2];
52684
0
    JSValue res;
52685
0
    int cmp;
52686
52687
0
    cmp = 0;
52688
0
    if (!psc->exception) {
52689
0
        a_idx = *(uint32_t *)a;
52690
0
        b_idx = *(uint32_t *)b;
52691
0
        argv[0] = psc->getfun(ctx, psc->array_ptr +
52692
0
                              a_idx * (size_t)psc->elt_size);
52693
0
        argv[1] = psc->getfun(ctx, psc->array_ptr +
52694
0
                              b_idx * (size_t)(psc->elt_size));
52695
0
        res = JS_Call(ctx, psc->cmp, JS_UNDEFINED, 2, argv);
52696
0
        if (JS_IsException(res)) {
52697
0
            psc->exception = 1;
52698
0
            goto done;
52699
0
        }
52700
0
        if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
52701
0
            int val = JS_VALUE_GET_INT(res);
52702
0
            cmp = (val > 0) - (val < 0);
52703
0
        } else {
52704
0
            double val;
52705
0
            if (JS_ToFloat64Free(ctx, &val, res) < 0) {
52706
0
                psc->exception = 1;
52707
0
                goto done;
52708
0
            } else {
52709
0
                cmp = (val > 0) - (val < 0);
52710
0
            }
52711
0
        }
52712
0
        if (cmp == 0) {
52713
            /* make sort stable: compare array offsets */
52714
0
            cmp = (a_idx > b_idx) - (a_idx < b_idx);
52715
0
        }
52716
0
        if (validate_typed_array(ctx, psc->arr) < 0) {
52717
0
            psc->exception = 1;
52718
0
        }
52719
0
    done:
52720
0
        JS_FreeValue(ctx, (JSValue)argv[0]);
52721
0
        JS_FreeValue(ctx, (JSValue)argv[1]);
52722
0
    }
52723
0
    return cmp;
52724
0
}
52725
52726
static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
52727
                                   int argc, JSValueConst *argv)
52728
0
{
52729
0
    JSObject *p;
52730
0
    int len;
52731
0
    size_t elt_size;
52732
0
    struct TA_sort_context tsc;
52733
0
    void *array_ptr;
52734
0
    int (*cmpfun)(const void *a, const void *b, void *opaque);
52735
52736
0
    tsc.ctx = ctx;
52737
0
    tsc.exception = 0;
52738
0
    tsc.arr = this_val;
52739
0
    tsc.cmp = argv[0];
52740
52741
0
    len = js_typed_array_get_length_internal(ctx, this_val);
52742
0
    if (len < 0)
52743
0
        return JS_EXCEPTION;
52744
0
    if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp))
52745
0
        return JS_EXCEPTION;
52746
52747
0
    if (len > 1) {
52748
0
        p = JS_VALUE_GET_OBJ(this_val);
52749
0
        switch (p->class_id) {
52750
0
        case JS_CLASS_INT8_ARRAY:
52751
0
            tsc.getfun = js_TA_get_int8;
52752
0
            cmpfun = js_TA_cmp_int8;
52753
0
            break;
52754
0
        case JS_CLASS_UINT8C_ARRAY:
52755
0
        case JS_CLASS_UINT8_ARRAY:
52756
0
            tsc.getfun = js_TA_get_uint8;
52757
0
            cmpfun = js_TA_cmp_uint8;
52758
0
            break;
52759
0
        case JS_CLASS_INT16_ARRAY:
52760
0
            tsc.getfun = js_TA_get_int16;
52761
0
            cmpfun = js_TA_cmp_int16;
52762
0
            break;
52763
0
        case JS_CLASS_UINT16_ARRAY:
52764
0
            tsc.getfun = js_TA_get_uint16;
52765
0
            cmpfun = js_TA_cmp_uint16;
52766
0
            break;
52767
0
        case JS_CLASS_INT32_ARRAY:
52768
0
            tsc.getfun = js_TA_get_int32;
52769
0
            cmpfun = js_TA_cmp_int32;
52770
0
            break;
52771
0
        case JS_CLASS_UINT32_ARRAY:
52772
0
            tsc.getfun = js_TA_get_uint32;
52773
0
            cmpfun = js_TA_cmp_uint32;
52774
0
            break;
52775
0
#ifdef CONFIG_BIGNUM
52776
0
        case JS_CLASS_BIG_INT64_ARRAY:
52777
0
            tsc.getfun = js_TA_get_int64;
52778
0
            cmpfun = js_TA_cmp_int64;
52779
0
            break;
52780
0
        case JS_CLASS_BIG_UINT64_ARRAY:
52781
0
            tsc.getfun = js_TA_get_uint64;
52782
0
            cmpfun = js_TA_cmp_uint64;
52783
0
            break;
52784
0
#endif
52785
0
        case JS_CLASS_FLOAT32_ARRAY:
52786
0
            tsc.getfun = js_TA_get_float32;
52787
0
            cmpfun = js_TA_cmp_float32;
52788
0
            break;
52789
0
        case JS_CLASS_FLOAT64_ARRAY:
52790
0
            tsc.getfun = js_TA_get_float64;
52791
0
            cmpfun = js_TA_cmp_float64;
52792
0
            break;
52793
0
        default:
52794
0
            abort();
52795
0
        }
52796
0
        array_ptr = p->u.array.u.ptr;
52797
0
        elt_size = 1 << typed_array_size_log2(p->class_id);
52798
0
        if (!JS_IsUndefined(tsc.cmp)) {
52799
0
            uint32_t *array_idx;
52800
0
            void *array_tmp;
52801
0
            size_t i, j;
52802
            
52803
            /* XXX: a stable sort would use less memory */
52804
0
            array_idx = js_malloc(ctx, len * sizeof(array_idx[0]));
52805
0
            if (!array_idx)
52806
0
                return JS_EXCEPTION;
52807
0
            for(i = 0; i < len; i++)
52808
0
                array_idx[i] = i;
52809
0
            tsc.array_ptr = array_ptr;
52810
0
            tsc.elt_size = elt_size;
52811
0
            rqsort(array_idx, len, sizeof(array_idx[0]),
52812
0
                   js_TA_cmp_generic, &tsc);
52813
0
            if (tsc.exception)
52814
0
                goto fail;
52815
0
            array_tmp = js_malloc(ctx, len * elt_size);
52816
0
            if (!array_tmp) {
52817
0
            fail:
52818
0
                js_free(ctx, array_idx);
52819
0
                return JS_EXCEPTION;
52820
0
            }
52821
0
            memcpy(array_tmp, array_ptr, len * elt_size);
52822
0
            switch(elt_size) {
52823
0
            case 1:
52824
0
                for(i = 0; i < len; i++) {
52825
0
                    j = array_idx[i];
52826
0
                    ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j];
52827
0
                }
52828
0
                break;
52829
0
            case 2:
52830
0
                for(i = 0; i < len; i++) {
52831
0
                    j = array_idx[i];
52832
0
                    ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j];
52833
0
                }
52834
0
                break;
52835
0
            case 4:
52836
0
                for(i = 0; i < len; i++) {
52837
0
                    j = array_idx[i];
52838
0
                    ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j];
52839
0
                }
52840
0
                break;
52841
0
            case 8:
52842
0
                for(i = 0; i < len; i++) {
52843
0
                    j = array_idx[i];
52844
0
                    ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j];
52845
0
                }
52846
0
                break;
52847
0
            default:
52848
0
                abort();
52849
0
            }
52850
0
            js_free(ctx, array_tmp);
52851
0
            js_free(ctx, array_idx);
52852
0
        } else {
52853
0
            rqsort(array_ptr, len, elt_size, cmpfun, &tsc);
52854
0
            if (tsc.exception)
52855
0
                return JS_EXCEPTION;
52856
0
        }
52857
0
    }
52858
0
    return JS_DupValue(ctx, this_val);
52859
0
}
52860
52861
static const JSCFunctionListEntry js_typed_array_base_funcs[] = {
52862
    JS_CFUNC_DEF("from", 1, js_typed_array_from ),
52863
    JS_CFUNC_DEF("of", 0, js_typed_array_of ),
52864
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
52865
    //JS_CFUNC_DEF("__getLength", 2, js_typed_array___getLength ),
52866
    //JS_CFUNC_DEF("__create", 2, js_typed_array___create ),
52867
    //JS_CFUNC_DEF("__speciesCreate", 2, js_typed_array___speciesCreate ),
52868
};
52869
52870
static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = {
52871
    JS_CGETSET_DEF("length", js_typed_array_get_length, NULL ),
52872
    JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 0 ),
52873
    JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 0 ),
52874
    JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 0 ),
52875
    JS_CFUNC_DEF("set", 1, js_typed_array_set ),
52876
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_VALUE ),
52877
    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
52878
    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY ),
52879
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
52880
    JS_CGETSET_DEF("[Symbol.toStringTag]", js_typed_array_get_toStringTag, NULL ),
52881
    JS_CFUNC_DEF("copyWithin", 2, js_typed_array_copyWithin ),
52882
    JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every | special_TA ),
52883
    JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some | special_TA ),
52884
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach | special_TA ),
52885
    JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map | special_TA ),
52886
    JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter | special_TA ),
52887
    JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA ),
52888
    JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA ),
52889
    JS_CFUNC_DEF("fill", 1, js_typed_array_fill ),
52890
    JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, 0 ),
52891
    JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, 1 ),
52892
    JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse ),
52893
    JS_CFUNC_DEF("slice", 2, js_typed_array_slice ),
52894
    JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray ),
52895
    JS_CFUNC_DEF("sort", 1, js_typed_array_sort ),
52896
    JS_CFUNC_MAGIC_DEF("join", 1, js_typed_array_join, 0 ),
52897
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_typed_array_join, 1 ),
52898
    JS_CFUNC_MAGIC_DEF("indexOf", 1, js_typed_array_indexOf, special_indexOf ),
52899
    JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_typed_array_indexOf, special_lastIndexOf ),
52900
    JS_CFUNC_MAGIC_DEF("includes", 1, js_typed_array_indexOf, special_includes ),
52901
    //JS_ALIAS_BASE_DEF("toString", "toString", 2 /* Array.prototype. */), @@@
52902
};
52903
52904
static JSValue js_typed_array_base_constructor(JSContext *ctx,
52905
                                               JSValueConst this_val,
52906
                                               int argc, JSValueConst *argv)
52907
0
{
52908
0
    return JS_ThrowTypeError(ctx, "cannot be called");
52909
0
}
52910
52911
/* 'obj' must be an allocated typed array object */
52912
static int typed_array_init(JSContext *ctx, JSValueConst obj,
52913
                            JSValue buffer, uint64_t offset, uint64_t len)
52914
0
{
52915
0
    JSTypedArray *ta;
52916
0
    JSObject *p, *pbuffer;
52917
0
    JSArrayBuffer *abuf;
52918
0
    int size_log2;
52919
52920
0
    p = JS_VALUE_GET_OBJ(obj);
52921
0
    size_log2 = typed_array_size_log2(p->class_id);
52922
0
    ta = js_malloc(ctx, sizeof(*ta));
52923
0
    if (!ta) {
52924
0
        JS_FreeValue(ctx, buffer);
52925
0
        return -1;
52926
0
    }
52927
0
    pbuffer = JS_VALUE_GET_OBJ(buffer);
52928
0
    abuf = pbuffer->u.array_buffer;
52929
0
    ta->obj = p;
52930
0
    ta->buffer = pbuffer;
52931
0
    ta->offset = offset;
52932
0
    ta->length = len << size_log2;
52933
0
    list_add_tail(&ta->link, &abuf->array_list);
52934
0
    p->u.typed_array = ta;
52935
0
    p->u.array.count = len;
52936
0
    p->u.array.u.ptr = abuf->data + offset;
52937
0
    return 0;
52938
0
}
52939
52940
52941
static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen,
52942
                                      JSValueConst obj, JSValueConst method)
52943
0
{
52944
0
    JSValue arr, iter, next_method = JS_UNDEFINED, val;
52945
0
    BOOL done;
52946
0
    uint32_t k;
52947
52948
0
    *plen = 0;
52949
0
    arr = JS_NewArray(ctx);
52950
0
    if (JS_IsException(arr))
52951
0
        return arr;
52952
0
    iter = JS_GetIterator2(ctx, obj, method);
52953
0
    if (JS_IsException(iter))
52954
0
        goto fail;
52955
0
    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
52956
0
    if (JS_IsException(next_method))
52957
0
        goto fail;
52958
0
    k = 0;
52959
0
    for(;;) {
52960
0
        val = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
52961
0
        if (JS_IsException(val))
52962
0
            goto fail;
52963
0
        if (done) {
52964
0
            JS_FreeValue(ctx, val);
52965
0
            break;
52966
0
        }
52967
0
        if (JS_CreateDataPropertyUint32(ctx, arr, k, val, JS_PROP_THROW) < 0)
52968
0
            goto fail;
52969
0
        k++;
52970
0
    }
52971
0
    JS_FreeValue(ctx, next_method);
52972
0
    JS_FreeValue(ctx, iter);
52973
0
    *plen = k;
52974
0
    return arr;
52975
0
 fail:
52976
0
    JS_FreeValue(ctx, next_method);
52977
0
    JS_FreeValue(ctx, iter);
52978
0
    JS_FreeValue(ctx, arr);
52979
0
    return JS_EXCEPTION;
52980
0
}
52981
52982
static JSValue js_typed_array_constructor_obj(JSContext *ctx,
52983
                                              JSValueConst new_target,
52984
                                              JSValueConst obj,
52985
                                              int classid)
52986
0
{
52987
0
    JSValue iter, ret, arr = JS_UNDEFINED, val, buffer;
52988
0
    uint32_t i;
52989
0
    int size_log2;
52990
0
    int64_t len;
52991
52992
0
    size_log2 = typed_array_size_log2(classid);
52993
0
    ret = js_create_from_ctor(ctx, new_target, classid);
52994
0
    if (JS_IsException(ret))
52995
0
        return JS_EXCEPTION;
52996
52997
0
    iter = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
52998
0
    if (JS_IsException(iter))
52999
0
        goto fail;
53000
0
    if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {
53001
0
        uint32_t len1;
53002
0
        arr = js_array_from_iterator(ctx, &len1, obj, iter);
53003
0
        JS_FreeValue(ctx, iter);
53004
0
        if (JS_IsException(arr))
53005
0
            goto fail;
53006
0
        len = len1;
53007
0
    } else {
53008
0
        if (js_get_length64(ctx, &len, obj))
53009
0
            goto fail;
53010
0
        arr = JS_DupValue(ctx, obj);
53011
0
    }
53012
53013
0
    buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
53014
0
                                          len << size_log2);
53015
0
    if (JS_IsException(buffer))
53016
0
        goto fail;
53017
0
    if (typed_array_init(ctx, ret, buffer, 0, len))
53018
0
        goto fail;
53019
53020
0
    for(i = 0; i < len; i++) {
53021
0
        val = JS_GetPropertyUint32(ctx, arr, i);
53022
0
        if (JS_IsException(val))
53023
0
            goto fail;
53024
0
        if (JS_SetPropertyUint32(ctx, ret, i, val) < 0)
53025
0
            goto fail;
53026
0
    }
53027
0
    JS_FreeValue(ctx, arr);
53028
0
    return ret;
53029
0
 fail:
53030
0
    JS_FreeValue(ctx, arr);
53031
0
    JS_FreeValue(ctx, ret);
53032
0
    return JS_EXCEPTION;
53033
0
}
53034
53035
static JSValue js_typed_array_constructor_ta(JSContext *ctx,
53036
                                             JSValueConst new_target,
53037
                                             JSValueConst src_obj,
53038
                                             int classid)
53039
0
{
53040
0
    JSObject *p, *src_buffer;
53041
0
    JSTypedArray *ta;
53042
0
    JSValue ctor, obj, buffer;
53043
0
    uint32_t len, i;
53044
0
    int size_log2;
53045
0
    JSArrayBuffer *src_abuf, *abuf;
53046
53047
0
    obj = js_create_from_ctor(ctx, new_target, classid);
53048
0
    if (JS_IsException(obj))
53049
0
        return obj;
53050
0
    p = JS_VALUE_GET_OBJ(src_obj);
53051
0
    if (typed_array_is_detached(ctx, p)) {
53052
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53053
0
        goto fail;
53054
0
    }
53055
0
    ta = p->u.typed_array;
53056
0
    len = p->u.array.count;
53057
0
    src_buffer = ta->buffer;
53058
0
    src_abuf = src_buffer->u.array_buffer;
53059
0
    if (!src_abuf->shared) {
53060
0
        ctor = JS_SpeciesConstructor(ctx, JS_MKPTR(JS_TAG_OBJECT, src_buffer),
53061
0
                                     JS_UNDEFINED);
53062
0
        if (JS_IsException(ctor))
53063
0
            goto fail;
53064
0
    } else {
53065
        /* force ArrayBuffer default constructor */
53066
0
        ctor = JS_UNDEFINED;
53067
0
    }
53068
0
    size_log2 = typed_array_size_log2(classid);
53069
0
    buffer = js_array_buffer_constructor1(ctx, ctor,
53070
0
                                          (uint64_t)len << size_log2);
53071
0
    JS_FreeValue(ctx, ctor);
53072
0
    if (JS_IsException(buffer))
53073
0
        goto fail;
53074
    /* necessary because it could have been detached */
53075
0
    if (typed_array_is_detached(ctx, p)) {
53076
0
        JS_FreeValue(ctx, buffer);
53077
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53078
0
        goto fail;
53079
0
    }
53080
0
    abuf = JS_GetOpaque(buffer, JS_CLASS_ARRAY_BUFFER);
53081
0
    if (typed_array_init(ctx, obj, buffer, 0, len))
53082
0
        goto fail;
53083
0
    if (p->class_id == classid) {
53084
        /* same type: copy the content */
53085
0
        memcpy(abuf->data, src_abuf->data + ta->offset, abuf->byte_length);
53086
0
    } else {
53087
0
        for(i = 0; i < len; i++) {
53088
0
            JSValue val;
53089
0
            val = JS_GetPropertyUint32(ctx, src_obj, i);
53090
0
            if (JS_IsException(val))
53091
0
                goto fail;
53092
0
            if (JS_SetPropertyUint32(ctx, obj, i, val) < 0)
53093
0
                goto fail;
53094
0
        }
53095
0
    }
53096
0
    return obj;
53097
0
 fail:
53098
0
    JS_FreeValue(ctx, obj);
53099
0
    return JS_EXCEPTION;
53100
0
}
53101
53102
static JSValue js_typed_array_constructor(JSContext *ctx,
53103
                                          JSValueConst new_target,
53104
                                          int argc, JSValueConst *argv,
53105
                                          int classid)
53106
0
{
53107
0
    JSValue buffer, obj;
53108
0
    JSArrayBuffer *abuf;
53109
0
    int size_log2;
53110
0
    uint64_t len, offset;
53111
53112
0
    size_log2 = typed_array_size_log2(classid);
53113
0
    if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) {
53114
0
        if (JS_ToIndex(ctx, &len, argv[0]))
53115
0
            return JS_EXCEPTION;
53116
0
        buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
53117
0
                                              len << size_log2);
53118
0
        if (JS_IsException(buffer))
53119
0
            return JS_EXCEPTION;
53120
0
        offset = 0;
53121
0
    } else {
53122
0
        JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
53123
0
        if (p->class_id == JS_CLASS_ARRAY_BUFFER ||
53124
0
            p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER) {
53125
0
            abuf = p->u.array_buffer;
53126
0
            if (JS_ToIndex(ctx, &offset, argv[1]))
53127
0
                return JS_EXCEPTION;
53128
0
            if (abuf->detached)
53129
0
                return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53130
0
            if ((offset & ((1 << size_log2) - 1)) != 0 ||
53131
0
                offset > abuf->byte_length)
53132
0
                return JS_ThrowRangeError(ctx, "invalid offset");
53133
0
            if (JS_IsUndefined(argv[2])) {
53134
0
                if ((abuf->byte_length & ((1 << size_log2) - 1)) != 0)
53135
0
                    goto invalid_length;
53136
0
                len = (abuf->byte_length - offset) >> size_log2;
53137
0
            } else {
53138
0
                if (JS_ToIndex(ctx, &len, argv[2]))
53139
0
                    return JS_EXCEPTION;
53140
0
                if (abuf->detached)
53141
0
                    return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53142
0
                if ((offset + (len << size_log2)) > abuf->byte_length) {
53143
0
                invalid_length:
53144
0
                    return JS_ThrowRangeError(ctx, "invalid length");
53145
0
                }
53146
0
            }
53147
0
            buffer = JS_DupValue(ctx, argv[0]);
53148
0
        } else {
53149
0
            if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
53150
0
                p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
53151
0
                return js_typed_array_constructor_ta(ctx, new_target, argv[0], classid);
53152
0
            } else {
53153
0
                return js_typed_array_constructor_obj(ctx, new_target, argv[0], classid);
53154
0
            }
53155
0
        }
53156
0
    }
53157
53158
0
    obj = js_create_from_ctor(ctx, new_target, classid);
53159
0
    if (JS_IsException(obj)) {
53160
0
        JS_FreeValue(ctx, buffer);
53161
0
        return JS_EXCEPTION;
53162
0
    }
53163
0
    if (typed_array_init(ctx, obj, buffer, offset, len)) {
53164
0
        JS_FreeValue(ctx, obj);
53165
0
        return JS_EXCEPTION;
53166
0
    }
53167
0
    return obj;
53168
0
}
53169
53170
static void js_typed_array_finalizer(JSRuntime *rt, JSValue val)
53171
0
{
53172
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
53173
0
    JSTypedArray *ta = p->u.typed_array;
53174
0
    if (ta) {
53175
        /* during the GC the finalizers are called in an arbitrary
53176
           order so the ArrayBuffer finalizer may have been called */
53177
0
        if (JS_IsLiveObject(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer))) {
53178
0
            list_del(&ta->link);
53179
0
        }
53180
0
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
53181
0
        js_free_rt(rt, ta);
53182
0
    }
53183
0
}
53184
53185
static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
53186
                                JS_MarkFunc *mark_func)
53187
0
{
53188
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
53189
0
    JSTypedArray *ta = p->u.typed_array;
53190
0
    if (ta) {
53191
0
        JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer), mark_func);
53192
0
    }
53193
0
}
53194
53195
static JSValue js_dataview_constructor(JSContext *ctx,
53196
                                       JSValueConst new_target,
53197
                                       int argc, JSValueConst *argv)
53198
0
{
53199
0
    JSArrayBuffer *abuf;
53200
0
    uint64_t offset;
53201
0
    uint32_t len;
53202
0
    JSValueConst buffer;
53203
0
    JSValue obj;
53204
0
    JSTypedArray *ta;
53205
0
    JSObject *p;
53206
53207
0
    buffer = argv[0];
53208
0
    abuf = js_get_array_buffer(ctx, buffer);
53209
0
    if (!abuf)
53210
0
        return JS_EXCEPTION;
53211
0
    offset = 0;
53212
0
    if (argc > 1) {
53213
0
        if (JS_ToIndex(ctx, &offset, argv[1]))
53214
0
            return JS_EXCEPTION;
53215
0
    }
53216
0
    if (abuf->detached)
53217
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53218
0
    if (offset > abuf->byte_length)
53219
0
        return JS_ThrowRangeError(ctx, "invalid byteOffset");
53220
0
    len = abuf->byte_length - offset;
53221
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
53222
0
        uint64_t l;
53223
0
        if (JS_ToIndex(ctx, &l, argv[2]))
53224
0
            return JS_EXCEPTION;
53225
0
        if (l > len)
53226
0
            return JS_ThrowRangeError(ctx, "invalid byteLength");
53227
0
        len = l;
53228
0
    }
53229
53230
0
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_DATAVIEW);
53231
0
    if (JS_IsException(obj))
53232
0
        return JS_EXCEPTION;
53233
0
    if (abuf->detached) {
53234
        /* could have been detached in js_create_from_ctor() */
53235
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53236
0
        goto fail;
53237
0
    }
53238
0
    ta = js_malloc(ctx, sizeof(*ta));
53239
0
    if (!ta) {
53240
0
    fail:
53241
0
        JS_FreeValue(ctx, obj);
53242
0
        return JS_EXCEPTION;
53243
0
    }
53244
0
    p = JS_VALUE_GET_OBJ(obj);
53245
0
    ta->obj = p;
53246
0
    ta->buffer = JS_VALUE_GET_OBJ(JS_DupValue(ctx, buffer));
53247
0
    ta->offset = offset;
53248
0
    ta->length = len;
53249
0
    list_add_tail(&ta->link, &abuf->array_list);
53250
0
    p->u.typed_array = ta;
53251
0
    return obj;
53252
0
}
53253
53254
static JSValue js_dataview_getValue(JSContext *ctx,
53255
                                    JSValueConst this_obj,
53256
                                    int argc, JSValueConst *argv, int class_id)
53257
0
{
53258
0
    JSTypedArray *ta;
53259
0
    JSArrayBuffer *abuf;
53260
0
    int is_swap, size;
53261
0
    uint8_t *ptr;
53262
0
    uint32_t v;
53263
0
    uint64_t pos;
53264
53265
0
    ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
53266
0
    if (!ta)
53267
0
        return JS_EXCEPTION;
53268
0
    size = 1 << typed_array_size_log2(class_id);
53269
0
    if (JS_ToIndex(ctx, &pos, argv[0]))
53270
0
        return JS_EXCEPTION;
53271
0
    is_swap = FALSE;
53272
0
    if (argc > 1)
53273
0
        is_swap = JS_ToBool(ctx, argv[1]);
53274
0
#ifndef WORDS_BIGENDIAN
53275
0
    is_swap ^= 1;
53276
0
#endif
53277
0
    abuf = ta->buffer->u.array_buffer;
53278
0
    if (abuf->detached)
53279
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53280
0
    if ((pos + size) > ta->length)
53281
0
        return JS_ThrowRangeError(ctx, "out of bound");
53282
0
    ptr = abuf->data + ta->offset + pos;
53283
53284
0
    switch(class_id) {
53285
0
    case JS_CLASS_INT8_ARRAY:
53286
0
        return JS_NewInt32(ctx, *(int8_t *)ptr);
53287
0
    case JS_CLASS_UINT8_ARRAY:
53288
0
        return JS_NewInt32(ctx, *(uint8_t *)ptr);
53289
0
    case JS_CLASS_INT16_ARRAY:
53290
0
        v = get_u16(ptr);
53291
0
        if (is_swap)
53292
0
            v = bswap16(v);
53293
0
        return JS_NewInt32(ctx, (int16_t)v);
53294
0
    case JS_CLASS_UINT16_ARRAY:
53295
0
        v = get_u16(ptr);
53296
0
        if (is_swap)
53297
0
            v = bswap16(v);
53298
0
        return JS_NewInt32(ctx, v);
53299
0
    case JS_CLASS_INT32_ARRAY:
53300
0
        v = get_u32(ptr);
53301
0
        if (is_swap)
53302
0
            v = bswap32(v);
53303
0
        return JS_NewInt32(ctx, v);
53304
0
    case JS_CLASS_UINT32_ARRAY:
53305
0
        v = get_u32(ptr);
53306
0
        if (is_swap)
53307
0
            v = bswap32(v);
53308
0
        return JS_NewUint32(ctx, v);
53309
0
#ifdef CONFIG_BIGNUM
53310
0
    case JS_CLASS_BIG_INT64_ARRAY:
53311
0
        {
53312
0
            uint64_t v;
53313
0
            v = get_u64(ptr);
53314
0
            if (is_swap)
53315
0
                v = bswap64(v);
53316
0
            return JS_NewBigInt64(ctx, v);
53317
0
        }
53318
0
        break;
53319
0
    case JS_CLASS_BIG_UINT64_ARRAY:
53320
0
        {
53321
0
            uint64_t v;
53322
0
            v = get_u64(ptr);
53323
0
            if (is_swap)
53324
0
                v = bswap64(v);
53325
0
            return JS_NewBigUint64(ctx, v);
53326
0
        }
53327
0
        break;
53328
0
#endif
53329
0
    case JS_CLASS_FLOAT32_ARRAY:
53330
0
        {
53331
0
            union {
53332
0
                float f;
53333
0
                uint32_t i;
53334
0
            } u;
53335
0
            v = get_u32(ptr);
53336
0
            if (is_swap)
53337
0
                v = bswap32(v);
53338
0
            u.i = v;
53339
0
            return __JS_NewFloat64(ctx, u.f);
53340
0
        }
53341
0
    case JS_CLASS_FLOAT64_ARRAY:
53342
0
        {
53343
0
            union {
53344
0
                double f;
53345
0
                uint64_t i;
53346
0
            } u;
53347
0
            u.i = get_u64(ptr);
53348
0
            if (is_swap)
53349
0
                u.i = bswap64(u.i);
53350
0
            return __JS_NewFloat64(ctx, u.f);
53351
0
        }
53352
0
    default:
53353
0
        abort();
53354
0
    }
53355
0
}
53356
53357
static JSValue js_dataview_setValue(JSContext *ctx,
53358
                                    JSValueConst this_obj,
53359
                                    int argc, JSValueConst *argv, int class_id)
53360
0
{
53361
0
    JSTypedArray *ta;
53362
0
    JSArrayBuffer *abuf;
53363
0
    int is_swap, size;
53364
0
    uint8_t *ptr;
53365
0
    uint64_t v64;
53366
0
    uint32_t v;
53367
0
    uint64_t pos;
53368
0
    JSValueConst val;
53369
53370
0
    ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
53371
0
    if (!ta)
53372
0
        return JS_EXCEPTION;
53373
0
    size = 1 << typed_array_size_log2(class_id);
53374
0
    if (JS_ToIndex(ctx, &pos, argv[0]))
53375
0
        return JS_EXCEPTION;
53376
0
    val = argv[1];
53377
0
    v = 0; /* avoid warning */
53378
0
    v64 = 0; /* avoid warning */
53379
0
    if (class_id <= JS_CLASS_UINT32_ARRAY) {
53380
0
        if (JS_ToUint32(ctx, &v, val))
53381
0
            return JS_EXCEPTION;
53382
0
    } else
53383
0
#ifdef CONFIG_BIGNUM
53384
0
    if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
53385
0
        if (JS_ToBigInt64(ctx, (int64_t *)&v64, val))
53386
0
            return JS_EXCEPTION;
53387
0
    } else
53388
0
#endif
53389
0
    {
53390
0
        double d;
53391
0
        if (JS_ToFloat64(ctx, &d, val))
53392
0
            return JS_EXCEPTION;
53393
0
        if (class_id == JS_CLASS_FLOAT32_ARRAY) {
53394
0
            union {
53395
0
                float f;
53396
0
                uint32_t i;
53397
0
            } u;
53398
0
            u.f = d;
53399
0
            v = u.i;
53400
0
        } else {
53401
0
            JSFloat64Union u;
53402
0
            u.d = d;
53403
0
            v64 = u.u64;
53404
0
        }
53405
0
    }
53406
0
    is_swap = FALSE;
53407
0
    if (argc > 2)
53408
0
        is_swap = JS_ToBool(ctx, argv[2]);
53409
0
#ifndef WORDS_BIGENDIAN
53410
0
    is_swap ^= 1;
53411
0
#endif
53412
0
    abuf = ta->buffer->u.array_buffer;
53413
0
    if (abuf->detached)
53414
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53415
0
    if ((pos + size) > ta->length)
53416
0
        return JS_ThrowRangeError(ctx, "out of bound");
53417
0
    ptr = abuf->data + ta->offset + pos;
53418
53419
0
    switch(class_id) {
53420
0
    case JS_CLASS_INT8_ARRAY:
53421
0
    case JS_CLASS_UINT8_ARRAY:
53422
0
        *ptr = v;
53423
0
        break;
53424
0
    case JS_CLASS_INT16_ARRAY:
53425
0
    case JS_CLASS_UINT16_ARRAY:
53426
0
        if (is_swap)
53427
0
            v = bswap16(v);
53428
0
        put_u16(ptr, v);
53429
0
        break;
53430
0
    case JS_CLASS_INT32_ARRAY:
53431
0
    case JS_CLASS_UINT32_ARRAY:
53432
0
    case JS_CLASS_FLOAT32_ARRAY:
53433
0
        if (is_swap)
53434
0
            v = bswap32(v);
53435
0
        put_u32(ptr, v);
53436
0
        break;
53437
0
#ifdef CONFIG_BIGNUM
53438
0
    case JS_CLASS_BIG_INT64_ARRAY:
53439
0
    case JS_CLASS_BIG_UINT64_ARRAY:
53440
0
#endif
53441
0
    case JS_CLASS_FLOAT64_ARRAY:
53442
0
        if (is_swap)
53443
0
            v64 = bswap64(v64);
53444
0
        put_u64(ptr, v64);
53445
0
        break;
53446
0
    default:
53447
0
        abort();
53448
0
    }
53449
0
    return JS_UNDEFINED;
53450
0
}
53451
53452
static const JSCFunctionListEntry js_dataview_proto_funcs[] = {
53453
    JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 1 ),
53454
    JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 1 ),
53455
    JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 1 ),
53456
    JS_CFUNC_MAGIC_DEF("getInt8", 1, js_dataview_getValue, JS_CLASS_INT8_ARRAY ),
53457
    JS_CFUNC_MAGIC_DEF("getUint8", 1, js_dataview_getValue, JS_CLASS_UINT8_ARRAY ),
53458
    JS_CFUNC_MAGIC_DEF("getInt16", 1, js_dataview_getValue, JS_CLASS_INT16_ARRAY ),
53459
    JS_CFUNC_MAGIC_DEF("getUint16", 1, js_dataview_getValue, JS_CLASS_UINT16_ARRAY ),
53460
    JS_CFUNC_MAGIC_DEF("getInt32", 1, js_dataview_getValue, JS_CLASS_INT32_ARRAY ),
53461
    JS_CFUNC_MAGIC_DEF("getUint32", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY ),
53462
#ifdef CONFIG_BIGNUM
53463
    JS_CFUNC_MAGIC_DEF("getBigInt64", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY ),
53464
    JS_CFUNC_MAGIC_DEF("getBigUint64", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY ),
53465
#endif
53466
    JS_CFUNC_MAGIC_DEF("getFloat32", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY ),
53467
    JS_CFUNC_MAGIC_DEF("getFloat64", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY ),
53468
    JS_CFUNC_MAGIC_DEF("setInt8", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY ),
53469
    JS_CFUNC_MAGIC_DEF("setUint8", 2, js_dataview_setValue, JS_CLASS_UINT8_ARRAY ),
53470
    JS_CFUNC_MAGIC_DEF("setInt16", 2, js_dataview_setValue, JS_CLASS_INT16_ARRAY ),
53471
    JS_CFUNC_MAGIC_DEF("setUint16", 2, js_dataview_setValue, JS_CLASS_UINT16_ARRAY ),
53472
    JS_CFUNC_MAGIC_DEF("setInt32", 2, js_dataview_setValue, JS_CLASS_INT32_ARRAY ),
53473
    JS_CFUNC_MAGIC_DEF("setUint32", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY ),
53474
#ifdef CONFIG_BIGNUM
53475
    JS_CFUNC_MAGIC_DEF("setBigInt64", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY ),
53476
    JS_CFUNC_MAGIC_DEF("setBigUint64", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY ),
53477
#endif
53478
    JS_CFUNC_MAGIC_DEF("setFloat32", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY ),
53479
    JS_CFUNC_MAGIC_DEF("setFloat64", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY ),
53480
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DataView", JS_PROP_CONFIGURABLE ),
53481
};
53482
53483
/* Atomics */
53484
#ifdef CONFIG_ATOMICS
53485
53486
typedef enum AtomicsOpEnum {
53487
    ATOMICS_OP_ADD,
53488
    ATOMICS_OP_AND,
53489
    ATOMICS_OP_OR,
53490
    ATOMICS_OP_SUB,
53491
    ATOMICS_OP_XOR,
53492
    ATOMICS_OP_EXCHANGE,
53493
    ATOMICS_OP_COMPARE_EXCHANGE,
53494
    ATOMICS_OP_LOAD,
53495
} AtomicsOpEnum;
53496
53497
static void *js_atomics_get_ptr(JSContext *ctx,
53498
                                JSArrayBuffer **pabuf,
53499
                                int *psize_log2, JSClassID *pclass_id,
53500
                                JSValueConst obj, JSValueConst idx_val,
53501
                                int is_waitable)
53502
0
{
53503
0
    JSObject *p;
53504
0
    JSTypedArray *ta;
53505
0
    JSArrayBuffer *abuf;
53506
0
    void *ptr;
53507
0
    uint64_t idx;
53508
0
    BOOL err;
53509
0
    int size_log2;
53510
53511
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
53512
0
        goto fail;
53513
0
    p = JS_VALUE_GET_OBJ(obj);
53514
0
#ifdef CONFIG_BIGNUM
53515
0
    if (is_waitable)
53516
0
        err = (p->class_id != JS_CLASS_INT32_ARRAY &&
53517
0
               p->class_id != JS_CLASS_BIG_INT64_ARRAY);
53518
0
    else
53519
0
        err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
53520
0
                p->class_id <= JS_CLASS_BIG_UINT64_ARRAY);
53521
#else
53522
    if (is_waitable)
53523
        err = (p->class_id != JS_CLASS_INT32_ARRAY);
53524
    else
53525
        err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
53526
                p->class_id <= JS_CLASS_UINT32_ARRAY);
53527
#endif
53528
0
    if (err) {
53529
0
    fail:
53530
0
        JS_ThrowTypeError(ctx, "integer TypedArray expected");
53531
0
        return NULL;
53532
0
    }
53533
0
    ta = p->u.typed_array;
53534
0
    abuf = ta->buffer->u.array_buffer;
53535
0
    if (!abuf->shared) {
53536
0
        if (is_waitable == 2) {
53537
0
            JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray");
53538
0
            return NULL;
53539
0
        }
53540
0
        if (abuf->detached) {
53541
0
            JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53542
0
            return NULL;
53543
0
        }
53544
0
    }
53545
0
    if (JS_ToIndex(ctx, &idx, idx_val)) {
53546
0
        return NULL;
53547
0
    }
53548
    /* if the array buffer is detached, p->u.array.count = 0 */
53549
0
    if (idx >= p->u.array.count) {
53550
0
        JS_ThrowRangeError(ctx, "out-of-bound access");
53551
0
        return NULL;
53552
0
    }
53553
0
    size_log2 = typed_array_size_log2(p->class_id);
53554
0
    ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);
53555
0
    if (pabuf)
53556
0
        *pabuf = abuf;
53557
0
    if (psize_log2)
53558
0
        *psize_log2 = size_log2;
53559
0
    if (pclass_id)
53560
0
        *pclass_id = p->class_id;
53561
0
    return ptr;
53562
0
}
53563
53564
static JSValue js_atomics_op(JSContext *ctx,
53565
                             JSValueConst this_obj,
53566
                             int argc, JSValueConst *argv, int op)
53567
0
{
53568
0
    int size_log2;
53569
0
#ifdef CONFIG_BIGNUM
53570
0
    uint64_t v, a, rep_val;
53571
#else
53572
    uint32_t v, a, rep_val;
53573
#endif
53574
0
    void *ptr;
53575
0
    JSValue ret;
53576
0
    JSClassID class_id;
53577
0
    JSArrayBuffer *abuf;
53578
53579
0
    ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, &class_id,
53580
0
                             argv[0], argv[1], 0);
53581
0
    if (!ptr)
53582
0
        return JS_EXCEPTION;
53583
0
    rep_val = 0;
53584
0
    if (op == ATOMICS_OP_LOAD) {
53585
0
        v = 0;
53586
0
    } else {
53587
0
#ifdef CONFIG_BIGNUM
53588
0
        if (size_log2 == 3) {
53589
0
            int64_t v64;
53590
0
            if (JS_ToBigInt64(ctx, &v64, argv[2]))
53591
0
                return JS_EXCEPTION;
53592
0
            v = v64;
53593
0
            if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
53594
0
                if (JS_ToBigInt64(ctx, &v64, argv[3]))
53595
0
                    return JS_EXCEPTION;
53596
0
                rep_val = v64;
53597
0
            }
53598
0
        } else
53599
0
#endif
53600
0
        {
53601
0
                uint32_t v32;
53602
0
                if (JS_ToUint32(ctx, &v32, argv[2]))
53603
0
                    return JS_EXCEPTION;
53604
0
                v = v32;
53605
0
                if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
53606
0
                    if (JS_ToUint32(ctx, &v32, argv[3]))
53607
0
                        return JS_EXCEPTION;
53608
0
                    rep_val = v32;
53609
0
                }
53610
0
        }
53611
0
        if (abuf->detached)
53612
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53613
0
   }
53614
53615
0
   switch(op | (size_log2 << 3)) {
53616
            
53617
0
#ifdef CONFIG_BIGNUM
53618
0
#define OP(op_name, func_name)                          \
53619
0
    case ATOMICS_OP_ ## op_name | (0 << 3):             \
53620
0
       a = func_name((_Atomic(uint8_t) *)ptr, v);       \
53621
0
       break;                                           \
53622
0
    case ATOMICS_OP_ ## op_name | (1 << 3):             \
53623
0
        a = func_name((_Atomic(uint16_t) *)ptr, v);     \
53624
0
        break;                                          \
53625
0
    case ATOMICS_OP_ ## op_name | (2 << 3):             \
53626
0
        a = func_name((_Atomic(uint32_t) *)ptr, v);     \
53627
0
        break;                                          \
53628
0
    case ATOMICS_OP_ ## op_name | (3 << 3):             \
53629
0
        a = func_name((_Atomic(uint64_t) *)ptr, v);     \
53630
0
        break;
53631
#else
53632
#define OP(op_name, func_name)                          \
53633
    case ATOMICS_OP_ ## op_name | (0 << 3):             \
53634
       a = func_name((_Atomic(uint8_t) *)ptr, v);       \
53635
       break;                                           \
53636
    case ATOMICS_OP_ ## op_name | (1 << 3):             \
53637
        a = func_name((_Atomic(uint16_t) *)ptr, v);     \
53638
        break;                                          \
53639
    case ATOMICS_OP_ ## op_name | (2 << 3):             \
53640
        a = func_name((_Atomic(uint32_t) *)ptr, v);     \
53641
        break;
53642
#endif
53643
0
        OP(ADD, atomic_fetch_add)
53644
0
        OP(AND, atomic_fetch_and)
53645
0
        OP(OR, atomic_fetch_or)
53646
0
        OP(SUB, atomic_fetch_sub)
53647
0
        OP(XOR, atomic_fetch_xor)
53648
0
        OP(EXCHANGE, atomic_exchange)
53649
0
#undef OP
53650
53651
0
    case ATOMICS_OP_LOAD | (0 << 3):
53652
0
        a = atomic_load((_Atomic(uint8_t) *)ptr);
53653
0
        break;
53654
0
    case ATOMICS_OP_LOAD | (1 << 3):
53655
0
        a = atomic_load((_Atomic(uint16_t) *)ptr);
53656
0
        break;
53657
0
    case ATOMICS_OP_LOAD | (2 << 3):
53658
0
        a = atomic_load((_Atomic(uint32_t) *)ptr);
53659
0
        break;
53660
0
#ifdef CONFIG_BIGNUM
53661
0
    case ATOMICS_OP_LOAD | (3 << 3):
53662
0
        a = atomic_load((_Atomic(uint64_t) *)ptr);
53663
0
        break;
53664
0
#endif
53665
        
53666
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3):
53667
0
        {
53668
0
            uint8_t v1 = v;
53669
0
            atomic_compare_exchange_strong((_Atomic(uint8_t) *)ptr, &v1, rep_val);
53670
0
            a = v1;
53671
0
        }
53672
0
        break;
53673
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (1 << 3):
53674
0
        {
53675
0
            uint16_t v1 = v;
53676
0
            atomic_compare_exchange_strong((_Atomic(uint16_t) *)ptr, &v1, rep_val);
53677
0
            a = v1;
53678
0
        }
53679
0
        break;
53680
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (2 << 3):
53681
0
        {
53682
0
            uint32_t v1 = v;
53683
0
            atomic_compare_exchange_strong((_Atomic(uint32_t) *)ptr, &v1, rep_val);
53684
0
            a = v1;
53685
0
        }
53686
0
        break;
53687
0
#ifdef CONFIG_BIGNUM
53688
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3):
53689
0
        {
53690
0
            uint64_t v1 = v;
53691
0
            atomic_compare_exchange_strong((_Atomic(uint64_t) *)ptr, &v1, rep_val);
53692
0
            a = v1;
53693
0
        }
53694
0
        break;
53695
0
#endif
53696
0
    default:
53697
0
        abort();
53698
0
    }
53699
53700
0
    switch(class_id) {
53701
0
    case JS_CLASS_INT8_ARRAY:
53702
0
        a = (int8_t)a;
53703
0
        goto done;
53704
0
    case JS_CLASS_UINT8_ARRAY:
53705
0
        a = (uint8_t)a;
53706
0
        goto done;
53707
0
    case JS_CLASS_INT16_ARRAY:
53708
0
        a = (int16_t)a;
53709
0
        goto done;
53710
0
    case JS_CLASS_UINT16_ARRAY:
53711
0
        a = (uint16_t)a;
53712
0
        goto done;
53713
0
    case JS_CLASS_INT32_ARRAY:
53714
0
    done:
53715
0
        ret = JS_NewInt32(ctx, a);
53716
0
        break;
53717
0
    case JS_CLASS_UINT32_ARRAY:
53718
0
        ret = JS_NewUint32(ctx, a);
53719
0
        break;
53720
0
#ifdef CONFIG_BIGNUM
53721
0
    case JS_CLASS_BIG_INT64_ARRAY:
53722
0
        ret = JS_NewBigInt64(ctx, a);
53723
0
        break;
53724
0
    case JS_CLASS_BIG_UINT64_ARRAY:
53725
0
        ret = JS_NewBigUint64(ctx, a);
53726
0
        break;
53727
0
#endif
53728
0
    default:
53729
0
        abort();
53730
0
    }
53731
0
    return ret;
53732
0
}
53733
53734
static JSValue js_atomics_store(JSContext *ctx,
53735
                                JSValueConst this_obj,
53736
                                int argc, JSValueConst *argv)
53737
0
{
53738
0
    int size_log2;
53739
0
    void *ptr;
53740
0
    JSValue ret;
53741
0
    JSArrayBuffer *abuf;
53742
53743
0
    ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, NULL,
53744
0
                             argv[0], argv[1], 0);
53745
0
    if (!ptr)
53746
0
        return JS_EXCEPTION;
53747
0
#ifdef CONFIG_BIGNUM
53748
0
    if (size_log2 == 3) {
53749
0
        int64_t v64;
53750
0
        ret = JS_ToBigIntValueFree(ctx, JS_DupValue(ctx, argv[2]));
53751
0
        if (JS_IsException(ret))
53752
0
            return ret;
53753
0
        if (JS_ToBigInt64(ctx, &v64, ret)) {
53754
0
            JS_FreeValue(ctx, ret);
53755
0
            return JS_EXCEPTION;
53756
0
        }
53757
0
        if (abuf->detached)
53758
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53759
0
        atomic_store((_Atomic(uint64_t) *)ptr, v64);
53760
0
    } else
53761
0
#endif
53762
0
    {
53763
0
        uint32_t v;
53764
        /* XXX: spec, would be simpler to return the written value */
53765
0
        ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2]));
53766
0
        if (JS_IsException(ret))
53767
0
            return ret;
53768
0
        if (JS_ToUint32(ctx, &v, ret)) {
53769
0
            JS_FreeValue(ctx, ret);
53770
0
            return JS_EXCEPTION;
53771
0
        }
53772
0
        if (abuf->detached)
53773
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53774
0
        switch(size_log2) {
53775
0
        case 0:
53776
0
            atomic_store((_Atomic(uint8_t) *)ptr, v);
53777
0
            break;
53778
0
        case 1:
53779
0
            atomic_store((_Atomic(uint16_t) *)ptr, v);
53780
0
            break;
53781
0
        case 2:
53782
0
            atomic_store((_Atomic(uint32_t) *)ptr, v);
53783
0
            break;
53784
0
        default:
53785
0
            abort();
53786
0
        }
53787
0
    }
53788
0
    return ret;
53789
0
}
53790
53791
static JSValue js_atomics_isLockFree(JSContext *ctx,
53792
                                     JSValueConst this_obj,
53793
                                     int argc, JSValueConst *argv)
53794
0
{
53795
0
    int v, ret;
53796
0
    if (JS_ToInt32Sat(ctx, &v, argv[0]))
53797
0
        return JS_EXCEPTION;
53798
0
    ret = (v == 1 || v == 2 || v == 4
53799
0
#ifdef CONFIG_BIGNUM
53800
0
           || v == 8
53801
0
#endif
53802
0
           );
53803
0
    return JS_NewBool(ctx, ret);
53804
0
}
53805
53806
typedef struct JSAtomicsWaiter {
53807
    struct list_head link;
53808
    BOOL linked;
53809
    pthread_cond_t cond;
53810
    int32_t *ptr;
53811
} JSAtomicsWaiter;
53812
53813
static pthread_mutex_t js_atomics_mutex = PTHREAD_MUTEX_INITIALIZER;
53814
static struct list_head js_atomics_waiter_list =
53815
    LIST_HEAD_INIT(js_atomics_waiter_list);
53816
53817
static JSValue js_atomics_wait(JSContext *ctx,
53818
                               JSValueConst this_obj,
53819
                               int argc, JSValueConst *argv)
53820
0
{
53821
0
    int64_t v;
53822
0
    int32_t v32;
53823
0
    void *ptr;
53824
0
    int64_t timeout;
53825
0
    struct timespec ts;
53826
0
    JSAtomicsWaiter waiter_s, *waiter;
53827
0
    int ret, size_log2, res;
53828
0
    double d;
53829
53830
0
    ptr = js_atomics_get_ptr(ctx, NULL, &size_log2, NULL,
53831
0
                             argv[0], argv[1], 2);
53832
0
    if (!ptr)
53833
0
        return JS_EXCEPTION;
53834
0
#ifdef CONFIG_BIGNUM
53835
0
    if (size_log2 == 3) {
53836
0
        if (JS_ToBigInt64(ctx, &v, argv[2]))
53837
0
            return JS_EXCEPTION;
53838
0
    } else
53839
0
#endif
53840
0
    {        
53841
0
        if (JS_ToInt32(ctx, &v32, argv[2]))
53842
0
            return JS_EXCEPTION;
53843
0
        v = v32;
53844
0
    }
53845
0
    if (JS_ToFloat64(ctx, &d, argv[3]))
53846
0
        return JS_EXCEPTION;
53847
0
    if (isnan(d) || d > INT64_MAX)
53848
0
        timeout = INT64_MAX;
53849
0
    else if (d < 0)
53850
0
        timeout = 0;
53851
0
    else
53852
0
        timeout = (int64_t)d;
53853
0
    if (!ctx->rt->can_block)
53854
0
        return JS_ThrowTypeError(ctx, "cannot block in this thread");
53855
53856
    /* XXX: inefficient if large number of waiters, should hash on
53857
       'ptr' value */
53858
    /* XXX: use Linux futexes when available ? */
53859
0
    pthread_mutex_lock(&js_atomics_mutex);
53860
0
    if (size_log2 == 3) {
53861
0
        res = *(int64_t *)ptr != v;
53862
0
    } else {
53863
0
        res = *(int32_t *)ptr != v;
53864
0
    }
53865
0
    if (res) {
53866
0
        pthread_mutex_unlock(&js_atomics_mutex);
53867
0
        return JS_AtomToString(ctx, JS_ATOM_not_equal);
53868
0
    }
53869
53870
0
    waiter = &waiter_s;
53871
0
    waiter->ptr = ptr;
53872
0
    pthread_cond_init(&waiter->cond, NULL);
53873
0
    waiter->linked = TRUE;
53874
0
    list_add_tail(&waiter->link, &js_atomics_waiter_list);
53875
53876
0
    if (timeout == INT64_MAX) {
53877
0
        pthread_cond_wait(&waiter->cond, &js_atomics_mutex);
53878
0
        ret = 0;
53879
0
    } else {
53880
        /* XXX: use clock monotonic */
53881
0
        clock_gettime(CLOCK_REALTIME, &ts);
53882
0
        ts.tv_sec += timeout / 1000;
53883
0
        ts.tv_nsec += (timeout % 1000) * 1000000;
53884
0
        if (ts.tv_nsec >= 1000000000) {
53885
0
            ts.tv_nsec -= 1000000000;
53886
0
            ts.tv_sec++;
53887
0
        }
53888
0
        ret = pthread_cond_timedwait(&waiter->cond, &js_atomics_mutex,
53889
0
                                     &ts);
53890
0
    }
53891
0
    if (waiter->linked)
53892
0
        list_del(&waiter->link);
53893
0
    pthread_mutex_unlock(&js_atomics_mutex);
53894
0
    pthread_cond_destroy(&waiter->cond);
53895
0
    if (ret == ETIMEDOUT) {
53896
0
        return JS_AtomToString(ctx, JS_ATOM_timed_out);
53897
0
    } else {
53898
0
        return JS_AtomToString(ctx, JS_ATOM_ok);
53899
0
    }
53900
0
}
53901
53902
static JSValue js_atomics_notify(JSContext *ctx,
53903
                                 JSValueConst this_obj,
53904
                                 int argc, JSValueConst *argv)
53905
0
{
53906
0
    struct list_head *el, *el1, waiter_list;
53907
0
    int32_t count, n;
53908
0
    void *ptr;
53909
0
    JSAtomicsWaiter *waiter;
53910
0
    JSArrayBuffer *abuf;
53911
53912
0
    ptr = js_atomics_get_ptr(ctx, &abuf, NULL, NULL, argv[0], argv[1], 1);
53913
0
    if (!ptr)
53914
0
        return JS_EXCEPTION;
53915
53916
0
    if (JS_IsUndefined(argv[2])) {
53917
0
        count = INT32_MAX;
53918
0
    } else {
53919
0
        if (JS_ToInt32Clamp(ctx, &count, argv[2], 0, INT32_MAX, 0))
53920
0
            return JS_EXCEPTION;
53921
0
    }
53922
0
    if (abuf->detached)
53923
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53924
53925
0
    n = 0;
53926
0
    if (abuf->shared && count > 0) {
53927
0
        pthread_mutex_lock(&js_atomics_mutex);
53928
0
        init_list_head(&waiter_list);
53929
0
        list_for_each_safe(el, el1, &js_atomics_waiter_list) {
53930
0
            waiter = list_entry(el, JSAtomicsWaiter, link);
53931
0
            if (waiter->ptr == ptr) {
53932
0
                list_del(&waiter->link);
53933
0
                waiter->linked = FALSE;
53934
0
                list_add_tail(&waiter->link, &waiter_list);
53935
0
                n++;
53936
0
                if (n >= count)
53937
0
                    break;
53938
0
            }
53939
0
        }
53940
0
        list_for_each(el, &waiter_list) {
53941
0
            waiter = list_entry(el, JSAtomicsWaiter, link);
53942
0
            pthread_cond_signal(&waiter->cond);
53943
0
        }
53944
0
        pthread_mutex_unlock(&js_atomics_mutex);
53945
0
    }
53946
0
    return JS_NewInt32(ctx, n);
53947
0
}
53948
53949
static const JSCFunctionListEntry js_atomics_funcs[] = {
53950
    JS_CFUNC_MAGIC_DEF("add", 3, js_atomics_op, ATOMICS_OP_ADD ),
53951
    JS_CFUNC_MAGIC_DEF("and", 3, js_atomics_op, ATOMICS_OP_AND ),
53952
    JS_CFUNC_MAGIC_DEF("or", 3, js_atomics_op, ATOMICS_OP_OR ),
53953
    JS_CFUNC_MAGIC_DEF("sub", 3, js_atomics_op, ATOMICS_OP_SUB ),
53954
    JS_CFUNC_MAGIC_DEF("xor", 3, js_atomics_op, ATOMICS_OP_XOR ),
53955
    JS_CFUNC_MAGIC_DEF("exchange", 3, js_atomics_op, ATOMICS_OP_EXCHANGE ),
53956
    JS_CFUNC_MAGIC_DEF("compareExchange", 4, js_atomics_op, ATOMICS_OP_COMPARE_EXCHANGE ),
53957
    JS_CFUNC_MAGIC_DEF("load", 2, js_atomics_op, ATOMICS_OP_LOAD ),
53958
    JS_CFUNC_DEF("store", 3, js_atomics_store ),
53959
    JS_CFUNC_DEF("isLockFree", 1, js_atomics_isLockFree ),
53960
    JS_CFUNC_DEF("wait", 4, js_atomics_wait ),
53961
    JS_CFUNC_DEF("notify", 3, js_atomics_notify ),
53962
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Atomics", JS_PROP_CONFIGURABLE ),
53963
};
53964
53965
static const JSCFunctionListEntry js_atomics_obj[] = {
53966
    JS_OBJECT_DEF("Atomics", js_atomics_funcs, countof(js_atomics_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
53967
};
53968
53969
void JS_AddIntrinsicAtomics(JSContext *ctx)
53970
2
{
53971
    /* add Atomics as autoinit object */
53972
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_atomics_obj, countof(js_atomics_obj));
53973
2
}
53974
53975
#endif /* CONFIG_ATOMICS */
53976
53977
void JS_AddIntrinsicTypedArrays(JSContext *ctx)
53978
2
{
53979
2
    JSValue typed_array_base_proto, typed_array_base_func;
53980
2
    JSValueConst array_buffer_func, shared_array_buffer_func;
53981
2
    int i;
53982
53983
2
    ctx->class_proto[JS_CLASS_ARRAY_BUFFER] = JS_NewObject(ctx);
53984
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_BUFFER],
53985
2
                               js_array_buffer_proto_funcs,
53986
2
                               countof(js_array_buffer_proto_funcs));
53987
53988
2
    array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "ArrayBuffer",
53989
2
                                                 js_array_buffer_constructor, 1,
53990
2
                                                 ctx->class_proto[JS_CLASS_ARRAY_BUFFER]);
53991
2
    JS_SetPropertyFunctionList(ctx, array_buffer_func,
53992
2
                               js_array_buffer_funcs,
53993
2
                               countof(js_array_buffer_funcs));
53994
53995
2
    ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER] = JS_NewObject(ctx);
53996
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER],
53997
2
                               js_shared_array_buffer_proto_funcs,
53998
2
                               countof(js_shared_array_buffer_proto_funcs));
53999
54000
2
    shared_array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "SharedArrayBuffer",
54001
2
                                                 js_shared_array_buffer_constructor, 1,
54002
2
                                                 ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER]);
54003
2
    JS_SetPropertyFunctionList(ctx, shared_array_buffer_func,
54004
2
                               js_shared_array_buffer_funcs,
54005
2
                               countof(js_shared_array_buffer_funcs));
54006
54007
2
    typed_array_base_proto = JS_NewObject(ctx);
54008
2
    JS_SetPropertyFunctionList(ctx, typed_array_base_proto,
54009
2
                               js_typed_array_base_proto_funcs,
54010
2
                               countof(js_typed_array_base_proto_funcs));
54011
54012
    /* TypedArray.prototype.toString must be the same object as Array.prototype.toString */
54013
2
    JSValue obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_toString);
54014
    /* XXX: should use alias method in JSCFunctionListEntry */ //@@@
54015
2
    JS_DefinePropertyValue(ctx, typed_array_base_proto, JS_ATOM_toString, obj,
54016
2
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
54017
54018
2
    typed_array_base_func = JS_NewCFunction(ctx, js_typed_array_base_constructor,
54019
2
                                            "TypedArray", 0);
54020
2
    JS_SetPropertyFunctionList(ctx, typed_array_base_func,
54021
2
                               js_typed_array_base_funcs,
54022
2
                               countof(js_typed_array_base_funcs));
54023
2
    JS_SetConstructor(ctx, typed_array_base_func, typed_array_base_proto);
54024
54025
24
    for(i = JS_CLASS_UINT8C_ARRAY; i < JS_CLASS_UINT8C_ARRAY + JS_TYPED_ARRAY_COUNT; i++) {
54026
22
        JSValue func_obj;
54027
22
        char buf[ATOM_GET_STR_BUF_SIZE];
54028
22
        const char *name;
54029
54030
22
        ctx->class_proto[i] = JS_NewObjectProto(ctx, typed_array_base_proto);
54031
22
        JS_DefinePropertyValueStr(ctx, ctx->class_proto[i],
54032
22
                                  "BYTES_PER_ELEMENT",
54033
22
                                  JS_NewInt32(ctx, 1 << typed_array_size_log2(i)),
54034
22
                                  0);
54035
22
        name = JS_AtomGetStr(ctx, buf, sizeof(buf),
54036
22
                             JS_ATOM_Uint8ClampedArray + i - JS_CLASS_UINT8C_ARRAY);
54037
22
        func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_typed_array_constructor,
54038
22
                                    name, 3, JS_CFUNC_constructor_magic, i,
54039
22
                                    typed_array_base_func);
54040
22
        JS_NewGlobalCConstructor2(ctx, func_obj, name, ctx->class_proto[i]);
54041
22
        JS_DefinePropertyValueStr(ctx, func_obj,
54042
22
                                  "BYTES_PER_ELEMENT",
54043
22
                                  JS_NewInt32(ctx, 1 << typed_array_size_log2(i)),
54044
22
                                  0);
54045
22
    }
54046
2
    JS_FreeValue(ctx, typed_array_base_proto);
54047
2
    JS_FreeValue(ctx, typed_array_base_func);
54048
54049
    /* DataView */
54050
2
    ctx->class_proto[JS_CLASS_DATAVIEW] = JS_NewObject(ctx);
54051
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATAVIEW],
54052
2
                               js_dataview_proto_funcs,
54053
2
                               countof(js_dataview_proto_funcs));
54054
2
    JS_NewGlobalCConstructorOnly(ctx, "DataView",
54055
2
                                 js_dataview_constructor, 1,
54056
2
                                 ctx->class_proto[JS_CLASS_DATAVIEW]);
54057
    /* Atomics */
54058
2
#ifdef CONFIG_ATOMICS
54059
2
    JS_AddIntrinsicAtomics(ctx);
54060
2
#endif
54061
2
}