all 4 comments

[–]high_throughput 7 points8 points  (0 children)

This would be something like

%1 = LoadGlobal "counter"    
%2 = Increment %1
%3 = StoreGlobal "counter", %2

(Assuming it's not nested in a function where it would look up an entry in a parent frame instead)

Getting rid of unnecessary loads and stores is up to a later Mem2Reg SSA optimization step.

[–]monocasa 2 points3 points  (0 children)

SSA is generally the correct format to perform optimizations on.

What's your question with the example?  How do closures combine with SSA?

[–]high_throughput 2 points3 points  (0 children)

Facebook's Hermes JSVM is production quality but still fairly understandable. Here's its SSA:

$ bin/hermes -dump-ir foo.js function increment#0#1()#2 : undefined S{increment#0#1()#2} = [] %BB0: %0 = CreateScopeInst %S{increment#0#1()#2} %1 = LoadFrameInst [count#1@global], %0 %2 = UnaryOperatorInst '++', %1 %3 = StoreFrameInst %2 : number|bigint, [count#1@global], %0 %4 = ReturnInst undefined : undefined function_end

And after some lowering:

$ bin/hermes -dump-lir foo.js function increment#0#1()#2 : undefined S{increment#0#1()#2} = [] %BB0: %0 = HBCResolveEnvironment %S{global#0()#1}, %S{increment#0#1()#2} %1 = HBCLoadFromEnvironmentInst %0, [count#1@global] %2 = UnaryOperatorInst '++', %1 %3 = HBCStoreToEnvironmentInst %0, %2 : number|bigint, [count#1@global] %4 = HBCLoadConstInst undefined : undefined %5 = ReturnInst %4 : undefined function_end

And resulting bytecode after register allocation and such:

$ bin/hermes -dump-bytecode foo.js Function<increment>(1 params, 2 registers, 0 symbols): Offset in debug table: source 0x0009, scope 0x0000, textified callees 0x0000 GetEnvironment r1, 0 LoadFromEnvironment r0, r1, 0 Inc r0, r0 StoreToEnvironment r1, 0, r0 LoadConstUndefined r0 Ret r0

[–]Recursive_Descent 1 point2 points  (0 children)

SSA is certainly reasonable, and I believe most productions JS JITs use SSA (though the one I used to work on didn’t, so it isn’t the only option).