Browser hacking: More JIT coverage on Kraken + Optimizing "this"

  Рет қаралды 6,954

Andreas Kling

Andreas Kling

Күн бұрын

Пікірлер: 50
@relakin
@relakin 11 ай бұрын
Now I get to watch this with my newborn baby boy, nice!
@0xvector850
@0xvector850 11 ай бұрын
Congrats!
@awesomekling
@awesomekling 11 ай бұрын
Well hello baby boy!
@petroczizoltan6524
@petroczizoltan6524 11 ай бұрын
Congrats!
@Lied25
@Lied25 11 ай бұрын
Congratulations!!!
@ViktorLofgren
@ViktorLofgren 11 ай бұрын
Hello World
@xbzq
@xbzq 11 ай бұрын
36:36 You're not resetting the accumulator even though it's being reset in the interpreter. You may not catch this easily if it only matters whenever a property setter modifies the accumulator.
@samu6982
@samu6982 11 ай бұрын
It's so great seeing iterative improvement at work. Love this series
@andreialdea6072
@andreialdea6072 11 ай бұрын
the wallpaper in this one is hilarious. that's a fast yak you got there
@reallyreason6354
@reallyreason6354 11 ай бұрын
Totally loving this JIT series and it's inspired me to get back to working on my own language. Thank you for all the amazing work & content.
@dbarenholz
@dbarenholz 11 ай бұрын
Really appreciate these JIT videos :) Optimization part is super fun to watch
@perotubinger
@perotubinger 11 ай бұрын
The Saturday fix I needed! ❤
@GAoctavio
@GAoctavio 11 ай бұрын
Loving this JIT engine implementation, its simple but effective
@MarekKnapek
@MarekKnapek 11 ай бұрын
Well hello Andreas, I have question about labels in the JIT. The interface is like `auto some_label = m_assembler.make_label();` and then `some_label.link(m_assembler);`. Why does the link member function need an assembler as a parameter? The label could already know the assembler when it was created, because the assembler created it, the assembler could stash a reference to itself into the label at label creation time. Then the usage of the link function would be easier / simpler / less cluttered. Is it really needed? Or is this some philosophical and not technical reason behind it?
@pedrokalil4410
@pedrokalil4410 11 ай бұрын
Andreas, i was wondering, maybe you could create an simple allocator for allocating native executables. The simplest way i could view it is an linked list of begin, curr and end pointers to pages, to allocate, you walk the list, see if it would fit in any already allocated executable pages, and if not, allocate new memory with memmap in the smallest size possible (if the executable takes 1.5 pages, you allocate two). then, once the native executables are not needed anymore, you free this mix of arena allocator with an linked list allocator. imo this would be an good idea because i think native compiled functions would be tiny, wasting the remaining of a page is wasteful and walking through the linked list would be faster than memmap. This is just guess work tho, i dont know how big functions (and top level execution contexts) get when compiled. And probably there are more efficient data structures, other than a linked list. Maybe an min heap? So that small sections of memory are faster to find. And if so, we may store the largest slot available as an simple usize, so that we dont need to traverse the heap if we know that we wont find anywhere to put the memory. I dont know which class would own this allocator tho, as i dont know much about the internals of libjs, but it should be the same class that owns Bytecode::Executable, i guess
@JordanWerthman
@JordanWerthman 11 ай бұрын
Would be interesting to time against V8 for some of the tests to easily compare how fast a heavily optimized JIT can run them.
@maixicek
@maixicek 11 ай бұрын
Cool ai wallpaper 😅 awesome video, thank you 🥰
@begga9682
@begga9682 11 ай бұрын
epic background
@Stdvwr
@Stdvwr 11 ай бұрын
hope you are clearing that cached this_value somewhere
@kreuner11
@kreuner11 11 ай бұрын
He does since each function call gets a new one
@driedurchin
@driedurchin 11 ай бұрын
So, at this phase any speedup we see is mostly from the slightly smaller function call overhead, since it's still calling back into the same code that would run anyway. The idea is that this paves the way for hand-rolled assembly that replaces the native calls?
@awesomekling
@awesomekling 11 ай бұрын
Basically yes! The main speedup right now comes from not having to iterate over the bytecode while running + avoiding various checks & control flow. This indeed paves the way for fast paths in hand-rolled assembly for common operations that can often be achieved in a handful of machine code instructions. :)
@driedurchin
@driedurchin 11 ай бұрын
@@awesomekling Gotcha, getting all the plumbing done first, then it's nothing but speedups 😎
@movax20h
@movax20h 11 ай бұрын
@@driedurchin Yeah, no main loop overhead and essential exec_impl calls got devirtualized. It is simple and not super smart, but great start for future improvements. All the values that are known at jit time could be constant folded eventually, and even generate specialized machine code and/or call different native functions depending on values (like initialization mode). This way a lot of runtime conditionals could be eliminated.
@driedurchin
@driedurchin 11 ай бұрын
@@movax20hI see. The part I can't still wrap my head around fully is how the jitted code calls machine code that was compiled C++, but then interacts with the C++ state at the class level, conceptually. Makes my head spin.
@movax20h
@movax20h 11 ай бұрын
@@driedurchin It is not that hard. C++ and C ABIs for normal (i.e. non defaults arguments no template) free standing functions are not that hard. Andreas is passing only few params via registers (passing way more might require stack or custom prologs), each being up to 64 bit so each goes into own register. References are just pointers to the object. And for example Value he uses is 64-bit value (double, with nan boxing used to store other types of values), so again just one register. In jited code he is not really doing anything with C++ values, they are treated as just pointers, small value constants, or Value. So he does not (at least not yet) access any complex C++ data structers from the jited code (this requires knowing offsets, memory layout, but is doable as long as you do not mess up with inheritance and virtual methods). This is for example why he did not want to deal with Optional or ThrowableOr (which you normally would pass by value, or would need to deal) in the jited code, and instead deal with them in C++. Rest (like using stack) is just standard x86 assembler stuff.
@JohanDahlin
@JohanDahlin 11 ай бұрын
I wonder if you could add some macros so that you could do JIT_IF(cond) { ... } JIT_ELSE(cond) { ...} JIT_ENDIF() and automagically generate the labels for the control flow
@DanelonNicolas
@DanelonNicolas 11 ай бұрын
kick4ss! 👏🏻👏🏻👏🏻🐞
@dennisheij8793
@dennisheij8793 11 ай бұрын
Shouldn't cxx_put_by_value set the accumulator at the end?
@movax20h
@movax20h 11 ай бұрын
It should. He forgot that. In 99% of the cases the accumulator will not be touched, it will only be overwritten if the put by value is a setter/getter property, but most of the time this is not a case. He will find out soon enough when he runs the js test suite. Or our comments.
@abhijeetviswa
@abhijeetviswa 11 ай бұрын
Where is the vm parameter for all the cxx calls being set? Wouldnt it have to explicitly be set to rdi? 🤔
@beyondcatastrophe_
@beyondcatastrophe_ 11 ай бұрын
The ARG0 is, by convention, always the VM. That is what is set up by the initial call, and then they never touch it (NativeExecutable::run on his libjs_jeet branch). The first argument is in RDI according to SystemV ABI, which is preserved by Assembler::native_call.
@abhijeetviswa
@abhijeetviswa 11 ай бұрын
​@@beyondcatastrophe_ Ah so it's implicitly set and preserved. But in the function cxx_call, perform_call is being called with a different reference. Does gcc implicitly preserve rdi? Couldn't find any reference for this.
@beyondcatastrophe_
@beyondcatastrophe_ 11 ай бұрын
@@abhijeetviswa As mentioned, the `native_call` function preserves the registers. This includes RDI, and it restores it after the cxx_* function returns. So no, it's not implicitly preserved by gcc, it's explicitly preserved by the JIT, and it simply leaves it alone everywhere else
@shmuel-k
@shmuel-k 11 ай бұрын
Will this assembly only work on x86? Will new instructions need to be generated for ARM, apple silicon, etc?
@BrettCWX
@BrettCWX 11 ай бұрын
Yes and even on windows x64 the calling convention is different. That means you have two dimensions here, one is the CPU architecture and the other is the calling convention. Basically all *nix stuff is using a convention called System V and Microsoft has their own x64 calling convention
@alichay
@alichay 11 ай бұрын
​@@BrettCWX this is really pedantic, but technically this could be portable to Windows. On GCC and Clang (but not MSVC!), you can use __attribute__((sysv_abi)) to force a function to use the SysV ABI, which would allow these functions to work. Probably not the best solution, since it does rule out MSVC, but it's a fun (and rarely used) thing to be able to do :)
@kreuner11
@kreuner11 11 ай бұрын
Apple Silicon is ARM
@kreuner11
@kreuner11 11 ай бұрын
@@alichay if Serenity Lagom libraries are to support Windows, it is highly unlikely that MSVC will be considered at all. Too many features used are agreed upon GCC-Clang world extensions
@StopBuggingMeGoogleIHateYou
@StopBuggingMeGoogleIHateYou 11 ай бұрын
@@alichayThat won't work if you plan to use Windows x64 runtime exception handling support, due to the different volatile register set.
@kelvium8669
@kelvium8669 11 ай бұрын
hi!
@awesomekling
@awesomekling 11 ай бұрын
Well hello friend!
@AntonioNoack
@AntonioNoack 11 ай бұрын
For the this_value optimization, I'm wondering who is resetting the caching register 🤔(on entering/exiting your function). Example, which would be broken, if you forget to reset the cache to an empty value: function TestClass(x){ this.x = x } TestClass.prototype.getX = function(){ return this.x } console.log(new TestClass(1).getX()) console.log(new TestClass(2).getX()) If it's not reset, I'd guess you'd get two times '1' printed.
@awesomekling
@awesomekling 11 ай бұрын
Every function call gets a fresh call frame with an empty this_value register :)
@lmdcrash
@lmdcrash 11 ай бұрын
So calls of fn.apply() should be also in safe? =) function logThis() { console.log(this); } logThis.apply(1); logThis.apply(2);
Browser hacking: Making a dumb loop go fast in the JIT!
1:10:25
Andreas Kling
Рет қаралды 9 М.
Fixing some HTML canvas tests for WPT
1:09:43
Andreas Kling
Рет қаралды 822
小路飞嫁祸姐姐搞破坏 #路飞#海贼王
00:45
路飞与唐舞桐
Рет қаралды 14 МЛН
ДЕНЬ УЧИТЕЛЯ В ШКОЛЕ
01:00
SIDELNIKOVVV
Рет қаралды 3,2 МЛН
Incredible: Teacher builds airplane to teach kids behavior! #shorts
00:32
Fabiosa Stories
Рет қаралды 11 МЛН
Fixing a WPT timeout in Window.postMessage()
32:49
Andreas Kling
Рет қаралды 5 М.
#uv IS the Future of #Python Packaging 🐍📦
25:16
Hynek Schlawack
Рет қаралды 11 М.
Ep 0: Design Patterns (TheStartup)
1:01:29
ThePrimeTime
Рет қаралды 193 М.
Why Isn't Functional Programming the Norm? - Richard Feldman
46:09
Ladybird browser update (June 2024)
18:17
Andreas Kling
Рет қаралды 38 М.
Harder Drive: Hard drives we didn't want or need
36:47
suckerpinch
Рет қаралды 1,7 МЛН
The Future of Shells with Nushell! Shell + Data + Programming Language
25:45
Become a bash scripting pro - full course
36:00
CODE IS EVERYTHING
Рет қаралды 59 М.
Evolution of the Samsung Galaxy
0:50
ios_aesthetics
Рет қаралды 7 МЛН
Где купить колонку Алиса в ОАЭ или США ?
0:17
Electronics_latvia
Рет қаралды 3,7 МЛН