@mikrojs/quickjs 0.8.0-pr-115.g87a99f9 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deps/quickjs/api-test.c +127 -18
- package/deps/quickjs/builtin-array-fromasync.h +72 -72
- package/deps/quickjs/builtin-iterator-zip-keyed.h +233 -233
- package/deps/quickjs/builtin-iterator-zip.h +236 -236
- package/deps/quickjs/quickjs-atom.h +12 -0
- package/deps/quickjs/quickjs-libc.c +1 -1
- package/deps/quickjs/quickjs-opcode.h +9 -1
- package/deps/quickjs/quickjs.c +2705 -196
- package/deps/quickjs/quickjs.h +21 -38
- package/package.json +1 -1
package/deps/quickjs/quickjs.c
CHANGED
|
@@ -176,6 +176,7 @@ enum {
|
|
|
176
176
|
JS_CLASS_STRING_ITERATOR, /* u.array_iterator_data */
|
|
177
177
|
JS_CLASS_REGEXP_STRING_ITERATOR, /* u.regexp_string_iterator_data */
|
|
178
178
|
JS_CLASS_GENERATOR, /* u.generator_data */
|
|
179
|
+
JS_CLASS_DISPOSABLE_STACK,
|
|
179
180
|
JS_CLASS_PROXY, /* u.proxy_data */
|
|
180
181
|
JS_CLASS_PROMISE, /* u.promise_data */
|
|
181
182
|
JS_CLASS_PROMISE_RESOLVE_FUNCTION, /* u.promise_function_data */
|
|
@@ -186,6 +187,7 @@ enum {
|
|
|
186
187
|
JS_CLASS_ASYNC_FROM_SYNC_ITERATOR, /* u.async_from_sync_iterator_data */
|
|
187
188
|
JS_CLASS_ASYNC_GENERATOR_FUNCTION, /* u.func */
|
|
188
189
|
JS_CLASS_ASYNC_GENERATOR, /* u.async_generator_data */
|
|
190
|
+
JS_CLASS_ASYNC_DISPOSABLE_STACK,
|
|
189
191
|
JS_CLASS_WEAK_REF,
|
|
190
192
|
JS_CLASS_FINALIZATION_REGISTRY,
|
|
191
193
|
JS_CLASS_DOM_EXCEPTION,
|
|
@@ -209,6 +211,7 @@ typedef enum JSErrorEnum {
|
|
|
209
211
|
JS_URI_ERROR,
|
|
210
212
|
JS_INTERNAL_ERROR,
|
|
211
213
|
JS_AGGREGATE_ERROR,
|
|
214
|
+
JS_SUPPRESSED_ERROR,
|
|
212
215
|
|
|
213
216
|
JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */
|
|
214
217
|
JS_PLAIN_ERROR = JS_NATIVE_ERROR_COUNT
|
|
@@ -702,6 +705,10 @@ typedef struct JSClosureVar {
|
|
|
702
705
|
typedef struct JSVarScope {
|
|
703
706
|
int parent; /* index into fd->scopes of the enclosing scope */
|
|
704
707
|
int first; /* index into fd->vars of the last variable in this scope */
|
|
708
|
+
uint8_t has_using : 1; /* scope has using declarations */
|
|
709
|
+
uint8_t is_await_using : 1; /* scope has await using declarations */
|
|
710
|
+
int using_label_catch; /* label for catch handler (-1 if none) */
|
|
711
|
+
int using_label_end; /* label for end of disposal block (-1 if none) */
|
|
705
712
|
} JSVarScope;
|
|
706
713
|
|
|
707
714
|
typedef enum {
|
|
@@ -717,6 +724,10 @@ typedef enum {
|
|
|
717
724
|
JS_VAR_PRIVATE_GETTER,
|
|
718
725
|
JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */
|
|
719
726
|
JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */
|
|
727
|
+
JS_VAR_USING, /* using declaration variable */
|
|
728
|
+
JS_VAR_USING_METHOD, /* hidden local holding the cached dispose method
|
|
729
|
+
for the preceding JS_VAR_USING var (always
|
|
730
|
+
allocated immediately after it). */
|
|
720
731
|
} JSVarKindEnum;
|
|
721
732
|
|
|
722
733
|
/* XXX: could use a different structure in bytecode functions to save
|
|
@@ -1135,7 +1146,7 @@ enum {
|
|
|
1135
1146
|
#undef DEF
|
|
1136
1147
|
JS_ATOM_END,
|
|
1137
1148
|
};
|
|
1138
|
-
#define JS_ATOM_LAST_KEYWORD
|
|
1149
|
+
#define JS_ATOM_LAST_KEYWORD JS_ATOM_using
|
|
1139
1150
|
#define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield
|
|
1140
1151
|
|
|
1141
1152
|
static const char js_atom_init[] =
|
|
@@ -1200,6 +1211,8 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
|
|
|
1200
1211
|
JSValue val, bool is_array_ctor);
|
|
1201
1212
|
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
|
|
1202
1213
|
JSValueConst val, int flags, int scope_idx);
|
|
1214
|
+
static JSValue js_new_suppressed_error(JSContext *ctx, JSValueConst error,
|
|
1215
|
+
JSValueConst suppressed);
|
|
1203
1216
|
static __maybe_unused void JS_DumpString(JSRuntime *rt, JSString *p);
|
|
1204
1217
|
static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
|
|
1205
1218
|
static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
|
|
@@ -1270,6 +1283,9 @@ static void js_promise_mark(JSRuntime *rt, JSValueConst val,
|
|
|
1270
1283
|
static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValueConst val);
|
|
1271
1284
|
static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
|
|
1272
1285
|
JS_MarkFunc *mark_func);
|
|
1286
|
+
static void js_disposable_stack_finalizer(JSRuntime *rt, JSValueConst val);
|
|
1287
|
+
static void js_disposable_stack_mark(JSRuntime *rt, JSValueConst val,
|
|
1288
|
+
JS_MarkFunc *mark_func);
|
|
1273
1289
|
|
|
1274
1290
|
#define HINT_STRING 0
|
|
1275
1291
|
#define HINT_NUMBER 1
|
|
@@ -1529,6 +1545,12 @@ static JSValue js_number(double d)
|
|
|
1529
1545
|
return js_float64(d);
|
|
1530
1546
|
}
|
|
1531
1547
|
|
|
1548
|
+
static JSValue __JS_NewShortBigInt(JSContext *ctx, int32_t d)
|
|
1549
|
+
{
|
|
1550
|
+
(void)&ctx;
|
|
1551
|
+
return JS_MKVAL(JS_TAG_SHORT_BIG_INT, d);
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1532
1554
|
JSValue JS_NewNumber(JSContext *ctx, double d)
|
|
1533
1555
|
{
|
|
1534
1556
|
return js_number(d);
|
|
@@ -1888,6 +1910,7 @@ static JSClassShortDef const js_std_class_def[] = {
|
|
|
1888
1910
|
{ JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */
|
|
1889
1911
|
{ JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */
|
|
1890
1912
|
{ JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */
|
|
1913
|
+
{ JS_ATOM_DisposableStack, js_disposable_stack_finalizer, js_disposable_stack_mark }, /* JS_CLASS_DISPOSABLE_STACK */
|
|
1891
1914
|
};
|
|
1892
1915
|
|
|
1893
1916
|
static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab,
|
|
@@ -2265,6 +2288,7 @@ void JS_SetRuntimeInfo(JSRuntime *rt, const char *s)
|
|
|
2265
2288
|
void JS_FreeRuntime(JSRuntime *rt)
|
|
2266
2289
|
{
|
|
2267
2290
|
struct list_head *el, *el1;
|
|
2291
|
+
bool leak = false;
|
|
2268
2292
|
int i;
|
|
2269
2293
|
|
|
2270
2294
|
rt->in_free = true;
|
|
@@ -2305,6 +2329,7 @@ void JS_FreeRuntime(JSRuntime *rt)
|
|
|
2305
2329
|
header_done = true;
|
|
2306
2330
|
}
|
|
2307
2331
|
JS_DumpGCObject(rt, p);
|
|
2332
|
+
leak = true;
|
|
2308
2333
|
}
|
|
2309
2334
|
}
|
|
2310
2335
|
|
|
@@ -2381,6 +2406,7 @@ void JS_FreeRuntime(JSRuntime *rt)
|
|
|
2381
2406
|
} else {
|
|
2382
2407
|
printf("\n");
|
|
2383
2408
|
}
|
|
2409
|
+
leak = true;
|
|
2384
2410
|
}
|
|
2385
2411
|
}
|
|
2386
2412
|
}
|
|
@@ -2429,6 +2455,7 @@ void JS_FreeRuntime(JSRuntime *rt)
|
|
|
2429
2455
|
}
|
|
2430
2456
|
if (rt->rt_info)
|
|
2431
2457
|
printf("\n");
|
|
2458
|
+
leak = true;
|
|
2432
2459
|
}
|
|
2433
2460
|
#endif
|
|
2434
2461
|
|
|
@@ -2448,14 +2475,20 @@ void JS_FreeRuntime(JSRuntime *rt)
|
|
|
2448
2475
|
printf("Memory leak: %zd bytes lost in %zd block%s\n",
|
|
2449
2476
|
s->malloc_size - sizeof(JSRuntime),
|
|
2450
2477
|
s->malloc_count - 1, &"s"[s->malloc_count == 2]);
|
|
2478
|
+
leak = true;
|
|
2451
2479
|
}
|
|
2452
2480
|
}
|
|
2453
2481
|
#endif
|
|
2454
2482
|
|
|
2483
|
+
leak &= check_dump_flag(rt, JS_ABORT_ON_LEAKS);
|
|
2484
|
+
|
|
2455
2485
|
{
|
|
2456
2486
|
JSMallocState *ms = &rt->malloc_state;
|
|
2457
2487
|
rt->mf.js_free(ms->opaque, rt);
|
|
2458
2488
|
}
|
|
2489
|
+
|
|
2490
|
+
if (leak)
|
|
2491
|
+
abort();
|
|
2459
2492
|
}
|
|
2460
2493
|
|
|
2461
2494
|
JSContext *JS_NewContextRaw(JSRuntime *rt)
|
|
@@ -2500,7 +2533,6 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
|
|
|
2500
2533
|
JSContext *JS_NewContext(JSRuntime *rt)
|
|
2501
2534
|
{
|
|
2502
2535
|
JSContext *ctx;
|
|
2503
|
-
|
|
2504
2536
|
ctx = JS_NewContextRaw(rt);
|
|
2505
2537
|
if (!ctx)
|
|
2506
2538
|
return NULL;
|
|
@@ -2515,7 +2547,7 @@ JSContext *JS_NewContext(JSRuntime *rt)
|
|
|
2515
2547
|
JS_AddIntrinsicTypedArrays(ctx) ||
|
|
2516
2548
|
JS_AddIntrinsicPromise(ctx) ||
|
|
2517
2549
|
JS_AddIntrinsicWeakRef(ctx) ||
|
|
2518
|
-
|
|
2550
|
+
JS_AddIntrinsicAToB(ctx) ||
|
|
2519
2551
|
JS_AddPerformance(ctx)) {
|
|
2520
2552
|
JS_FreeContext(ctx);
|
|
2521
2553
|
return NULL;
|
|
@@ -3404,10 +3436,23 @@ static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,
|
|
|
3404
3436
|
/* `description` may be pure ASCII or UTF-8 encoded */
|
|
3405
3437
|
JSValue JS_NewSymbol(JSContext *ctx, const char *description, bool is_global)
|
|
3406
3438
|
{
|
|
3439
|
+
if (description == NULL) {
|
|
3440
|
+
if (!is_global) {
|
|
3441
|
+
/* Local symbol without description: Symbol() */
|
|
3442
|
+
return JS_NewSymbolInternal(ctx, NULL, JS_ATOM_TYPE_SYMBOL);
|
|
3443
|
+
}
|
|
3444
|
+
/* Global symbol without description: Symbol.for()
|
|
3445
|
+
Per ES spec, ToString(undefined) becomes "undefined" */
|
|
3446
|
+
description = "undefined";
|
|
3447
|
+
}
|
|
3407
3448
|
JSAtom atom = JS_NewAtom(ctx, description);
|
|
3408
3449
|
if (atom == JS_ATOM_NULL)
|
|
3409
3450
|
return JS_EXCEPTION;
|
|
3410
|
-
|
|
3451
|
+
int atom_type =
|
|
3452
|
+
is_global ? JS_ATOM_TYPE_GLOBAL_SYMBOL : JS_ATOM_TYPE_SYMBOL;
|
|
3453
|
+
JSValue symbol = JS_NewSymbolFromAtom(ctx, atom, atom_type);
|
|
3454
|
+
JS_FreeAtom(ctx, atom);
|
|
3455
|
+
return symbol;
|
|
3411
3456
|
}
|
|
3412
3457
|
|
|
3413
3458
|
#define ATOM_GET_STR_BUF_SIZE 64
|
|
@@ -4329,18 +4374,18 @@ JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)
|
|
|
4329
4374
|
size_t len;
|
|
4330
4375
|
int kind;
|
|
4331
4376
|
|
|
4332
|
-
if (buf_len <= 0)
|
|
4377
|
+
if (unlikely(buf_len <= 0))
|
|
4333
4378
|
return js_empty_string(ctx->rt);
|
|
4334
|
-
|
|
4379
|
+
|
|
4335
4380
|
/* Compute string kind and length: 7-bit, 8-bit, 16-bit, 16-bit UTF-16 */
|
|
4336
4381
|
kind = utf8_scan(buf, buf_len, &len);
|
|
4337
|
-
if (len > JS_STRING_LEN_MAX)
|
|
4382
|
+
if (unlikely(len > JS_STRING_LEN_MAX))
|
|
4338
4383
|
return JS_ThrowRangeError(ctx, "invalid string length");
|
|
4339
4384
|
|
|
4340
4385
|
switch (kind) {
|
|
4341
4386
|
case UTF8_PLAIN_ASCII:
|
|
4342
4387
|
str = js_alloc_string(ctx, len, 0);
|
|
4343
|
-
if (!str)
|
|
4388
|
+
if (unlikely(!str))
|
|
4344
4389
|
return JS_EXCEPTION;
|
|
4345
4390
|
memcpy(str8(str), buf, len);
|
|
4346
4391
|
str8(str)[len] = '\0';
|
|
@@ -4348,7 +4393,7 @@ JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)
|
|
|
4348
4393
|
case UTF8_NON_ASCII:
|
|
4349
4394
|
/* buf contains non-ASCII code-points, but limited to 8-bit values */
|
|
4350
4395
|
str = js_alloc_string(ctx, len, 0);
|
|
4351
|
-
if (!str)
|
|
4396
|
+
if (unlikely(!str))
|
|
4352
4397
|
return JS_EXCEPTION;
|
|
4353
4398
|
utf8_decode_buf8(str8(str), len + 1, buf, buf_len);
|
|
4354
4399
|
break;
|
|
@@ -4357,7 +4402,7 @@ JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)
|
|
|
4357
4402
|
//if (kind & UTF8_HAS_ERRORS)
|
|
4358
4403
|
// return JS_ThrowRangeError(ctx, "invalid UTF-8 sequence");
|
|
4359
4404
|
str = js_alloc_string(ctx, len, 1);
|
|
4360
|
-
if (!str)
|
|
4405
|
+
if (unlikely(!str))
|
|
4361
4406
|
return JS_EXCEPTION;
|
|
4362
4407
|
utf8_decode_buf16(str16(str), len, buf, buf_len);
|
|
4363
4408
|
break;
|
|
@@ -4369,10 +4414,13 @@ JSValue JS_NewStringUTF16(JSContext *ctx, const uint16_t *buf, size_t len)
|
|
|
4369
4414
|
{
|
|
4370
4415
|
JSString *str;
|
|
4371
4416
|
|
|
4372
|
-
if (!len)
|
|
4417
|
+
if (unlikely(!len))
|
|
4373
4418
|
return js_empty_string(ctx->rt);
|
|
4419
|
+
if (unlikely(len > JS_STRING_LEN_MAX))
|
|
4420
|
+
return JS_ThrowRangeError(ctx, "invalid string length");
|
|
4421
|
+
|
|
4374
4422
|
str = js_alloc_string(ctx, len, 1);
|
|
4375
|
-
if (!str)
|
|
4423
|
+
if (unlikely(!str))
|
|
4376
4424
|
return JS_EXCEPTION;
|
|
4377
4425
|
memcpy(str16(str), buf, len * sizeof(*buf));
|
|
4378
4426
|
return JS_MKPTR(JS_TAG_STRING, str);
|
|
@@ -6460,7 +6508,7 @@ static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref)
|
|
|
6460
6508
|
static void js_array_finalizer(JSRuntime *rt, JSValueConst val)
|
|
6461
6509
|
{
|
|
6462
6510
|
JSObject *p = JS_VALUE_GET_OBJ(val);
|
|
6463
|
-
|
|
6511
|
+
uint32_t i;
|
|
6464
6512
|
|
|
6465
6513
|
for(i = 0; i < p->u.array.count; i++) {
|
|
6466
6514
|
JS_FreeValueRT(rt, p->u.array.u.values[i]);
|
|
@@ -6472,7 +6520,7 @@ static void js_array_mark(JSRuntime *rt, JSValueConst val,
|
|
|
6472
6520
|
JS_MarkFunc *mark_func)
|
|
6473
6521
|
{
|
|
6474
6522
|
JSObject *p = JS_VALUE_GET_OBJ(val);
|
|
6475
|
-
|
|
6523
|
+
uint32_t i;
|
|
6476
6524
|
|
|
6477
6525
|
for(i = 0; i < p->u.array.count; i++) {
|
|
6478
6526
|
JS_MarkValue(rt, p->u.array.u.values[i], mark_func);
|
|
@@ -7720,7 +7768,7 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_val,
|
|
|
7720
7768
|
int line_num, int col_num, int backtrace_flags)
|
|
7721
7769
|
{
|
|
7722
7770
|
JSStackFrame *sf, *sf_start;
|
|
7723
|
-
JSValue stack, prepare, saved_exception;
|
|
7771
|
+
JSValue stack, prepare, saved_exception, error_obj;
|
|
7724
7772
|
DynBuf dbuf;
|
|
7725
7773
|
const char *func_name_str;
|
|
7726
7774
|
const char *str1;
|
|
@@ -7737,6 +7785,7 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_val,
|
|
|
7737
7785
|
if (rt->in_build_stack_trace)
|
|
7738
7786
|
return;
|
|
7739
7787
|
rt->in_build_stack_trace = true;
|
|
7788
|
+
error_obj = js_dup(error_val);
|
|
7740
7789
|
|
|
7741
7790
|
// Save exception because conversion to double may fail.
|
|
7742
7791
|
saved_exception = JS_GetException(ctx);
|
|
@@ -7882,7 +7931,7 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_val,
|
|
|
7882
7931
|
JS_FreeValue(ctx, csd[k].func_name);
|
|
7883
7932
|
}
|
|
7884
7933
|
JSValueConst args[] = {
|
|
7885
|
-
|
|
7934
|
+
error_obj,
|
|
7886
7935
|
stack,
|
|
7887
7936
|
};
|
|
7888
7937
|
JSValue stack2 = JS_Call(ctx, prepare, ctx->error_ctor, countof(args), args);
|
|
@@ -7903,13 +7952,14 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_val,
|
|
|
7903
7952
|
|
|
7904
7953
|
if (JS_IsUndefined(ctx->error_back_trace))
|
|
7905
7954
|
ctx->error_back_trace = js_dup(stack);
|
|
7906
|
-
if (has_filter_func || can_add_backtrace(
|
|
7907
|
-
JS_DefinePropertyValue(ctx,
|
|
7955
|
+
if (has_filter_func || can_add_backtrace(error_obj)) {
|
|
7956
|
+
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, stack,
|
|
7908
7957
|
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
7909
7958
|
} else {
|
|
7910
7959
|
JS_FreeValue(ctx, stack);
|
|
7911
7960
|
}
|
|
7912
7961
|
|
|
7962
|
+
JS_FreeValue(ctx, error_obj);
|
|
7913
7963
|
rt->in_build_stack_trace = false;
|
|
7914
7964
|
}
|
|
7915
7965
|
|
|
@@ -9878,6 +9928,7 @@ static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
|
|
|
9878
9928
|
if (len < old_len) {
|
|
9879
9929
|
for(i = len; i < old_len; i++) {
|
|
9880
9930
|
JS_FreeValue(ctx, p->u.array.u.values[i]);
|
|
9931
|
+
p->u.array.u.values[i] = JS_UNDEFINED;
|
|
9881
9932
|
}
|
|
9882
9933
|
p->u.array.count = len;
|
|
9883
9934
|
}
|
|
@@ -9956,13 +10007,18 @@ static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len)
|
|
|
9956
10007
|
size_t slack;
|
|
9957
10008
|
JSValue *new_array_prop;
|
|
9958
10009
|
|
|
10010
|
+
if (unlikely(new_len > (uint32_t)INT32_MAX)) {
|
|
10011
|
+
JS_ThrowOutOfMemory(ctx);
|
|
10012
|
+
return -1;
|
|
10013
|
+
}
|
|
10014
|
+
|
|
9959
10015
|
old_size = p->u.array.u1.size;
|
|
9960
|
-
new_size = old_size + old_size/2;
|
|
9961
|
-
if (new_size < old_size) {
|
|
10016
|
+
new_size = old_size + old_size/2;
|
|
10017
|
+
if (new_size < old_size) {
|
|
9962
10018
|
JS_ThrowOutOfMemory(ctx);
|
|
9963
10019
|
return -1;
|
|
9964
10020
|
}
|
|
9965
|
-
new_size =
|
|
10021
|
+
new_size = max_uint32(new_len, new_size);
|
|
9966
10022
|
new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack);
|
|
9967
10023
|
if (!new_array_prop)
|
|
9968
10024
|
return -1;
|
|
@@ -10004,6 +10060,35 @@ static int add_fast_array_element(JSContext *ctx, JSObject *p,
|
|
|
10004
10060
|
return true;
|
|
10005
10061
|
}
|
|
10006
10062
|
|
|
10063
|
+
/* Allocate a new fast array initialized to JS_UNDEFINED. Its maximum
|
|
10064
|
+
size is 2^31-1 elements. For convenience, 'len' is a 64 bit
|
|
10065
|
+
integer. */
|
|
10066
|
+
static JSValue js_allocate_fast_array(JSContext *ctx, int64_t len)
|
|
10067
|
+
{
|
|
10068
|
+
JSValue arr;
|
|
10069
|
+
JSObject *p;
|
|
10070
|
+
int i;
|
|
10071
|
+
|
|
10072
|
+
if (len > INT32_MAX)
|
|
10073
|
+
return JS_ThrowRangeError(ctx, "invalid array length");
|
|
10074
|
+
arr = JS_NewArray(ctx);
|
|
10075
|
+
if (JS_IsException(arr))
|
|
10076
|
+
return arr;
|
|
10077
|
+
if (len > 0) {
|
|
10078
|
+
p = JS_VALUE_GET_OBJ(arr);
|
|
10079
|
+
if (expand_fast_array(ctx, p, len) < 0) {
|
|
10080
|
+
JS_FreeValue(ctx, arr);
|
|
10081
|
+
return JS_EXCEPTION;
|
|
10082
|
+
}
|
|
10083
|
+
p->u.array.count = len;
|
|
10084
|
+
for(i = 0; i < len; i++)
|
|
10085
|
+
p->u.array.u.values[i] = JS_UNDEFINED;
|
|
10086
|
+
/* update the 'length' field */
|
|
10087
|
+
set_value(ctx, &p->prop[0].u.value, js_int32(len));
|
|
10088
|
+
}
|
|
10089
|
+
return arr;
|
|
10090
|
+
}
|
|
10091
|
+
|
|
10007
10092
|
static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
|
|
10008
10093
|
{
|
|
10009
10094
|
JS_FreeValue(ctx, desc->getter);
|
|
@@ -10198,12 +10283,11 @@ retry:
|
|
|
10198
10283
|
goto done;
|
|
10199
10284
|
}
|
|
10200
10285
|
|
|
10201
|
-
if (unlikely(!p->extensible)) {
|
|
10202
|
-
ret = JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
|
|
10203
|
-
goto done;
|
|
10204
|
-
}
|
|
10205
|
-
|
|
10206
10286
|
if (p == JS_VALUE_GET_OBJ(obj)) {
|
|
10287
|
+
if (unlikely(!p->extensible)) {
|
|
10288
|
+
ret = JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
|
|
10289
|
+
goto done;
|
|
10290
|
+
}
|
|
10207
10291
|
if (p->is_exotic) {
|
|
10208
10292
|
if (p->class_id == JS_CLASS_ARRAY && p->fast_array &&
|
|
10209
10293
|
__JS_AtomIsTaggedInt(prop)) {
|
|
@@ -10244,6 +10328,10 @@ retry:
|
|
|
10244
10328
|
JS_UNDEFINED, JS_UNDEFINED,
|
|
10245
10329
|
JS_PROP_HAS_VALUE);
|
|
10246
10330
|
} else {
|
|
10331
|
+
if (unlikely(!p->extensible)) {
|
|
10332
|
+
ret = JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
|
|
10333
|
+
goto done;
|
|
10334
|
+
}
|
|
10247
10335
|
generic_create_prop:
|
|
10248
10336
|
ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,
|
|
10249
10337
|
flags |
|
|
@@ -16625,6 +16713,63 @@ static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValue obj,
|
|
|
16625
16713
|
return JS_EXCEPTION;
|
|
16626
16714
|
}
|
|
16627
16715
|
|
|
16716
|
+
static JSValue js_sync_dispose_wrapper(JSContext *ctx, JSValueConst this_val,
|
|
16717
|
+
int argc, JSValueConst *argv,
|
|
16718
|
+
int magic, JSValueConst *func_data);
|
|
16719
|
+
|
|
16720
|
+
static __exception int js_op_using_check(JSContext *ctx, JSValueConst val,
|
|
16721
|
+
int hint, JSValue *pmethod)
|
|
16722
|
+
{
|
|
16723
|
+
JSValue method;
|
|
16724
|
+
bool is_sync_fallback = false;
|
|
16725
|
+
|
|
16726
|
+
*pmethod = JS_UNDEFINED;
|
|
16727
|
+
if (JS_IsNull(val) || JS_IsUndefined(val))
|
|
16728
|
+
return 0;
|
|
16729
|
+
if (!JS_IsObject(val)) {
|
|
16730
|
+
JS_ThrowTypeErrorNotAnObject(ctx);
|
|
16731
|
+
return -1;
|
|
16732
|
+
}
|
|
16733
|
+
if (hint == 1) {
|
|
16734
|
+
method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_asyncDispose);
|
|
16735
|
+
if (JS_IsException(method))
|
|
16736
|
+
return -1;
|
|
16737
|
+
if (JS_IsUndefined(method) || JS_IsNull(method)) {
|
|
16738
|
+
JS_FreeValue(ctx, method);
|
|
16739
|
+
method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_dispose);
|
|
16740
|
+
if (JS_IsException(method))
|
|
16741
|
+
return -1;
|
|
16742
|
+
is_sync_fallback = true;
|
|
16743
|
+
}
|
|
16744
|
+
} else {
|
|
16745
|
+
method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_dispose);
|
|
16746
|
+
if (JS_IsException(method))
|
|
16747
|
+
return -1;
|
|
16748
|
+
}
|
|
16749
|
+
if (JS_IsUndefined(method) || JS_IsNull(method)) {
|
|
16750
|
+
JS_ThrowTypeError(ctx, "value is not disposable");
|
|
16751
|
+
return -1;
|
|
16752
|
+
}
|
|
16753
|
+
if (!JS_IsFunction(ctx, method)) {
|
|
16754
|
+
JS_FreeValue(ctx, method);
|
|
16755
|
+
JS_ThrowTypeError(ctx, "dispose method is not a function");
|
|
16756
|
+
return -1;
|
|
16757
|
+
}
|
|
16758
|
+
if (is_sync_fallback) {
|
|
16759
|
+
JSValueConst data[1];
|
|
16760
|
+
JSValue wrapped;
|
|
16761
|
+
data[0] = method;
|
|
16762
|
+
wrapped = JS_NewCFunctionData(ctx, js_sync_dispose_wrapper, 0, 0,
|
|
16763
|
+
1, data);
|
|
16764
|
+
JS_FreeValue(ctx, method);
|
|
16765
|
+
if (JS_IsException(wrapped))
|
|
16766
|
+
return -1;
|
|
16767
|
+
method = wrapped;
|
|
16768
|
+
}
|
|
16769
|
+
*pmethod = method;
|
|
16770
|
+
return 0;
|
|
16771
|
+
}
|
|
16772
|
+
|
|
16628
16773
|
static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)
|
|
16629
16774
|
{
|
|
16630
16775
|
JSValue obj, value;
|
|
@@ -18689,9 +18834,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
|
|
18689
18834
|
goto exception;
|
|
18690
18835
|
sp += 1;
|
|
18691
18836
|
BREAK;
|
|
18692
|
-
CASE(
|
|
18837
|
+
CASE(OP_check_object):
|
|
18693
18838
|
if (unlikely(!JS_IsObject(sp[-1]))) {
|
|
18694
|
-
|
|
18839
|
+
JS_ThrowTypeErrorNotAnObject(ctx);
|
|
18695
18840
|
goto exception;
|
|
18696
18841
|
}
|
|
18697
18842
|
BREAK;
|
|
@@ -18727,6 +18872,124 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
|
|
18727
18872
|
}
|
|
18728
18873
|
BREAK;
|
|
18729
18874
|
|
|
18875
|
+
CASE(OP_using_dispose_init):
|
|
18876
|
+
sp[0] = JS_UNINITIALIZED;
|
|
18877
|
+
sp++;
|
|
18878
|
+
BREAK;
|
|
18879
|
+
|
|
18880
|
+
CASE(OP_using_dispose):
|
|
18881
|
+
{
|
|
18882
|
+
int idx;
|
|
18883
|
+
JSValueConst val, method;
|
|
18884
|
+
JSValue ret, error_state;
|
|
18885
|
+
|
|
18886
|
+
idx = get_u16(pc);
|
|
18887
|
+
pc += 2;
|
|
18888
|
+
val = var_buf[idx];
|
|
18889
|
+
method = var_buf[idx + 1];
|
|
18890
|
+
error_state = sp[-1];
|
|
18891
|
+
|
|
18892
|
+
if (JS_IsNull(val) || JS_IsUndefined(val) ||
|
|
18893
|
+
JS_IsUninitialized(val)) {
|
|
18894
|
+
/* null/undefined (spec-permitted) or uninitialized
|
|
18895
|
+
(declaration threw before assignment). */
|
|
18896
|
+
BREAK;
|
|
18897
|
+
}
|
|
18898
|
+
sf->cur_pc = pc;
|
|
18899
|
+
ret = JS_Call(ctx, method, val, 0, NULL);
|
|
18900
|
+
if (JS_IsException(ret)) {
|
|
18901
|
+
JSValue new_error = JS_GetException(ctx);
|
|
18902
|
+
if (!JS_IsUninitialized(error_state)) {
|
|
18903
|
+
JSValue se;
|
|
18904
|
+
se = js_new_suppressed_error(ctx, new_error,
|
|
18905
|
+
error_state);
|
|
18906
|
+
JS_FreeValue(ctx, new_error);
|
|
18907
|
+
JS_FreeValue(ctx, error_state);
|
|
18908
|
+
if (JS_IsException(se)) {
|
|
18909
|
+
sp[-1] = JS_GetException(ctx);
|
|
18910
|
+
} else {
|
|
18911
|
+
sp[-1] = se;
|
|
18912
|
+
}
|
|
18913
|
+
} else {
|
|
18914
|
+
sp[-1] = new_error;
|
|
18915
|
+
}
|
|
18916
|
+
} else {
|
|
18917
|
+
JS_FreeValue(ctx, ret);
|
|
18918
|
+
}
|
|
18919
|
+
}
|
|
18920
|
+
BREAK;
|
|
18921
|
+
|
|
18922
|
+
CASE(OP_using_dispose_async):
|
|
18923
|
+
{
|
|
18924
|
+
int idx;
|
|
18925
|
+
JSValueConst val, method;
|
|
18926
|
+
JSValue ret;
|
|
18927
|
+
|
|
18928
|
+
idx = get_u16(pc);
|
|
18929
|
+
pc += 2;
|
|
18930
|
+
val = var_buf[idx];
|
|
18931
|
+
method = var_buf[idx + 1];
|
|
18932
|
+
|
|
18933
|
+
if (JS_IsNull(val) || JS_IsUndefined(val) ||
|
|
18934
|
+
JS_IsUninitialized(val)) {
|
|
18935
|
+
sp[0] = JS_UNDEFINED;
|
|
18936
|
+
sp++;
|
|
18937
|
+
BREAK;
|
|
18938
|
+
}
|
|
18939
|
+
sf->cur_pc = pc;
|
|
18940
|
+
ret = JS_Call(ctx, method, val, 0, NULL);
|
|
18941
|
+
if (JS_IsException(ret))
|
|
18942
|
+
goto exception;
|
|
18943
|
+
sp[0] = ret;
|
|
18944
|
+
sp++;
|
|
18945
|
+
}
|
|
18946
|
+
BREAK;
|
|
18947
|
+
|
|
18948
|
+
CASE(OP_using_dispose_merge):
|
|
18949
|
+
{
|
|
18950
|
+
JSValue new_error = sp[-1];
|
|
18951
|
+
JSValue error_state = sp[-2];
|
|
18952
|
+
sp--;
|
|
18953
|
+
if (!JS_IsUninitialized(error_state)) {
|
|
18954
|
+
JSValue se = js_new_suppressed_error(ctx, new_error,
|
|
18955
|
+
error_state);
|
|
18956
|
+
JS_FreeValue(ctx, new_error);
|
|
18957
|
+
JS_FreeValue(ctx, error_state);
|
|
18958
|
+
if (JS_IsException(se)) {
|
|
18959
|
+
sp[-1] = JS_GetException(ctx);
|
|
18960
|
+
} else {
|
|
18961
|
+
sp[-1] = se;
|
|
18962
|
+
}
|
|
18963
|
+
} else {
|
|
18964
|
+
sp[-1] = new_error;
|
|
18965
|
+
}
|
|
18966
|
+
}
|
|
18967
|
+
BREAK;
|
|
18968
|
+
|
|
18969
|
+
CASE(OP_using_dispose_end):
|
|
18970
|
+
{
|
|
18971
|
+
JSValue error_state = sp[-1];
|
|
18972
|
+
sp--;
|
|
18973
|
+
if (!JS_IsUninitialized(error_state)) {
|
|
18974
|
+
JS_Throw(ctx, error_state);
|
|
18975
|
+
goto exception;
|
|
18976
|
+
}
|
|
18977
|
+
}
|
|
18978
|
+
BREAK;
|
|
18979
|
+
|
|
18980
|
+
CASE(OP_using_check):
|
|
18981
|
+
{
|
|
18982
|
+
int hint = pc[0];
|
|
18983
|
+
JSValue method;
|
|
18984
|
+
pc += 1;
|
|
18985
|
+
sf->cur_pc = pc;
|
|
18986
|
+
if (js_op_using_check(ctx, sp[-1], hint, &method))
|
|
18987
|
+
goto exception;
|
|
18988
|
+
sp[0] = method;
|
|
18989
|
+
sp++;
|
|
18990
|
+
}
|
|
18991
|
+
BREAK;
|
|
18992
|
+
|
|
18730
18993
|
CASE(OP_iterator_next):
|
|
18731
18994
|
/* stack: iter_obj next catch_offset val */
|
|
18732
18995
|
{
|
|
@@ -21287,6 +21550,7 @@ enum {
|
|
|
21287
21550
|
TOK_EXTENDS,
|
|
21288
21551
|
TOK_IMPORT,
|
|
21289
21552
|
TOK_SUPER,
|
|
21553
|
+
TOK_USING,
|
|
21290
21554
|
/* FutureReservedWords when parsing strict mode code */
|
|
21291
21555
|
TOK_IMPLEMENTS,
|
|
21292
21556
|
TOK_INTERFACE,
|
|
@@ -21321,6 +21585,8 @@ typedef struct BlockEnv {
|
|
|
21321
21585
|
int scope_level;
|
|
21322
21586
|
uint8_t has_iterator : 1;
|
|
21323
21587
|
uint8_t is_regular_stmt : 1; // i.e. not a loop statement
|
|
21588
|
+
uint8_t has_using : 1; /* scope has using declarations needing disposal */
|
|
21589
|
+
int using_scope_level; /* scope level for OP_dispose_scope (-1 if none) */
|
|
21324
21590
|
} BlockEnv;
|
|
21325
21591
|
|
|
21326
21592
|
typedef struct JSGlobalVar {
|
|
@@ -22097,6 +22363,12 @@ static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
|
|
|
22097
22363
|
/* convert a TOK_IDENT to a keyword when needed */
|
|
22098
22364
|
static void update_token_ident(JSParseState *s)
|
|
22099
22365
|
{
|
|
22366
|
+
/* `using` is contextually reserved, not a true keyword. Leave it as
|
|
22367
|
+
TOK_IDENT so it can be used as a regular identifier in expressions.
|
|
22368
|
+
Using declarations are detected explicitly at statement and
|
|
22369
|
+
for-loop head parsing via token_is_pseudo_keyword. */
|
|
22370
|
+
if (s->token.u.ident.atom == JS_ATOM_using)
|
|
22371
|
+
return;
|
|
22100
22372
|
if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
|
|
22101
22373
|
(s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&
|
|
22102
22374
|
s->cur_func->is_strict_mode) ||
|
|
@@ -22415,6 +22687,7 @@ static __exception int next_token(JSParseState *s)
|
|
|
22415
22687
|
if (JS_VALUE_IS_NAN(ret) ||
|
|
22416
22688
|
lre_js_is_ident_next(utf8_decode(p, &p1))) {
|
|
22417
22689
|
JS_FreeValue(s->ctx, ret);
|
|
22690
|
+
s->col_num = max_int(1, s->mark - s->eol);
|
|
22418
22691
|
js_parse_error(s, "invalid number literal");
|
|
22419
22692
|
goto fail;
|
|
22420
22693
|
}
|
|
@@ -23040,6 +23313,9 @@ static int simple_next_token(const uint8_t **pp, bool no_line_terminator)
|
|
|
23040
23313
|
} else if (c == 'a' && p[0] == 'w' && p[1] == 'a' &&
|
|
23041
23314
|
p[2] == 'i' && p[3] == 't' && !lre_js_is_ident_next(p[4])) {
|
|
23042
23315
|
return TOK_AWAIT;
|
|
23316
|
+
} else if (c == 'u' && p[0] == 's' && p[1] == 'i' &&
|
|
23317
|
+
p[2] == 'n' && p[3] == 'g' && !lre_js_is_ident_next(p[4])) {
|
|
23318
|
+
return TOK_USING;
|
|
23043
23319
|
}
|
|
23044
23320
|
return TOK_IDENT;
|
|
23045
23321
|
}
|
|
@@ -23119,14 +23395,19 @@ static void emit_u32(JSParseState *s, uint32_t val)
|
|
|
23119
23395
|
dbuf_put_u32(&s->cur_func->byte_code, val);
|
|
23120
23396
|
}
|
|
23121
23397
|
|
|
23122
|
-
static void
|
|
23398
|
+
static void emit_source_loc_at(JSParseState *s, int line_num, int col_num)
|
|
23123
23399
|
{
|
|
23124
23400
|
JSFunctionDef *fd = s->cur_func;
|
|
23125
23401
|
DynBuf *bc = &fd->byte_code;
|
|
23126
23402
|
|
|
23127
23403
|
dbuf_putc(bc, OP_source_loc);
|
|
23128
|
-
dbuf_put_u32(bc,
|
|
23129
|
-
dbuf_put_u32(bc,
|
|
23404
|
+
dbuf_put_u32(bc, line_num);
|
|
23405
|
+
dbuf_put_u32(bc, col_num);
|
|
23406
|
+
}
|
|
23407
|
+
|
|
23408
|
+
static void emit_source_loc(JSParseState *s)
|
|
23409
|
+
{
|
|
23410
|
+
emit_source_loc_at(s, s->token.line_num, s->token.col_num);
|
|
23130
23411
|
}
|
|
23131
23412
|
|
|
23132
23413
|
static void emit_op(JSParseState *s, uint8_t val)
|
|
@@ -23347,7 +23628,7 @@ static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
|
|
|
23347
23628
|
if (i == -1)
|
|
23348
23629
|
goto not_found;
|
|
23349
23630
|
vd = &fd->vars[i];
|
|
23350
|
-
if (
|
|
23631
|
+
if (vd->scope_level == 0)
|
|
23351
23632
|
return i;
|
|
23352
23633
|
}
|
|
23353
23634
|
for(i = fd->var_count; i-- > 0;) {
|
|
@@ -23473,6 +23754,10 @@ static int push_scope(JSParseState *s) {
|
|
|
23473
23754
|
fd->scope_count++;
|
|
23474
23755
|
fd->scopes[scope].parent = fd->scope_level;
|
|
23475
23756
|
fd->scopes[scope].first = fd->scope_first;
|
|
23757
|
+
fd->scopes[scope].has_using = 0;
|
|
23758
|
+
fd->scopes[scope].is_await_using = 0;
|
|
23759
|
+
fd->scopes[scope].using_label_catch = -1;
|
|
23760
|
+
fd->scopes[scope].using_label_end = -1;
|
|
23476
23761
|
emit_op(s, OP_enter_scope);
|
|
23477
23762
|
emit_u16(s, scope);
|
|
23478
23763
|
return fd->scope_level = scope;
|
|
@@ -23646,6 +23931,7 @@ typedef enum {
|
|
|
23646
23931
|
JS_VAR_DEF_NEW_FUNCTION_DECL, /* async/generator function declaration */
|
|
23647
23932
|
JS_VAR_DEF_CATCH,
|
|
23648
23933
|
JS_VAR_DEF_VAR,
|
|
23934
|
+
JS_VAR_DEF_USING,
|
|
23649
23935
|
} JSVarDefEnum;
|
|
23650
23936
|
|
|
23651
23937
|
static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
|
|
@@ -23662,6 +23948,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
|
|
|
23662
23948
|
|
|
23663
23949
|
case JS_VAR_DEF_LET:
|
|
23664
23950
|
case JS_VAR_DEF_CONST:
|
|
23951
|
+
case JS_VAR_DEF_USING:
|
|
23665
23952
|
case JS_VAR_DEF_FUNCTION_DECL:
|
|
23666
23953
|
case JS_VAR_DEF_NEW_FUNCTION_DECL:
|
|
23667
23954
|
idx = find_lexical_decl(ctx, fd, name, fd->scope_first, true);
|
|
@@ -23708,9 +23995,10 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
|
|
|
23708
23995
|
}
|
|
23709
23996
|
|
|
23710
23997
|
if (fd->is_eval &&
|
|
23711
|
-
|
|
23712
|
-
|
|
23713
|
-
|
|
23998
|
+
(fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
|
|
23999
|
+
fd->eval_type == JS_EVAL_TYPE_MODULE) &&
|
|
24000
|
+
fd->scope_level == fd->body_scope &&
|
|
24001
|
+
var_def_type != JS_VAR_DEF_USING) {
|
|
23714
24002
|
JSGlobalVar *hf;
|
|
23715
24003
|
hf = add_global_var(s->ctx, fd, name);
|
|
23716
24004
|
if (!hf)
|
|
@@ -23724,13 +24012,16 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
|
|
|
23724
24012
|
var_kind = JS_VAR_FUNCTION_DECL;
|
|
23725
24013
|
else if (var_def_type == JS_VAR_DEF_NEW_FUNCTION_DECL)
|
|
23726
24014
|
var_kind = JS_VAR_NEW_FUNCTION_DECL;
|
|
24015
|
+
else if (var_def_type == JS_VAR_DEF_USING)
|
|
24016
|
+
var_kind = JS_VAR_USING;
|
|
23727
24017
|
else
|
|
23728
24018
|
var_kind = JS_VAR_NORMAL;
|
|
23729
24019
|
idx = add_scope_var(ctx, fd, name, var_kind);
|
|
23730
24020
|
if (idx >= 0) {
|
|
23731
24021
|
vd = &fd->vars[idx];
|
|
23732
24022
|
vd->is_lexical = 1;
|
|
23733
|
-
vd->is_const = (var_def_type == JS_VAR_DEF_CONST
|
|
24023
|
+
vd->is_const = (var_def_type == JS_VAR_DEF_CONST ||
|
|
24024
|
+
var_def_type == JS_VAR_DEF_USING);
|
|
23734
24025
|
}
|
|
23735
24026
|
}
|
|
23736
24027
|
break;
|
|
@@ -24443,6 +24734,7 @@ static __exception int js_parse_object_literal(JSParseState *s)
|
|
|
24443
24734
|
#define PF_POW_ALLOWED (1 << 2)
|
|
24444
24735
|
/* forbid the exponentiation operator in js_parse_unary() */
|
|
24445
24736
|
#define PF_POW_FORBIDDEN (1 << 3)
|
|
24737
|
+
#define PF_AWAIT_USING (1 << 4)
|
|
24446
24738
|
|
|
24447
24739
|
static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
|
|
24448
24740
|
|
|
@@ -25595,6 +25887,9 @@ static __exception int js_define_var(JSParseState *s, JSAtom name, int tok)
|
|
|
25595
25887
|
case TOK_VAR:
|
|
25596
25888
|
var_def_type = JS_VAR_DEF_VAR;
|
|
25597
25889
|
break;
|
|
25890
|
+
case TOK_USING:
|
|
25891
|
+
var_def_type = JS_VAR_DEF_USING;
|
|
25892
|
+
break;
|
|
25598
25893
|
case TOK_CATCH:
|
|
25599
25894
|
var_def_type = JS_VAR_DEF_CATCH;
|
|
25600
25895
|
break;
|
|
@@ -25971,8 +26266,11 @@ static int js_parse_destructuring_element(JSParseState *s, int tok,
|
|
|
25971
26266
|
} else if (s->token.val == '[') {
|
|
25972
26267
|
bool has_spread;
|
|
25973
26268
|
int enum_depth;
|
|
26269
|
+
int source_line_num, source_col_num;
|
|
25974
26270
|
BlockEnv block_env;
|
|
25975
26271
|
|
|
26272
|
+
source_line_num = s->token.line_num;
|
|
26273
|
+
source_col_num = s->token.col_num;
|
|
25976
26274
|
if (next_token(s))
|
|
25977
26275
|
return -1;
|
|
25978
26276
|
/* the block environment is only needed in generators in case
|
|
@@ -26068,6 +26366,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok,
|
|
|
26068
26366
|
}
|
|
26069
26367
|
/* close iterator object:
|
|
26070
26368
|
if completed, enum_obj has been replaced by undefined */
|
|
26369
|
+
emit_source_loc_at(s, source_line_num, source_col_num);
|
|
26071
26370
|
emit_op(s, OP_iterator_close);
|
|
26072
26371
|
pop_break_entry(s->cur_func);
|
|
26073
26372
|
if (next_token(s))
|
|
@@ -26880,6 +27179,9 @@ static __exception int js_parse_delete(JSParseState *s)
|
|
|
26880
27179
|
return 0;
|
|
26881
27180
|
}
|
|
26882
27181
|
|
|
27182
|
+
static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
|
|
27183
|
+
bool export_flag);
|
|
27184
|
+
|
|
26883
27185
|
/* allowed parse_flags: PF_POW_ALLOWED, PF_POW_FORBIDDEN */
|
|
26884
27186
|
static __exception int js_parse_unary(JSParseState *s, int parse_flags)
|
|
26885
27187
|
{
|
|
@@ -26966,8 +27268,8 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags)
|
|
|
26966
27268
|
return -1;
|
|
26967
27269
|
if (js_parse_unary(s, PF_POW_FORBIDDEN))
|
|
26968
27270
|
return -1;
|
|
26969
|
-
s->cur_func->has_await = true;
|
|
26970
27271
|
emit_op(s, OP_await);
|
|
27272
|
+
s->cur_func->has_await = true;
|
|
26971
27273
|
parse_flags = 0;
|
|
26972
27274
|
break;
|
|
26973
27275
|
default:
|
|
@@ -27323,7 +27625,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
|
|
|
27323
27625
|
emit_op(s, OP_iterator_next);
|
|
27324
27626
|
if (is_async)
|
|
27325
27627
|
emit_op(s, OP_await);
|
|
27326
|
-
emit_op(s,
|
|
27628
|
+
emit_op(s, OP_check_object);
|
|
27327
27629
|
emit_op(s, OP_get_field2);
|
|
27328
27630
|
emit_atom(s, JS_ATOM_done);
|
|
27329
27631
|
label_next = emit_goto(s, OP_if_true, -1); /* end of loop */
|
|
@@ -27356,7 +27658,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
|
|
|
27356
27658
|
label_return1 = emit_goto(s, OP_if_true, -1);
|
|
27357
27659
|
if (is_async)
|
|
27358
27660
|
emit_op(s, OP_await);
|
|
27359
|
-
emit_op(s,
|
|
27661
|
+
emit_op(s, OP_check_object);
|
|
27360
27662
|
emit_op(s, OP_get_field2);
|
|
27361
27663
|
emit_atom(s, JS_ATOM_done);
|
|
27362
27664
|
emit_goto(s, OP_if_false, label_yield);
|
|
@@ -27377,7 +27679,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
|
|
|
27377
27679
|
label_throw1 = emit_goto(s, OP_if_true, -1);
|
|
27378
27680
|
if (is_async)
|
|
27379
27681
|
emit_op(s, OP_await);
|
|
27380
|
-
emit_op(s,
|
|
27682
|
+
emit_op(s, OP_check_object);
|
|
27381
27683
|
emit_op(s, OP_get_field2);
|
|
27382
27684
|
emit_atom(s, JS_ATOM_done);
|
|
27383
27685
|
emit_goto(s, OP_if_false, label_yield);
|
|
@@ -27624,6 +27926,8 @@ static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
|
|
|
27624
27926
|
be->scope_level = fd->scope_level;
|
|
27625
27927
|
be->has_iterator = false;
|
|
27626
27928
|
be->is_regular_stmt = false;
|
|
27929
|
+
be->has_using = false;
|
|
27930
|
+
be->using_scope_level = -1;
|
|
27627
27931
|
}
|
|
27628
27932
|
|
|
27629
27933
|
static void pop_break_entry(JSFunctionDef *fd)
|
|
@@ -27664,6 +27968,12 @@ static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
|
|
|
27664
27968
|
}
|
|
27665
27969
|
for(; i < top->drop_count; i++)
|
|
27666
27970
|
emit_op(s, OP_drop);
|
|
27971
|
+
if (top->has_using) {
|
|
27972
|
+
emit_op(s, OP_using_dispose_init);
|
|
27973
|
+
emit_op(s, OP_dispose_scope);
|
|
27974
|
+
emit_u16(s, top->using_scope_level);
|
|
27975
|
+
emit_op(s, OP_using_dispose_end);
|
|
27976
|
+
}
|
|
27667
27977
|
if (top->label_finally != -1) {
|
|
27668
27978
|
/* must push dummy value to keep same stack depth */
|
|
27669
27979
|
emit_op(s, OP_undefined);
|
|
@@ -27701,7 +28011,8 @@ static void emit_return(JSParseState *s, bool hasval)
|
|
|
27701
28011
|
|
|
27702
28012
|
top = s->cur_func->top_break;
|
|
27703
28013
|
while (top != NULL) {
|
|
27704
|
-
if (top->has_iterator || top->label_finally != -1
|
|
28014
|
+
if (top->has_iterator || top->label_finally != -1 ||
|
|
28015
|
+
top->has_using) {
|
|
27705
28016
|
if (!hasval) {
|
|
27706
28017
|
emit_op(s, OP_undefined);
|
|
27707
28018
|
hasval = true;
|
|
@@ -27725,7 +28036,7 @@ static void emit_return(JSParseState *s, bool hasval)
|
|
|
27725
28036
|
label_next = emit_goto(s, OP_if_true, -1);
|
|
27726
28037
|
emit_op(s, OP_call_method);
|
|
27727
28038
|
emit_u16(s, 0);
|
|
27728
|
-
emit_op(s,
|
|
28039
|
+
emit_op(s, OP_check_object);
|
|
27729
28040
|
emit_op(s, OP_await);
|
|
27730
28041
|
label_next2 = emit_goto(s, OP_goto, -1);
|
|
27731
28042
|
emit_label(s, label_next);
|
|
@@ -27737,6 +28048,14 @@ static void emit_return(JSParseState *s, bool hasval)
|
|
|
27737
28048
|
emit_op(s, OP_undefined); /* dummy catch offset */
|
|
27738
28049
|
emit_op(s, OP_iterator_close);
|
|
27739
28050
|
}
|
|
28051
|
+
} else if (top->has_using) {
|
|
28052
|
+
/* Dispose using variables. The return value is on TOS.
|
|
28053
|
+
stack: ret_val */
|
|
28054
|
+
emit_op(s, OP_using_dispose_init); /* initial error_state */
|
|
28055
|
+
emit_op(s, OP_dispose_scope);
|
|
28056
|
+
emit_u16(s, top->using_scope_level);
|
|
28057
|
+
emit_op(s, OP_using_dispose_end);
|
|
28058
|
+
/* stack: ret_val */
|
|
27740
28059
|
} else {
|
|
27741
28060
|
/* execute the "finally" block */
|
|
27742
28061
|
emit_goto(s, OP_gosub, top->label_finally);
|
|
@@ -27788,16 +28107,53 @@ static __exception int js_parse_statement(JSParseState *s)
|
|
|
27788
28107
|
|
|
27789
28108
|
static __exception int js_parse_block(JSParseState *s)
|
|
27790
28109
|
{
|
|
28110
|
+
JSFunctionDef *fd = s->cur_func;
|
|
28111
|
+
|
|
27791
28112
|
if (js_parse_expect(s, '{'))
|
|
27792
28113
|
return -1;
|
|
27793
28114
|
if (s->token.val != '}') {
|
|
28115
|
+
BlockEnv using_be;
|
|
28116
|
+
int has_using_be = 0;
|
|
28117
|
+
int scope_level;
|
|
28118
|
+
|
|
27794
28119
|
push_scope(s);
|
|
28120
|
+
scope_level = fd->scope_level;
|
|
27795
28121
|
for(;;) {
|
|
27796
28122
|
if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
|
|
27797
28123
|
return -1;
|
|
28124
|
+
if (!has_using_be && fd->scopes[scope_level].has_using) {
|
|
28125
|
+
has_using_be = 1;
|
|
28126
|
+
push_break_entry(fd, &using_be, JS_ATOM_NULL, -1, -1, 1);
|
|
28127
|
+
using_be.has_using = true;
|
|
28128
|
+
using_be.using_scope_level = scope_level;
|
|
28129
|
+
}
|
|
27798
28130
|
if (s->token.val == '}')
|
|
27799
28131
|
break;
|
|
27800
28132
|
}
|
|
28133
|
+
if (has_using_be) {
|
|
28134
|
+
int label_catch = fd->scopes[scope_level].using_label_catch;
|
|
28135
|
+
int label_end = fd->scopes[scope_level].using_label_end;
|
|
28136
|
+
|
|
28137
|
+
pop_break_entry(fd);
|
|
28138
|
+
|
|
28139
|
+
if (js_is_live_code(s)) {
|
|
28140
|
+
emit_op(s, OP_drop); /* drop catch_offset */
|
|
28141
|
+
emit_op(s, OP_using_dispose_init); /* initial error_state: no error */
|
|
28142
|
+
emit_op(s, OP_dispose_scope);
|
|
28143
|
+
emit_u16(s, scope_level);
|
|
28144
|
+
emit_op(s, OP_using_dispose_end);
|
|
28145
|
+
emit_goto(s, OP_goto, label_end);
|
|
28146
|
+
}
|
|
28147
|
+
|
|
28148
|
+
emit_label(s, label_catch);
|
|
28149
|
+
/* Stack: exception_value (= initial error_state) */
|
|
28150
|
+
emit_op(s, OP_dispose_scope);
|
|
28151
|
+
emit_u16(s, scope_level);
|
|
28152
|
+
/* Stack: final_error_state (original or SuppressedError) */
|
|
28153
|
+
emit_op(s, OP_throw);
|
|
28154
|
+
|
|
28155
|
+
emit_label(s, label_end);
|
|
28156
|
+
}
|
|
27801
28157
|
pop_scope(s);
|
|
27802
28158
|
}
|
|
27803
28159
|
if (next_token(s))
|
|
@@ -27819,14 +28175,29 @@ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
|
|
|
27819
28175
|
return js_parse_error_reserved_identifier(s);
|
|
27820
28176
|
}
|
|
27821
28177
|
name = JS_DupAtom(ctx, s->token.u.ident.atom);
|
|
27822
|
-
if (name == JS_ATOM_let &&
|
|
28178
|
+
if (name == JS_ATOM_let &&
|
|
28179
|
+
(tok == TOK_LET || tok == TOK_CONST || tok == TOK_USING)) {
|
|
27823
28180
|
js_parse_error(s, "'let' is not a valid lexical identifier");
|
|
27824
28181
|
goto var_error;
|
|
27825
28182
|
}
|
|
28183
|
+
int using_method_idx = -1;
|
|
27826
28184
|
if (next_token(s))
|
|
27827
28185
|
goto var_error;
|
|
27828
28186
|
if (js_define_var(s, name, tok))
|
|
27829
28187
|
goto var_error;
|
|
28188
|
+
if (tok == TOK_USING) {
|
|
28189
|
+
/* Allocate a paired hidden local for the cached dispose
|
|
28190
|
+
method. Must be allocated immediately after the value
|
|
28191
|
+
var so OP_using_dispose can locate it at value_idx + 1.
|
|
28192
|
+
*/
|
|
28193
|
+
using_method_idx = add_scope_var(ctx, fd,
|
|
28194
|
+
JS_ATOM__using_dispose_,
|
|
28195
|
+
JS_VAR_USING_METHOD);
|
|
28196
|
+
if (using_method_idx < 0)
|
|
28197
|
+
goto var_error;
|
|
28198
|
+
fd->vars[using_method_idx].is_lexical = 1;
|
|
28199
|
+
fd->vars[using_method_idx].is_const = 1;
|
|
28200
|
+
}
|
|
27830
28201
|
if (export_flag) {
|
|
27831
28202
|
if (!add_export_entry(s, s->cur_func->module, name, name,
|
|
27832
28203
|
JS_EXPORT_TYPE_LOCAL))
|
|
@@ -27854,17 +28225,54 @@ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
|
|
|
27854
28225
|
put_lvalue(s, opcode, scope, name1, label,
|
|
27855
28226
|
PUT_LVALUE_NOKEEP, false);
|
|
27856
28227
|
} else {
|
|
28228
|
+
bool init;
|
|
28229
|
+
|
|
28230
|
+
if (tok == TOK_USING) {
|
|
28231
|
+
bool is_await = (parse_flags & PF_AWAIT_USING) != 0;
|
|
28232
|
+
|
|
28233
|
+
if (!fd->scopes[fd->scope_level].has_using) {
|
|
28234
|
+
/* First 'using' in this scope: set up labels
|
|
28235
|
+
for the catch handler and end of disposal */
|
|
28236
|
+
fd->scopes[fd->scope_level].has_using = 1;
|
|
28237
|
+
fd->scopes[fd->scope_level].using_label_catch =
|
|
28238
|
+
new_label(s);
|
|
28239
|
+
fd->scopes[fd->scope_level].using_label_end =
|
|
28240
|
+
new_label(s);
|
|
28241
|
+
|
|
28242
|
+
/* Emit OP_catch: push catch_offset on the value
|
|
28243
|
+
stack. If an exception occurs, control jumps
|
|
28244
|
+
to catch_label with the exception value on the
|
|
28245
|
+
stack instead of catch_offset. */
|
|
28246
|
+
emit_goto(s, OP_catch,
|
|
28247
|
+
fd->scopes[fd->scope_level].using_label_catch);
|
|
28248
|
+
}
|
|
28249
|
+
if (is_await)
|
|
28250
|
+
fd->scopes[fd->scope_level].is_await_using = 1;
|
|
28251
|
+
}
|
|
28252
|
+
|
|
27857
28253
|
if (js_parse_assign_expr2(s, parse_flags))
|
|
27858
28254
|
goto var_error;
|
|
27859
28255
|
set_object_name(s, name);
|
|
27860
|
-
|
|
27861
|
-
|
|
28256
|
+
|
|
28257
|
+
if (tok == TOK_USING) {
|
|
28258
|
+
emit_op(s, OP_using_check);
|
|
28259
|
+
emit_u8(s, (parse_flags & PF_AWAIT_USING) != 0);
|
|
28260
|
+
/* Stack: value, method. Store the method first.
|
|
28261
|
+
Emit OP_put_loc directly (bypasses atom lookup)
|
|
28262
|
+
so multiple using decls with the shared hidden
|
|
28263
|
+
atom name don't collide. */
|
|
28264
|
+
emit_op(s, OP_put_loc);
|
|
28265
|
+
emit_u16(s, using_method_idx);
|
|
28266
|
+
}
|
|
28267
|
+
|
|
28268
|
+
init = (tok == TOK_CONST || tok == TOK_LET || tok == TOK_USING);
|
|
28269
|
+
emit_op(s, init ? OP_scope_put_var_init : OP_scope_put_var);
|
|
27862
28270
|
emit_atom(s, name);
|
|
27863
28271
|
emit_u16(s, fd->scope_level);
|
|
27864
28272
|
}
|
|
27865
28273
|
} else {
|
|
27866
|
-
if (tok == TOK_CONST) {
|
|
27867
|
-
js_parse_error(s, "missing initializer for
|
|
28274
|
+
if (tok == TOK_CONST || tok == TOK_USING) {
|
|
28275
|
+
js_parse_error(s, "missing initializer for variable");
|
|
27868
28276
|
goto var_error;
|
|
27869
28277
|
}
|
|
27870
28278
|
if (tok == TOK_LET) {
|
|
@@ -27880,6 +28288,10 @@ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
|
|
|
27880
28288
|
int skip_bits;
|
|
27881
28289
|
if ((s->token.val == '[' || s->token.val == '{')
|
|
27882
28290
|
&& js_parse_skip_parens_token(s, &skip_bits, false) == '=') {
|
|
28291
|
+
/* using declarations do not allow binding patterns */
|
|
28292
|
+
if (tok == TOK_USING) {
|
|
28293
|
+
return js_parse_error(s, "binding patterns are not allowed in using declarations");
|
|
28294
|
+
}
|
|
27883
28295
|
emit_op(s, OP_undefined);
|
|
27884
28296
|
if (js_parse_destructuring_element(s, tok, false, true, skip_bits & SKIP_HAS_ELLIPSIS, true, export_flag) < 0)
|
|
27885
28297
|
return -1;
|
|
@@ -27948,10 +28360,38 @@ static int is_let(JSParseState *s, int decl_mask)
|
|
|
27948
28360
|
return res;
|
|
27949
28361
|
}
|
|
27950
28362
|
|
|
28363
|
+
/* Return 1 if the current token is `using` introducing a UsingDeclaration,
|
|
28364
|
+
0 if it is a plain identifier usage, or -1 on error.
|
|
28365
|
+
If `is_for_of` is true, `using of` is specifically treated as identifier
|
|
28366
|
+
per the for-of lookahead restriction. */
|
|
28367
|
+
static int is_using(JSParseState *s, bool is_for_of)
|
|
28368
|
+
{
|
|
28369
|
+
int res = false;
|
|
28370
|
+
if (token_is_pseudo_keyword(s, JS_ATOM_using)) {
|
|
28371
|
+
JSParsePos pos;
|
|
28372
|
+
js_parse_get_pos(s, &pos);
|
|
28373
|
+
if (next_token(s))
|
|
28374
|
+
return -1;
|
|
28375
|
+
/* No line terminator allowed between `using` and the binding */
|
|
28376
|
+
if (s->last_line_num == s->token.line_num) {
|
|
28377
|
+
if (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) {
|
|
28378
|
+
if (!(is_for_of && s->token.u.ident.atom == JS_ATOM_of)) {
|
|
28379
|
+
res = true;
|
|
28380
|
+
}
|
|
28381
|
+
}
|
|
28382
|
+
}
|
|
28383
|
+
if (js_parse_seek_token(s, &pos))
|
|
28384
|
+
res = -1;
|
|
28385
|
+
}
|
|
28386
|
+
return res;
|
|
28387
|
+
}
|
|
28388
|
+
|
|
27951
28389
|
/* XXX: handle IteratorClose when exiting the loop before the
|
|
27952
28390
|
enumeration is done */
|
|
27953
28391
|
static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
|
|
27954
|
-
bool is_async
|
|
28392
|
+
bool is_async,
|
|
28393
|
+
int source_line_num,
|
|
28394
|
+
int source_col_num)
|
|
27955
28395
|
{
|
|
27956
28396
|
JSContext *ctx = s->ctx;
|
|
27957
28397
|
JSFunctionDef *fd = s->cur_func;
|
|
@@ -27997,7 +28437,27 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
|
|
|
27997
28437
|
default:
|
|
27998
28438
|
return -1;
|
|
27999
28439
|
}
|
|
28000
|
-
|
|
28440
|
+
bool is_await_using = false;
|
|
28441
|
+
if (tok == TOK_AWAIT) {
|
|
28442
|
+
int u;
|
|
28443
|
+
if (next_token(s))
|
|
28444
|
+
return -1;
|
|
28445
|
+
u = is_using(s, false);
|
|
28446
|
+
if (u < 0)
|
|
28447
|
+
return -1;
|
|
28448
|
+
if (!u)
|
|
28449
|
+
return js_parse_error(s, "'using' expected");
|
|
28450
|
+
tok = TOK_USING;
|
|
28451
|
+
is_await_using = true;
|
|
28452
|
+
s->cur_func->has_await = true;
|
|
28453
|
+
} else if (token_is_pseudo_keyword(s, JS_ATOM_using)) {
|
|
28454
|
+
int u = is_using(s, true);
|
|
28455
|
+
if (u < 0)
|
|
28456
|
+
return -1;
|
|
28457
|
+
if (u)
|
|
28458
|
+
tok = TOK_USING;
|
|
28459
|
+
}
|
|
28460
|
+
if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST || tok == TOK_USING) {
|
|
28001
28461
|
if (next_token(s))
|
|
28002
28462
|
return -1;
|
|
28003
28463
|
|
|
@@ -28011,7 +28471,13 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
|
|
|
28011
28471
|
}
|
|
28012
28472
|
var_name = JS_ATOM_NULL;
|
|
28013
28473
|
} else {
|
|
28474
|
+
bool init;
|
|
28014
28475
|
var_name = JS_DupAtom(ctx, s->token.u.ident.atom);
|
|
28476
|
+
if (var_name == JS_ATOM_let &&
|
|
28477
|
+
(tok == TOK_LET || tok == TOK_CONST || tok == TOK_USING)) {
|
|
28478
|
+
JS_FreeAtom(s->ctx, var_name);
|
|
28479
|
+
return js_parse_error(s, "'let' is not a valid lexical identifier");
|
|
28480
|
+
}
|
|
28015
28481
|
if (next_token(s)) {
|
|
28016
28482
|
JS_FreeAtom(s->ctx, var_name);
|
|
28017
28483
|
return -1;
|
|
@@ -28020,10 +28486,33 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
|
|
|
28020
28486
|
JS_FreeAtom(s->ctx, var_name);
|
|
28021
28487
|
return -1;
|
|
28022
28488
|
}
|
|
28023
|
-
|
|
28024
|
-
|
|
28489
|
+
if (tok == TOK_USING) {
|
|
28490
|
+
int mi = add_scope_var(ctx, fd, JS_ATOM__using_dispose_,
|
|
28491
|
+
JS_VAR_USING_METHOD);
|
|
28492
|
+
if (mi < 0) {
|
|
28493
|
+
JS_FreeAtom(s->ctx, var_name);
|
|
28494
|
+
return -1;
|
|
28495
|
+
}
|
|
28496
|
+
fd->vars[mi].is_lexical = 1;
|
|
28497
|
+
fd->vars[mi].is_const = 1;
|
|
28498
|
+
emit_op(s, OP_using_check);
|
|
28499
|
+
emit_u8(s, is_await_using);
|
|
28500
|
+
emit_op(s, OP_put_loc);
|
|
28501
|
+
emit_u16(s, mi);
|
|
28502
|
+
}
|
|
28503
|
+
init = (tok == TOK_CONST || tok == TOK_LET || tok == TOK_USING);
|
|
28504
|
+
emit_op(s, init ? OP_scope_put_var_init : OP_scope_put_var);
|
|
28025
28505
|
emit_atom(s, var_name);
|
|
28026
28506
|
emit_u16(s, fd->scope_level);
|
|
28507
|
+
if (tok == TOK_USING) {
|
|
28508
|
+
if (!fd->scopes[fd->scope_level].has_using) {
|
|
28509
|
+
fd->scopes[fd->scope_level].has_using = 1;
|
|
28510
|
+
fd->scopes[fd->scope_level].using_label_catch = new_label(s);
|
|
28511
|
+
fd->scopes[fd->scope_level].using_label_end = new_label(s);
|
|
28512
|
+
}
|
|
28513
|
+
if (is_await_using)
|
|
28514
|
+
fd->scopes[fd->scope_level].is_await_using = 1;
|
|
28515
|
+
}
|
|
28027
28516
|
}
|
|
28028
28517
|
} else if (!is_async && token_is_pseudo_keyword(s, JS_ATOM_async) && peek_token(s, false) == TOK_OF) {
|
|
28029
28518
|
return js_parse_error(s, "'for of' expression cannot start with 'async'");
|
|
@@ -28074,6 +28563,8 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
|
|
|
28074
28563
|
} else if (s->token.val == TOK_IN) {
|
|
28075
28564
|
if (is_async)
|
|
28076
28565
|
return js_parse_error(s, "'for await' loop should be used with 'of'");
|
|
28566
|
+
if (tok == TOK_USING)
|
|
28567
|
+
return js_parse_error(s, "using declaration not allowed in for-in");
|
|
28077
28568
|
if (has_initializer &&
|
|
28078
28569
|
(tok != TOK_VAR || fd->is_strict_mode || has_destructuring)) {
|
|
28079
28570
|
initializer_error:
|
|
@@ -28136,8 +28627,46 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
|
|
|
28136
28627
|
}
|
|
28137
28628
|
|
|
28138
28629
|
emit_label(s, label_body);
|
|
28139
|
-
|
|
28140
|
-
|
|
28630
|
+
{
|
|
28631
|
+
bool scope_has_using = fd->scopes[fd->scope_level].has_using;
|
|
28632
|
+
int using_scope_level = fd->scope_level;
|
|
28633
|
+
BlockEnv using_be;
|
|
28634
|
+
int had_using_be = 0;
|
|
28635
|
+
|
|
28636
|
+
if (scope_has_using) {
|
|
28637
|
+
emit_goto(s, OP_catch, fd->scopes[using_scope_level].using_label_catch);
|
|
28638
|
+
push_break_entry(fd, &using_be, JS_ATOM_NULL, -1, -1, 1);
|
|
28639
|
+
using_be.has_using = true;
|
|
28640
|
+
using_be.using_scope_level = using_scope_level;
|
|
28641
|
+
had_using_be = 1;
|
|
28642
|
+
}
|
|
28643
|
+
|
|
28644
|
+
if (js_parse_statement(s))
|
|
28645
|
+
return -1;
|
|
28646
|
+
|
|
28647
|
+
if (had_using_be) {
|
|
28648
|
+
pop_break_entry(fd);
|
|
28649
|
+
}
|
|
28650
|
+
|
|
28651
|
+
if (scope_has_using && js_is_live_code(s)) {
|
|
28652
|
+
emit_op(s, OP_drop);
|
|
28653
|
+
emit_op(s, OP_using_dispose_init);
|
|
28654
|
+
emit_op(s, OP_dispose_scope);
|
|
28655
|
+
emit_u16(s, using_scope_level);
|
|
28656
|
+
emit_op(s, OP_using_dispose_end);
|
|
28657
|
+
emit_goto(s, OP_goto,
|
|
28658
|
+
fd->scopes[using_scope_level].using_label_end);
|
|
28659
|
+
}
|
|
28660
|
+
|
|
28661
|
+
if (scope_has_using) {
|
|
28662
|
+
emit_label(s, fd->scopes[using_scope_level].using_label_catch);
|
|
28663
|
+
emit_op(s, OP_dispose_scope);
|
|
28664
|
+
emit_u16(s, using_scope_level);
|
|
28665
|
+
emit_op(s, OP_throw);
|
|
28666
|
+
|
|
28667
|
+
emit_label(s, fd->scopes[using_scope_level].using_label_end);
|
|
28668
|
+
}
|
|
28669
|
+
}
|
|
28141
28670
|
|
|
28142
28671
|
close_scopes(s, s->cur_func->scope_level, block_scope_level);
|
|
28143
28672
|
|
|
@@ -28169,6 +28698,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
|
|
|
28169
28698
|
emit_label(s, label_break);
|
|
28170
28699
|
if (is_for_of) {
|
|
28171
28700
|
/* close and drop enum_rec */
|
|
28701
|
+
emit_source_loc_at(s, source_line_num, source_col_num);
|
|
28172
28702
|
emit_op(s, OP_iterator_close);
|
|
28173
28703
|
} else {
|
|
28174
28704
|
emit_op(s, OP_drop);
|
|
@@ -28278,6 +28808,36 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
|
|
|
28278
28808
|
if (js_parse_expect_semi(s))
|
|
28279
28809
|
goto fail;
|
|
28280
28810
|
break;
|
|
28811
|
+
case TOK_AWAIT:
|
|
28812
|
+
/* Check for 'await using' declaration */
|
|
28813
|
+
if (s->cur_func->func_kind & JS_FUNC_ASYNC) {
|
|
28814
|
+
JSParsePos pos;
|
|
28815
|
+
int u;
|
|
28816
|
+
js_parse_get_pos(s, &pos);
|
|
28817
|
+
if (next_token(s)) /* skip 'await' */
|
|
28818
|
+
goto fail;
|
|
28819
|
+
u = is_using(s, false);
|
|
28820
|
+
if (u < 0)
|
|
28821
|
+
goto fail;
|
|
28822
|
+
if (u) {
|
|
28823
|
+
if (!(decl_mask & DECL_MASK_OTHER)) {
|
|
28824
|
+
js_parse_error(s, "lexical declarations can't appear in single-statement context");
|
|
28825
|
+
goto fail;
|
|
28826
|
+
}
|
|
28827
|
+
s->cur_func->has_await = true;
|
|
28828
|
+
if (next_token(s)) /* skip 'using' */
|
|
28829
|
+
goto fail;
|
|
28830
|
+
if (js_parse_var(s, PF_IN_ACCEPTED | PF_AWAIT_USING, TOK_USING, /*export_flag*/false))
|
|
28831
|
+
goto fail;
|
|
28832
|
+
if (js_parse_expect_semi(s))
|
|
28833
|
+
goto fail;
|
|
28834
|
+
break;
|
|
28835
|
+
}
|
|
28836
|
+
/* Not 'await using': restore to parse as expression */
|
|
28837
|
+
if (js_parse_seek_token(s, &pos))
|
|
28838
|
+
goto fail;
|
|
28839
|
+
}
|
|
28840
|
+
goto hasexpr;
|
|
28281
28841
|
case TOK_LET:
|
|
28282
28842
|
case TOK_CONST:
|
|
28283
28843
|
haslet:
|
|
@@ -28401,10 +28961,14 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
|
|
|
28401
28961
|
{
|
|
28402
28962
|
int label_cont, label_break, label_body, label_test;
|
|
28403
28963
|
int pos_cont, pos_body, block_scope_level;
|
|
28964
|
+
int for_scope_level;
|
|
28404
28965
|
BlockEnv break_entry;
|
|
28405
28966
|
int tok, bits;
|
|
28967
|
+
int source_line_num, source_col_num;
|
|
28406
28968
|
bool is_async;
|
|
28407
28969
|
|
|
28970
|
+
source_line_num = s->token.line_num;
|
|
28971
|
+
source_col_num = s->token.col_num;
|
|
28408
28972
|
if (next_token(s))
|
|
28409
28973
|
goto fail;
|
|
28410
28974
|
|
|
@@ -28428,7 +28992,8 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
|
|
|
28428
28992
|
|
|
28429
28993
|
if (!(bits & SKIP_HAS_SEMI)) {
|
|
28430
28994
|
/* parse for/in or for/of */
|
|
28431
|
-
if (js_parse_for_in_of(s, label_name, is_async
|
|
28995
|
+
if (js_parse_for_in_of(s, label_name, is_async,
|
|
28996
|
+
source_line_num, source_col_num))
|
|
28432
28997
|
goto fail;
|
|
28433
28998
|
break;
|
|
28434
28999
|
}
|
|
@@ -28437,6 +29002,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
|
|
|
28437
29002
|
/* create scope for the lexical variables declared in the initial,
|
|
28438
29003
|
test and increment expressions */
|
|
28439
29004
|
push_scope(s);
|
|
29005
|
+
for_scope_level = s->cur_func->scope_level;
|
|
28440
29006
|
/* initial expression */
|
|
28441
29007
|
tok = s->token.val;
|
|
28442
29008
|
if (tok != ';') {
|
|
@@ -28449,10 +29015,48 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
|
|
|
28449
29015
|
default:
|
|
28450
29016
|
goto fail;
|
|
28451
29017
|
}
|
|
28452
|
-
if (tok
|
|
29018
|
+
if (tok != TOK_VAR && tok != TOK_LET && tok != TOK_CONST &&
|
|
29019
|
+
token_is_pseudo_keyword(s, JS_ATOM_using)) {
|
|
29020
|
+
int u = is_using(s, false);
|
|
29021
|
+
if (u < 0)
|
|
29022
|
+
goto fail;
|
|
29023
|
+
if (u)
|
|
29024
|
+
tok = TOK_USING;
|
|
29025
|
+
}
|
|
29026
|
+
if (tok == TOK_AWAIT &&
|
|
29027
|
+
(s->cur_func->func_kind & JS_FUNC_ASYNC)) {
|
|
29028
|
+
/* Check for `await using` declaration head */
|
|
29029
|
+
JSParsePos pos;
|
|
29030
|
+
int u;
|
|
29031
|
+
js_parse_get_pos(s, &pos);
|
|
29032
|
+
if (next_token(s)) /* skip 'await' */
|
|
29033
|
+
goto fail;
|
|
29034
|
+
u = is_using(s, false);
|
|
29035
|
+
if (u < 0)
|
|
29036
|
+
goto fail;
|
|
29037
|
+
if (u) {
|
|
29038
|
+
s->cur_func->has_await = true;
|
|
29039
|
+
tok = TOK_USING;
|
|
29040
|
+
if (next_token(s)) /* skip 'using' */
|
|
29041
|
+
goto fail;
|
|
29042
|
+
if (js_parse_var(s, PF_IN_ACCEPTED | PF_AWAIT_USING,
|
|
29043
|
+
TOK_USING, false))
|
|
29044
|
+
goto fail;
|
|
29045
|
+
goto for_init_done;
|
|
29046
|
+
}
|
|
29047
|
+
if (js_parse_seek_token(s, &pos))
|
|
29048
|
+
goto fail;
|
|
29049
|
+
}
|
|
29050
|
+
if (tok == TOK_VAR
|
|
29051
|
+
|| tok == TOK_LET
|
|
29052
|
+
|| tok == TOK_CONST
|
|
29053
|
+
|| tok == TOK_USING) {
|
|
29054
|
+
int pf = 0;
|
|
29055
|
+
if (tok == TOK_USING && is_async)
|
|
29056
|
+
pf |= PF_AWAIT_USING;
|
|
28453
29057
|
if (next_token(s))
|
|
28454
29058
|
goto fail;
|
|
28455
|
-
if (js_parse_var(s,
|
|
29059
|
+
if (js_parse_var(s, pf, tok, /*export_flag*/false))
|
|
28456
29060
|
goto fail;
|
|
28457
29061
|
} else {
|
|
28458
29062
|
if (js_parse_expr2(s, false))
|
|
@@ -28460,6 +29064,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
|
|
|
28460
29064
|
emit_op(s, OP_drop);
|
|
28461
29065
|
}
|
|
28462
29066
|
|
|
29067
|
+
for_init_done:
|
|
28463
29068
|
/* close the closures before the first iteration */
|
|
28464
29069
|
close_scopes(s, s->cur_func->scope_level, block_scope_level);
|
|
28465
29070
|
}
|
|
@@ -28473,6 +29078,11 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
|
|
|
28473
29078
|
|
|
28474
29079
|
push_break_entry(s->cur_func, &break_entry,
|
|
28475
29080
|
label_name, label_break, label_cont, 0);
|
|
29081
|
+
if (s->cur_func->scopes[for_scope_level].has_using) {
|
|
29082
|
+
break_entry.has_using = true;
|
|
29083
|
+
break_entry.using_scope_level = for_scope_level;
|
|
29084
|
+
break_entry.drop_count = 1; /* catch_offset from OP_catch */
|
|
29085
|
+
}
|
|
28476
29086
|
|
|
28477
29087
|
/* test expression */
|
|
28478
29088
|
if (s->token.val == ';') {
|
|
@@ -28540,6 +29150,27 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
|
|
|
28540
29150
|
emit_label(s, label_break);
|
|
28541
29151
|
|
|
28542
29152
|
pop_break_entry(s->cur_func);
|
|
29153
|
+
|
|
29154
|
+
if (s->cur_func->scopes[for_scope_level].has_using) {
|
|
29155
|
+
int label_catch = s->cur_func->scopes[for_scope_level].using_label_catch;
|
|
29156
|
+
int label_end = s->cur_func->scopes[for_scope_level].using_label_end;
|
|
29157
|
+
|
|
29158
|
+
/* Normal exit: drop catch_offset, dispose */
|
|
29159
|
+
emit_op(s, OP_drop);
|
|
29160
|
+
emit_op(s, OP_using_dispose_init);
|
|
29161
|
+
emit_op(s, OP_dispose_scope);
|
|
29162
|
+
emit_u16(s, for_scope_level);
|
|
29163
|
+
emit_op(s, OP_using_dispose_end);
|
|
29164
|
+
emit_goto(s, OP_goto, label_end);
|
|
29165
|
+
|
|
29166
|
+
/* Catch handler: exception on stack */
|
|
29167
|
+
emit_label(s, label_catch);
|
|
29168
|
+
emit_op(s, OP_dispose_scope);
|
|
29169
|
+
emit_u16(s, for_scope_level);
|
|
29170
|
+
emit_op(s, OP_throw);
|
|
29171
|
+
|
|
29172
|
+
emit_label(s, label_end);
|
|
29173
|
+
}
|
|
28543
29174
|
pop_scope(s);
|
|
28544
29175
|
}
|
|
28545
29176
|
break;
|
|
@@ -28642,6 +29273,35 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
|
|
|
28642
29273
|
js_parse_error(s, "invalid switch statement");
|
|
28643
29274
|
goto fail;
|
|
28644
29275
|
}
|
|
29276
|
+
/* `using` / `await using` declarations are not allowed
|
|
29277
|
+
directly within a CaseClause or DefaultClause
|
|
29278
|
+
(early error per spec). */
|
|
29279
|
+
if (token_is_pseudo_keyword(s, JS_ATOM_using)) {
|
|
29280
|
+
int u = is_using(s, false);
|
|
29281
|
+
if (u < 0)
|
|
29282
|
+
goto fail;
|
|
29283
|
+
if (u) {
|
|
29284
|
+
js_parse_error(s, "using declaration is not allowed in this context");
|
|
29285
|
+
goto fail;
|
|
29286
|
+
}
|
|
29287
|
+
}
|
|
29288
|
+
if (s->token.val == TOK_AWAIT &&
|
|
29289
|
+
(s->cur_func->func_kind & JS_FUNC_ASYNC)) {
|
|
29290
|
+
JSParsePos pos;
|
|
29291
|
+
int u;
|
|
29292
|
+
js_parse_get_pos(s, &pos);
|
|
29293
|
+
if (next_token(s))
|
|
29294
|
+
goto fail;
|
|
29295
|
+
u = is_using(s, false);
|
|
29296
|
+
if (u < 0)
|
|
29297
|
+
goto fail;
|
|
29298
|
+
if (js_parse_seek_token(s, &pos))
|
|
29299
|
+
goto fail;
|
|
29300
|
+
if (u) {
|
|
29301
|
+
js_parse_error(s, "await using declaration is not allowed in this context");
|
|
29302
|
+
goto fail;
|
|
29303
|
+
}
|
|
29304
|
+
}
|
|
28645
29305
|
if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
|
|
28646
29306
|
goto fail;
|
|
28647
29307
|
}
|
|
@@ -28875,6 +29535,33 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
|
|
|
28875
29535
|
default:
|
|
28876
29536
|
goto fail;
|
|
28877
29537
|
}
|
|
29538
|
+
if (token_is_pseudo_keyword(s, JS_ATOM_using)) {
|
|
29539
|
+
int u = is_using(s, false);
|
|
29540
|
+
if (u < 0)
|
|
29541
|
+
goto fail;
|
|
29542
|
+
if (u) {
|
|
29543
|
+
JSFunctionDef *fd = s->cur_func;
|
|
29544
|
+
if (!(decl_mask & DECL_MASK_OTHER)) {
|
|
29545
|
+
js_parse_error(s, "lexical declarations can't appear in single-statement context");
|
|
29546
|
+
goto fail;
|
|
29547
|
+
}
|
|
29548
|
+
if (fd->is_eval &&
|
|
29549
|
+
(fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
|
|
29550
|
+
fd->eval_type == JS_EVAL_TYPE_DIRECT ||
|
|
29551
|
+
fd->eval_type == JS_EVAL_TYPE_INDIRECT) &&
|
|
29552
|
+
fd->scope_level == fd->body_scope) {
|
|
29553
|
+
js_parse_error(s, "using declaration is not allowed at the top level of a script");
|
|
29554
|
+
goto fail;
|
|
29555
|
+
}
|
|
29556
|
+
if (next_token(s))
|
|
29557
|
+
goto fail;
|
|
29558
|
+
if (js_parse_var(s, PF_IN_ACCEPTED, TOK_USING, /*export_flag*/false))
|
|
29559
|
+
goto fail;
|
|
29560
|
+
if (js_parse_expect_semi(s))
|
|
29561
|
+
goto fail;
|
|
29562
|
+
break;
|
|
29563
|
+
}
|
|
29564
|
+
}
|
|
28878
29565
|
if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
|
|
28879
29566
|
peek_token(s, true) == TOK_FUNCTION) {
|
|
28880
29567
|
if (!(decl_mask & DECL_MASK_OTHER)) {
|
|
@@ -29037,33 +29724,6 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
|
|
|
29037
29724
|
js_free(ctx, m);
|
|
29038
29725
|
}
|
|
29039
29726
|
|
|
29040
|
-
/* mikrojs patch: public wrapper to free a single module (remove it from
|
|
29041
|
-
* the context's loaded-modules cache and release all its resources).
|
|
29042
|
-
* Callers must ensure the module is not mid-linking or mid-evaluating and
|
|
29043
|
-
* that no other modules hold live import bindings to its exports (or accept
|
|
29044
|
-
* that such bindings remain valid via refcounted JSVarRefs). */
|
|
29045
|
-
void JS_FreeModule(JSContext *ctx, JSModuleDef *m)
|
|
29046
|
-
{
|
|
29047
|
-
js_free_module_def(ctx, m);
|
|
29048
|
-
}
|
|
29049
|
-
|
|
29050
|
-
static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name);
|
|
29051
|
-
|
|
29052
|
-
/* mikrojs patch: lookup a module in the context cache by name atom.
|
|
29053
|
-
* Returns NULL if no module with that name is loaded. */
|
|
29054
|
-
JSModuleDef *JS_FindLoadedModule(JSContext *ctx, JSAtom name)
|
|
29055
|
-
{
|
|
29056
|
-
return js_find_loaded_module(ctx, name);
|
|
29057
|
-
}
|
|
29058
|
-
|
|
29059
|
-
/* mikrojs patch: return the module's current status as an integer.
|
|
29060
|
-
* 0=UNLINKED, 1=LINKING, 2=LINKED, 3=EVALUATING, 4=EVALUATING_ASYNC, 5=EVALUATED. */
|
|
29061
|
-
int JS_GetModuleStatus(JSContext *ctx, JSModuleDef *m)
|
|
29062
|
-
{
|
|
29063
|
-
(void)ctx;
|
|
29064
|
-
return (int)m->status;
|
|
29065
|
-
}
|
|
29066
|
-
|
|
29067
29727
|
#ifndef QJS_DISABLE_PARSER
|
|
29068
29728
|
|
|
29069
29729
|
static int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
|
|
@@ -31247,6 +31907,7 @@ static __exception int js_parse_export(JSParseState *s)
|
|
|
31247
31907
|
case TOK_VAR:
|
|
31248
31908
|
case TOK_LET:
|
|
31249
31909
|
case TOK_CONST:
|
|
31910
|
+
case TOK_USING:
|
|
31250
31911
|
return js_parse_var(s, PF_IN_ACCEPTED, tok, /*export_flag*/true);
|
|
31251
31912
|
default:
|
|
31252
31913
|
return js_parse_error(s, "invalid export syntax");
|
|
@@ -31500,6 +32161,10 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx,
|
|
|
31500
32161
|
fd->scope_count = 1;
|
|
31501
32162
|
fd->scopes[0].first = -1;
|
|
31502
32163
|
fd->scopes[0].parent = -1;
|
|
32164
|
+
fd->scopes[0].has_using = 0;
|
|
32165
|
+
fd->scopes[0].is_await_using = 0;
|
|
32166
|
+
fd->scopes[0].using_label_catch = -1;
|
|
32167
|
+
fd->scopes[0].using_label_end = -1;
|
|
31503
32168
|
fd->scope_level = 0; /* 0: var/arg scope */
|
|
31504
32169
|
fd->scope_first = -1;
|
|
31505
32170
|
fd->body_scope = -1;
|
|
@@ -33861,6 +34526,62 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
|
|
|
33861
34526
|
}
|
|
33862
34527
|
break;
|
|
33863
34528
|
|
|
34529
|
+
case OP_dispose_scope:
|
|
34530
|
+
{
|
|
34531
|
+
int scope_idx, scope = get_u16(bc_buf + pos + 1);
|
|
34532
|
+
bool is_async = s->scopes[scope].is_await_using;
|
|
34533
|
+
|
|
34534
|
+
for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
|
|
34535
|
+
JSVarDef *vd = &s->vars[scope_idx];
|
|
34536
|
+
if (vd->scope_level == scope) {
|
|
34537
|
+
if (vd->var_kind == JS_VAR_USING) {
|
|
34538
|
+
if (is_async) {
|
|
34539
|
+
int label_catch = new_label_fd(s);
|
|
34540
|
+
int label_end = new_label_fd(s);
|
|
34541
|
+
if (label_catch < 0 || label_end < 0) {
|
|
34542
|
+
dbuf_set_error(&bc_out);
|
|
34543
|
+
break;
|
|
34544
|
+
}
|
|
34545
|
+
|
|
34546
|
+
dbuf_putc(&bc_out, OP_catch);
|
|
34547
|
+
dbuf_put_u32(&bc_out, label_catch);
|
|
34548
|
+
update_label(s, label_catch, 1);
|
|
34549
|
+
s->jump_size++;
|
|
34550
|
+
|
|
34551
|
+
dbuf_putc(&bc_out, OP_using_dispose_async);
|
|
34552
|
+
dbuf_put_u16(&bc_out, scope_idx);
|
|
34553
|
+
|
|
34554
|
+
dbuf_putc(&bc_out, OP_await);
|
|
34555
|
+
dbuf_putc(&bc_out, OP_drop);
|
|
34556
|
+
dbuf_putc(&bc_out, OP_drop);
|
|
34557
|
+
|
|
34558
|
+
dbuf_putc(&bc_out, OP_goto);
|
|
34559
|
+
dbuf_put_u32(&bc_out, label_end);
|
|
34560
|
+
update_label(s, label_end, 1);
|
|
34561
|
+
s->jump_size++;
|
|
34562
|
+
|
|
34563
|
+
dbuf_putc(&bc_out, OP_label);
|
|
34564
|
+
dbuf_put_u32(&bc_out, label_catch);
|
|
34565
|
+
s->label_slots[label_catch].pos2 = bc_out.size;
|
|
34566
|
+
|
|
34567
|
+
dbuf_putc(&bc_out, OP_using_dispose_merge);
|
|
34568
|
+
|
|
34569
|
+
dbuf_putc(&bc_out, OP_label);
|
|
34570
|
+
dbuf_put_u32(&bc_out, label_end);
|
|
34571
|
+
s->label_slots[label_end].pos2 = bc_out.size;
|
|
34572
|
+
} else {
|
|
34573
|
+
dbuf_putc(&bc_out, OP_using_dispose);
|
|
34574
|
+
dbuf_put_u16(&bc_out, scope_idx);
|
|
34575
|
+
}
|
|
34576
|
+
}
|
|
34577
|
+
scope_idx = vd->scope_next;
|
|
34578
|
+
} else {
|
|
34579
|
+
break;
|
|
34580
|
+
}
|
|
34581
|
+
}
|
|
34582
|
+
}
|
|
34583
|
+
break;
|
|
34584
|
+
|
|
33864
34585
|
case OP_set_name:
|
|
33865
34586
|
{
|
|
33866
34587
|
/* remove dummy set_name opcodes */
|
|
@@ -35671,6 +36392,7 @@ static __exception int js_parse_directives(JSParseState *s)
|
|
|
35671
36392
|
case TOK_IF:
|
|
35672
36393
|
case TOK_RETURN:
|
|
35673
36394
|
case TOK_VAR:
|
|
36395
|
+
case TOK_USING:
|
|
35674
36396
|
case TOK_THIS:
|
|
35675
36397
|
case TOK_DELETE:
|
|
35676
36398
|
case TOK_TYPEOF:
|
|
@@ -36235,25 +36957,59 @@ static __exception int js_parse_function_decl2(JSParseState *s,
|
|
|
36235
36957
|
if (js_parse_function_check_names(s, fd, func_name))
|
|
36236
36958
|
goto fail;
|
|
36237
36959
|
|
|
36238
|
-
|
|
36239
|
-
|
|
36960
|
+
{
|
|
36961
|
+
BlockEnv using_be;
|
|
36962
|
+
int has_using_be = 0;
|
|
36963
|
+
|
|
36964
|
+
while (s->token.val != '}') {
|
|
36965
|
+
if (js_parse_source_element(s))
|
|
36966
|
+
goto fail;
|
|
36967
|
+
/* Check if a 'using' was encountered in the body scope */
|
|
36968
|
+
if (!has_using_be && fd->scopes[fd->body_scope].has_using) {
|
|
36969
|
+
has_using_be = 1;
|
|
36970
|
+
push_break_entry(fd, &using_be, JS_ATOM_NULL, -1, -1, 1);
|
|
36971
|
+
using_be.has_using = true;
|
|
36972
|
+
using_be.using_scope_level = fd->body_scope;
|
|
36973
|
+
}
|
|
36974
|
+
}
|
|
36975
|
+
|
|
36976
|
+
/* save the function source code */
|
|
36977
|
+
fd->source_len = s->buf_ptr - ptr;
|
|
36978
|
+
fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
|
|
36979
|
+
if (!fd->source)
|
|
36240
36980
|
goto fail;
|
|
36241
|
-
}
|
|
36242
36981
|
|
|
36243
|
-
|
|
36244
|
-
|
|
36245
|
-
|
|
36246
|
-
|
|
36247
|
-
goto fail;
|
|
36982
|
+
if (next_token(s)) {
|
|
36983
|
+
/* consume the '}' */
|
|
36984
|
+
goto fail;
|
|
36985
|
+
}
|
|
36248
36986
|
|
|
36249
|
-
|
|
36250
|
-
|
|
36251
|
-
|
|
36252
|
-
}
|
|
36987
|
+
if (has_using_be) {
|
|
36988
|
+
int label_catch = fd->scopes[fd->body_scope].using_label_catch;
|
|
36989
|
+
int label_end = fd->scopes[fd->body_scope].using_label_end;
|
|
36253
36990
|
|
|
36254
|
-
|
|
36255
|
-
|
|
36256
|
-
|
|
36991
|
+
pop_break_entry(fd);
|
|
36992
|
+
|
|
36993
|
+
if (js_is_live_code(s)) {
|
|
36994
|
+
emit_op(s, OP_drop); /* drop catch_offset */
|
|
36995
|
+
emit_op(s, OP_using_dispose_init); /* initial error_state */
|
|
36996
|
+
emit_op(s, OP_dispose_scope);
|
|
36997
|
+
emit_u16(s, fd->body_scope);
|
|
36998
|
+
emit_op(s, OP_using_dispose_end);
|
|
36999
|
+
emit_return(s, false);
|
|
37000
|
+
}
|
|
37001
|
+
|
|
37002
|
+
emit_label(s, label_catch);
|
|
37003
|
+
emit_op(s, OP_dispose_scope);
|
|
37004
|
+
emit_u16(s, fd->body_scope);
|
|
37005
|
+
emit_op(s, OP_throw);
|
|
37006
|
+
|
|
37007
|
+
emit_label(s, label_end);
|
|
37008
|
+
} else {
|
|
37009
|
+
if (js_is_live_code(s)) {
|
|
37010
|
+
emit_return(s, false);
|
|
37011
|
+
}
|
|
37012
|
+
}
|
|
36257
37013
|
}
|
|
36258
37014
|
done:
|
|
36259
37015
|
s->cur_func = fd->parent;
|
|
@@ -36391,6 +37147,8 @@ static __exception int js_parse_program(JSParseState *s)
|
|
|
36391
37147
|
{
|
|
36392
37148
|
JSFunctionDef *fd = s->cur_func;
|
|
36393
37149
|
int idx;
|
|
37150
|
+
BlockEnv using_be;
|
|
37151
|
+
int has_using_be = 0;
|
|
36394
37152
|
|
|
36395
37153
|
if (next_token(s))
|
|
36396
37154
|
return -1;
|
|
@@ -36412,28 +37170,71 @@ static __exception int js_parse_program(JSParseState *s)
|
|
|
36412
37170
|
while (s->token.val != TOK_EOF) {
|
|
36413
37171
|
if (js_parse_source_element(s))
|
|
36414
37172
|
return -1;
|
|
37173
|
+
/* Check if a 'using' was encountered at the body scope level */
|
|
37174
|
+
if (!has_using_be && fd->scopes[fd->body_scope].has_using) {
|
|
37175
|
+
has_using_be = 1;
|
|
37176
|
+
push_break_entry(fd, &using_be, JS_ATOM_NULL, -1, -1, 1);
|
|
37177
|
+
using_be.has_using = true;
|
|
37178
|
+
using_be.using_scope_level = fd->body_scope;
|
|
37179
|
+
}
|
|
36415
37180
|
}
|
|
36416
37181
|
|
|
36417
|
-
if (
|
|
36418
|
-
|
|
36419
|
-
|
|
36420
|
-
/* wrap the return value in an object so that promises can
|
|
36421
|
-
be safely returned */
|
|
36422
|
-
emit_op(s, OP_object);
|
|
36423
|
-
emit_op(s, OP_dup);
|
|
37182
|
+
if (has_using_be) {
|
|
37183
|
+
int label_catch = fd->scopes[fd->body_scope].using_label_catch;
|
|
37184
|
+
int label_end = fd->scopes[fd->body_scope].using_label_end;
|
|
36424
37185
|
|
|
36425
|
-
|
|
36426
|
-
emit_u16(s, fd->eval_ret_idx);
|
|
37186
|
+
pop_break_entry(fd);
|
|
36427
37187
|
|
|
36428
|
-
|
|
36429
|
-
|
|
37188
|
+
if (js_is_live_code(s)) {
|
|
37189
|
+
/* Normal path: drop catch_offset, dispose, then return */
|
|
37190
|
+
emit_op(s, OP_drop); /* drop catch_offset */
|
|
37191
|
+
emit_op(s, OP_using_dispose_init); /* initial error_state */
|
|
37192
|
+
emit_op(s, OP_dispose_scope);
|
|
37193
|
+
emit_u16(s, fd->body_scope);
|
|
37194
|
+
emit_op(s, OP_using_dispose_end);
|
|
37195
|
+
}
|
|
37196
|
+
|
|
37197
|
+
if (!s->is_module) {
|
|
37198
|
+
if (fd->func_kind == JS_FUNC_ASYNC) {
|
|
37199
|
+
emit_op(s, OP_object);
|
|
37200
|
+
emit_op(s, OP_dup);
|
|
37201
|
+
emit_op(s, OP_get_loc);
|
|
37202
|
+
emit_u16(s, fd->eval_ret_idx);
|
|
37203
|
+
emit_op(s, OP_put_field);
|
|
37204
|
+
emit_atom(s, JS_ATOM_value);
|
|
37205
|
+
} else {
|
|
37206
|
+
emit_op(s, OP_get_loc);
|
|
37207
|
+
emit_u16(s, fd->eval_ret_idx);
|
|
37208
|
+
}
|
|
37209
|
+
emit_return(s, true);
|
|
36430
37210
|
} else {
|
|
36431
|
-
|
|
36432
|
-
emit_u16(s, fd->eval_ret_idx);
|
|
37211
|
+
emit_return(s, false);
|
|
36433
37212
|
}
|
|
36434
|
-
|
|
37213
|
+
|
|
37214
|
+
/* Catch handler */
|
|
37215
|
+
emit_label(s, label_catch);
|
|
37216
|
+
emit_op(s, OP_dispose_scope);
|
|
37217
|
+
emit_u16(s, fd->body_scope);
|
|
37218
|
+
emit_op(s, OP_throw);
|
|
37219
|
+
|
|
37220
|
+
emit_label(s, label_end);
|
|
36435
37221
|
} else {
|
|
36436
|
-
|
|
37222
|
+
if (!s->is_module) {
|
|
37223
|
+
if (fd->func_kind == JS_FUNC_ASYNC) {
|
|
37224
|
+
emit_op(s, OP_object);
|
|
37225
|
+
emit_op(s, OP_dup);
|
|
37226
|
+
emit_op(s, OP_get_loc);
|
|
37227
|
+
emit_u16(s, fd->eval_ret_idx);
|
|
37228
|
+
emit_op(s, OP_put_field);
|
|
37229
|
+
emit_atom(s, JS_ATOM_value);
|
|
37230
|
+
} else {
|
|
37231
|
+
emit_op(s, OP_get_loc);
|
|
37232
|
+
emit_u16(s, fd->eval_ret_idx);
|
|
37233
|
+
}
|
|
37234
|
+
emit_return(s, true);
|
|
37235
|
+
} else {
|
|
37236
|
+
emit_return(s, false);
|
|
37237
|
+
}
|
|
36437
37238
|
}
|
|
36438
37239
|
|
|
36439
37240
|
return 0;
|
|
@@ -36852,7 +37653,7 @@ typedef enum BCTagEnum {
|
|
|
36852
37653
|
BC_TAG_SYMBOL,
|
|
36853
37654
|
} BCTagEnum;
|
|
36854
37655
|
|
|
36855
|
-
#define BC_VERSION
|
|
37656
|
+
#define BC_VERSION 26
|
|
36856
37657
|
|
|
36857
37658
|
typedef struct BCWriterState {
|
|
36858
37659
|
JSContext *ctx;
|
|
@@ -39256,6 +40057,20 @@ static JSValue JS_NewGlobalCConstructor(JSContext *ctx, const char *name,
|
|
|
39256
40057
|
return func_obj;
|
|
39257
40058
|
}
|
|
39258
40059
|
|
|
40060
|
+
static JSValue JS_NewGlobalCConstructorMagic(JSContext *ctx, const char *name,
|
|
40061
|
+
JSCFunctionMagic *func, int length,
|
|
40062
|
+
JSValueConst proto, int magic)
|
|
40063
|
+
{
|
|
40064
|
+
/* Used to squelch a -Wcast-function-type warning. */
|
|
40065
|
+
JSCFunctionType ft = { .constructor_magic = func };
|
|
40066
|
+
JSValue func_obj;
|
|
40067
|
+
|
|
40068
|
+
func_obj = JS_NewCFunction2(ctx, ft.constructor, name, length,
|
|
40069
|
+
JS_CFUNC_constructor_or_func_magic, magic);
|
|
40070
|
+
JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
|
|
40071
|
+
return func_obj;
|
|
40072
|
+
}
|
|
40073
|
+
|
|
39259
40074
|
static JSValue JS_NewObjectProtoList(JSContext *ctx, JSValueConst proto,
|
|
39260
40075
|
const JSCFunctionListEntry *fields, int n_fields)
|
|
39261
40076
|
{
|
|
@@ -39427,7 +40242,7 @@ JSValue JS_ToObject(JSContext *ctx, JSValueConst val)
|
|
|
39427
40242
|
if (!JS_IsException(obj)) {
|
|
39428
40243
|
JS_DefinePropertyValue(ctx, obj, JS_ATOM_length,
|
|
39429
40244
|
JS_NewInt32(ctx, JS_VALUE_GET_STRING(str)->len), 0);
|
|
39430
|
-
JS_SetObjectData(ctx, obj,
|
|
40245
|
+
JS_SetObjectData(ctx, obj, js_dup(str));
|
|
39431
40246
|
}
|
|
39432
40247
|
JS_FreeValue(ctx, str);
|
|
39433
40248
|
return obj;
|
|
@@ -41101,10 +41916,16 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
|
|
|
41101
41916
|
JS_FreeValue(ctx, proto);
|
|
41102
41917
|
if (JS_IsException(obj))
|
|
41103
41918
|
return obj;
|
|
41104
|
-
|
|
41919
|
+
switch (magic) {
|
|
41920
|
+
case JS_AGGREGATE_ERROR:
|
|
41105
41921
|
message = argv[1];
|
|
41106
41922
|
opts = 2;
|
|
41107
|
-
|
|
41923
|
+
break;
|
|
41924
|
+
case JS_SUPPRESSED_ERROR:
|
|
41925
|
+
message = argv[2];
|
|
41926
|
+
opts = 3;
|
|
41927
|
+
break;
|
|
41928
|
+
default:
|
|
41108
41929
|
message = argv[0];
|
|
41109
41930
|
opts = 1;
|
|
41110
41931
|
}
|
|
@@ -41138,6 +41959,15 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
|
|
|
41138
41959
|
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
41139
41960
|
}
|
|
41140
41961
|
|
|
41962
|
+
if (magic == JS_SUPPRESSED_ERROR) {
|
|
41963
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_error,
|
|
41964
|
+
js_dup(argv[0]),
|
|
41965
|
+
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
41966
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_suppressed,
|
|
41967
|
+
js_dup(argv[1]),
|
|
41968
|
+
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
41969
|
+
}
|
|
41970
|
+
|
|
41141
41971
|
/* skip the Error() function in the backtrace */
|
|
41142
41972
|
build_backtrace(ctx, obj, JS_UNDEFINED, NULL, 0, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
|
|
41143
41973
|
return obj;
|
|
@@ -41626,11 +42456,6 @@ static JSValue js_array_with(JSContext *ctx, JSValueConst this_val,
|
|
|
41626
42456
|
if (js_get_length64(ctx, &len, obj))
|
|
41627
42457
|
goto exception;
|
|
41628
42458
|
|
|
41629
|
-
if (len > UINT32_MAX) {
|
|
41630
|
-
JS_ThrowRangeError(ctx, "invalid array length");
|
|
41631
|
-
goto exception;
|
|
41632
|
-
}
|
|
41633
|
-
|
|
41634
42459
|
if (JS_ToInt64Sat(ctx, &idx, argv[0]))
|
|
41635
42460
|
goto exception;
|
|
41636
42461
|
|
|
@@ -41642,15 +42467,11 @@ static JSValue js_array_with(JSContext *ctx, JSValueConst this_val,
|
|
|
41642
42467
|
goto exception;
|
|
41643
42468
|
}
|
|
41644
42469
|
|
|
41645
|
-
arr =
|
|
42470
|
+
arr = js_allocate_fast_array(ctx, len);
|
|
41646
42471
|
if (JS_IsException(arr))
|
|
41647
42472
|
goto exception;
|
|
41648
42473
|
|
|
41649
42474
|
p = JS_VALUE_GET_OBJ(arr);
|
|
41650
|
-
if (expand_fast_array(ctx, p, len) < 0)
|
|
41651
|
-
goto exception;
|
|
41652
|
-
p->u.array.count = len;
|
|
41653
|
-
|
|
41654
42475
|
i = 0;
|
|
41655
42476
|
pval = p->u.array.u.values;
|
|
41656
42477
|
if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
|
|
@@ -41662,21 +42483,14 @@ static JSValue js_array_with(JSContext *ctx, JSValueConst this_val,
|
|
|
41662
42483
|
} else {
|
|
41663
42484
|
for (; i < idx; i++, pval++)
|
|
41664
42485
|
if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
|
|
41665
|
-
goto
|
|
42486
|
+
goto exception;
|
|
41666
42487
|
*pval = js_dup(argv[1]);
|
|
41667
42488
|
for (i++, pval++; i < len; i++, pval++) {
|
|
41668
|
-
if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
|
|
41669
|
-
fill_and_fail:
|
|
41670
|
-
for (; i < len; i++, pval++)
|
|
41671
|
-
*pval = JS_UNDEFINED;
|
|
42489
|
+
if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
|
|
41672
42490
|
goto exception;
|
|
41673
|
-
}
|
|
41674
42491
|
}
|
|
41675
42492
|
}
|
|
41676
42493
|
|
|
41677
|
-
if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(len)) < 0)
|
|
41678
|
-
goto exception;
|
|
41679
|
-
|
|
41680
42494
|
ret = arr;
|
|
41681
42495
|
arr = JS_UNDEFINED;
|
|
41682
42496
|
|
|
@@ -42454,7 +43268,7 @@ static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
|
|
|
42454
43268
|
(p->shape->prop->flags & JS_PROP_WRITABLE))) {
|
|
42455
43269
|
array_len = JS_VALUE_GET_INT(p->prop[0].u.value);
|
|
42456
43270
|
new_len = array_len + argc;
|
|
42457
|
-
if (likely(new_len >= array_len)) { /* no overflow */
|
|
43271
|
+
if (likely(new_len >= array_len && new_len <= (uint32_t)INT32_MAX)) { /* no overflow and within fast-array bounds */
|
|
42458
43272
|
if (unlikely(new_len > p->u.array.u1.size)) {
|
|
42459
43273
|
if (expand_fast_array(ctx, p, new_len))
|
|
42460
43274
|
return JS_EXCEPTION;
|
|
@@ -42463,7 +43277,7 @@ static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
|
|
|
42463
43277
|
p->u.array.u.values[array_len + i] = js_dup(argv[i]);
|
|
42464
43278
|
}
|
|
42465
43279
|
p->u.array.count = new_len;
|
|
42466
|
-
p->prop[0].u.value =
|
|
43280
|
+
p->prop[0].u.value = js_uint32(new_len);
|
|
42467
43281
|
return js_int32(new_len);
|
|
42468
43282
|
}
|
|
42469
43283
|
}
|
|
@@ -42586,20 +43400,12 @@ static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val,
|
|
|
42586
43400
|
if (js_get_length64(ctx, &len, obj))
|
|
42587
43401
|
goto exception;
|
|
42588
43402
|
|
|
42589
|
-
|
|
42590
|
-
JS_ThrowRangeError(ctx, "invalid array length");
|
|
42591
|
-
goto exception;
|
|
42592
|
-
}
|
|
42593
|
-
|
|
42594
|
-
arr = JS_NewArray(ctx);
|
|
43403
|
+
arr = js_allocate_fast_array(ctx, len);
|
|
42595
43404
|
if (JS_IsException(arr))
|
|
42596
43405
|
goto exception;
|
|
42597
43406
|
|
|
42598
43407
|
if (len > 0) {
|
|
42599
43408
|
p = JS_VALUE_GET_OBJ(arr);
|
|
42600
|
-
if (expand_fast_array(ctx, p, len) < 0)
|
|
42601
|
-
goto exception;
|
|
42602
|
-
p->u.array.count = len;
|
|
42603
43409
|
|
|
42604
43410
|
i = len - 1;
|
|
42605
43411
|
pval = p->u.array.u.values;
|
|
@@ -42609,17 +43415,10 @@ static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val,
|
|
|
42609
43415
|
} else {
|
|
42610
43416
|
// Query order is observable; test262 expects descending order.
|
|
42611
43417
|
for (; i >= 0; i--, pval++) {
|
|
42612
|
-
if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
|
|
42613
|
-
// Exception; initialize remaining elements.
|
|
42614
|
-
for (; i >= 0; i--, pval++)
|
|
42615
|
-
*pval = JS_UNDEFINED;
|
|
43418
|
+
if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
|
|
42616
43419
|
goto exception;
|
|
42617
|
-
}
|
|
42618
43420
|
}
|
|
42619
43421
|
}
|
|
42620
|
-
|
|
42621
|
-
if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(len)) < 0)
|
|
42622
|
-
goto exception;
|
|
42623
43422
|
}
|
|
42624
43423
|
|
|
42625
43424
|
ret = arr;
|
|
@@ -42745,8 +43544,6 @@ static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val,
|
|
|
42745
43544
|
int64_t i, j, len, newlen, start, add, del;
|
|
42746
43545
|
uint32_t count32;
|
|
42747
43546
|
|
|
42748
|
-
pval = NULL;
|
|
42749
|
-
last = NULL;
|
|
42750
43547
|
ret = JS_EXCEPTION;
|
|
42751
43548
|
arr = JS_UNDEFINED;
|
|
42752
43549
|
|
|
@@ -42771,17 +43568,12 @@ static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val,
|
|
|
42771
43568
|
add = argc - 2;
|
|
42772
43569
|
|
|
42773
43570
|
newlen = len + add - del;
|
|
42774
|
-
if (newlen >
|
|
42775
|
-
|
|
42776
|
-
if (newlen > MAX_SAFE_INTEGER) {
|
|
42777
|
-
JS_ThrowTypeError(ctx, "invalid array length");
|
|
42778
|
-
} else {
|
|
42779
|
-
JS_ThrowRangeError(ctx, "invalid array length");
|
|
42780
|
-
}
|
|
43571
|
+
if (newlen > MAX_SAFE_INTEGER) {
|
|
43572
|
+
JS_ThrowTypeError(ctx, "invalid array length");
|
|
42781
43573
|
goto exception;
|
|
42782
43574
|
}
|
|
42783
43575
|
|
|
42784
|
-
arr =
|
|
43576
|
+
arr = js_allocate_fast_array(ctx, newlen);
|
|
42785
43577
|
if (JS_IsException(arr))
|
|
42786
43578
|
goto exception;
|
|
42787
43579
|
|
|
@@ -42789,10 +43581,6 @@ static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val,
|
|
|
42789
43581
|
goto done;
|
|
42790
43582
|
|
|
42791
43583
|
p = JS_VALUE_GET_OBJ(arr);
|
|
42792
|
-
if (expand_fast_array(ctx, p, newlen) < 0)
|
|
42793
|
-
goto exception;
|
|
42794
|
-
|
|
42795
|
-
p->u.array.count = newlen;
|
|
42796
43584
|
pval = &p->u.array.u.values[0];
|
|
42797
43585
|
last = &p->u.array.u.values[newlen];
|
|
42798
43586
|
|
|
@@ -42816,17 +43604,11 @@ static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val,
|
|
|
42816
43604
|
|
|
42817
43605
|
assert(pval == last);
|
|
42818
43606
|
|
|
42819
|
-
if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(newlen)) < 0)
|
|
42820
|
-
goto exception;
|
|
42821
|
-
|
|
42822
43607
|
done:
|
|
42823
43608
|
ret = arr;
|
|
42824
43609
|
arr = JS_UNDEFINED;
|
|
42825
43610
|
|
|
42826
43611
|
exception:
|
|
42827
|
-
while (pval != last)
|
|
42828
|
-
*pval++ = JS_UNDEFINED;
|
|
42829
|
-
|
|
42830
43612
|
JS_FreeValue(ctx, arr);
|
|
42831
43613
|
JS_FreeValue(ctx, obj);
|
|
42832
43614
|
return ret;
|
|
@@ -43159,21 +43941,12 @@ static JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val,
|
|
|
43159
43941
|
if (js_get_length64(ctx, &len, obj))
|
|
43160
43942
|
goto exception;
|
|
43161
43943
|
|
|
43162
|
-
|
|
43163
|
-
JS_ThrowRangeError(ctx, "invalid array length");
|
|
43164
|
-
goto exception;
|
|
43165
|
-
}
|
|
43166
|
-
|
|
43167
|
-
arr = JS_NewArray(ctx);
|
|
43944
|
+
arr = js_allocate_fast_array(ctx, len);
|
|
43168
43945
|
if (JS_IsException(arr))
|
|
43169
43946
|
goto exception;
|
|
43170
43947
|
|
|
43171
43948
|
if (len > 0) {
|
|
43172
43949
|
p = JS_VALUE_GET_OBJ(arr);
|
|
43173
|
-
if (expand_fast_array(ctx, p, len) < 0)
|
|
43174
|
-
goto exception;
|
|
43175
|
-
p->u.array.count = len;
|
|
43176
|
-
|
|
43177
43950
|
i = 0;
|
|
43178
43951
|
pval = p->u.array.u.values;
|
|
43179
43952
|
if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
|
|
@@ -43181,16 +43954,10 @@ static JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val,
|
|
|
43181
43954
|
*pval = js_dup(arrp[i]);
|
|
43182
43955
|
} else {
|
|
43183
43956
|
for (; i < len; i++, pval++) {
|
|
43184
|
-
if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
|
|
43185
|
-
for (; i < len; i++, pval++)
|
|
43186
|
-
*pval = JS_UNDEFINED;
|
|
43957
|
+
if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
|
|
43187
43958
|
goto exception;
|
|
43188
|
-
}
|
|
43189
43959
|
}
|
|
43190
43960
|
}
|
|
43191
|
-
|
|
43192
|
-
if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(len)) < 0)
|
|
43193
|
-
goto exception;
|
|
43194
43961
|
}
|
|
43195
43962
|
|
|
43196
43963
|
ret = js_array_sort(ctx, arr, argc, argv);
|
|
@@ -44048,6 +44815,66 @@ exception:
|
|
|
44048
44815
|
return JS_EXCEPTION;
|
|
44049
44816
|
}
|
|
44050
44817
|
|
|
44818
|
+
static JSValue js_async_dispose_to_undef(JSContext *ctx, JSValueConst this_val,
|
|
44819
|
+
int argc, JSValueConst *argv,
|
|
44820
|
+
int magic, JSValueConst *func_data);
|
|
44821
|
+
|
|
44822
|
+
static JSValue js_iterator_proto_dispose(JSContext *ctx, JSValueConst this_val,
|
|
44823
|
+
int argc, JSValueConst *argv)
|
|
44824
|
+
{
|
|
44825
|
+
JSValue method;
|
|
44826
|
+
|
|
44827
|
+
method = JS_GetProperty(ctx, this_val, JS_ATOM_return);
|
|
44828
|
+
if (JS_IsException(method))
|
|
44829
|
+
return JS_EXCEPTION;
|
|
44830
|
+
if (JS_IsUndefined(method))
|
|
44831
|
+
return JS_UNDEFINED;
|
|
44832
|
+
return JS_CallFree(ctx, method, this_val, 0, NULL);
|
|
44833
|
+
}
|
|
44834
|
+
|
|
44835
|
+
static JSValue js_async_iterator_proto_dispose(JSContext *ctx,
|
|
44836
|
+
JSValueConst this_val,
|
|
44837
|
+
int argc, JSValueConst *argv)
|
|
44838
|
+
{
|
|
44839
|
+
JSValue method, ret, promise, undef_fn, then_args[1], result;
|
|
44840
|
+
JSValue undef = JS_UNDEFINED;
|
|
44841
|
+
|
|
44842
|
+
method = JS_GetProperty(ctx, this_val, JS_ATOM_return);
|
|
44843
|
+
if (JS_IsException(method)) {
|
|
44844
|
+
JSValue exc = JS_GetException(ctx);
|
|
44845
|
+
JSValue p = js_promise_resolve(ctx, ctx->promise_ctor, 1, vc(&exc), 1);
|
|
44846
|
+
JS_FreeValue(ctx, exc);
|
|
44847
|
+
return p;
|
|
44848
|
+
}
|
|
44849
|
+
if (JS_IsUndefined(method)) {
|
|
44850
|
+
return js_promise_resolve(ctx, ctx->promise_ctor, 1, vc(&undef), 0);
|
|
44851
|
+
}
|
|
44852
|
+
ret = JS_Call(ctx, method, this_val, 0, NULL);
|
|
44853
|
+
JS_FreeValue(ctx, method);
|
|
44854
|
+
if (JS_IsException(ret)) {
|
|
44855
|
+
JSValue exc = JS_GetException(ctx);
|
|
44856
|
+
JSValue p = js_promise_resolve(ctx, ctx->promise_ctor, 1, vc(&exc), 1);
|
|
44857
|
+
JS_FreeValue(ctx, exc);
|
|
44858
|
+
return p;
|
|
44859
|
+
}
|
|
44860
|
+
/* Wrap in Promise.resolve(ret).then(() => undefined) */
|
|
44861
|
+
promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, vc(&ret), 0);
|
|
44862
|
+
JS_FreeValue(ctx, ret);
|
|
44863
|
+
if (JS_IsException(promise))
|
|
44864
|
+
return promise;
|
|
44865
|
+
undef_fn = JS_NewCFunctionData(ctx, js_async_dispose_to_undef, 0, 0, 0,
|
|
44866
|
+
NULL);
|
|
44867
|
+
if (JS_IsException(undef_fn)) {
|
|
44868
|
+
JS_FreeValue(ctx, promise);
|
|
44869
|
+
return JS_EXCEPTION;
|
|
44870
|
+
}
|
|
44871
|
+
then_args[0] = undef_fn;
|
|
44872
|
+
result = JS_Invoke(ctx, promise, JS_ATOM_then, 1, vc(then_args));
|
|
44873
|
+
JS_FreeValue(ctx, undef_fn);
|
|
44874
|
+
JS_FreeValue(ctx, promise);
|
|
44875
|
+
return result;
|
|
44876
|
+
}
|
|
44877
|
+
|
|
44051
44878
|
static JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val,
|
|
44052
44879
|
int argc, JSValueConst *argv)
|
|
44053
44880
|
{
|
|
@@ -44376,6 +45203,7 @@ static const JSCFunctionListEntry js_iterator_proto_funcs[] = {
|
|
|
44376
45203
|
JS_CFUNC_MAGIC_DEF("some", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_SOME ),
|
|
44377
45204
|
JS_CFUNC_DEF("reduce", 1, js_iterator_proto_reduce ),
|
|
44378
45205
|
JS_CFUNC_DEF("toArray", 0, js_iterator_proto_toArray ),
|
|
45206
|
+
JS_CFUNC_DEF("[Symbol.dispose]", 0, js_iterator_proto_dispose ),
|
|
44379
45207
|
JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator ),
|
|
44380
45208
|
JS_CGETSET_DEF("[Symbol.toStringTag]", js_iterator_proto_get_toStringTag, js_iterator_proto_set_toStringTag),
|
|
44381
45209
|
};
|
|
@@ -51137,6 +51965,8 @@ static const JSCFunctionListEntry js_symbol_funcs[] = {
|
|
|
51137
51965
|
JS_PROP_SYMBOL_DEF("species", JS_ATOM_Symbol_species, 0),
|
|
51138
51966
|
JS_PROP_SYMBOL_DEF("unscopables", JS_ATOM_Symbol_unscopables, 0),
|
|
51139
51967
|
JS_PROP_SYMBOL_DEF("asyncIterator", JS_ATOM_Symbol_asyncIterator, 0),
|
|
51968
|
+
JS_PROP_SYMBOL_DEF("dispose", JS_ATOM_Symbol_dispose, 0),
|
|
51969
|
+
JS_PROP_SYMBOL_DEF("asyncDispose", JS_ATOM_Symbol_asyncDispose, 0),
|
|
51140
51970
|
};
|
|
51141
51971
|
|
|
51142
51972
|
/* Set/Map/WeakSet/WeakMap */
|
|
@@ -52729,6 +53559,658 @@ static const JSCFunctionListEntry js_generator_proto_funcs[] = {
|
|
|
52729
53559
|
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Generator", JS_PROP_CONFIGURABLE),
|
|
52730
53560
|
};
|
|
52731
53561
|
|
|
53562
|
+
/* Explicit resource management */
|
|
53563
|
+
|
|
53564
|
+
enum {
|
|
53565
|
+
JS_DISPOSE_HINT_SYNC, /* use: Call(method, value) */
|
|
53566
|
+
JS_DISPOSE_HINT_ADOPT, /* adopt: Call(method, undefined, [value]) */
|
|
53567
|
+
JS_DISPOSE_HINT_DEFER, /* defer: Call(method, undefined) */
|
|
53568
|
+
};
|
|
53569
|
+
|
|
53570
|
+
typedef struct JSDisposableResource {
|
|
53571
|
+
JSValue value;
|
|
53572
|
+
JSValue method; /* dispose method */
|
|
53573
|
+
uint8_t hint;
|
|
53574
|
+
} JSDisposableResource;
|
|
53575
|
+
|
|
53576
|
+
typedef struct JSDisposableStack {
|
|
53577
|
+
bool disposed;
|
|
53578
|
+
int resource_count;
|
|
53579
|
+
int resource_capacity;
|
|
53580
|
+
JSDisposableResource *resources;
|
|
53581
|
+
} JSDisposableStack;
|
|
53582
|
+
|
|
53583
|
+
static JSValue js_new_suppressed_error(JSContext *ctx, JSValueConst error,
|
|
53584
|
+
JSValueConst suppressed)
|
|
53585
|
+
{
|
|
53586
|
+
JSValue obj;
|
|
53587
|
+
|
|
53588
|
+
/* Construct via the intrinsic prototype rather than going through
|
|
53589
|
+
SuppressedError.prototype.constructor, which is user-writable. */
|
|
53590
|
+
obj = JS_NewObjectProtoClass(ctx,
|
|
53591
|
+
ctx->native_error_proto[JS_SUPPRESSED_ERROR],
|
|
53592
|
+
JS_CLASS_ERROR);
|
|
53593
|
+
if (JS_IsException(obj))
|
|
53594
|
+
return JS_EXCEPTION;
|
|
53595
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_error, js_dup(error),
|
|
53596
|
+
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
53597
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_suppressed, js_dup(suppressed),
|
|
53598
|
+
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
53599
|
+
build_backtrace(ctx, obj, JS_UNDEFINED, NULL, 0, 0,
|
|
53600
|
+
JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
|
|
53601
|
+
return obj;
|
|
53602
|
+
}
|
|
53603
|
+
|
|
53604
|
+
/* Perform DisposeResources. Returns 0 on success, -1 on exception.
|
|
53605
|
+
completion_error is the pending error (JS_UNDEFINED if none).
|
|
53606
|
+
It is consumed (freed) by this function. */
|
|
53607
|
+
static int js_dispose_resources(JSContext *ctx, JSDisposableStack *ds,
|
|
53608
|
+
JSValue completion_error)
|
|
53609
|
+
{
|
|
53610
|
+
JSValue error = completion_error;
|
|
53611
|
+
bool has_error = !JS_IsUndefined(error);
|
|
53612
|
+
int i;
|
|
53613
|
+
|
|
53614
|
+
ds->disposed = true;
|
|
53615
|
+
/* dispose in LIFO order */
|
|
53616
|
+
for (i = ds->resource_count - 1; i >= 0; i--) {
|
|
53617
|
+
JSDisposableResource *res = &ds->resources[i];
|
|
53618
|
+
JSValue ret;
|
|
53619
|
+
if (JS_IsUndefined(res->method)) {
|
|
53620
|
+
/* null/undefined resource, skip */
|
|
53621
|
+
JS_FreeValue(ctx, res->value);
|
|
53622
|
+
continue;
|
|
53623
|
+
}
|
|
53624
|
+
switch (res->hint) {
|
|
53625
|
+
case JS_DISPOSE_HINT_ADOPT:
|
|
53626
|
+
ret = JS_Call(ctx, res->method, JS_UNDEFINED, 1, vc(&res->value));
|
|
53627
|
+
break;
|
|
53628
|
+
case JS_DISPOSE_HINT_DEFER:
|
|
53629
|
+
ret = JS_Call(ctx, res->method, JS_UNDEFINED, 0, NULL);
|
|
53630
|
+
break;
|
|
53631
|
+
default: /* JS_DISPOSE_HINT_SYNC */
|
|
53632
|
+
ret = JS_Call(ctx, res->method, res->value, 0, NULL);
|
|
53633
|
+
break;
|
|
53634
|
+
}
|
|
53635
|
+
JS_FreeValue(ctx, res->value);
|
|
53636
|
+
JS_FreeValue(ctx, res->method);
|
|
53637
|
+
if (JS_IsException(ret)) {
|
|
53638
|
+
JSValue new_error = JS_GetException(ctx);
|
|
53639
|
+
if (has_error) {
|
|
53640
|
+
JSValue suppressed = js_new_suppressed_error(ctx, new_error, error);
|
|
53641
|
+
JS_FreeValue(ctx, new_error);
|
|
53642
|
+
JS_FreeValue(ctx, error);
|
|
53643
|
+
if (JS_IsException(suppressed)) {
|
|
53644
|
+
error = JS_GetException(ctx);
|
|
53645
|
+
} else {
|
|
53646
|
+
error = suppressed;
|
|
53647
|
+
}
|
|
53648
|
+
} else {
|
|
53649
|
+
error = new_error;
|
|
53650
|
+
has_error = true;
|
|
53651
|
+
}
|
|
53652
|
+
} else {
|
|
53653
|
+
JS_FreeValue(ctx, ret);
|
|
53654
|
+
}
|
|
53655
|
+
}
|
|
53656
|
+
ds->resource_count = 0;
|
|
53657
|
+
if (has_error) {
|
|
53658
|
+
JS_Throw(ctx, error);
|
|
53659
|
+
return -1;
|
|
53660
|
+
}
|
|
53661
|
+
return 0;
|
|
53662
|
+
}
|
|
53663
|
+
|
|
53664
|
+
static void js_disposable_stack_clear(JSRuntime *rt, JSDisposableStack *ds)
|
|
53665
|
+
{
|
|
53666
|
+
int i;
|
|
53667
|
+
for (i = 0; i < ds->resource_count; i++) {
|
|
53668
|
+
JS_FreeValueRT(rt, ds->resources[i].value);
|
|
53669
|
+
JS_FreeValueRT(rt, ds->resources[i].method);
|
|
53670
|
+
}
|
|
53671
|
+
js_free_rt(rt, ds->resources);
|
|
53672
|
+
}
|
|
53673
|
+
|
|
53674
|
+
static int js_disposable_stack_add(JSContext *ctx, JSDisposableStack *ds,
|
|
53675
|
+
JSValueConst value, JSValueConst method,
|
|
53676
|
+
int hint)
|
|
53677
|
+
{
|
|
53678
|
+
if (ds->resource_count >= ds->resource_capacity) {
|
|
53679
|
+
int new_cap = max_int(ds->resource_capacity * 2, 4);
|
|
53680
|
+
JSDisposableResource *new_res;
|
|
53681
|
+
new_res = js_realloc(ctx, ds->resources,
|
|
53682
|
+
new_cap * sizeof(JSDisposableResource));
|
|
53683
|
+
if (!new_res)
|
|
53684
|
+
return -1;
|
|
53685
|
+
ds->resources = new_res;
|
|
53686
|
+
ds->resource_capacity = new_cap;
|
|
53687
|
+
}
|
|
53688
|
+
ds->resources[ds->resource_count].value = js_dup(value);
|
|
53689
|
+
ds->resources[ds->resource_count].method = js_dup(method);
|
|
53690
|
+
ds->resources[ds->resource_count].hint = hint;
|
|
53691
|
+
ds->resource_count++;
|
|
53692
|
+
return 0;
|
|
53693
|
+
}
|
|
53694
|
+
|
|
53695
|
+
static JSValue js_sync_dispose_wrapper(JSContext *ctx, JSValueConst this_val,
|
|
53696
|
+
int argc, JSValueConst *argv,
|
|
53697
|
+
int magic, JSValueConst *func_data)
|
|
53698
|
+
{
|
|
53699
|
+
JSValueConst method = func_data[0];
|
|
53700
|
+
JSValue ret = JS_Call(ctx, method, this_val, 0, NULL);
|
|
53701
|
+
if (JS_IsException(ret))
|
|
53702
|
+
return JS_EXCEPTION;
|
|
53703
|
+
JS_FreeValue(ctx, ret);
|
|
53704
|
+
return JS_UNDEFINED;
|
|
53705
|
+
}
|
|
53706
|
+
|
|
53707
|
+
static JSValue js_get_dispose_method(JSContext *ctx, JSValueConst value, int hint)
|
|
53708
|
+
{
|
|
53709
|
+
JSValue method;
|
|
53710
|
+
|
|
53711
|
+
if (hint == 1) {
|
|
53712
|
+
/* async: try Symbol.asyncDispose first */
|
|
53713
|
+
method = JS_GetProperty(ctx, value, JS_ATOM_Symbol_asyncDispose);
|
|
53714
|
+
if (JS_IsException(method))
|
|
53715
|
+
return JS_EXCEPTION;
|
|
53716
|
+
if (!JS_IsUndefined(method) && !JS_IsNull(method)) {
|
|
53717
|
+
if (!JS_IsFunction(ctx, method)) {
|
|
53718
|
+
JS_FreeValue(ctx, method);
|
|
53719
|
+
return JS_ThrowTypeError(ctx, "property is not a function");
|
|
53720
|
+
}
|
|
53721
|
+
return method;
|
|
53722
|
+
}
|
|
53723
|
+
JS_FreeValue(ctx, method);
|
|
53724
|
+
/* Fall back to Symbol.dispose, but wrap it so its return value is
|
|
53725
|
+
NOT awaited (per spec GetDisposeMethod). */
|
|
53726
|
+
method = JS_GetProperty(ctx, value, JS_ATOM_Symbol_dispose);
|
|
53727
|
+
if (JS_IsException(method))
|
|
53728
|
+
return JS_EXCEPTION;
|
|
53729
|
+
if (JS_IsUndefined(method) || JS_IsNull(method))
|
|
53730
|
+
return JS_ThrowTypeError(ctx, "property is not a function");
|
|
53731
|
+
if (!JS_IsFunction(ctx, method)) {
|
|
53732
|
+
JS_FreeValue(ctx, method);
|
|
53733
|
+
return JS_ThrowTypeError(ctx, "property is not a function");
|
|
53734
|
+
}
|
|
53735
|
+
|
|
53736
|
+
{
|
|
53737
|
+
JSValue data[1], wrapped;
|
|
53738
|
+
data[0] = method;
|
|
53739
|
+
wrapped = JS_NewCFunctionData(ctx, js_sync_dispose_wrapper, 0, 0,
|
|
53740
|
+
1, vc(data));
|
|
53741
|
+
JS_FreeValue(ctx, method);
|
|
53742
|
+
return wrapped;
|
|
53743
|
+
}
|
|
53744
|
+
}
|
|
53745
|
+
|
|
53746
|
+
/* sync dispose */
|
|
53747
|
+
method = JS_GetProperty(ctx, value, JS_ATOM_Symbol_dispose);
|
|
53748
|
+
if (JS_IsException(method))
|
|
53749
|
+
return JS_EXCEPTION;
|
|
53750
|
+
if (JS_IsUndefined(method) || JS_IsNull(method))
|
|
53751
|
+
return JS_ThrowTypeError(ctx, "property is not a function");
|
|
53752
|
+
if (!JS_IsFunction(ctx, method)) {
|
|
53753
|
+
JS_FreeValue(ctx, method);
|
|
53754
|
+
return JS_ThrowTypeError(ctx, "property is not a function");
|
|
53755
|
+
}
|
|
53756
|
+
return method;
|
|
53757
|
+
}
|
|
53758
|
+
|
|
53759
|
+
static JSValue js_disposable_stack_constructor(JSContext *ctx,
|
|
53760
|
+
JSValueConst new_target,
|
|
53761
|
+
int argc, JSValueConst *argv,
|
|
53762
|
+
int class_id)
|
|
53763
|
+
{
|
|
53764
|
+
JSDisposableStack *s;
|
|
53765
|
+
JSValue obj;
|
|
53766
|
+
|
|
53767
|
+
if (JS_IsUndefined(new_target))
|
|
53768
|
+
return JS_ThrowTypeError(ctx, "Constructor requires 'new'");
|
|
53769
|
+
obj = js_create_from_ctor(ctx, new_target, class_id);
|
|
53770
|
+
if (JS_IsException(obj))
|
|
53771
|
+
return JS_EXCEPTION;
|
|
53772
|
+
s = js_mallocz(ctx, sizeof(*s));
|
|
53773
|
+
if (!s) {
|
|
53774
|
+
JS_FreeValue(ctx, obj);
|
|
53775
|
+
return JS_EXCEPTION;
|
|
53776
|
+
}
|
|
53777
|
+
JS_SetOpaqueInternal(obj, s);
|
|
53778
|
+
return obj;
|
|
53779
|
+
}
|
|
53780
|
+
|
|
53781
|
+
static void js_disposable_stack_finalizer(JSRuntime *rt, JSValueConst val)
|
|
53782
|
+
{
|
|
53783
|
+
JSObject *p;
|
|
53784
|
+
JSDisposableStack *s;
|
|
53785
|
+
|
|
53786
|
+
p = JS_VALUE_GET_OBJ(val);
|
|
53787
|
+
s = p->u.opaque;
|
|
53788
|
+
if (s) {
|
|
53789
|
+
js_disposable_stack_clear(rt, s);
|
|
53790
|
+
js_free_rt(rt, s);
|
|
53791
|
+
}
|
|
53792
|
+
}
|
|
53793
|
+
|
|
53794
|
+
static void js_disposable_stack_mark(JSRuntime *rt, JSValueConst val,
|
|
53795
|
+
JS_MarkFunc *mark_func)
|
|
53796
|
+
{
|
|
53797
|
+
JSObject *p;
|
|
53798
|
+
JSDisposableStack *s;
|
|
53799
|
+
int i;
|
|
53800
|
+
|
|
53801
|
+
p = JS_VALUE_GET_OBJ(val);
|
|
53802
|
+
s = p->u.opaque;
|
|
53803
|
+
if (s) {
|
|
53804
|
+
for (i = 0; i < s->resource_count; i++) {
|
|
53805
|
+
JS_MarkValue(rt, s->resources[i].value, mark_func);
|
|
53806
|
+
JS_MarkValue(rt, s->resources[i].method, mark_func);
|
|
53807
|
+
}
|
|
53808
|
+
}
|
|
53809
|
+
}
|
|
53810
|
+
|
|
53811
|
+
static JSDisposableStack *js_disposable_stack_get(JSContext *ctx,
|
|
53812
|
+
JSValueConst this_val,
|
|
53813
|
+
int class_id)
|
|
53814
|
+
{
|
|
53815
|
+
JSDisposableStack *s;
|
|
53816
|
+
s = JS_GetOpaque2(ctx, this_val, class_id);
|
|
53817
|
+
if (!s)
|
|
53818
|
+
return NULL;
|
|
53819
|
+
if (s->disposed) {
|
|
53820
|
+
JS_ThrowReferenceError(ctx, "DisposableStack has been disposed");
|
|
53821
|
+
return NULL;
|
|
53822
|
+
}
|
|
53823
|
+
return s;
|
|
53824
|
+
}
|
|
53825
|
+
|
|
53826
|
+
static JSValue js_disposable_stack_use(JSContext *ctx, JSValueConst this_val,
|
|
53827
|
+
int argc, JSValueConst *argv, int class_id)
|
|
53828
|
+
{
|
|
53829
|
+
JSDisposableStack *s;
|
|
53830
|
+
JSValueConst value;
|
|
53831
|
+
JSValue method;
|
|
53832
|
+
int hint = (class_id == JS_CLASS_ASYNC_DISPOSABLE_STACK) ? 1 : 0;
|
|
53833
|
+
|
|
53834
|
+
s = js_disposable_stack_get(ctx, this_val, class_id);
|
|
53835
|
+
if (!s)
|
|
53836
|
+
return JS_EXCEPTION;
|
|
53837
|
+
value = argv[0];
|
|
53838
|
+
if (JS_IsNull(value) || JS_IsUndefined(value)) {
|
|
53839
|
+
/* For async stacks, a null/undefined resource still needs a record
|
|
53840
|
+
so disposeAsync performs the required Await(undefined). */
|
|
53841
|
+
if (class_id == JS_CLASS_ASYNC_DISPOSABLE_STACK) {
|
|
53842
|
+
if (js_disposable_stack_add(ctx, s, JS_UNDEFINED, JS_UNDEFINED,
|
|
53843
|
+
JS_DISPOSE_HINT_SYNC) < 0)
|
|
53844
|
+
return JS_EXCEPTION;
|
|
53845
|
+
}
|
|
53846
|
+
return js_dup(value);
|
|
53847
|
+
}
|
|
53848
|
+
if (!JS_IsObject(value))
|
|
53849
|
+
return JS_ThrowTypeError(ctx, "not an object");
|
|
53850
|
+
method = js_get_dispose_method(ctx, value, hint);
|
|
53851
|
+
if (JS_IsException(method))
|
|
53852
|
+
return JS_EXCEPTION;
|
|
53853
|
+
if (js_disposable_stack_add(ctx, s, value, method, JS_DISPOSE_HINT_SYNC) < 0) {
|
|
53854
|
+
JS_FreeValue(ctx, method);
|
|
53855
|
+
return JS_EXCEPTION;
|
|
53856
|
+
}
|
|
53857
|
+
JS_FreeValue(ctx, method);
|
|
53858
|
+
return js_dup(value);
|
|
53859
|
+
}
|
|
53860
|
+
|
|
53861
|
+
static JSValue js_disposable_stack_adopt(JSContext *ctx, JSValueConst this_val,
|
|
53862
|
+
int argc, JSValueConst *argv, int class_id)
|
|
53863
|
+
{
|
|
53864
|
+
JSDisposableStack *s;
|
|
53865
|
+
JSValueConst value, on_dispose;
|
|
53866
|
+
|
|
53867
|
+
s = js_disposable_stack_get(ctx, this_val, class_id);
|
|
53868
|
+
if (!s)
|
|
53869
|
+
return JS_EXCEPTION;
|
|
53870
|
+
value = argv[0];
|
|
53871
|
+
on_dispose = argv[1];
|
|
53872
|
+
if (!JS_IsFunction(ctx, on_dispose))
|
|
53873
|
+
return JS_ThrowTypeError(ctx, "not a function");
|
|
53874
|
+
if (js_disposable_stack_add(ctx, s, value, on_dispose, JS_DISPOSE_HINT_ADOPT) < 0)
|
|
53875
|
+
return JS_EXCEPTION;
|
|
53876
|
+
return js_dup(value);
|
|
53877
|
+
}
|
|
53878
|
+
|
|
53879
|
+
static JSValue js_disposable_stack_defer(JSContext *ctx, JSValueConst this_val,
|
|
53880
|
+
int argc, JSValueConst *argv, int class_id)
|
|
53881
|
+
{
|
|
53882
|
+
JSDisposableStack *s;
|
|
53883
|
+
JSValueConst on_dispose;
|
|
53884
|
+
|
|
53885
|
+
s = js_disposable_stack_get(ctx, this_val, class_id);
|
|
53886
|
+
if (!s)
|
|
53887
|
+
return JS_EXCEPTION;
|
|
53888
|
+
on_dispose = argv[0];
|
|
53889
|
+
if (!JS_IsFunction(ctx, on_dispose))
|
|
53890
|
+
return JS_ThrowTypeError(ctx, "not a function");
|
|
53891
|
+
if (js_disposable_stack_add(ctx, s, JS_UNDEFINED, on_dispose, JS_DISPOSE_HINT_DEFER) < 0)
|
|
53892
|
+
return JS_EXCEPTION;
|
|
53893
|
+
return JS_UNDEFINED;
|
|
53894
|
+
}
|
|
53895
|
+
|
|
53896
|
+
/* Simple .then handler that discards its argument and returns undefined;
|
|
53897
|
+
used to normalize the chain's resolved value after all disposals. */
|
|
53898
|
+
static JSValue js_async_dispose_to_undef(JSContext *ctx, JSValueConst this_val,
|
|
53899
|
+
int argc, JSValueConst *argv,
|
|
53900
|
+
int magic, JSValueConst *func_data)
|
|
53901
|
+
{
|
|
53902
|
+
return JS_UNDEFINED;
|
|
53903
|
+
}
|
|
53904
|
+
|
|
53905
|
+
static JSValue js_async_dispose_rethrow(JSContext *ctx, JSValueConst this_val,
|
|
53906
|
+
int argc, JSValueConst *argv,
|
|
53907
|
+
int magic, JSValueConst *func_data)
|
|
53908
|
+
{
|
|
53909
|
+
JSValue prev_err = js_dup(func_data[0]);
|
|
53910
|
+
if (magic == 0) {
|
|
53911
|
+
return JS_Throw(ctx, prev_err);
|
|
53912
|
+
} else {
|
|
53913
|
+
JSValue se = js_new_suppressed_error(ctx, argv[0], prev_err);
|
|
53914
|
+
JS_FreeValue(ctx, prev_err);
|
|
53915
|
+
if (JS_IsException(se))
|
|
53916
|
+
return JS_EXCEPTION;
|
|
53917
|
+
return JS_Throw(ctx, se);
|
|
53918
|
+
}
|
|
53919
|
+
}
|
|
53920
|
+
|
|
53921
|
+
static JSValue js_async_dispose_step(JSContext *ctx, JSValueConst this_val,
|
|
53922
|
+
int argc, JSValueConst *argv,
|
|
53923
|
+
int magic, JSValueConst *func_data)
|
|
53924
|
+
{
|
|
53925
|
+
JSValueConst value = func_data[0];
|
|
53926
|
+
JSValueConst method = func_data[1];
|
|
53927
|
+
int hint = JS_VALUE_GET_INT(func_data[2]);
|
|
53928
|
+
bool has_prev_err = (magic == 1);
|
|
53929
|
+
JSValue ret;
|
|
53930
|
+
|
|
53931
|
+
if (JS_IsUndefined(method)) {
|
|
53932
|
+
/* null/undefined resource on async stack: Await(undefined) */
|
|
53933
|
+
if (has_prev_err)
|
|
53934
|
+
return JS_Throw(ctx, js_dup(argv[0]));
|
|
53935
|
+
return JS_UNDEFINED;
|
|
53936
|
+
}
|
|
53937
|
+
|
|
53938
|
+
switch (hint) {
|
|
53939
|
+
case JS_DISPOSE_HINT_ADOPT:
|
|
53940
|
+
ret = JS_Call(ctx, method, JS_UNDEFINED, 1, &value);
|
|
53941
|
+
break;
|
|
53942
|
+
case JS_DISPOSE_HINT_DEFER:
|
|
53943
|
+
ret = JS_Call(ctx, method, JS_UNDEFINED, 0, NULL);
|
|
53944
|
+
break;
|
|
53945
|
+
default:
|
|
53946
|
+
ret = JS_Call(ctx, method, value, 0, NULL);
|
|
53947
|
+
break;
|
|
53948
|
+
}
|
|
53949
|
+
|
|
53950
|
+
if (JS_IsException(ret)) {
|
|
53951
|
+
JSValue new_err = JS_GetException(ctx);
|
|
53952
|
+
if (has_prev_err) {
|
|
53953
|
+
JSValue se = js_new_suppressed_error(ctx, new_err, argv[0]);
|
|
53954
|
+
JS_FreeValue(ctx, new_err);
|
|
53955
|
+
if (JS_IsException(se))
|
|
53956
|
+
return JS_EXCEPTION;
|
|
53957
|
+
return JS_Throw(ctx, se);
|
|
53958
|
+
}
|
|
53959
|
+
return JS_Throw(ctx, new_err);
|
|
53960
|
+
}
|
|
53961
|
+
|
|
53962
|
+
if (!has_prev_err) {
|
|
53963
|
+
/* Propagate method result; next .then awaits it */
|
|
53964
|
+
return ret;
|
|
53965
|
+
}
|
|
53966
|
+
|
|
53967
|
+
/* Await ret, then rethrow the stored error (possibly wrapped) */
|
|
53968
|
+
{
|
|
53969
|
+
JSValueConst prev_err = argv[0];
|
|
53970
|
+
JSValue ret_promise, resolve_fn, reject_fn, then_args[2], result;
|
|
53971
|
+
ret_promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, vc(&ret), 0);
|
|
53972
|
+
JS_FreeValue(ctx, ret);
|
|
53973
|
+
if (JS_IsException(ret_promise))
|
|
53974
|
+
return JS_EXCEPTION;
|
|
53975
|
+
resolve_fn = JS_NewCFunctionData(ctx, js_async_dispose_rethrow, 0, 0,
|
|
53976
|
+
1, &prev_err);
|
|
53977
|
+
reject_fn = JS_NewCFunctionData(ctx, js_async_dispose_rethrow, 0, 1,
|
|
53978
|
+
1, &prev_err);
|
|
53979
|
+
then_args[0] = resolve_fn;
|
|
53980
|
+
then_args[1] = reject_fn;
|
|
53981
|
+
result = JS_Invoke(ctx, ret_promise, JS_ATOM_then, 2, vc(then_args));
|
|
53982
|
+
JS_FreeValue(ctx, resolve_fn);
|
|
53983
|
+
JS_FreeValue(ctx, reject_fn);
|
|
53984
|
+
JS_FreeValue(ctx, ret_promise);
|
|
53985
|
+
return result;
|
|
53986
|
+
}
|
|
53987
|
+
}
|
|
53988
|
+
|
|
53989
|
+
static JSValue js_disposable_stack_dispose(JSContext *ctx,
|
|
53990
|
+
JSValueConst this_val,
|
|
53991
|
+
int argc,
|
|
53992
|
+
JSValueConst *argv,
|
|
53993
|
+
int class_id)
|
|
53994
|
+
{
|
|
53995
|
+
JSDisposableStack *s;
|
|
53996
|
+
|
|
53997
|
+
s = JS_GetOpaque2(ctx, this_val, class_id);
|
|
53998
|
+
if (!s) {
|
|
53999
|
+
if (class_id == JS_CLASS_ASYNC_DISPOSABLE_STACK) {
|
|
54000
|
+
JSValue exc = JS_GetException(ctx);
|
|
54001
|
+
JSValue p = js_promise_resolve(ctx, ctx->promise_ctor, 1, vc(&exc),
|
|
54002
|
+
/*is_reject*/1);
|
|
54003
|
+
JS_FreeValue(ctx, exc);
|
|
54004
|
+
return p;
|
|
54005
|
+
}
|
|
54006
|
+
return JS_EXCEPTION;
|
|
54007
|
+
}
|
|
54008
|
+
if (s->disposed) {
|
|
54009
|
+
if (class_id == JS_CLASS_ASYNC_DISPOSABLE_STACK) {
|
|
54010
|
+
JSValue undef = JS_UNDEFINED;
|
|
54011
|
+
return js_promise_resolve(ctx, ctx->promise_ctor, 1, vc(&undef),
|
|
54012
|
+
/*is_reject*/0);
|
|
54013
|
+
}
|
|
54014
|
+
return JS_UNDEFINED;
|
|
54015
|
+
}
|
|
54016
|
+
if (class_id == JS_CLASS_ASYNC_DISPOSABLE_STACK) {
|
|
54017
|
+
/* Per spec DisposeResources: iterate resources in LIFO order and
|
|
54018
|
+
for each do Call + Await. The first Call happens synchronously
|
|
54019
|
+
inside disposeAsync(); subsequent Calls fire in microtasks via a
|
|
54020
|
+
Promise.then() chain so that each call sees the previous
|
|
54021
|
+
dispose's promise already settled. */
|
|
54022
|
+
int i, count = s->resource_count;
|
|
54023
|
+
JSValue chain, undef, ret;
|
|
54024
|
+
|
|
54025
|
+
s->disposed = true;
|
|
54026
|
+
|
|
54027
|
+
/* First (top-of-stack) resource: synchronous Call. */
|
|
54028
|
+
undef = JS_UNDEFINED;
|
|
54029
|
+
i = count - 1;
|
|
54030
|
+
if (i < 0) {
|
|
54031
|
+
chain = js_promise_resolve(ctx, ctx->promise_ctor, 1, vc(&undef),
|
|
54032
|
+
/*is_reject*/0);
|
|
54033
|
+
if (JS_IsException(chain))
|
|
54034
|
+
goto async_dispose_fail;
|
|
54035
|
+
} else {
|
|
54036
|
+
JSDisposableResource *res = &s->resources[i];
|
|
54037
|
+
if (JS_IsUndefined(res->method)) {
|
|
54038
|
+
/* null/undefined resource: Await(undefined) */
|
|
54039
|
+
chain = js_promise_resolve(ctx, ctx->promise_ctor, 1,
|
|
54040
|
+
vc(&undef), /*is_reject*/0);
|
|
54041
|
+
} else {
|
|
54042
|
+
switch (res->hint) {
|
|
54043
|
+
case JS_DISPOSE_HINT_ADOPT:
|
|
54044
|
+
ret = JS_Call(ctx, res->method, JS_UNDEFINED, 1,
|
|
54045
|
+
vc(&res->value));
|
|
54046
|
+
break;
|
|
54047
|
+
case JS_DISPOSE_HINT_DEFER:
|
|
54048
|
+
ret = JS_Call(ctx, res->method, JS_UNDEFINED, 0, NULL);
|
|
54049
|
+
break;
|
|
54050
|
+
default:
|
|
54051
|
+
ret = JS_Call(ctx, res->method, res->value, 0, NULL);
|
|
54052
|
+
break;
|
|
54053
|
+
}
|
|
54054
|
+
if (JS_IsException(ret)) {
|
|
54055
|
+
JSValue err = JS_GetException(ctx);
|
|
54056
|
+
chain = js_promise_resolve(ctx, ctx->promise_ctor, 1,
|
|
54057
|
+
vc(&err), /*is_reject*/1);
|
|
54058
|
+
JS_FreeValue(ctx, err);
|
|
54059
|
+
} else {
|
|
54060
|
+
chain = js_promise_resolve(ctx, ctx->promise_ctor, 1,
|
|
54061
|
+
vc(&ret), /*is_reject*/0);
|
|
54062
|
+
JS_FreeValue(ctx, ret);
|
|
54063
|
+
}
|
|
54064
|
+
}
|
|
54065
|
+
JS_FreeValue(ctx, res->value);
|
|
54066
|
+
JS_FreeValue(ctx, res->method);
|
|
54067
|
+
res->value = JS_UNDEFINED;
|
|
54068
|
+
res->method = JS_UNDEFINED;
|
|
54069
|
+
if (JS_IsException(chain)) {
|
|
54070
|
+
i--;
|
|
54071
|
+
goto async_dispose_fail;
|
|
54072
|
+
}
|
|
54073
|
+
i--;
|
|
54074
|
+
}
|
|
54075
|
+
|
|
54076
|
+
/* Remaining resources: chain lazy steps. */
|
|
54077
|
+
for (; i >= 0; i--) {
|
|
54078
|
+
JSDisposableResource *res = &s->resources[i];
|
|
54079
|
+
JSValueConst data[3];
|
|
54080
|
+
JSValue hint_val, resolve_fn, reject_fn, then_args[2], new_chain;
|
|
54081
|
+
|
|
54082
|
+
hint_val = JS_NewInt32(ctx, res->hint);
|
|
54083
|
+
data[0] = res->value;
|
|
54084
|
+
data[1] = res->method;
|
|
54085
|
+
data[2] = hint_val;
|
|
54086
|
+
resolve_fn = JS_NewCFunctionData(ctx, js_async_dispose_step, 0, 0,
|
|
54087
|
+
3, data);
|
|
54088
|
+
reject_fn = JS_NewCFunctionData(ctx, js_async_dispose_step, 0, 1,
|
|
54089
|
+
3, data);
|
|
54090
|
+
JS_FreeValue(ctx, hint_val);
|
|
54091
|
+
JS_FreeValue(ctx, res->value);
|
|
54092
|
+
JS_FreeValue(ctx, res->method);
|
|
54093
|
+
res->value = JS_UNDEFINED;
|
|
54094
|
+
res->method = JS_UNDEFINED;
|
|
54095
|
+
if (JS_IsException(resolve_fn) || JS_IsException(reject_fn)) {
|
|
54096
|
+
JS_FreeValue(ctx, resolve_fn);
|
|
54097
|
+
JS_FreeValue(ctx, reject_fn);
|
|
54098
|
+
JS_FreeValue(ctx, chain);
|
|
54099
|
+
chain = JS_EXCEPTION;
|
|
54100
|
+
goto async_dispose_fail;
|
|
54101
|
+
}
|
|
54102
|
+
then_args[0] = resolve_fn;
|
|
54103
|
+
then_args[1] = reject_fn;
|
|
54104
|
+
new_chain = JS_Invoke(ctx, chain, JS_ATOM_then, 2, vc(then_args));
|
|
54105
|
+
JS_FreeValue(ctx, resolve_fn);
|
|
54106
|
+
JS_FreeValue(ctx, reject_fn);
|
|
54107
|
+
JS_FreeValue(ctx, chain);
|
|
54108
|
+
if (JS_IsException(new_chain)) {
|
|
54109
|
+
chain = JS_EXCEPTION;
|
|
54110
|
+
goto async_dispose_fail;
|
|
54111
|
+
}
|
|
54112
|
+
chain = new_chain;
|
|
54113
|
+
}
|
|
54114
|
+
s->resource_count = 0;
|
|
54115
|
+
|
|
54116
|
+
if (count > 0) {
|
|
54117
|
+
JSValue undef_fn, then_args[1], new_chain;
|
|
54118
|
+
undef_fn = JS_NewCFunctionData(ctx, js_async_dispose_to_undef,
|
|
54119
|
+
0, 0, 0, NULL);
|
|
54120
|
+
if (JS_IsException(undef_fn)) {
|
|
54121
|
+
JS_FreeValue(ctx, chain);
|
|
54122
|
+
return JS_EXCEPTION;
|
|
54123
|
+
}
|
|
54124
|
+
then_args[0] = undef_fn;
|
|
54125
|
+
new_chain = JS_Invoke(ctx, chain, JS_ATOM_then, 1, vc(then_args));
|
|
54126
|
+
JS_FreeValue(ctx, undef_fn);
|
|
54127
|
+
JS_FreeValue(ctx, chain);
|
|
54128
|
+
return new_chain;
|
|
54129
|
+
}
|
|
54130
|
+
return chain;
|
|
54131
|
+
|
|
54132
|
+
async_dispose_fail:
|
|
54133
|
+
for (; i >= 0; i--) {
|
|
54134
|
+
JSDisposableResource *res = &s->resources[i];
|
|
54135
|
+
JS_FreeValue(ctx, res->value);
|
|
54136
|
+
JS_FreeValue(ctx, res->method);
|
|
54137
|
+
res->value = JS_UNDEFINED;
|
|
54138
|
+
res->method = JS_UNDEFINED;
|
|
54139
|
+
}
|
|
54140
|
+
s->resource_count = 0;
|
|
54141
|
+
return JS_EXCEPTION;
|
|
54142
|
+
}
|
|
54143
|
+
if (js_dispose_resources(ctx, s, JS_UNDEFINED) < 0)
|
|
54144
|
+
return JS_EXCEPTION;
|
|
54145
|
+
return JS_UNDEFINED;
|
|
54146
|
+
}
|
|
54147
|
+
|
|
54148
|
+
static JSValue js_disposable_stack_move(JSContext *ctx, JSValueConst this_val,
|
|
54149
|
+
int argc, JSValueConst *argv, int class_id)
|
|
54150
|
+
{
|
|
54151
|
+
JSDisposableStack *s, *ns;
|
|
54152
|
+
JSValue new_obj;
|
|
54153
|
+
|
|
54154
|
+
s = js_disposable_stack_get(ctx, this_val, class_id);
|
|
54155
|
+
if (!s)
|
|
54156
|
+
return JS_EXCEPTION;
|
|
54157
|
+
/* Use the intrinsic prototype directly so tampering with the global
|
|
54158
|
+
binding or subclassing cannot redirect move(). */
|
|
54159
|
+
new_obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id],
|
|
54160
|
+
class_id);
|
|
54161
|
+
if (JS_IsException(new_obj))
|
|
54162
|
+
return JS_EXCEPTION;
|
|
54163
|
+
ns = js_mallocz(ctx, sizeof(*ns));
|
|
54164
|
+
if (!ns) {
|
|
54165
|
+
JS_FreeValue(ctx, new_obj);
|
|
54166
|
+
return JS_EXCEPTION;
|
|
54167
|
+
}
|
|
54168
|
+
JS_SetOpaqueInternal(new_obj, ns);
|
|
54169
|
+
/* Transfer resources to new stack */
|
|
54170
|
+
ns->resources = s->resources;
|
|
54171
|
+
ns->resource_count = s->resource_count;
|
|
54172
|
+
ns->resource_capacity = s->resource_capacity;
|
|
54173
|
+
/* Reset original stack */
|
|
54174
|
+
s->resources = NULL;
|
|
54175
|
+
s->resource_count = 0;
|
|
54176
|
+
s->resource_capacity = 0;
|
|
54177
|
+
s->disposed = true;
|
|
54178
|
+
return new_obj;
|
|
54179
|
+
}
|
|
54180
|
+
|
|
54181
|
+
static JSValue js_disposable_stack_get_disposed(JSContext *ctx,
|
|
54182
|
+
JSValueConst this_val, int class_id)
|
|
54183
|
+
{
|
|
54184
|
+
JSDisposableStack *s;
|
|
54185
|
+
|
|
54186
|
+
s = JS_GetOpaque2(ctx, this_val, class_id);
|
|
54187
|
+
if (!s)
|
|
54188
|
+
return JS_EXCEPTION;
|
|
54189
|
+
return js_bool(s->disposed);
|
|
54190
|
+
}
|
|
54191
|
+
|
|
54192
|
+
static const JSCFunctionListEntry js_disposable_stack_proto_funcs[] = {
|
|
54193
|
+
JS_CFUNC_MAGIC_DEF("adopt", 2, js_disposable_stack_adopt, JS_CLASS_DISPOSABLE_STACK ),
|
|
54194
|
+
JS_CFUNC_MAGIC_DEF("defer", 1, js_disposable_stack_defer, JS_CLASS_DISPOSABLE_STACK ),
|
|
54195
|
+
JS_CFUNC_MAGIC_DEF("dispose", 0, js_disposable_stack_dispose, JS_CLASS_DISPOSABLE_STACK ),
|
|
54196
|
+
JS_CFUNC_MAGIC_DEF("move", 0, js_disposable_stack_move, JS_CLASS_DISPOSABLE_STACK ),
|
|
54197
|
+
JS_CFUNC_MAGIC_DEF("use", 1, js_disposable_stack_use, JS_CLASS_DISPOSABLE_STACK ),
|
|
54198
|
+
JS_CGETSET_MAGIC_DEF("disposed", js_disposable_stack_get_disposed, NULL, JS_CLASS_DISPOSABLE_STACK ),
|
|
54199
|
+
JS_ALIAS_DEF("[Symbol.dispose]", "dispose" ),
|
|
54200
|
+
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DisposableStack", JS_PROP_CONFIGURABLE ),
|
|
54201
|
+
};
|
|
54202
|
+
|
|
54203
|
+
static const JSCFunctionListEntry js_async_disposable_stack_proto_funcs[] = {
|
|
54204
|
+
JS_CFUNC_MAGIC_DEF("adopt", 2, js_disposable_stack_adopt, JS_CLASS_ASYNC_DISPOSABLE_STACK ),
|
|
54205
|
+
JS_CFUNC_MAGIC_DEF("defer", 1, js_disposable_stack_defer, JS_CLASS_ASYNC_DISPOSABLE_STACK ),
|
|
54206
|
+
JS_CFUNC_MAGIC_DEF("disposeAsync", 0, js_disposable_stack_dispose, JS_CLASS_ASYNC_DISPOSABLE_STACK ),
|
|
54207
|
+
JS_CFUNC_MAGIC_DEF("move", 0, js_disposable_stack_move, JS_CLASS_ASYNC_DISPOSABLE_STACK ),
|
|
54208
|
+
JS_CFUNC_MAGIC_DEF("use", 1, js_disposable_stack_use, JS_CLASS_ASYNC_DISPOSABLE_STACK ),
|
|
54209
|
+
JS_CGETSET_MAGIC_DEF("disposed", js_disposable_stack_get_disposed, NULL, JS_CLASS_ASYNC_DISPOSABLE_STACK ),
|
|
54210
|
+
JS_ALIAS_DEF("[Symbol.asyncDispose]", "disposeAsync" ),
|
|
54211
|
+
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncDisposableStack", JS_PROP_CONFIGURABLE),
|
|
54212
|
+
};
|
|
54213
|
+
|
|
52732
54214
|
/* Promise */
|
|
52733
54215
|
|
|
52734
54216
|
typedef struct JSPromiseData {
|
|
@@ -53877,6 +55359,7 @@ static JSValue js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx,
|
|
|
53877
55359
|
|
|
53878
55360
|
static const JSCFunctionListEntry js_async_iterator_proto_funcs[] = {
|
|
53879
55361
|
JS_CFUNC_DEF("[Symbol.asyncIterator]", 0, js_iterator_proto_iterator ),
|
|
55362
|
+
JS_CFUNC_DEF("[Symbol.asyncDispose]", 0, js_async_iterator_proto_dispose ),
|
|
53880
55363
|
};
|
|
53881
55364
|
|
|
53882
55365
|
/* AsyncFromSyncIteratorPrototype */
|
|
@@ -54075,6 +55558,7 @@ static JSClassShortDef const js_async_class_def[] = {
|
|
|
54075
55558
|
{ JS_ATOM_empty_string, js_async_from_sync_iterator_finalizer, js_async_from_sync_iterator_mark }, /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
|
|
54076
55559
|
{ JS_ATOM_AsyncGeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_ASYNC_GENERATOR_FUNCTION */
|
|
54077
55560
|
{ JS_ATOM_AsyncGenerator, js_async_generator_finalizer, js_async_generator_mark }, /* JS_CLASS_ASYNC_GENERATOR */
|
|
55561
|
+
{ JS_ATOM_AsyncDisposableStack, js_disposable_stack_finalizer, js_disposable_stack_mark }, /* JS_CLASS_ASYNC_DISPOSABLE_STACK */
|
|
54078
55562
|
};
|
|
54079
55563
|
|
|
54080
55564
|
int JS_AddIntrinsicPromise(JSContext *ctx)
|
|
@@ -54154,9 +55638,21 @@ int JS_AddIntrinsicPromise(JSContext *ctx)
|
|
|
54154
55638
|
return -1;
|
|
54155
55639
|
JS_FreeValue(ctx, obj1);
|
|
54156
55640
|
|
|
54157
|
-
|
|
54158
|
-
|
|
54159
|
-
|
|
55641
|
+
if (JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
|
|
55642
|
+
ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
|
|
55643
|
+
JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE))
|
|
55644
|
+
return -1;
|
|
55645
|
+
|
|
55646
|
+
/* AsyncDisposableStack */
|
|
55647
|
+
ctx->class_proto[JS_CLASS_ASYNC_DISPOSABLE_STACK] = JS_NewObject(ctx);
|
|
55648
|
+
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ASYNC_DISPOSABLE_STACK],
|
|
55649
|
+
js_async_disposable_stack_proto_funcs,
|
|
55650
|
+
countof(js_async_disposable_stack_proto_funcs));
|
|
55651
|
+
JS_NewGlobalCConstructorMagic(ctx, "AsyncDisposableStack",
|
|
55652
|
+
js_disposable_stack_constructor, 0,
|
|
55653
|
+
ctx->class_proto[JS_CLASS_ASYNC_DISPOSABLE_STACK],
|
|
55654
|
+
JS_CLASS_ASYNC_DISPOSABLE_STACK);
|
|
55655
|
+
return 0;
|
|
54160
55656
|
}
|
|
54161
55657
|
|
|
54162
55658
|
/* URI handling */
|
|
@@ -55830,6 +57326,7 @@ static const char * const native_error_name[JS_NATIVE_ERROR_COUNT] = {
|
|
|
55830
57326
|
"EvalError", "RangeError", "ReferenceError",
|
|
55831
57327
|
"SyntaxError", "TypeError", "URIError",
|
|
55832
57328
|
"InternalError", "AggregateError",
|
|
57329
|
+
"SuppressedError",
|
|
55833
57330
|
};
|
|
55834
57331
|
|
|
55835
57332
|
/* Minimum amount of objects to be able to compile code and display
|
|
@@ -55978,7 +57475,16 @@ int JS_AddIntrinsicBaseObjects(JSContext *ctx)
|
|
|
55978
57475
|
for(int i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
|
|
55979
57476
|
JSValue func_obj;
|
|
55980
57477
|
int n_args;
|
|
55981
|
-
|
|
57478
|
+
switch (i) {
|
|
57479
|
+
case JS_AGGREGATE_ERROR:
|
|
57480
|
+
n_args = 2;
|
|
57481
|
+
break;
|
|
57482
|
+
case JS_SUPPRESSED_ERROR:
|
|
57483
|
+
n_args = 3;
|
|
57484
|
+
break;
|
|
57485
|
+
default:
|
|
57486
|
+
n_args = 1;
|
|
57487
|
+
}
|
|
55982
57488
|
func_obj = JS_NewCFunction3(ctx, ft.generic,
|
|
55983
57489
|
native_error_name[i], n_args,
|
|
55984
57490
|
JS_CFUNC_constructor_or_func_magic, i,
|
|
@@ -56176,6 +57682,16 @@ int JS_AddIntrinsicBaseObjects(JSContext *ctx)
|
|
|
56176
57682
|
JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE))
|
|
56177
57683
|
return -1;
|
|
56178
57684
|
|
|
57685
|
+
/* explicit resource management */
|
|
57686
|
+
ctx->class_proto[JS_CLASS_DISPOSABLE_STACK] = JS_NewObject(ctx);
|
|
57687
|
+
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DISPOSABLE_STACK],
|
|
57688
|
+
js_disposable_stack_proto_funcs,
|
|
57689
|
+
countof(js_disposable_stack_proto_funcs));
|
|
57690
|
+
JS_NewGlobalCConstructorMagic(ctx, "DisposableStack",
|
|
57691
|
+
js_disposable_stack_constructor, 0,
|
|
57692
|
+
ctx->class_proto[JS_CLASS_DISPOSABLE_STACK],
|
|
57693
|
+
JS_CLASS_DISPOSABLE_STACK);
|
|
57694
|
+
|
|
56179
57695
|
/* global properties */
|
|
56180
57696
|
ctx->eval_obj = JS_GetProperty(ctx, ctx->global_obj, JS_ATOM_eval);
|
|
56181
57697
|
if (JS_IsException(ctx->eval_obj))
|
|
@@ -59885,6 +61401,8 @@ static int JS_AddIntrinsicAtomics(JSContext *ctx)
|
|
|
59885
61401
|
|
|
59886
61402
|
#endif /* CONFIG_ATOMICS */
|
|
59887
61403
|
|
|
61404
|
+
static int js_uint8array_funcs_init(JSContext *ctx);
|
|
61405
|
+
|
|
59888
61406
|
int JS_AddIntrinsicTypedArrays(JSContext *ctx)
|
|
59889
61407
|
{
|
|
59890
61408
|
JSValue typed_array_base_func, typed_array_base_proto, obj;
|
|
@@ -59959,6 +61477,10 @@ int JS_AddIntrinsicTypedArrays(JSContext *ctx)
|
|
|
59959
61477
|
}
|
|
59960
61478
|
JS_FreeValue(ctx, typed_array_base_func);
|
|
59961
61479
|
|
|
61480
|
+
/* Uint8Array base64/hex methods */
|
|
61481
|
+
if (js_uint8array_funcs_init(ctx))
|
|
61482
|
+
return -1;
|
|
61483
|
+
|
|
59962
61484
|
/* DataView */
|
|
59963
61485
|
obj = JS_NewCConstructor(ctx, JS_CLASS_DATAVIEW, "DataView",
|
|
59964
61486
|
js_dataview_constructor, 1, JS_CFUNC_constructor, 0,
|
|
@@ -60829,6 +62351,993 @@ int JS_AddIntrinsicDOMException(JSContext *ctx)
|
|
|
60829
62351
|
ctx->class_proto[JS_CLASS_DOM_EXCEPTION] = proto;
|
|
60830
62352
|
return 0;
|
|
60831
62353
|
}
|
|
62354
|
+
/* base64 */
|
|
62355
|
+
|
|
62356
|
+
static const unsigned char b64_enc[64] = {
|
|
62357
|
+
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
|
|
62358
|
+
'Q','R','S','T','U','V','W','X','Y','Z',
|
|
62359
|
+
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p',
|
|
62360
|
+
'q','r','s','t','u','v','w','x','y','z',
|
|
62361
|
+
'0','1','2','3','4','5','6','7','8','9',
|
|
62362
|
+
'+','/'
|
|
62363
|
+
};
|
|
62364
|
+
|
|
62365
|
+
static const unsigned char b64url_enc[64] = {
|
|
62366
|
+
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
|
|
62367
|
+
'Q','R','S','T','U','V','W','X','Y','Z',
|
|
62368
|
+
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p',
|
|
62369
|
+
'q','r','s','t','u','v','w','x','y','z',
|
|
62370
|
+
'0','1','2','3','4','5','6','7','8','9',
|
|
62371
|
+
'-','_'
|
|
62372
|
+
};
|
|
62373
|
+
|
|
62374
|
+
enum { K_VAL = 1u, K_WS = 2u };
|
|
62375
|
+
|
|
62376
|
+
static const uint8_t b64_val[256] = {
|
|
62377
|
+
['A']=0, ['B']=1, ['C']=2, ['D']=3, ['E']=4, ['F']=5, ['G']=6, ['H']=7,
|
|
62378
|
+
['I']=8, ['J']=9, ['K']=10,['L']=11,['M']=12,['N']=13,['O']=14,['P']=15,
|
|
62379
|
+
['Q']=16,['R']=17,['S']=18,['T']=19,['U']=20,['V']=21,['W']=22,['X']=23,['Y']=24,['Z']=25,
|
|
62380
|
+
['a']=26,['b']=27,['c']=28,['d']=29,['e']=30,['f']=31,['g']=32,['h']=33,
|
|
62381
|
+
['i']=34,['j']=35,['k']=36,['l']=37,['m']=38,['n']=39,['o']=40,['p']=41,
|
|
62382
|
+
['q']=42,['r']=43,['s']=44,['t']=45,['u']=46,['v']=47,['w']=48,['x']=49,['y']=50,['z']=51,
|
|
62383
|
+
['0']=52,['1']=53,['2']=54,['3']=55,['4']=56,['5']=57,['6']=58,['7']=59,['8']=60,['9']=61,
|
|
62384
|
+
['+']=62, ['/']=63,
|
|
62385
|
+
['-']=62, ['_']=63,
|
|
62386
|
+
};
|
|
62387
|
+
|
|
62388
|
+
static const char b64_flags[256] = {
|
|
62389
|
+
[' ']=K_WS, ['\t']=K_WS, ['\n']=K_WS, ['\f']=K_WS, ['\r']=K_WS,
|
|
62390
|
+
['A']=K_VAL,['B']=K_VAL,['C']=K_VAL,['D']=K_VAL,['E']=K_VAL,['F']=K_VAL,['G']=K_VAL,['H']=K_VAL,
|
|
62391
|
+
['I']=K_VAL,['J']=K_VAL,['K']=K_VAL,['L']=K_VAL,['M']=K_VAL,['N']=K_VAL,['O']=K_VAL,['P']=K_VAL,
|
|
62392
|
+
['Q']=K_VAL,['R']=K_VAL,['S']=K_VAL,['T']=K_VAL,['U']=K_VAL,['V']=K_VAL,['W']=K_VAL,['X']=K_VAL,
|
|
62393
|
+
['Y']=K_VAL,['Z']=K_VAL,
|
|
62394
|
+
['a']=K_VAL,['b']=K_VAL,['c']=K_VAL,['d']=K_VAL,['e']=K_VAL,['f']=K_VAL,['g']=K_VAL,['h']=K_VAL,
|
|
62395
|
+
['i']=K_VAL,['j']=K_VAL,['k']=K_VAL,['l']=K_VAL,['m']=K_VAL,['n']=K_VAL,['o']=K_VAL,['p']=K_VAL,
|
|
62396
|
+
['q']=K_VAL,['r']=K_VAL,['s']=K_VAL,['t']=K_VAL,['u']=K_VAL,['v']=K_VAL,['w']=K_VAL,['x']=K_VAL,
|
|
62397
|
+
['y']=K_VAL,['z']=K_VAL,
|
|
62398
|
+
['0']=K_VAL,['1']=K_VAL,['2']=K_VAL,['3']=K_VAL,['4']=K_VAL,['5']=K_VAL,['6']=K_VAL,['7']=K_VAL,
|
|
62399
|
+
['8']=K_VAL,['9']=K_VAL,
|
|
62400
|
+
['+']=K_VAL,['/']=K_VAL,
|
|
62401
|
+
};
|
|
62402
|
+
|
|
62403
|
+
static const char b64_flags_url[256] = {
|
|
62404
|
+
[' ']=K_WS, ['\t']=K_WS, ['\n']=K_WS, ['\f']=K_WS, ['\r']=K_WS,
|
|
62405
|
+
['A']=K_VAL,['B']=K_VAL,['C']=K_VAL,['D']=K_VAL,['E']=K_VAL,['F']=K_VAL,['G']=K_VAL,['H']=K_VAL,
|
|
62406
|
+
['I']=K_VAL,['J']=K_VAL,['K']=K_VAL,['L']=K_VAL,['M']=K_VAL,['N']=K_VAL,['O']=K_VAL,['P']=K_VAL,
|
|
62407
|
+
['Q']=K_VAL,['R']=K_VAL,['S']=K_VAL,['T']=K_VAL,['U']=K_VAL,['V']=K_VAL,['W']=K_VAL,['X']=K_VAL,
|
|
62408
|
+
['Y']=K_VAL,['Z']=K_VAL,
|
|
62409
|
+
['a']=K_VAL,['b']=K_VAL,['c']=K_VAL,['d']=K_VAL,['e']=K_VAL,['f']=K_VAL,['g']=K_VAL,['h']=K_VAL,
|
|
62410
|
+
['i']=K_VAL,['j']=K_VAL,['k']=K_VAL,['l']=K_VAL,['m']=K_VAL,['n']=K_VAL,['o']=K_VAL,['p']=K_VAL,
|
|
62411
|
+
['q']=K_VAL,['r']=K_VAL,['s']=K_VAL,['t']=K_VAL,['u']=K_VAL,['v']=K_VAL,['w']=K_VAL,['x']=K_VAL,
|
|
62412
|
+
['y']=K_VAL,['z']=K_VAL,
|
|
62413
|
+
['0']=K_VAL,['1']=K_VAL,['2']=K_VAL,['3']=K_VAL,['4']=K_VAL,['5']=K_VAL,['6']=K_VAL,['7']=K_VAL,
|
|
62414
|
+
['8']=K_VAL,['9']=K_VAL,
|
|
62415
|
+
['-']=K_VAL,['_']=K_VAL,
|
|
62416
|
+
};
|
|
62417
|
+
|
|
62418
|
+
static size_t b64_encode(const uint8_t *src, size_t len, char *dst,
|
|
62419
|
+
const unsigned char *alpha)
|
|
62420
|
+
{
|
|
62421
|
+
size_t i = 0, j = 0;
|
|
62422
|
+
size_t main_len = (len / 3) * 3;
|
|
62423
|
+
|
|
62424
|
+
for (; i < main_len; i += 3, j += 4) {
|
|
62425
|
+
uint32_t v = 65536*src[i] + 256*src[i + 1] + src[i + 2];
|
|
62426
|
+
dst[j + 0] = alpha[(v >> 18) & 63];
|
|
62427
|
+
dst[j + 1] = alpha[(v >> 12) & 63];
|
|
62428
|
+
dst[j + 2] = alpha[(v >> 6) & 63];
|
|
62429
|
+
dst[j + 3] = alpha[v & 63];
|
|
62430
|
+
}
|
|
62431
|
+
|
|
62432
|
+
size_t rem = len - i;
|
|
62433
|
+
if (rem == 1) {
|
|
62434
|
+
uint32_t v = 65536*src[i];
|
|
62435
|
+
dst[j++] = alpha[(v >> 18) & 63];
|
|
62436
|
+
dst[j++] = alpha[(v >> 12) & 63];
|
|
62437
|
+
dst[j++] = '=';
|
|
62438
|
+
dst[j++] = '=';
|
|
62439
|
+
} else if (rem == 2) {
|
|
62440
|
+
uint32_t v = 65536*src[i] + 256*src[i + 1];
|
|
62441
|
+
dst[j++] = alpha[(v >> 18) & 63];
|
|
62442
|
+
dst[j++] = alpha[(v >> 12) & 63];
|
|
62443
|
+
dst[j++] = alpha[(v >> 6) & 63];
|
|
62444
|
+
dst[j++] = '=';
|
|
62445
|
+
}
|
|
62446
|
+
return j;
|
|
62447
|
+
}
|
|
62448
|
+
|
|
62449
|
+
/* Implements https://infra.spec.whatwg.org/#forgiving-base64-decode */
|
|
62450
|
+
static size_t
|
|
62451
|
+
b64_decode(const char *src, size_t len, uint8_t *dst, int *err)
|
|
62452
|
+
{
|
|
62453
|
+
size_t i, j;
|
|
62454
|
+
uint32_t acc;
|
|
62455
|
+
int seen, pad;
|
|
62456
|
+
unsigned ch;
|
|
62457
|
+
|
|
62458
|
+
acc = 0;
|
|
62459
|
+
seen = 0;
|
|
62460
|
+
for (i = 0, j = 0; i < len; i++) {
|
|
62461
|
+
ch = (unsigned char)src[i];
|
|
62462
|
+
if ((b64_flags[ch] & K_WS))
|
|
62463
|
+
continue;
|
|
62464
|
+
if (!(b64_flags[ch] & K_VAL))
|
|
62465
|
+
break;
|
|
62466
|
+
acc = (acc << 6) | b64_val[ch];
|
|
62467
|
+
seen++;
|
|
62468
|
+
if (seen == 4) {
|
|
62469
|
+
dst[j++] = (acc >> 16) & 0xFF;
|
|
62470
|
+
dst[j++] = (acc >> 8) & 0xFF;
|
|
62471
|
+
dst[j++] = acc & 0xFF;
|
|
62472
|
+
seen = 0;
|
|
62473
|
+
acc = 0;
|
|
62474
|
+
}
|
|
62475
|
+
}
|
|
62476
|
+
|
|
62477
|
+
if (seen != 0) {
|
|
62478
|
+
if (seen == 3) {
|
|
62479
|
+
dst[j++] = (acc >> 10) & 0xFF;
|
|
62480
|
+
dst[j++] = (acc >> 2) & 0xFF;
|
|
62481
|
+
} else if (seen == 2) {
|
|
62482
|
+
dst[j++] = (acc >> 4) & 0xFF;
|
|
62483
|
+
} else {
|
|
62484
|
+
*err = 1;
|
|
62485
|
+
return 0;
|
|
62486
|
+
}
|
|
62487
|
+
for (pad = 0; i < len; i++) {
|
|
62488
|
+
ch = (unsigned char)src[i];
|
|
62489
|
+
if (pad < 2 && ch == '=')
|
|
62490
|
+
pad++;
|
|
62491
|
+
else if (!(b64_flags[ch] & K_WS))
|
|
62492
|
+
break;
|
|
62493
|
+
}
|
|
62494
|
+
if (pad != 0 && seen + pad != 4) {
|
|
62495
|
+
*err = 1;
|
|
62496
|
+
return 0;
|
|
62497
|
+
}
|
|
62498
|
+
}
|
|
62499
|
+
|
|
62500
|
+
*err = i < len;
|
|
62501
|
+
return j;
|
|
62502
|
+
}
|
|
62503
|
+
|
|
62504
|
+
static JSValue js_btoa(JSContext *ctx, JSValueConst this_val,
|
|
62505
|
+
int argc, JSValueConst *argv)
|
|
62506
|
+
{
|
|
62507
|
+
const uint8_t *in8;
|
|
62508
|
+
uint8_t *tmp = NULL;
|
|
62509
|
+
uint8_t *outp;
|
|
62510
|
+
JSValue val, ret = JS_EXCEPTION;
|
|
62511
|
+
JSString *s, *ostr;
|
|
62512
|
+
size_t len, out_len, written;
|
|
62513
|
+
|
|
62514
|
+
val = JS_ToString(ctx, argv[0]);
|
|
62515
|
+
if (unlikely(JS_IsException(val)))
|
|
62516
|
+
return JS_EXCEPTION;
|
|
62517
|
+
|
|
62518
|
+
s = JS_VALUE_GET_STRING(val);
|
|
62519
|
+
len = (size_t)s->len;
|
|
62520
|
+
|
|
62521
|
+
if (likely(!s->is_wide_char)) {
|
|
62522
|
+
in8 = (const uint8_t *)str8(s);
|
|
62523
|
+
} else {
|
|
62524
|
+
const uint16_t *src = str16(s);
|
|
62525
|
+
tmp = js_malloc(ctx, likely(len) ? len : 1);
|
|
62526
|
+
if (unlikely(!tmp))
|
|
62527
|
+
goto fail;
|
|
62528
|
+
for (size_t i = 0; i < len; i++) {
|
|
62529
|
+
uint32_t c = src[i];
|
|
62530
|
+
if (unlikely(c > 0xFF)) {
|
|
62531
|
+
JS_ThrowDOMException(ctx, "InvalidCharacterError",
|
|
62532
|
+
"String contains an invalid character");
|
|
62533
|
+
goto fail;
|
|
62534
|
+
}
|
|
62535
|
+
tmp[i] = (uint8_t)c;
|
|
62536
|
+
}
|
|
62537
|
+
in8 = tmp;
|
|
62538
|
+
}
|
|
62539
|
+
|
|
62540
|
+
if (unlikely(len > (SIZE_MAX - 2) / 3)) {
|
|
62541
|
+
JS_ThrowRangeError(ctx, "input too large");
|
|
62542
|
+
goto fail;
|
|
62543
|
+
}
|
|
62544
|
+
out_len = 4 * ((len + 2) / 3);
|
|
62545
|
+
if (unlikely(out_len > JS_STRING_LEN_MAX)) {
|
|
62546
|
+
JS_ThrowRangeError(ctx, "output too large");
|
|
62547
|
+
goto fail;
|
|
62548
|
+
}
|
|
62549
|
+
|
|
62550
|
+
ostr = js_alloc_string(ctx, out_len, 0);
|
|
62551
|
+
if (unlikely(!ostr))
|
|
62552
|
+
goto fail;
|
|
62553
|
+
|
|
62554
|
+
outp = str8(ostr);
|
|
62555
|
+
written = b64_encode(in8, len, (char *)outp, b64_enc);
|
|
62556
|
+
outp[written] = '\0';
|
|
62557
|
+
ostr->len = out_len;
|
|
62558
|
+
ret = JS_MKPTR(JS_TAG_STRING, ostr);
|
|
62559
|
+
fail:
|
|
62560
|
+
if (tmp)
|
|
62561
|
+
js_free(ctx, tmp);
|
|
62562
|
+
JS_FreeValue(ctx, val);
|
|
62563
|
+
return ret;
|
|
62564
|
+
}
|
|
62565
|
+
|
|
62566
|
+
static JSValue js_atob(JSContext *ctx, JSValueConst this_val,
|
|
62567
|
+
int argc, JSValueConst *argv)
|
|
62568
|
+
{
|
|
62569
|
+
const uint8_t *in;
|
|
62570
|
+
uint8_t *tmp = NULL, *outp;
|
|
62571
|
+
JSValue val, ret = JS_EXCEPTION;
|
|
62572
|
+
JSString *s, *ostr;
|
|
62573
|
+
size_t slen, out_cap, out_len;
|
|
62574
|
+
int err;
|
|
62575
|
+
|
|
62576
|
+
val = JS_ToString(ctx, argv[0]);
|
|
62577
|
+
if (unlikely(JS_IsException(val)))
|
|
62578
|
+
return JS_EXCEPTION;
|
|
62579
|
+
|
|
62580
|
+
s = JS_VALUE_GET_STRING(val);
|
|
62581
|
+
slen = (size_t)s->len;
|
|
62582
|
+
|
|
62583
|
+
if (likely(!s->is_wide_char)) {
|
|
62584
|
+
const uint8_t *p = (const uint8_t *)str8(s);
|
|
62585
|
+
for (size_t i = 0; i < slen; i++) {
|
|
62586
|
+
if (unlikely(p[i] & 0x80)) {
|
|
62587
|
+
JS_ThrowDOMException(ctx, "InvalidCharacterError",
|
|
62588
|
+
"The string to be decoded is not correctly encoded");
|
|
62589
|
+
goto fail;
|
|
62590
|
+
}
|
|
62591
|
+
}
|
|
62592
|
+
in = p;
|
|
62593
|
+
} else {
|
|
62594
|
+
const uint16_t *src = str16(s);
|
|
62595
|
+
tmp = js_malloc(ctx, likely(slen) ? slen : 1);
|
|
62596
|
+
if (unlikely(!tmp))
|
|
62597
|
+
goto fail;
|
|
62598
|
+
for (size_t i = 0; i < slen; i++) {
|
|
62599
|
+
if (unlikely(src[i] > 0x7F)) {
|
|
62600
|
+
JS_ThrowDOMException(ctx, "InvalidCharacterError",
|
|
62601
|
+
"The string to be decoded is not correctly encoded");
|
|
62602
|
+
goto fail;
|
|
62603
|
+
}
|
|
62604
|
+
tmp[i] = (uint8_t)src[i];
|
|
62605
|
+
}
|
|
62606
|
+
in = tmp;
|
|
62607
|
+
}
|
|
62608
|
+
|
|
62609
|
+
if (unlikely(slen > (SIZE_MAX / 3) * 4)) {
|
|
62610
|
+
JS_ThrowRangeError(ctx, "input too large");
|
|
62611
|
+
goto fail;
|
|
62612
|
+
}
|
|
62613
|
+
out_cap = (slen / 4) * 3 + 3;
|
|
62614
|
+
if (unlikely(out_cap > JS_STRING_LEN_MAX)) {
|
|
62615
|
+
JS_ThrowRangeError(ctx, "output too large");
|
|
62616
|
+
goto fail;
|
|
62617
|
+
}
|
|
62618
|
+
|
|
62619
|
+
ostr = js_alloc_string(ctx, out_cap, 0);
|
|
62620
|
+
if (unlikely(!ostr))
|
|
62621
|
+
goto fail;
|
|
62622
|
+
|
|
62623
|
+
outp = str8(ostr);
|
|
62624
|
+
err = 0;
|
|
62625
|
+
out_len = b64_decode((const char *)in, slen, outp, &err);
|
|
62626
|
+
|
|
62627
|
+
if (unlikely(err)) {
|
|
62628
|
+
js_free_string(ctx->rt, ostr);
|
|
62629
|
+
JS_ThrowDOMException(ctx, "InvalidCharacterError",
|
|
62630
|
+
"The string to be decoded is not correctly encoded");
|
|
62631
|
+
goto fail;
|
|
62632
|
+
}
|
|
62633
|
+
outp[out_len] = '\0';
|
|
62634
|
+
ostr->len = out_len;
|
|
62635
|
+
ret = JS_MKPTR(JS_TAG_STRING, ostr);
|
|
62636
|
+
fail:
|
|
62637
|
+
if (tmp)
|
|
62638
|
+
js_free(ctx, tmp);
|
|
62639
|
+
JS_FreeValue(ctx, val);
|
|
62640
|
+
return ret;
|
|
62641
|
+
}
|
|
62642
|
+
|
|
62643
|
+
static const JSCFunctionListEntry js_base64_funcs[] = {
|
|
62644
|
+
JS_CFUNC_DEF("btoa", 1, js_btoa),
|
|
62645
|
+
JS_CFUNC_DEF("atob", 1, js_atob),
|
|
62646
|
+
};
|
|
62647
|
+
|
|
62648
|
+
|
|
62649
|
+
/* Uint8Array base64/hex (tc39 proposal-arraybuffer-base64) */
|
|
62650
|
+
|
|
62651
|
+
enum {
|
|
62652
|
+
B64_ALPHABET_BASE64 = 0,
|
|
62653
|
+
B64_ALPHABET_BASE64URL = 1,
|
|
62654
|
+
};
|
|
62655
|
+
|
|
62656
|
+
enum {
|
|
62657
|
+
B64_LAST_LOOSE = 0,
|
|
62658
|
+
B64_LAST_STRICT = 1,
|
|
62659
|
+
B64_LAST_STOP_BEFORE_PARTIAL = 2,
|
|
62660
|
+
};
|
|
62661
|
+
|
|
62662
|
+
|
|
62663
|
+
static size_t b64_skip_ws(const char *src, size_t len, size_t index,
|
|
62664
|
+
const char *flags)
|
|
62665
|
+
{
|
|
62666
|
+
while (index < len && (flags[(unsigned char)src[index]] & K_WS))
|
|
62667
|
+
index++;
|
|
62668
|
+
return index;
|
|
62669
|
+
}
|
|
62670
|
+
|
|
62671
|
+
/* Implements the FromBase64 abstract operation.
|
|
62672
|
+
src/src_len: the input string (must be ASCII/latin1)
|
|
62673
|
+
dst/max_len: output buffer
|
|
62674
|
+
flags: b64_flags or b64_flags_url (selects valid characters)
|
|
62675
|
+
last_chunk: B64_LAST_LOOSE, B64_LAST_STRICT, or B64_LAST_STOP_BEFORE_PARTIAL
|
|
62676
|
+
*p_read: set to number of input characters consumed
|
|
62677
|
+
*p_err: set to 1 on error, 0 on success
|
|
62678
|
+
Returns: number of bytes written to dst */
|
|
62679
|
+
static size_t from_base64(const char *src, size_t src_len,
|
|
62680
|
+
uint8_t *dst, size_t max_len,
|
|
62681
|
+
const char *flags, int last_chunk,
|
|
62682
|
+
size_t *p_read, int *p_err)
|
|
62683
|
+
{
|
|
62684
|
+
size_t read = 0, written = 0;
|
|
62685
|
+
uint32_t acc = 0;
|
|
62686
|
+
int seen = 0;
|
|
62687
|
+
size_t index = 0;
|
|
62688
|
+
|
|
62689
|
+
*p_err = 0;
|
|
62690
|
+
|
|
62691
|
+
if (max_len == 0) {
|
|
62692
|
+
*p_read = 0;
|
|
62693
|
+
return 0;
|
|
62694
|
+
}
|
|
62695
|
+
|
|
62696
|
+
/* Fast path: decode complete groups of 4 valid characters.
|
|
62697
|
+
Breaks out on whitespace, padding, invalid chars, or capacity. */
|
|
62698
|
+
while (index + 4 <= src_len && written + 3 <= max_len) {
|
|
62699
|
+
uint8_t f = flags[(unsigned char)src[index]]
|
|
62700
|
+
& flags[(unsigned char)src[index + 1]]
|
|
62701
|
+
& flags[(unsigned char)src[index + 2]]
|
|
62702
|
+
& flags[(unsigned char)src[index + 3]];
|
|
62703
|
+
if (!(f & K_VAL))
|
|
62704
|
+
break;
|
|
62705
|
+
uint32_t v = ((uint32_t)b64_val[(unsigned char)src[index]] << 18)
|
|
62706
|
+
| ((uint32_t)b64_val[(unsigned char)src[index + 1]] << 12)
|
|
62707
|
+
| ((uint32_t)b64_val[(unsigned char)src[index + 2]] << 6)
|
|
62708
|
+
| (uint32_t)b64_val[(unsigned char)src[index + 3]];
|
|
62709
|
+
dst[written] = (uint8_t)(v >> 16);
|
|
62710
|
+
dst[written + 1] = (uint8_t)(v >> 8);
|
|
62711
|
+
dst[written + 2] = (uint8_t)(v);
|
|
62712
|
+
written += 3;
|
|
62713
|
+
index += 4;
|
|
62714
|
+
}
|
|
62715
|
+
read = index;
|
|
62716
|
+
|
|
62717
|
+
if (written >= max_len) {
|
|
62718
|
+
*p_read = read;
|
|
62719
|
+
return written;
|
|
62720
|
+
}
|
|
62721
|
+
|
|
62722
|
+
/* Slow path: handle whitespace, padding, partial groups, capacity. */
|
|
62723
|
+
for (;;) {
|
|
62724
|
+
index = b64_skip_ws(src, src_len, index, flags);
|
|
62725
|
+
|
|
62726
|
+
if (index == src_len) {
|
|
62727
|
+
if (seen > 0) {
|
|
62728
|
+
if (last_chunk == B64_LAST_STOP_BEFORE_PARTIAL) {
|
|
62729
|
+
*p_read = read;
|
|
62730
|
+
return written;
|
|
62731
|
+
}
|
|
62732
|
+
if (last_chunk == B64_LAST_STRICT) {
|
|
62733
|
+
*p_err = 1;
|
|
62734
|
+
return 0;
|
|
62735
|
+
}
|
|
62736
|
+
/* loose */
|
|
62737
|
+
if (seen == 1) {
|
|
62738
|
+
*p_err = 1;
|
|
62739
|
+
return 0;
|
|
62740
|
+
}
|
|
62741
|
+
goto decode_partial;
|
|
62742
|
+
}
|
|
62743
|
+
*p_read = src_len;
|
|
62744
|
+
return written;
|
|
62745
|
+
}
|
|
62746
|
+
|
|
62747
|
+
unsigned char ch = src[index++];
|
|
62748
|
+
|
|
62749
|
+
if (ch == '=') {
|
|
62750
|
+
if (seen < 2) {
|
|
62751
|
+
*p_err = 1;
|
|
62752
|
+
return 0;
|
|
62753
|
+
}
|
|
62754
|
+
index = b64_skip_ws(src, src_len, index, flags);
|
|
62755
|
+
if (seen == 2) {
|
|
62756
|
+
if (index == src_len) {
|
|
62757
|
+
if (last_chunk == B64_LAST_STOP_BEFORE_PARTIAL) {
|
|
62758
|
+
*p_read = read;
|
|
62759
|
+
return written;
|
|
62760
|
+
}
|
|
62761
|
+
*p_err = 1;
|
|
62762
|
+
return 0;
|
|
62763
|
+
}
|
|
62764
|
+
if (src[index] == '=') {
|
|
62765
|
+
index++;
|
|
62766
|
+
index = b64_skip_ws(src, src_len, index, flags);
|
|
62767
|
+
} else {
|
|
62768
|
+
*p_err = 1;
|
|
62769
|
+
return 0;
|
|
62770
|
+
}
|
|
62771
|
+
}
|
|
62772
|
+
/* After padding, only whitespace is allowed */
|
|
62773
|
+
if (index != src_len) {
|
|
62774
|
+
*p_err = 1;
|
|
62775
|
+
return 0;
|
|
62776
|
+
}
|
|
62777
|
+
if (last_chunk == B64_LAST_STRICT) {
|
|
62778
|
+
uint32_t mask = (seen == 2) ? 0xF : 0x3;
|
|
62779
|
+
if (acc & mask) {
|
|
62780
|
+
*p_err = 1;
|
|
62781
|
+
return 0;
|
|
62782
|
+
}
|
|
62783
|
+
}
|
|
62784
|
+
goto decode_partial;
|
|
62785
|
+
}
|
|
62786
|
+
|
|
62787
|
+
if (!(flags[ch] & K_VAL)) {
|
|
62788
|
+
*p_err = 1;
|
|
62789
|
+
return 0;
|
|
62790
|
+
}
|
|
62791
|
+
|
|
62792
|
+
/* Check remaining capacity before committing to this group */
|
|
62793
|
+
{
|
|
62794
|
+
size_t remaining = max_len - written;
|
|
62795
|
+
if ((remaining == 1 && seen == 2) ||
|
|
62796
|
+
(remaining == 2 && seen == 3)) {
|
|
62797
|
+
*p_read = read;
|
|
62798
|
+
return written;
|
|
62799
|
+
}
|
|
62800
|
+
}
|
|
62801
|
+
|
|
62802
|
+
acc = (acc << 6) | b64_val[ch];
|
|
62803
|
+
seen++;
|
|
62804
|
+
|
|
62805
|
+
if (seen == 4) {
|
|
62806
|
+
dst[written] = (uint8_t)(acc >> 16);
|
|
62807
|
+
dst[written + 1] = (uint8_t)(acc >> 8);
|
|
62808
|
+
dst[written + 2] = (uint8_t)(acc);
|
|
62809
|
+
written += 3;
|
|
62810
|
+
acc = 0;
|
|
62811
|
+
seen = 0;
|
|
62812
|
+
read = index;
|
|
62813
|
+
if (written >= max_len) {
|
|
62814
|
+
*p_read = read;
|
|
62815
|
+
return written;
|
|
62816
|
+
}
|
|
62817
|
+
}
|
|
62818
|
+
}
|
|
62819
|
+
|
|
62820
|
+
decode_partial:
|
|
62821
|
+
if (seen == 2) {
|
|
62822
|
+
dst[written++] = (uint8_t)(acc >> 4);
|
|
62823
|
+
} else if (seen == 3) {
|
|
62824
|
+
dst[written] = (uint8_t)(acc >> 10);
|
|
62825
|
+
dst[written + 1] = (uint8_t)(acc >> 2);
|
|
62826
|
+
written += 2;
|
|
62827
|
+
}
|
|
62828
|
+
*p_read = src_len;
|
|
62829
|
+
return written;
|
|
62830
|
+
}
|
|
62831
|
+
|
|
62832
|
+
/* Hex helpers */
|
|
62833
|
+
static const char u8a_hex_digits[] = "0123456789abcdef";
|
|
62834
|
+
|
|
62835
|
+
static int u8a_hex_nibble(unsigned char ch)
|
|
62836
|
+
{
|
|
62837
|
+
if (ch >= '0' && ch <= '9') return ch - '0';
|
|
62838
|
+
if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10;
|
|
62839
|
+
if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10;
|
|
62840
|
+
return -1;
|
|
62841
|
+
}
|
|
62842
|
+
|
|
62843
|
+
static size_t u8a_hex_encode(const uint8_t *src, size_t len, char *dst)
|
|
62844
|
+
{
|
|
62845
|
+
for (size_t i = 0; i < len; i++) {
|
|
62846
|
+
dst[i * 2] = u8a_hex_digits[src[i] >> 4];
|
|
62847
|
+
dst[i * 2 + 1] = u8a_hex_digits[src[i] & 0xF];
|
|
62848
|
+
}
|
|
62849
|
+
return len * 2;
|
|
62850
|
+
}
|
|
62851
|
+
|
|
62852
|
+
/* Decode hex string to bytes.
|
|
62853
|
+
Returns bytes written. Sets *p_read to chars consumed, *p_err on error. */
|
|
62854
|
+
static size_t u8a_hex_decode(const char *src, size_t src_len,
|
|
62855
|
+
uint8_t *dst, size_t max_len,
|
|
62856
|
+
size_t *p_read, int *p_err)
|
|
62857
|
+
{
|
|
62858
|
+
size_t written = 0, i = 0;
|
|
62859
|
+
*p_err = 0;
|
|
62860
|
+
|
|
62861
|
+
if (src_len & 1) {
|
|
62862
|
+
*p_err = 1;
|
|
62863
|
+
return 0;
|
|
62864
|
+
}
|
|
62865
|
+
|
|
62866
|
+
while (i < src_len && written < max_len) {
|
|
62867
|
+
int hi = u8a_hex_nibble(src[i]);
|
|
62868
|
+
int lo = u8a_hex_nibble(src[i + 1]);
|
|
62869
|
+
if (hi < 0 || lo < 0) {
|
|
62870
|
+
*p_err = 1;
|
|
62871
|
+
return 0;
|
|
62872
|
+
}
|
|
62873
|
+
dst[written++] = (uint8_t)((hi << 4) | lo);
|
|
62874
|
+
i += 2;
|
|
62875
|
+
}
|
|
62876
|
+
|
|
62877
|
+
*p_read = i;
|
|
62878
|
+
return written;
|
|
62879
|
+
}
|
|
62880
|
+
|
|
62881
|
+
/* Validate that this_val is a Uint8Array (type check only, no detach check).
|
|
62882
|
+
Returns the JSObject pointer or NULL on error (throws). */
|
|
62883
|
+
static JSObject *check_uint8array(JSContext *ctx, JSValueConst this_val)
|
|
62884
|
+
{
|
|
62885
|
+
JSObject *p;
|
|
62886
|
+
|
|
62887
|
+
if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
|
|
62888
|
+
goto fail;
|
|
62889
|
+
p = JS_VALUE_GET_OBJ(this_val);
|
|
62890
|
+
if (p->class_id != JS_CLASS_UINT8_ARRAY)
|
|
62891
|
+
goto fail;
|
|
62892
|
+
return p;
|
|
62893
|
+
fail:
|
|
62894
|
+
JS_ThrowTypeError(ctx, "not a Uint8Array");
|
|
62895
|
+
return NULL;
|
|
62896
|
+
}
|
|
62897
|
+
|
|
62898
|
+
/* Get the data pointer and length of a Uint8Array, checking for detached
|
|
62899
|
+
buffers. Must be called after options are read (per spec ordering).
|
|
62900
|
+
Returns 0 on success, -1 on error (throws). */
|
|
62901
|
+
static int get_uint8array_bytes(JSContext *ctx, JSObject *p,
|
|
62902
|
+
uint8_t **pdata, size_t *plen)
|
|
62903
|
+
{
|
|
62904
|
+
if (typed_array_is_oob(p)) {
|
|
62905
|
+
JS_ThrowTypeErrorArrayBufferOOB(ctx);
|
|
62906
|
+
return -1;
|
|
62907
|
+
}
|
|
62908
|
+
*pdata = p->u.array.u.uint8_ptr;
|
|
62909
|
+
*plen = p->u.array.count;
|
|
62910
|
+
return 0;
|
|
62911
|
+
}
|
|
62912
|
+
|
|
62913
|
+
/* Validate options is undefined or an object (GetOptionsObject).
|
|
62914
|
+
Returns 0 on success, -1 on error (throws). */
|
|
62915
|
+
static int check_options_object(JSContext *ctx, JSValueConst options)
|
|
62916
|
+
{
|
|
62917
|
+
if (JS_IsUndefined(options))
|
|
62918
|
+
return 0;
|
|
62919
|
+
if (!JS_IsObject(options)) {
|
|
62920
|
+
JS_ThrowTypeError(ctx, "options must be an object");
|
|
62921
|
+
return -1;
|
|
62922
|
+
}
|
|
62923
|
+
return 0;
|
|
62924
|
+
}
|
|
62925
|
+
|
|
62926
|
+
/* Parse the 'alphabet' option from an options object.
|
|
62927
|
+
Returns B64_ALPHABET_BASE64 or B64_ALPHABET_BASE64URL, or -1 on error. */
|
|
62928
|
+
static int parse_alphabet_option(JSContext *ctx, JSValueConst options)
|
|
62929
|
+
{
|
|
62930
|
+
JSValue val;
|
|
62931
|
+
const char *str;
|
|
62932
|
+
int ret;
|
|
62933
|
+
|
|
62934
|
+
if (JS_IsUndefined(options))
|
|
62935
|
+
return B64_ALPHABET_BASE64;
|
|
62936
|
+
|
|
62937
|
+
val = JS_GetPropertyStr(ctx, options, "alphabet");
|
|
62938
|
+
if (JS_IsException(val))
|
|
62939
|
+
return -1;
|
|
62940
|
+
if (JS_IsUndefined(val))
|
|
62941
|
+
return B64_ALPHABET_BASE64;
|
|
62942
|
+
if (!JS_IsString(val)) {
|
|
62943
|
+
JS_FreeValue(ctx, val);
|
|
62944
|
+
JS_ThrowTypeError(ctx, "expected string for alphabet");
|
|
62945
|
+
return -1;
|
|
62946
|
+
}
|
|
62947
|
+
|
|
62948
|
+
str = JS_ToCString(ctx, val);
|
|
62949
|
+
JS_FreeValue(ctx, val);
|
|
62950
|
+
if (!str)
|
|
62951
|
+
return -1;
|
|
62952
|
+
|
|
62953
|
+
if (!strcmp(str, "base64"))
|
|
62954
|
+
ret = B64_ALPHABET_BASE64;
|
|
62955
|
+
else if (!strcmp(str, "base64url"))
|
|
62956
|
+
ret = B64_ALPHABET_BASE64URL;
|
|
62957
|
+
else {
|
|
62958
|
+
JS_ThrowTypeError(ctx, "invalid alphabet");
|
|
62959
|
+
ret = -1;
|
|
62960
|
+
}
|
|
62961
|
+
JS_FreeCString(ctx, str);
|
|
62962
|
+
return ret;
|
|
62963
|
+
}
|
|
62964
|
+
|
|
62965
|
+
/* Parse the 'lastChunkHandling' option. Returns mode or -1 on error. */
|
|
62966
|
+
static int parse_last_chunk_option(JSContext *ctx, JSValueConst options)
|
|
62967
|
+
{
|
|
62968
|
+
JSValue val;
|
|
62969
|
+
const char *str;
|
|
62970
|
+
int ret;
|
|
62971
|
+
|
|
62972
|
+
if (JS_IsUndefined(options))
|
|
62973
|
+
return B64_LAST_LOOSE;
|
|
62974
|
+
|
|
62975
|
+
val = JS_GetPropertyStr(ctx, options, "lastChunkHandling");
|
|
62976
|
+
if (JS_IsException(val))
|
|
62977
|
+
return -1;
|
|
62978
|
+
if (JS_IsUndefined(val))
|
|
62979
|
+
return B64_LAST_LOOSE;
|
|
62980
|
+
if (!JS_IsString(val)) {
|
|
62981
|
+
JS_FreeValue(ctx, val);
|
|
62982
|
+
JS_ThrowTypeError(ctx, "expected string for lastChunkHandling");
|
|
62983
|
+
return -1;
|
|
62984
|
+
}
|
|
62985
|
+
|
|
62986
|
+
str = JS_ToCString(ctx, val);
|
|
62987
|
+
JS_FreeValue(ctx, val);
|
|
62988
|
+
if (!str)
|
|
62989
|
+
return -1;
|
|
62990
|
+
|
|
62991
|
+
if (!strcmp(str, "loose"))
|
|
62992
|
+
ret = B64_LAST_LOOSE;
|
|
62993
|
+
else if (!strcmp(str, "strict"))
|
|
62994
|
+
ret = B64_LAST_STRICT;
|
|
62995
|
+
else if (!strcmp(str, "stop-before-partial"))
|
|
62996
|
+
ret = B64_LAST_STOP_BEFORE_PARTIAL;
|
|
62997
|
+
else {
|
|
62998
|
+
JS_ThrowTypeError(ctx, "invalid lastChunkHandling option");
|
|
62999
|
+
ret = -1;
|
|
63000
|
+
}
|
|
63001
|
+
JS_FreeCString(ctx, str);
|
|
63002
|
+
return ret;
|
|
63003
|
+
}
|
|
63004
|
+
|
|
63005
|
+
/* Uint8Array.prototype.toBase64([options]) */
|
|
63006
|
+
static JSValue js_uint8array_to_base64(JSContext *ctx, JSValueConst this_val,
|
|
63007
|
+
int argc, JSValueConst *argv)
|
|
63008
|
+
{
|
|
63009
|
+
uint8_t *data;
|
|
63010
|
+
size_t len;
|
|
63011
|
+
JSValue options;
|
|
63012
|
+
JSObject *p;
|
|
63013
|
+
int alphabet, omit_padding;
|
|
63014
|
+
size_t out_len, written;
|
|
63015
|
+
JSString *ostr;
|
|
63016
|
+
char *dst;
|
|
63017
|
+
|
|
63018
|
+
p = check_uint8array(ctx, this_val);
|
|
63019
|
+
if (!p)
|
|
63020
|
+
return JS_EXCEPTION;
|
|
63021
|
+
|
|
63022
|
+
options = argc > 0 ? unsafe_unconst(argv[0]) : JS_UNDEFINED;
|
|
63023
|
+
if (check_options_object(ctx, options))
|
|
63024
|
+
return JS_EXCEPTION;
|
|
63025
|
+
alphabet = parse_alphabet_option(ctx, options);
|
|
63026
|
+
if (alphabet < 0)
|
|
63027
|
+
return JS_EXCEPTION;
|
|
63028
|
+
|
|
63029
|
+
omit_padding = 0;
|
|
63030
|
+
if (!JS_IsUndefined(options)) {
|
|
63031
|
+
JSValue op_val = JS_GetPropertyStr(ctx, options, "omitPadding");
|
|
63032
|
+
if (JS_IsException(op_val))
|
|
63033
|
+
return JS_EXCEPTION;
|
|
63034
|
+
omit_padding = JS_ToBool(ctx, op_val);
|
|
63035
|
+
JS_FreeValue(ctx, op_val);
|
|
63036
|
+
}
|
|
63037
|
+
|
|
63038
|
+
if (get_uint8array_bytes(ctx, p, &data, &len))
|
|
63039
|
+
return JS_EXCEPTION;
|
|
63040
|
+
|
|
63041
|
+
out_len = 4 * ((len + 2) / 3);
|
|
63042
|
+
|
|
63043
|
+
if (unlikely(out_len > JS_STRING_LEN_MAX))
|
|
63044
|
+
return JS_ThrowRangeError(ctx, "output too large");
|
|
63045
|
+
|
|
63046
|
+
ostr = js_alloc_string(ctx, out_len, 0);
|
|
63047
|
+
if (!ostr)
|
|
63048
|
+
return JS_EXCEPTION;
|
|
63049
|
+
|
|
63050
|
+
dst = (char *)str8(ostr);
|
|
63051
|
+
written = b64_encode(data, len, dst,
|
|
63052
|
+
alphabet == B64_ALPHABET_BASE64URL ? b64url_enc : b64_enc);
|
|
63053
|
+
if (omit_padding) {
|
|
63054
|
+
while (written > 0 && dst[written - 1] == '=')
|
|
63055
|
+
written--;
|
|
63056
|
+
}
|
|
63057
|
+
dst[written] = '\0';
|
|
63058
|
+
|
|
63059
|
+
ostr->len = written;
|
|
63060
|
+
return JS_MKPTR(JS_TAG_STRING, ostr);
|
|
63061
|
+
}
|
|
63062
|
+
|
|
63063
|
+
/* Uint8Array.prototype.toHex() */
|
|
63064
|
+
static JSValue js_uint8array_to_hex(JSContext *ctx, JSValueConst this_val,
|
|
63065
|
+
int argc, JSValueConst *argv)
|
|
63066
|
+
{
|
|
63067
|
+
uint8_t *data;
|
|
63068
|
+
size_t len, out_len;
|
|
63069
|
+
JSObject *p;
|
|
63070
|
+
JSString *ostr;
|
|
63071
|
+
|
|
63072
|
+
p = check_uint8array(ctx, this_val);
|
|
63073
|
+
if (!p)
|
|
63074
|
+
return JS_EXCEPTION;
|
|
63075
|
+
if (get_uint8array_bytes(ctx, p, &data, &len))
|
|
63076
|
+
return JS_EXCEPTION;
|
|
63077
|
+
|
|
63078
|
+
out_len = len * 2;
|
|
63079
|
+
if (unlikely(out_len > JS_STRING_LEN_MAX))
|
|
63080
|
+
return JS_ThrowRangeError(ctx, "output too large");
|
|
63081
|
+
|
|
63082
|
+
ostr = js_alloc_string(ctx, out_len, 0);
|
|
63083
|
+
if (!ostr)
|
|
63084
|
+
return JS_EXCEPTION;
|
|
63085
|
+
|
|
63086
|
+
u8a_hex_encode(data, len, (char *)str8(ostr));
|
|
63087
|
+
str8(ostr)[out_len] = '\0';
|
|
63088
|
+
return JS_MKPTR(JS_TAG_STRING, ostr);
|
|
63089
|
+
}
|
|
63090
|
+
|
|
63091
|
+
/* Uint8Array.fromBase64(string[, options]) */
|
|
63092
|
+
static JSValue js_uint8array_from_base64(JSContext *ctx, JSValueConst this_val,
|
|
63093
|
+
int argc, JSValueConst *argv)
|
|
63094
|
+
{
|
|
63095
|
+
const char *str;
|
|
63096
|
+
size_t str_len, read_pos, decoded_len, out_cap;
|
|
63097
|
+
int alphabet, last_chunk, err;
|
|
63098
|
+
uint8_t *buf;
|
|
63099
|
+
JSValue result, options;
|
|
63100
|
+
|
|
63101
|
+
if (!JS_IsString(argv[0]))
|
|
63102
|
+
return JS_ThrowTypeError(ctx, "expected string");
|
|
63103
|
+
|
|
63104
|
+
str = JS_ToCStringLen(ctx, &str_len, argv[0]);
|
|
63105
|
+
if (!str)
|
|
63106
|
+
return JS_EXCEPTION;
|
|
63107
|
+
|
|
63108
|
+
options = argc > 1 ? unsafe_unconst(argv[1]) : JS_UNDEFINED;
|
|
63109
|
+
if (check_options_object(ctx, options)) {
|
|
63110
|
+
JS_FreeCString(ctx, str);
|
|
63111
|
+
return JS_EXCEPTION;
|
|
63112
|
+
}
|
|
63113
|
+
alphabet = parse_alphabet_option(ctx, options);
|
|
63114
|
+
if (alphabet < 0) {
|
|
63115
|
+
JS_FreeCString(ctx, str);
|
|
63116
|
+
return JS_EXCEPTION;
|
|
63117
|
+
}
|
|
63118
|
+
last_chunk = parse_last_chunk_option(ctx, options);
|
|
63119
|
+
if (last_chunk < 0) {
|
|
63120
|
+
JS_FreeCString(ctx, str);
|
|
63121
|
+
return JS_EXCEPTION;
|
|
63122
|
+
}
|
|
63123
|
+
|
|
63124
|
+
out_cap = (str_len / 4) * 3 + 3;
|
|
63125
|
+
buf = js_malloc(ctx, out_cap ? out_cap : 1);
|
|
63126
|
+
if (!buf) {
|
|
63127
|
+
JS_FreeCString(ctx, str);
|
|
63128
|
+
return JS_EXCEPTION;
|
|
63129
|
+
}
|
|
63130
|
+
|
|
63131
|
+
decoded_len = from_base64(str, str_len, buf, out_cap,
|
|
63132
|
+
alphabet == B64_ALPHABET_BASE64URL
|
|
63133
|
+
? b64_flags_url : b64_flags,
|
|
63134
|
+
last_chunk, &read_pos, &err);
|
|
63135
|
+
JS_FreeCString(ctx, str);
|
|
63136
|
+
|
|
63137
|
+
if (err) {
|
|
63138
|
+
js_free(ctx, buf);
|
|
63139
|
+
return JS_ThrowSyntaxError(ctx, "invalid base64 string");
|
|
63140
|
+
}
|
|
63141
|
+
|
|
63142
|
+
result = JS_NewUint8ArrayCopy(ctx, buf, decoded_len);
|
|
63143
|
+
js_free(ctx, buf);
|
|
63144
|
+
return result;
|
|
63145
|
+
}
|
|
63146
|
+
|
|
63147
|
+
/* Uint8Array.fromHex(string) */
|
|
63148
|
+
static JSValue js_uint8array_from_hex(JSContext *ctx, JSValueConst this_val,
|
|
63149
|
+
int argc, JSValueConst *argv)
|
|
63150
|
+
{
|
|
63151
|
+
const char *str;
|
|
63152
|
+
size_t str_len, read_pos, decoded_len, out_cap;
|
|
63153
|
+
int err;
|
|
63154
|
+
uint8_t *buf;
|
|
63155
|
+
JSValue result;
|
|
63156
|
+
|
|
63157
|
+
if (!JS_IsString(argv[0]))
|
|
63158
|
+
return JS_ThrowTypeError(ctx, "expected string");
|
|
63159
|
+
|
|
63160
|
+
str = JS_ToCStringLen(ctx, &str_len, argv[0]);
|
|
63161
|
+
if (!str)
|
|
63162
|
+
return JS_EXCEPTION;
|
|
63163
|
+
|
|
63164
|
+
out_cap = str_len / 2 + 1;
|
|
63165
|
+
buf = js_malloc(ctx, out_cap ? out_cap : 1);
|
|
63166
|
+
if (!buf) {
|
|
63167
|
+
JS_FreeCString(ctx, str);
|
|
63168
|
+
return JS_EXCEPTION;
|
|
63169
|
+
}
|
|
63170
|
+
|
|
63171
|
+
decoded_len = u8a_hex_decode(str, str_len, buf, out_cap, &read_pos, &err);
|
|
63172
|
+
JS_FreeCString(ctx, str);
|
|
63173
|
+
|
|
63174
|
+
if (err) {
|
|
63175
|
+
js_free(ctx, buf);
|
|
63176
|
+
return JS_ThrowSyntaxError(ctx, "invalid hex string");
|
|
63177
|
+
}
|
|
63178
|
+
|
|
63179
|
+
result = JS_NewUint8ArrayCopy(ctx, buf, decoded_len);
|
|
63180
|
+
js_free(ctx, buf);
|
|
63181
|
+
return result;
|
|
63182
|
+
}
|
|
63183
|
+
|
|
63184
|
+
/* Return a { read, written } result object */
|
|
63185
|
+
static JSValue js_make_read_written(JSContext *ctx, size_t read, size_t written)
|
|
63186
|
+
{
|
|
63187
|
+
JSValue obj = JS_NewObject(ctx);
|
|
63188
|
+
if (JS_IsException(obj))
|
|
63189
|
+
return JS_EXCEPTION;
|
|
63190
|
+
if (JS_DefinePropertyValueStr(ctx, obj, "read",
|
|
63191
|
+
js_uint32(read), JS_PROP_C_W_E) < 0)
|
|
63192
|
+
goto fail;
|
|
63193
|
+
if (JS_DefinePropertyValueStr(ctx, obj, "written",
|
|
63194
|
+
js_uint32(written), JS_PROP_C_W_E) < 0)
|
|
63195
|
+
goto fail;
|
|
63196
|
+
return obj;
|
|
63197
|
+
fail:
|
|
63198
|
+
JS_FreeValue(ctx, obj);
|
|
63199
|
+
return JS_EXCEPTION;
|
|
63200
|
+
}
|
|
63201
|
+
|
|
63202
|
+
/* Uint8Array.prototype.setFromBase64(string[, options]) */
|
|
63203
|
+
static JSValue js_uint8array_set_from_base64(JSContext *ctx,
|
|
63204
|
+
JSValueConst this_val,
|
|
63205
|
+
int argc, JSValueConst *argv)
|
|
63206
|
+
{
|
|
63207
|
+
uint8_t *data;
|
|
63208
|
+
size_t len;
|
|
63209
|
+
const char *str;
|
|
63210
|
+
size_t str_len, read_pos, decoded_len;
|
|
63211
|
+
JSObject *p;
|
|
63212
|
+
int alphabet, last_chunk, err;
|
|
63213
|
+
JSValue options;
|
|
63214
|
+
|
|
63215
|
+
p = check_uint8array(ctx, this_val);
|
|
63216
|
+
if (!p)
|
|
63217
|
+
return JS_EXCEPTION;
|
|
63218
|
+
|
|
63219
|
+
if (!JS_IsString(argv[0]))
|
|
63220
|
+
return JS_ThrowTypeError(ctx, "expected string");
|
|
63221
|
+
|
|
63222
|
+
str = JS_ToCStringLen(ctx, &str_len, argv[0]);
|
|
63223
|
+
if (!str)
|
|
63224
|
+
return JS_EXCEPTION;
|
|
63225
|
+
|
|
63226
|
+
options = argc > 1 ? unsafe_unconst(argv[1]) : JS_UNDEFINED;
|
|
63227
|
+
if (check_options_object(ctx, options)) {
|
|
63228
|
+
JS_FreeCString(ctx, str);
|
|
63229
|
+
return JS_EXCEPTION;
|
|
63230
|
+
}
|
|
63231
|
+
alphabet = parse_alphabet_option(ctx, options);
|
|
63232
|
+
if (alphabet < 0) {
|
|
63233
|
+
JS_FreeCString(ctx, str);
|
|
63234
|
+
return JS_EXCEPTION;
|
|
63235
|
+
}
|
|
63236
|
+
last_chunk = parse_last_chunk_option(ctx, options);
|
|
63237
|
+
if (last_chunk < 0) {
|
|
63238
|
+
JS_FreeCString(ctx, str);
|
|
63239
|
+
return JS_EXCEPTION;
|
|
63240
|
+
}
|
|
63241
|
+
|
|
63242
|
+
if (get_uint8array_bytes(ctx, p, &data, &len)) {
|
|
63243
|
+
JS_FreeCString(ctx, str);
|
|
63244
|
+
return JS_EXCEPTION;
|
|
63245
|
+
}
|
|
63246
|
+
|
|
63247
|
+
decoded_len = from_base64(str, str_len, data, len,
|
|
63248
|
+
alphabet == B64_ALPHABET_BASE64URL
|
|
63249
|
+
? b64_flags_url : b64_flags,
|
|
63250
|
+
last_chunk, &read_pos, &err);
|
|
63251
|
+
JS_FreeCString(ctx, str);
|
|
63252
|
+
|
|
63253
|
+
if (err)
|
|
63254
|
+
return JS_ThrowSyntaxError(ctx, "invalid base64 string");
|
|
63255
|
+
|
|
63256
|
+
return js_make_read_written(ctx, read_pos, decoded_len);
|
|
63257
|
+
}
|
|
63258
|
+
|
|
63259
|
+
/* Uint8Array.prototype.setFromHex(string) */
|
|
63260
|
+
static JSValue js_uint8array_set_from_hex(JSContext *ctx,
|
|
63261
|
+
JSValueConst this_val,
|
|
63262
|
+
int argc, JSValueConst *argv)
|
|
63263
|
+
{
|
|
63264
|
+
uint8_t *data;
|
|
63265
|
+
size_t len;
|
|
63266
|
+
const char *str;
|
|
63267
|
+
size_t str_len, read_pos, decoded_len;
|
|
63268
|
+
JSObject *p;
|
|
63269
|
+
int err;
|
|
63270
|
+
|
|
63271
|
+
p = check_uint8array(ctx, this_val);
|
|
63272
|
+
if (!p)
|
|
63273
|
+
return JS_EXCEPTION;
|
|
63274
|
+
|
|
63275
|
+
if (!JS_IsString(argv[0]))
|
|
63276
|
+
return JS_ThrowTypeError(ctx, "expected string");
|
|
63277
|
+
|
|
63278
|
+
str = JS_ToCStringLen(ctx, &str_len, argv[0]);
|
|
63279
|
+
if (!str)
|
|
63280
|
+
return JS_EXCEPTION;
|
|
63281
|
+
|
|
63282
|
+
if (get_uint8array_bytes(ctx, p, &data, &len)) {
|
|
63283
|
+
JS_FreeCString(ctx, str);
|
|
63284
|
+
return JS_EXCEPTION;
|
|
63285
|
+
}
|
|
63286
|
+
|
|
63287
|
+
decoded_len = u8a_hex_decode(str, str_len, data, len, &read_pos, &err);
|
|
63288
|
+
JS_FreeCString(ctx, str);
|
|
63289
|
+
|
|
63290
|
+
if (err)
|
|
63291
|
+
return JS_ThrowSyntaxError(ctx, "invalid hex string");
|
|
63292
|
+
|
|
63293
|
+
return js_make_read_written(ctx, read_pos, decoded_len);
|
|
63294
|
+
}
|
|
63295
|
+
|
|
63296
|
+
static const JSCFunctionListEntry js_uint8array_proto_funcs[] = {
|
|
63297
|
+
JS_CFUNC_DEF("toBase64", 0, js_uint8array_to_base64),
|
|
63298
|
+
JS_CFUNC_DEF("toHex", 0, js_uint8array_to_hex),
|
|
63299
|
+
JS_CFUNC_DEF("setFromBase64", 1, js_uint8array_set_from_base64),
|
|
63300
|
+
JS_CFUNC_DEF("setFromHex", 1, js_uint8array_set_from_hex),
|
|
63301
|
+
};
|
|
63302
|
+
|
|
63303
|
+
static const JSCFunctionListEntry js_uint8array_funcs[] = {
|
|
63304
|
+
JS_CFUNC_DEF("fromBase64", 1, js_uint8array_from_base64),
|
|
63305
|
+
JS_CFUNC_DEF("fromHex", 1, js_uint8array_from_hex),
|
|
63306
|
+
};
|
|
63307
|
+
|
|
63308
|
+
static int js_uint8array_funcs_init(JSContext *ctx)
|
|
63309
|
+
{
|
|
63310
|
+
JSValue ctor, proto;
|
|
63311
|
+
|
|
63312
|
+
ctor = JS_GetProperty(ctx, ctx->global_obj, JS_ATOM_Uint8Array);
|
|
63313
|
+
if (JS_IsException(ctor))
|
|
63314
|
+
return -1;
|
|
63315
|
+
proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
|
|
63316
|
+
if (JS_IsException(proto)) {
|
|
63317
|
+
JS_FreeValue(ctx, ctor);
|
|
63318
|
+
return -1;
|
|
63319
|
+
}
|
|
63320
|
+
JS_SetPropertyFunctionList(ctx, proto,
|
|
63321
|
+
js_uint8array_proto_funcs,
|
|
63322
|
+
countof(js_uint8array_proto_funcs));
|
|
63323
|
+
JS_FreeValue(ctx, proto);
|
|
63324
|
+
JS_SetPropertyFunctionList(ctx, ctor,
|
|
63325
|
+
js_uint8array_funcs,
|
|
63326
|
+
countof(js_uint8array_funcs));
|
|
63327
|
+
JS_FreeValue(ctx, ctor);
|
|
63328
|
+
return 0;
|
|
63329
|
+
}
|
|
63330
|
+
|
|
63331
|
+
int JS_AddIntrinsicAToB(JSContext *ctx)
|
|
63332
|
+
{
|
|
63333
|
+
if (!JS_IsRegisteredClass(ctx->rt, JS_CLASS_DOM_EXCEPTION)) {
|
|
63334
|
+
if (JS_AddIntrinsicDOMException(ctx))
|
|
63335
|
+
return -1;
|
|
63336
|
+
}
|
|
63337
|
+
JS_SetPropertyFunctionList(ctx, ctx->global_obj,
|
|
63338
|
+
js_base64_funcs, countof(js_base64_funcs));
|
|
63339
|
+
return 0;
|
|
63340
|
+
}
|
|
60832
63341
|
|
|
60833
63342
|
bool JS_DetectModule(const char *input, size_t input_len)
|
|
60834
63343
|
{
|