@@ -530,6 +530,12 @@ typedef struct JSMapState {
530530 resize is needed */
531531} JSMapState;
532532
533+ enum
534+ {
535+ JS_TO_STRING_IS_PROPERTY_KEY = 1 << 0,
536+ JS_TO_STRING_NO_SIDE_EFFECTS = 1 << 1,
537+ };
538+
533539enum {
534540 JS_ATOM_TYPE_STRING = 1,
535541 JS_ATOM_TYPE_GLOBAL_SYMBOL,
@@ -1199,6 +1205,8 @@ static int JS_ToBoolFree(JSContext *ctx, JSValue val);
11991205static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
12001206static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val);
12011207static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val);
1208+ static JSValue JS_ToPropertyKeyInternal(JSContext *ctx, JSValueConst val,
1209+ int flags);
12021210static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len);
12031211static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
12041212 JSValueConst flags);
@@ -8364,7 +8372,8 @@ static JSAtom js_symbol_to_atom(JSContext *ctx, JSValueConst val)
83648372}
83658373
83668374/* 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)
83688377{
83698378 JSAtom atom;
83708379 uint32_t tag;
@@ -8378,7 +8387,7 @@ JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
83788387 atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p));
83798388 } else {
83808389 JSValue str;
8381- str = JS_ToPropertyKey (ctx, val);
8390+ str = JS_ToPropertyKeyInternal (ctx, val, flags );
83828391 if (JS_IsException(str))
83838392 return JS_ATOM_NULL;
83848393 if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) {
@@ -8390,6 +8399,11 @@ JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
83908399 return atom;
83918400}
83928401
8402+ JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
8403+ {
8404+ return JS_ValueToAtomInternal(ctx, val, /*flags*/0);
8405+ }
8406+
83938407static bool js_get_fast_array_element(JSContext *ctx, JSObject *p,
83948408 uint32_t idx, JSValue *pval)
83958409{
@@ -8466,15 +8480,21 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
84668480 if (js_get_fast_array_element(ctx, p, idx, &val))
84678481 return val;
84688482 }
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);
84778495 }
8496+ JS_FreeAtom(ctx, atom);
8497+ return JS_EXCEPTION;
84788498 }
84798499 atom = JS_ValueToAtom(ctx, prop);
84808500 JS_FreeValue(ctx, prop);
@@ -12887,8 +12907,8 @@ static JSValue js_dtoa2(JSContext *ctx,
1288712907 return res;
1288812908}
1288912909
12890- JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val,
12891- bool is_ToPropertyKey )
12910+ static JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val,
12911+ int flags )
1289212912{
1289312913 uint32_t tag;
1289412914 char buf[32];
@@ -12911,20 +12931,22 @@ JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val,
1291112931 case JS_TAG_EXCEPTION:
1291212932 return JS_EXCEPTION;
1291312933 case JS_TAG_OBJECT:
12914- {
12934+ if (flags & JS_TO_STRING_NO_SIDE_EFFECTS) {
12935+ return js_new_string8(ctx, "{}");
12936+ } else {
1291512937 JSValue val1, ret;
1291612938 val1 = JS_ToPrimitive(ctx, val, HINT_STRING);
1291712939 if (JS_IsException(val1))
1291812940 return val1;
12919- ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey );
12941+ ret = JS_ToStringInternal(ctx, val1, flags );
1292012942 JS_FreeValue(ctx, val1);
1292112943 return ret;
1292212944 }
1292312945 break;
1292412946 case JS_TAG_FUNCTION_BYTECODE:
1292512947 return js_new_string8(ctx, "[function bytecode]");
1292612948 case JS_TAG_SYMBOL:
12927- if (is_ToPropertyKey ) {
12949+ if (flags & JS_TO_STRING_IS_PROPERTY_KEY ) {
1292812950 return js_dup(val);
1292912951 } else {
1293012952 return JS_ThrowTypeError(ctx, "cannot convert symbol to string");
@@ -12944,7 +12966,7 @@ JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val,
1294412966
1294512967JSValue JS_ToString(JSContext *ctx, JSValueConst val)
1294612968{
12947- return JS_ToStringInternal(ctx, val, false );
12969+ return JS_ToStringInternal(ctx, val, /*flags*/0 );
1294812970}
1294912971
1295012972static JSValue JS_ToStringFree(JSContext *ctx, JSValue val)
@@ -12962,9 +12984,15 @@ static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val)
1296212984 return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL);
1296312985}
1296412986
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+
1296512993JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val)
1296612994{
12967- return JS_ToStringInternal (ctx, val, true );
12995+ return JS_ToPropertyKeyInternal (ctx, val, /*flags*/0 );
1296812996}
1296912997
1297012998static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val)
0 commit comments