@@ -530,6 +530,12 @@ typedef struct JSMapState {
530
530
resize is needed */
531
531
} JSMapState;
532
532
533
+ enum
534
+ {
535
+ JS_TO_STRING_IS_PROPERTY_KEY = 1 << 0,
536
+ JS_TO_STRING_NO_SIDE_EFFECTS = 1 << 1,
537
+ };
538
+
533
539
enum {
534
540
JS_ATOM_TYPE_STRING = 1,
535
541
JS_ATOM_TYPE_GLOBAL_SYMBOL,
@@ -1199,6 +1205,8 @@ static int JS_ToBoolFree(JSContext *ctx, JSValue val);
1199
1205
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
1200
1206
static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val);
1201
1207
static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val);
1208
+ static JSValue JS_ToPropertyKeyInternal(JSContext *ctx, JSValueConst val,
1209
+ int flags);
1202
1210
static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len);
1203
1211
static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
1204
1212
JSValueConst flags);
@@ -8364,7 +8372,8 @@ static JSAtom js_symbol_to_atom(JSContext *ctx, JSValueConst val)
8364
8372
}
8365
8373
8366
8374
/* return JS_ATOM_NULL in case of exception */
8367
- JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
8375
+ static JSAtom JS_ValueToAtomInternal(JSContext *ctx, JSValueConst val,
8376
+ int flags)
8368
8377
{
8369
8378
JSAtom atom;
8370
8379
uint32_t tag;
@@ -8378,7 +8387,7 @@ JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
8378
8387
atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p));
8379
8388
} else {
8380
8389
JSValue str;
8381
- str = JS_ToPropertyKey (ctx, val);
8390
+ str = JS_ToPropertyKeyInternal (ctx, val, flags );
8382
8391
if (JS_IsException(str))
8383
8392
return JS_ATOM_NULL;
8384
8393
if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) {
@@ -8390,6 +8399,11 @@ JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
8390
8399
return atom;
8391
8400
}
8392
8401
8402
+ JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
8403
+ {
8404
+ return JS_ValueToAtomInternal(ctx, val, /*flags*/0);
8405
+ }
8406
+
8393
8407
static bool js_get_fast_array_element(JSContext *ctx, JSObject *p,
8394
8408
uint32_t idx, JSValue *pval)
8395
8409
{
@@ -8466,15 +8480,21 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
8466
8480
if (js_get_fast_array_element(ctx, p, idx, &val))
8467
8481
return val;
8468
8482
}
8469
- } else {
8470
- switch(tag) {
8471
- case JS_TAG_NULL:
8472
- JS_FreeValue(ctx, prop);
8473
- return JS_ThrowTypeError(ctx, "cannot read property of null");
8474
- case JS_TAG_UNDEFINED:
8475
- JS_FreeValue(ctx, prop);
8476
- return JS_ThrowTypeError(ctx, "cannot read property of undefined");
8483
+ } else if (unlikely(tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)) {
8484
+ // per spec: not allowed to call ToPropertyKey before ToObject
8485
+ // so we must ensure to not invoke JS anything that's observable
8486
+ // from JS code
8487
+ atom = JS_ValueToAtomInternal(ctx, prop, JS_TO_STRING_NO_SIDE_EFFECTS);
8488
+ JS_FreeValue(ctx, prop);
8489
+ if (unlikely(atom == JS_ATOM_NULL))
8490
+ return JS_EXCEPTION;
8491
+ if (tag == JS_TAG_NULL) {
8492
+ JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", atom);
8493
+ } else {
8494
+ JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", atom);
8477
8495
}
8496
+ JS_FreeAtom(ctx, atom);
8497
+ return JS_EXCEPTION;
8478
8498
}
8479
8499
atom = JS_ValueToAtom(ctx, prop);
8480
8500
JS_FreeValue(ctx, prop);
@@ -12887,8 +12907,8 @@ static JSValue js_dtoa2(JSContext *ctx,
12887
12907
return res;
12888
12908
}
12889
12909
12890
- JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val,
12891
- bool is_ToPropertyKey )
12910
+ static JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val,
12911
+ int flags )
12892
12912
{
12893
12913
uint32_t tag;
12894
12914
char buf[32];
@@ -12911,20 +12931,22 @@ JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val,
12911
12931
case JS_TAG_EXCEPTION:
12912
12932
return JS_EXCEPTION;
12913
12933
case JS_TAG_OBJECT:
12914
- {
12934
+ if (flags & JS_TO_STRING_NO_SIDE_EFFECTS) {
12935
+ return js_new_string8(ctx, "{}");
12936
+ } else {
12915
12937
JSValue val1, ret;
12916
12938
val1 = JS_ToPrimitive(ctx, val, HINT_STRING);
12917
12939
if (JS_IsException(val1))
12918
12940
return val1;
12919
- ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey );
12941
+ ret = JS_ToStringInternal(ctx, val1, flags );
12920
12942
JS_FreeValue(ctx, val1);
12921
12943
return ret;
12922
12944
}
12923
12945
break;
12924
12946
case JS_TAG_FUNCTION_BYTECODE:
12925
12947
return js_new_string8(ctx, "[function bytecode]");
12926
12948
case JS_TAG_SYMBOL:
12927
- if (is_ToPropertyKey ) {
12949
+ if (flags & JS_TO_STRING_IS_PROPERTY_KEY ) {
12928
12950
return js_dup(val);
12929
12951
} else {
12930
12952
return JS_ThrowTypeError(ctx, "cannot convert symbol to string");
@@ -12944,7 +12966,7 @@ JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val,
12944
12966
12945
12967
JSValue JS_ToString(JSContext *ctx, JSValueConst val)
12946
12968
{
12947
- return JS_ToStringInternal(ctx, val, false );
12969
+ return JS_ToStringInternal(ctx, val, /*flags*/0 );
12948
12970
}
12949
12971
12950
12972
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val)
@@ -12962,9 +12984,15 @@ static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val)
12962
12984
return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL);
12963
12985
}
12964
12986
12987
+ static JSValue JS_ToPropertyKeyInternal(JSContext *ctx, JSValueConst val,
12988
+ int flags)
12989
+ {
12990
+ return JS_ToStringInternal(ctx, val, flags | JS_TO_STRING_IS_PROPERTY_KEY);
12991
+ }
12992
+
12965
12993
JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val)
12966
12994
{
12967
- return JS_ToStringInternal (ctx, val, true );
12995
+ return JS_ToPropertyKeyInternal (ctx, val, /*flags*/0 );
12968
12996
}
12969
12997
12970
12998
static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val)
0 commit comments