WebKit is now 100% ES6 complete
twitter.com
twitter.com
tl;dr we implemented it, it works, but we are not shipping it because we believe it would hurt developers to lose some stack frames from Error.stack in existing sites, among other issues.
function mainloop()
local packet = receive()
if not packet then
syslog('warning',"error")
return mainloop()
end
process(packet)
return mainloop()
end
(mainly because Lua does not have a 'continue' statement, and this is the best way I've found to handle that) or in state machines: function state_a(state)
return state_b(state)
end
function state_b(state)
return state_c(state)
end
function state_c(state)
if somecondition()
return 'done'
else
return state_a(state)
end
end
The thing to remember is that a TCO is a form of GOTO. And with GOTO, you have no stack entry, but given that this is a controlled GOTO, I don't see much wrong with it. Do most programmers find TCO that confusing? Or is it the perception that most programmers will find TCO confusing? Have any real studies been done?http://repository.readscheme.org/ftp/papers/ai-lab-pubs/AIM-...
For example, you could compact the stack every 200 frames it grows, but never remove frames in the top 50 or bottom 50. How often in practice would that give you a misleading view of the stack? (Assume that each frame keeps track of how many tail frames are omitted after it. If needed, assume that tail frames within X distance of a non-tail frame will not be omitted ever.)
It works great!
(I hope Felix sees this particular commit sometime; I think he might feel a little flattered! Also, wow, that's an excellent summary by Peter Bex.)
Another is that you keep looking into old quiet dark corners of language nerdery and actually make use of the good ideas lurking there (notably while retaining the "no performance regressions EVER" tyranny).
I think there are some neat ideas Chicken Scheme's compiler too.
Also, did you have a raiding party on T when doing DFG? (cf. Olin Shivers at http://www.paulgraham.com/thist.html starting with the paragraph, "This brings us to the summer of 1984. The mission was to build the world's most highly-optimising Scheme compiler." and notably also the paragraphs starting "Richard Kelsey..." and "Norman Adams...". . Always take ideas from Shivers, at least if they're faster in practice. Also, sorry for the several edits. I forgot how good this overview was, and how much meat is in it.)
1) I'm not aware of complaints about the change to error.stack behavior from users or developers. I don't know of an app that broke because of the change to error.stack. I don't know of an app whose telemetry got messed up because of the change to error.stack. So, we don't have a real-world test case that would be improved or fixed by integrating ShadowChicken into error.stack. We're not going to impose any overhead, or spend time trying to optimize that overhead, if it isn't going to benefit anyone.
I've heard lots of hypothetical fears about error.stack changing, but I haven't seen a real-world example of the change in error.stack behavior being harmful. If you know of an app that breaks because of our error.stack change, please let us know!
2) Philosophically, we view the feature as PTC (proper tail calls), not TCO (tail call optimization). If it was an optimization then we'd want it to be hidden from the user. But that's not what PTC is: it's a guarantee to the user about how the stack will behave. Therefore, we make error.stack precisely reflect PTC. We go to great lengths to emulate PTCs in some cases to make this work, for example if the optimizing JIT is involved. For example:
function foo() { ... } // say that this is inlined
function bar() { return foo(); } // this tail-calls foo. say that this is inlined
function baz() { return bar() + 1; } // say that our top-tier JIT compiles this
In this case, foo and bar will sort of cease to exist since all that really matters for execution is the code that the JIT generated for baz, which now also includes the code for foo and bar. Inlining is super careful about error.stack. In this case, our optimizing JIT's inlining data will include complete information about the call stack (baz->bar->foo) but will flag the bar frame as tail-deleted so that error.stack will only show baz->foo.
So, instead of making ShadowChicken hide PTC from error.stack, we actually have an entirely separate set of features to make error.stack precisely reflect the reality PTC. On the other hand, if you open the inspector, we want ShadowChicken to show you the tail-deleted frames and to flag them appropriately. The inspector integration WIP is here: https://bugs.webkit.org/show_bug.cgi?id=156685
Screenshot: https://bug-156685-attachments.webkit.org/attachment.cgi?id=...
TL;DR. JSC doesn't try to lie to its clients about PTC. PTC is part of the language, so we precisely reflect PTC's behavior in error.stack and in the inspector (the tail-deleted frames show up but are flagged as such).
(EDIT: I changed the definition of bar and baz above because my original example didn't have the tail calls that I wanted.)
We already know that debugging isn't the issue. ShadowChicken solves the debugging problem and other VMs could do it, too. ShadowChicken is just one possible algorithm in a much larger family of chicken algorithms.
The only way that PTCs are observable outside the debugger - beyond making you run faster and use less memory - is error.stack. Hence the challenge: find me a website that uses error.stack in such a way that PTC breaks that website. Surely if the other VMs are so against PTC on the grounds that it will break websites, they will be able to tell us about a website that broke in Safari because of PTC.
Even if were the worst engine since IE4, it's Not Chrome(tm) and can help when chrome dev tools fail (or - more likely - I fail at working with chrome dev tools and need a fresh perspective.)
It's also good practice to run the profilers at least occasionally, because (a) performance in Safari is relevant and I've been bitten by idiosyncrasies where one browser took >5x than another (in all directions. And (b), as above, just by being different they may add useful information.
What changed your/the team's mind?
There's been a lot of active discussion between browser vendors and TC39 recently to sort out a path forward. All teams are excited about explicit TCO syntax, but there remains skepticism that implicit TCO is good for users or developers.
This is a problem for AOT languages, where binary compatibility is paramount and so you cannot change the calling convention. Since tail calls don't play well with existing native conventions, they end up being hard (or sometimes even impossible) to implement.
That's not really an issue in JS or other VM-based languages. JS VMs don't make their internal calling conventions public. In JSC, our old calling convention was incompatible with PTC, so we changed our calling convention to make PTCs work.
No browser is at 100%, BTW.
Waiting for a WATWG JavaScript standard that removes these parts from the spec...
On the subject of the table, it's interesting that Firefox's only failure is in "Date.parse produces NaN for invalid dates". However, as far as I can tell this is not a requirement of the spec, since per https://tc39.github.io/ecma262/#sec-date.parse
> If the String does not conform to that format the function may fall back to any implementation-specific heuristics or implementation-specific date formats.
I.e. instead of waiting for ecma262 to be implemented by all browsers, scripts can just load common polyfill, which then can be overridden by browser later:
<lib name="ecma262" version="1.0"><script scr="https://cdn.host/ecma262.polyfill.js"/></lib>I didn't know the standard existed.
Generally, agree with the "let's put back every piece of dung in place after paving the cowpath" approach the WHATWG follows. Anosmic folks come to rely on the reduced friction coefficient...
I suppose that the Date.parse stuff was updated between ES5 and the living stabdard.
The loader repository at https://whatwg.github.io/loader/ is an experimental proving ground, as noted by its title ("A Collection of Interesting Ideas") and its Status section ("This document is a work in progress and dreams of becoming a living standard."), as well as the fact that it's in the whatwg.github.io namespace instead of the spec.whatwg.org namespace. To my knowledge no browser implementers have begun implementation of the experimental ideas here.
Contrast that with the agreed-upon work in the WHATWG HTML Living Standard discussed at https://blog.whatwg.org/js-modules, which is relatively finalized and is being actively implemented now in all browser engines.
I think we will see a gradual stabilization of the experimental ideas in the Loader spec, either in the Loader spec itself (with the stable ideas staying, and the experimental ones moving to a supplementary document) or by moving the relevant spec text into other locations (HTML and/or ES, probably). For example, I would hope that we will soon see a very simple promise-returning `importModule("./foo.js")` async module loading API, far ahead of the loader's more experimental in-browser-transpilation APIs or create-a-module-from-scratch-reflectively APIs. That could be done either by specifying it in the Loader spec, or by specifying it in ES with a call-out to a HostFetchModule() abstract operation, which HTML then specifies for browser hosts.
Just to clarify, unlike TC39, the WHATWG HTML ("Living Standard") spec requires no consensus at all in order to add new features. Consensus is arrived at once all implementers have implemented the relevant features to the stable versions of their browsers.
To say that what is in the spec has consensus at the same time as browser implementers are beginning implementation (and expressing some concern over details) gets the WHATWG process backwards.
If you'd like to analogize to the TC39 process, features are merged into the HTML Standard once they've reached TC39 "stage 3".
When the Babel community creates a module loading approach, it's guessing at the future ("The spec is the law! When the community makes something, it's guessing at the law!").
Edit: To clarify, I want them standardized more than anything else, but as far as I know ES6 only specified the syntax
It's a dev preview. There is no reason to use it as your main browser. There isn't even much point testing your site in it, since you can never tell who's responsible for something being broken, and it becomes more a test of how production-ready the preview is, which is a really pointless metric. The only real reason for its existence is so we can all track progress in benchmarks, and for this story to get publicity when all us browser nerds check ES6 compat and then try little code snippets in the console.
If you want the cool purple icon, copy it to to Safari 9. That's what I've done.
1) With gifs, Safari TP will loop the first few frames (or whatever loads quickly) and loop that, whilst the remaining frames load, but then never update to looping the entire gif once completely downloaded; refreshing doesn't correct it, just focussing the address bar and hitting to load the gif from cache.
2) Math.random() returns the same result the first two calls on page load.
Tracked here: https://bugs.webkit.org/show_bug.cgi?id=157805
Great job spotting it chrstphrknwtn!
I changed the icon out with the original safari icon though, personal preference, and set it as my system default web browser.
Anyone know of any good tooling to use transpiled code for older browsers and es6 for newer?
EDIT (for clarity): It'd be great to see similar query support to derive a "lowest common denominator" Babel preset for an intended ES generation vs. browser profile set.
[1] https://github.com/postcss/autoprefixer [2] https://github.com/ai/browserslist#queries
Also https://twitter.com/samccone/status/722826060161617923.
You should continue to use the transpilers for some time though. It has been reported that many ES6 features run quite a bit faster as transpiled ES5 than natively as ES6.
However... the potential upside is size. Native code will usually be smaller, which for a web client is a win.
And I would assume that the baseline has been established on a per-engine basis.
Chrome JUST took over IE in market share in the last few months here. All other browsers are sub-5%.
IE11 is the new IE6 and will be around a long time in enterprise. Thank you Microsoft. It's epecially annoying as Edge is based just on a refactored and improved trident engine after all, so basically IE12 html engine under hood (and was already called "Edge" in DevTools in IE11).
[0] var isStrict = (function() { return !this; })();
I'm 99% super confident that this is an almost optimal solution.