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));