mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-05-15 03:17:05 +02:00
Instead of storing a u32 index into a cache vector and looking up the cache at runtime through a chain of dependent loads (load Executable*, load vector data pointer, multiply index, add), store the actual cache pointer as a u64 directly in the instruction stream. A fixup pass (Executable::fixup_cache_pointers()) runs after Executable construction in both the Rust and C++ pipelines, walking the bytecode and replacing each index with the corresponding pointer. The cache pointer type is encoded in Bytecode.def (e.g. PropertyLookupCache*, GlobalVariableCache*) so the fixup switch is auto-generated by the Python Op code generator, making it impossible to forget updating the fixup when adding new cached instructions. This eliminates 3-4 dependent loads on every inline cache access in both the C++ interpreter and the assembly interpreter.
19 lines
860 B
Plaintext
19 lines
860 B
Plaintext
JS bytecode executable ""
|
|
[ 0] 0: GetLexicalEnvironment dst:reg4
|
|
[ 8] GetGlobal dst:reg6, identifier:foo
|
|
[ 20] Call dst:reg5, callee:reg6, this_value:Undefined, foo
|
|
[ 40] End value:reg5
|
|
|
|
JS bytecode executable "foo"
|
|
[ 0] 0: GetLexicalEnvironment dst:reg4
|
|
[ 8] CreateArguments is_immutable:false
|
|
[ 18] GetCalleeAndThisFromEnvironment callee:reg6, this_value:reg7, identifier:eval
|
|
[ 30] CallDirectEval dst:reg5, callee:reg6, this_value:reg7, eval, arguments:[String("var x = 1")]
|
|
[ 58] GetBinding dst:reg6, identifier:Number
|
|
[ 70] CallConstruct dst:reg5, callee:reg6, Number, arguments:[Int32(42)]
|
|
[ 90] Return value:reg5
|
|
|
|
JS bytecode executable "eval"
|
|
[ 0] 0: GetLexicalEnvironment dst:reg4
|
|
[ 8] SetLexicalBinding identifier:x, src:Int32(1)
|
|
[ 20] End value:Undefined |