Allen Wirfs-Brock (AWB), Sebastian Markbåge (SM), Jafar Husain (JH), Eric Ferraiuolo (EF), Caridy Patiño (CP), Waldemar Horwat (WH), István Sebestyén (IS), Mark S. Miller (MM), Adam Klein (AK), Michael Ficarra (MF), Peter Jensen (PJ), Domenic Denicola (DD), Jordan Harband (JHD), Jonathan Turner (JT), Paul Leathers (PL), Chip Morningstar (CM), Vladimir Matveev (VM), Ron Buckton (RBN), Brian Terlson (BT), Alan Schmitt (AS), Ben Newman (BN), Mohamed Hegazy (MDH), Abhijith Chatra (AC), Tom Care (TC), John Neumann (JN), Dave Herman (DH), Brendan Eich (BE), Daniel Ehrenberg (DE), Dan Gohman (DGN), Andreas Rossberg (ARB), Rick Waldron (RW), Mike Pennisi (MP), Akrosh Gandhi (AGI), Jonathan Sampson (JSN)
(Andreas Rossberg, on phone)
ARB: Strictness Scoping
Issues:
DH: clarify backtracking (2 possibilities?)
ARB: rewinding token stream
ARB: easy in ES5 because only additional check is duplicate parameter names
"use sloppy";
function f(x, x) { "use strict"; }
Difficult in ES6, b/c default parameters
"use sloppy";
function f(g = (o) => {with (o) {}}) { "use strict"; }
ARB: also cannot determine scope due to interactions between Annex B and strict mode:
"use sloppy";
function f(g = function(h) {
{ function h() {} } return h;
}) {
"use strict";
}
WH: The issue in this example is hoisting and variable binding, which is more than just error checking. Function h here is nested inside a local block, which means that the 'h' in the return statement refers to different bindings in strict vs. non-strict mode. But you don't know that strict mode is in effect until encountering the 'use strict' later!
DH: Don't know yet whether this is an error until later. Previous examples: Store a "dirty bit". This example: have to have a data structure that will hoist in 1 of 2 ways if it turns out to be strict mode. Implementable without backtracking.
WH: Note that a single state bit is insufficient. You can have these things nested arbitrarily deep, leading to a potential exponential explosion of states.
ARB:
Much More Difficult in ES6
"use sloppy";
let f = (g = () => { /* Are we a parameter? Do we have to defer? */ with (o) {} }) => { "use strict"; }
ARB:
BE: The arrows are parsed with a cover grammar
ARB:
Categories of mode specific logic
DH: yield doesn't have contextual differences in strict mode, in generator functions
AWB: restricted in strict mode (non-generator) functions
DH: this-binding
YK: to be clear, these disadvantages only apply to sloppy mode programs; modules and strict mode programs are not affected
ARB: 3 modes, effectively:
DH: (discussing potential for performance regression)
ARB: Agree
AWB: Don't see this as a problem for JITs
BE: (asks implementors what they're doing to solve)
PL: We haven't gotten this far
ARB: This has been brought up with the team before, and token stream rewinding has been off the table
BE: If it can be done and satisfies performance constraints, then engines should consider
ARB: Compiling functions separately, ie. if function in parameters, compile sep. More than just rewind, would have to record all the functions, may be done with them, may not be done with them
MF: Can we see a proposal/solution?
ARB: Make it an error to have a "use strict" directive in a function with a non-simple parameter list.
YK: Should implement ES6 as written while this is resolved.
BE: "more of a guideline than rule"
AWB: You could make the restriction more specific: only disallow functions that declare "use strict" and contain a function in their formals list
ARB: Could be that only error when "use strict" inside function would change the mode, as the outer mode might already be strict
YK: refactoring hazard.
BE: Jason Orendorff says "works for me"
AC: don't like this suggestion, I don't want to impose an error because an implementor couldn't make it work
Discussion, re: hardship of implementation
YK: Don't like that end developers have to know why this won't work, b/c implementing hard.
BE: implementors are considered second to developers
AWB: previously, sloppy mode was restricted to simple parameter lists.
BE: No micro modes: no runtime semantic differences due to
AC: Chakra implements with rewinding
YK: objection: semantically this is the wrong thing
DD: but we're moving to all-strict world, so making the mixed mode cases more painful might be ok
DH: This is such an edge case that I don't tihnk there is an adoption risk.
BE: Suggestion fixes the right-to-left violation
DH: Could enumerate all those cases and make errors, but much harder.
YK: Poisoning function () { "use strict" }
BE: use top level "use strict"
YK: Not realistic
BE: Andreas reduced list to parameter lists that contain:
Discussion re: "use strict" expectations
YK: Prefer the stricter rule
DH: appear to have consensus on Andreas' solution
AWB: What exactly do we mean by "a function with a 'use strict'; prologue? Are we only talking about "strict transitions" (i.e. functions that declare "use strict" that are in non-strict contexts) or do we mean "use strict" in any functions.
MM: Functions that have a "use strict" know that they are strict, whether they are "pasted" or typed
MP: Another (less difficult/serious) case where strict-function-rewinding is relevant is in the case of named function expressions. e.g.
(function static() { "use strict"; });
Ref: https://bugs.ecmascript.org/show_bug.cgi?id=4243
Discussing implemention strategies
BE/AWB: existing semantics imply some right-to-left checking
BE: Non-simple is:
(Anything that is not a list of identifiers)
YK: Need to acknowledge that we'll need to tell people to not "use strict" in functions, if they use non-simple parameters.
Acknowledged.
The solution is just use top level "use strict"
DH: We'll fail to explain this at the level of enumerating ES6 features they can or can't use in this case. The outcome is something like "just use top-level strict, or iife strict"
YK: Not just this edge case: ES6 and strict mode has created this weird window.
AK: Functions in the parameter list might become strict if the function is "use strict"
DH: this
behaviour changes
YK: Ultimately breaking "use strict" for function
AWB: Any function whose mode (lost track)
Discussion about ES6 feature adoption.
RW: disagreed with error when "use strict" occurs locally, but outer mode is already strict (ie. no mode change)
Discussion about developer expectation.
AWB: there is another alternative spec function that is more restrictive: ContainsExpression
RW demures ("You might say I am not willing to die on this hill.")
(Daniel Ehrenberg)
DE: This change breaks the web (specifically: mootools calls Number.prototype.valueOf(Number.prototype)
)
https://esdiscuss.org/topic/number-prototype-not-being-an-instance-breaks-the-web-too https://github.com/mootools/mootools-core/issues/2711
Solution: roll back the change.
BE: Number, String, Boolean should be
MM: To be clear: Date.prototype will be an object, not Date; RegExp.protototype will be an object, not RegExp. Every built-in constructor introduced after ES5 will have a plain object prototype.
MM: Prefer we do Number, Boolean, String together
(Sebastian Markbåge)
https://github.com/sebmarkbage/ecmascript-string-left-right-trim
SM: Already shipping in all major engines. Controversy: what to call it?
JHD: in JavaScript, left-to-rightness of strings is a rendering artifact. The conceptual "first" character of any string, whether LTR or RTL, is index 0, and the "last" is index length minus 1. Thus, in JS, left/start/index zero are the same, and right/end/index length minus one are the same.
DH: These are extremely common in programming languages
Discussing semantics of "left", "right" and "start", "end"
DH: There is precedence for JavaScript interpreting the word "right" to mean "the end of a sequence", from ES5: Array.prototype.reduceRight
DH: The only thing that "use strict" can cause (in ES5) is an error (to the left)
AWB: There are implementation semantics, w/r to parameters
WH: How does it affect hoisting checks?
AWB: Hoisting rules in annex b don't apply if there is decl of same name (need to double check)
MM: How did we resolve names introduced in the function head vs names introduced in the function body, w/r let/const
AWB: disallowed
Discussion, re: strict in blocks?
AWB: need to check this against the existing function declaration instantiation, re: strict/non-strict checks
STH: Expressions in parameter list are not in strict mode.
YK: Bigger picture: ES5 introduced the concept of a strict function.
Discussion, re: expectations of strict mode in functions
AWB: parameter with an initializer that uses this
this
?this
is undefinedthis
is global object"use sloppy";
function f(foo = this) {
"use strict";
return foo;
}
f();
// what is the value of this expression? the global object? or `undefined`?
// w/r to Sam's proposal (eliminating right-to-left strict-ness effect)
YK:
With Sam's proposa, this would return [undefined, Global]
, despite expecting [undefined, undefined]
(function(foo = this) {
"use strict";
return [this, foo];
})();
DH: In ES5, there was a fundamental confusion about "use strict" in functions. This was exacerbated by ES6. In the fullness of time, TC39 is saying, the directive prologue should be used:
MM: We should be explicit w/r to "top level strict mode", in that we actually mean "top level iife with strict mode"—to avoid the concatenation problem.
Advice: "Just use modules".
AWB: (answers to questions from yesterday)
function * g() { this.foo }
x = {
*f() { this.foo }
};
new f(); // ok
new x.f(); // ok
Relevant SpiderMonkey bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1166950
DH: Bare generator function call behaviour is correct?
AWB: Confirm
Updated:
S | I | Code |
---|---|---|
X | X | { *foo() {} } (no [[construct]]) |
X | X | function * () {} (no [[construct]]) |
? | ? | function * () { this } is exactly like function() { this } |
AWB: Concern about removing new:
this
Acceptable risk?
BT: Implementors on both V8 and SpiderMonkey have shown interest in making generator not newable
new
throws(Domenic Denicola)
DD: (Showing https://tc39.github.io/process-document/)
Reviewed:
AWB: w/r to reviewers, committee should assign reviewers.
DD/RW: reviewers attached at Stage 1. Stage 2 entrance requires review
RW: Propose: At Stage 0, reviewers get "attached", but non-binding. (basically, it's a "champion group")
... Next thing...
Discussion re: Stage 4
RW: Concerns about flag/no flag
DD: Must be unflagged
RW: Disagree, will result in stonewalling from implementors
DH: Transpilers should count
Discussion, re: experiences had with other new features.
"Significant in-the-field experience with shipping implementations, such as that provided by independent VMs"
Stage 3: "Will require feedback from implementations and users"
(Dan Gohman, John Mccutchan, Peter Jensen, Daniel Ehrenberg)
DE: (introducing topic)
Unsigned comparisons Unsigned saturating add/sub Unsigned extractLane No changes needed for constructor, replaceLane because coercion will wrap unsigned values to the appropriate signed value No separate unsigned type
Float64x2--we couldn't find an important use case with improved performance Int64x2--Not needed due to boolean vectors, and really not needed because Float64x2 is out selectBits--minimal utility due to select, and efficiently implementable in terms of other boolean operations
widenedAbsoluteDifference, unsignedHorizontalSum, absoluteDifference Seeking implementation feedback: applications and benchmarks Replaces sumOfAbsoluteDifferences (slow on ARM)
Homoiconic toString()
SIMD.Float32x4(1, 2, 3, 4).toString()
=> "SIMD.Float32x4(1, 2, 3, 4)"
Shift operations max out at 0/-1, rather than wrapping around
Ops like reciprocalApproximation are loosely specified, like Math.sin
Removed operations on DataView--TypedArray ops suffice
Operations on subnormals may flush to 0, unlike ES scalars
Various minor spec bug fixes
AWB: w/r toString. The approach shown is a new precedent
DD: Similar to Symbol
AWB: Will this be the new way
BE: value types with literal form should convert, but this isn't value types. I like it.
AWB: Should other new things have this toString() output? Map & Set?
(moving on)
Lanes are required to be Int32s and not implicitly coerced
(See 5.1.2, http://littledan.github.io/simd.html )
AWB: for WebIDL, we advised to use normal ES coercions
DE: Considered specified getX, getY, etc.
DH: I don't know if it's that important to coerce or check.
BE: Doesn't want this to be an enumerated type. Symbols?
AWB: The advantage is that Symbol is not coercible and you only accept those that you've defined.
DE: if we had a Symbol API, we'd still want an extract lane API
STH: numbers are the right thing here
AWB: ToNumber, because that's what ES does
WH: Note that the proposal is a bit inconsistent in validating numeric inputs. For example, shifts use ToUint32 for the shift count, which turns -1 into a huge shift amount. ECMAScript's built-in shifts treat the shift amount mod 32, while the proposed ones treat it mod 2^32.
DE:
load and store take TypedArrays as arguments and permit array element type mismatch with SIMD type
WH: Reading spec, cannot load and store booleans. Looks intentional.
DE: Fails on booleans, intentionally.
WH: Fix other places in the spec for booleans, such as the statement that bitwise cast can cast any SIMD type into another SIMD type.
AWB: (requests justification for extracting values of a different type than the type of the Typed Array)
DE: DataView doesn't really work, in an asm context. Operations on DataView accept endianness where this has to use native endianness to be efficient
AWB: if int8 array, extracting floar 64, does it
DE: No, it is element-aligned. The hardware supports this.
DGN: (phone) confirms hardware support
AWB: If you're talking about a float32array and you're extracting int16's, that just seems like a type error.
DE: Better?
DH: Go back and change array buffer, can't do that
DE: how is opacity enforced?
(no answer yet)
WH: Some ArrayBuffers are indeed opaque. Restricted exposure for security reason
DH: TypedArray views on ArrayBuffer, detached
BE/DH: what they're doing will work
WH: Not a pointless invariant. Move on.
(moved on)
Questions for Committee
BE: have to call with new to get the object
AWB: Symbol is just odd because concern that new Symbol()
would be used to get a generative object.
DD: Necessary to impose a rule for creating a Symbol
DE: if you call construct, if NewTarget undefined, construct wrapper
AWB: Minimize new patterns. Overloading constructor is not new.
AK: Why this route instead of Symbol route?
DE: Symbol is special throwing on new? But maybe Symbol is the new way
DD: If no literal, then no new
. If a literal is added later, then re-open new
BE: (explains wrapper history, aggree with DD)
(moving on)
Spec Language Innovation Acceptable?
AWB: There was use of rest early in ES6, but taken out
BE: parameters that were optional
AWB: implies JS level parameter list
DE: no
Discussion, re: spec mechanisms
(moving on)
RW: Recommend moving this to a separate spec, similar to Intl (Ecma-402). (Note that this was considered ideal by the champions as well, despite the opposition from other members).
DH: disagrees
WH: Also disagrees with separate spec. This defines primitives tightly bound into the core of ES, with serious interactions and precedence-setting with other ES work such as value types.
DE: Issues surrounding value type definitions, but don't want to to wait for value types. Don't want to be blocked and separate spec ensures that
(moving on to implementation status)
Firefox Implementation Status
In Firefox nightly:
Microsoft Edge Implementation Status
V8 Implementation Status
Specification Status
Requesting reviewers
WH: purpose of spec, disagreement whether to support only use cases experienced or useful with a more ecmascripty orthogonal feel. For example, the spec currently can load int8, uint8, int16, uint16, int32, uint32, but it can only extract the first five of them (can't extract uint32 even though can extract int32 or uint16). Min and max work on floats but not on integers, even though there is no hardware obstacle to do so and even though there are much more complex intrinsics defined such as unsignedAbsoluteDifference.
DE: support unsigned operations on int16 and int8
BE: waldemar wants max on integers that can
DH: SIMD building clear layer to hardware
WH: want consistency:
WH: Diverged from TypedArray,
AWB: TypedArray both have int32 and uint32, JS programmer expects that
BE: argument to be consistent
DE: TypedArray is the model going forward, with the exception of Uint8ClampedArray
AWB/BE: Yes
WH: treatment of denorms non-deterministic
DE:
WH: Does the hardware flush both inputs and outputs to 0, or is there some major hardware that flashes only inputs or only outputs to zero? (an arithmetic operation might take denorms as inputs, or it could produce a denorm output even though all inputs are norms)
DE: Both inputs and outputs
WH: [later in the discussion] Intel has FTZ and DAZ bits which control these separately, so they can be independent.
(Difference between Arm and Intel)
DGN: Arm 64, arm v8 corrects this
MM: this non-determinism is actually just difference between platform
WH: The SIMD spec doesn't state that. It could differ operation-by-operation.
DE: The spec can't state that.
WH: Really? Why?
Discussion re: nan encoding
DE: http://www.ecma-international.org/ecma-262/6.0/#sec-setvalueinbuffer (step 9.a)
AWB: (explaining why spec says this)
DH: we should change the def of SameValueZero to say that two different bit patterns for a NaN are not equivalent
DE: create a data property and set value to one bit pattern, non-writable, non-configurable, call Object.defineProperty with a different NaN, then do [[Get]] and you'll receive old bit pattern
DH: No mutation, but incorrectly states that change was successful
DE: spec says a platform will have one endianess or the other; this can be applied to denorms. Spec dependent.
WH: What do relational operations (.equal, .lessThan, etc.) do when they see a denorm? treat as zero?
DGN: treat as zero
WH: So then what will === do? Do they equate all distinct denorms to zero (which would be really weird as ES behavior)? Are you going for the fast implementation of === or the precise implementation?
DGN: === does not equate denorms to zero, even on platforms that flush denorms. It can be slower than .equal.
http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4610935
DE: One outstanding question was whether this work should be done in a separate specification.
RW: Yes, I had suggested that. But you said something about a polyfill for SIMD.js?
DE: It is incomplete
BE: It can't express value object; it can't intercept ==
or ===
RW: Alright, then it is no longer a suggestion of mine
Unsigned Types? Argument for them?
Consistency with TypedArray
DH: I want to know more about what SIMD use cases are, operations should map to need
WH: want unsigned types:
(not an explosion of the API)
DE: fewer function names, more function objects.
AWB: lot's of domains with similar conventions
DE: it's a large thing, mostly irreducible
JHD: non-specialists are going to write this stuff by hand.
(Argument to make the API more like JS)
DE: prefer to keep it as is
YK: So a specialist doesn't need the unsigned types?
DH: Either accept Waldemar's argument, or state case based on historical precedence. If no consistency, then don't care.
WH: Note that I'm not alone with that argument. I don't want this to become personal.
new
throws