1 of 34

Restricting subclassing support in built-in methods

Yulia Startsev, Mozilla

Shu-yu Guo, Google

2 of 34

Primary Motivation

3 of 34

Implementation Complexity and Maintenance

  • Spec Complexity and Maintenance
    • Knock on effects on new builtins, which must add subclassing only for consistency and due to intent.
    • Knock on effects in other specifications (WebAssembly)
  • Engine Complexity and Maintenance
    • Negatively affects any new engine
    • Negatively affects maintenance in existing engines
    • Introduces (arguably unnecessary) complexity in existing engines
  • Edge cases are easy to miss and break

4 of 34

Secondary Motivations

5 of 34

Performance and robustness

  • Performance improvements depend on the type of intervention that can be achieved.
    • Example: ArraySpeciesCreate, TypedArraySpeciesCreate, regexp exec/flags lookups
      • Possible to mitigate for trivial cases with caches, but this solution is brittle.
  • Fewer property lookups (@@species, exec/flags etc.).
    • There may be guards present to avoid these lookups for the fast case, but engines still need�to ensure the guards are valid, so even with guards there are non-zero costs.
  • Fewer or no type checks after object allocations.
  • Memory savings.
    • Engines have to implement many functions twice: One implementation which follows every step as described in the spec and then another implementation which contains the fast-path.
  • More stable performance.

6 of 34

Security Bugs

7 of 34

Why isn’t this “water under the bridge”?

  • This feature has a continued impact on all new built-ins added to the language
    • Unnecessary complexity propagated through the specification, which we have reason to believe does not benefit users.
  • Edge cases in other spec bodies that are difficult to catch
  • This is easy to get wrong and is a brittle part of existing implementations.
  • This impacts future implementations.

8 of 34

Regardless, why do this when the risks are so high?

  • Isn’t our goal “Do not break the web” -- even for the smaller websites?
    • This is the guiding principle
    • If we cannot detect breakage, we have no way of knowing. We similarly have no way of knowing that any additive features are breaking the web for smaller websites, yet we do this anyway. See `Array.prototype.flatten` as an example of a breaking additive change.
    • If we use this argument here, it would be inconsistent with how we treat additive proposals.
  • Initial evidence points to this either not being used, or being used in a way that does not take advantage of the spec complexity.
  • We will address this in more detail later in this presentation.

9 of 34

Taxonomy of Subclassing

10 of 34

Type I: Minimal Support

11 of 34

Type II: subclass instance creation in builtin methods

12 of 34

Type III: custom subclass instance creation in BIM

13 of 34

Type IV: Delegation to property lookups in BIM

14 of 34

Proposed new “old semantics”

15 of 34

Impacts from Species Removal

Major change in behavior:

  • Array
  • Promise
  • TypedArray
  • ArrayBuffer
  • SharedArrayBuffer

Minor change in behavior

  • Map
  • Set

<Class>[@@species] will be removed. It is currently not used.

16 of 34

Other Impacts

Major

  • RegExp

Property lookups of "exec" and "flags" will be removed in favor of internal slots.

Continue to use @@match et al as an interface between RegExp and String

Minor

  • Meta

Symbol.species will remain as a vestigial symbol if any user code wants to use it in its own subclassing protocol.

17 of 34

Example Species Removal: Array

18 of 34

Array Prototype Methods

Impacts:

  • Array.prototype.concat
  • Array.prototype.filter
  • Array.prototype.flat
  • Array.prototype.flatMap
  • Array.prototype.map
  • Array.prototype.slice
  • Array.prototype.splice

19 of 34

Before & After

20 of 34

Array Constructor Methods

Impacts:

  • Array.from
  • Array.of

21 of 34

Before & After

22 of 34

Removing Array[@@species]

No longer possible.

23 of 34

Similar impacts

  • Promise
  • TypedArray
  • SharedArrayBuffer
  • ArrayBuffer

24 of 34

RegExp

25 of 34

Changes

  • Keep @@match et al. as the interface between String / RegExp
  • Instead of this.flags,this.exec, etc. consult this.[[OriginalFlags]]

26 of 34

Before & After

27 of 34

What about WebCompat?

28 of 34

Current Efforts

  • Using Chrome UseCounter data to get a conservative picture of usage of subclassing mechanisms, namely @@species and .constructor.
  • Using queries on HTTP Archive.
  • Using a crawler to check more in depth URLs from queries on HTTP Archive.
  • Using instrumented builds of browsers to manually check for breakage.

29 of 34

Results so far

  • Compatibility risk of unshipping @@species is real. Chrome counters estimate 2% of pages modify .constructor or @@species on Array, RegExp, and Promise
    • Both an undercount (eg. does not count modifying .constructor) and an overcount (shims)
  • Manual inspection revealed an outdated core-js shim unconditionally installing a function() { return this; } as the @@species getter.
    • Everything that we have found so far has been core-js.
    • We are looking for more ideas of how to test this.
  • Out of 1k sampled sites out of 400k, all 26 traps were from coreJS. Core-js is used by babel that would not be affected by removing subclassing.

30 of 34

Results cont.

  • We contacted Feross, which used to use subclassing, in order to see what the usage was like for affected methods (map, filter, or subarray)
    • Users responded that they do use slice, but not the other methods
    • Subclassing via species has already been substituted and removed
  • Angular.js used to have subclassing
    • Has a fallback
    • Would not be affected by this change, we can keep @@species for users to use as they wish.

31 of 34

Working Hypothesis

Most of the real uses are false positives due to outdated shims, and this change is by and large web compatible.

32 of 34

Exit Criteria

  • If removing Type III and Type IV is not web compatible, this proposal shall be withdrawn.
  • If removing Type II is not web compatible (or if there is renewed consensus in TC39 to uphold developer intuition) but removing Type III and Type IV subclassing is web compatible, then this proposal shall explore alternative ways to support only Type II with less implementation and security burden. If no good alternative arises, and implementers deem the benefits of removing Type III and Type IV alone does not justify changing behavior, this proposal shall be withdrawn.

33 of 34

To sum up:

This is a proposal to investigate, intervene, and if there is evidence that this is a positive direction, act.

  • We aim for reducing subclassing to Type I, we would settle for Type II
  • Steps:
    • Investigate the WebCompat Impact, and the impact of the intervention
    • Intervene and test -- Participating browsers implement the proposed intervention behind a flag, with a prolonged testing period
    • Assess the evidence.
  • We would use the staging process to track and inform the committee

34 of 34

Stage 1?