22 ms·
How JavaScript works: inside the V8 engine
- kevmo314 9y ago> Now, you would assume that for both p1 and p2 the same hidden classes and transitions would be used. Well, not really. For “p1”, first the property “a” will be added and then the property “b”. For “p2”, however, first “b” is being assigned, followed by “a”. Thus, “p1” and “p2” end up with different hidden classes as a result of the different transition paths. In such cases, it’s much better to initialize dynamic properties in the same order so that the hidden classes can be reused. Does that mean an object with n properties takes up O(n^2) memory for the class definitions or O(n!) if the classes do not guarantee a property initialization order?
- ridiculous_fish 9y agoAn object with N properties will typically require N hidden classes, forming a chain back to the empty class. However most hidden classes only require a constant amount of memory, so this is O(N) allocation size. If you initialize the same properties but in a different order, you'll get a new list of N hidden classes. In the worst case you could indeed have O(N!) hidden classes, if you construct with every possible initialization order.
- inglor 9y agoAre you sure of that? If I recall correctly from the source an object with N properties typically requires 1 hidden class (for that object). In order for it to require 8 it needs to add properties very dynamically. Am I remembering this wrong?
- ridiculous_fish 9y agoYou can see the description of how hidden classes work on the v8 wiki [1]. The short explanation is that the way v8 finds a hidden class is by following a chain of transitions starting at the empty class. Intermediate classes have to be kept around to retain the transitions. That is, in code like: function Point(x, y) { this.x = x; this.y = y; } v8 retains the hidden class for {x}, so it can find the hidden class for {x, y}. [1] https://github.com/v8/v8/wiki/Design%20Elements#fast-property-access https://github.com/v8/v8/wiki/Design%20Elements#fast-propert...
- btown 9y agoIs there a way to see what hidden class an object has? For instance, if an array of objects is parsed from json, were all the objects assigned the same hidden class? Alternately, can one obtain statistics about hidden class usage? Seems like this would be very helpful for real world apps, especially given the prevalence of data intensive Electron apps. EDIT: https://www.npmjs.com/package/v8-natives https://www.npmjs.com/package/v8-natives haveSameMap seems to do exactly this!
- sjrd 9y agoFor a more comprehensive reference on v8 internals, there is http://wingolog.org/tags/v8 http://wingolog.org/tags/v8, which has been around for a long time. It is even directly referenced from https://developers.google.com/v8/under_the_hood https://developers.google.com/v8/under_the_hood. I don't think there's anything in this post that wasn't already explained in this reference, except the fact that now there's Ignition and TurboFan, but that doesn't fundamentally change anything.
- cm2187 9y agoI was wondering, given that 90% of the javascript in browsers must be standard libraries (jquery, bootstrap & co) wouldn't it make sense for google to hash the source code for every published version of these libraries, compile those statically using full optimisation and ship the binaries as part of their updates to the browser, so that you only have to compile the idiosyncratic part of the code?
- sand500 9y agoMaybe ship popular libraries as web assembly?
- mhh__ 9y agoCould be done, although it would have to be done carefully.
- sjrd 9y agoRight, because wasm is there to solve all our performance problems, isn't it? And how exactly is your jquery.wasm going to access the DOM? Or expose methods to your application, for that matter? wasm is not a drop-in replacement for JS.
- Spivak 9y agoNo, but if we're being honest, it's exactly what everyone wants it to be. A bytecode for the web.
- Fifer82 9y agoI really don't know much about wasm. I just wondered though, from a birds eye view, does using wasm effectively give you control of everything within the "frame" of your browser? Can I get rid of the DOM(boilerplate aside), get rid of CSS? For example HTMLCanvasElement is a flat surface. I can do what I want within it as a scene graph renderer. Could I do that with wasm? Could I invent my own 2D entities (x, y, width, height). My own 2D Constraints resize like Apple Devices etc?
- dlbucci 9y ago> Also, try to avoid pre-allocating large arrays. It’s better to grow as you go. Is this really true? I've only heard the opposite (preallocate arrays whenever possible) and I know that preallocation was a significant performance improvement on older devices with older javascript engines.
- ChrisSD 9y agoHm, it might have something to do with this: https://groups.google.com/d/msg/v8-users/Vov_e5GUq3o/eqRT8mAePMMJ https://groups.google.com/d/msg/v8-users/Vov_e5GUq3o/eqRT8mA... > For preallocated arrays, 100,000 just so happens to be the threshold where V8 decides to give you a slow (a.k.a. "dictionary mode") array.
- nybblet 9y agotl;dr: No, this is outdated, and please don't try to hand-optimize. This is outdated. It was true in 2013, but changed in 2014 (https://codereview.chromium.org/416403002/ https://codereview.chromium.org/416403002/ ; specific change in elements.cc). Two tangential cents/Unpopular Puffin: there's a lot of misinformation or half truths that are propagated about V8 in an effort to boil all their optimizations down to One True Set of Advice, in this post and others. The thing is, in just about every case, the real answer is "it depends". That's why V8 is ~1,000,000 lines of code, not 1,000. Please don't try to follow some rule blindly, much less derive. More often than not, when you try to hand-tune for the last bit of performance, you'll actually trigger something that was introduced to streamline the other [95% of] cases/JS devs' code, and then you've spent hours on making your code less readable with no benefit. There is no "Try This One Crazy Trick To Make Your JavaScript Fast!!!" (or even ten!) (And in this particular case of pre-allocation vs. growing as you go? Usually the difference is so tiny it doesn't matter, and in the other cases --- it depends.) Disclaimer: I'm not on the V8 team but I'm on a personal basis with some of them, and these are my own thoughts cobbled from casual conversations.
- edw519 9y agoWhy don't you benchmark it yourself and let us know what you learn. Data > Rumor.
- Veedrac 9y ago> How to write optimized JavaScript This is all sensible advice if you're interested in writing fast-enough code, but I do find there's a lack of material for people who want to write fast Javascript. Pretty much the only thing I've found is the post by Oz[1], though I really don't want to have to compile Chrome. For an example, I have a method in Javascript that does a mix of (integer) arithmetic and typed array accesses; no object creation or other baggage. I want it to go faster, and with effort I managed to speed it up a factor of 5. One of the things that helped was inlining the {data, width, height} fields of an ImageData object; just moving them to locals dropped time by ~40%. Yet after all this effort, mostly based on educated guesses since Chrome's tooling doesn't expose the underlying JIT code for analysis, the code is still suboptimal. There's a pair of `if`s that if I swap their order, that part of the code allocates. How do people deal with these issues? A large fraction of this code is still allocating, and I haven't a clue where or why. Perhaps I'm asking too much from a language without value types (srsly tho, every fast language has value types), but what I want is clearly possible: ASM.js does it! I don't really want to handwrite that, though. [1]: https://www.html5rocks.com/en/tutorials/performance/mystery/ https://www.html5rocks.com/en/tutorials/performance/mystery/ (E: This link is actually written from a different perspective than the one I read, but the content is the same.)
- pjmlp 9y agoYes, it would be nice to just have some config flags to enable it on the debugger.
- inglor 9y agoYou can ask V8 to dump the assembly or intermediate representation or you can just run it with --trace-deopt and it'll tell you most of the time (generally) what's slowing your code down. > I'm asking too much from a language without value types JavaScript has value types, what it doesn't have is user defined value types. BigInts are coming (stage 3 already!) though.
- avaer 9y agoI have some experience with this stuff, and my go-to advice is: - Never construct or mutate objects in a loop or recursive call. - Preallocate the max of what you'll need at load time, then index into it. - Prefer typed arrays over objects. - Don't use strings. Work with numbers. - Remove function calls. - Do not call a function with differently shaped arguments. - If the JS engine can't prove a number is a 32 bit int, you'll take a large perf hit. - Break out your algo into a worker. Not only does it keep things responsive, but it might actually be faster due to less GC pressure. - The web stack is full of frightening gotchas that you'll discover. Recieving large data on a WebSocket can halt your DOM rendering. Leaking a Promise callback can completely blow a function into interpreter mode. And other fun times. Finally: If you're hand optimizing and not getting sufficient results on your preferred browser, accept that you're screwed. The next browser will break your assumptions. Rethink your algorithm and data flow, or move it elsewhere, like a worker or server. I do agree the tooling for this stuff isn't great, but I found Chrome's line-by-line perf counts to be excellent hints about where you could do better. It's often surprising but obvious in retrospect.
- fdw 9y agoIf you're into V8 internals, I'd recommend watching these talks by Franzsika Hinkelmann, a V8 engineer at Google: https://www.youtube.com/watch?v=1kAkGWJZ6Zo https://www.youtube.com/watch?v=1kAkGWJZ6Zo , https://www.youtube.com/watch?v=B9igDWV5ZUg https://www.youtube.com/watch?v=B9igDWV5ZUg and https://www.youtube.com/watch?v=p-iiEDtpy6I&t=606s https://www.youtube.com/watch?v=p-iiEDtpy6I&t=606s She's also recently started blogging at https://medium.com/@fhinkel https://medium.com/@fhinkel
- deleted 9y ago[deleted]
- cryptozeus 9y agoThanks for the post, great writing...
- yanowitz 9y agoInteresting article--I'd love to see one just on GC. I just downloaded the latest node.js sources and v8 still has a call to CollectAllAvailableGarbage in a loop of 2-7 passes. It does this if a much cheaper mark-and-sweep fails. Under production loads, that would occasionally happen. This led to pause-the-world-gc of 3600+ms with v8, which was terrible for our p99 latency. The fix still feels weird -- we just commented out the fallback strategy and saw much tighter response time variance with no increased memory footprint (RSS). I never submitted a patch though because although it was successful for our workload, I wasn't sure it was generally appropriate (exposed as a runtime flag) and I left the job before I could do a better job of running it all down.
- tracker1 9y agoI've had a similar, but differing issue on a server that ran a lot of one-off node scripts for things ranging from ETL, or queue processing. I found that I wanted to force GC after every, or every N items, because the memory could bloat out a lot before GC would happen and pause for several seconds... or, potentially starving out peer processes. Fortunately, that was already in the box, though behind a runtime flag.
- schindlabua 9y agoDoes this also mean that in the function that returns an object vs. prototype debate the former wins because object literals presumably require less class transitions? let Ctor = function(a, b){ this.a = a; this.b = b; } vs let obj = (a,b) => ({ a:a, b:b });