4 ms·
> the poor performance of switch for opcodes I think you've slightly misunderstood TFA. The issue there wasn't that the switch statement was slow, per se - it
by fenomas 4y ago
> the poor performance of switch for opcodes
I think you've slightly misunderstood TFA. The issue there wasn't that the switch statement was slow, per se - it was that V8's optimizing compiler didn't yet support such statements, so V8 was bailing out of its JIT step and executing the function via a (dog-slow) interpreter. In other words the function would have run painfully slow even if it returned before reaching the switch statement.
It's also maybe worth adding that gotchas like this were super common way back in the early days TFA describes, but AFAIK they are no longer a concern now. Back when V8's optimizer was primitive it used to bail out for all kinds of reasons - because it saw a "try()" statement, because a function was too long, or even just because it got confused. Nowadays it's a different world - I do a lot of JS perf work, but it's probably been two years since I've seen V8 deopt anything for any reason.
- ncmncm 4y agoI think you also misread the article. It clearly said that an optimized switch would still run as a series of "if" tests, and that when he got the compiler to generate that code, it wasn't faster.
- fenomas 4y agoTFA doesn't cover any cases where switch statements got optimized. It starts with the relevant code getting deopted, then the author tries a fix but the code is still deopted, then he removes the switch statements. (Mind you I'm not saying switch statements are fast - they may well be slower than the alternatives even after being optimized. I'm just pointing out that TFA isn't about the performance of switch statements, it's about avoiding deopts.)
- fps_doug 4y agoTFA references a post that states that optimized switch statements in V8 are still just if-elseif-else and not jump tables, at least back when it was written. They might be faster than unoptimized JS, but certainly not as fast as jump tables. The author didn't even bother to split up the functions/switch blocks further when they learned about the requirements to get V8 to actually optimize a switch, as it seemed not worth it.
- whizzter 4y agoThe if-else behaviour comes from the EcmaScript spec, check the sibling comment.
- fenomas 4y agoSure, none of that is in doubt. But in my experience the performance cost of hot code getting deopted is so massive as to overwhelm virtually any other factor, so realistically, fixing the deopt is what solved TFA's problem. Of course getting rid of the switch statements was presumably an additional speedup, but since TFA doesn't compare those cases I guess that's neither here nor there.
- whizzter 4y agoThe EcmaScript switch spec basically says that each case statement in turn is evaluated until one becomes equal or default is encountered, so to follow the spec the basic case is equal to a bunch of if-else's. To optimize the runtime first has to figure out that all case values are constants (and insert guards to de-opt if it doesn't hold anymore), so in essence the machinery for running this code optimized has to be very conservative (and probably why they placed arbitrary limits that really aren't suited for emulators). https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#prod-SwitchStatement https://tc39.es/ecma262/multipage/ecmascript-language-statem...
- ruuda 4y agoV8 did not have an interpreter in 2013.
- nickelpro 4y agoOf course it did, how do you think a JS engine runs code that it doesn't have any type information about without an interpreter?
- dchest 4y agoThe bytecode interpreter appeared in 2016 https://v8.dev/blog/ignition-interpreter https://v8.dev/blog/ignition-interpreter Before that, it compiled everything into machine code.
- ReadTheLicense 4y agoCould you please explain what do you mean by type information? I thought you never have type information in JavaScript... - except the base types (bool, number, string, object, array, function), but you always have this information...
- fenomas 4y agoBasically, modern JS engines are fast because they do a lot of inferring about types. They do this both statically (by inspecting the code at compile time) and dynamically (by watching the code as it executes), and they do it for objects as well as literals. For a hand-waving theoretical example, if you have code like: var a = { foo:1 } var b = { foo:2 } var c = { foo:3 } doSomething(a) doSomething(b) doSomething(c) then modern JS engines can see that the "doSomething" function always gets called with arguments of the same type signature, and if it's a hot function they might optimize the function around that information. If you want to know more, searching on "V8 hidden classes" should turn up relevant articles.
- Dylan16807 4y agoWith a bunch of dynamic dispatch. Interpreters and basic compilers are remarkably similar, and it's easy to transform between them if you do some extra busy work. Once you have your final AST, instead of outputting bytecode instructions, output the implementation of each instruction. Or vice versa. You have code that handles different types in the interpreter? Great, bake it into the compiled code. The transform from bytecode interpreter to compiler is always pretty simple, but the other way around gets more difficult the smarter the compiler is. So yes it is very possible to have a baseline javascript compiler and no interpreter.
- madacol 4y agoWhat is TFA?
- cleerline 4y agoThe Freaking Article
- dotancohen 4y agoThe _Fine_ Article.
- hinkley 4y ago> because a function was too long, Famously, function inlining decisions were based on the size of the function, not the size of the AST of the function, which lead to situations where removing inline comments allowed a function to be faster.