News for hackers. Stuff that matters.
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by fenomas on Monday August 08, 2022 @01:23AM (#32382587)
> 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.

Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by ncmncm on Monday August 08, 2022 @01:57AM (#32382734)
I 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.
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by fenomas on Monday August 08, 2022 @02:13AM (#32382807)
TFA 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.)

Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by whizzter on Monday August 08, 2022 @04:21AM (#32383389)
The 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-statem...

Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by fps_doug on Monday August 08, 2022 @04:11AM (#32383355)
TFA 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.
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by fenomas on Monday August 08, 2022 @05:22AM (#32383653)
Sure, 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.
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by whizzter on Monday August 08, 2022 @04:22AM (#32383398)
The if-else behaviour comes from the EcmaScript spec, check the sibling comment.
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by hinkley on Monday August 08, 2022 @12:07PM (#32387299)
> 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.

Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by madacol on Monday August 08, 2022 @07:36AM (#32384333)
What is TFA?
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by cleerline on Monday August 08, 2022 @07:52AM (#32384428)
The Freaking Article
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by dotancohen on Monday August 08, 2022 @09:29AM (#32385121)
The _Fine_ Article.
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by ruuda on Monday August 08, 2022 @02:06AM (#32382776)
V8 did not have an interpreter in 2013.
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by nickelpro on Monday August 08, 2022 @02:20AM (#32382837)
Of course it did, how do you think a JS engine runs code that it doesn't have any type information about without an interpreter?
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by dchest on Monday August 08, 2022 @03:23AM (#32383105)
The bytecode interpreter appeared in 2016 https://v8.dev/blog/ignition-interpreter Before that, it compiled everything into machine code.
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by Dylan16807 on Monday August 08, 2022 @06:38AM (#32384023)
With 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.

Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by nickelpro on Monday August 08, 2022 @11:53AM (#32387085)
I guess I'm differing on this point. By "baking in" the dynamic dispatch the final compiled code is, in my mind, an interpreter. Which is how I always thought of the "Full Codegen" step of the old v8 architecture.
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by ruuda on Monday August 08, 2022 @07:18PM (#32392314)
I guess the lines can be a bit blurry especially when the compiled code still relies heavily on dynamic dispatch, but V8 generated machine code for the target CPU, marked the page as executable, and then it would call that just generated code. I think most people would call that a JIT-compiler.

It wasn’t a very advanced compiler in the sense that it generated very inefficient machine code. But it still ran circles around a tree-walking or bytecode interpreter. Over time the compiler became more advanced and multi-tiered, but at the cost of startup time, and mobile was taking off, where memory was more scarce than on desktop. x86 or ARM code is a lot bigger than a specialized bytecode that is optimized for space efficiency. So eventually the Ignition interpreter was added. But unlike some of the other Javascript engines that started as an interpreter and later added native code generation, V8 started out generating native code and only later added a bytecode interpreter.

Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by Dylan16807 on Monday August 08, 2022 @03:23PM (#32389836)
Well let's say you wrote C++ where most of your data is in a super union of float, string,*, bool, int, map*, etc, with gobs of repetitive dynamic dispatch whenever you touch one of those unions. That wouldn't mean your code is being interpreted, would it?
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by ReadTheLicense on Monday August 08, 2022 @03:55AM (#32383264)
Could 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...
Re:I 10x'd a TI-84 emulator's speed by replacing a switch-case by fenomas on Monday August 08, 2022 @04:28AM (#32383417)
Basically, 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.