ecma402 icon indicating copy to clipboard operation
ecma402 copied to clipboard

%Intl%.[[FallbackSymbol]] per-realm

Open acutmore opened this issue 3 years ago • 23 comments

This has come up a few times during proposal-symbols-as-weakmap-keys. Creating an issue here as the 402 repo feels like a more central point to discuss this.

Related discussions in original PR: https://github.com/tc39/ecma402/pull/84 Test262 issue: https://github.com/tc39/test262/issues/3420


The Intl spec says that %Intl%.[[FallbackSymbol]] is created in the current realm. Implying that each realm has it's own unique IntlLegacyConstructedSymbol.

https://github.com/tc39/ecma402/blob/fe78d968c0d109ab93ebf1c4b23ebe7e617f3c10/spec/intl.html#L16

This can be observed:

let getFallbackSymbol_code = `Reflect.ownKeys(
  Intl.DateTimeFormat.call(Object.create(Intl.DateTimeFormat.prototype))
).filter(v => typeof v === 'symbol' && v.description === 'IntlLegacyConstructedSymbol')[0];`;

// using ShadowRealms:
(new ShadowRealm).evaluate(getFallbackSymbol_code) !== (new ShadowRealm).evaluate(getFallbackSymbol_code)

// Or iframes:
const frame = document.createElement('iframe');
document.body.appendChild(frame);
eval(getFallbackSymbol_code) !== frame.contentWindow.eval(getFallbackSymbol_code);

However implementations differ.

  • V8 : same across realms ref
  • JSC : same across realms ref
  • SM : unique per realm ref

It is unclear if this is an issue in practice. The symbol is there to ensure backwards compatibility with existing code, rather than for new code to use. However having a concrete issue to capture/track the subtle inconsistency feels appropriate.

cc: @ljharb

acutmore avatar Jun 01 '22 15:06 acutmore

If this is a well-known symbol (it’s cross-realm, like in v8 and jsc) then it belongs in the WKS table. If not, there should be a test262 test that fails on v8 and jsc.

An additional concern is that this is a built-in value, with identity, that isn’t reachable directly from the global. It’d be nice to address that as well (cc @erights @kriskowal)

ljharb avatar Jun 01 '22 15:06 ljharb

It should be per Realm instead of a well-known symbol. The fact that Intl is optional, having it as a well-known is just odd because you might have the symbol but not Intl in some environments. It was never intended to be a well-known symbol IIRC.

caridy avatar Jun 01 '22 17:06 caridy

@caridy that's fine, if v8 and jsc are willing to change. either way tho, i still think it should be directly accessible somewhere from the global without having to invoke functions.

ljharb avatar Jun 01 '22 18:06 ljharb

@ljharb

i still think it should be directly accessible somewhere from the global without having to invoke functions.

What about putting that realm specific symbol into Intl instead?

caridy avatar Jun 01 '22 19:06 caridy

@caridy whether it's well-known or not, that seems like the appropriate place to put it to me!

ljharb avatar Jun 01 '22 20:06 ljharb

There are two other options:

  1. We could check if we actually still need the legacy fallback. (#84 mentions that we hope we can remove this kludge one day.)
  2. Now that engines have support for private fields, %Intl%.[[FallbackSymbol]] could be changed to a private symbol. That way it can't be observed in the first place.

anba avatar Jun 08 '22 17:06 anba

What is a private symbol?

ljharb avatar Jun 08 '22 17:06 ljharb

What is a private symbol?

Some engines, like v8, internally implement private fields using symbols that are hidden from things like Reflect.ownKeys

acutmore avatar Jun 08 '22 17:06 acutmore

Yes, exactly that. "Private Name" should be the correct spec term.

anba avatar Jun 08 '22 17:06 anba

If removing it is web compatible, that seems ideal. If not, imo it should be directly exposed on Intl, whether it remains per-realm or not.

ljharb avatar Jun 08 '22 17:06 ljharb

First, I agree that simply removing it, if possible, would be ideal.

Otherwise, the spec and SpiderMonkey are both already correct --- it is per realm. We need a test added to test262 which v8 and jsc will fail until they implement this correctly.

Separately, the spec currently happens to obey the useful invariant that the string-named symbol-valued properties of %Symbol%, the Symbol constructor, are exactly the well-known symbols. I have already written code that depends on this invariant, and I suspect others have too. @codehag , I suggest this is a nice self-contained clear invariant that could go first in our efforts to document invariants and make some normative. (Attn @mhofman )

erights avatar Jun 08 '22 20:06 erights

We could check if we actually still need the legacy fallback.

How would this practically work? I suppose at this point browser teams have experience around finding websites that utilize a certain feature, right?

ryzokuken avatar Jun 09 '22 17:06 ryzokuken

Separately, the spec currently happens to obey the useful invariant that the string-named symbol-valued properties of %Symbol%, the Symbol constructor, are exactly the well-known symbols. I have already written code that depends on this invariant, and I suspect others have too. I suggest this is a nice self-contained clear invariant that could go first in our efforts to document invariants and make some normative.

I am very strongly opposed to treating this as an invariant. We should not constrain the language in this way. For example, in the Set methods proposal, I am considering having Sets speak to Sets by accessing a cross-realm symbol to get the method to test membership (which avoids the problem of using a string-based has, which conflicts with Maps), but it makes absolutely no sense for such a symbol to live on Symbol, since it is Set-specific.

If we need to treat this as an invariant it will severely constrain our ability to evolve the language. @erights, please, please revise your code that depends on this, and avoid writing such code in the future.

(If we need to have a list of all cross-realm symbols somewhere, that's fine, I just don't think that list should be "string-named properties of Symbol".)

bakkot avatar Jul 11 '22 17:07 bakkot

it makes absolutely no sense for such a symbol to live on Symbol, since it is Set-specific.

More than half of the well-known symbols concern built-in-specific contracts. Is this one different from the others or do you mean you’d have preferred none of them to live there?

bathos avatar Jul 20 '22 15:07 bathos

I would also have preferred the RegExp ones live somewhere related to RegExp and that Symbol.isConcatSpreadable lived somewhere related to Array, yes. Putting everything on Symbol is not sustainable.

bakkot avatar Jul 20 '22 15:07 bakkot

I 100% agree with this.

ljharb avatar Jul 20 '22 16:07 ljharb

so... can someone make a test262 test to verify the per-realm behavior?

FrankYFTang avatar Aug 16 '22 07:08 FrankYFTang

I'm told that the web reality in V8 is that this is a cross-realm symbol, so making it per-realm would require a change in V8. Should we revisit this and change the spec to be consistent with web reality (at least in V8)? What do other engines do?

sffc avatar Aug 16 '22 18:08 sffc

@sffc we revisited this in the recent plenary, and consensus was to keep it per-realm, which indeed forces v8 to change (since v8 is the only engine that implemented it in this fashion)

ljharb avatar Aug 16 '22 18:08 ljharb

The original post suggests JSC also has the cross-realm behavior. Is this no longer the case?

syg avatar Aug 16 '22 19:08 syg

Got it; according to the OP, the web reality is inconsistent, so someone needs to change. Let's stick with the TC39 conclusion of per-realm.

sffc avatar Aug 16 '22 19:08 sffc

@syg ah, my mistake, thanks for clarifying - both v8 and jsc would need to change, then, yes.

ljharb avatar Aug 16 '22 19:08 ljharb

I have already expressed in TC39 that I am willing to make the code change in v8, assuming there will be a test262 test which can validate/ verify my fix. So I am waiting for someone to write a test262 test to help me for that.

FrankYFTang avatar Aug 16 '22 22:08 FrankYFTang