| @@ -71,6 +71,12 @@ · 70 unmodified lines |
| 71 | 71 | #define CONFIG_ATOMICS |
| 72 | 72 | #endif |
| 73 | 73 | |
| 74 | +#if !defined(EMSCRIPTEN) |
| 75 | +/* enable stack limitation */ |
| 76 | +#define CONFIG_STACK_CHECK |
| 77 | +#endif |
| 78 | + |
| 79 | + |
| 74 | 80 | /* dump object free */ |
| 75 | 81 | //#define DUMP_FREE |
| 76 | 82 | //#define DUMP_CLOSURE |
| @@ -281,7 +287,9 @@ struct JSRuntime { · 204 unmodified lines |
| 281 | 287 | void *module_loader_opaque; |
| 282 | 288 | |
| 283 | 289 | BOOL can_block : 8; /* TRUE if Atomics.wait can block */ |
| 284 | | − |
| 290 | + /* used to allocate, free and clone SharedArrayBuffers */ |
| 291 | + JSSharedArrayBufferFunctions sab_funcs; |
| 292 | + |
| 285 | 293 | /* Shape hash table */ |
| 286 | 294 | int shape_hash_bits; |
| 287 | 295 | int shape_hash_size; |
| @@ -392,7 +400,7 @@ typedef struct JSBigDecimal { · 104 unmodified lines |
| 392 | 400 | typedef enum { |
| 393 | 401 | JS_AUTOINIT_ID_PROTOTYPE, |
| 394 | 402 | JS_AUTOINIT_ID_MODULE_NS, |
| 395 | | − JS_AUTOINIT_ID_PROP, /* must be last */ |
| 403 | + JS_AUTOINIT_ID_PROP, |
| 396 | 404 | } JSAutoInitIDEnum; |
| 397 | 405 | |
| 398 | 406 | /* must be large enough to have a negligible runtime cost and small |
| @@ -625,7 +633,6 @@ typedef struct JSRegExp { · 226 unmodified lines |
| 625 | 633 | typedef struct JSProxyData { |
| 626 | 634 | JSValue target; |
| 627 | 635 | JSValue handler; |
| 628 | | − JSValue proto; |
| 629 | 636 | uint8_t is_func; |
| 630 | 637 | uint8_t is_revoked; |
| 631 | 638 | } JSProxyData; |
| @@ -770,6 +777,7 @@ struct JSModuleDef { · 138 unmodified lines |
| 770 | 777 | JSValue func_obj; /* only used for JS modules */ |
| 771 | 778 | JSModuleInitFunc *init_func; /* only used for C modules */ |
| 772 | 779 | BOOL resolved : 8; |
| 780 | + BOOL func_created : 8; |
| 773 | 781 | BOOL instantiated : 8; |
| 774 | 782 | BOOL evaluated : 8; |
| 775 | 783 | BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */ |
| @@ -799,10 +807,8 @@ typedef struct JSProperty { · 23 unmodified lines |
| 799 | 807 | struct { /* JS_PROP_AUTOINIT */ |
| 800 | 808 | /* in order to use only 2 pointers, we compress the realm |
| 801 | 809 | and the init function pointer */ |
| 802 | | − union { |
| 803 | | − JSContext *realm; /* for JS_AUTOINIT_ID_PROP */ |
| 804 | | − uintptr_t init_id; /* JS_AUTOINIT_ID_x */ |
| 805 | | − } u; |
| 810 | + uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x) |
| 811 | + in the 2 low bits */ |
| 806 | 812 | void *opaque; |
| 807 | 813 | } init; |
| 808 | 814 | } u; |
| @@ -832,11 +838,13 @@ struct JSShape { · 23 unmodified lines |
| 832 | 838 | uint32_t hash; /* current hash value */ |
| 833 | 839 | uint32_t prop_hash_mask; |
| 834 | 840 | int prop_size; /* allocated properties */ |
| 835 | | − int prop_count; |
| 841 | + int prop_count; /* include deleted properties */ |
| 842 | + int deleted_prop_count; |
| 836 | 843 | JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */ |
| 837 | 844 | JSObject *proto; |
| 838 | 845 | JSShapeProperty prop[0]; /* prop_size elements */ |
| 839 | 846 | }; |
| 847 | + |
| 840 | 848 | struct JSObject { |
| 841 | 849 | union { |
| 842 | 850 | JSGCObjectHeader header; |
| @@ -850,7 +858,6 @@ struct JSObject { · 7 unmodified lines |
| 850 | 858 | uint8_t fast_array : 1; /* TRUE if u.array is used for get/put */ |
| 851 | 859 | uint8_t is_constructor : 1; /* TRUE if object is a constructor function */ |
| 852 | 860 | uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */ |
| 853 | | − uint8_t is_class : 1; /* TRUE if object is a class constructor */ |
| 854 | 861 | uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */ |
| 855 | 862 | uint16_t class_id; /* see JS_CLASS_x */ |
| 856 | 863 | }; |
| @@ -1124,7 +1131,7 @@ static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val); · 267 unmodified lines |
| 1124 | 1131 | #endif |
| 1125 | 1132 | JSValue JS_ThrowOutOfMemory(JSContext *ctx); |
| 1126 | 1133 | static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx); |
| 1127 | | −static JSValueConst js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj); |
| 1134 | +static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj); |
| 1128 | 1135 | static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj, |
| 1129 | 1136 | JSValueConst proto_val, BOOL throw_flag); |
| 1130 | 1137 | static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj); |
| @@ -1136,6 +1143,17 @@ static int JS_CreateProperty(JSContext *ctx, JSObject *p, · 5 unmodified lines |
| 1136 | 1143 | int flags); |
| 1137 | 1144 | static int js_string_memcmp(const JSString *p1, const JSString *p2, int len); |
| 1138 | 1145 | static void reset_weak_ref(JSRuntime *rt, JSObject *p); |
| 1146 | +static JSValue js_array_buffer_constructor3(JSContext *ctx, |
| 1147 | + JSValueConst new_target, |
| 1148 | + uint64_t len, JSClassID class_id, |
| 1149 | + uint8_t *buf, |
| 1150 | + JSFreeArrayBufferDataFunc *free_func, |
| 1151 | + void *opaque, BOOL alloc_flag); |
| 1152 | +static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj); |
| 1153 | +static JSValue js_typed_array_constructor(JSContext *ctx, |
| 1154 | + JSValueConst this_val, |
| 1155 | + int argc, JSValueConst *argv, |
| 1156 | + int classid); |
| 1139 | 1157 | static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p); |
| 1140 | 1158 | static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p); |
| 1141 | 1159 | static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx); |
| @@ -1212,6 +1230,7 @@ static int js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, · 70 unmodified lines |
| 1212 | 1230 | void *opaque); |
| 1213 | 1231 | static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p, |
| 1214 | 1232 | JSAtom atom, void *opaque); |
| 1233 | +void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag); |
| 1215 | 1234 | |
| 1216 | 1235 | static const JSClassExoticMethods js_arguments_exotic_methods; |
| 1217 | 1236 | static const JSClassExoticMethods js_string_exotic_methods; |
| @@ -1361,6 +1380,33 @@ char *js_strdup(JSContext *ctx, const char *str) · 143 unmodified lines |
| 1361 | 1380 | return js_strndup(ctx, str, strlen(str)); |
| 1362 | 1381 | } |
| 1363 | 1382 | |
| 1383 | +static no_inline int js_realloc_array(JSContext *ctx, void **parray, |
| 1384 | + int elem_size, int *psize, int req_size) |
| 1385 | +{ |
| 1386 | + int new_size; |
| 1387 | + size_t slack; |
| 1388 | + void *new_array; |
| 1389 | + /* XXX: potential arithmetic overflow */ |
| 1390 | + new_size = max_int(req_size, *psize * 3 / 2); |
| 1391 | + new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack); |
| 1392 | + if (!new_array) |
| 1393 | + return -1; |
| 1394 | + new_size += slack / elem_size; |
| 1395 | + *psize = new_size; |
| 1396 | + *parray = new_array; |
| 1397 | + return 0; |
| 1398 | +} |
| 1399 | + |
| 1400 | +/* resize the array and update its size if req_size > *psize */ |
| 1401 | +static inline int js_resize_array(JSContext *ctx, void **parray, int elem_size, |
| 1402 | + int *psize, int req_size) |
| 1403 | +{ |
| 1404 | + if (unlikely(req_size > *psize)) |
| 1405 | + return js_realloc_array(ctx, parray, elem_size, psize, req_size); |
| 1406 | + else |
| 1407 | + return 0; |
| 1408 | +} |
| 1409 | + |
| 1364 | 1410 | static inline void js_dbuf_init(JSContext *ctx, DynBuf *s) |
| 1365 | 1411 | { |
| 1366 | 1412 | dbuf_init2(s, ctx->rt, (DynBufReallocFunc *)js_realloc_rt); |
| @@ -1379,7 +1425,7 @@ typedef struct JSClassShortDef { · 12 unmodified lines |
| 1379 | 1425 | static JSClassShortDef const js_std_class_def[] = { |
| 1380 | 1426 | { JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_OBJECT */ |
| 1381 | 1427 | { JS_ATOM_Array, js_array_finalizer, js_array_mark }, /* JS_CLASS_ARRAY */ |
| 1382 | | − { JS_ATOM_Error, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_ERROR */ |
| 1428 | + { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */ |
| 1383 | 1429 | { JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */ |
| 1384 | 1430 | { JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */ |
| 1385 | 1431 | { JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */ |
| @@ -1426,7 +1472,7 @@ static JSClassShortDef const js_std_class_def[] = { · 40 unmodified lines |
| 1426 | 1472 | { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */ |
| 1427 | 1473 | { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */ |
| 1428 | 1474 | { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */ |
| 1429 | | − { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */ |
| 1475 | + { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */ |
| 1430 | 1476 | { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */ |
| 1431 | 1477 | }; |
| 1432 | 1478 | |
| @@ -1505,8 +1551,8 @@ static void set_dummy_numeric_ops(JSNumericOperations *ops) · 72 unmodified lines |
| 1505 | 1551 | |
| 1506 | 1552 | #endif /* CONFIG_BIGNUM */ |
| 1507 | 1553 | |
| 1508 | | −#if defined(EMSCRIPTEN) |
| 1509 | | −/* currently no stack limitation */ |
| 1554 | +#if !defined(CONFIG_STACK_CHECK) |
| 1555 | +/* no stack limitation */ |
| 1510 | 1556 | static inline uint8_t *js_get_stack_pointer(void) |
| 1511 | 1557 | { |
| 1512 | 1558 | return NULL; |
| @@ -1729,6 +1775,12 @@ void JS_SetCanBlock(JSRuntime *rt, BOOL can_block) · 216 unmodified lines |
| 1729 | 1775 | rt->can_block = can_block; |
| 1730 | 1776 | } |
| 1731 | 1777 | |
| 1778 | +void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, |
| 1779 | + const JSSharedArrayBufferFunctions *sf) |
| 1780 | +{ |
| 1781 | + rt->sab_funcs = *sf; |
| 1782 | +} |
| 1783 | + |
| 1732 | 1784 | /* return 0 if OK, < 0 if exception */ |
| 1733 | 1785 | int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, |
| 1734 | 1786 | int argc, JSValueConst *argv) |
| @@ -4262,9 +4314,10 @@ static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto, · 2527 unmodified lines |
| 4262 | 4314 | memset(sh->prop_hash_end - hash_size, 0, sizeof(sh->prop_hash_end[0]) * |
| 4263 | 4315 | hash_size); |
| 4264 | 4316 | sh->prop_hash_mask = hash_size - 1; |
| 4265 | | − sh->prop_count = 0; |
| 4266 | 4317 | sh->prop_size = prop_size; |
| 4267 | | − |
| 4318 | + sh->prop_count = 0; |
| 4319 | + sh->deleted_prop_count = 0; |
| 4320 | + |
| 4268 | 4321 | /* insert in the hash table */ |
| 4269 | 4322 | sh->hash = shape_initial_hash(proto); |
| 4270 | 4323 | sh->is_hashed = TRUE; |
| @@ -4415,6 +4468,74 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh, · 144 unmodified lines |
| 4415 | 4468 | return 0; |
| 4416 | 4469 | } |
| 4417 | 4470 | |
| 4471 | +/* remove the deleted properties. */ |
| 4472 | +static int compact_properties(JSContext *ctx, JSObject *p) |
| 4473 | +{ |
| 4474 | + JSShape *sh, *old_sh; |
| 4475 | + void *sh_alloc; |
| 4476 | + intptr_t h; |
| 4477 | + uint32_t new_hash_size, i, j, new_hash_mask, new_size; |
| 4478 | + JSShapeProperty *old_pr, *pr; |
| 4479 | + JSProperty *prop, *new_prop; |
| 4480 | + |
| 4481 | + sh = p->shape; |
| 4482 | + assert(!sh->is_hashed); |
| 4483 | + |
| 4484 | + new_size = max_int(JS_PROP_INITIAL_SIZE, |
| 4485 | + sh->prop_count - sh->deleted_prop_count); |
| 4486 | + assert(new_size <= sh->prop_size); |
| 4487 | + |
| 4488 | + new_hash_size = sh->prop_hash_mask + 1; |
| 4489 | + while ((new_hash_size / 2) >= new_size) |
| 4490 | + new_hash_size = new_hash_size / 2; |
| 4491 | + new_hash_mask = new_hash_size - 1; |
| 4492 | + |
| 4493 | + /* resize the hash table and the properties */ |
| 4494 | + old_sh = sh; |
| 4495 | + sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size)); |
| 4496 | + if (!sh_alloc) |
| 4497 | + return -1; |
| 4498 | + sh = get_shape_from_alloc(sh_alloc, new_hash_size); |
| 4499 | + list_del(&old_sh->header.link); |
| 4500 | + memcpy(sh, old_sh, sizeof(JSShape)); |
| 4501 | + list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); |
| 4502 | + |
| 4503 | + memset(sh->prop_hash_end - new_hash_size, 0, |
| 4504 | + sizeof(sh->prop_hash_end[0]) * new_hash_size); |
| 4505 | + |
| 4506 | + j = 0; |
| 4507 | + old_pr = old_sh->prop; |
| 4508 | + pr = sh->prop; |
| 4509 | + prop = p->prop; |
| 4510 | + for(i = 0; i < sh->prop_count; i++) { |
| 4511 | + if (old_pr->atom != JS_ATOM_NULL) { |
| 4512 | + pr->atom = old_pr->atom; |
| 4513 | + pr->flags = old_pr->flags; |
| 4514 | + h = ((uintptr_t)old_pr->atom & new_hash_mask); |
| 4515 | + pr->hash_next = sh->prop_hash_end[-h - 1]; |
| 4516 | + sh->prop_hash_end[-h - 1] = j + 1; |
| 4517 | + prop[j] = prop[i]; |
| 4518 | + j++; |
| 4519 | + pr++; |
| 4520 | + } |
| 4521 | + old_pr++; |
| 4522 | + } |
| 4523 | + assert(j == (sh->prop_count - sh->deleted_prop_count)); |
| 4524 | + sh->prop_hash_mask = new_hash_mask; |
| 4525 | + sh->prop_size = new_size; |
| 4526 | + sh->deleted_prop_count = 0; |
| 4527 | + sh->prop_count = j; |
| 4528 | + |
| 4529 | + p->shape = sh; |
| 4530 | + js_free(ctx, get_alloc_from_shape(old_sh)); |
| 4531 | + |
| 4532 | + /* reduce the size of the object properties */ |
| 4533 | + new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size); |
| 4534 | + if (new_prop) |
| 4535 | + p->prop = new_prop; |
| 4536 | + return 0; |
| 4537 | +} |
| 4538 | + |
| 4418 | 4539 | static int add_shape_property(JSContext *ctx, JSShape **psh, |
| 4419 | 4540 | JSObject *p, JSAtom atom, int prop_flags) |
| 4420 | 4541 | { |
| @@ -4571,7 +4692,6 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas · 150 unmodified lines |
| 4571 | 4692 | p->fast_array = 0; |
| 4572 | 4693 | p->is_constructor = 0; |
| 4573 | 4694 | p->is_uncatchable_error = 0; |
| 4574 | | − p->is_class = 0; |
| 4575 | 4695 | p->tmp_mark = 0; |
| 4576 | 4696 | p->first_weak_ref = NULL; |
| 4577 | 4697 | p->u.opaque = NULL; |
| @@ -4621,7 +4741,6 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas · 43 unmodified lines |
| 4621 | 4741 | p->u.array.u.ptr = NULL; |
| 4622 | 4742 | p->u.array.count = 0; |
| 4623 | 4743 | break; |
| 4624 | | − case JS_CLASS_ERROR: |
| 4625 | 4744 | case JS_CLASS_NUMBER: |
| 4626 | 4745 | case JS_CLASS_STRING: |
| 4627 | 4746 | case JS_CLASS_BOOLEAN: |
| @@ -4967,19 +5086,25 @@ JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, · 339 unmodified lines |
| 4967 | 5086 | return func_obj; |
| 4968 | 5087 | } |
| 4969 | 5088 | |
| 5089 | +static JSContext *js_autoinit_get_realm(JSProperty *pr) |
| 5090 | +{ |
| 5091 | + return (JSContext *)(pr->u.init.realm_and_id & ~3); |
| 5092 | +} |
| 5093 | + |
| 5094 | +static JSAutoInitIDEnum js_autoinit_get_id(JSProperty *pr) |
| 5095 | +{ |
| 5096 | + return pr->u.init.realm_and_id & 3; |
| 5097 | +} |
| 5098 | + |
| 4970 | 5099 | static void js_autoinit_free(JSRuntime *rt, JSProperty *pr) |
| 4971 | 5100 | { |
| 4972 | | − if (pr->u.init.u.init_id >= JS_AUTOINIT_ID_PROP) { |
| 4973 | | − JS_FreeContext(pr->u.init.u.realm); |
| 4974 | | − } |
| 5101 | + JS_FreeContext(js_autoinit_get_realm(pr)); |
| 4975 | 5102 | } |
| 4976 | 5103 | |
| 4977 | 5104 | static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr, |
| 4978 | 5105 | JS_MarkFunc *mark_func) |
| 4979 | 5106 | { |
| 4980 | | − if (pr->u.init.u.init_id >= JS_AUTOINIT_ID_PROP) { |
| 4981 | | − mark_func(rt, &pr->u.init.u.realm->header); |
| 4982 | | − } |
| 5107 | + mark_func(rt, &js_autoinit_get_realm(pr)->header); |
| 4983 | 5108 | } |
| 4984 | 5109 | |
| 4985 | 5110 | static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags) |
| @@ -6331,7 +6456,7 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj, · 1345 unmodified lines |
| 6331 | 6456 | backtrace_barrier = FALSE; |
| 6332 | 6457 | if (js_class_has_bytecode(p->class_id)) { |
| 6333 | 6458 | JSFunctionBytecode *b; |
| 6334 | | − char atom_buf[ATOM_GET_STR_BUF_SIZE]; |
| 6459 | + const char *atom_str; |
| 6335 | 6460 | int line_num1; |
| 6336 | 6461 | |
| 6337 | 6462 | b = p->u.func.function_bytecode; |
| @@ -6339,9 +6464,10 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj, · 1 unmodified line |
| 6339 | 6464 | if (b->has_debug) { |
| 6340 | 6465 | line_num1 = find_line_num(ctx, b, |
| 6341 | 6466 | sf->cur_pc - b->byte_code_buf - 1); |
| 6467 | + atom_str = JS_AtomToCString(ctx, b->debug.filename); |
| 6342 | 6468 | dbuf_printf(&dbuf, " (%s", |
| 6343 | | − JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), |
| 6344 | | − b->debug.filename)); |
| 6469 | + atom_str ? atom_str : "<null>"); |
| 6470 | + JS_FreeCString(ctx, atom_str); |
| 6345 | 6471 | if (line_num1 != -1) |
| 6346 | 6472 | dbuf_printf(&dbuf, ":%d", line_num1); |
| 6347 | 6473 | dbuf_putc(&dbuf, ')'); |
| @@ -6459,13 +6585,32 @@ static int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSCont · 111 unmodified lines |
| 6459 | 6585 | } |
| 6460 | 6586 | } |
| 6461 | 6587 | |
| 6588 | +/* never use it directly */ |
| 6589 | +static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...) |
| 6590 | +{ |
| 6591 | + char buf[ATOM_GET_STR_BUF_SIZE]; |
| 6592 | + return JS_ThrowTypeError(ctx, fmt, |
| 6593 | + JS_AtomGetStr(ctx, buf, sizeof(buf), atom)); |
| 6594 | +} |
| 6595 | + |
| 6596 | +/* never use it directly */ |
| 6597 | +static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...) |
| 6598 | +{ |
| 6599 | + char buf[ATOM_GET_STR_BUF_SIZE]; |
| 6600 | + return JS_ThrowSyntaxError(ctx, fmt, |
| 6601 | + JS_AtomGetStr(ctx, buf, sizeof(buf), atom)); |
| 6602 | +} |
| 6603 | + |
| 6604 | +/* %s is replaced by 'atom'. The macro is used so that gcc can check |
| 6605 | + the format string. */ |
| 6606 | +#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, "") |
| 6607 | +#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, "") |
| 6608 | + |
| 6462 | 6609 | static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom) |
| 6463 | 6610 | { |
| 6464 | 6611 | if ((flags & JS_PROP_THROW) || |
| 6465 | 6612 | ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { |
| 6466 | | − char buf[ATOM_GET_STR_BUF_SIZE]; |
| 6467 | | − JS_ThrowTypeError(ctx, "%s is read-only", |
| 6468 | | − JS_AtomGetStr(ctx, buf, sizeof(buf), atom)); |
| 6613 | + JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom); |
| 6469 | 6614 | return -1; |
| 6470 | 6615 | } else { |
| 6471 | 6616 | return FALSE; |
| @@ -6534,7 +6679,7 @@ static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx) · 62 unmodified lines |
| 6534 | 6679 | static JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name) |
| 6535 | 6680 | { |
| 6536 | 6681 | char buf[ATOM_GET_STR_BUF_SIZE]; |
| 6537 | | − return JS_ThrowReferenceError(ctx, "%s is not defined", |
| 6682 | + return JS_ThrowReferenceError(ctx, "'%s' is not defined", |
| 6538 | 6683 | JS_AtomGetStr(ctx, buf, sizeof(buf), name)); |
| 6539 | 6684 | } |
| 6540 | 6685 | |
| @@ -6549,11 +6694,33 @@ static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name) · 8 unmodified lines |
| 6549 | 6694 | static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id) |
| 6550 | 6695 | { |
| 6551 | 6696 | JSRuntime *rt = ctx->rt; |
| 6552 | | − char buf[ATOM_GET_STR_BUF_SIZE]; |
| 6553 | 6697 | JSAtom name; |
| 6554 | 6698 | name = rt->class_array[class_id].class_name; |
| 6555 | | − return JS_ThrowTypeError(ctx, "%s object expected", |
| 6556 | | − JS_AtomGetStr(ctx, buf, sizeof(buf), name)); |
| 6699 | + return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name); |
| 6700 | +} |
| 6701 | + |
| 6702 | +static no_inline __exception int __js_poll_interrupts(JSContext *ctx) |
| 6703 | +{ |
| 6704 | + JSRuntime *rt = ctx->rt; |
| 6705 | + ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT; |
| 6706 | + if (rt->interrupt_handler) { |
| 6707 | + if (rt->interrupt_handler(rt, rt->interrupt_opaque)) { |
| 6708 | + /* XXX: should set a specific flag to avoid catching */ |
| 6709 | + JS_ThrowInternalError(ctx, "interrupted"); |
| 6710 | + JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE); |
| 6711 | + return -1; |
| 6712 | + } |
| 6713 | + } |
| 6714 | + return 0; |
| 6715 | +} |
| 6716 | + |
| 6717 | +static inline __exception int js_poll_interrupts(JSContext *ctx) |
| 6718 | +{ |
| 6719 | + if (unlikely(--ctx->interrupt_counter <= 0)) { |
| 6720 | + return __js_poll_interrupts(ctx); |
| 6721 | + } else { |
| 6722 | + return 0; |
| 6723 | + } |
| 6557 | 6724 | } |
| 6558 | 6725 | |
| 6559 | 6726 | /* return -1 (exception) or TRUE/FALSE */ |
| @@ -6633,11 +6800,9 @@ int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val) · 73 unmodified lines |
| 6633 | 6800 | return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE); |
| 6634 | 6801 | } |
| 6635 | 6802 | |
| 6636 | | −/* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */ |
| 6637 | | −JSValueConst JS_GetPrototype(JSContext *ctx, JSValueConst val) |
| 6803 | +/* Only works for primitive types, otherwise return JS_NULL. */ |
| 6804 | +static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val) |
| 6638 | 6805 | { |
| 6639 | | − JSObject *p; |
| 6640 | | − |
| 6641 | 6806 | switch(JS_VALUE_GET_NORM_TAG(val)) { |
| 6642 | 6807 | #ifdef CONFIG_BIGNUM |
| 6643 | 6808 | case JS_TAG_BIG_INT: |
| @@ -6664,26 +6829,45 @@ JSValueConst JS_GetPrototype(JSContext *ctx, JSValueConst val) · 20 unmodified lines |
| 6664 | 6829 | val = ctx->class_proto[JS_CLASS_SYMBOL]; |
| 6665 | 6830 | break; |
| 6666 | 6831 | case JS_TAG_OBJECT: |
| 6667 | | − p = JS_VALUE_GET_OBJ(val); |
| 6832 | + case JS_TAG_NULL: |
| 6833 | + case JS_TAG_UNDEFINED: |
| 6834 | + default: |
| 6835 | + val = JS_NULL; |
| 6836 | + break; |
| 6837 | + } |
| 6838 | + return val; |
| 6839 | +} |
| 6840 | + |
| 6841 | +/* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */ |
| 6842 | +JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj) |
| 6843 | +{ |
| 6844 | + JSValue val; |
| 6845 | + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { |
| 6846 | + JSObject *p; |
| 6847 | + p = JS_VALUE_GET_OBJ(obj); |
| 6668 | 6848 | if (unlikely(p->class_id == JS_CLASS_PROXY)) { |
| 6669 | | − val = js_proxy_getPrototypeOf(ctx, val); |
| 6849 | + val = js_proxy_getPrototypeOf(ctx, obj); |
| 6670 | 6850 | } else { |
| 6671 | 6851 | p = p->shape->proto; |
| 6672 | 6852 | if (!p) |
| 6673 | 6853 | val = JS_NULL; |
| 6674 | 6854 | else |
| 6675 | | − val = JS_MKPTR(JS_TAG_OBJECT, p); |
| 6855 | + val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); |
| 6676 | 6856 | } |
| 6677 | | − break; |
| 6678 | | − case JS_TAG_NULL: |
| 6679 | | − case JS_TAG_UNDEFINED: |
| 6680 | | − default: |
| 6681 | | − val = JS_NULL; |
| 6682 | | − break; |
| 6857 | + } else { |
| 6858 | + val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj)); |
| 6683 | 6859 | } |
| 6684 | 6860 | return val; |
| 6685 | 6861 | } |
| 6686 | 6862 | |
| 6863 | +static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj) |
| 6864 | +{ |
| 6865 | + JSValue obj1; |
| 6866 | + obj1 = JS_GetPrototype(ctx, obj); |
| 6867 | + JS_FreeValue(ctx, obj); |
| 6868 | + return obj1; |
| 6869 | +} |
| 6870 | + |
| 6687 | 6871 | /* return TRUE, FALSE or (-1) in case of exception */ |
| 6688 | 6872 | static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, |
| 6689 | 6873 | JSValueConst obj) |
| @@ -6704,7 +6888,6 @@ static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, · 14 unmodified lines |
| 6704 | 6888 | /* Only explicitly boxed values are instances of constructors */ |
| 6705 | 6889 | if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) |
| 6706 | 6890 | return FALSE; |
| 6707 | | − ret = FALSE; |
| 6708 | 6891 | obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype); |
| 6709 | 6892 | if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) { |
| 6710 | 6893 | if (!JS_IsException(obj_proto)) |
| @@ -6717,19 +6900,36 @@ static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, · 6 unmodified lines |
| 6717 | 6900 | for(;;) { |
| 6718 | 6901 | proto1 = p->shape->proto; |
| 6719 | 6902 | if (!proto1) { |
| 6720 | | − if (p->class_id == JS_CLASS_PROXY) { |
| 6721 | | − JSValueConst proto_val; |
| 6722 | | − proto_val = JS_GetPrototype(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p)); |
| 6723 | | − if (JS_IsException(proto_val)) { |
| 6724 | | − ret = -1; |
| 6725 | | − goto done; |
| 6903 | + /* slow case if proxy in the prototype chain */ |
| 6904 | + if (unlikely(p->class_id == JS_CLASS_PROXY)) { |
| 6905 | + JSValue obj1; |
| 6906 | + obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p)); |
| 6907 | + for(;;) { |
| 6908 | + obj1 = JS_GetPrototypeFree(ctx, obj1); |
| 6909 | + if (JS_IsException(obj1)) { |
| 6910 | + ret = -1; |
| 6911 | + break; |
| 6912 | + } |
| 6913 | + if (JS_IsNull(obj1)) { |
| 6914 | + ret = FALSE; |
| 6915 | + break; |
| 6916 | + } |
| 6917 | + if (proto == JS_VALUE_GET_OBJ(obj1)) { |
| 6918 | + JS_FreeValue(ctx, obj1); |
| 6919 | + ret = TRUE; |
| 6920 | + break; |
| 6921 | + } |
| 6922 | + /* must check for timeout to avoid infinite loop */ |
| 6923 | + if (js_poll_interrupts(ctx)) { |
| 6924 | + JS_FreeValue(ctx, obj1); |
| 6925 | + ret = -1; |
| 6926 | + break; |
| 6927 | + } |
| 6726 | 6928 | } |
| 6727 | | − proto1 = JS_VALUE_GET_OBJ(proto_val); |
| 6728 | | − if (!proto1) |
| 6729 | | − break; |
| 6730 | 6929 | } else { |
| 6731 | | − break; |
| 6930 | + ret = FALSE; |
| 6732 | 6931 | } |
| 6932 | + break; |
| 6733 | 6933 | } |
| 6734 | 6934 | p = proto1; |
| 6735 | 6935 | if (proto == p) { |
| @@ -6767,28 +6967,24 @@ int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj) · 31 unmodified lines |
| 6767 | 6967 | return JS_OrdinaryIsInstanceOf(ctx, val, obj); |
| 6768 | 6968 | } |
| 6769 | 6969 | |
| 6770 | | −static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, JSProperty *pr) |
| 6970 | +typedef int JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); |
| 6971 | + |
| 6972 | +static JSAutoInitFunc *js_autoinit_func_table[] = { |
| 6973 | + js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */ |
| 6974 | + js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */ |
| 6975 | + JS_InstantiateFunctionListItem, /* JS_AUTOINIT_ID_PROP */ |
| 6976 | +}; |
| 6977 | + |
| 6978 | +static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, |
| 6979 | + JSProperty *pr) |
| 6771 | 6980 | { |
| 6772 | 6981 | int ret; |
| 6773 | 6982 | JSContext *realm; |
| 6774 | | − |
| 6775 | | − if (pr->u.init.u.init_id >= JS_AUTOINIT_ID_PROP) { |
| 6776 | | − realm = pr->u.init.u.realm; |
| 6777 | | − ret = JS_InstantiateFunctionListItem(realm, p, prop, pr->u.init.opaque); |
| 6778 | | − if (ret) |
| 6779 | | − return ret; |
| 6780 | | − } else { |
| 6781 | | − switch(pr->u.init.u.init_id) { |
| 6782 | | − case JS_AUTOINIT_ID_PROTOTYPE: |
| 6783 | | − ret = js_instantiate_prototype(ctx, p, prop, pr->u.init.opaque); |
| 6784 | | − break; |
| 6785 | | − case JS_AUTOINIT_ID_MODULE_NS: |
| 6786 | | − ret = js_module_ns_autoinit(ctx, p, prop, pr->u.init.opaque); |
| 6787 | | − break; |
| 6788 | | − default: |
| 6789 | | − abort(); |
| 6790 | | − } |
| 6791 | | − } |
| 6983 | + JSAutoInitFunc *func; |
| 6984 | + |
| 6985 | + realm = js_autoinit_get_realm(pr); |
| 6986 | + func = js_autoinit_func_table[js_autoinit_get_id(pr)]; |
| 6987 | + ret = func(realm, p, prop, pr->u.init.opaque); |
| 6792 | 6988 | return ret; |
| 6793 | 6989 | } |
| 6794 | 6990 | |
| @@ -6805,8 +7001,9 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, · 10 unmodified lines |
| 6805 | 7001 | if (unlikely(tag != JS_TAG_OBJECT)) { |
| 6806 | 7002 | switch(tag) { |
| 6807 | 7003 | case JS_TAG_NULL: |
| 7004 | + return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop); |
| 6808 | 7005 | case JS_TAG_UNDEFINED: |
| 6809 | | − return JS_ThrowTypeError(ctx, "value has no property"); |
| 7006 | + return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop); |
| 6810 | 7007 | case JS_TAG_EXCEPTION: |
| 6811 | 7008 | return JS_EXCEPTION; |
| 6812 | 7009 | case JS_TAG_STRING: |
| @@ -6831,7 +7028,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, · 18 unmodified lines |
| 6831 | 7028 | break; |
| 6832 | 7029 | } |
| 6833 | 7030 | /* cannot raise an exception */ |
| 6834 | | − p = JS_VALUE_GET_OBJ(JS_GetPrototype(ctx, obj)); |
| 7031 | + p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj)); |
| 6835 | 7032 | if (!p) |
| 6836 | 7033 | return JS_UNDEFINED; |
| 6837 | 7034 | } else { |
| @@ -6896,15 +7093,25 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, · 58 unmodified lines |
| 6896 | 7093 | const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; |
| 6897 | 7094 | if (em) { |
| 6898 | 7095 | if (em->get_property) { |
| 7096 | + JSValue obj1, retval; |
| 6899 | 7097 | /* XXX: should pass throw_ref_error */ |
| 6900 | | − return em->get_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), |
| 6901 | | − prop, this_obj); |
| 7098 | + /* Note: if 'p' is a prototype, it can be |
| 7099 | + freed in the called function */ |
| 7100 | + obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); |
| 7101 | + retval = em->get_property(ctx, obj1, prop, this_obj); |
| 7102 | + JS_FreeValue(ctx, obj1); |
| 7103 | + return retval; |
| 6902 | 7104 | } |
| 6903 | 7105 | if (em->get_own_property) { |
| 6904 | 7106 | JSPropertyDescriptor desc; |
| 6905 | 7107 | int ret; |
| 7108 | + JSValue obj1; |
| 6906 | 7109 | |
| 6907 | | − ret = em->get_own_property(ctx, &desc, JS_MKPTR(JS_TAG_OBJECT, p), prop); |
| 7110 | + /* Note: if 'p' is a prototype, it can be |
| 7111 | + freed in the called function */ |
| 7112 | + obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); |
| 7113 | + ret = em->get_own_property(ctx, &desc, obj1, prop); |
| 7114 | + JS_FreeValue(ctx, obj1); |
| 6908 | 7115 | if (ret < 0) |
| 6909 | 7116 | return JS_EXCEPTION; |
| 6910 | 7117 | if (ret) { |
| @@ -6932,9 +7139,8 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, · 21 unmodified lines |
| 6932 | 7139 | |
| 6933 | 7140 | static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom) |
| 6934 | 7141 | { |
| 6935 | | − char buf[ATOM_GET_STR_BUF_SIZE]; |
| 6936 | | − return JS_ThrowTypeError(ctx, "private class field %s does not exist", |
| 6937 | | − JS_AtomGetStr(ctx, buf, sizeof(buf), atom)); |
| 7142 | + return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist", |
| 7143 | + atom); |
| 6938 | 7144 | } |
| 6939 | 7145 | |
| 6940 | 7146 | /* Private fields can be added even on non extensible objects or |
| @@ -6960,9 +7166,8 @@ static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj, · 19 unmodified lines |
| 6960 | 7166 | p = JS_VALUE_GET_OBJ(obj); |
| 6961 | 7167 | prs = find_own_property(&pr, p, prop); |
| 6962 | 7168 | if (prs) { |
| 6963 | | − char buf[ATOM_GET_STR_BUF_SIZE]; |
| 6964 | | − JS_ThrowTypeError(ctx, "private class field %s already exists", |
| 6965 | | − JS_AtomGetStr(ctx, buf, sizeof(buf), prop)); |
| 7169 | + JS_ThrowTypeErrorAtom(ctx, "private class field '%s' already exists", |
| 7170 | + prop); |
| 6966 | 7171 | goto fail; |
| 6967 | 7172 | } |
| 6968 | 7173 | pr = add_property(ctx, p, prop, JS_PROP_C_W_E); |
| @@ -7211,7 +7416,9 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, · 242 unmodified lines |
| 7211 | 7416 | JS_ThrowTypeErrorDetachedArrayBuffer(ctx); |
| 7212 | 7417 | return -1; |
| 7213 | 7418 | } |
| 7214 | | − num_keys_count += p->u.array.count; |
| 7419 | + if (flags & JS_GPN_STRING_MASK) { |
| 7420 | + num_keys_count += p->u.array.count; |
| 7421 | + } |
| 7215 | 7422 | } else { |
| 7216 | 7423 | const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; |
| 7217 | 7424 | if (em && em->get_own_property_names) { |
| @@ -7293,15 +7500,17 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, · 75 unmodified lines |
| 7293 | 7500 | |
| 7294 | 7501 | if (p->is_exotic) { |
| 7295 | 7502 | if (p->fast_array) { |
| 7296 | | − for(i = 0; i < p->u.array.count; i++) { |
| 7297 | | − tab_atom[num_index].atom = __JS_AtomFromUInt32(i); |
| 7298 | | − if (tab_atom[num_index].atom == JS_ATOM_NULL) { |
| 7299 | | − js_free_prop_enum(ctx, tab_exotic, exotic_count); |
| 7300 | | − js_free_prop_enum(ctx, tab_atom, num_index); |
| 7301 | | − return -1; |
| 7503 | + if (flags & JS_GPN_STRING_MASK) { |
| 7504 | + for(i = 0; i < p->u.array.count; i++) { |
| 7505 | + tab_atom[num_index].atom = __JS_AtomFromUInt32(i); |
| 7506 | + if (tab_atom[num_index].atom == JS_ATOM_NULL) { |
| 7507 | + js_free_prop_enum(ctx, tab_exotic, exotic_count); |
| 7508 | + js_free_prop_enum(ctx, tab_atom, num_index); |
| 7509 | + return -1; |
| 7510 | + } |
| 7511 | + tab_atom[num_index].is_enumerable = TRUE; |
| 7512 | + num_index++; |
| 7302 | 7513 | } |
| 7303 | | − tab_atom[num_index].is_enumerable = TRUE; |
| 7304 | | − num_index++; |
| 7305 | 7514 | } |
| 7306 | 7515 | } |
| 7307 | 7516 | if (exotic_count > 0) { |
| @@ -7492,6 +7701,7 @@ int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop) · 184 unmodified lines |
| 7492 | 7701 | { |
| 7493 | 7702 | JSObject *p; |
| 7494 | 7703 | int ret; |
| 7704 | + JSValue obj1; |
| 7495 | 7705 | |
| 7496 | 7706 | if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) |
| 7497 | 7707 | return FALSE; |
| @@ -7499,10 +7709,18 @@ int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop) · 1 unmodified line |
| 7499 | 7709 | for(;;) { |
| 7500 | 7710 | if (p->is_exotic) { |
| 7501 | 7711 | const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; |
| 7502 | | − if (em && em->has_property) |
| 7503 | | − return em->has_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), prop); |
| 7712 | + if (em && em->has_property) { |
| 7713 | + /* has_property can free the prototype */ |
| 7714 | + obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); |
| 7715 | + ret = em->has_property(ctx, obj1, prop); |
| 7716 | + JS_FreeValue(ctx, obj1); |
| 7717 | + return ret; |
| 7718 | + } |
| 7504 | 7719 | } |
| 7720 | + /* JS_GetOwnPropertyInternal can free the prototype */ |
| 7721 | + JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); |
| 7505 | 7722 | ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop); |
| 7723 | + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); |
| 7506 | 7724 | if (ret != 0) |
| 7507 | 7725 | return ret; |
| 7508 | 7726 | if (p->class_id >= JS_CLASS_UINT8C_ARRAY && |
| @@ -7799,6 +8017,7 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) · 290 unmodified lines |
| 7799 | 8017 | } else { |
| 7800 | 8018 | sh->prop_hash_end[-h1 - 1] = pr->hash_next; |
| 7801 | 8019 | } |
| 8020 | + sh->deleted_prop_count++; |
| 7802 | 8021 | /* free the entry */ |
| 7803 | 8022 | pr1 = &p->prop[h - 1]; |
| 7804 | 8023 | free_property(ctx->rt, pr1, pr->flags); |
| @@ -7807,6 +8026,12 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) · 2 unmodified lines |
| 7807 | 8026 | pr->flags = 0; |
| 7808 | 8027 | pr->atom = JS_ATOM_NULL; |
| 7809 | 8028 | pr1->u.value = JS_UNDEFINED; |
| 8029 | + |
| 8030 | + /* compact the properties if too many deleted properties */ |
| 8031 | + if (sh->deleted_prop_count >= 8 && |
| 8032 | + sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) { |
| 8033 | + compact_properties(ctx, p); |
| 8034 | + } |
| 7810 | 8035 | return TRUE; |
| 7811 | 8036 | } |
| 7812 | 8037 | lpr = pr; |
| @@ -8016,8 +8241,12 @@ static int JS_SetPropertyGeneric(JSContext *ctx, · 203 unmodified lines |
| 8016 | 8241 | if (p->is_exotic) { |
| 8017 | 8242 | const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; |
| 8018 | 8243 | if (em && em->set_property) { |
| 8019 | | − ret = em->set_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), prop, |
| 8244 | + JSValue obj1; |
| 8245 | + /* set_property can free the prototype */ |
| 8246 | + obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); |
| 8247 | + ret = em->set_property(ctx, obj1, prop, |
| 8020 | 8248 | val, this_obj, flags); |
| 8249 | + JS_FreeValue(ctx, obj1); |
| 8021 | 8250 | JS_FreeValue(ctx, val); |
| 8022 | 8251 | return ret; |
| 8023 | 8252 | } |
| @@ -8110,14 +8339,17 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, · 86 unmodified lines |
| 8110 | 8339 | if (unlikely(tag != JS_TAG_OBJECT)) { |
| 8111 | 8340 | switch(tag) { |
| 8112 | 8341 | case JS_TAG_NULL: |
| 8342 | + JS_FreeValue(ctx, val); |
| 8343 | + JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop); |
| 8344 | + return -1; |
| 8113 | 8345 | case JS_TAG_UNDEFINED: |
| 8114 | 8346 | JS_FreeValue(ctx, val); |
| 8115 | | − JS_ThrowTypeError(ctx, "value has no property"); |
| 8347 | + JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop); |
| 8116 | 8348 | return -1; |
| 8117 | 8349 | default: |
| 8118 | 8350 | /* even on a primitive type we can have setters on the prototype */ |
| 8119 | 8351 | p = NULL; |
| 8120 | | − p1 = JS_VALUE_GET_OBJ(JS_GetPrototype(ctx, this_obj)); |
| 8352 | + p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, this_obj)); |
| 8121 | 8353 | goto prototype_lookup; |
| 8122 | 8354 | } |
| 8123 | 8355 | } |
| @@ -8195,15 +8427,22 @@ retry: · 71 unmodified lines |
| 8195 | 8427 | } else { |
| 8196 | 8428 | const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic; |
| 8197 | 8429 | if (em) { |
| 8430 | + JSValue obj1; |
| 8198 | 8431 | if (em->set_property) { |
| 8199 | | − ret = em->set_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p1), prop, |
| 8432 | + /* set_property can free the prototype */ |
| 8433 | + obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); |
| 8434 | + ret = em->set_property(ctx, obj1, prop, |
| 8200 | 8435 | val, this_obj, flags); |
| 8436 | + JS_FreeValue(ctx, obj1); |
| 8201 | 8437 | JS_FreeValue(ctx, val); |
| 8202 | 8438 | return ret; |
| 8203 | 8439 | } |
| 8204 | 8440 | if (em->get_own_property) { |
| 8441 | + /* get_own_property can free the prototype */ |
| 8442 | + obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); |
| 8205 | 8443 | ret = em->get_own_property(ctx, &desc, |
| 8206 | | − JS_MKPTR(JS_TAG_OBJECT, p1), prop); |
| 8444 | + obj1, prop); |
| 8445 | + JS_FreeValue(ctx, obj1); |
| 8207 | 8446 | if (ret < 0) { |
| 8208 | 8447 | JS_FreeValue(ctx, val); |
| 8209 | 8448 | return ret; |
| @@ -8973,11 +9212,10 @@ static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj, · 763 unmodified lines |
| 8973 | 9212 | pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT); |
| 8974 | 9213 | if (unlikely(!pr)) |
| 8975 | 9214 | return -1; |
| 8976 | | − if (id == JS_AUTOINIT_ID_PROP) { |
| 8977 | | − pr->u.init.u.realm = JS_DupContext(ctx); |
| 8978 | | − } else { |
| 8979 | | − pr->u.init.u.init_id = id; |
| 8980 | | − } |
| 9215 | + pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx); |
| 9216 | + assert((pr->u.init.realm_and_id & 3) == 0); |
| 9217 | + assert(id <= 3); |
| 9218 | + pr->u.init.realm_and_id |= id; |
| 8981 | 9219 | pr->u.init.opaque = opaque; |
| 8982 | 9220 | return TRUE; |
| 8983 | 9221 | } |
| @@ -9114,9 +9352,7 @@ static int JS_DefineObjectNameComputed(JSContext *ctx, JSValueConst obj, · 130 unmodified lines |
| 9114 | 9352 | |
| 9115 | 9353 | static JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop) |
| 9116 | 9354 | { |
| 9117 | | − char buf[ATOM_GET_STR_BUF_SIZE]; |
| 9118 | | − return JS_ThrowSyntaxError(ctx, "redeclaration of %s", |
| 9119 | | − JS_AtomGetStr(ctx, buf, sizeof(buf), prop)); |
| 9355 | + return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop); |
| 9120 | 9356 | } |
| 9121 | 9357 | |
| 9122 | 9358 | /* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */ |
| @@ -9125,7 +9361,6 @@ static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags) · 2 unmodified lines |
| 9125 | 9361 | { |
| 9126 | 9362 | JSObject *p; |
| 9127 | 9363 | JSShapeProperty *prs; |
| 9128 | | − char buf[ATOM_GET_STR_BUF_SIZE]; |
| 9129 | 9364 | |
| 9130 | 9365 | p = JS_VALUE_GET_OBJ(ctx->global_obj); |
| 9131 | 9366 | prs = find_own_property1(p, prop); |
| @@ -9143,8 +9378,8 @@ static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags) · 11 unmodified lines |
| 9143 | 9378 | ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) != |
| 9144 | 9379 | (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) { |
| 9145 | 9380 | define_error: |
| 9146 | | − JS_ThrowTypeError(ctx, "cannot define variable %s", |
| 9147 | | − JS_AtomGetStr(ctx, buf, sizeof(buf), prop)); |
| 9381 | + JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'", |
| 9382 | + prop); |
| 9148 | 9383 | return -1; |
| 9149 | 9384 | } |
| 9150 | 9385 | } |
| @@ -11395,7 +11630,9 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) · 2244 unmodified lines |
| 11395 | 11630 | } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { |
| 11396 | 11631 | printf("[varref %p]", (void *)pr->u.var_ref); |
| 11397 | 11632 | } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { |
| 11398 | | − printf("[autoinit %p %p]", (void *)pr->u.init.u.realm, |
| 11633 | + printf("[autoinit %p %d %p]", |
| 11634 | + (void *)js_autoinit_get_realm(pr), |
| 11635 | + js_autoinit_get_id(pr), |
| 11399 | 11636 | (void *)pr->u.init.opaque); |
| 11400 | 11637 | } else { |
| 11401 | 11638 | JS_DumpValueShort(rt, pr->u.value); |
| @@ -15726,30 +15963,6 @@ static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj, · 4324 unmodified lines |
| 15726 | 15963 | } |
| 15727 | 15964 | } |
| 15728 | 15965 | |
| 15729 | | −static no_inline __exception int __js_poll_interrupts(JSContext *ctx) |
| 15730 | | −{ |
| 15731 | | − JSRuntime *rt = ctx->rt; |
| 15732 | | − ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT; |
| 15733 | | − if (rt->interrupt_handler) { |
| 15734 | | − if (rt->interrupt_handler(rt, rt->interrupt_opaque)) { |
| 15735 | | − /* XXX: should set a specific flag to avoid catching */ |
| 15736 | | − JS_ThrowInternalError(ctx, "interrupted"); |
| 15737 | | − JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE); |
| 15738 | | − return -1; |
| 15739 | | − } |
| 15740 | | − } |
| 15741 | | − return 0; |
| 15742 | | −} |
| 15743 | | − |
| 15744 | | −static inline __exception int js_poll_interrupts(JSContext *ctx) |
| 15745 | | −{ |
| 15746 | | − if (unlikely(--ctx->interrupt_counter <= 0)) { |
| 15747 | | − return __js_poll_interrupts(ctx); |
| 15748 | | − } else { |
| 15749 | | − return 0; |
| 15750 | | − } |
| 15751 | | −} |
| 15752 | | − |
| 15753 | 15966 | /* argument of OP_special_object */ |
| 15754 | 15967 | typedef enum { |
| 15755 | 15968 | OP_SPECIAL_OBJECT_ARGUMENTS, |
| @@ -16440,7 +16653,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, · 684 unmodified lines |
| 16440 | 16653 | CASE(OP_get_super): |
| 16441 | 16654 | { |
| 16442 | 16655 | JSValue proto; |
| 16443 | | − proto = JS_DupValue(ctx, JS_GetPrototype(ctx, sp[-1])); |
| 16656 | + proto = JS_GetPrototype(ctx, sp[-1]); |
| 16444 | 16657 | if (JS_IsException(proto)) |
| 16445 | 16658 | goto exception; |
| 16446 | 16659 | JS_FreeValue(ctx, sp[-1]); |
| @@ -18543,6 +18756,9 @@ static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s) · 2096 unmodified lines |
| 18543 | 18756 | { |
| 18544 | 18757 | JSValue func_obj; |
| 18545 | 18758 | |
| 18759 | + if (js_check_stack_overflow(ctx->rt, 0)) |
| 18760 | + return JS_ThrowStackOverflow(ctx); |
| 18761 | + |
| 18546 | 18762 | /* the tag does not matter provided it is not an object */ |
| 18547 | 18763 | func_obj = JS_MKPTR(JS_TAG_INT, s); |
| 18548 | 18764 | return JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED, |
| @@ -19670,8 +19886,8 @@ typedef struct JSFunctionDef { · 1121 unmodified lines |
| 19670 | 19886 | |
| 19671 | 19887 | /* constant pool (strings, functions, numbers) */ |
| 19672 | 19888 | JSValue *cpool; |
| 19673 | | − uint32_t cpool_count; |
| 19674 | | − uint32_t cpool_size; |
| 19889 | + int cpool_count; |
| 19890 | + int cpool_size; |
| 19675 | 19891 | |
| 19676 | 19892 | /* list of variables in the closure */ |
| 19677 | 19893 | int closure_var_count; |
| @@ -19741,6 +19957,7 @@ typedef struct JSParseState { · 63 unmodified lines |
| 19741 | 19957 | JSFunctionDef *cur_func; |
| 19742 | 19958 | BOOL is_module; /* parsing a module */ |
| 19743 | 19959 | BOOL allow_html_comments; |
| 19960 | + BOOL ext_json; /* true if accepting JSON superset */ |
| 19744 | 19961 | } JSParseState; |
| 19745 | 19962 | |
| 19746 | 19963 | typedef struct JSOpCode { |
| @@ -20308,23 +20525,18 @@ static __exception int next_token(JSParseState *s) · 561 unmodified lines |
| 20308 | 20525 | c = *p; |
| 20309 | 20526 | switch(c) { |
| 20310 | 20527 | case 0: |
| 20311 | | − s->token.val = TOK_EOF; |
| 20312 | | − break; |
| 20313 | | − case '`': |
| 20314 | | − if (!s->cur_func) { |
| 20315 | | − /* JSON does not accept templates */ |
| 20528 | + if (p >= s->buf_end) { |
| 20529 | + s->token.val = TOK_EOF; |
| 20530 | + } else { |
| 20316 | 20531 | goto def_token; |
| 20317 | 20532 | } |
| 20533 | + break; |
| 20534 | + case '`': |
| 20318 | 20535 | if (js_parse_template_part(s, p + 1)) |
| 20319 | 20536 | goto fail; |
| 20320 | 20537 | p = s->buf_ptr; |
| 20321 | 20538 | break; |
| 20322 | 20539 | case '\'': |
| 20323 | | − if (!s->cur_func) { |
| 20324 | | − /* JSON does not accept single quoted strings */ |
| 20325 | | − goto def_token; |
| 20326 | | − } |
| 20327 | | − /* fall through */ |
| 20328 | 20540 | case '\"': |
| 20329 | 20541 | if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p)) |
| 20330 | 20542 | goto fail; |
| @@ -20342,11 +20554,6 @@ static __exception int next_token(JSParseState *s) · 11 unmodified lines |
| 20342 | 20554 | goto redo; |
| 20343 | 20555 | case '\f': |
| 20344 | 20556 | case '\v': |
| 20345 | | − if (!s->cur_func) { |
| 20346 | | − /* JSONWhitespace does not match <VT>, nor <FF> */ |
| 20347 | | − goto def_token; |
| 20348 | | − } |
| 20349 | | − /* fall through */ |
| 20350 | 20557 | case ' ': |
| 20351 | 20558 | case '\t': |
| 20352 | 20559 | p++; |
| @@ -20443,16 +20650,15 @@ static __exception int next_token(JSParseState *s) · 90 unmodified lines |
| 20443 | 20650 | s->token.u.ident.is_reserved = FALSE; |
| 20444 | 20651 | if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD || |
| 20445 | 20652 | (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD && |
| 20446 | | − s->cur_func && (s->cur_func->js_mode & JS_MODE_STRICT)) || |
| 20447 | | − (s->token.u.ident.atom == JS_ATOM_yield && s->cur_func && |
| 20653 | + (s->cur_func->js_mode & JS_MODE_STRICT)) || |
| 20654 | + (s->token.u.ident.atom == JS_ATOM_yield && |
| 20448 | 20655 | ((s->cur_func->func_kind & JS_FUNC_GENERATOR) || |
| 20449 | 20656 | (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && |
| 20450 | 20657 | !s->cur_func->in_function_body && s->cur_func->parent && |
| 20451 | 20658 | (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) || |
| 20452 | 20659 | (s->token.u.ident.atom == JS_ATOM_await && |
| 20453 | 20660 | (s->is_module || |
| 20454 | | − (s->cur_func && |
| 20455 | | − ((s->cur_func->func_kind & JS_FUNC_ASYNC) || |
| 20661 | + (((s->cur_func->func_kind & JS_FUNC_ASYNC) || |
| 20456 | 20662 | (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && |
| 20457 | 20663 | !s->cur_func->in_function_body && s->cur_func->parent && |
| 20458 | 20664 | (s->cur_func->parent->func_kind & JS_FUNC_ASYNC))))))) { |
| @@ -20505,9 +20711,8 @@ static __exception int next_token(JSParseState *s) · 46 unmodified lines |
| 20505 | 20711 | } |
| 20506 | 20712 | break; |
| 20507 | 20713 | case '0': |
| 20508 | | − /* in strict or JSON parsing mode, octal literals are not accepted */ |
| 20509 | | − if (is_digit(p[1]) && (!s->cur_func || |
| 20510 | | − (s->cur_func->js_mode & JS_MODE_STRICT))) { |
| 20714 | + /* in strict mode, octal literals are not accepted */ |
| 20715 | + if (is_digit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) { |
| 20511 | 20716 | js_parse_error(s, "octal literals are deprecated in strict mode"); |
| 20512 | 20717 | goto fail; |
| 20513 | 20718 | } |
| @@ -20519,22 +20724,17 @@ static __exception int next_token(JSParseState *s) · 5 unmodified lines |
| 20519 | 20724 | JSValue ret; |
| 20520 | 20725 | const uint8_t *p1; |
| 20521 | 20726 | int flags, radix; |
| 20522 | | − if (!s->cur_func) { |
| 20523 | | − flags = 0; |
| 20524 | | − radix = 10; |
| 20525 | | − } else { |
| 20526 | | − flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL | |
| 20527 | | − ATOD_ACCEPT_UNDERSCORES; |
| 20727 | + flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL | |
| 20728 | + ATOD_ACCEPT_UNDERSCORES; |
| 20528 | 20729 | #ifdef CONFIG_BIGNUM |
| 20529 | | − flags |= ATOD_ACCEPT_SUFFIX; |
| 20530 | | − if (s->cur_func->js_mode & JS_MODE_MATH) { |
| 20531 | | − flags |= ATOD_MODE_BIGINT; |
| 20532 | | − if (s->cur_func->js_mode & JS_MODE_MATH) |
| 20533 | | − flags |= ATOD_TYPE_BIG_FLOAT; |
| 20534 | | − } |
| 20535 | | −#endif |
| 20536 | | − radix = 0; |
| 20730 | + flags |= ATOD_ACCEPT_SUFFIX; |
| 20731 | + if (s->cur_func->js_mode & JS_MODE_MATH) { |
| 20732 | + flags |= ATOD_MODE_BIGINT; |
| 20733 | + if (s->cur_func->js_mode & JS_MODE_MATH) |
| 20734 | + flags |= ATOD_TYPE_BIG_FLOAT; |
| 20537 | 20735 | } |
| 20736 | +#endif |
| 20737 | + radix = 0; |
| 20538 | 20738 | #ifdef CONFIG_BIGNUM |
| 20539 | 20739 | s->token.u.num.exponent = 0; |
| 20540 | 20740 | ret = js_atof2(s->ctx, (const char *)p, (const char **)&p, radix, |
| @@ -20699,7 +20899,7 @@ static __exception int next_token(JSParseState *s) · 158 unmodified lines |
| 20699 | 20899 | case '^': |
| 20700 | 20900 | if (p[1] == '=') { |
| 20701 | 20901 | p += 2; |
| 20702 | | − if (s->cur_func && (s->cur_func->js_mode & JS_MODE_MATH)) |
| 20902 | + if (s->cur_func->js_mode & JS_MODE_MATH) |
| 20703 | 20903 | s->token.val = TOK_MATH_POW_ASSIGN; |
| 20704 | 20904 | else |
| 20705 | 20905 | s->token.val = TOK_XOR_ASSIGN; |
| @@ -20713,7 +20913,7 @@ static __exception int next_token(JSParseState *s) · 7 unmodified lines |
| 20713 | 20913 | } |
| 20714 | 20914 | } else { |
| 20715 | 20915 | p++; |
| 20716 | | − if (s->cur_func && (s->cur_func->js_mode & JS_MODE_MATH)) |
| 20916 | + if (s->cur_func->js_mode & JS_MODE_MATH) |
| 20717 | 20917 | s->token.val = TOK_MATH_POW; |
| 20718 | 20918 | else |
| 20719 | 20919 | s->token.val = '^'; |
| @@ -20758,22 +20958,12 @@ static __exception int next_token(JSParseState *s) · 38 unmodified lines |
| 20758 | 20958 | switch(c) { |
| 20759 | 20959 | case CP_PS: |
| 20760 | 20960 | case CP_LS: |
| 20761 | | − if (!s->cur_func) { |
| 20762 | | − /* <PS> and <LS> are not JSONWhitespace */ |
| 20763 | | − goto def_token; |
| 20764 | | − } else { |
| 20765 | | − /* XXX: should avoid incrementing line_number, but |
| 20766 | | − needed to handle HTML comments */ |
| 20767 | | − goto line_terminator; |
| 20768 | | − } |
| 20961 | + /* XXX: should avoid incrementing line_number, but |
| 20962 | + needed to handle HTML comments */ |
| 20963 | + goto line_terminator; |
| 20769 | 20964 | default: |
| 20770 | 20965 | if (lre_is_space(c)) { |
| 20771 | | − if (!s->cur_func) { |
| 20772 | | − /* category z spaces are not JSONWhitespace */ |
| 20773 | | − goto def_token; |
| 20774 | | − } else { |
| 20775 | | − goto redo; |
| 20776 | | − } |
| 20966 | + goto redo; |
| 20777 | 20967 | } else if (lre_js_is_ident_first(c)) { |
| 20778 | 20968 | ident_has_escape = FALSE; |
| 20779 | 20969 | goto has_ident; |
| @@ -20798,6 +20988,220 @@ static __exception int next_token(JSParseState *s) · 18 unmodified lines |
| 20798 | 20988 | return -1; |
| 20799 | 20989 | } |
| 20800 | 20990 | |
| 20991 | +/* 'c' is the first character. Return JS_ATOM_NULL in case of error */ |
| 20992 | +static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c) |
| 20993 | +{ |
| 20994 | + const uint8_t *p; |
| 20995 | + char ident_buf[128], *buf; |
| 20996 | + size_t ident_size, ident_pos; |
| 20997 | + JSAtom atom; |
| 20998 | + |
| 20999 | + p = *pp; |
| 21000 | + buf = ident_buf; |
| 21001 | + ident_size = sizeof(ident_buf); |
| 21002 | + ident_pos = 0; |
| 21003 | + for(;;) { |
| 21004 | + buf[ident_pos++] = c; |
| 21005 | + c = *p; |
| 21006 | + if (c >= 128 || |
| 21007 | + !((lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1)) |
| 21008 | + break; |
| 21009 | + p++; |
| 21010 | + if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) { |
| 21011 | + if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) { |
| 21012 | + atom = JS_ATOM_NULL; |
| 21013 | + goto done; |
| 21014 | + } |
| 21015 | + } |
| 21016 | + } |
| 21017 | + atom = JS_NewAtomLen(s->ctx, buf, ident_pos); |
| 21018 | + done: |
| 21019 | + if (unlikely(buf != ident_buf)) |
| 21020 | + js_free(s->ctx, buf); |
| 21021 | + *pp = p; |
| 21022 | + return atom; |
| 21023 | +} |
| 21024 | + |
| 21025 | +static __exception int json_next_token(JSParseState *s) |
| 21026 | +{ |
| 21027 | + const uint8_t *p; |
| 21028 | + int c; |
| 21029 | + JSAtom atom; |
| 21030 | + |
| 21031 | + if (js_check_stack_overflow(s->ctx->rt, 0)) { |
| 21032 | + return js_parse_error(s, "stack overflow"); |
| 21033 | + } |
| 21034 | + |
| 21035 | + free_token(s, &s->token); |
| 21036 | + |
| 21037 | + p = s->last_ptr = s->buf_ptr; |
| 21038 | + s->last_line_num = s->token.line_num; |
| 21039 | + redo: |
| 21040 | + s->token.line_num = s->line_num; |
| 21041 | + s->token.ptr = p; |
| 21042 | + c = *p; |
| 21043 | + switch(c) { |
| 21044 | + case 0: |
| 21045 | + if (p >= s->buf_end) { |
| 21046 | + s->token.val = TOK_EOF; |
| 21047 | + } else { |
| 21048 | + goto def_token; |
| 21049 | + } |
| 21050 | + break; |
| 21051 | + case '\'': |
| 21052 | + if (!s->ext_json) { |
| 21053 | + /* JSON does not accept single quoted strings */ |
| 21054 | + goto def_token; |
| 21055 | + } |
| 21056 | + /* fall through */ |
| 21057 | + case '\"': |
| 21058 | + if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p)) |
| 21059 | + goto fail; |
| 21060 | + break; |
| 21061 | + case '\r': /* accept DOS and MAC newline sequences */ |
| 21062 | + if (p[1] == '\n') { |
| 21063 | + p++; |
| 21064 | + } |
| 21065 | + /* fall thru */ |
| 21066 | + case '\n': |
| 21067 | + p++; |
| 21068 | + s->line_num++; |
| 21069 | + goto redo; |
| 21070 | + case '\f': |
| 21071 | + case '\v': |
| 21072 | + if (!s->ext_json) { |
| 21073 | + /* JSONWhitespace does not match <VT>, nor <FF> */ |
| 21074 | + goto def_token; |
| 21075 | + } |
| 21076 | + /* fall through */ |
| 21077 | + case ' ': |
| 21078 | + case '\t': |
| 21079 | + p++; |
| 21080 | + goto redo; |
| 21081 | + case '/': |
| 21082 | + if (!s->ext_json) { |
| 21083 | + /* JSON does not accept comments */ |
| 21084 | + goto def_token; |
| 21085 | + } |
| 21086 | + if (p[1] == '*') { |
| 21087 | + /* comment */ |
| 21088 | + p += 2; |
| 21089 | + for(;;) { |
| 21090 | + if (*p == '\0' && p >= s->buf_end) { |
| 21091 | + js_parse_error(s, "unexpected end of comment"); |
| 21092 | + goto fail; |
| 21093 | + } |
| 21094 | + if (p[0] == '*' && p[1] == '/') { |
| 21095 | + p += 2; |
| 21096 | + break; |
| 21097 | + } |
| 21098 | + if (*p == '\n') { |
| 21099 | + s->line_num++; |
| 21100 | + p++; |
| 21101 | + } else if (*p == '\r') { |
| 21102 | + p++; |
| 21103 | + } else if (*p >= 0x80) { |
| 21104 | + c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); |
| 21105 | + if (c == -1) { |
| 21106 | + p++; /* skip invalid UTF-8 */ |
| 21107 | + } |
| 21108 | + } else { |
| 21109 | + p++; |
| 21110 | + } |
| 21111 | + } |
| 21112 | + goto redo; |
| 21113 | + } else if (p[1] == '/') { |
| 21114 | + /* line comment */ |
| 21115 | + p += 2; |
| 21116 | + for(;;) { |
| 21117 | + if (*p == '\0' && p >= s->buf_end) |
| 21118 | + break; |
| 21119 | + if (*p == '\r' || *p == '\n') |
| 21120 | + break; |
| 21121 | + if (*p >= 0x80) { |
| 21122 | + c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); |
| 21123 | + /* LS or PS are considered as line terminator */ |
| 21124 | + if (c == CP_LS || c == CP_PS) { |
| 21125 | + break; |
| 21126 | + } else if (c == -1) { |
| 21127 | + p++; /* skip invalid UTF-8 */ |
| 21128 | + } |
| 21129 | + } else { |
| 21130 | + p++; |
| 21131 | + } |
| 21132 | + } |
| 21133 | + goto redo; |
| 21134 | + } else { |
| 21135 | + goto def_token; |
| 21136 | + } |
| 21137 | + break; |
| 21138 | + case 'a' ... 'z': |
| 21139 | + case 'A' ... 'Z': |
| 21140 | + case '_': |
| 21141 | + case '$': |
| 21142 | + /* identifier : only pure ascii characters are accepted */ |
| 21143 | + p++; |
| 21144 | + atom = json_parse_ident(s, &p, c); |
| 21145 | + if (atom == JS_ATOM_NULL) |
| 21146 | + goto fail; |
| 21147 | + s->token.u.ident.atom = atom; |
| 21148 | + s->token.u.ident.has_escape = FALSE; |
| 21149 | + s->token.u.ident.is_reserved = FALSE; |
| 21150 | + s->token.val = TOK_IDENT; |
| 21151 | + break; |
| 21152 | + case '+': |
| 21153 | + if (!s->ext_json || !is_digit(p[1])) |
| 21154 | + goto def_token; |
| 21155 | + goto parse_number; |
| 21156 | + case '0': |
| 21157 | + if (is_digit(p[1])) |
| 21158 | + goto def_token; |
| 21159 | + goto parse_number; |
| 21160 | + case '-': |
| 21161 | + if (!is_digit(p[1])) |
| 21162 | + goto def_token; |
| 21163 | + goto parse_number; |
| 21164 | + case '1' ... '9': |
| 21165 | + /* number */ |
| 21166 | + parse_number: |
| 21167 | + { |
| 21168 | + JSValue ret; |
| 21169 | + int flags, radix; |
| 21170 | + if (!s->ext_json) { |
| 21171 | + flags = 0; |
| 21172 | + radix = 10; |
| 21173 | + } else { |
| 21174 | + flags = ATOD_ACCEPT_BIN_OCT; |
| 21175 | + radix = 0; |
| 21176 | + } |
| 21177 | + ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix, |
| 21178 | + flags); |
| 21179 | + if (JS_IsException(ret)) |
| 21180 | + goto fail; |
| 21181 | + s->token.val = TOK_NUMBER; |
| 21182 | + s->token.u.num.val = ret; |
| 21183 | + } |
| 21184 | + break; |
| 21185 | + default: |
| 21186 | + if (c >= 128) { |
| 21187 | + js_parse_error(s, "unexpected character"); |
| 21188 | + goto fail; |
| 21189 | + } |
| 21190 | + def_token: |
| 21191 | + s->token.val = c; |
| 21192 | + p++; |
| 21193 | + break; |
| 21194 | + } |
| 21195 | + s->buf_ptr = p; |
| 21196 | + |
| 21197 | + // dump_token(s, &s->token); |
| 21198 | + return 0; |
| 21199 | + |
| 21200 | + fail: |
| 21201 | + s->token.val = TOK_ERROR; |
| 21202 | + return -1; |
| 21203 | +} |
| 21204 | + |
| 20801 | 21205 | /* only used for ':' and '=>', 'let' or 'function' look-ahead. *pp is |
| 20802 | 21206 | only set if TOK_IMPORT is returned */ |
| 20803 | 21207 | /* XXX: handle all unicode cases */ |
| @@ -20858,6 +21262,12 @@ static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator) · 54 unmodified lines |
| 20858 | 21262 | } |
| 20859 | 21263 | } else if (c == 'o' && *p == 'f' && !lre_js_is_ident_next(p[1])) { |
| 20860 | 21264 | return TOK_OF; |
| 21265 | + } else if (c == 'e' && |
| 21266 | + p[0] == 'x' && p[1] == 'p' && p[2] == 'o' && |
| 21267 | + p[3] == 'r' && p[4] == 't' && |
| 21268 | + !lre_js_is_ident_next(p[5])) { |
| 21269 | + *pp = p + 5; |
| 21270 | + return TOK_EXPORT; |
| 20861 | 21271 | } else if (c == 'f' && p[0] == 'u' && p[1] == 'n' && |
| 20862 | 21272 | p[2] == 'c' && p[3] == 't' && p[4] == 'i' && |
| 20863 | 21273 | p[5] == 'o' && p[6] == 'n' && !lre_js_is_ident_next(p[7])) { |
| @@ -20881,16 +21291,21 @@ static int peek_token(JSParseState *s, BOOL no_line_terminator) · 17 unmodified lines |
| 20881 | 21291 | (heuristic). 'input' must be a zero terminated. |
| 20882 | 21292 | |
| 20883 | 21293 | Heuristic: skip comments and expect 'import' keyword not followed |
| 20884 | | − by '(' or '.' |
| 21294 | + by '(' or '.' or export keyword. |
| 20885 | 21295 | */ |
| 20886 | 21296 | BOOL JS_DetectModule(const char *input, size_t input_len) |
| 20887 | 21297 | { |
| 20888 | 21298 | const uint8_t *p = (const uint8_t *)input; |
| 20889 | 21299 | int tok; |
| 20890 | | − if (simple_next_token(&p, FALSE) != TOK_IMPORT) |
| 21300 | + switch(simple_next_token(&p, FALSE)) { |
| 21301 | + case TOK_IMPORT: |
| 21302 | + tok = simple_next_token(&p, FALSE); |
| 21303 | + return (tok != '.' && tok != '('); |
| 21304 | + case TOK_EXPORT: |
| 21305 | + return TRUE; |
| 21306 | + default: |
| 20891 | 21307 | return FALSE; |
| 20892 | | − tok = simple_next_token(&p, FALSE); |
| 20893 | | − return (tok != '.' && tok != '('); |
| 21308 | + } |
| 20894 | 21309 | } |
| 20895 | 21310 | |
| 20896 | 21311 | static inline int get_prev_opcode(JSFunctionDef *fd) { |
| @@ -20974,20 +21389,10 @@ static int new_label_fd(JSFunctionDef *fd, int label) · 77 unmodified lines |
| 20974 | 21389 | LabelSlot *ls; |
| 20975 | 21390 | |
| 20976 | 21391 | if (label < 0) { |
| 20977 | | − if (fd->label_count >= fd->label_size) { |
| 20978 | | − int new_size; |
| 20979 | | − size_t slack; |
| 20980 | | − LabelSlot *new_tab; |
| 20981 | | − |
| 20982 | | − /* XXX: potential arithmetic overflow */ |
| 20983 | | − new_size = fd->label_size * 3 / 2 + 4; |
| 20984 | | − new_tab = js_realloc2(fd->ctx, fd->label_slots, new_size * sizeof(*new_tab), &slack); |
| 20985 | | − if (!new_tab) |
| 20986 | | − return -1; |
| 20987 | | − new_size += slack / sizeof(*new_tab); |
| 20988 | | − fd->label_slots = new_tab; |
| 20989 | | − fd->label_size = new_size; |
| 20990 | | − } |
| 21392 | + if (js_resize_array(fd->ctx, (void *)&fd->label_slots, |
| 21393 | + sizeof(fd->label_slots[0]), |
| 21394 | + &fd->label_size, fd->label_count + 1)) |
| 21395 | + return -1; |
| 20991 | 21396 | label = fd->label_count++; |
| 20992 | 21397 | ls = &fd->label_slots[label]; |
| 20993 | 21398 | ls->ref_count = 0; |
| @@ -21035,19 +21440,10 @@ static int emit_goto(JSParseState *s, int opcode, int label) · 41 unmodified lines |
| 21035 | 21440 | static int cpool_add(JSParseState *s, JSValue val) |
| 21036 | 21441 | { |
| 21037 | 21442 | JSFunctionDef *fd = s->cur_func; |
| 21038 | | − if (fd->cpool_count >= fd->cpool_size) { |
| 21039 | | − int new_size; |
| 21040 | | − size_t slack; |
| 21041 | | − JSValue *new_tab; |
| 21042 | | − /* XXX: potential arithmetic overflow */ |
| 21043 | | − new_size = max_int(fd->cpool_count + 1, fd->cpool_size * 3 / 2); |
| 21044 | | − new_tab = js_realloc2(s->ctx, fd->cpool, new_size * sizeof(JSValue), &slack); |
| 21045 | | − if (!new_tab) |
| 21046 | | − return -1; |
| 21047 | | − new_size += slack / sizeof(*new_tab); |
| 21048 | | − fd->cpool = new_tab; |
| 21049 | | − fd->cpool_size = new_size; |
| 21050 | | − } |
| 21443 | + |
| 21444 | + if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]), |
| 21445 | + &fd->cpool_size, fd->cpool_count + 1)) |
| 21446 | + return -1; |
| 21051 | 21447 | fd->cpool[fd->cpool_count++] = val; |
| 21052 | 21448 | return fd->cpool_count - 1; |
| 21053 | 21449 | } |
| @@ -21246,18 +21642,9 @@ static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) · 192 unmodified lines |
| 21246 | 21642 | JS_ThrowInternalError(ctx, "too many local variables"); |
| 21247 | 21643 | return -1; |
| 21248 | 21644 | } |
| 21249 | | − if ((fd->var_count + 1) > fd->var_size) { |
| 21250 | | − int new_size; |
| 21251 | | − size_t slack; |
| 21252 | | − JSVarDef *new_buf; |
| 21253 | | − new_size = max_int(fd->var_count + 1, fd->var_size * 3 / 2); |
| 21254 | | − new_buf = js_realloc2(ctx, fd->vars, new_size * sizeof(*fd->vars), &slack); |
| 21255 | | − if (!new_buf) |
| 21256 | | − return -1; |
| 21257 | | − new_size += slack / sizeof(*new_buf); |
| 21258 | | − fd->vars = new_buf; |
| 21259 | | − fd->var_size = new_size; |
| 21260 | | − } |
| 21645 | + if (js_resize_array(ctx, (void **)&fd->vars, sizeof(fd->vars[0]), |
| 21646 | + &fd->var_size, fd->var_count + 1)) |
| 21647 | + return -1; |
| 21261 | 21648 | vd = &fd->vars[fd->var_count++]; |
| 21262 | 21649 | memset(vd, 0, sizeof(*vd)); |
| 21263 | 21650 | vd->var_name = JS_DupAtom(ctx, name); |
| @@ -21309,18 +21696,9 @@ static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name) · 45 unmodified lines |
| 21309 | 21696 | JS_ThrowInternalError(ctx, "too many arguments"); |
| 21310 | 21697 | return -1; |
| 21311 | 21698 | } |
| 21312 | | − if ((fd->arg_count + 1) > fd->arg_size) { |
| 21313 | | − int new_size; |
| 21314 | | − size_t slack; |
| 21315 | | − JSVarDef *new_buf; |
| 21316 | | − new_size = max_int(fd->arg_count + 1, fd->arg_size * 3 / 2); |
| 21317 | | − new_buf = js_realloc2(ctx, fd->args, new_size * sizeof(*fd->args), &slack); |
| 21318 | | − if (!new_buf) |
| 21319 | | − return -1; |
| 21320 | | − new_size += slack / sizeof(*new_buf); |
| 21321 | | − fd->args = new_buf; |
| 21322 | | − fd->arg_size = new_size; |
| 21323 | | − } |
| 21699 | + if (js_resize_array(ctx, (void **)&fd->args, sizeof(fd->args[0]), |
| 21700 | + &fd->arg_size, fd->arg_count + 1)) |
| 21701 | + return -1; |
| 21324 | 21702 | vd = &fd->args[fd->arg_count++]; |
| 21325 | 21703 | memset(vd, 0, sizeof(*vd)); |
| 21326 | 21704 | vd->var_name = JS_DupAtom(ctx, name); |
| @@ -21335,19 +21713,10 @@ static JSHoistedDef *add_hoisted_def(JSContext *ctx, · 8 unmodified lines |
| 21335 | 21713 | { |
| 21336 | 21714 | JSHoistedDef *hf; |
| 21337 | 21715 | |
| 21338 | | − if (s->hoisted_def_count >= s->hoisted_def_size) { |
| 21339 | | − int new_size; |
| 21340 | | − size_t slack; |
| 21341 | | − JSHoistedDef *new_tab; |
| 21342 | | − new_size = max_int(s->hoisted_def_count + 1, |
| 21343 | | − s->hoisted_def_size * 3 / 2); |
| 21344 | | − new_tab = js_realloc2(ctx, s->hoisted_def, new_size * sizeof(s->hoisted_def[0]), &slack); |
| 21345 | | − if (!new_tab) |
| 21346 | | − return NULL; |
| 21347 | | − new_size += slack / sizeof(*new_tab); |
| 21348 | | − s->hoisted_def = new_tab; |
| 21349 | | − s->hoisted_def_size = new_size; |
| 21350 | | − } |
| 21716 | + if (js_resize_array(ctx, (void **)&s->hoisted_def, |
| 21717 | + sizeof(s->hoisted_def[0]), |
| 21718 | + &s->hoisted_def_size, s->hoisted_def_count + 1)) |
| 21719 | + return NULL; |
| 21351 | 21720 | hf = &s->hoisted_def[s->hoisted_def_count++]; |
| 21352 | 21721 | hf->cpool_idx = cpool_idx; |
| 21353 | 21722 | hf->force_init = 0; |
| @@ -21639,7 +22008,7 @@ static __exception int js_parse_template(JSParseState *s, int call, int *argc) · 285 unmodified lines |
| 21639 | 22008 | goto done; |
| 21640 | 22009 | if (next_token(s)) |
| 21641 | 22010 | return -1; |
| 21642 | | − if (js_parse_assign_expr(s, TRUE)) |
| 22011 | + if (js_parse_expr(s)) |
| 21643 | 22012 | return -1; |
| 21644 | 22013 | depth++; |
| 21645 | 22014 | if (s->token.val != '}') { |
| @@ -21647,7 +22016,8 @@ static __exception int js_parse_template(JSParseState *s, int call, int *argc) · 1 unmodified line |
| 21647 | 22016 | } |
| 21648 | 22017 | /* XXX: should convert to string at this stage? */ |
| 21649 | 22018 | free_token(s, &s->token); |
| 21650 | | − /* Resume TOK_TEMPLATE parsing (s->token.line_num and s->token.ptr are OK) */ |
| 22019 | + /* Resume TOK_TEMPLATE parsing (s->token.line_num and |
| 22020 | + * s->token.ptr are OK) */ |
| 21651 | 22021 | s->got_lf = FALSE; |
| 21652 | 22022 | s->last_line_num = s->token.line_num; |
| 21653 | 22023 | if (js_parse_template_part(s, s->buf_ptr)) |
| @@ -21875,7 +22245,7 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_ · 221 unmodified lines |
| 21875 | 22245 | size_t level = 0; |
| 21876 | 22246 | JSParsePos pos; |
| 21877 | 22247 | int last_tok, tok = TOK_EOF; |
| 21878 | | − int tok_len, bits = 0; |
| 22248 | + int c, tok_len, bits = 0; |
| 21879 | 22249 | |
| 21880 | 22250 | /* protect from underflow */ |
| 21881 | 22251 | state[level++] = 0; |
| @@ -21900,8 +22270,30 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_ · 18 unmodified lines |
| 21900 | 22270 | goto done; |
| 21901 | 22271 | break; |
| 21902 | 22272 | case '}': |
| 21903 | | − if (state[--level] != '{') |
| 22273 | + c = state[--level]; |
| 22274 | + if (c == '`') { |
| 22275 | + /* continue the parsing of the template */ |
| 22276 | + free_token(s, &s->token); |
| 22277 | + /* Resume TOK_TEMPLATE parsing (s->token.line_num and |
| 22278 | + * s->token.ptr are OK) */ |
| 22279 | + s->got_lf = FALSE; |
| 22280 | + s->last_line_num = s->token.line_num; |
| 22281 | + if (js_parse_template_part(s, s->buf_ptr)) |
| 22282 | + goto done; |
| 22283 | + goto handle_template; |
| 22284 | + } else if (c != '{') { |
| 21904 | 22285 | goto done; |
| 22286 | + } |
| 22287 | + break; |
| 22288 | + case TOK_TEMPLATE: |
| 22289 | + handle_template: |
| 22290 | + if (s->token.u.str.sep != '`') { |
| 22291 | + /* '${' inside the template : closing '}' and continue |
| 22292 | + parsing the template */ |
| 22293 | + if (level >= sizeof(state)) |
| 22294 | + goto done; |
| 22295 | + state[level++] = '`'; |
| 22296 | + } |
| 21905 | 22297 | break; |
| 21906 | 22298 | case TOK_EOF: |
| 21907 | 22299 | goto done; |
| @@ -24005,7 +24397,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen · 2097 unmodified lines |
| 24005 | 24397 | int scope; |
| 24006 | 24398 | name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); |
| 24007 | 24399 | scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5); |
| 24008 | | − if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL) { |
| 24400 | + if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL && !has_optional_chain) { |
| 24009 | 24401 | /* direct 'eval' */ |
| 24010 | 24402 | opcode = OP_eval; |
| 24011 | 24403 | } else { |
| @@ -26318,26 +26710,6 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m) · 2306 unmodified lines |
| 26318 | 26710 | js_free(ctx, m); |
| 26319 | 26711 | } |
| 26320 | 26712 | |
| 26321 | | −static int js_resize_array(JSContext *ctx, void **parray, int elem_size, |
| 26322 | | − int *psize, int *pcount, int new_count) |
| 26323 | | −{ |
| 26324 | | − if (unlikely(new_count > *psize)) { |
| 26325 | | − int new_size; |
| 26326 | | − size_t slack; |
| 26327 | | − void *new_array; |
| 26328 | | − /* XXX: potential arithmetic overflow */ |
| 26329 | | − new_size = max_int(new_count, *psize * 3 / 2); |
| 26330 | | − new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack); |
| 26331 | | − if (!new_array) |
| 26332 | | − return -1; |
| 26333 | | − new_size += slack / elem_size; |
| 26334 | | − *psize = new_size; |
| 26335 | | − *parray = new_array; |
| 26336 | | − } |
| 26337 | | − *pcount = new_count; |
| 26338 | | − return 0; |
| 26339 | | −} |
| 26340 | | − |
| 26341 | 26713 | static int add_req_module_entry(JSContext *ctx, JSModuleDef *m, |
| 26342 | 26714 | JSAtom module_name) |
| 26343 | 26715 | { |
| @@ -26353,11 +26725,10 @@ static int add_req_module_entry(JSContext *ctx, JSModuleDef *m, · 9 unmodified lines |
| 26353 | 26725 | |
| 26354 | 26726 | if (js_resize_array(ctx, (void **)&m->req_module_entries, |
| 26355 | 26727 | sizeof(JSReqModuleEntry), |
| 26356 | | − &m->req_module_entries_size, &m->req_module_entries_count, |
| 26728 | + &m->req_module_entries_size, |
| 26357 | 26729 | m->req_module_entries_count + 1)) |
| 26358 | 26730 | return -1; |
| 26359 | | − i = m->req_module_entries_count - 1; |
| 26360 | | − rme = &m->req_module_entries[i]; |
| 26731 | + rme = &m->req_module_entries[m->req_module_entries_count++]; |
| 26361 | 26732 | rme->module_name = JS_DupAtom(ctx, module_name); |
| 26362 | 26733 | rme->module = NULL; |
| 26363 | 26734 | return i; |
| @@ -26389,18 +26760,17 @@ static JSExportEntry *add_export_entry2(JSContext *ctx, · 25 unmodified lines |
| 26389 | 26760 | js_parse_error(s, "duplicate exported name '%s'", |
| 26390 | 26761 | JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name)); |
| 26391 | 26762 | } else { |
| 26392 | | − JS_ThrowSyntaxError(ctx, "duplicate exported name '%s'", |
| 26393 | | − JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name)); |
| 26763 | + JS_ThrowSyntaxErrorAtom(ctx, "duplicate exported name '%s'", export_name); |
| 26394 | 26764 | } |
| 26395 | 26765 | return NULL; |
| 26396 | 26766 | } |
| 26397 | 26767 | |
| 26398 | 26768 | if (js_resize_array(ctx, (void **)&m->export_entries, |
| 26399 | 26769 | sizeof(JSExportEntry), |
| 26400 | | − &m->export_entries_size, &m->export_entries_count, |
| 26770 | + &m->export_entries_size, |
| 26401 | 26771 | m->export_entries_count + 1)) |
| 26402 | 26772 | return NULL; |
| 26403 | | − me = &m->export_entries[m->export_entries_count - 1]; |
| 26773 | + me = &m->export_entries[m->export_entries_count++]; |
| 26404 | 26774 | memset(me, 0, sizeof(*me)); |
| 26405 | 26775 | me->local_name = JS_DupAtom(ctx, local_name); |
| 26406 | 26776 | me->export_name = JS_DupAtom(ctx, export_name); |
| @@ -26423,10 +26793,10 @@ static int add_star_export_entry(JSContext *ctx, JSModuleDef *m, · 16 unmodified lines |
| 26423 | 26793 | |
| 26424 | 26794 | if (js_resize_array(ctx, (void **)&m->star_export_entries, |
| 26425 | 26795 | sizeof(JSStarExportEntry), |
| 26426 | | − &m->star_export_entries_size, &m->star_export_entries_count, |
| 26796 | + &m->star_export_entries_size, |
| 26427 | 26797 | m->star_export_entries_count + 1)) |
| 26428 | 26798 | return -1; |
| 26429 | | − se = &m->star_export_entries[m->star_export_entries_count - 1]; |
| 26799 | + se = &m->star_export_entries[m->star_export_entries_count++]; |
| 26430 | 26800 | se->req_module_idx = req_module_idx; |
| 26431 | 26801 | return 0; |
| 26432 | 26802 | } |
| @@ -26652,10 +27022,9 @@ static int add_resolve_entry(JSContext *ctx, JSResolveState *s, · 219 unmodified lines |
| 26652 | 27022 | |
| 26653 | 27023 | if (js_resize_array(ctx, (void **)&s->array, |
| 26654 | 27024 | sizeof(JSResolveEntry), |
| 26655 | | − &s->size, &s->count, |
| 26656 | | − s->count + 1)) |
| 27025 | + &s->size, s->count + 1)) |
| 26657 | 27026 | return -1; |
| 26658 | | − re = &s->array[s->count - 1]; |
| 27027 | + re = &s->array[s->count++]; |
| 26659 | 27028 | re->module = m; |
| 26660 | 27029 | re->name = JS_DupAtom(ctx, name); |
| 26661 | 27030 | return 0; |
| @@ -26780,17 +27149,17 @@ static void js_resolve_export_throw_error(JSContext *ctx, · 118 unmodified lines |
| 26780 | 27149 | break; |
| 26781 | 27150 | default: |
| 26782 | 27151 | case JS_RESOLVE_RES_NOT_FOUND: |
| 26783 | | − JS_ThrowSyntaxError(ctx, "export '%s' in module '%s' is ambiguous", |
| 27152 | + JS_ThrowSyntaxError(ctx, "Could not find export '%s' in module '%s'", |
| 26784 | 27153 | JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name), |
| 26785 | 27154 | JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name)); |
| 26786 | 27155 | break; |
| 26787 | 27156 | case JS_RESOLVE_RES_CIRCULAR: |
| 26788 | | − JS_ThrowSyntaxError(ctx, "Could not find export '%s' in module '%s'", |
| 27157 | + JS_ThrowSyntaxError(ctx, "circular reference when looking for export '%s' in module '%s'", |
| 26789 | 27158 | JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name), |
| 26790 | 27159 | JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name)); |
| 26791 | 27160 | break; |
| 26792 | 27161 | case JS_RESOLVE_RES_AMBIGUOUS: |
| 26793 | | − JS_ThrowSyntaxError(ctx, "circular reference when looking for export '%s' in module '%s'", |
| 27162 | + JS_ThrowSyntaxError(ctx, "export '%s' in module '%s' is ambiguous", |
| 26794 | 27163 | JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name), |
| 26795 | 27164 | JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name)); |
| 26796 | 27165 | break; |
| @@ -26847,9 +27216,9 @@ static __exception int get_exported_names(JSContext *ctx, · 50 unmodified lines |
| 26847 | 27216 | return 0; |
| 26848 | 27217 | } |
| 26849 | 27218 | if (js_resize_array(ctx, (void **)&s->modules, sizeof(s->modules[0]), |
| 26850 | | − &s->modules_size, &s->modules_count, s->modules_count + 1)) |
| 27219 | + &s->modules_size, s->modules_count + 1)) |
| 26851 | 27220 | return -1; |
| 26852 | | − s->modules[s->modules_count - 1] = m; |
| 27221 | + s->modules[s->modules_count++] = m; |
| 26853 | 27222 | |
| 26854 | 27223 | for(i = 0; i < m->export_entries_count; i++) { |
| 26855 | 27224 | JSExportEntry *me = &m->export_entries[i]; |
| @@ -26858,9 +27227,10 @@ static __exception int get_exported_names(JSContext *ctx, · 2 unmodified lines |
| 26858 | 27227 | j = find_exported_name(s, me->export_name); |
| 26859 | 27228 | if (j < 0) { |
| 26860 | 27229 | if (js_resize_array(ctx, (void **)&s->exported_names, sizeof(s->exported_names[0]), |
| 26861 | | − &s->exported_names_size, &s->exported_names_count, s->exported_names_count + 1)) |
| 27230 | + &s->exported_names_size, |
| 27231 | + s->exported_names_count + 1)) |
| 26862 | 27232 | return -1; |
| 26863 | | − en = &s->exported_names[s->exported_names_count - 1]; |
| 27233 | + en = &s->exported_names[s->exported_names_count++]; |
| 26864 | 27234 | en->export_name = me->export_name; |
| 26865 | 27235 | /* avoid a second lookup for simple module exports */ |
| 26866 | 27236 | if (from_star || me->export_type != JS_EXPORT_TYPE_LOCAL) |
| @@ -27096,7 +27466,7 @@ static JSVarRef *js_create_module_var(JSContext *ctx, BOOL is_lexical) · 229 unmodified lines |
| 27096 | 27466 | } |
| 27097 | 27467 | |
| 27098 | 27468 | /* Create the <eval> function associated with the module */ |
| 27099 | | −static int js_create_module_function(JSContext *ctx, JSModuleDef *m) |
| 27469 | +static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m) |
| 27100 | 27470 | { |
| 27101 | 27471 | JSFunctionBytecode *b; |
| 27102 | 27472 | int i; |
| @@ -27147,20 +27517,15 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m) · 44 unmodified lines |
| 27147 | 27517 | return -1; |
| 27148 | 27518 | } |
| 27149 | 27519 | |
| 27150 | | −/* Prepare a module to be executed by resolving all the imported |
| 27151 | | − variables. */ |
| 27152 | | −static int js_instantiate_module(JSContext *ctx, JSModuleDef *m) |
| 27520 | +/* must be done before js_instantiate_module() because of cyclic references */ |
| 27521 | +static int js_create_module_function(JSContext *ctx, JSModuleDef *m) |
| 27153 | 27522 | { |
| 27154 | | − int i; |
| 27155 | | − JSImportEntry *mi; |
| 27156 | | − JSModuleDef *m1; |
| 27157 | | − JSVarRef **var_refs, *var_ref; |
| 27158 | | − JSObject *p; |
| 27159 | 27523 | BOOL is_c_module; |
| 27160 | | − |
| 27161 | | − if (m->instantiated) |
| 27524 | + int i; |
| 27525 | + JSVarRef *var_ref; |
| 27526 | + |
| 27527 | + if (m->func_created) |
| 27162 | 27528 | return 0; |
| 27163 | | − m->instantiated = TRUE; |
| 27164 | 27529 | |
| 27165 | 27530 | is_c_module = (m->init_func != NULL); |
| 27166 | 27531 | |
| @@ -27171,14 +27536,49 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m) · 4 unmodified lines |
| 27171 | 27536 | if (me->export_type == JS_EXPORT_TYPE_LOCAL) { |
| 27172 | 27537 | var_ref = js_create_module_var(ctx, FALSE); |
| 27173 | 27538 | if (!var_ref) |
| 27174 | | − goto fail; |
| 27539 | + return -1; |
| 27175 | 27540 | me->u.local.var_ref = var_ref; |
| 27176 | 27541 | } |
| 27177 | 27542 | } |
| 27178 | 27543 | } else { |
| 27179 | | − if (js_create_module_function(ctx, m) < 0) |
| 27180 | | − goto fail; |
| 27544 | + if (js_create_module_bytecode_function(ctx, m)) |
| 27545 | + return -1; |
| 27181 | 27546 | } |
| 27547 | + m->func_created = TRUE; |
| 27548 | + |
| 27549 | + /* do it on the dependencies */ |
| 27550 | + |
| 27551 | + for(i = 0; i < m->req_module_entries_count; i++) { |
| 27552 | + JSReqModuleEntry *rme = &m->req_module_entries[i]; |
| 27553 | + if (js_create_module_function(ctx, rme->module) < 0) |
| 27554 | + return -1; |
| 27555 | + } |
| 27556 | + |
| 27557 | + return 0; |
| 27558 | +} |
| 27559 | + |
| 27560 | + |
| 27561 | +/* Prepare a module to be executed by resolving all the imported |
| 27562 | + variables. */ |
| 27563 | +static int js_instantiate_module(JSContext *ctx, JSModuleDef *m) |
| 27564 | +{ |
| 27565 | + int i; |
| 27566 | + JSImportEntry *mi; |
| 27567 | + JSModuleDef *m1; |
| 27568 | + JSVarRef **var_refs, *var_ref; |
| 27569 | + JSObject *p; |
| 27570 | + BOOL is_c_module; |
| 27571 | + |
| 27572 | + if (m->instantiated) |
| 27573 | + return 0; |
| 27574 | + m->instantiated = TRUE; |
| 27575 | + |
| 27576 | +#ifdef DUMP_MODULE_RESOLVE |
| 27577 | + { |
| 27578 | + char buf1[ATOM_GET_STR_BUF_SIZE]; |
| 27579 | + printf("start instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); |
| 27580 | + } |
| 27581 | +#endif |
| 27182 | 27582 | |
| 27183 | 27583 | for(i = 0; i < m->req_module_entries_count; i++) { |
| 27184 | 27584 | JSReqModuleEntry *rme = &m->req_module_entries[i]; |
| @@ -27221,6 +27621,8 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m) · 36 unmodified lines |
| 27221 | 27621 | } |
| 27222 | 27622 | #endif |
| 27223 | 27623 | |
| 27624 | + is_c_module = (m->init_func != NULL); |
| 27625 | + |
| 27224 | 27626 | if (!is_c_module) { |
| 27225 | 27627 | p = JS_VALUE_GET_OBJ(m->func_obj); |
| 27226 | 27628 | var_refs = p->u.func.var_refs; |
| @@ -27740,10 +28142,10 @@ static int add_import(JSParseState *s, JSModuleDef *m, · 513 unmodified lines |
| 27740 | 28142 | return -1; |
| 27741 | 28143 | if (js_resize_array(ctx, (void **)&m->import_entries, |
| 27742 | 28144 | sizeof(JSImportEntry), |
| 27743 | | − &m->import_entries_size, &m->import_entries_count, |
| 28145 | + &m->import_entries_size, |
| 27744 | 28146 | m->import_entries_count + 1)) |
| 27745 | 28147 | return -1; |
| 27746 | | − mi = &m->import_entries[m->import_entries_count - 1]; |
| 28148 | + mi = &m->import_entries[m->import_entries_count++]; |
| 27747 | 28149 | mi->import_name = JS_DupAtom(ctx, import_name); |
| 27748 | 28150 | mi->var_idx = var_idx; |
| 27749 | 28151 | return 0; |
| @@ -28474,20 +28876,10 @@ static int add_closure_var(JSContext *ctx, JSFunctionDef *s, · 724 unmodified lines |
| 28474 | 28876 | return -1; |
| 28475 | 28877 | } |
| 28476 | 28878 | |
| 28477 | | − if (s->closure_var_count >= s->closure_var_size) { |
| 28478 | | − JSClosureVar *new_tab; |
| 28479 | | − int new_size; |
| 28480 | | − size_t slack; |
| 28481 | | − new_size = max_int(s->closure_var_count + 1, |
| 28482 | | − s->closure_var_size * 3 / 2); |
| 28483 | | − new_tab = js_realloc2(ctx, s->closure_var, |
| 28484 | | − new_size * sizeof(JSClosureVar), &slack); |
| 28485 | | − if (!new_tab) |
| 28486 | | − return -1; |
| 28487 | | − new_size += slack / sizeof(*new_tab); |
| 28488 | | − s->closure_var = new_tab; |
| 28489 | | − s->closure_var_size = new_size; |
| 28490 | | − } |
| 28879 | + if (js_resize_array(ctx, (void **)&s->closure_var, |
| 28880 | + sizeof(s->closure_var[0]), |
| 28881 | + &s->closure_var_size, s->closure_var_count + 1)) |
| 28882 | + return -1; |
| 28491 | 28883 | cv = &s->closure_var[s->closure_var_count++]; |
| 28492 | 28884 | cv->is_local = is_local; |
| 28493 | 28885 | cv->is_arg = is_arg; |
| @@ -29243,8 +29635,6 @@ static int resolve_scope_private_field1(JSContext *ctx, · 749 unmodified lines |
| 29243 | 29635 | } |
| 29244 | 29636 | scope_level = fd->parent_scope_level; |
| 29245 | 29637 | if (!fd->parent) { |
| 29246 | | − char buf[ATOM_GET_STR_BUF_SIZE]; |
| 29247 | | − |
| 29248 | 29638 | if (fd->is_eval) { |
| 29249 | 29639 | /* closure of the eval function (top level) */ |
| 29250 | 29640 | for (idx = 0; idx < fd->closure_var_count; idx++) { |
| @@ -29267,8 +29657,8 @@ static int resolve_scope_private_field1(JSContext *ctx, · 16 unmodified lines |
| 29267 | 29657 | } |
| 29268 | 29658 | } |
| 29269 | 29659 | /* XXX: no line number info */ |
| 29270 | | − JS_ThrowSyntaxError(ctx, "undefined private field %s", |
| 29271 | | − JS_AtomGetStr(ctx, buf, sizeof(buf), var_name)); |
| 29660 | + JS_ThrowSyntaxErrorAtom(ctx, "undefined private field '%s'", |
| 29661 | + var_name); |
| 29272 | 29662 | return -1; |
| 29273 | 29663 | } else { |
| 29274 | 29664 | fd = fd->parent; |
| @@ -31535,9 +31925,8 @@ static int add_module_variables(JSContext *ctx, JSFunctionDef *fd) · 2260 unmodified lines |
| 31535 | 31925 | if (me->export_type == JS_EXPORT_TYPE_LOCAL) { |
| 31536 | 31926 | idx = find_closure_var(ctx, fd, me->local_name); |
| 31537 | 31927 | if (idx < 0) { |
| 31538 | | − char buf1[ATOM_GET_STR_BUF_SIZE]; |
| 31539 | | − JS_ThrowSyntaxError(ctx, "exported variable '%s' does not exist", |
| 31540 | | − JS_AtomGetStr(ctx, buf1, sizeof(buf1), me->local_name)); |
| 31928 | + JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does not exist", |
| 31929 | + me->local_name); |
| 31541 | 31930 | return -1; |
| 31542 | 31931 | } |
| 31543 | 31932 | me->u.local.var_idx = idx; |
| @@ -32559,6 +32948,8 @@ static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj, · 1015 unmodified lines |
| 32559 | 32948 | m = JS_VALUE_GET_PTR(fun_obj); |
| 32560 | 32949 | /* the module refcount should be >= 2 */ |
| 32561 | 32950 | JS_FreeValue(ctx, fun_obj); |
| 32951 | + if (js_create_module_function(ctx, m) < 0) |
| 32952 | + goto fail; |
| 32562 | 32953 | if (js_instantiate_module(ctx, m) < 0) |
| 32563 | 32954 | goto fail; |
| 32564 | 32955 | ret_val = js_evaluate_module(ctx, m); |
| @@ -32769,6 +33160,110 @@ int JS_ResolveModule(JSContext *ctx, JSValueConst obj) · 204 unmodified lines |
| 32769 | 33160 | return 0; |
| 32770 | 33161 | } |
| 32771 | 33162 | |
| 33163 | +/*******************************************************************/ |
| 33164 | +/* object list */ |
| 33165 | + |
| 33166 | +typedef struct { |
| 33167 | + JSObject *obj; |
| 33168 | + uint32_t hash_next; /* -1 if no next entry */ |
| 33169 | +} JSObjectListEntry; |
| 33170 | + |
| 33171 | +/* XXX: reuse it to optimize weak references */ |
| 33172 | +typedef struct { |
| 33173 | + JSObjectListEntry *object_tab; |
| 33174 | + int object_count; |
| 33175 | + int object_size; |
| 33176 | + uint32_t *hash_table; |
| 33177 | + uint32_t hash_size; |
| 33178 | +} JSObjectList; |
| 33179 | + |
| 33180 | +static void js_object_list_init(JSObjectList *s) |
| 33181 | +{ |
| 33182 | + memset(s, 0, sizeof(*s)); |
| 33183 | +} |
| 33184 | + |
| 33185 | +static uint32_t js_object_list_get_hash(JSObject *p, uint32_t hash_size) |
| 33186 | +{ |
| 33187 | + return ((uintptr_t)p * 3163) & (hash_size - 1); |
| 33188 | +} |
| 33189 | + |
| 33190 | +static int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s, |
| 33191 | + uint32_t new_hash_size) |
| 33192 | +{ |
| 33193 | + JSObjectListEntry *e; |
| 33194 | + uint32_t i, h, *new_hash_table; |
| 33195 | + |
| 33196 | + new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size); |
| 33197 | + if (!new_hash_table) |
| 33198 | + return -1; |
| 33199 | + js_free(ctx, s->hash_table); |
| 33200 | + s->hash_table = new_hash_table; |
| 33201 | + s->hash_size = new_hash_size; |
| 33202 | + |
| 33203 | + for(i = 0; i < s->hash_size; i++) { |
| 33204 | + s->hash_table[i] = -1; |
| 33205 | + } |
| 33206 | + for(i = 0; i < s->object_count; i++) { |
| 33207 | + e = &s->object_tab[i]; |
| 33208 | + h = js_object_list_get_hash(e->obj, s->hash_size); |
| 33209 | + e->hash_next = s->hash_table[h]; |
| 33210 | + s->hash_table[h] = i; |
| 33211 | + } |
| 33212 | + return 0; |
| 33213 | +} |
| 33214 | + |
| 33215 | +/* the reference count of 'obj' is not modified. Return 0 if OK, -1 if |
| 33216 | + memory error */ |
| 33217 | +static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj) |
| 33218 | +{ |
| 33219 | + JSObjectListEntry *e; |
| 33220 | + uint32_t h, new_hash_size; |
| 33221 | + |
| 33222 | + if (js_resize_array(ctx, (void *)&s->object_tab, |
| 33223 | + sizeof(s->object_tab[0]), |
| 33224 | + &s->object_size, s->object_count + 1)) |
| 33225 | + return -1; |
| 33226 | + if (unlikely((s->object_count + 1) >= s->hash_size)) { |
| 33227 | + new_hash_size = max_uint32(s->hash_size, 4); |
| 33228 | + while (new_hash_size <= s->object_count) |
| 33229 | + new_hash_size *= 2; |
| 33230 | + if (js_object_list_resize_hash(ctx, s, new_hash_size)) |
| 33231 | + return -1; |
| 33232 | + } |
| 33233 | + e = &s->object_tab[s->object_count++]; |
| 33234 | + h = js_object_list_get_hash(obj, s->hash_size); |
| 33235 | + e->obj = obj; |
| 33236 | + e->hash_next = s->hash_table[h]; |
| 33237 | + s->hash_table[h] = s->object_count - 1; |
| 33238 | + return 0; |
| 33239 | +} |
| 33240 | + |
| 33241 | +/* return -1 if not present or the object index */ |
| 33242 | +static int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj) |
| 33243 | +{ |
| 33244 | + JSObjectListEntry *e; |
| 33245 | + uint32_t h, p; |
| 33246 | + |
| 33247 | + /* must test empty size because there is no hash table */ |
| 33248 | + if (s->object_count == 0) |
| 33249 | + return -1; |
| 33250 | + h = js_object_list_get_hash(obj, s->hash_size); |
| 33251 | + p = s->hash_table[h]; |
| 33252 | + while (p != -1) { |
| 33253 | + e = &s->object_tab[p]; |
| 33254 | + if (e->obj == obj) |
| 33255 | + return p; |
| 33256 | + p = e->hash_next; |
| 33257 | + } |
| 33258 | + return -1; |
| 33259 | +} |
| 33260 | + |
| 33261 | +static void js_object_list_end(JSContext *ctx, JSObjectList *s) |
| 33262 | +{ |
| 33263 | + js_free(ctx, s->object_tab); |
| 33264 | + js_free(ctx, s->hash_table); |
| 33265 | +} |
| 33266 | + |
| 32772 | 33267 | /*******************************************************************/ |
| 32773 | 33268 | /* binary object writer & reader */ |
| 32774 | 33269 | |
| @@ -32788,6 +33283,12 @@ typedef enum BCTagEnum { · 13 unmodified lines |
| 32788 | 33283 | BC_TAG_TEMPLATE_OBJECT, |
| 32789 | 33284 | BC_TAG_FUNCTION_BYTECODE, |
| 32790 | 33285 | BC_TAG_MODULE, |
| 33286 | + BC_TAG_TYPED_ARRAY, |
| 33287 | + BC_TAG_ARRAY_BUFFER, |
| 33288 | + BC_TAG_SHARED_ARRAY_BUFFER, |
| 33289 | + BC_TAG_DATE, |
| 33290 | + BC_TAG_OBJECT_VALUE, |
| 33291 | + BC_TAG_OBJECT_REFERENCE, |
| 32791 | 33292 | } BCTagEnum; |
| 32792 | 33293 | |
| 32793 | 33294 | #ifdef CONFIG_BIGNUM |
| @@ -32805,14 +33306,21 @@ typedef enum BCTagEnum { · 11 unmodified lines |
| 32805 | 33306 | typedef struct BCWriterState { |
| 32806 | 33307 | JSContext *ctx; |
| 32807 | 33308 | DynBuf dbuf; |
| 32808 | | − BOOL byte_swap; |
| 32809 | | − BOOL allow_bytecode; |
| 33309 | + BOOL byte_swap : 8; |
| 33310 | + BOOL allow_bytecode : 8; |
| 33311 | + BOOL allow_sab : 8; |
| 33312 | + BOOL allow_reference : 8; |
| 32810 | 33313 | uint32_t first_atom; |
| 32811 | 33314 | uint32_t *atom_to_idx; |
| 32812 | 33315 | int atom_to_idx_size; |
| 32813 | 33316 | JSAtom *idx_to_atom; |
| 32814 | 33317 | int idx_to_atom_count; |
| 32815 | 33318 | int idx_to_atom_size; |
| 33319 | + uint8_t **sab_tab; |
| 33320 | + int sab_tab_len; |
| 33321 | + int sab_tab_size; |
| 33322 | + /* list of referenced objects (used if allow_reference = TRUE) */ |
| 33323 | + JSObjectList object_list; |
| 32816 | 33324 | } BCWriterState; |
| 32817 | 33325 | |
| 32818 | 33326 | #ifdef DUMP_READ_OBJECT |
| @@ -32833,6 +33341,12 @@ static const char * const bc_tag_str[] = { · 14 unmodified lines |
| 32833 | 33341 | "template", |
| 32834 | 33342 | "function", |
| 32835 | 33343 | "module", |
| 33344 | + "TypedArray", |
| 33345 | + "ArrayBuffer", |
| 33346 | + "SharedArrayBuffer", |
| 33347 | + "Date", |
| 33348 | + "ObjectValue", |
| 33349 | + "ObjectReference", |
| 32836 | 33350 | }; |
| 32837 | 33351 | #endif |
| 32838 | 33352 | |
| @@ -32892,36 +33406,20 @@ static int bc_atom_to_idx(BCWriterState *s, uint32_t *pres, JSAtom atom) · 53 unmodified lines |
| 32892 | 33406 | return 0; |
| 32893 | 33407 | } |
| 32894 | 33408 | if (atom >= s->atom_to_idx_size) { |
| 32895 | | − size_t new_size, i, slack; |
| 32896 | | − uint32_t *new_tab; |
| 32897 | | − /* XXX: potential arithmetic overflow */ |
| 32898 | | − new_size = s->atom_to_idx_size * 3 / 2; |
| 32899 | | − if ((atom + 1) > new_size) |
| 32900 | | − new_size = atom + 1; |
| 32901 | | − new_tab = js_realloc2(s->ctx, s->atom_to_idx, |
| 32902 | | − new_size * sizeof(s->atom_to_idx[0]), &slack); |
| 32903 | | − if (!new_tab) |
| 32904 | | − goto fail; |
| 32905 | | − new_size += slack / sizeof(*new_tab); |
| 32906 | | − for(i = s->atom_to_idx_size; i < new_size; i++) |
| 32907 | | − new_tab[i] = 0; |
| 32908 | | − s->atom_to_idx = new_tab; |
| 32909 | | − s->atom_to_idx_size = new_size; |
| 32910 | | − } |
| 32911 | | − if ((s->idx_to_atom_count + 1) > s->idx_to_atom_size) { |
| 32912 | | − size_t new_size, slack; |
| 32913 | | − JSAtom *new_tab; |
| 32914 | | − new_size = s->idx_to_atom_size * 3 / 2; |
| 32915 | | − if ((s->idx_to_atom_count + 1) > new_size) |
| 32916 | | − new_size = s->idx_to_atom_count + 1; |
| 32917 | | − new_tab = js_realloc2(s->ctx, s->idx_to_atom, |
| 32918 | | − new_size * sizeof(s->idx_to_atom[0]), &slack); |
| 32919 | | − if (!new_tab) |
| 32920 | | − goto fail; |
| 32921 | | − new_size += slack / sizeof(*new_tab); |
| 32922 | | − s->idx_to_atom = new_tab; |
| 32923 | | − s->idx_to_atom_size = new_size; |
| 33409 | + int old_size, i; |
| 33410 | + old_size = s->atom_to_idx_size; |
| 33411 | + if (js_resize_array(s->ctx, (void **)&s->atom_to_idx, |
| 33412 | + sizeof(s->atom_to_idx[0]), &s->atom_to_idx_size, |
| 33413 | + atom + 1)) |
| 33414 | + return -1; |
| 33415 | + /* XXX: could add a specific js_resize_array() function to do it */ |
| 33416 | + for(i = old_size; i < s->atom_to_idx_size; i++) |
| 33417 | + s->atom_to_idx[i] = 0; |
| 32924 | 33418 | } |
| 33419 | + if (js_resize_array(s->ctx, (void **)&s->idx_to_atom, |
| 33420 | + sizeof(s->idx_to_atom[0]), |
| 33421 | + &s->idx_to_atom_size, s->idx_to_atom_count + 1)) |
| 33422 | + goto fail; |
| 32925 | 33423 | |
| 32926 | 33424 | v = s->idx_to_atom_count++; |
| 32927 | 33425 | s->idx_to_atom[v] = atom + s->first_atom; |
| @@ -33204,10 +33702,276 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) · 276 unmodified lines |
| 33204 | 33702 | } |
| 33205 | 33703 | #endif /* CONFIG_BIGNUM */ |
| 33206 | 33704 | |
| 33705 | +static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj); |
| 33706 | + |
| 33707 | +static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) |
| 33708 | +{ |
| 33709 | + JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj); |
| 33710 | + uint32_t flags; |
| 33711 | + int idx, i; |
| 33712 | + |
| 33713 | + bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE); |
| 33714 | + flags = idx = 0; |
| 33715 | + bc_set_flags(&flags, &idx, b->has_prototype, 1); |
| 33716 | + bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1); |
| 33717 | + bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1); |
| 33718 | + bc_set_flags(&flags, &idx, b->need_home_object, 1); |
| 33719 | + bc_set_flags(&flags, &idx, b->func_kind, 2); |
| 33720 | + bc_set_flags(&flags, &idx, b->new_target_allowed, 1); |
| 33721 | + bc_set_flags(&flags, &idx, b->super_call_allowed, 1); |
| 33722 | + bc_set_flags(&flags, &idx, b->super_allowed, 1); |
| 33723 | + bc_set_flags(&flags, &idx, b->arguments_allowed, 1); |
| 33724 | + bc_set_flags(&flags, &idx, b->has_debug, 1); |
| 33725 | + bc_set_flags(&flags, &idx, b->backtrace_barrier, 1); |
| 33726 | + assert(idx <= 16); |
| 33727 | + bc_put_u16(s, flags); |
| 33728 | + bc_put_u8(s, b->js_mode); |
| 33729 | + bc_put_atom(s, b->func_name); |
| 33730 | + |
| 33731 | + bc_put_leb128(s, b->arg_count); |
| 33732 | + bc_put_leb128(s, b->var_count); |
| 33733 | + bc_put_leb128(s, b->defined_arg_count); |
| 33734 | + bc_put_leb128(s, b->stack_size); |
| 33735 | + bc_put_leb128(s, b->closure_var_count); |
| 33736 | + bc_put_leb128(s, b->cpool_count); |
| 33737 | + bc_put_leb128(s, b->byte_code_len); |
| 33738 | + if (b->vardefs) { |
| 33739 | + bc_put_leb128(s, b->arg_count + b->var_count); |
| 33740 | + for(i = 0; i < b->arg_count + b->var_count; i++) { |
| 33741 | + JSVarDef *vd = &b->vardefs[i]; |
| 33742 | + bc_put_atom(s, vd->var_name); |
| 33743 | + bc_put_leb128(s, vd->scope_level); |
| 33744 | + bc_put_leb128(s, vd->scope_next + 1); |
| 33745 | + flags = idx = 0; |
| 33746 | + bc_set_flags(&flags, &idx, vd->var_kind, 4); |
| 33747 | + bc_set_flags(&flags, &idx, vd->is_func_var, 1); |
| 33748 | + bc_set_flags(&flags, &idx, vd->is_const, 1); |
| 33749 | + bc_set_flags(&flags, &idx, vd->is_lexical, 1); |
| 33750 | + bc_set_flags(&flags, &idx, vd->is_captured, 1); |
| 33751 | + assert(idx <= 8); |
| 33752 | + bc_put_u8(s, flags); |
| 33753 | + } |
| 33754 | + } else { |
| 33755 | + bc_put_leb128(s, 0); |
| 33756 | + } |
| 33757 | + |
| 33758 | + for(i = 0; i < b->closure_var_count; i++) { |
| 33759 | + JSClosureVar *cv = &b->closure_var[i]; |
| 33760 | + bc_put_atom(s, cv->var_name); |
| 33761 | + bc_put_leb128(s, cv->var_idx); |
| 33762 | + flags = idx = 0; |
| 33763 | + bc_set_flags(&flags, &idx, cv->is_local, 1); |
| 33764 | + bc_set_flags(&flags, &idx, cv->is_arg, 1); |
| 33765 | + bc_set_flags(&flags, &idx, cv->is_const, 1); |
| 33766 | + bc_set_flags(&flags, &idx, cv->is_lexical, 1); |
| 33767 | + bc_set_flags(&flags, &idx, cv->var_kind, 4); |
| 33768 | + assert(idx <= 8); |
| 33769 | + bc_put_u8(s, flags); |
| 33770 | + } |
| 33771 | + |
| 33772 | + if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len)) |
| 33773 | + goto fail; |
| 33774 | + |
| 33775 | + if (b->has_debug) { |
| 33776 | + bc_put_atom(s, b->debug.filename); |
| 33777 | + bc_put_leb128(s, b->debug.line_num); |
| 33778 | + bc_put_leb128(s, b->debug.pc2line_len); |
| 33779 | + dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len); |
| 33780 | + } |
| 33781 | + |
| 33782 | + for(i = 0; i < b->cpool_count; i++) { |
| 33783 | + if (JS_WriteObjectRec(s, b->cpool[i])) |
| 33784 | + goto fail; |
| 33785 | + } |
| 33786 | + return 0; |
| 33787 | + fail: |
| 33788 | + return -1; |
| 33789 | +} |
| 33790 | + |
| 33791 | +static int JS_WriteModule(BCWriterState *s, JSValueConst obj) |
| 33792 | +{ |
| 33793 | + JSModuleDef *m = JS_VALUE_GET_PTR(obj); |
| 33794 | + int i; |
| 33795 | + |
| 33796 | + bc_put_u8(s, BC_TAG_MODULE); |
| 33797 | + bc_put_atom(s, m->module_name); |
| 33798 | + |
| 33799 | + bc_put_leb128(s, m->req_module_entries_count); |
| 33800 | + for(i = 0; i < m->req_module_entries_count; i++) { |
| 33801 | + JSReqModuleEntry *rme = &m->req_module_entries[i]; |
| 33802 | + bc_put_atom(s, rme->module_name); |
| 33803 | + } |
| 33804 | + |
| 33805 | + bc_put_leb128(s, m->export_entries_count); |
| 33806 | + for(i = 0; i < m->export_entries_count; i++) { |
| 33807 | + JSExportEntry *me = &m->export_entries[i]; |
| 33808 | + bc_put_u8(s, me->export_type); |
| 33809 | + if (me->export_type == JS_EXPORT_TYPE_LOCAL) { |
| 33810 | + bc_put_leb128(s, me->u.local.var_idx); |
| 33811 | + } else { |
| 33812 | + bc_put_leb128(s, me->u.req_module_idx); |
| 33813 | + bc_put_atom(s, me->local_name); |
| 33814 | + } |
| 33815 | + bc_put_atom(s, me->export_name); |
| 33816 | + } |
| 33817 | + |
| 33818 | + bc_put_leb128(s, m->star_export_entries_count); |
| 33819 | + for(i = 0; i < m->star_export_entries_count; i++) { |
| 33820 | + JSStarExportEntry *se = &m->star_export_entries[i]; |
| 33821 | + bc_put_leb128(s, se->req_module_idx); |
| 33822 | + } |
| 33823 | + |
| 33824 | + bc_put_leb128(s, m->import_entries_count); |
| 33825 | + for(i = 0; i < m->import_entries_count; i++) { |
| 33826 | + JSImportEntry *mi = &m->import_entries[i]; |
| 33827 | + bc_put_leb128(s, mi->var_idx); |
| 33828 | + bc_put_atom(s, mi->import_name); |
| 33829 | + bc_put_leb128(s, mi->req_module_idx); |
| 33830 | + } |
| 33831 | + |
| 33832 | + if (JS_WriteObjectRec(s, m->func_obj)) |
| 33833 | + goto fail; |
| 33834 | + return 0; |
| 33835 | + fail: |
| 33836 | + return -1; |
| 33837 | +} |
| 33838 | + |
| 33839 | +static int JS_WriteArray(BCWriterState *s, JSValueConst obj) |
| 33840 | +{ |
| 33841 | + JSObject *p = JS_VALUE_GET_OBJ(obj); |
| 33842 | + uint32_t i, len; |
| 33843 | + JSValue val; |
| 33844 | + int ret; |
| 33845 | + BOOL is_template; |
| 33846 | + |
| 33847 | + if (s->allow_bytecode && !p->extensible) { |
| 33848 | + /* not extensible array: we consider it is a |
| 33849 | + template when we are saving bytecode */ |
| 33850 | + bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT); |
| 33851 | + is_template = TRUE; |
| 33852 | + } else { |
| 33853 | + bc_put_u8(s, BC_TAG_ARRAY); |
| 33854 | + is_template = FALSE; |
| 33855 | + } |
| 33856 | + if (js_get_length32(s->ctx, &len, obj)) |
| 33857 | + goto fail1; |
| 33858 | + bc_put_leb128(s, len); |
| 33859 | + for(i = 0; i < len; i++) { |
| 33860 | + val = JS_GetPropertyUint32(s->ctx, obj, i); |
| 33861 | + if (JS_IsException(val)) |
| 33862 | + goto fail1; |
| 33863 | + ret = JS_WriteObjectRec(s, val); |
| 33864 | + JS_FreeValue(s->ctx, val); |
| 33865 | + if (ret) |
| 33866 | + goto fail1; |
| 33867 | + } |
| 33868 | + if (is_template) { |
| 33869 | + val = JS_GetProperty(s->ctx, obj, JS_ATOM_raw); |
| 33870 | + if (JS_IsException(val)) |
| 33871 | + goto fail1; |
| 33872 | + ret = JS_WriteObjectRec(s, val); |
| 33873 | + JS_FreeValue(s->ctx, val); |
| 33874 | + if (ret) |
| 33875 | + goto fail1; |
| 33876 | + } |
| 33877 | + return 0; |
| 33878 | + fail1: |
| 33879 | + return -1; |
| 33880 | +} |
| 33881 | + |
| 33882 | +static int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj) |
| 33883 | +{ |
| 33884 | + JSObject *p = JS_VALUE_GET_OBJ(obj); |
| 33885 | + uint32_t i, prop_count; |
| 33886 | + JSShape *sh; |
| 33887 | + JSShapeProperty *pr; |
| 33888 | + int pass; |
| 33889 | + JSAtom atom; |
| 33890 | + |
| 33891 | + bc_put_u8(s, BC_TAG_OBJECT); |
| 33892 | + prop_count = 0; |
| 33893 | + sh = p->shape; |
| 33894 | + for(pass = 0; pass < 2; pass++) { |
| 33895 | + if (pass == 1) |
| 33896 | + bc_put_leb128(s, prop_count); |
| 33897 | + for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) { |
| 33898 | + atom = pr->atom; |
| 33899 | + if (atom != JS_ATOM_NULL && |
| 33900 | + JS_AtomIsString(s->ctx, atom) && |
| 33901 | + (pr->flags & JS_PROP_ENUMERABLE)) { |
| 33902 | + if (pr->flags & JS_PROP_TMASK) { |
| 33903 | + JS_ThrowTypeError(s->ctx, "only value properties are supported"); |
| 33904 | + goto fail; |
| 33905 | + } |
| 33906 | + if (pass == 0) { |
| 33907 | + prop_count++; |
| 33908 | + } else { |
| 33909 | + bc_put_atom(s, atom); |
| 33910 | + if (JS_WriteObjectRec(s, p->prop[i].u.value)) |
| 33911 | + goto fail; |
| 33912 | + } |
| 33913 | + } |
| 33914 | + } |
| 33915 | + } |
| 33916 | + return 0; |
| 33917 | + fail: |
| 33918 | + return -1; |
| 33919 | +} |
| 33920 | + |
| 33921 | +static int JS_WriteTypedArray(BCWriterState *s, JSValueConst obj) |
| 33922 | +{ |
| 33923 | + JSObject *p = JS_VALUE_GET_OBJ(obj); |
| 33924 | + JSTypedArray *ta = p->u.typed_array; |
| 33925 | + |
| 33926 | + bc_put_u8(s, BC_TAG_TYPED_ARRAY); |
| 33927 | + bc_put_u8(s, p->class_id - JS_CLASS_UINT8C_ARRAY); |
| 33928 | + bc_put_leb128(s, p->u.array.count); |
| 33929 | + bc_put_leb128(s, ta->offset); |
| 33930 | + if (JS_WriteObjectRec(s, JS_MKPTR(JS_TAG_OBJECT, ta->buffer))) |
| 33931 | + return -1; |
| 33932 | + return 0; |
| 33933 | +} |
| 33934 | + |
| 33935 | +static int JS_WriteArrayBuffer(BCWriterState *s, JSValueConst obj) |
| 33936 | +{ |
| 33937 | + JSObject *p = JS_VALUE_GET_OBJ(obj); |
| 33938 | + JSArrayBuffer *abuf = p->u.array_buffer; |
| 33939 | + if (abuf->detached) { |
| 33940 | + JS_ThrowTypeErrorDetachedArrayBuffer(s->ctx); |
| 33941 | + return -1; |
| 33942 | + } |
| 33943 | + bc_put_u8(s, BC_TAG_ARRAY_BUFFER); |
| 33944 | + bc_put_leb128(s, abuf->byte_length); |
| 33945 | + dbuf_put(&s->dbuf, abuf->data, abuf->byte_length); |
| 33946 | + return 0; |
| 33947 | +} |
| 33948 | + |
| 33949 | +static int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValueConst obj) |
| 33950 | +{ |
| 33951 | + JSObject *p = JS_VALUE_GET_OBJ(obj); |
| 33952 | + JSArrayBuffer *abuf = p->u.array_buffer; |
| 33953 | + assert(!abuf->detached); /* SharedArrayBuffer are never detached */ |
| 33954 | + bc_put_u8(s, BC_TAG_SHARED_ARRAY_BUFFER); |
| 33955 | + bc_put_leb128(s, abuf->byte_length); |
| 33956 | + bc_put_u64(s, (uintptr_t)abuf->data); |
| 33957 | + if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]), |
| 33958 | + &s->sab_tab_size, s->sab_tab_len + 1)) |
| 33959 | + return -1; |
| 33960 | + /* keep the SAB pointer so that the user can clone it or free it */ |
| 33961 | + s->sab_tab[s->sab_tab_len++] = abuf->data; |
| 33962 | + return 0; |
| 33963 | +} |
| 33964 | + |
| 33207 | 33965 | static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) |
| 33208 | 33966 | { |
| 33209 | | − uint32_t tag = JS_VALUE_GET_NORM_TAG(obj); |
| 33967 | + uint32_t tag; |
| 33968 | + |
| 33969 | + if (js_check_stack_overflow(s->ctx->rt, 0)) { |
| 33970 | + JS_ThrowStackOverflow(s->ctx); |
| 33971 | + return -1; |
| 33972 | + } |
| 33210 | 33973 | |
| 33974 | + tag = JS_VALUE_GET_NORM_TAG(obj); |
| 33211 | 33975 | switch(tag) { |
| 33212 | 33976 | case JS_TAG_NULL: |
| 33213 | 33977 | bc_put_u8(s, BC_TAG_NULL); |
| @@ -33238,218 +34002,82 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) · 24 unmodified lines |
| 33238 | 34002 | } |
| 33239 | 34003 | break; |
| 33240 | 34004 | case JS_TAG_FUNCTION_BYTECODE: |
| 33241 | | − { |
| 33242 | | − JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj); |
| 33243 | | − uint32_t flags; |
| 33244 | | − int idx, i; |
| 33245 | | − |
| 33246 | | − if (!s->allow_bytecode) |
| 33247 | | − goto invalid_tag; |
| 33248 | | − bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE); |
| 33249 | | − flags = idx = 0; |
| 33250 | | − bc_set_flags(&flags, &idx, b->has_prototype, 1); |
| 33251 | | − bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1); |
| 33252 | | − bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1); |
| 33253 | | − bc_set_flags(&flags, &idx, b->need_home_object, 1); |
| 33254 | | − bc_set_flags(&flags, &idx, b->func_kind, 2); |
| 33255 | | − bc_set_flags(&flags, &idx, b->new_target_allowed, 1); |
| 33256 | | − bc_set_flags(&flags, &idx, b->super_call_allowed, 1); |
| 33257 | | − bc_set_flags(&flags, &idx, b->super_allowed, 1); |
| 33258 | | − bc_set_flags(&flags, &idx, b->arguments_allowed, 1); |
| 33259 | | − bc_set_flags(&flags, &idx, b->has_debug, 1); |
| 33260 | | − bc_set_flags(&flags, &idx, b->backtrace_barrier, 1); |
| 33261 | | − assert(idx <= 16); |
| 33262 | | − bc_put_u16(s, flags); |
| 33263 | | − bc_put_u8(s, b->js_mode); |
| 33264 | | − bc_put_atom(s, b->func_name); |
| 33265 | | − |
| 33266 | | − bc_put_leb128(s, b->arg_count); |
| 33267 | | − bc_put_leb128(s, b->var_count); |
| 33268 | | − bc_put_leb128(s, b->defined_arg_count); |
| 33269 | | − bc_put_leb128(s, b->stack_size); |
| 33270 | | − bc_put_leb128(s, b->closure_var_count); |
| 33271 | | − bc_put_leb128(s, b->cpool_count); |
| 33272 | | − bc_put_leb128(s, b->byte_code_len); |
| 33273 | | − if (b->vardefs) { |
| 33274 | | − bc_put_leb128(s, b->arg_count + b->var_count); |
| 33275 | | − for(i = 0; i < b->arg_count + b->var_count; i++) { |
| 33276 | | − JSVarDef *vd = &b->vardefs[i]; |
| 33277 | | − bc_put_atom(s, vd->var_name); |
| 33278 | | − bc_put_leb128(s, vd->scope_level); |
| 33279 | | − bc_put_leb128(s, vd->scope_next + 1); |
| 33280 | | − flags = idx = 0; |
| 33281 | | − bc_set_flags(&flags, &idx, vd->var_kind, 4); |
| 33282 | | − bc_set_flags(&flags, &idx, vd->is_func_var, 1); |
| 33283 | | − bc_set_flags(&flags, &idx, vd->is_const, 1); |
| 33284 | | − bc_set_flags(&flags, &idx, vd->is_lexical, 1); |
| 33285 | | − bc_set_flags(&flags, &idx, vd->is_captured, 1); |
| 33286 | | − assert(idx <= 8); |
| 33287 | | − bc_put_u8(s, flags); |
| 33288 | | − } |
| 33289 | | − } else { |
| 33290 | | − bc_put_leb128(s, 0); |
| 33291 | | − } |
| 33292 | | − |
| 33293 | | − for(i = 0; i < b->closure_var_count; i++) { |
| 33294 | | − JSClosureVar *cv = &b->closure_var[i]; |
| 33295 | | − bc_put_atom(s, cv->var_name); |
| 33296 | | − bc_put_leb128(s, cv->var_idx); |
| 33297 | | − flags = idx = 0; |
| 33298 | | − bc_set_flags(&flags, &idx, cv->is_local, 1); |
| 33299 | | − bc_set_flags(&flags, &idx, cv->is_arg, 1); |
| 33300 | | − bc_set_flags(&flags, &idx, cv->is_const, 1); |
| 33301 | | − bc_set_flags(&flags, &idx, cv->is_lexical, 1); |
| 33302 | | − bc_set_flags(&flags, &idx, cv->var_kind, 4); |
| 33303 | | − assert(idx <= 8); |
| 33304 | | − bc_put_u8(s, flags); |
| 33305 | | − } |
| 33306 | | − |
| 33307 | | − if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len)) |
| 33308 | | − goto fail; |
| 33309 | | − |
| 33310 | | − if (b->has_debug) { |
| 33311 | | − bc_put_atom(s, b->debug.filename); |
| 33312 | | − bc_put_leb128(s, b->debug.line_num); |
| 33313 | | − bc_put_leb128(s, b->debug.pc2line_len); |
| 33314 | | − dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len); |
| 33315 | | − } |
| 33316 | | − |
| 33317 | | − for(i = 0; i < b->cpool_count; i++) { |
| 33318 | | − if (JS_WriteObjectRec(s, b->cpool[i])) |
| 33319 | | − goto fail; |
| 33320 | | − } |
| 33321 | | − } |
| 34005 | + if (!s->allow_bytecode) |
| 34006 | + goto invalid_tag; |
| 34007 | + if (JS_WriteFunctionTag(s, obj)) |
| 34008 | + goto fail; |
| 33322 | 34009 | break; |
| 33323 | 34010 | case JS_TAG_MODULE: |
| 33324 | | − { |
| 33325 | | − JSModuleDef *m = JS_VALUE_GET_PTR(obj); |
| 33326 | | − int i; |
| 33327 | | − |
| 33328 | | − if (!s->allow_bytecode) |
| 33329 | | − goto invalid_tag; |
| 33330 | | − bc_put_u8(s, BC_TAG_MODULE); |
| 33331 | | − bc_put_atom(s, m->module_name); |
| 33332 | | − |
| 33333 | | − bc_put_leb128(s, m->req_module_entries_count); |
| 33334 | | − for(i = 0; i < m->req_module_entries_count; i++) { |
| 33335 | | − JSReqModuleEntry *rme = &m->req_module_entries[i]; |
| 33336 | | − bc_put_atom(s, rme->module_name); |
| 33337 | | − } |
| 33338 | | − |
| 33339 | | − bc_put_leb128(s, m->export_entries_count); |
| 33340 | | − for(i = 0; i < m->export_entries_count; i++) { |
| 33341 | | − JSExportEntry *me = &m->export_entries[i]; |
| 33342 | | − bc_put_u8(s, me->export_type); |
| 33343 | | − if (me->export_type == JS_EXPORT_TYPE_LOCAL) { |
| 33344 | | − bc_put_leb128(s, me->u.local.var_idx); |
| 33345 | | − } else { |
| 33346 | | − bc_put_leb128(s, me->u.req_module_idx); |
| 33347 | | − bc_put_atom(s, me->local_name); |
| 33348 | | − } |
| 33349 | | − bc_put_atom(s, me->export_name); |
| 33350 | | − } |
| 33351 | | − |
| 33352 | | − bc_put_leb128(s, m->star_export_entries_count); |
| 33353 | | − for(i = 0; i < m->star_export_entries_count; i++) { |
| 33354 | | − JSStarExportEntry *se = &m->star_export_entries[i]; |
| 33355 | | − bc_put_leb128(s, se->req_module_idx); |
| 33356 | | − } |
| 33357 | | − |
| 33358 | | − bc_put_leb128(s, m->import_entries_count); |
| 33359 | | − for(i = 0; i < m->import_entries_count; i++) { |
| 33360 | | − JSImportEntry *mi = &m->import_entries[i]; |
| 33361 | | − bc_put_leb128(s, mi->var_idx); |
| 33362 | | − bc_put_atom(s, mi->import_name); |
| 33363 | | − bc_put_leb128(s, mi->req_module_idx); |
| 33364 | | − } |
| 33365 | | − |
| 33366 | | − if (JS_WriteObjectRec(s, m->func_obj)) |
| 33367 | | − goto fail; |
| 33368 | | − } |
| 34011 | + if (!s->allow_bytecode) |
| 34012 | + goto invalid_tag; |
| 34013 | + if (JS_WriteModule(s, obj)) |
| 34014 | + goto fail; |
| 33369 | 34015 | break; |
| 33370 | 34016 | case JS_TAG_OBJECT: |
| 33371 | 34017 | { |
| 33372 | 34018 | JSObject *p = JS_VALUE_GET_OBJ(obj); |
| 33373 | | − uint32_t i, prop_count, len; |
| 33374 | | − JSShape *sh; |
| 33375 | | − JSShapeProperty *pr; |
| 33376 | | − JSValue val; |
| 33377 | | − int ret, pass; |
| 33378 | | − BOOL is_template; |
| 33379 | | − JSAtom atom; |
| 33380 | | − |
| 33381 | | − if (p->class_id != JS_CLASS_ARRAY && |
| 33382 | | − p->class_id != JS_CLASS_OBJECT) { |
| 33383 | | − JS_ThrowTypeError(s->ctx, "unsupported object class"); |
| 33384 | | − goto fail; |
| 33385 | | − } |
| 33386 | | − if (p->tmp_mark) { |
| 33387 | | − JS_ThrowTypeError(s->ctx, "circular reference"); |
| 33388 | | − goto fail; |
| 33389 | | − } |
| 33390 | | − p->tmp_mark = 1; |
| 33391 | | − if (p->class_id == JS_CLASS_ARRAY) { |
| 33392 | | − if (s->allow_bytecode && !p->extensible) { |
| 33393 | | − /* not extensible array: we consider it is a |
| 33394 | | − template when we are saving bytecode */ |
| 33395 | | − bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT); |
| 33396 | | − is_template = TRUE; |
| 34019 | + int ret, idx; |
| 34020 | + |
| 34021 | + if (s->allow_reference) { |
| 34022 | + idx = js_object_list_find(s->ctx, &s->object_list, p); |
| 34023 | + if (idx >= 0) { |
| 34024 | + bc_put_u8(s, BC_TAG_OBJECT_REFERENCE); |
| 34025 | + bc_put_leb128(s, idx); |
| 34026 | + break; |
| 33397 | 34027 | } else { |
| 33398 | | − bc_put_u8(s, BC_TAG_ARRAY); |
| 33399 | | − is_template = FALSE; |
| 33400 | | − } |
| 33401 | | − if (js_get_length32(s->ctx, &len, obj)) |
| 33402 | | − goto fail1; |
| 33403 | | − bc_put_leb128(s, len); |
| 33404 | | − for(i = 0; i < len; i++) { |
| 33405 | | − val = JS_GetPropertyUint32(s->ctx, obj, i); |
| 33406 | | − if (JS_IsException(val)) |
| 33407 | | − goto fail1; |
| 33408 | | − ret = JS_WriteObjectRec(s, val); |
| 33409 | | − JS_FreeValue(s->ctx, val); |
| 33410 | | − if (ret) |
| 33411 | | − goto fail1; |
| 33412 | | − } |
| 33413 | | − if (is_template) { |
| 33414 | | − val = JS_GetProperty(s->ctx, obj, JS_ATOM_raw); |
| 33415 | | − if (JS_IsException(val)) |
| 33416 | | − goto fail1; |
| 33417 | | − ret = JS_WriteObjectRec(s, val); |
| 33418 | | − JS_FreeValue(s->ctx, val); |
| 33419 | | − if (ret) |
| 33420 | | − goto fail1; |
| 34028 | + if (js_object_list_add(s->ctx, &s->object_list, p)) |
| 34029 | + goto fail; |
| 33421 | 34030 | } |
| 33422 | 34031 | } else { |
| 33423 | | − bc_put_u8(s, BC_TAG_OBJECT); |
| 33424 | | − prop_count = 0; |
| 33425 | | − sh = p->shape; |
| 33426 | | − for(pass = 0; pass < 2; pass++) { |
| 33427 | | − if (pass == 1) |
| 33428 | | − bc_put_leb128(s, prop_count); |
| 33429 | | − for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) { |
| 33430 | | − atom = pr->atom; |
| 33431 | | − if (atom != JS_ATOM_NULL && |
| 33432 | | − JS_AtomIsString(s->ctx, atom) && |
| 33433 | | − (pr->flags & JS_PROP_ENUMERABLE)) { |
| 33434 | | − if (pr->flags & JS_PROP_TMASK) { |
| 33435 | | − JS_ThrowTypeError(s->ctx, "only value properties are supported"); |
| 33436 | | − goto fail; |
| 33437 | | − } |
| 33438 | | − if (pass == 0) { |
| 33439 | | − prop_count++; |
| 33440 | | − } else { |
| 33441 | | − bc_put_atom(s, atom); |
| 33442 | | − if (JS_WriteObjectRec(s, p->prop[i].u.value)) { |
| 33443 | | − fail1: |
| 33444 | | − p->tmp_mark = 0; |
| 33445 | | − goto fail; |
| 33446 | | − } |
| 33447 | | − } |
| 33448 | | − } |
| 33449 | | − } |
| 34032 | + if (p->tmp_mark) { |
| 34033 | + JS_ThrowTypeError(s->ctx, "circular reference"); |
| 34034 | + goto fail; |
| 34035 | + } |
| 34036 | + p->tmp_mark = 1; |
| 34037 | + } |
| 34038 | + switch(p->class_id) { |
| 34039 | + case JS_CLASS_ARRAY: |
| 34040 | + ret = JS_WriteArray(s, obj); |
| 34041 | + break; |
| 34042 | + case JS_CLASS_OBJECT: |
| 34043 | + ret = JS_WriteObjectTag(s, obj); |
| 34044 | + break; |
| 34045 | + case JS_CLASS_ARRAY_BUFFER: |
| 34046 | + ret = JS_WriteArrayBuffer(s, obj); |
| 34047 | + break; |
| 34048 | + case JS_CLASS_SHARED_ARRAY_BUFFER: |
| 34049 | + if (!s->allow_sab) |
| 34050 | + goto invalid_tag; |
| 34051 | + ret = JS_WriteSharedArrayBuffer(s, obj); |
| 34052 | + break; |
| 34053 | + case JS_CLASS_DATE: |
| 34054 | + bc_put_u8(s, BC_TAG_DATE); |
| 34055 | + ret = JS_WriteObjectRec(s, p->u.object_data); |
| 34056 | + break; |
| 34057 | + case JS_CLASS_NUMBER: |
| 34058 | + case JS_CLASS_STRING: |
| 34059 | + case JS_CLASS_BOOLEAN: |
| 34060 | +#ifdef CONFIG_BIGNUM |
| 34061 | + case JS_CLASS_BIG_INT: |
| 34062 | + case JS_CLASS_BIG_FLOAT: |
| 34063 | + case JS_CLASS_BIG_DECIMAL: |
| 34064 | +#endif |
| 34065 | + bc_put_u8(s, BC_TAG_OBJECT_VALUE); |
| 34066 | + ret = JS_WriteObjectRec(s, p->u.object_data); |
| 34067 | + break; |
| 34068 | + default: |
| 34069 | + if (p->class_id >= JS_CLASS_UINT8C_ARRAY && |
| 34070 | + p->class_id <= JS_CLASS_FLOAT64_ARRAY) { |
| 34071 | + ret = JS_WriteTypedArray(s, obj); |
| 34072 | + } else { |
| 34073 | + JS_ThrowTypeError(s->ctx, "unsupported object class"); |
| 34074 | + ret = -1; |
| 33450 | 34075 | } |
| 34076 | + break; |
| 33451 | 34077 | } |
| 33452 | 34078 | p->tmp_mark = 0; |
| 34079 | + if (ret) |
| 34080 | + goto fail; |
| 33453 | 34081 | } |
| 33454 | 34082 | break; |
| 33455 | 34083 | #ifdef CONFIG_BIGNUM |
| @@ -33511,8 +34139,8 @@ static int JS_WriteObjectAtoms(BCWriterState *s) · 55 unmodified lines |
| 33511 | 34139 | return -1; |
| 33512 | 34140 | } |
| 33513 | 34141 | |
| 33514 | | −uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, |
| 33515 | | − int flags) |
| 34142 | +uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, |
| 34143 | + int flags, uint8_t ***psab_tab, size_t *psab_tab_len) |
| 33516 | 34144 | { |
| 33517 | 34145 | BCWriterState ss, *s = &ss; |
| 33518 | 34146 | |
| @@ -33521,29 +34149,48 @@ uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, · 2 unmodified lines |
| 33521 | 34149 | /* XXX: byte swapped output is untested */ |
| 33522 | 34150 | s->byte_swap = ((flags & JS_WRITE_OBJ_BSWAP) != 0); |
| 33523 | 34151 | s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0); |
| 34152 | + s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0); |
| 34153 | + s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0); |
| 33524 | 34154 | /* XXX: could use a different version when bytecode is included */ |
| 33525 | 34155 | if (s->allow_bytecode) |
| 33526 | 34156 | s->first_atom = JS_ATOM_END; |
| 33527 | 34157 | else |
| 33528 | 34158 | s->first_atom = 1; |
| 33529 | 34159 | js_dbuf_init(ctx, &s->dbuf); |
| 33530 | | − |
| 34160 | + js_object_list_init(&s->object_list); |
| 34161 | + |
| 33531 | 34162 | if (JS_WriteObjectRec(s, obj)) |
| 33532 | 34163 | goto fail; |
| 33533 | 34164 | if (JS_WriteObjectAtoms(s)) |
| 33534 | 34165 | goto fail; |
| 34166 | + js_object_list_end(ctx, &s->object_list); |
| 33535 | 34167 | js_free(ctx, s->atom_to_idx); |
| 33536 | 34168 | js_free(ctx, s->idx_to_atom); |
| 33537 | 34169 | *psize = s->dbuf.size; |
| 34170 | + if (psab_tab) |
| 34171 | + *psab_tab = s->sab_tab; |
| 34172 | + if (psab_tab_len) |
| 34173 | + *psab_tab_len = s->sab_tab_len; |
| 33538 | 34174 | return s->dbuf.buf; |
| 33539 | 34175 | fail: |
| 34176 | + js_object_list_end(ctx, &s->object_list); |
| 33540 | 34177 | js_free(ctx, s->atom_to_idx); |
| 33541 | 34178 | js_free(ctx, s->idx_to_atom); |
| 33542 | 34179 | dbuf_free(&s->dbuf); |
| 33543 | 34180 | *psize = 0; |
| 34181 | + if (psab_tab) |
| 34182 | + *psab_tab = NULL; |
| 34183 | + if (psab_tab_len) |
| 34184 | + *psab_tab_len = 0; |
| 33544 | 34185 | return NULL; |
| 33545 | 34186 | } |
| 33546 | 34187 | |
| 34188 | +uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, |
| 34189 | + int flags) |
| 34190 | +{ |
| 34191 | + return JS_WriteObject2(ctx, psize, obj, flags, NULL, NULL); |
| 34192 | +} |
| 34193 | + |
| 33547 | 34194 | typedef struct BCReaderState { |
| 33548 | 34195 | JSContext *ctx; |
| 33549 | 34196 | const uint8_t *buf_start, *ptr, *buf_end; |
| @@ -33551,8 +34198,15 @@ typedef struct BCReaderState { · 1 unmodified line |
| 33551 | 34198 | uint32_t idx_to_atom_count; |
| 33552 | 34199 | JSAtom *idx_to_atom; |
| 33553 | 34200 | int error_state; |
| 33554 | | − BOOL allow_bytecode; |
| 33555 | | − BOOL is_rom_data; |
| 34201 | + BOOL allow_sab : 8; |
| 34202 | + BOOL allow_bytecode : 8; |
| 34203 | + BOOL is_rom_data : 8; |
| 34204 | + BOOL allow_reference : 8; |
| 34205 | + /* object references */ |
| 34206 | + JSObject **objects; |
| 34207 | + int objects_count; |
| 34208 | + int objects_size; |
| 34209 | + |
| 33556 | 34210 | #ifdef DUMP_READ_OBJECT |
| 33557 | 34211 | const uint8_t *ptr_last; |
| 33558 | 34212 | int level; |
| @@ -33756,7 +34410,7 @@ static JSString *JS_ReadString(BCReaderState *s) · 197 unmodified lines |
| 33756 | 34410 | p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */ |
| 33757 | 34411 | } |
| 33758 | 34412 | #ifdef DUMP_READ_OBJECT |
| 33759 | | − bc_read_trace(s, "string: "); JS_DumpString(s->ctx->rt, p); printf("\n"); |
| 34413 | + JS_DumpString(s->ctx->rt, p); printf("\n"); |
| 33760 | 34414 | #endif |
| 33761 | 34415 | return p; |
| 33762 | 34416 | } |
| @@ -33838,8 +34492,6 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) · 75 unmodified lines |
| 33838 | 34492 | bf_t *a; |
| 33839 | 34493 | int bpos, d; |
| 33840 | 34494 | |
| 33841 | | − bc_read_trace(s, "%s {\n", bc_tag_str[tag]); |
| 33842 | | − |
| 33843 | 34495 | p = js_new_bf(s->ctx); |
| 33844 | 34496 | if (!p) |
| 33845 | 34497 | goto fail; |
| @@ -33961,28 +34613,560 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) · 115 unmodified lines |
| 33961 | 34613 | } |
| 33962 | 34614 | #endif /* CONFIG_BIGNUM */ |
| 33963 | 34615 | |
| 34616 | +static JSValue JS_ReadObjectRec(BCReaderState *s); |
| 34617 | + |
| 34618 | +static int BC_add_object_ref1(BCReaderState *s, JSObject *p) |
| 34619 | +{ |
| 34620 | + if (s->allow_reference) { |
| 34621 | + if (js_resize_array(s->ctx, (void *)&s->objects, |
| 34622 | + sizeof(s->objects[0]), |
| 34623 | + &s->objects_size, s->objects_count + 1)) |
| 34624 | + return -1; |
| 34625 | + s->objects[s->objects_count++] = p; |
| 34626 | + } |
| 34627 | + return 0; |
| 34628 | +} |
| 34629 | + |
| 34630 | +static int BC_add_object_ref(BCReaderState *s, JSValueConst obj) |
| 34631 | +{ |
| 34632 | + return BC_add_object_ref1(s, JS_VALUE_GET_OBJ(obj)); |
| 34633 | +} |
| 34634 | + |
| 34635 | +static JSValue JS_ReadFunctionTag(BCReaderState *s) |
| 34636 | +{ |
| 34637 | + JSContext *ctx = s->ctx; |
| 34638 | + JSFunctionBytecode bc, *b; |
| 34639 | + JSValue obj = JS_UNDEFINED; |
| 34640 | + uint16_t v16; |
| 34641 | + uint8_t v8; |
| 34642 | + int idx, i, local_count; |
| 34643 | + int function_size, cpool_offset, byte_code_offset; |
| 34644 | + int closure_var_offset, vardefs_offset; |
| 34645 | + |
| 34646 | + memset(&bc, 0, sizeof(bc)); |
| 34647 | + bc.header.ref_count = 1; |
| 34648 | + //bc.gc_header.mark = 0; |
| 34649 | + |
| 34650 | + if (bc_get_u16(s, &v16)) |
| 34651 | + goto fail; |
| 34652 | + idx = 0; |
| 34653 | + bc.has_prototype = bc_get_flags(v16, &idx, 1); |
| 34654 | + bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1); |
| 34655 | + bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1); |
| 34656 | + bc.need_home_object = bc_get_flags(v16, &idx, 1); |
| 34657 | + bc.func_kind = bc_get_flags(v16, &idx, 2); |
| 34658 | + bc.new_target_allowed = bc_get_flags(v16, &idx, 1); |
| 34659 | + bc.super_call_allowed = bc_get_flags(v16, &idx, 1); |
| 34660 | + bc.super_allowed = bc_get_flags(v16, &idx, 1); |
| 34661 | + bc.arguments_allowed = bc_get_flags(v16, &idx, 1); |
| 34662 | + bc.has_debug = bc_get_flags(v16, &idx, 1); |
| 34663 | + bc.backtrace_barrier = bc_get_flags(v16, &idx, 1); |
| 34664 | + bc.read_only_bytecode = s->is_rom_data; |
| 34665 | + if (bc_get_u8(s, &v8)) |
| 34666 | + goto fail; |
| 34667 | + bc.js_mode = v8; |
| 34668 | + if (bc_get_atom(s, &bc.func_name)) //@ atom leak if failure |
| 34669 | + goto fail; |
| 34670 | + if (bc_get_leb128_u16(s, &bc.arg_count)) |
| 34671 | + goto fail; |
| 34672 | + if (bc_get_leb128_u16(s, &bc.var_count)) |
| 34673 | + goto fail; |
| 34674 | + if (bc_get_leb128_u16(s, &bc.defined_arg_count)) |
| 34675 | + goto fail; |
| 34676 | + if (bc_get_leb128_u16(s, &bc.stack_size)) |
| 34677 | + goto fail; |
| 34678 | + if (bc_get_leb128_int(s, &bc.closure_var_count)) |
| 34679 | + goto fail; |
| 34680 | + if (bc_get_leb128_int(s, &bc.cpool_count)) |
| 34681 | + goto fail; |
| 34682 | + if (bc_get_leb128_int(s, &bc.byte_code_len)) |
| 34683 | + goto fail; |
| 34684 | + if (bc_get_leb128_int(s, &local_count)) |
| 34685 | + goto fail; |
| 34686 | + |
| 34687 | + if (bc.has_debug) { |
| 34688 | + function_size = sizeof(*b); |
| 34689 | + } else { |
| 34690 | + function_size = offsetof(JSFunctionBytecode, debug); |
| 34691 | + } |
| 34692 | + cpool_offset = function_size; |
| 34693 | + function_size += bc.cpool_count * sizeof(*bc.cpool); |
| 34694 | + vardefs_offset = function_size; |
| 34695 | + function_size += local_count * sizeof(*bc.vardefs); |
| 34696 | + closure_var_offset = function_size; |
| 34697 | + function_size += bc.closure_var_count * sizeof(*bc.closure_var); |
| 34698 | + byte_code_offset = function_size; |
| 34699 | + if (!bc.read_only_bytecode) { |
| 34700 | + function_size += bc.byte_code_len; |
| 34701 | + } |
| 34702 | + |
| 34703 | + b = js_mallocz(ctx, function_size); |
| 34704 | + if (!b) |
| 34705 | + return JS_EXCEPTION; |
| 34706 | + |
| 34707 | + memcpy(b, &bc, offsetof(JSFunctionBytecode, debug)); |
| 34708 | + b->header.ref_count = 1; |
| 34709 | + add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); |
| 34710 | + |
| 34711 | + obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b); |
| 34712 | + |
| 34713 | +#ifdef DUMP_READ_OBJECT |
| 34714 | + bc_read_trace(s, "name: "); print_atom(s->ctx, b->func_name); printf("\n"); |
| 34715 | +#endif |
| 34716 | + bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n", |
| 34717 | + b->arg_count, b->var_count, b->defined_arg_count, |
| 34718 | + b->closure_var_count, b->cpool_count); |
| 34719 | + bc_read_trace(s, "stack=%d bclen=%d locals=%d\n", |
| 34720 | + b->stack_size, b->byte_code_len, local_count); |
| 34721 | + |
| 34722 | + if (local_count != 0) { |
| 34723 | + bc_read_trace(s, "vars {\n"); |
| 34724 | + b->vardefs = (void *)((uint8_t*)b + vardefs_offset); |
| 34725 | + for(i = 0; i < local_count; i++) { |
| 34726 | + JSVarDef *vd = &b->vardefs[i]; |
| 34727 | + if (bc_get_atom(s, &vd->var_name)) |
| 34728 | + goto fail; |
| 34729 | + if (bc_get_leb128_int(s, &vd->scope_level)) |
| 34730 | + goto fail; |
| 34731 | + if (bc_get_leb128_int(s, &vd->scope_next)) |
| 34732 | + goto fail; |
| 34733 | + vd->scope_next--; |
| 34734 | + if (bc_get_u8(s, &v8)) |
| 34735 | + goto fail; |
| 34736 | + idx = 0; |
| 34737 | + vd->var_kind = bc_get_flags(v8, &idx, 4); |
| 34738 | + vd->is_func_var = bc_get_flags(v8, &idx, 1); |
| 34739 | + vd->is_const = bc_get_flags(v8, &idx, 1); |
| 34740 | + vd->is_lexical = bc_get_flags(v8, &idx, 1); |
| 34741 | + vd->is_captured = bc_get_flags(v8, &idx, 1); |
| 34742 | +#ifdef DUMP_READ_OBJECT |
| 34743 | + bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n"); |
| 34744 | +#endif |
| 34745 | + } |
| 34746 | + bc_read_trace(s, "}\n"); |
| 34747 | + } |
| 34748 | + if (b->closure_var_count != 0) { |
| 34749 | + bc_read_trace(s, "closure vars {\n"); |
| 34750 | + b->closure_var = (void *)((uint8_t*)b + closure_var_offset); |
| 34751 | + for(i = 0; i < b->closure_var_count; i++) { |
| 34752 | + JSClosureVar *cv = &b->closure_var[i]; |
| 34753 | + int var_idx; |
| 34754 | + if (bc_get_atom(s, &cv->var_name)) |
| 34755 | + goto fail; |
| 34756 | + if (bc_get_leb128_int(s, &var_idx)) |
| 34757 | + goto fail; |
| 34758 | + cv->var_idx = var_idx; |
| 34759 | + if (bc_get_u8(s, &v8)) |
| 34760 | + goto fail; |
| 34761 | + idx = 0; |
| 34762 | + cv->is_local = bc_get_flags(v8, &idx, 1); |
| 34763 | + cv->is_arg = bc_get_flags(v8, &idx, 1); |
| 34764 | + cv->is_const = bc_get_flags(v8, &idx, 1); |
| 34765 | + cv->is_lexical = bc_get_flags(v8, &idx, 1); |
| 34766 | + cv->var_kind = bc_get_flags(v8, &idx, 4); |
| 34767 | +#ifdef DUMP_READ_OBJECT |
| 34768 | + bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); printf("\n"); |
| 34769 | +#endif |
| 34770 | + } |
| 34771 | + bc_read_trace(s, "}\n"); |
| 34772 | + } |
| 34773 | + { |
| 34774 | + bc_read_trace(s, "bytecode {\n"); |
| 34775 | + if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len)) |
| 34776 | + goto fail; |
| 34777 | + bc_read_trace(s, "}\n"); |
| 34778 | + } |
| 34779 | + if (b->has_debug) { |
| 34780 | + /* read optional debug information */ |
| 34781 | + bc_read_trace(s, "debug {\n"); |
| 34782 | + if (bc_get_atom(s, &b->debug.filename)) |
| 34783 | + goto fail; |
| 34784 | + if (bc_get_leb128_int(s, &b->debug.line_num)) |
| 34785 | + goto fail; |
| 34786 | + if (bc_get_leb128_int(s, &b->debug.pc2line_len)) |
| 34787 | + goto fail; |
| 34788 | + if (b->debug.pc2line_len) { |
| 34789 | + b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len); |
| 34790 | + if (!b->debug.pc2line_buf) |
| 34791 | + goto fail; |
| 34792 | + if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len)) |
| 34793 | + goto fail; |
| 34794 | + } |
| 34795 | +#ifdef DUMP_READ_OBJECT |
| 34796 | + bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n"); |
| 34797 | +#endif |
| 34798 | + bc_read_trace(s, "}\n"); |
| 34799 | + } |
| 34800 | + if (b->cpool_count != 0) { |
| 34801 | + bc_read_trace(s, "cpool {\n"); |
| 34802 | + b->cpool = (void *)((uint8_t*)b + cpool_offset); |
| 34803 | + for(i = 0; i < b->cpool_count; i++) { |
| 34804 | + JSValue val; |
| 34805 | + val = JS_ReadObjectRec(s); |
| 34806 | + if (JS_IsException(val)) |
| 34807 | + goto fail; |
| 34808 | + b->cpool[i] = val; |
| 34809 | + } |
| 34810 | + bc_read_trace(s, "}\n"); |
| 34811 | + } |
| 34812 | + b->realm = JS_DupContext(ctx); |
| 34813 | + return obj; |
| 34814 | + fail: |
| 34815 | + JS_FreeValue(ctx, obj); |
| 34816 | + return JS_EXCEPTION; |
| 34817 | +} |
| 34818 | + |
| 34819 | +static JSValue JS_ReadModule(BCReaderState *s) |
| 34820 | +{ |
| 34821 | + JSContext *ctx = s->ctx; |
| 34822 | + JSValue obj; |
| 34823 | + JSModuleDef *m = NULL; |
| 34824 | + JSAtom module_name; |
| 34825 | + int i; |
| 34826 | + uint8_t v8; |
| 34827 | + |
| 34828 | + if (bc_get_atom(s, &module_name)) |
| 34829 | + goto fail; |
| 34830 | +#ifdef DUMP_READ_OBJECT |
| 34831 | + bc_read_trace(s, "name: "); print_atom(s->ctx, module_name); printf("\n"); |
| 34832 | +#endif |
| 34833 | + m = js_new_module_def(ctx, module_name); |
| 34834 | + if (!m) |
| 34835 | + goto fail; |
| 34836 | + obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); |
| 34837 | + if (bc_get_leb128_int(s, &m->req_module_entries_count)) |
| 34838 | + goto fail; |
| 34839 | + if (m->req_module_entries_count != 0) { |
| 34840 | + m->req_module_entries_size = m->req_module_entries_count; |
| 34841 | + m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size); |
| 34842 | + if (!m->req_module_entries) |
| 34843 | + goto fail; |
| 34844 | + for(i = 0; i < m->req_module_entries_count; i++) { |
| 34845 | + JSReqModuleEntry *rme = &m->req_module_entries[i]; |
| 34846 | + if (bc_get_atom(s, &rme->module_name)) |
| 34847 | + goto fail; |
| 34848 | + } |
| 34849 | + } |
| 34850 | + |
| 34851 | + if (bc_get_leb128_int(s, &m->export_entries_count)) |
| 34852 | + goto fail; |
| 34853 | + if (m->export_entries_count != 0) { |
| 34854 | + m->export_entries_size = m->export_entries_count; |
| 34855 | + m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size); |
| 34856 | + if (!m->export_entries) |
| 34857 | + goto fail; |
| 34858 | + for(i = 0; i < m->export_entries_count; i++) { |
| 34859 | + JSExportEntry *me = &m->export_entries[i]; |
| 34860 | + if (bc_get_u8(s, &v8)) |
| 34861 | + goto fail; |
| 34862 | + me->export_type = v8; |
| 34863 | + if (me->export_type == JS_EXPORT_TYPE_LOCAL) { |
| 34864 | + if (bc_get_leb128_int(s, &me->u.local.var_idx)) |
| 34865 | + goto fail; |
| 34866 | + } else { |
| 34867 | + if (bc_get_leb128_int(s, &me->u.req_module_idx)) |
| 34868 | + goto fail; |
| 34869 | + if (bc_get_atom(s, &me->local_name)) |
| 34870 | + goto fail; |
| 34871 | + } |
| 34872 | + if (bc_get_atom(s, &me->export_name)) |
| 34873 | + goto fail; |
| 34874 | + } |
| 34875 | + } |
| 34876 | + |
| 34877 | + if (bc_get_leb128_int(s, &m->star_export_entries_count)) |
| 34878 | + goto fail; |
| 34879 | + if (m->star_export_entries_count != 0) { |
| 34880 | + m->star_export_entries_size = m->star_export_entries_count; |
| 34881 | + m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size); |
| 34882 | + if (!m->star_export_entries) |
| 34883 | + goto fail; |
| 34884 | + for(i = 0; i < m->star_export_entries_count; i++) { |
| 34885 | + JSStarExportEntry *se = &m->star_export_entries[i]; |
| 34886 | + if (bc_get_leb128_int(s, &se->req_module_idx)) |
| 34887 | + goto fail; |
| 34888 | + } |
| 34889 | + } |
| 34890 | + |
| 34891 | + if (bc_get_leb128_int(s, &m->import_entries_count)) |
| 34892 | + goto fail; |
| 34893 | + if (m->import_entries_count != 0) { |
| 34894 | + m->import_entries_size = m->import_entries_count; |
| 34895 | + m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size); |
| 34896 | + if (!m->import_entries) |
| 34897 | + goto fail; |
| 34898 | + for(i = 0; i < m->import_entries_count; i++) { |
| 34899 | + JSImportEntry *mi = &m->import_entries[i]; |
| 34900 | + if (bc_get_leb128_int(s, &mi->var_idx)) |
| 34901 | + goto fail; |
| 34902 | + if (bc_get_atom(s, &mi->import_name)) |
| 34903 | + goto fail; |
| 34904 | + if (bc_get_leb128_int(s, &mi->req_module_idx)) |
| 34905 | + goto fail; |
| 34906 | + } |
| 34907 | + } |
| 34908 | + |
| 34909 | + m->func_obj = JS_ReadObjectRec(s); |
| 34910 | + if (JS_IsException(m->func_obj)) |
| 34911 | + goto fail; |
| 34912 | + return obj; |
| 34913 | + fail: |
| 34914 | + if (m) { |
| 34915 | + js_free_module_def(ctx, m); |
| 34916 | + } |
| 34917 | + return JS_EXCEPTION; |
| 34918 | +} |
| 34919 | + |
| 34920 | +static JSValue JS_ReadObjectTag(BCReaderState *s) |
| 34921 | +{ |
| 34922 | + JSContext *ctx = s->ctx; |
| 34923 | + JSValue obj; |
| 34924 | + uint32_t prop_count, i; |
| 34925 | + JSAtom atom; |
| 34926 | + JSValue val; |
| 34927 | + int ret; |
| 34928 | + |
| 34929 | + obj = JS_NewObject(ctx); |
| 34930 | + if (BC_add_object_ref(s, obj)) |
| 34931 | + goto fail; |
| 34932 | + if (bc_get_leb128(s, &prop_count)) |
| 34933 | + goto fail; |
| 34934 | + for(i = 0; i < prop_count; i++) { |
| 34935 | + if (bc_get_atom(s, &atom)) |
| 34936 | + goto fail; |
| 34937 | +#ifdef DUMP_READ_OBJECT |
| 34938 | + bc_read_trace(s, "propname: "); print_atom(s->ctx, atom); printf("\n"); |
| 34939 | +#endif |
| 34940 | + val = JS_ReadObjectRec(s); |
| 34941 | + if (JS_IsException(val)) { |
| 34942 | + JS_FreeAtom(ctx, atom); |
| 34943 | + goto fail; |
| 34944 | + } |
| 34945 | + ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E); |
| 34946 | + JS_FreeAtom(ctx, atom); |
| 34947 | + if (ret < 0) |
| 34948 | + goto fail; |
| 34949 | + } |
| 34950 | + return obj; |
| 34951 | + fail: |
| 34952 | + JS_FreeValue(ctx, obj); |
| 34953 | + return JS_EXCEPTION; |
| 34954 | +} |
| 34955 | + |
| 34956 | +static JSValue JS_ReadArray(BCReaderState *s, int tag) |
| 34957 | +{ |
| 34958 | + JSContext *ctx = s->ctx; |
| 34959 | + JSValue obj; |
| 34960 | + uint32_t len, i; |
| 34961 | + JSValue val; |
| 34962 | + int ret, prop_flags; |
| 34963 | + BOOL is_template; |
| 34964 | + |
| 34965 | + obj = JS_NewArray(ctx); |
| 34966 | + if (BC_add_object_ref(s, obj)) |
| 34967 | + goto fail; |
| 34968 | + is_template = (tag == BC_TAG_TEMPLATE_OBJECT); |
| 34969 | + if (bc_get_leb128(s, &len)) |
| 34970 | + goto fail; |
| 34971 | + for(i = 0; i < len; i++) { |
| 34972 | + val = JS_ReadObjectRec(s); |
| 34973 | + if (JS_IsException(val)) |
| 34974 | + goto fail; |
| 34975 | + if (is_template) |
| 34976 | + prop_flags = JS_PROP_ENUMERABLE; |
| 34977 | + else |
| 34978 | + prop_flags = JS_PROP_C_W_E; |
| 34979 | + ret = JS_DefinePropertyValueUint32(ctx, obj, i, val, |
| 34980 | + prop_flags); |
| 34981 | + if (ret < 0) |
| 34982 | + goto fail; |
| 34983 | + } |
| 34984 | + if (is_template) { |
| 34985 | + val = JS_ReadObjectRec(s); |
| 34986 | + if (JS_IsException(val)) |
| 34987 | + goto fail; |
| 34988 | + if (!JS_IsUndefined(val)) { |
| 34989 | + ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0); |
| 34990 | + if (ret < 0) |
| 34991 | + goto fail; |
| 34992 | + } |
| 34993 | + JS_PreventExtensions(ctx, obj); |
| 34994 | + } |
| 34995 | + return obj; |
| 34996 | + fail: |
| 34997 | + JS_FreeValue(ctx, obj); |
| 34998 | + return JS_EXCEPTION; |
| 34999 | +} |
| 35000 | + |
| 35001 | +static JSValue JS_ReadTypedArray(BCReaderState *s) |
| 35002 | +{ |
| 35003 | + JSContext *ctx = s->ctx; |
| 35004 | + JSValue obj = JS_UNDEFINED, array_buffer = JS_UNDEFINED; |
| 35005 | + uint8_t array_tag; |
| 35006 | + JSValueConst args[3]; |
| 35007 | + uint32_t offset, len, idx; |
| 35008 | + |
| 35009 | + if (bc_get_u8(s, &array_tag)) |
| 35010 | + return JS_EXCEPTION; |
| 35011 | + if (array_tag >= JS_TYPED_ARRAY_COUNT) |
| 35012 | + return JS_ThrowTypeError(ctx, "invalid typed array"); |
| 35013 | + if (bc_get_leb128(s, &len)) |
| 35014 | + return JS_EXCEPTION; |
| 35015 | + if (bc_get_leb128(s, &offset)) |
| 35016 | + return JS_EXCEPTION; |
| 35017 | + /* XXX: this hack could be avoided if the typed array could be |
| 35018 | + created before the array buffer */ |
| 35019 | + idx = s->objects_count; |
| 35020 | + if (BC_add_object_ref1(s, NULL)) |
| 35021 | + goto fail; |
| 35022 | + array_buffer = JS_ReadObjectRec(s); |
| 35023 | + if (JS_IsException(array_buffer)) |
| 35024 | + return JS_EXCEPTION; |
| 35025 | + if (!js_get_array_buffer(ctx, array_buffer)) { |
| 35026 | + JS_FreeValue(ctx, array_buffer); |
| 35027 | + return JS_EXCEPTION; |
| 35028 | + } |
| 35029 | + args[0] = array_buffer; |
| 35030 | + args[1] = JS_NewInt64(ctx, offset); |
| 35031 | + args[2] = JS_NewInt64(ctx, len); |
| 35032 | + obj = js_typed_array_constructor(ctx, JS_UNDEFINED, |
| 35033 | + 3, args, |
| 35034 | + JS_CLASS_UINT8C_ARRAY + array_tag); |
| 35035 | + if (JS_IsException(obj)) |
| 35036 | + goto fail; |
| 35037 | + if (s->allow_reference) { |
| 35038 | + s->objects[idx] = JS_VALUE_GET_OBJ(obj); |
| 35039 | + } |
| 35040 | + JS_FreeValue(ctx, array_buffer); |
| 35041 | + return obj; |
| 35042 | + fail: |
| 35043 | + JS_FreeValue(ctx, array_buffer); |
| 35044 | + JS_FreeValue(ctx, obj); |
| 35045 | + return JS_EXCEPTION; |
| 35046 | +} |
| 35047 | + |
| 35048 | +static JSValue JS_ReadArrayBuffer(BCReaderState *s) |
| 35049 | +{ |
| 35050 | + JSContext *ctx = s->ctx; |
| 35051 | + uint32_t byte_length; |
| 35052 | + JSValue obj; |
| 35053 | + |
| 35054 | + if (bc_get_leb128(s, &byte_length)) |
| 35055 | + return JS_EXCEPTION; |
| 35056 | + if (unlikely(s->buf_end - s->ptr < byte_length)) { |
| 35057 | + bc_read_error_end(s); |
| 35058 | + return JS_EXCEPTION; |
| 35059 | + } |
| 35060 | + obj = JS_NewArrayBufferCopy(ctx, s->ptr, byte_length); |
| 35061 | + if (JS_IsException(obj)) |
| 35062 | + goto fail; |
| 35063 | + if (BC_add_object_ref(s, obj)) |
| 35064 | + goto fail; |
| 35065 | + s->ptr += byte_length; |
| 35066 | + return obj; |
| 35067 | + fail: |
| 35068 | + JS_FreeValue(ctx, obj); |
| 35069 | + return JS_EXCEPTION; |
| 35070 | +} |
| 35071 | + |
| 35072 | +static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s) |
| 35073 | +{ |
| 35074 | + JSContext *ctx = s->ctx; |
| 35075 | + uint32_t byte_length; |
| 35076 | + uint8_t *data_ptr; |
| 35077 | + JSValue obj; |
| 35078 | + uint64_t u64; |
| 35079 | + |
| 35080 | + if (bc_get_leb128(s, &byte_length)) |
| 35081 | + return JS_EXCEPTION; |
| 35082 | + if (bc_get_u64(s, &u64)) |
| 35083 | + return JS_EXCEPTION; |
| 35084 | + data_ptr = (uint8_t *)(uintptr_t)u64; |
| 35085 | + /* the SharedArrayBuffer is cloned */ |
| 35086 | + obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED, byte_length, |
| 35087 | + JS_CLASS_SHARED_ARRAY_BUFFER, |
| 35088 | + data_ptr, |
| 35089 | + NULL, NULL, FALSE); |
| 35090 | + if (JS_IsException(obj)) |
| 35091 | + goto fail; |
| 35092 | + if (BC_add_object_ref(s, obj)) |
| 35093 | + goto fail; |
| 35094 | + return obj; |
| 35095 | + fail: |
| 35096 | + JS_FreeValue(ctx, obj); |
| 35097 | + return JS_EXCEPTION; |
| 35098 | +} |
| 35099 | + |
| 35100 | +static JSValue JS_ReadDate(BCReaderState *s) |
| 35101 | +{ |
| 35102 | + JSContext *ctx = s->ctx; |
| 35103 | + JSValue val, obj = JS_UNDEFINED; |
| 35104 | + |
| 35105 | + val = JS_ReadObjectRec(s); |
| 35106 | + if (JS_IsException(val)) |
| 35107 | + goto fail; |
| 35108 | + if (!JS_IsNumber(val)) { |
| 35109 | + JS_ThrowTypeError(ctx, "Number tag expected for date"); |
| 35110 | + goto fail; |
| 35111 | + } |
| 35112 | + obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_DATE], |
| 35113 | + JS_CLASS_DATE); |
| 35114 | + if (JS_IsException(obj)) |
| 35115 | + goto fail; |
| 35116 | + if (BC_add_object_ref(s, obj)) |
| 35117 | + goto fail; |
| 35118 | + JS_SetObjectData(ctx, obj, val); |
| 35119 | + return obj; |
| 35120 | + fail: |
| 35121 | + JS_FreeValue(ctx, val); |
| 35122 | + JS_FreeValue(ctx, obj); |
| 35123 | + return JS_EXCEPTION; |
| 35124 | +} |
| 35125 | + |
| 35126 | +static JSValue JS_ReadObjectValue(BCReaderState *s) |
| 35127 | +{ |
| 35128 | + JSContext *ctx = s->ctx; |
| 35129 | + JSValue val, obj = JS_UNDEFINED; |
| 35130 | + |
| 35131 | + val = JS_ReadObjectRec(s); |
| 35132 | + if (JS_IsException(val)) |
| 35133 | + goto fail; |
| 35134 | + obj = JS_ToObject(ctx, val); |
| 35135 | + if (JS_IsException(obj)) |
| 35136 | + goto fail; |
| 35137 | + if (BC_add_object_ref(s, obj)) |
| 35138 | + goto fail; |
| 35139 | + JS_FreeValue(ctx, val); |
| 35140 | + return obj; |
| 35141 | + fail: |
| 35142 | + JS_FreeValue(ctx, val); |
| 35143 | + JS_FreeValue(ctx, obj); |
| 35144 | + return JS_EXCEPTION; |
| 35145 | +} |
| 35146 | + |
| 33964 | 35147 | static JSValue JS_ReadObjectRec(BCReaderState *s) |
| 33965 | 35148 | { |
| 33966 | 35149 | JSContext *ctx = s->ctx; |
| 33967 | 35150 | uint8_t tag; |
| 33968 | 35151 | JSValue obj = JS_UNDEFINED; |
| 33969 | | − JSModuleDef *m = NULL; |
| 35152 | + |
| 35153 | + if (js_check_stack_overflow(ctx->rt, 0)) |
| 35154 | + return JS_ThrowStackOverflow(ctx); |
| 33970 | 35155 | |
| 33971 | 35156 | if (bc_get_u8(s, &tag)) |
| 33972 | 35157 | return JS_EXCEPTION; |
| 33973 | 35158 | |
| 35159 | + bc_read_trace(s, "%s {\n", bc_tag_str[tag]); |
| 35160 | + |
| 33974 | 35161 | switch(tag) { |
| 33975 | 35162 | case BC_TAG_NULL: |
| 33976 | | − bc_read_trace(s, "null\n"); |
| 33977 | 35163 | obj = JS_NULL; |
| 33978 | 35164 | break; |
| 33979 | 35165 | case BC_TAG_UNDEFINED: |
| 33980 | | − bc_read_trace(s, "undefined\n"); |
| 33981 | 35166 | obj = JS_UNDEFINED; |
| 33982 | 35167 | break; |
| 33983 | 35168 | case BC_TAG_BOOL_FALSE: |
| 33984 | 35169 | case BC_TAG_BOOL_TRUE: |
| 33985 | | − bc_read_trace(s, "%s\n", bc_tag_str[tag]); |
| 33986 | 35170 | obj = JS_NewBool(ctx, tag - BC_TAG_BOOL_FALSE); |
| 33987 | 35171 | break; |
| 33988 | 35172 | case BC_TAG_INT32: |
| @@ -33990,7 +35174,7 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) · 1 unmodified line |
| 33990 | 35174 | int32_t val; |
| 33991 | 35175 | if (bc_get_sleb128(s, &val)) |
| 33992 | 35176 | return JS_EXCEPTION; |
| 33993 | | − bc_read_trace(s, "int32 %d\n", val); |
| 35177 | + bc_read_trace(s, "%d\n", val); |
| 33994 | 35178 | obj = JS_NewInt32(ctx, val); |
| 33995 | 35179 | } |
| 33996 | 35180 | break; |
| @@ -33999,7 +35183,7 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) · 2 unmodified lines |
| 33999 | 35183 | JSFloat64Union u; |
| 34000 | 35184 | if (bc_get_u64(s, &u.u64)) |
| 34001 | 35185 | return JS_EXCEPTION; |
| 34002 | | − bc_read_trace(s, "float64 %g\n", u.d); |
| 35186 | + bc_read_trace(s, "%g\n", u.d); |
| 34003 | 35187 | obj = __JS_NewFloat64(ctx, u.d); |
| 34004 | 35188 | } |
| 34005 | 35189 | break; |
| @@ -34013,378 +35197,68 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) · 7 unmodified lines |
| 34013 | 35197 | } |
| 34014 | 35198 | break; |
| 34015 | 35199 | case BC_TAG_FUNCTION_BYTECODE: |
| 34016 | | − { |
| 34017 | | − JSFunctionBytecode bc, *b; |
| 34018 | | − uint16_t v16; |
| 34019 | | − uint8_t v8; |
| 34020 | | − int idx, i, local_count; |
| 34021 | | − int function_size, cpool_offset, byte_code_offset; |
| 34022 | | − int closure_var_offset, vardefs_offset; |
| 34023 | | − |
| 34024 | | − if (!s->allow_bytecode) |
| 34025 | | − goto invalid_tag; |
| 34026 | | − bc_read_trace(s, "%s {\n", bc_tag_str[tag]); |
| 34027 | | − |
| 34028 | | − memset(&bc, 0, sizeof(bc)); |
| 34029 | | − bc.header.ref_count = 1; |
| 34030 | | − //bc.gc_header.mark = 0; |
| 34031 | | − |
| 34032 | | − if (bc_get_u16(s, &v16)) |
| 34033 | | − goto fail; |
| 34034 | | − idx = 0; |
| 34035 | | − bc.has_prototype = bc_get_flags(v16, &idx, 1); |
| 34036 | | − bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1); |
| 34037 | | − bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1); |
| 34038 | | − bc.need_home_object = bc_get_flags(v16, &idx, 1); |
| 34039 | | − bc.func_kind = bc_get_flags(v16, &idx, 2); |
| 34040 | | − bc.new_target_allowed = bc_get_flags(v16, &idx, 1); |
| 34041 | | − bc.super_call_allowed = bc_get_flags(v16, &idx, 1); |
| 34042 | | − bc.super_allowed = bc_get_flags(v16, &idx, 1); |
| 34043 | | − bc.arguments_allowed = bc_get_flags(v16, &idx, 1); |
| 34044 | | − bc.has_debug = bc_get_flags(v16, &idx, 1); |
| 34045 | | − bc.backtrace_barrier = bc_get_flags(v16, &idx, 1); |
| 34046 | | − bc.read_only_bytecode = s->is_rom_data; |
| 34047 | | − if (bc_get_u8(s, &v8)) |
| 34048 | | − goto fail; |
| 34049 | | − bc.js_mode = v8; |
| 34050 | | − if (bc_get_atom(s, &bc.func_name)) //@ atom leak if failure |
| 34051 | | − goto fail; |
| 34052 | | − if (bc_get_leb128_u16(s, &bc.arg_count)) |
| 34053 | | − goto fail; |
| 34054 | | − if (bc_get_leb128_u16(s, &bc.var_count)) |
| 34055 | | − goto fail; |
| 34056 | | − if (bc_get_leb128_u16(s, &bc.defined_arg_count)) |
| 34057 | | − goto fail; |
| 34058 | | − if (bc_get_leb128_u16(s, &bc.stack_size)) |
| 34059 | | − goto fail; |
| 34060 | | − if (bc_get_leb128_int(s, &bc.closure_var_count)) |
| 34061 | | − goto fail; |
| 34062 | | − if (bc_get_leb128_int(s, &bc.cpool_count)) |
| 34063 | | − goto fail; |
| 34064 | | − if (bc_get_leb128_int(s, &bc.byte_code_len)) |
| 34065 | | − goto fail; |
| 34066 | | − if (bc_get_leb128_int(s, &local_count)) |
| 34067 | | − goto fail; |
| 34068 | | − |
| 34069 | | − if (bc.has_debug) { |
| 34070 | | − function_size = sizeof(*b); |
| 34071 | | − } else { |
| 34072 | | − function_size = offsetof(JSFunctionBytecode, debug); |
| 34073 | | − } |
| 34074 | | − cpool_offset = function_size; |
| 34075 | | − function_size += bc.cpool_count * sizeof(*bc.cpool); |
| 34076 | | − vardefs_offset = function_size; |
| 34077 | | − function_size += local_count * sizeof(*bc.vardefs); |
| 34078 | | − closure_var_offset = function_size; |
| 34079 | | − function_size += bc.closure_var_count * sizeof(*bc.closure_var); |
| 34080 | | − byte_code_offset = function_size; |
| 34081 | | − if (!bc.read_only_bytecode) { |
| 34082 | | − function_size += bc.byte_code_len; |
| 34083 | | − } |
| 34084 | | − |
| 34085 | | − b = js_mallocz(ctx, function_size); |
| 34086 | | − if (!b) |
| 34087 | | − return JS_EXCEPTION; |
| 34088 | | − |
| 34089 | | − memcpy(b, &bc, offsetof(JSFunctionBytecode, debug)); |
| 34090 | | − b->header.ref_count = 1; |
| 34091 | | − add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); |
| 34092 | | − |
| 34093 | | − obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b); |
| 34094 | | − |
| 34095 | | −#ifdef DUMP_READ_OBJECT |
| 34096 | | − bc_read_trace(s, "name: "); print_atom(s->ctx, b->func_name); printf("\n"); |
| 34097 | | −#endif |
| 34098 | | − bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n", |
| 34099 | | − b->arg_count, b->var_count, b->defined_arg_count, |
| 34100 | | − b->closure_var_count, b->cpool_count); |
| 34101 | | − bc_read_trace(s, "stack=%d bclen=%d locals=%d\n", |
| 34102 | | − b->stack_size, b->byte_code_len, local_count); |
| 34103 | | − |
| 34104 | | − if (local_count != 0) { |
| 34105 | | − bc_read_trace(s, "vars {\n"); |
| 34106 | | − b->vardefs = (void *)((uint8_t*)b + vardefs_offset); |
| 34107 | | − for(i = 0; i < local_count; i++) { |
| 34108 | | − JSVarDef *vd = &b->vardefs[i]; |
| 34109 | | − if (bc_get_atom(s, &vd->var_name)) |
| 34110 | | − goto fail; |
| 34111 | | − if (bc_get_leb128_int(s, &vd->scope_level)) |
| 34112 | | − goto fail; |
| 34113 | | − if (bc_get_leb128_int(s, &vd->scope_next)) |
| 34114 | | − goto fail; |
| 34115 | | − vd->scope_next--; |
| 34116 | | − if (bc_get_u8(s, &v8)) |
| 34117 | | − goto fail; |
| 34118 | | − idx = 0; |
| 34119 | | − vd->var_kind = bc_get_flags(v8, &idx, 4); |
| 34120 | | − vd->is_func_var = bc_get_flags(v8, &idx, 1); |
| 34121 | | − vd->is_const = bc_get_flags(v8, &idx, 1); |
| 34122 | | − vd->is_lexical = bc_get_flags(v8, &idx, 1); |
| 34123 | | − vd->is_captured = bc_get_flags(v8, &idx, 1); |
| 34124 | | −#ifdef DUMP_READ_OBJECT |
| 34125 | | − bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n"); |
| 34126 | | −#endif |
| 34127 | | − } |
| 34128 | | − bc_read_trace(s, "}\n"); |
| 34129 | | − } |
| 34130 | | − if (b->closure_var_count != 0) { |
| 34131 | | − bc_read_trace(s, "closure vars {\n"); |
| 34132 | | − b->closure_var = (void *)((uint8_t*)b + closure_var_offset); |
| 34133 | | − for(i = 0; i < b->closure_var_count; i++) { |
| 34134 | | − JSClosureVar *cv = &b->closure_var[i]; |
| 34135 | | − int var_idx; |
| 34136 | | − if (bc_get_atom(s, &cv->var_name)) |
| 34137 | | − goto fail; |
| 34138 | | − if (bc_get_leb128_int(s, &var_idx)) |
| 34139 | | − goto fail; |
| 34140 | | − cv->var_idx = var_idx; |
| 34141 | | − if (bc_get_u8(s, &v8)) |
| 34142 | | − goto fail; |
| 34143 | | − idx = 0; |
| 34144 | | − cv->is_local = bc_get_flags(v8, &idx, 1); |
| 34145 | | − cv->is_arg = bc_get_flags(v8, &idx, 1); |
| 34146 | | − cv->is_const = bc_get_flags(v8, &idx, 1); |
| 34147 | | − cv->is_lexical = bc_get_flags(v8, &idx, 1); |
| 34148 | | − cv->var_kind = bc_get_flags(v8, &idx, 4); |
| 34149 | | −#ifdef DUMP_READ_OBJECT |
| 34150 | | − bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); printf("\n"); |
| 34151 | | −#endif |
| 34152 | | − } |
| 34153 | | − bc_read_trace(s, "}\n"); |
| 34154 | | − } |
| 34155 | | − { |
| 34156 | | − bc_read_trace(s, "bytecode {\n"); |
| 34157 | | − if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len)) |
| 34158 | | − goto fail; |
| 34159 | | − bc_read_trace(s, "}\n"); |
| 34160 | | − } |
| 34161 | | − if (b->has_debug) { |
| 34162 | | − /* read optional debug information */ |
| 34163 | | − bc_read_trace(s, "debug {\n"); |
| 34164 | | − if (bc_get_atom(s, &b->debug.filename)) |
| 34165 | | − goto fail; |
| 34166 | | − if (bc_get_leb128_int(s, &b->debug.line_num)) |
| 34167 | | − goto fail; |
| 34168 | | − if (bc_get_leb128_int(s, &b->debug.pc2line_len)) |
| 34169 | | − goto fail; |
| 34170 | | − if (b->debug.pc2line_len) { |
| 34171 | | − b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len); |
| 34172 | | − if (!b->debug.pc2line_buf) |
| 34173 | | − goto fail; |
| 34174 | | − if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len)) |
| 34175 | | − goto fail; |
| 34176 | | − } |
| 34177 | | −#ifdef DUMP_READ_OBJECT |
| 34178 | | − bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n"); |
| 34179 | | −#endif |
| 34180 | | − bc_read_trace(s, "}\n"); |
| 34181 | | − } |
| 34182 | | − if (b->cpool_count != 0) { |
| 34183 | | − bc_read_trace(s, "cpool {\n"); |
| 34184 | | − b->cpool = (void *)((uint8_t*)b + cpool_offset); |
| 34185 | | − for(i = 0; i < b->cpool_count; i++) { |
| 34186 | | − JSValue val; |
| 34187 | | − val = JS_ReadObjectRec(s); |
| 34188 | | − if (JS_IsException(val)) |
| 34189 | | − goto fail; |
| 34190 | | − b->cpool[i] = val; |
| 34191 | | − } |
| 34192 | | − bc_read_trace(s, "}\n"); |
| 34193 | | − } |
| 34194 | | − bc_read_trace(s, "}\n"); |
| 34195 | | − b->realm = JS_DupContext(ctx); |
| 34196 | | − } |
| 35200 | + if (!s->allow_bytecode) |
| 35201 | + goto invalid_tag; |
| 35202 | + obj = JS_ReadFunctionTag(s); |
| 34197 | 35203 | break; |
| 34198 | 35204 | case BC_TAG_MODULE: |
| 34199 | | − { |
| 34200 | | − JSAtom module_name; |
| 34201 | | − int i; |
| 34202 | | − uint8_t v8; |
| 34203 | | − |
| 34204 | | − if (!s->allow_bytecode) |
| 34205 | | − goto invalid_tag; |
| 34206 | | − bc_read_trace(s, "%s {\n", bc_tag_str[tag]); |
| 34207 | | − if (bc_get_atom(s, &module_name)) |
| 34208 | | − goto fail; |
| 34209 | | −#ifdef DUMP_READ_OBJECT |
| 34210 | | − bc_read_trace(s, "name: "); print_atom(s->ctx, module_name); printf("\n"); |
| 34211 | | −#endif |
| 34212 | | − m = js_new_module_def(ctx, module_name); |
| 34213 | | − if (!m) |
| 34214 | | − goto fail; |
| 34215 | | − obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); |
| 34216 | | − if (bc_get_leb128_int(s, &m->req_module_entries_count)) |
| 34217 | | − goto fail; |
| 34218 | | − if (m->req_module_entries_count != 0) { |
| 34219 | | − m->req_module_entries_size = m->req_module_entries_count; |
| 34220 | | − m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size); |
| 34221 | | − if (!m->req_module_entries) |
| 34222 | | − goto fail; |
| 34223 | | − for(i = 0; i < m->req_module_entries_count; i++) { |
| 34224 | | − JSReqModuleEntry *rme = &m->req_module_entries[i]; |
| 34225 | | − if (bc_get_atom(s, &rme->module_name)) |
| 34226 | | − goto fail; |
| 34227 | | − } |
| 34228 | | − } |
| 34229 | | − |
| 34230 | | − if (bc_get_leb128_int(s, &m->export_entries_count)) |
| 34231 | | − goto fail; |
| 34232 | | − if (m->export_entries_count != 0) { |
| 34233 | | − m->export_entries_size = m->export_entries_count; |
| 34234 | | − m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size); |
| 34235 | | − if (!m->export_entries) |
| 34236 | | − goto fail; |
| 34237 | | − for(i = 0; i < m->export_entries_count; i++) { |
| 34238 | | − JSExportEntry *me = &m->export_entries[i]; |
| 34239 | | − if (bc_get_u8(s, &v8)) |
| 34240 | | − goto fail; |
| 34241 | | − me->export_type = v8; |
| 34242 | | − if (me->export_type == JS_EXPORT_TYPE_LOCAL) { |
| 34243 | | − if (bc_get_leb128_int(s, &me->u.local.var_idx)) |
| 34244 | | − goto fail; |
| 34245 | | − } else { |
| 34246 | | − if (bc_get_leb128_int(s, &me->u.req_module_idx)) |
| 34247 | | − goto fail; |
| 34248 | | − if (bc_get_atom(s, &me->local_name)) |
| 34249 | | − goto fail; |
| 34250 | | − } |
| 34251 | | − if (bc_get_atom(s, &me->export_name)) |
| 34252 | | − goto fail; |
| 34253 | | − } |
| 34254 | | − } |
| 34255 | | − |
| 34256 | | − if (bc_get_leb128_int(s, &m->star_export_entries_count)) |
| 34257 | | − goto fail; |
| 34258 | | − if (m->star_export_entries_count != 0) { |
| 34259 | | − m->star_export_entries_size = m->star_export_entries_count; |
| 34260 | | − m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size); |
| 34261 | | − if (!m->star_export_entries) |
| 34262 | | − goto fail; |
| 34263 | | − for(i = 0; i < m->star_export_entries_count; i++) { |
| 34264 | | − JSStarExportEntry *se = &m->star_export_entries[i]; |
| 34265 | | − if (bc_get_leb128_int(s, &se->req_module_idx)) |
| 34266 | | − goto fail; |
| 34267 | | − } |
| 34268 | | − } |
| 34269 | | − |
| 34270 | | − if (bc_get_leb128_int(s, &m->import_entries_count)) |
| 34271 | | − goto fail; |
| 34272 | | − if (m->import_entries_count != 0) { |
| 34273 | | − m->import_entries_size = m->import_entries_count; |
| 34274 | | − m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size); |
| 34275 | | − if (!m->import_entries) |
| 34276 | | − goto fail; |
| 34277 | | − for(i = 0; i < m->import_entries_count; i++) { |
| 34278 | | − JSImportEntry *mi = &m->import_entries[i]; |
| 34279 | | − if (bc_get_leb128_int(s, &mi->var_idx)) |
| 34280 | | − goto fail; |
| 34281 | | − if (bc_get_atom(s, &mi->import_name)) |
| 34282 | | − goto fail; |
| 34283 | | − if (bc_get_leb128_int(s, &mi->req_module_idx)) |
| 34284 | | − goto fail; |
| 34285 | | − } |
| 34286 | | − } |
| 34287 | | − |
| 34288 | | − m->func_obj = JS_ReadObjectRec(s); |
| 34289 | | − if (JS_IsException(m->func_obj)) |
| 34290 | | − goto fail; |
| 34291 | | − bc_read_trace(s, "}\n"); |
| 34292 | | − } |
| 35205 | + if (!s->allow_bytecode) |
| 35206 | + goto invalid_tag; |
| 35207 | + obj = JS_ReadModule(s); |
| 34293 | 35208 | break; |
| 34294 | 35209 | case BC_TAG_OBJECT: |
| 34295 | | − { |
| 34296 | | − uint32_t prop_count, i; |
| 34297 | | − JSAtom atom; |
| 34298 | | − JSValue val; |
| 34299 | | − int ret; |
| 34300 | | − |
| 34301 | | − bc_read_trace(s, "%s {\n", bc_tag_str[tag]); |
| 34302 | | − |
| 34303 | | − obj = JS_NewObject(ctx); |
| 34304 | | − if (bc_get_leb128(s, &prop_count)) |
| 34305 | | − goto fail; |
| 34306 | | − for(i = 0; i < prop_count; i++) { |
| 34307 | | − if (bc_get_atom(s, &atom)) |
| 34308 | | − goto fail; |
| 34309 | | −#ifdef DUMP_READ_OBJECT |
| 34310 | | − bc_read_trace(s, "propname: "); print_atom(s->ctx, atom); printf("\n"); |
| 34311 | | −#endif |
| 34312 | | − val = JS_ReadObjectRec(s); |
| 34313 | | − if (JS_IsException(val)) { |
| 34314 | | − JS_FreeAtom(ctx, atom); |
| 34315 | | − goto fail; |
| 34316 | | − } |
| 34317 | | − ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E); |
| 34318 | | − JS_FreeAtom(ctx, atom); |
| 34319 | | − if (ret < 0) |
| 34320 | | − goto fail; |
| 34321 | | − } |
| 34322 | | − bc_read_trace(s, "}\n"); |
| 34323 | | − } |
| 35210 | + obj = JS_ReadObjectTag(s); |
| 34324 | 35211 | break; |
| 34325 | 35212 | case BC_TAG_ARRAY: |
| 34326 | 35213 | case BC_TAG_TEMPLATE_OBJECT: |
| 34327 | | − { |
| 34328 | | − uint32_t len, i; |
| 34329 | | − JSValue val; |
| 34330 | | − int ret, prop_flags; |
| 34331 | | − BOOL is_template; |
| 34332 | | − |
| 34333 | | − bc_read_trace(s, "%s {\n", bc_tag_str[tag]); |
| 34334 | | − |
| 34335 | | − obj = JS_NewArray(ctx); |
| 34336 | | − is_template = (tag == BC_TAG_TEMPLATE_OBJECT); |
| 34337 | | − if (bc_get_leb128(s, &len)) |
| 34338 | | − goto fail; |
| 34339 | | − for(i = 0; i < len; i++) { |
| 34340 | | − val = JS_ReadObjectRec(s); |
| 34341 | | − if (JS_IsException(val)) |
| 34342 | | − goto fail; |
| 34343 | | − if (is_template) |
| 34344 | | − prop_flags = JS_PROP_ENUMERABLE; |
| 34345 | | − else |
| 34346 | | − prop_flags = JS_PROP_C_W_E; |
| 34347 | | − ret = JS_DefinePropertyValueUint32(ctx, obj, i, val, |
| 34348 | | − prop_flags); |
| 34349 | | − if (ret < 0) |
| 34350 | | − goto fail; |
| 34351 | | − } |
| 34352 | | − if (is_template) { |
| 34353 | | − val = JS_ReadObjectRec(s); |
| 34354 | | − if (JS_IsException(val)) |
| 34355 | | − goto fail; |
| 34356 | | − if (!JS_IsUndefined(val)) { |
| 34357 | | − ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0); |
| 34358 | | − if (ret < 0) |
| 34359 | | − goto fail; |
| 34360 | | − } |
| 34361 | | − JS_PreventExtensions(ctx, obj); |
| 34362 | | − } |
| 34363 | | − bc_read_trace(s, "}\n"); |
| 34364 | | − } |
| 35214 | + obj = JS_ReadArray(s, tag); |
| 35215 | + break; |
| 35216 | + case BC_TAG_TYPED_ARRAY: |
| 35217 | + obj = JS_ReadTypedArray(s); |
| 35218 | + break; |
| 35219 | + case BC_TAG_ARRAY_BUFFER: |
| 35220 | + obj = JS_ReadArrayBuffer(s); |
| 35221 | + break; |
| 35222 | + case BC_TAG_SHARED_ARRAY_BUFFER: |
| 35223 | + if (!s->allow_sab || !ctx->rt->sab_funcs.sab_dup) |
| 35224 | + goto invalid_tag; |
| 35225 | + obj = JS_ReadSharedArrayBuffer(s); |
| 35226 | + break; |
| 35227 | + case BC_TAG_DATE: |
| 35228 | + obj = JS_ReadDate(s); |
| 35229 | + break; |
| 35230 | + case BC_TAG_OBJECT_VALUE: |
| 35231 | + obj = JS_ReadObjectValue(s); |
| 34365 | 35232 | break; |
| 34366 | 35233 | #ifdef CONFIG_BIGNUM |
| 34367 | 35234 | case BC_TAG_BIG_INT: |
| 34368 | 35235 | case BC_TAG_BIG_FLOAT: |
| 34369 | 35236 | case BC_TAG_BIG_DECIMAL: |
| 34370 | 35237 | obj = JS_ReadBigNum(s, tag); |
| 34371 | | − if (JS_IsException(obj)) |
| 34372 | | − goto fail; |
| 34373 | 35238 | break; |
| 34374 | 35239 | #endif |
| 35240 | + case BC_TAG_OBJECT_REFERENCE: |
| 35241 | + { |
| 35242 | + uint32_t val; |
| 35243 | + if (!s->allow_reference) |
| 35244 | + return JS_ThrowSyntaxError(ctx, "object references are not allowed"); |
| 35245 | + if (bc_get_leb128(s, &val)) |
| 35246 | + return JS_EXCEPTION; |
| 35247 | + bc_read_trace(s, "%u\n", val); |
| 35248 | + if (val >= s->objects_count) { |
| 35249 | + return JS_ThrowSyntaxError(ctx, "invalid object reference (%u >= %u)", |
| 35250 | + val, s->objects_count); |
| 35251 | + } |
| 35252 | + obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, s->objects[val])); |
| 35253 | + } |
| 35254 | + break; |
| 34375 | 35255 | default: |
| 34376 | 35256 | invalid_tag: |
| 34377 | 35257 | return JS_ThrowSyntaxError(ctx, "invalid tag (tag=%d pos=%u)", |
| 34378 | 35258 | tag, (unsigned int)(s->ptr - s->buf_start)); |
| 34379 | 35259 | } |
| 35260 | + bc_read_trace(s, "}\n"); |
| 34380 | 35261 | return obj; |
| 34381 | | − fail: |
| 34382 | | − if (m) { |
| 34383 | | − js_free_module_def(ctx, m); |
| 34384 | | − } else { |
| 34385 | | − JS_FreeValue(ctx, obj); |
| 34386 | | − } |
| 34387 | | − return JS_EXCEPTION; |
| 34388 | 35262 | } |
| 34389 | 35263 | |
| 34390 | 35264 | static int JS_ReadObjectAtoms(BCReaderState *s) |
| @@ -34437,10 +35311,11 @@ static void bc_reader_free(BCReaderState *s) · 46 unmodified lines |
| 34437 | 35311 | } |
| 34438 | 35312 | js_free(s->ctx, s->idx_to_atom); |
| 34439 | 35313 | } |
| 35314 | + js_free(s->ctx, s->objects); |
| 34440 | 35315 | } |
| 34441 | 35316 | |
| 34442 | 35317 | JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, |
| 34443 | | − int flags) |
| 35318 | + int flags) |
| 34444 | 35319 | { |
| 34445 | 35320 | BCReaderState ss, *s = &ss; |
| 34446 | 35321 | JSValue obj; |
| @@ -34455,6 +35330,8 @@ JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, · 8 unmodified lines |
| 34455 | 35330 | s->ptr = buf; |
| 34456 | 35331 | s->allow_bytecode = ((flags & JS_READ_OBJ_BYTECODE) != 0); |
| 34457 | 35332 | s->is_rom_data = ((flags & JS_READ_OBJ_ROM_DATA) != 0); |
| 35333 | + s->allow_sab = ((flags & JS_READ_OBJ_SAB) != 0); |
| 35334 | + s->allow_reference = ((flags & JS_READ_OBJ_REFERENCE) != 0); |
| 34458 | 35335 | if (s->allow_bytecode) |
| 34459 | 35336 | s->first_atom = JS_ATOM_END; |
| 34460 | 35337 | else |
| @@ -34944,7 +35821,7 @@ static __exception int JS_ObjectDefineProperties(JSContext *ctx, · 483 unmodified lines |
| 34944 | 35821 | if (JS_IsException(props)) |
| 34945 | 35822 | return -1; |
| 34946 | 35823 | p = JS_VALUE_GET_OBJ(props); |
| 34947 | | − if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK) < 0) |
| 35824 | + if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) < 0) |
| 34948 | 35825 | goto exception; |
| 34949 | 35826 | for(i = 0; i < len; i++) { |
| 34950 | 35827 | JS_FreeValue(ctx, desc); |
| @@ -35021,7 +35898,7 @@ static JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val, · 70 unmodified lines |
| 35021 | 35898 | JS_VALUE_GET_TAG(val) == JS_TAG_UNDEFINED) |
| 35022 | 35899 | return JS_ThrowTypeErrorNotAnObject(ctx); |
| 35023 | 35900 | } |
| 35024 | | − return JS_DupValue(ctx, JS_GetPrototype(ctx, val)); |
| 35901 | + return JS_GetPrototype(ctx, val); |
| 35025 | 35902 | } |
| 35026 | 35903 | |
| 35027 | 35904 | static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val, |
| @@ -35815,7 +36692,7 @@ static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val) · 787 unmodified lines |
| 35815 | 36692 | val = JS_ToObject(ctx, this_val); |
| 35816 | 36693 | if (JS_IsException(val)) |
| 35817 | 36694 | return val; |
| 35818 | | − ret = JS_DupValue(ctx, JS_GetPrototype(ctx, val)); |
| 36695 | + ret = JS_GetPrototype(ctx, val); |
| 35819 | 36696 | JS_FreeValue(ctx, val); |
| 35820 | 36697 | return ret; |
| 35821 | 36698 | } |
| @@ -35836,9 +36713,9 @@ static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val, · 14 unmodified lines |
| 35836 | 36713 | static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val, |
| 35837 | 36714 | int argc, JSValueConst *argv) |
| 35838 | 36715 | { |
| 35839 | | − JSValue obj; |
| 36716 | + JSValue obj, v1; |
| 35840 | 36717 | JSValueConst v; |
| 35841 | | − int max_depth = 1000, res = -1; |
| 36718 | + int res; |
| 35842 | 36719 | |
| 35843 | 36720 | v = argv[0]; |
| 35844 | 36721 | if (!JS_IsObject(v)) |
| @@ -35846,27 +36723,29 @@ static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val, · 1 unmodified line |
| 35846 | 36723 | obj = JS_ToObject(ctx, this_val); |
| 35847 | 36724 | if (JS_IsException(obj)) |
| 35848 | 36725 | return JS_EXCEPTION; |
| 35849 | | − while (--max_depth > 0) { |
| 35850 | | − v = JS_GetPrototype(ctx, v); |
| 35851 | | − if (JS_IsException(v)) |
| 36726 | + v1 = JS_DupValue(ctx, v); |
| 36727 | + for(;;) { |
| 36728 | + v1 = JS_GetPrototypeFree(ctx, v1); |
| 36729 | + if (JS_IsException(v1)) |
| 35852 | 36730 | goto exception; |
| 35853 | | − if (JS_IsNull(v)) { |
| 36731 | + if (JS_IsNull(v1)) { |
| 35854 | 36732 | res = FALSE; |
| 35855 | 36733 | break; |
| 35856 | 36734 | } |
| 35857 | | − if (js_strict_eq2(ctx, JS_DupValue(ctx, obj), JS_DupValue(ctx, v), |
| 35858 | | − JS_EQ_STRICT)) { |
| 36735 | + if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) { |
| 35859 | 36736 | res = TRUE; |
| 35860 | 36737 | break; |
| 35861 | 36738 | } |
| 36739 | + /* avoid infinite loop (possible with proxies) */ |
| 36740 | + if (js_poll_interrupts(ctx)) |
| 36741 | + goto exception; |
| 35862 | 36742 | } |
| 36743 | + JS_FreeValue(ctx, v1); |
| 35863 | 36744 | JS_FreeValue(ctx, obj); |
| 35864 | | − if (res < 0) |
| 35865 | | − return JS_ThrowInternalError(ctx, "prototype chain cycle"); |
| 35866 | | − else |
| 35867 | | − return JS_NewBool(ctx, res); |
| 36745 | + return JS_NewBool(ctx, res); |
| 35868 | 36746 | |
| 35869 | 36747 | exception: |
| 36748 | + JS_FreeValue(ctx, v1); |
| 35870 | 36749 | JS_FreeValue(ctx, obj); |
| 35871 | 36750 | return JS_EXCEPTION; |
| 35872 | 36751 | } |
| @@ -35906,7 +36785,6 @@ static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val, · 33 unmodified lines |
| 35906 | 36785 | int argc, JSValueConst *argv, int setter) |
| 35907 | 36786 | { |
| 35908 | 36787 | JSValue obj, res = JS_EXCEPTION; |
| 35909 | | − JSValueConst v; |
| 35910 | 36788 | JSAtom prop = JS_ATOM_NULL; |
| 35911 | 36789 | JSPropertyDescriptor desc; |
| 35912 | 36790 | int has_prop; |
| @@ -35918,8 +36796,8 @@ static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val, · 5 unmodified lines |
| 35918 | 36796 | if (unlikely(prop == JS_ATOM_NULL)) |
| 35919 | 36797 | goto exception; |
| 35920 | 36798 | |
| 35921 | | − for (v = obj;;) { |
| 35922 | | − has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(v), prop); |
| 36799 | + for (;;) { |
| 36800 | + has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop); |
| 35923 | 36801 | if (has_prop < 0) |
| 35924 | 36802 | goto exception; |
| 35925 | 36803 | if (has_prop) { |
| @@ -35930,13 +36808,16 @@ static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val, · 4 unmodified lines |
| 35930 | 36808 | js_free_desc(ctx, &desc); |
| 35931 | 36809 | break; |
| 35932 | 36810 | } |
| 35933 | | − v = JS_GetPrototype(ctx, v); |
| 35934 | | − if (JS_IsException(v)) |
| 36811 | + obj = JS_GetPrototypeFree(ctx, obj); |
| 36812 | + if (JS_IsException(obj)) |
| 35935 | 36813 | goto exception; |
| 35936 | | − if (JS_IsNull(v)) { |
| 36814 | + if (JS_IsNull(obj)) { |
| 35937 | 36815 | res = JS_UNDEFINED; |
| 35938 | 36816 | break; |
| 35939 | 36817 | } |
| 36818 | + /* avoid infinite loop (possible with proxies) */ |
| 36819 | + if (js_poll_interrupts(ctx)) |
| 36820 | + goto exception; |
| 35940 | 36821 | } |
| 35941 | 36822 | |
| 35942 | 36823 | exception: |
| @@ -36002,59 +36883,12 @@ static JSValue js_function_proto(JSContext *ctx, JSValueConst this_val, · 59 unmodified lines |
| 36002 | 36883 | return JS_UNDEFINED; |
| 36003 | 36884 | } |
| 36004 | 36885 | |
| 36005 | | −/* insert a '\n' at unicode character position 'pos' in the source of |
| 36006 | | − 'func_obj' */ |
| 36007 | | −static int patch_function_constructor_source(JSContext *ctx, |
| 36008 | | − JSValueConst func_obj, |
| 36009 | | − size_t pos) |
| 36010 | | −{ |
| 36011 | | − JSObject *p; |
| 36012 | | − JSFunctionBytecode *b; |
| 36013 | | − char *r, *r_end, *new_source; |
| 36014 | | − int c; |
| 36015 | | − size_t idx, len; |
| 36016 | | − |
| 36017 | | − if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT) |
| 36018 | | − return 0; |
| 36019 | | − p = JS_VALUE_GET_OBJ(func_obj); |
| 36020 | | − if (!js_class_has_bytecode(p->class_id)) |
| 36021 | | − return 0; |
| 36022 | | − b = p->u.func.function_bytecode; |
| 36023 | | − if (!b->has_debug) |
| 36024 | | − return 0; |
| 36025 | | − r = b->debug.source; |
| 36026 | | − r_end = b->debug.source + b->debug.source_len; |
| 36027 | | − idx = 0; |
| 36028 | | − while (r < r_end) { |
| 36029 | | − if (idx == pos) { |
| 36030 | | − /* add the '\n' */ |
| 36031 | | − new_source = js_realloc(ctx, b->debug.source, |
| 36032 | | − b->debug.source_len + 2); |
| 36033 | | − if (!new_source) |
| 36034 | | − return -1; |
| 36035 | | − len = r - b->debug.source; |
| 36036 | | − memmove(new_source + len + 1, new_source + len, |
| 36037 | | − b->debug.source_len + 1 - len); |
| 36038 | | − new_source[len] = '\n'; |
| 36039 | | − b->debug.source = new_source; |
| 36040 | | − b->debug.source_len++; |
| 36041 | | − break; |
| 36042 | | − } |
| 36043 | | − c = unicode_from_utf8((const uint8_t *)r, UTF8_CHAR_LEN_MAX, |
| 36044 | | − (const uint8_t **)&r); |
| 36045 | | − if (c < 0) |
| 36046 | | − break; |
| 36047 | | − idx++; |
| 36048 | | − } |
| 36049 | | − return 0; |
| 36050 | | −} |
| 36051 | | − |
| 36052 | 36886 | /* XXX: add a specific eval mode so that Function("}), ({") is rejected */ |
| 36053 | 36887 | static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target, |
| 36054 | 36888 | int argc, JSValueConst *argv, int magic) |
| 36055 | 36889 | { |
| 36056 | 36890 | JSFunctionKindEnum func_kind = magic; |
| 36057 | | − int i, n, ret, func_start_pos; |
| 36891 | + int i, n, ret; |
| 36058 | 36892 | JSValue s, proto, obj = JS_UNDEFINED; |
| 36059 | 36893 | StringBuffer b_s, *b = &b_s; |
| 36060 | 36894 | |
| @@ -36079,13 +36913,7 @@ static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target, · 18 unmodified lines |
| 36079 | 36913 | if (string_buffer_concat_value(b, argv[i])) |
| 36080 | 36914 | goto fail; |
| 36081 | 36915 | } |
| 36082 | | − string_buffer_puts8(b, "\n) {"); |
| 36083 | | − /* Annex B HTML comments: We don't add a '\n' after "{" so that |
| 36084 | | − "-->" is not considered as an HTML comment. It is necessary |
| 36085 | | − because in the spec the function body is parsed separately. */ |
| 36086 | | − /* XXX: find a simpler way or be deliberately incompatible to |
| 36087 | | − simplify the code ? */ |
| 36088 | | − func_start_pos = b->len - 1; /* the leading '(' is not in the source */ |
| 36916 | + string_buffer_puts8(b, "\n) {\n"); |
| 36089 | 36917 | if (n >= 0) { |
| 36090 | 36918 | if (string_buffer_concat_value(b, argv[n])) |
| 36091 | 36919 | goto fail; |
| @@ -36099,8 +36927,6 @@ static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target, · 7 unmodified lines |
| 36099 | 36927 | JS_FreeValue(ctx, s); |
| 36100 | 36928 | if (JS_IsException(obj)) |
| 36101 | 36929 | goto fail1; |
| 36102 | | − if (patch_function_constructor_source(ctx, obj, func_start_pos) < 0) |
| 36103 | | − goto fail1; |
| 36104 | 36930 | if (!JS_IsUndefined(new_target)) { |
| 36105 | 36931 | /* set the prototype */ |
| 36106 | 36932 | proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype); |
| @@ -36315,27 +37141,22 @@ static JSValue js_function_toString(JSContext *ctx, JSValueConst this_val, · 208 unmodified lines |
| 36315 | 37141 | JSValue name; |
| 36316 | 37142 | const char *pref, *suff; |
| 36317 | 37143 | |
| 36318 | | − if (p->is_class) { |
| 36319 | | − pref = "class "; |
| 36320 | | − suff = " {\n [native code]\n}"; |
| 36321 | | − } else { |
| 36322 | | − switch(func_kind) { |
| 36323 | | − default: |
| 36324 | | − case JS_FUNC_NORMAL: |
| 36325 | | − pref = "function "; |
| 36326 | | − break; |
| 36327 | | − case JS_FUNC_GENERATOR: |
| 36328 | | − pref = "function *"; |
| 36329 | | − break; |
| 36330 | | − case JS_FUNC_ASYNC: |
| 36331 | | − pref = "async function "; |
| 36332 | | − break; |
| 36333 | | − case JS_FUNC_ASYNC_GENERATOR: |
| 36334 | | − pref = "async function *"; |
| 36335 | | − break; |
| 36336 | | − } |
| 36337 | | − suff = "() {\n [native code]\n}"; |
| 37144 | + switch(func_kind) { |
| 37145 | + default: |
| 37146 | + case JS_FUNC_NORMAL: |
| 37147 | + pref = "function "; |
| 37148 | + break; |
| 37149 | + case JS_FUNC_GENERATOR: |
| 37150 | + pref = "function *"; |
| 37151 | + break; |
| 37152 | + case JS_FUNC_ASYNC: |
| 37153 | + pref = "async function "; |
| 37154 | + break; |
| 37155 | + case JS_FUNC_ASYNC_GENERATOR: |
| 37156 | + pref = "async function *"; |
| 37157 | + break; |
| 36338 | 37158 | } |
| 37159 | + suff = "() {\n [native code]\n}"; |
| 36339 | 37160 | name = JS_GetProperty(ctx, this_val, JS_ATOM_name); |
| 36340 | 37161 | if (JS_IsUndefined(name)) |
| 36341 | 37162 | name = JS_AtomToString(ctx, JS_ATOM_empty_string); |
| @@ -36435,12 +37256,6 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, · 93 unmodified lines |
| 36435 | 37256 | if (JS_IsException(obj)) |
| 36436 | 37257 | return obj; |
| 36437 | 37258 | if (magic == JS_AGGREGATE_ERROR) { |
| 36438 | | − JSObject *p; |
| 36439 | | − JSValue error_list = iterator_to_array(ctx, argv[0]); |
| 36440 | | − if (JS_IsException(error_list)) |
| 36441 | | − goto exception; |
| 36442 | | − p = JS_VALUE_GET_OBJ(obj); |
| 36443 | | − p->u.object_data = error_list; |
| 36444 | 37259 | message = argv[1]; |
| 36445 | 37260 | } else { |
| 36446 | 37261 | message = argv[0]; |
| @@ -36448,17 +37263,26 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, · 1 unmodified line |
| 36448 | 37263 | |
| 36449 | 37264 | if (!JS_IsUndefined(message)) { |
| 36450 | 37265 | msg = JS_ToString(ctx, message); |
| 36451 | | − if (unlikely(JS_IsException(msg))) { |
| 36452 | | − exception: |
| 36453 | | − JS_FreeValue(ctx, obj); |
| 36454 | | − return JS_EXCEPTION; |
| 36455 | | − } |
| 37266 | + if (unlikely(JS_IsException(msg))) |
| 37267 | + goto exception; |
| 36456 | 37268 | JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg, |
| 36457 | 37269 | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); |
| 36458 | 37270 | } |
| 37271 | + |
| 37272 | + if (magic == JS_AGGREGATE_ERROR) { |
| 37273 | + JSValue error_list = iterator_to_array(ctx, argv[0]); |
| 37274 | + if (JS_IsException(error_list)) |
| 37275 | + goto exception; |
| 37276 | + JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, error_list, |
| 37277 | + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); |
| 37278 | + } |
| 37279 | + |
| 36459 | 37280 | /* skip the Error() function in the backtrace */ |
| 36460 | 37281 | build_backtrace(ctx, obj, NULL, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL); |
| 36461 | 37282 | return obj; |
| 37283 | + exception: |
| 37284 | + JS_FreeValue(ctx, obj); |
| 37285 | + return JS_EXCEPTION; |
| 36462 | 37286 | } |
| 36463 | 37287 | |
| 36464 | 37288 | static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val, |
| @@ -36498,56 +37322,22 @@ static const JSCFunctionListEntry js_error_proto_funcs[] = { · 33 unmodified lines |
| 36498 | 37322 | |
| 36499 | 37323 | /* AggregateError */ |
| 36500 | 37324 | |
| 36501 | | −/* used by C code. 'errors' must be a fast array. */ |
| 37325 | +/* used by C code. */ |
| 36502 | 37326 | static JSValue js_aggregate_error_constructor(JSContext *ctx, |
| 36503 | 37327 | JSValueConst errors) |
| 36504 | 37328 | { |
| 36505 | 37329 | JSValue obj; |
| 36506 | | − JSObject *p; |
| 36507 | 37330 | |
| 36508 | 37331 | obj = JS_NewObjectProtoClass(ctx, |
| 36509 | 37332 | ctx->native_error_proto[JS_AGGREGATE_ERROR], |
| 36510 | 37333 | JS_CLASS_ERROR); |
| 36511 | 37334 | if (JS_IsException(obj)) |
| 36512 | 37335 | return obj; |
| 36513 | | − p = JS_VALUE_GET_OBJ(obj); |
| 36514 | | − p->u.object_data = JS_DupValue(ctx, errors); |
| 37336 | + JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, JS_DupValue(ctx, errors), |
| 37337 | + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); |
| 36515 | 37338 | return obj; |
| 36516 | 37339 | } |
| 36517 | 37340 | |
| 36518 | | −static JSValue js_aggregate_error_errors(JSContext *ctx, JSValueConst this_val) |
| 36519 | | −{ |
| 36520 | | − JSObject *p; |
| 36521 | | − JSValue r, *arr; |
| 36522 | | − uint32_t len, i; |
| 36523 | | − |
| 36524 | | − if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT) |
| 36525 | | − goto invalid_type; |
| 36526 | | − p = JS_VALUE_GET_OBJ(this_val); |
| 36527 | | − if (p->class_id != JS_CLASS_ERROR) |
| 36528 | | − goto invalid_type; |
| 36529 | | − if (!js_get_fast_array(ctx, p->u.object_data, &arr, &len)) { |
| 36530 | | − invalid_type: |
| 36531 | | − return JS_ThrowTypeError(ctx, "not an AggregateError"); |
| 36532 | | − } |
| 36533 | | − r = JS_NewArray(ctx); |
| 36534 | | − if (JS_IsException(r)) |
| 36535 | | − goto exception; |
| 36536 | | − for(i = 0; i < len; i++) { |
| 36537 | | − if (JS_DefinePropertyValueInt64(ctx, r, i, JS_DupValue(ctx, arr[i]), |
| 36538 | | − JS_PROP_C_W_E | JS_PROP_THROW) < 0) |
| 36539 | | − goto exception; |
| 36540 | | − } |
| 36541 | | − return r; |
| 36542 | | − exception: |
| 36543 | | − JS_FreeValue(ctx, r); |
| 36544 | | − return JS_EXCEPTION; |
| 36545 | | −} |
| 36546 | | − |
| 36547 | | −static const JSCFunctionListEntry js_aggregate_error_proto_funcs[] = { |
| 36548 | | − JS_CGETSET_DEF("errors", js_aggregate_error_errors, NULL), |
| 36549 | | −}; |
| 36550 | | − |
| 36551 | 37341 | /* Array */ |
| 36552 | 37342 | |
| 36553 | 37343 | static int JS_CopySubArray(JSContext *ctx, |
| @@ -39130,22 +39920,25 @@ static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val, · 2576 unmodified lines |
| 39130 | 39920 | p1 = JS_VALUE_GET_STRING(v); |
| 39131 | 39921 | len = p->len; |
| 39132 | 39922 | v_len = p1->len; |
| 39133 | | − pos = (magic & 2) ? len : 0; |
| 39923 | + pos = (magic == 2) ? len : 0; |
| 39134 | 39924 | if (argc > 1 && !JS_IsUndefined(argv[1])) { |
| 39135 | 39925 | if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0)) |
| 39136 | 39926 | goto fail; |
| 39137 | 39927 | } |
| 39138 | 39928 | len -= v_len; |
| 39139 | | − start = pos; |
| 39140 | | − stop = len; |
| 39141 | | − if (magic & 1) { |
| 39142 | | − stop = pos; |
| 39143 | | − } |
| 39144 | | − if (magic & 2) { |
| 39145 | | − pos -= v_len; |
| 39929 | + ret = 0; |
| 39930 | + if (magic == 0) { |
| 39931 | + start = pos; |
| 39932 | + stop = len; |
| 39933 | + } else { |
| 39934 | + if (magic == 1) { |
| 39935 | + if (pos > len) |
| 39936 | + goto done; |
| 39937 | + } else { |
| 39938 | + pos -= v_len; |
| 39939 | + } |
| 39146 | 39940 | start = stop = pos; |
| 39147 | 39941 | } |
| 39148 | | − ret = 0; |
| 39149 | 39942 | if (start >= 0 && start <= stop) { |
| 39150 | 39943 | for (i = start;; i++) { |
| 39151 | 39944 | if (!string_cmp(p, p1, i, 0, v_len)) { |
| @@ -39156,6 +39949,7 @@ static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val, · 4 unmodified lines |
| 39156 | 39949 | break; |
| 39157 | 39950 | } |
| 39158 | 39951 | } |
| 39952 | + done: |
| 39159 | 39953 | JS_FreeValue(ctx, str); |
| 39160 | 39954 | JS_FreeValue(ctx, v); |
| 39161 | 39955 | return JS_NewBool(ctx, ret); |
| @@ -40372,46 +41166,23 @@ static double js_math_round(double a) · 1210 unmodified lines |
| 40372 | 41166 | static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val, |
| 40373 | 41167 | int argc, JSValueConst *argv) |
| 40374 | 41168 | { |
| 40375 | | − double r, a, b; |
| 41169 | + double r, a; |
| 40376 | 41170 | int i; |
| 40377 | 41171 | |
| 40378 | | − if (argc == 2) { |
| 40379 | | − /* use the more precise built-in function when possible */ |
| 40380 | | − if (JS_ToFloat64(ctx, &a, argv[0])) |
| 40381 | | − return JS_EXCEPTION; |
| 40382 | | − if (JS_ToFloat64(ctx, &b, argv[1])) |
| 40383 | | − return JS_EXCEPTION; |
| 40384 | | − r = hypot(a, b); |
| 40385 | | − } else if (argc == 0) { |
| 40386 | | − r = 0; |
| 40387 | | − } else { |
| 40388 | | − double *tab, a_max; |
| 40389 | | − tab = js_malloc(ctx, sizeof(tab[0]) * argc); |
| 40390 | | − if (!tab) |
| 41172 | + r = 0; |
| 41173 | + if (argc > 0) { |
| 41174 | + if (JS_ToFloat64(ctx, &r, argv[0])) |
| 40391 | 41175 | return JS_EXCEPTION; |
| 40392 | | − /* avoid overflow by taking the maximum */ |
| 40393 | | − a_max = 0; |
| 40394 | | − for(i = 0; i < argc; i++) { |
| 40395 | | − if (JS_ToFloat64(ctx, &a, argv[i])) { |
| 40396 | | − js_free(ctx, tab); |
| 40397 | | − return JS_EXCEPTION; |
| 40398 | | − } |
| 40399 | | − a = fabs(a); |
| 40400 | | − tab[i] = a; |
| 40401 | | − if (a > a_max) |
| 40402 | | − a_max = a; |
| 40403 | | − } |
| 40404 | | − if (a_max == 0 || !isfinite(a_max)) { |
| 40405 | | − r = a_max; |
| 41176 | + if (argc == 1) { |
| 41177 | + r = fabs(r); |
| 40406 | 41178 | } else { |
| 40407 | | − r = 0; |
| 40408 | | − for(i = 0; i < argc; i++) { |
| 40409 | | − a = tab[i] / a_max; |
| 40410 | | − r += a * a; |
| 41179 | + /* use the built-in function to minimize precision loss */ |
| 41180 | + for (i = 1; i < argc; i++) { |
| 41181 | + if (JS_ToFloat64(ctx, &a, argv[i])) |
| 41182 | + return JS_EXCEPTION; |
| 41183 | + r = hypot(r, a); |
| 40411 | 41184 | } |
| 40412 | | − r = a_max * sqrt(r); |
| 40413 | 41185 | } |
| 40414 | | − js_free(ctx, tab); |
| 40415 | 41186 | } |
| 40416 | 41187 | return JS_NewFloat64(ctx, r); |
| 40417 | 41188 | } |
| @@ -42093,58 +42864,69 @@ void JS_AddIntrinsicRegExp(JSContext *ctx) · 1675 unmodified lines |
| 42093 | 42864 | |
| 42094 | 42865 | /* JSON */ |
| 42095 | 42866 | |
| 42096 | | −/* XXX: this parser is less strict than the JSON standard because we |
| 42097 | | − reuse the Javascript tokenizer. It could be improved by adding a |
| 42098 | | − specific JSON parse flag. */ |
| 42867 | +static int json_parse_expect(JSParseState *s, int tok) |
| 42868 | +{ |
| 42869 | + if (s->token.val != tok) { |
| 42870 | + /* XXX: dump token correctly in all cases */ |
| 42871 | + return js_parse_error(s, "expecting '%c'", tok); |
| 42872 | + } |
| 42873 | + return json_next_token(s); |
| 42874 | +} |
| 42875 | + |
| 42099 | 42876 | static JSValue json_parse_value(JSParseState *s) |
| 42100 | 42877 | { |
| 42101 | 42878 | JSContext *ctx = s->ctx; |
| 42102 | 42879 | JSValue val = JS_NULL; |
| 42103 | | − BOOL is_neg; |
| 42104 | 42880 | int ret; |
| 42105 | 42881 | |
| 42106 | 42882 | switch(s->token.val) { |
| 42107 | 42883 | case '{': |
| 42108 | 42884 | { |
| 42109 | | − JSValue prop_val, prop_str; |
| 42110 | | − |
| 42111 | | − if (next_token(s)) |
| 42885 | + JSValue prop_val; |
| 42886 | + JSAtom prop_name; |
| 42887 | + |
| 42888 | + if (json_next_token(s)) |
| 42112 | 42889 | goto fail; |
| 42113 | 42890 | val = JS_NewObject(ctx); |
| 42114 | 42891 | if (JS_IsException(val)) |
| 42115 | 42892 | goto fail; |
| 42116 | 42893 | if (s->token.val != '}') { |
| 42117 | 42894 | for(;;) { |
| 42118 | | − if (s->token.val != TOK_STRING) { |
| 42895 | + if (s->token.val == TOK_STRING) { |
| 42896 | + prop_name = JS_ValueToAtom(ctx, s->token.u.str.str); |
| 42897 | + if (prop_name == JS_ATOM_NULL) |
| 42898 | + goto fail; |
| 42899 | + } else if (s->ext_json && s->token.val == TOK_IDENT) { |
| 42900 | + prop_name = JS_DupAtom(ctx, s->token.u.ident.atom); |
| 42901 | + } else { |
| 42119 | 42902 | js_parse_error(s, "expecting property name"); |
| 42120 | 42903 | goto fail; |
| 42121 | 42904 | } |
| 42122 | | − prop_str = JS_DupValue(ctx, s->token.u.str.str); |
| 42123 | | − if (next_token(s)) { |
| 42124 | | − JS_FreeValue(ctx, prop_str); |
| 42125 | | − goto fail; |
| 42126 | | − } |
| 42127 | | − if (js_parse_expect(s, ':')) { |
| 42128 | | − JS_FreeValue(ctx, prop_str); |
| 42129 | | − goto fail; |
| 42130 | | − } |
| 42905 | + if (json_next_token(s)) |
| 42906 | + goto fail1; |
| 42907 | + if (json_parse_expect(s, ':')) |
| 42908 | + goto fail1; |
| 42131 | 42909 | prop_val = json_parse_value(s); |
| 42132 | 42910 | if (JS_IsException(prop_val)) { |
| 42133 | | − JS_FreeValue(ctx, prop_str); |
| 42911 | + fail1: |
| 42912 | + JS_FreeAtom(ctx, prop_name); |
| 42134 | 42913 | goto fail; |
| 42135 | 42914 | } |
| 42136 | | − ret = JS_DefinePropertyValueValue(ctx, val, prop_str, |
| 42137 | | − prop_val, JS_PROP_C_W_E); |
| 42915 | + ret = JS_DefinePropertyValue(ctx, val, prop_name, |
| 42916 | + prop_val, JS_PROP_C_W_E); |
| 42917 | + JS_FreeAtom(ctx, prop_name); |
| 42138 | 42918 | if (ret < 0) |
| 42139 | 42919 | goto fail; |
| 42140 | 42920 | |
| 42141 | 42921 | if (s->token.val != ',') |
| 42142 | 42922 | break; |
| 42143 | | − if (next_token(s)) |
| 42923 | + if (json_next_token(s)) |
| 42144 | 42924 | goto fail; |
| 42925 | + if (s->ext_json && s->token.val == '}') |
| 42926 | + break; |
| 42145 | 42927 | } |
| 42146 | 42928 | } |
| 42147 | | − if (js_parse_expect(s, '}')) |
| 42929 | + if (json_parse_expect(s, '}')) |
| 42148 | 42930 | goto fail; |
| 42149 | 42931 | } |
| 42150 | 42932 | break; |
| @@ -42153,7 +42935,7 @@ static JSValue json_parse_value(JSParseState *s) · 2 unmodified lines |
| 42153 | 42935 | JSValue el; |
| 42154 | 42936 | uint32_t idx; |
| 42155 | 42937 | |
| 42156 | | − if (next_token(s)) |
| 42938 | + if (json_next_token(s)) |
| 42157 | 42939 | goto fail; |
| 42158 | 42940 | val = JS_NewArray(ctx); |
| 42159 | 42941 | if (JS_IsException(val)) |
| @@ -42169,52 +42951,41 @@ static JSValue json_parse_value(JSParseState *s) · 9 unmodified lines |
| 42169 | 42951 | goto fail; |
| 42170 | 42952 | if (s->token.val != ',') |
| 42171 | 42953 | break; |
| 42172 | | − if (next_token(s)) |
| 42954 | + if (json_next_token(s)) |
| 42173 | 42955 | goto fail; |
| 42174 | 42956 | idx++; |
| 42957 | + if (s->ext_json && s->token.val == ']') |
| 42958 | + break; |
| 42175 | 42959 | } |
| 42176 | 42960 | } |
| 42177 | | − if (js_parse_expect(s, ']')) |
| 42961 | + if (json_parse_expect(s, ']')) |
| 42178 | 42962 | goto fail; |
| 42179 | 42963 | } |
| 42180 | 42964 | break; |
| 42181 | 42965 | case TOK_STRING: |
| 42182 | 42966 | val = JS_DupValue(ctx, s->token.u.str.str); |
| 42183 | | − if (next_token(s)) |
| 42967 | + if (json_next_token(s)) |
| 42184 | 42968 | goto fail; |
| 42185 | 42969 | break; |
| 42186 | 42970 | case TOK_NUMBER: |
| 42187 | | − is_neg = 0; |
| 42188 | | − goto number; |
| 42189 | | − case '-': |
| 42190 | | − if (next_token(s)) |
| 42191 | | − goto fail; |
| 42192 | | − if (s->token.val != TOK_NUMBER) { |
| 42193 | | − js_parse_error(s, "number expected"); |
| 42194 | | − goto fail; |
| 42195 | | − } |
| 42196 | | − is_neg = 1; |
| 42197 | | − number: |
| 42198 | 42971 | val = s->token.u.num.val; |
| 42199 | | − if (is_neg) { |
| 42200 | | − double d; |
| 42201 | | − JS_ToFloat64(ctx, &d, val); /* no exception possible */ |
| 42202 | | − val = JS_NewFloat64(ctx, -d); |
| 42203 | | − } |
| 42204 | | − if (next_token(s)) |
| 42972 | + if (json_next_token(s)) |
| 42205 | 42973 | goto fail; |
| 42206 | 42974 | break; |
| 42207 | | − case TOK_FALSE: |
| 42208 | | − case TOK_TRUE: |
| 42209 | | − val = JS_NewBool(ctx, s->token.val - TOK_FALSE); |
| 42210 | | − if (next_token(s)) |
| 42211 | | − goto fail; |
| 42212 | | − break; |
| 42213 | | − case TOK_NULL: |
| 42214 | | − if (next_token(s)) |
| 42975 | + case TOK_IDENT: |
| 42976 | + if (s->token.u.ident.atom == JS_ATOM_false || |
| 42977 | + s->token.u.ident.atom == JS_ATOM_true) { |
| 42978 | + val = JS_NewBool(ctx, (s->token.u.ident.atom == JS_ATOM_true)); |
| 42979 | + } else if (s->token.u.ident.atom == JS_ATOM_null) { |
| 42980 | + val = JS_NULL; |
| 42981 | + } else { |
| 42982 | + goto def_token; |
| 42983 | + } |
| 42984 | + if (json_next_token(s)) |
| 42215 | 42985 | goto fail; |
| 42216 | 42986 | break; |
| 42217 | 42987 | default: |
| 42988 | + def_token: |
| 42218 | 42989 | if (s->token.val == TOK_EOF) { |
| 42219 | 42990 | js_parse_error(s, "unexpected end of input"); |
| 42220 | 42991 | } else { |
| @@ -42229,15 +43000,15 @@ static JSValue json_parse_value(JSParseState *s) · 8 unmodified lines |
| 42229 | 43000 | return JS_EXCEPTION; |
| 42230 | 43001 | } |
| 42231 | 43002 | |
| 42232 | | −JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, |
| 42233 | | − const char *filename) |
| 43003 | +JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len, |
| 43004 | + const char *filename, int flags) |
| 42234 | 43005 | { |
| 42235 | 43006 | JSParseState s1, *s = &s1; |
| 42236 | | − JSValue val; |
| 43007 | + JSValue val = JS_UNDEFINED; |
| 42237 | 43008 | |
| 42238 | 43009 | js_parse_init(ctx, s, buf, buf_len, filename); |
| 42239 | | − |
| 42240 | | − if (next_token(s)) |
| 43010 | + s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0); |
| 43011 | + if (json_next_token(s)) |
| 42241 | 43012 | goto fail; |
| 42242 | 43013 | val = json_parse_value(s); |
| 42243 | 43014 | if (JS_IsException(val)) |
| @@ -42248,10 +43019,17 @@ JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, · 4 unmodified lines |
| 42248 | 43019 | } |
| 42249 | 43020 | return val; |
| 42250 | 43021 | fail: |
| 43022 | + JS_FreeValue(ctx, val); |
| 42251 | 43023 | free_token(s, &s->token); |
| 42252 | 43024 | return JS_EXCEPTION; |
| 42253 | 43025 | } |
| 42254 | 43026 | |
| 43027 | +JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, |
| 43028 | + const char *filename) |
| 43029 | +{ |
| 43030 | + return JS_ParseJSON2(ctx, buf, buf_len, filename, 0); |
| 43031 | +} |
| 43032 | + |
| 42255 | 43033 | static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder, |
| 42256 | 43034 | JSAtom name, JSValueConst reviver) |
| 42257 | 43035 | { |
| @@ -42960,7 +43738,6 @@ static void js_proxy_finalizer(JSRuntime *rt, JSValue val) · 702 unmodified lines |
| 42960 | 43738 | if (s) { |
| 42961 | 43739 | JS_FreeValueRT(rt, s->target); |
| 42962 | 43740 | JS_FreeValueRT(rt, s->handler); |
| 42963 | | − JS_FreeValueRT(rt, s->proto); |
| 42964 | 43741 | js_free_rt(rt, s); |
| 42965 | 43742 | } |
| 42966 | 43743 | } |
| @@ -42972,7 +43749,6 @@ static void js_proxy_mark(JSRuntime *rt, JSValueConst val, · 5 unmodified lines |
| 42972 | 43749 | if (s) { |
| 42973 | 43750 | JS_MarkValue(rt, s->target, mark_func); |
| 42974 | 43751 | JS_MarkValue(rt, s->handler, mark_func); |
| 42975 | | − JS_MarkValue(rt, s->proto, mark_func); |
| 42976 | 43752 | } |
| 42977 | 43753 | } |
| 42978 | 43754 | |
| @@ -43007,17 +43783,12 @@ static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod, · 28 unmodified lines |
| 43007 | 43783 | return s; |
| 43008 | 43784 | } |
| 43009 | 43785 | |
| 43010 | | −static JSValueConst js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj) |
| 43786 | +static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj) |
| 43011 | 43787 | { |
| 43012 | 43788 | JSProxyData *s; |
| 43013 | | − JSValue method, ret; |
| 43014 | | − JSValueConst proto1; |
| 43789 | + JSValue method, ret, proto1; |
| 43015 | 43790 | int res; |
| 43016 | 43791 | |
| 43017 | | − /* must check for timeout to avoid infinite loop in instanceof */ |
| 43018 | | − if (js_poll_interrupts(ctx)) |
| 43019 | | − return JS_EXCEPTION; |
| 43020 | | − |
| 43021 | 43792 | s = get_proxy_method(ctx, &method, obj, JS_ATOM_getPrototypeOf); |
| 43022 | 43793 | if (!s) |
| 43023 | 43794 | return JS_EXCEPTION; |
| @@ -43043,22 +43814,22 @@ static JSValueConst js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj) · 19 unmodified lines |
| 43043 | 43814 | return JS_EXCEPTION; |
| 43044 | 43815 | } |
| 43045 | 43816 | if (JS_VALUE_GET_OBJ(proto1) != JS_VALUE_GET_OBJ(ret)) { |
| 43817 | + JS_FreeValue(ctx, proto1); |
| 43046 | 43818 | fail: |
| 43047 | 43819 | JS_FreeValue(ctx, ret); |
| 43048 | 43820 | return JS_ThrowTypeError(ctx, "proxy: inconsistent prototype"); |
| 43049 | 43821 | } |
| 43822 | + JS_FreeValue(ctx, proto1); |
| 43050 | 43823 | } |
| 43051 | | − /* store the prototype in the proxy so that its refcount is at least 1 */ |
| 43052 | | − set_value(ctx, &s->proto, ret); |
| 43053 | | − return (JSValueConst)ret; |
| 43824 | + return ret; |
| 43054 | 43825 | } |
| 43055 | 43826 | |
| 43056 | 43827 | static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj, |
| 43057 | 43828 | JSValueConst proto_val, BOOL throw_flag) |
| 43058 | 43829 | { |
| 43059 | 43830 | JSProxyData *s; |
| 43060 | | − JSValue method, ret; |
| 43061 | | − JSValueConst args[2], proto1; |
| 43831 | + JSValue method, ret, proto1; |
| 43832 | + JSValueConst args[2]; |
| 43062 | 43833 | BOOL res; |
| 43063 | 43834 | int res2; |
| 43064 | 43835 | |
| @@ -43089,9 +43860,11 @@ static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj, · 24 unmodified lines |
| 43089 | 43860 | if (JS_IsException(proto1)) |
| 43090 | 43861 | return -1; |
| 43091 | 43862 | if (JS_VALUE_GET_OBJ(proto_val) != JS_VALUE_GET_OBJ(proto1)) { |
| 43863 | + JS_FreeValue(ctx, proto1); |
| 43092 | 43864 | JS_ThrowTypeError(ctx, "proxy: inconsistent prototype"); |
| 43093 | 43865 | return -1; |
| 43094 | 43866 | } |
| 43867 | + JS_FreeValue(ctx, proto1); |
| 43095 | 43868 | } |
| 43096 | 43869 | return TRUE; |
| 43097 | 43870 | } |
| @@ -43829,7 +44602,6 @@ static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val, · 731 unmodified lines |
| 43829 | 44602 | } |
| 43830 | 44603 | s->target = JS_DupValue(ctx, target); |
| 43831 | 44604 | s->handler = JS_DupValue(ctx, handler); |
| 43832 | | − s->proto = JS_NULL; |
| 43833 | 44605 | s->is_func = JS_IsFunction(ctx, target); |
| 43834 | 44606 | s->is_revoked = FALSE; |
| 43835 | 44607 | JS_SetOpaque(obj, s); |
| @@ -45414,10 +46186,10 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx, · 1578 unmodified lines |
| 45414 | 46186 | static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, |
| 45415 | 46187 | int argc, JSValueConst *argv, int magic) |
| 45416 | 46188 | { |
| 45417 | | − JSValue result_promise, resolving_funcs[2], iter, item, next_promise, ret; |
| 46189 | + JSValue result_promise, resolving_funcs[2], item, next_promise, ret; |
| 45418 | 46190 | JSValue next_method = JS_UNDEFINED, values = JS_UNDEFINED; |
| 45419 | 46191 | JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element; |
| 45420 | | − JSValue promise_resolve = JS_UNDEFINED; |
| 46192 | + JSValue promise_resolve = JS_UNDEFINED, iter = JS_UNDEFINED; |
| 45421 | 46193 | JSValueConst then_args[2], resolve_element_data[5]; |
| 45422 | 46194 | BOOL done; |
| 45423 | 46195 | int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any); |
| @@ -45427,6 +46199,10 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, · 3 unmodified lines |
| 45427 | 46199 | result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val); |
| 45428 | 46200 | if (JS_IsException(result_promise)) |
| 45429 | 46201 | return result_promise; |
| 46202 | + promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve); |
| 46203 | + if (JS_IsException(promise_resolve) || |
| 46204 | + check_function(ctx, promise_resolve)) |
| 46205 | + goto fail_reject; |
| 45430 | 46206 | iter = JS_GetIterator(ctx, argv[0], FALSE); |
| 45431 | 46207 | if (JS_IsException(iter)) { |
| 45432 | 46208 | JSValue error; |
| @@ -45454,11 +46230,6 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, · 21 unmodified lines |
| 45454 | 46230 | JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0) |
| 45455 | 46231 | goto fail_reject; |
| 45456 | 46232 | |
| 45457 | | − promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve); |
| 45458 | | − if (JS_IsException(promise_resolve) || |
| 45459 | | − check_function(ctx, promise_resolve)) |
| 45460 | | − goto fail_reject1; |
| 45461 | | − |
| 45462 | 46233 | index = 0; |
| 45463 | 46234 | for(;;) { |
| 45464 | 46235 | /* XXX: conformance: should close the iterator if error on 'done' |
| @@ -45560,8 +46331,8 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, · 95 unmodified lines |
| 45560 | 46331 | static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val, |
| 45561 | 46332 | int argc, JSValueConst *argv) |
| 45562 | 46333 | { |
| 45563 | | − JSValue result_promise, resolving_funcs[2], iter, item, next_promise, ret; |
| 45564 | | − JSValue next_method = JS_UNDEFINED; |
| 46334 | + JSValue result_promise, resolving_funcs[2], item, next_promise, ret; |
| 46335 | + JSValue next_method = JS_UNDEFINED, iter = JS_UNDEFINED; |
| 45565 | 46336 | JSValue promise_resolve = JS_UNDEFINED; |
| 45566 | 46337 | BOOL done; |
| 45567 | 46338 | |
| @@ -45570,6 +46341,10 @@ static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val, · 2 unmodified lines |
| 45570 | 46341 | result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val); |
| 45571 | 46342 | if (JS_IsException(result_promise)) |
| 45572 | 46343 | return result_promise; |
| 46344 | + promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve); |
| 46345 | + if (JS_IsException(promise_resolve) || |
| 46346 | + check_function(ctx, promise_resolve)) |
| 46347 | + goto fail_reject; |
| 45573 | 46348 | iter = JS_GetIterator(ctx, argv[0], FALSE); |
| 45574 | 46349 | if (JS_IsException(iter)) { |
| 45575 | 46350 | JSValue error; |
| @@ -45586,11 +46361,6 @@ static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val, · 10 unmodified lines |
| 45586 | 46361 | if (JS_IsException(next_method)) |
| 45587 | 46362 | goto fail_reject; |
| 45588 | 46363 | |
| 45589 | | − promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve); |
| 45590 | | − if (JS_IsException(promise_resolve) || |
| 45591 | | − check_function(ctx, promise_resolve)) |
| 45592 | | − goto fail_reject1; |
| 45593 | | − |
| 45594 | 46364 | for(;;) { |
| 45595 | 46365 | /* XXX: conformance: should close the iterator if error on 'done' |
| 45596 | 46366 | access, but not on 'value' access */ |
| @@ -49385,9 +50155,6 @@ static void JS_AddIntrinsicBasicObjects(JSContext *ctx) · 3788 unmodified lines |
| 49385 | 50155 | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); |
| 49386 | 50156 | ctx->native_error_proto[i] = proto; |
| 49387 | 50157 | } |
| 49388 | | − JS_SetPropertyFunctionList(ctx, ctx->native_error_proto[JS_AGGREGATE_ERROR], |
| 49389 | | − js_aggregate_error_proto_funcs, |
| 49390 | | − countof(js_aggregate_error_proto_funcs)); |
| 49391 | 50158 | |
| 49392 | 50159 | /* the array prototype is an array */ |
| 49393 | 50160 | ctx->class_proto[JS_CLASS_ARRAY] = |
| @@ -49621,6 +50388,7 @@ static JSValue js_array_buffer_constructor3(JSContext *ctx, · 227 unmodified lines |
| 49621 | 50388 | JSFreeArrayBufferDataFunc *free_func, |
| 49622 | 50389 | void *opaque, BOOL alloc_flag) |
| 49623 | 50390 | { |
| 50391 | + JSRuntime *rt = ctx->rt; |
| 49624 | 50392 | JSValue obj; |
| 49625 | 50393 | JSArrayBuffer *abuf = NULL; |
| 49626 | 50394 | |
| @@ -49637,11 +50405,24 @@ static JSValue js_array_buffer_constructor3(JSContext *ctx, · 10 unmodified lines |
| 49637 | 50405 | goto fail; |
| 49638 | 50406 | abuf->byte_length = len; |
| 49639 | 50407 | if (alloc_flag) { |
| 49640 | | − /* the allocation must be done after the object creation */ |
| 49641 | | − abuf->data = js_mallocz(ctx, max_int(len, 1)); |
| 49642 | | − if (!abuf->data) |
| 49643 | | − goto fail; |
| 50408 | + if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER && |
| 50409 | + rt->sab_funcs.sab_alloc) { |
| 50410 | + abuf->data = rt->sab_funcs.sab_alloc(rt->sab_funcs.sab_opaque, |
| 50411 | + max_int(len, 1)); |
| 50412 | + if (!abuf->data) |
| 50413 | + goto fail; |
| 50414 | + memset(abuf->data, 0, len); |
| 50415 | + } else { |
| 50416 | + /* the allocation must be done after the object creation */ |
| 50417 | + abuf->data = js_mallocz(ctx, max_int(len, 1)); |
| 50418 | + if (!abuf->data) |
| 50419 | + goto fail; |
| 50420 | + } |
| 49644 | 50421 | } else { |
| 50422 | + if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER && |
| 50423 | + rt->sab_funcs.sab_dup) { |
| 50424 | + rt->sab_funcs.sab_dup(rt->sab_funcs.sab_opaque, buf); |
| 50425 | + } |
| 49645 | 50426 | abuf->data = buf; |
| 49646 | 50427 | } |
| 49647 | 50428 | init_list_head(&abuf->array_list); |
| @@ -49731,8 +50512,12 @@ static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val) · 83 unmodified lines |
| 49731 | 50512 | array finalizers using it, so abuf->array_list is not |
| 49732 | 50513 | necessarily empty. */ |
| 49733 | 50514 | // assert(list_empty(&abuf->array_list)); |
| 49734 | | − if (abuf->free_func) |
| 49735 | | − abuf->free_func(rt, abuf->opaque, abuf->data); |
| 50515 | + if (abuf->shared && rt->sab_funcs.sab_free) { |
| 50516 | + rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data); |
| 50517 | + } else { |
| 50518 | + if (abuf->free_func) |
| 50519 | + abuf->free_func(rt, abuf->opaque, abuf->data); |
| 50520 | + } |
| 49736 | 50521 | js_free_rt(rt, abuf); |
| 49737 | 50522 | } |
| 49738 | 50523 | } |
| @@ -50208,11 +50993,6 @@ static JSValue js_typed_array___getLength(JSContext *ctx, · 469 unmodified lines |
| 50208 | 50993 | } |
| 50209 | 50994 | #endif |
| 50210 | 50995 | |
| 50211 | | −static JSValue js_typed_array_constructor(JSContext *ctx, |
| 50212 | | − JSValueConst this_val, |
| 50213 | | − int argc, JSValueConst *argv, |
| 50214 | | − int classid); |
| 50215 | | − |
| 50216 | 50996 | static JSValue js_typed_array_create(JSContext *ctx, JSValueConst ctor, |
| 50217 | 50997 | int argc, JSValueConst *argv) |
| 50218 | 50998 | { |
| @@ -51967,9 +52747,10 @@ typedef enum AtomicsOpEnum { · 1748 unmodified lines |
| 51967 | 52747 | } AtomicsOpEnum; |
| 51968 | 52748 | |
| 51969 | 52749 | static void *js_atomics_get_ptr(JSContext *ctx, |
| 52750 | + JSArrayBuffer **pabuf, |
| 51970 | 52751 | int *psize_log2, JSClassID *pclass_id, |
| 51971 | 52752 | JSValueConst obj, JSValueConst idx_val, |
| 51972 | | − BOOL is_waitable) |
| 52753 | + int is_waitable) |
| 51973 | 52754 | { |
| 51974 | 52755 | JSObject *p; |
| 51975 | 52756 | JSTypedArray *ta; |
| @@ -52004,18 +52785,27 @@ static void *js_atomics_get_ptr(JSContext *ctx, · 28 unmodified lines |
| 52004 | 52785 | ta = p->u.typed_array; |
| 52005 | 52786 | abuf = ta->buffer->u.array_buffer; |
| 52006 | 52787 | if (!abuf->shared) { |
| 52007 | | − JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray"); |
| 52008 | | − return NULL; |
| 52788 | + if (is_waitable == 2) { |
| 52789 | + JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray"); |
| 52790 | + return NULL; |
| 52791 | + } |
| 52792 | + if (abuf->detached) { |
| 52793 | + JS_ThrowTypeErrorDetachedArrayBuffer(ctx); |
| 52794 | + return NULL; |
| 52795 | + } |
| 52009 | 52796 | } |
| 52010 | 52797 | if (JS_ToIndex(ctx, &idx, idx_val)) { |
| 52011 | 52798 | return NULL; |
| 52012 | 52799 | } |
| 52800 | + /* if the array buffer is detached, p->u.array.count = 0 */ |
| 52013 | 52801 | if (idx >= p->u.array.count) { |
| 52014 | 52802 | JS_ThrowRangeError(ctx, "out-of-bound access"); |
| 52015 | 52803 | return NULL; |
| 52016 | 52804 | } |
| 52017 | 52805 | size_log2 = typed_array_size_log2(p->class_id); |
| 52018 | 52806 | ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2); |
| 52807 | + if (pabuf) |
| 52808 | + *pabuf = abuf; |
| 52019 | 52809 | if (psize_log2) |
| 52020 | 52810 | *psize_log2 = size_log2; |
| 52021 | 52811 | if (pclass_id) |
| @@ -52036,17 +52826,18 @@ static JSValue js_atomics_op(JSContext *ctx, · 14 unmodified lines |
| 52036 | 52826 | void *ptr; |
| 52037 | 52827 | JSValue ret; |
| 52038 | 52828 | JSClassID class_id; |
| 52829 | + JSArrayBuffer *abuf; |
| 52039 | 52830 | |
| 52040 | | − ptr = js_atomics_get_ptr(ctx, &size_log2, &class_id, |
| 52041 | | − argv[0], argv[1], FALSE); |
| 52831 | + ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, &class_id, |
| 52832 | + argv[0], argv[1], 0); |
| 52042 | 52833 | if (!ptr) |
| 52043 | 52834 | return JS_EXCEPTION; |
| 52044 | 52835 | rep_val = 0; |
| 52045 | 52836 | if (op == ATOMICS_OP_LOAD) { |
| 52046 | 52837 | v = 0; |
| 52047 | | − } else |
| 52838 | + } else { |
| 52048 | 52839 | #ifdef CONFIG_BIGNUM |
| 52049 | | − if (size_log2 == 3) { |
| 52840 | + if (size_log2 == 3) { |
| 52050 | 52841 | int64_t v64; |
| 52051 | 52842 | if (JS_ToBigInt64(ctx, &v64, argv[2])) |
| 52052 | 52843 | return JS_EXCEPTION; |
| @@ -52056,19 +52847,23 @@ static JSValue js_atomics_op(JSContext *ctx, · 3 unmodified lines |
| 52056 | 52847 | return JS_EXCEPTION; |
| 52057 | 52848 | rep_val = v64; |
| 52058 | 52849 | } |
| 52059 | | − } else |
| 52850 | + } else |
| 52060 | 52851 | #endif |
| 52061 | | − { |
| 52062 | | − uint32_t v32; |
| 52063 | | − if (JS_ToUint32(ctx, &v32, argv[2])) |
| 52064 | | − return JS_EXCEPTION; |
| 52065 | | − v = v32; |
| 52066 | | − if (op == ATOMICS_OP_COMPARE_EXCHANGE) { |
| 52067 | | − if (JS_ToUint32(ctx, &v32, argv[3])) |
| 52068 | | − return JS_EXCEPTION; |
| 52069 | | − rep_val = v32; |
| 52070 | | − } |
| 52852 | + { |
| 52853 | + uint32_t v32; |
| 52854 | + if (JS_ToUint32(ctx, &v32, argv[2])) |
| 52855 | + return JS_EXCEPTION; |
| 52856 | + v = v32; |
| 52857 | + if (op == ATOMICS_OP_COMPARE_EXCHANGE) { |
| 52858 | + if (JS_ToUint32(ctx, &v32, argv[3])) |
| 52859 | + return JS_EXCEPTION; |
| 52860 | + rep_val = v32; |
| 52861 | + } |
| 52862 | + } |
| 52863 | + if (abuf->detached) |
| 52864 | + return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); |
| 52071 | 52865 | } |
| 52866 | + |
| 52072 | 52867 | switch(op | (size_log2 << 3)) { |
| 52073 | 52868 | |
| 52074 | 52869 | #ifdef CONFIG_BIGNUM |
| @@ -52195,8 +52990,10 @@ static JSValue js_atomics_store(JSContext *ctx, · 120 unmodified lines |
| 52195 | 52990 | int size_log2; |
| 52196 | 52991 | void *ptr; |
| 52197 | 52992 | JSValue ret; |
| 52993 | + JSArrayBuffer *abuf; |
| 52198 | 52994 | |
| 52199 | | − ptr = js_atomics_get_ptr(ctx, &size_log2, NULL, argv[0], argv[1], FALSE); |
| 52995 | + ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, NULL, |
| 52996 | + argv[0], argv[1], 0); |
| 52200 | 52997 | if (!ptr) |
| 52201 | 52998 | return JS_EXCEPTION; |
| 52202 | 52999 | #ifdef CONFIG_BIGNUM |
| @@ -52209,6 +53006,8 @@ static JSValue js_atomics_store(JSContext *ctx, · 6 unmodified lines |
| 52209 | 53006 | JS_FreeValue(ctx, ret); |
| 52210 | 53007 | return JS_EXCEPTION; |
| 52211 | 53008 | } |
| 53009 | + if (abuf->detached) |
| 53010 | + return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); |
| 52212 | 53011 | atomic_store((_Atomic(uint64_t) *)ptr, v64); |
| 52213 | 53012 | } else |
| 52214 | 53013 | #endif |
| @@ -52222,6 +53021,8 @@ static JSValue js_atomics_store(JSContext *ctx, · 7 unmodified lines |
| 52222 | 53021 | JS_FreeValue(ctx, ret); |
| 52223 | 53022 | return JS_EXCEPTION; |
| 52224 | 53023 | } |
| 53024 | + if (abuf->detached) |
| 53025 | + return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); |
| 52225 | 53026 | switch(size_log2) { |
| 52226 | 53027 | case 0: |
| 52227 | 53028 | atomic_store((_Atomic(uint8_t) *)ptr, v); |
| @@ -52278,7 +53079,8 @@ static JSValue js_atomics_wait(JSContext *ctx, · 50 unmodified lines |
| 52278 | 53079 | int ret, size_log2, res; |
| 52279 | 53080 | double d; |
| 52280 | 53081 | |
| 52281 | | − ptr = js_atomics_get_ptr(ctx, &size_log2, NULL, argv[0], argv[1], TRUE); |
| 53082 | + ptr = js_atomics_get_ptr(ctx, NULL, &size_log2, NULL, |
| 53083 | + argv[0], argv[1], 2); |
| 52282 | 53084 | if (!ptr) |
| 52283 | 53085 | return JS_EXCEPTION; |
| 52284 | 53086 | #ifdef CONFIG_BIGNUM |
| @@ -52357,8 +53159,9 @@ static JSValue js_atomics_notify(JSContext *ctx, · 72 unmodified lines |
| 52357 | 53159 | int32_t count, n; |
| 52358 | 53160 | void *ptr; |
| 52359 | 53161 | JSAtomicsWaiter *waiter; |
| 53162 | + JSArrayBuffer *abuf; |
| 52360 | 53163 | |
| 52361 | | − ptr = js_atomics_get_ptr(ctx, NULL, NULL, argv[0], argv[1], TRUE); |
| 53164 | + ptr = js_atomics_get_ptr(ctx, &abuf, NULL, NULL, argv[0], argv[1], 1); |
| 52362 | 53165 | if (!ptr) |
| 52363 | 53166 | return JS_EXCEPTION; |
| 52364 | 53167 | |
| @@ -52368,9 +53171,11 @@ static JSValue js_atomics_notify(JSContext *ctx, · 3 unmodified lines |
| 52368 | 53171 | if (JS_ToInt32Clamp(ctx, &count, argv[2], 0, INT32_MAX, 0)) |
| 52369 | 53172 | return JS_EXCEPTION; |
| 52370 | 53173 | } |
| 53174 | + if (abuf->detached) |
| 53175 | + return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); |
| 52371 | 53176 | |
| 52372 | 53177 | n = 0; |
| 52373 | | − if (count > 0) { |
| 53178 | + if (abuf->shared && count > 0) { |
| 52374 | 53179 | pthread_mutex_lock(&js_atomics_mutex); |
| 52375 | 53180 | init_list_head(&waiter_list); |
| 52376 | 53181 | list_for_each_safe(el, el1, &js_atomics_waiter_list) { |