02:11 | <Stephen Belanger> | I think React is actually kind of a bad basis in a way, because I feel it’s pointing us down a road that is only useful for functional code and not so much for procedural code. |
02:44 | <littledan> | I don’t understand why running it in the top level snapshot wouldn’t also amount to Zalgo to the same extent as falling back to the registration context is |
02:51 | <littledan> | “Consistently do nothing” just isn’t an option for certain APIs which people have been bringing up here |
02:54 | <Stephen Belanger> | I don’t understand why running it in the top level snapshot wouldn’t also amount to Zalgo to the same extent as falling back to the registration context is |
02:54 | <Stephen Belanger> | But yes, an imperfect solution. |
03:01 | <littledan> | I’ve been polling framework authors. Everyone is excited about AsyncContext, they all think it will work well for them for one or two variables like Justin said, and no one thinks it would be especially important to build stuff like React Context on top of |
03:01 | <littledan> | So I think we can forget about my point about needing saving and restoring contexts from JS to avoid an allocation |
03:10 | <Stephen Belanger> | We literally just landed that exact capability for CPED in V8 because AsyncLocalStorage in Node.js, Deno, and Cloudflare all need it. 😅 |
03:48 | <littledan> | We literally just landed that exact capability for CPED in V8 because AsyncLocalStorage in Node.js, Deno, and Cloudflare all need it. 😅 |
03:49 | <Stephen Belanger> | Saving and restoring context from JS. |
03:50 | <Stephen Belanger> | We just landed some code to generate turbofan code for setting and getting the context slot from pure generated code so we don’t have to go to native/builtins. |
04:07 | <littledan> | So how are you setting the cped? |
04:14 | <Stephen Belanger> | See: https://github.com/v8/v8/commit/7857eb34db42f339b337c6bdfb0d10deb14862f3 |
04:17 | <Stephen Belanger> | Basically we’re generating code to be able to interact with the context slot on the isolate from optimizable JS code. |
04:21 | <Stephen Belanger> | Node.js very frequently needs to set and get the stored value from both native and JS side. We have lots of native handles for async code that needs to capture when they are constructed and restore when their callback runs. We also have lots of JS-side things like the timer queue which needs to be able to do the same captures and restores from JS efficiently. |
04:46 | <Steve Hicks> | I don’t understand why running it in the top level snapshot wouldn’t also amount to Zalgo to the same extent as falling back to the registration context is |
05:02 | <Justin Ridgewell> | Node.js very frequently needs to set and get the stored value from both native and JS side. We have lots of native handles for async code that needs to capture when they are constructed and restore when their callback runs. We also have lots of JS-side things like the timer queue which needs to be able to do the same captures and restores from JS efficiently. |
05:05 | <Justin Ridgewell> | In the last meeting Dan suggested changing the new Snapshot() API (that returns a new object wrapping the internal context mapping) with a getSnapshot() immutable API that always returns the same object. |
05:05 | <Justin Ridgewell> | Purely as a performance optimization for frameworks that need to take lots of snapshots. |
05:21 | <James M Snell> | For workers, like node.js we have lots of things that are implemented entirely in c++ that need to be able to grab and preserve and manually propagate the current context across non-javascript async boundaries. For instance, any time we perform native I/o we have to grab a reference to the current snapshot and manually restore that when we are entering back into JS to continue. We build on v8's cped API for this. It's not an optimization as there are some things we use this for that only exist at the c++ layer... That is, we effectively have a c++ API equivalent to AsyncLocalStorage for things like metrics, etc |
05:33 | <Stephen Belanger> | Yes, the C++ side is certainly a requirement. I was more referring to the JS equivalent interfaces though which don’t call into native code and so don’t incur the native barrier cost. We can just expose the C++ API to JS, but it’s much slower. |
05:34 | <Stephen Belanger> | Thus the effort to expose generated code versions of setting and getting the context slot. My benchmarks show it being up to 120x faster than the native interface. |
05:34 | <James M Snell> | Yep, we absolutely need both with as little cost as possible. |
05:34 | <Stephen Belanger> | Which makes the difference between ALS being viable and not viable in many companies. |
05:36 | <James M Snell> | The new API absolutely won't be viable for us in workers unless we have both. There's no doubt about it |
05:39 | <Stephen Belanger> | Yep, same for many of our Node.js customers. The overhead of ALS is way too expensive, and the majority of the cost is just in how frequently that set and get are called—especially the get. That’s just about the hottest code in all of Node.js. 😅 |
05:40 | <Stephen Belanger> | My rewrite should make it more viable for a lot of customers, but even still, it’s hard to convince some customers when they see single digit overhead numbers in other languages and then like 30%+ sometimes in Node.js. 😐 |
05:44 | <Stephen Belanger> | Anyway, point is: it needs to be fast or it doesn’t help us. Server JS environments are doing way more frequent async activity than any browser environment ever would, so performance will impact us significantly. |
09:17 | <Chengzhong Wu> | Host APIs on manipulating the snapshot can definitely be optimized without strict 1:1 map to the JS built-ins. CPED extras binding is this kind of optimization that is not restricted by the ecma262 |
18:25 | <littledan> | It's not zalgo because it's statically determinable from the registration site. If you register a lifecycle hook in a particular context you know for certain that it will not hold onto a reference of that context - that's valuable. The alternative is that it holds onto a reference in case the lifecycle event is caused externally - that's the unpredictability/inconsistency I'm worried about. |
18:26 | <littledan> | For workers, like node.js we have lots of things that are implemented entirely in c++ that need to be able to grab and preserve and manually propagate the current context across non-javascript async boundaries. For instance, any time we perform native I/o we have to grab a reference to the current snapshot and manually restore that when we are entering back into JS to continue. We build on v8's cped API for this. It's not an optimization as there are some things we use this for that only exist at the c++ layer... That is, we effectively have a c++ API equivalent to AsyncLocalStorage for things like metrics, etc |
18:27 | <littledan> | Anyway, point is: it needs to be fast or it doesn’t help us. Server JS environments are doing way more frequent async activity than any browser environment ever would, so performance will impact us significantly. |
18:43 | <Stephen Belanger> | enterWith /set is not about performance, it's about usability. There are some cases where it can eliminate additional closures, but it's much more about a lot of patterns being difficult or impossible to express effectively when a closure is required--like you need to nest for both async functions and generators, and you need these additional closures in a lot of places where the given scope would exactly match what the runtime could have given itself automatically. |
18:45 | <Stephen Belanger> | Also, flowing forward makes a lot more sense with a set style interface as it is treated more like an actual variable reference and not some callback thing pretending like it's a variable. |
18:46 | <Stephen Belanger> | It also better matches the reality that context is actually a runtime capability not a type. Context variables are just interfaces to the runtime semantics the same as regular variables are to lexical scope. |
18:48 | <Stephen Belanger> | Treating context as an isolated type and not a runtime capability leads to poor usability designs. |
20:42 | <littledan> | For the slides: I put a slide about web framework feedback in the deck, as the first slide, since it might make sense for that to come before the issues |