- editor setup
- compilation database
- vscode debugger
- debug cctest
- debug mjsunit
- testing
- build system
- torque
- builtins snapshot
- JS feature
- object
- instantiating
JSObject
,Map
, etc... - named property access
- ic
- prototypee chain
- instantiating
- function
- instantiating
JSFunction
- function call
- instantiating
- arithmetic smi and heap number
- async/await, promise, generator, microtask
- new operator
- array
- elements and keyed property access
- string
- typed array
- exception
- object
- implementation
- bytecode interpreter (ignition)
- tier up from bytecode
- OSR (on stack replacement)
- compiler (turbofan)
- deoptimization
- CodeStubAssembler
- debugging generated code?
- x64 backend
- torque
- four tiers (Sparkplug, Maglev)
- gc
- debugger
- wasm
- embedding
- chromium/blink integration
- nodejs
- deno
-
- https://v8.dev/docs/embed#advanced-guide (handle, context, template)
- https://v8.dev/docs/csa-builtins (CodeStubAssembler)
-
misc
- The V8 deconfuser series (https://docs.google.com/document/d/1FJ7ryVat1LjQhPX8XhXk3cOIgj78LLTKdXTJhUn-tHk/edit?usp=sharing)
- V8’s Object Model Using Well-Defined C++ (https://docs.google.com/document/d/1_w49sakC1XM1OptjTurBDqO86NE16FH8LwbeUAtrbCo/edit?usp=sharing)
-
turbofan https://v8.dev/docs/turbofan
- Fast arithmetic for dynamic languages (https://docs.google.com/presentation/d/1wZVIqJMODGFYggueQySdiA3tUYuHNMcyp_PndgXsO1Y)
-
https://chromium.googlesource.com/chromium/src/+/master/docs/vscode.md
-
TODO
- debug CSA generation steps (e.g.
IGNITION_HANDLER
)- need to disable builtin snapshot?
- turbofan optimization
- debug mjsunit tests
- debug CSA generation steps (e.g.
# clone
fetch v8
cd v8
# pull changes
git pull
gclient sync
# gn gen + ninja
./tools/dev/gm.py x64.debug
# (for torque-language-server)
./tools/dev/gm.py x64.release
ninja -C out/x64.release torque-language-server
# generate `out/x64.debug/compile_commands.json` for vscode
ninja -C out/x64.debug -t compdb cxx cc > out/x64.debug/compile_commands.json
# build and run hello-world.cc
ninja -C out/x64.debug v8_hello_world
./out/x64.debug/v8_hello_world
# Hello, World!
# 3 + 4 = 7
# testing
ninja -C out/x64.debug cctest unittests # cf. `BUILD_TARGETS_TEST` in gm.py
tools/run-tests.py --outdir=out/x64.debug -p verbose mjsunit/interrupt-budget-override
tools/run-tests.py --outdir=out/x64.debug -p verbose 'cctest/test-elements-kind/*'
# run unittest directly
./out/x64.debug/unittests --gtest_filter=InterpreterTest.InterpreterGenerators
# run cctest directly (is it disappearing? https://bugs.chromium.org/p/v8/issues/detail?id=12781)
out/x64.debug/cctest --list
out/x64.debug/cctest test-elements-kind/JSObjectAddingProperties
# run mjsunit directly
out/x64.debug/d8 --test test/mjsunit/mjsunit.js test/mjsunit/interrupt-budget-override.js --turbofan --interrupt-budget=100 --interrupt-budget-for-feedback-allocation=10 --allow-natives-syntax
.vscode/c_cpp_properties.json
{
"version": 4,
"configurations": [
{
"name": "Linux",
"compilerPath": "${workspaceFolder}/third_party/llvm-build/Release+Asserts/bin/clang++",
"compileCommands": "${workspaceFolder}/out/x64.debug/compile_commands.json"
}
]
}
.vscode/launch.json
- tweak
args
ofcctest
it seems there are some problems in recent change in(it seems reverted)gdbinit
, so rollback a few commits:git co b04d9eea02a97f745db23e218a59aa04b5028e58 -- tools/gdbinit
- tweak
{
"version": "0.2.0",
"configurations": [
{
"name": "unittest",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/out/x64.debug/unittests",
// "args": ["--gtest_filter=InterpreterTest.InterpreterGenerators"],
"args": ["--gtest_filter=BytecodeGeneratorTest.AsyncModules"],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{ "text": "-enable-pretty-printing" },
{ "text": "-gdb-set disassembly-flavor intel" },
{
"text": "-interpreter-exec console \"source -v ${workspaceFolder}/tools/gdbinit\""
}
]
},
{
"name": "mjsunit",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/out/x64.debug/d8",
"args": [
"--test",
"test/mjsunit/mjsunit.js",
"test/mjsunit/interrupt-budget-override.js",
"--turbofan",
"--interrupt-budget=100",
"--interrupt-budget-for-feedback-allocation=10",
"--allow-natives-syntax"
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{ "text": "-enable-pretty-printing" },
{ "text": "-gdb-set disassembly-flavor intel" },
{
"text": "-interpreter-exec console \"source -v ${workspaceFolder}/tools/gdbinit\""
}
]
},
{
"name": "d8",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/out/x64.debug/d8",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{ "text": "-enable-pretty-printing" },
{ "text": "-gdb-set disassembly-flavor intel" },
{
"text": "-interpreter-exec console \"source -v ${workspaceFolder}/tools/gdbinit\""
}
]
},
{
"name": "hello-world.cc",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/out/x64.debug/v8_hello_world",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{ "text": "-enable-pretty-printing" },
{ "text": "-gdb-set disassembly-flavor intel" },
{
"text": "-interpreter-exec console \"source -v ${workspaceFolder}/tools/gdbinit\""
}
]
}
]
}
.vscode/settings.json
- jump to blame view https://github.com/fabiospampinato/vscode-open-in-github
{
// git remote add origin-github [email protected]:v8/v8.git
"openInGitHub.remote.name": "origin-github",
"openInGitHub.useLocalLine": true
}
- constant list
BYTECODE_LIST
e.g.LdaNamedProperty
(interpreter/bytecodes.h
)FOR_EACH_INTRINSIC
e.g.LoadIC_Miss
(runtime/runtime.h
)BUILTIN_LIST
(builtins/builtins-definitions.h
)BUILTIN_LIST_BYTECODE_HANDLERS
(generate-bytecodes-builtins-list.cc
)
AST_NODE_LIST
e.g.VariableDeclaration
(ast/ast.h
)OPEN_HANDLE_LIST
ROOT_LIST
ALL_OP_LIST
(src/compiler/opcodes.h
TurboFan IR)
- others
DEF_GETTER
objects/*.h
objects/*.tq
(some fields are defined/generated by torque)
Smi < Object < TaggedImpl
HeapObject < Object < TaggedImpl
Map
JSReceiver < HeapObject
PropertyArray
NameDictionary
JSObject < JSReceiver
elements
Map < HeapObject
NativeContext < Context
DescriptorArray instance_descriptors
descriptors[] DescriptorEntry
(fixed length on instantiation?)
(not all values are compatible to save in the same way? (cf. Representation, FieldType))
prototype
constructor_or_back_pointer
raw_transitions
Isolate
Heap
IsolateData
ThreadLocalTop
Context (TODO: how is this relate to `HandleScopeImplementer.entered_contexts_`?)
-
bytecodes.h
-
bytecode-generator.cc
-
interpreter-generator.cc
-
test-bytecode-generator.cc
bytecode-generator-unittest.cc
in https://chromium-review.googlesource.com/c/v8/v8/+/3609752PropertyLoads
,PropertyStores
,FunctionLiterals
-
test-interpreter.cc
InterpreterLoadNamedProperty
,InterpreterSetNamedProperty
-
virtual registers (cf.
bytecode-register.cc
) -
TODO
- map construction and modification
-
CreateObjectLiteral
-
SetNamedProperty
-
- smi arithmetic (cf.
out/x64.debug/cctest test-bytecode-generator/BasicLoops
) - prototype chain
- IC
- property access (
LoadIC
andStoreIC
) - call
- property access (
- tiering up to sparkplug/turbofan
- accessing outer-scope variables ("the hole"?)
- map construction and modification
- e.g.
out/x64.debug/cctest test-bytecode-generator/PropertyLoads
TEST(PropertyLoads) => BuildActual => BytecodeExpectationsPrinter.PrintExpectation =>
CompileScript => v8::Script::Compile => v8::ScriptCompiler::Compile =>
CompileUnboundInternal => i::Compiler::GetSharedFunctionInfoForScript => GetSharedFunctionInfoForScriptImpl =>
CompileScriptOnMainThread => CompileToplevel =>
(Script -> FunctionLiteral) parsing::ParseProgram => Parser::ParseProgram =>
DoParseProgram =>
ParseStatementList (as body of FunctionLiteral) => (usual recursive descent)
AstNodeFactory::NewScriptOrEvalFunctionLiteral
MaybeProcessSourceRanges
(FunctionLiteral -> SharedFunctionInfo) CreateTopLevelSharedFunctionInfo => NewSharedFunctionInfoForLiteral =>
NewSharedFunctionInfo
SharedFunctionInfo::InitFromFunctionLiteral
SharedFunctionInfo::SetScript
IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs =>
ExecuteSingleUnoptimizedCompilationJob =>
UnoptimizedCompilationJob::ExecuteJob, ExecuteJobImpl =>
MaybePrintAst (via FLAG_print_ast)
BytecodeGenerator::GenerateBytecode => ...
InitializeAstVisitor
GenerateBytecodeBody =>
VisitStatements (as AstVisitor) => ...
FinalizeUnoptimizedScriptCompilation =>
UnoptimizedCompilationJob::FinalizeJob, FinalizeJobImpl, DoFinalizeJobImpl =>
BytecodeGenerator::FinalizeBytecode => BytecodeArrayBuilder::ToBytecodeArray
(dump BytecodeArray::Disassemble if FLAG_print_bytecode)
InstallUnoptimizedCode => SharedFunctionInfo::set_bytecode_array
(SharedFunctionInfo => JSFunction) BindToCurrentContext =>
i::Factory::JSFunctionBuilder::Build =>
PrepareMap (based on SharedFunctionInfo::function_map_index)
PrepareFeedbackCell
SharedFunctionInfo::GetCode (e.g. Builtin::kInterpreterEntryTrampoline if function_data is BytecodeArray)
BuildRaw =>
Factory::New(Map, ...) =>
Heap::AllocateRawWith
HeapObject::set_map_after_allocation
JSReceiver::initialize_properties
JSObject::initialize_elements
JSFunction::set_code
JSFunction::set_prototype_or_initial_map
JSFunction::EnsureFeedbackVector =>
JSFunction::InitializeFeedbackCell
Run(v8::Script) => Script::Run =>
i::Execution::CallScript(Isolate, JSFunction, JSGlobalProxy, ...) =>
InvokeParams::SetUpForCall
Invoke =>
JSEntry (e.g. BUILTIN_CODE(JSEntry) for non-microtask and non-constructor)
CodeDataContainer::code_entry_point => ReadExternalPointerField ...
GeneratedCode::FromAddress
GeneratedCode::Call (calling function pointer)
GetBytecodeArrayForGlobal (grab BytecodeArray e.g. via `context->Global()->Get` and `SharedFunctionInfo::GetBytecodeArray`)
#
# data structure
#
ParseInfo
FunctionLiteral < Expression
BytecodeGenerator < AstVisitor
BytecodeArrayBuilder
FeedbackSlotCache
UnoptimizedCompilationInfo
FeedbackVectorSpec
FunctionLiteral
JSFunction < JSFunctionOrBoundFunction < JSObject
prototype_or_initial_map
FeedbackCell (e.g. FeedbackVector)
CodeT
Context
SharedFunctionInfo
function_literal_id
function_data (e.g. BytecodeArray (for ignition), CodeT (for sparkplug))
feedback_metadata
function_map_index (TODO: where does it come from?)
NativeContext < Context
JSGlobalProxy
out/x64.debug/cctest test-bytecode-generator/FunctionLiterals
#
# closure construction
#
BytecodeGenerator::VisitFunctionLiteral =>
CreateClosureFlags::Encode
GetCachedCreateClosureSlot
BytecodeArrayBuilder::CreateClosure
IGNITION_HANDLER(CreateClosure, ...) =>
CallBuiltin(Builtin::kFastNewClosure, ...)
TF_BUILTIN(FastNewClosure) =>
...
StoreObjectFieldNoWriteBarrier(..., JSFunction::kCodeOffset, BUILTIN_CODE(CompileLazy))
TF_BUILTIN(CompileLazy) =>
LazyBuiltinsAssembler::CompileLazy =>
GenerateTailCallToReturnedCode(Runtime::kCompileLazy)
RUNTIME_FUNCTION(Runtime_CompileLazy) =>
Compiler::Compile (looks similar to `CompileToplevel` above) =>
IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs
FinalizeUnoptimizedCompilation
...
#
# closure invocation
#
BytecodeGenerator::VisitCall =>
GetCallType (e.g. GLOBAL_CALL, NAMED_PROPERTY_CALL, super, optional, private, etc...)
BytecodeArrayBuilder::StoreAccumulatorInRegister
VisitArguments => VisitAndPushIntoRegisterList
BytecodeArrayBuilder::SetExpressionPosition
FeedbackVectorSpec::AddCallICSlot
BytecodeArrayBuilder::CallUndefinedReceiver (if no receiver)
IGNITION_HANDLER(CallUndefinedReceiver0)
JSCallN(0, ConvertReceiverMode::kNullOrUndefined) =>
LoadFeedbackVector
CollectCallFeedback (TODO: ic-callbacle.tq)
CallJSAndDispatch =>
CodeFactory::InterpreterPushArgsThenCall (e.g. Builtin::kInterpreterPushUndefinedAndArgsThenCall)
TailCallStubThenBytecodeDispatch (magical linkage matching?)
- https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-property-accessors
out/x64.debug/cctest test-bytecode-generator/PropertyLoads
out/x64.debug/cctest test-interpreter/InterpreterLoadNamedProperty
#
# bytecode generation
#
BytecodeGenerator::VisitProperty =>
VisitForRegisterValue (for Property::obj)
VisitPropertyLoad =>
Property::GetAssignType (e.g. check Expression::IsPropertyName to choose NAMED_PROPERTY or KEYED_PROPERTY)
BuildLoadNamedProperty =>
GetCachedLoadICSlot =>
FeedbackVectorSpec::AddLoadICSlot => AddSlot(FeedbackSlotKind::kLoadProperty)
FeedbackSlotCache::Put
BytecodeArrayBuilder::LoadNamedProperty => OutputGetNamedProperty
#
# execution
#
IGNITION_HANDLER(GetNamedProperty, ...) # changed from `LdaNamedProperty` (https://chromium-review.googlesource.com/c/v8/v8/+/3481475)
CodeStubAssembler::LoadFeedbackVector (load JSFunction::feedback_cell if exists)
AccessorAssembler::LoadIC_BytecodeHandler =>
LoadReceiverMap(receiver_and_lookup_start_object)
(fast path for common case)
TryMonomorphicCase =>
IsWeakReferenceTo (check if current receiver's map is same as the one in feedback vector cf. `IC::SetCache` below)
(if monomorphic)
HandleLoadICHandlerCase =>
(if smi_handler (cf. `LoadIC::ComputeHandler` below) (TODO: what's the other case `proto_handler` ?))
decode LoadHandler::Kind from smi_handler
HandleLoadICSmiHandlerLoadNamedCase =>
HandleLoadField (CSA equivalent of JSObject::FastPropertyAt?)
(if polymorphic)
HandlePolymorphicCase => ??
(stub_call)
Builtin::kLoadIC_Noninlined => ??
(no_feedback)
Builtin::kLoadIC_NoFeedback => ??
(miss)
Runtime::kLoadIC_Miss
RUNTIME_FUNCTION(Runtime_LoadIC_Miss) =>
LoadIC::UpdateState(lookup_start_object, name) =>
IC::update_lookup_start_object_map
LoadIC::Load =>
JSObject::MakePrototypesFast (what?)
IC::update_lookup_start_object_map (again)
LookupIterator => Start => ??
LookupForRead
(if property is found)
UpdateCaches(LookupIterator) =>
ComputeHandler =>
(if LookupIterator::DATA)
(if JSReceiver::HasFastProperties (i.e. not Map::is_dictionary_map))
LookupIterator::GetFieldIndex => FieldIndex::ForDescriptor(Map, ...)
LoadHandler::LoadField (found smi_handler)
IC::SetCache =>
(if UNINITIALIZED)
UpdateMonomorphicIC => ConfigureVectorState => FeedbackNexus::ConfigureMonomorphic
SetFeedback (write the entry as (address of receiver map, handler object))
Object::GetProperty(LookupIterator, ...) =>
(if LookupIterator::DATA) LookupIterator::GetDataValue =>
FetchValue => JSObject::FastPropertyAt => RawFastPropertyAt (handle property-array or in-object)
(otherwise)
ReferenceError
#
# data structure
#
Property < Expression
obj Expression
key Expression
IC
Map lookup_start_object_map_
InlineCacheState (e.g. UNINITIALIZED, MONOMORPHIC, POLYMORPHIC, ..)
FeedbackNexus
FeedbackVector
FeedbackSlot
LoadIC < IC
LookupIterator
Object receiver_, lookup_start_object_
Name name_ (property name)
JSReceiver holder_ (usually same as lookup_start_object_)
State (e.g. DATA, JSPROXY, ..)
PropertyDetails (e.g. PropertyLocation)
Map transition_ (TODO: when is this computed?)
- https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-assignment-operators-runtime-semantics-evaluation
out/x64.debug/cctest test-bytecode-generator/PropertyStore
out/x64.debug/cctest test-interpreter/InterpreterSetNamedProperty
#
# bytecode generation
#
BytecodeGenerator::VisitAssignment =>
PrepareAssignmentLhs (evaluting LHS before RHS) => VisitForRegisterValue
VisitForAccumulatorValue
BuildAssignment =>
(if x.y = z aka NAMED_PROPERTY)
BuildSetNamedProperty =>
GetCachedStoreICSlot
BytecodeArrayBuilder::SetNamedProperty
#
# execution
#
IGNITION_HANDLER(SetNamedProperty, ...)
InterpreterSetNamedPropertyAssembler::SetNamedProperty =>
Builtin::kStoreIC (TODO: where does this defined?)
Builtins::Generate_StoreIC => AccessorAssembler::GenerateStoreIC =>
AccessorAssembler::StoreIC =>
LoadReceiverMap
TryMonomorphicCase
(if monomorphic)
HandleStoreICHandlerCase =>
(if handler is smi e.g. StoreHandler::StoreField)
probably something like `JSObject::WriteToField` written in CSA
(if handler is "store transition" (cf. StoreHandler::StoreTransition below))
HandleStoreICTransitionMapHandlerCase
..
(miss)
Runtime::kStoreIC_Miss
RUNTIME_FUNCTION(Runtime_StoreIC_Miss)
StoreIC::UpdateState
StoreIC::Store =>
LookupIterator => LookupIterator::Start =>
LookupInHolder(Map, JSReceiver) => LookupInRegularHolder =>
(if not is_dictionary_map i.e. "fast property")
DescriptorArray::SearchWithCache
(if not found)
NextInternal (loop `LookupInHolder` for prototype chain (cf. Map::prototype))
UpdateCaches =>
LookupForWrite =>
(if not found)
LookupIterator::PrepareTransitionToDataProperty =>
update state from NOT_FOUND to TRANSITION
(if is_dictionary_map)
is it possible to always resuse old dictionary map?
(otherwise (i.e. "fast property"))
Map::TransitionToDataProperty (construct map based on old map and new property name) =>
TransitionsAccessor::SearchTransition => ??
(if found)
return UpdateDescriptorForValue (mostly reuse but modify based on FieldType)
(if not Map::TooManyFastProperties (cf. kMaxNumberOfDescriptors))
Map::CopyWithField(..., INSERT_TRANSITION) =>
Map::CopyAddDescriptor =>
DescriptorArray::Append
CopyReplaceDescriptors =>
CopyDropDescriptors
ConnectTransition (setup child's "backpointer" and parent's "raw transitions")
(otherwise)
Map::Normalize (promote to "dictionary map")
ComputeHandler =>
(if LookupIterator::TRANSITION)
StoreHandler::StoreTransition =>
(if dictionary_map) ?
(otherwise) transition_map itself is handler?
(if LookupIterator::DATA)
e.g. StoreHandler::StoreField if PropertyLocation::kField
SetCache
Object::SetProperty(LookupIterator, ...) =>
(if LookupIterator::IsFound)
SetPropertyInternal =>
(if LookupIterator::DATA)
SetDataProperty =>
LookupIterator::WriteDataValue =>
(if JSReceiver::HasFastProperties)
(if PropertyLocation::kField (other case `kDescriptor` is for constant saved in "map"?))
JSObject::WriteToField => FastPropertyAtPut
(otherwise)
AddDataProperty(LookupIterator, ...) =>
TransitionAndWriteDataProperty =>
LookupIterator::ApplyTransitionToDataProperty =>
JSObject::MigrateToMap =>
e.g. MigrateFastToFast (if simple, HeapObject::set_map, otherwise shuffling with actual storage)
update LookupIterator state `PropertyDetails`, `State` (e.g. TRANSITION to DATA for "simple transition")
LookupIterator::WriteDataValue
#
# data structure
#
Assignment < Expression < AstNode
target_
value_
bit_field_ (assignment operator is kept in AstNode::bit_field_)
- https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#prod-ObjectLiteral
out/x64.debug/cctest test-bytecode-generator/ObjectLiterals
out/x64.debug/cctest test-interpreter/InterpreterObjectLiterals
CreateObjectLiteral
bytecode- boilerplate in constant pool?
- feedback for fast path? (
AddLiteralSlot,
AddCloneObjectSlot
,AddDefineNamedOwnICSlot
, etc...)
Runtime_CreateObjectLiteralBoilerplate
#
# parsing
#
ParserBase<Parser>::ParseObjectLiteral =>
while not "}"
ParseObjectPropertyDefinition => ...
# check if e.g. `is_computed_name`, `isBoilerplateProperty`, etc...
AstNodeFactory::NewObjectLiteral
Parser::InitializeObjectLiteral
#
# bytecode generation
#
BytecodeGenerator::VisitObjectLiteral =>
ObjectLiteralBoilerplateBuilder::InitDepthAndFlags (loop properties and detect if the object is "simple" value etc...)
(if ObjectLiteralBoilerplateBuilder::IsEmptyObjectLiteral)
BytecodeArrayBuilder::CreateEmptyObjectLiteral
(otherwise)
push ObjectLiteralBoilerplateBuilder to object_literals_
BuildCreateObjectLiteral =>
FeedbackVectorSpec::AddLiteralSlot
BytecodeArrayBuilder::CreateObjectLiteral(<ObjectBoilerplateDescription in constant pool entry>, <feedback vector index>, <flags>)
# loop for "computed value" (i.e. not `IsCompileTimeValue`)
handle DefineNamedOwnProperty or DefineKeyedOwnProperty bytecode
# loop for "computed property name"
handle via `DefineKeyedOwnPropertyInLiteral` bytecode or runtime
BytecodeGenerator::FinalizeBytecode =>
BytecodeGenerator::AllocateDeferredConstants =>
# loop ObjectLiteralBoilerplateBuilder
ObjectLiteralBoilerplateBuilder::GetOrBuildBoilerplateDescription => BuildBoilerplateDescription =>
NewObjectBoilerplateDescription
# loop properties
ObjectBoilerplateDescription::set_key_value
#
# execution
#
IGNITION_HANDLER(CreateObjectLiteral, ...) =>
(fast path with feedback)
ConstructorBuiltinsAssembler::CreateShallowObjectLiteral (shallow copy implemented in CSA)
(otherwise)
CallRuntime(Runtime::kCreateObjectLiteral, ...)
RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) => CreateLiteral<ObjectLiteralHelper> =>
(if feedback slot already has `AllocationSite`)
use `JSObject` from `AllocationSite::boilerplate`
(otherwise)
ObjectLiteralHelper::Create => CreateObjectLiteral =>
(just constructing JSObject from ObjectBoilerplateDescription with usual API)
DeepCopy(boilerplate, ...) => ...
IGNITION_HANDLER(DefineNamedOwnProperty, ...) => SetNamedProperty with Builtin::kDefineNamedOwnIC
#
# data structure
#
ObjectLiteral < AggregateLiteral < MaterializedLiteral < Expression
Variable home_object_ (TODO: `super` for object literal?)
ZoneList<ObjectLiteralProperty*>
Kind (e.g. CONSTANT, COMPUTED, SPREAD, etc..)
ObjectLiteralBoilerplateBuilder
ObjectBoilerplateDescription
ZoneList<Property*>
BytecodeGenerator
ObjectLiteralBoilerplateBuilder object_literals_ (pre-built in constant pool?)
AllocationSite < Struct < HeapObject
boilerplate JSObject
- spec
- tests
bytecode-generator-unittest.cc
CallNew
interpreter-unittest.cc
InterpreterConstruct
- todo
- instance type? (
objects/instance-type.h
)
- instance type? (
#
# bytecode generation
#
BytecodeGenerator::VisitCallNew =>
# for simple arguments without spreads
BytecodeArrayBuilder::LoadAccumulatorWithRegister(constructor)
(set constructor itself as "new target" (relevant only when `CallSuper`?))
BytecodeArrayBuilder::Construct
#
# execution
#
IGNITION_HANDLER(Construct, InterpreterAssembler) =>
InterpreterAssembler::Construct =>
CollectConstructFeedback (optimization for array construction based on feedback?)
# for general case (InterpreterPushArgsMode::kOther)
CodeFactory::InterpreterPushArgsThenConstruct =>
Builtin::kInterpreterPushArgsThenConstruct
CallStub
# asm builtin (e.g. builtins-x64.cc)
Builtins::Generate_InterpreterPushArgsThenConstructImpl =>
(if InterpreterPushArgsMode::kOther)
Jump(Construct) =>
# check [[Construct]] internal method via `IsConstructorBit` on `Map`
# dispatch based on "instance type" (how come this end up in `r8`?)
Jump(ConstructFunction) =>
# special path for builtin
Jump(JSBuiltinsConstructStub) => InvokeFunction => ...
Jump(JSConstructStubGeneric) => ??
#
# data structure
#
Map
is_constructor # indicating [[Construct]] internal method
out/x64.debug/cctest test-bytecode-generator/BasicLoops
out/x64.debug/cctest test-interpreter/InterpreterBinaryOpsSmi
out/x64.debug/cctest test-interpreter/InterpreterBinaryOpsHeapNumber
V8_31BIT_SMIS_ON_64BIT_ARCH
#
# execution
#
IGNITION_HANDLER(Add, ...) =>
InterpreterBinaryOpAssembler::BinaryOpSmiWithFeedback =>
BinaryOpAssembler::Generate_AddWithFeedback =>
(if both lhs and rhs are Smi)
CodeStubAssembler::TrySmiAdd =>
# converting v8 smi to actual machin integers
BitcastTaggedToWordForTagAndSmiBits
TruncateIntPtrToInt32
Int32AddWithOverflow => AddNode(machine()->Int32AddWithOverflow(), ...) (what?)
# converting back to smi
ChangeInt32ToIntPtr
BitcastWordToTaggedSigned
(if overflow)
SmiToFloat64 and go "do_fadd"
(do_fadd)
Float64Add
AllocateHeapNumberWithValue
execution/tiering-manager.cc
- budget system
JSFunction::SetInterruptBudget
,FeedbackCell::SetInitialInterruptBudget
- v8 options e.g.
--interrupt-budget
- budget system
#
# "--always-sparkplug" flag
#
CompileTopLevel (see above "bytecode generator test entrypoint") =>
parsing::ParseProgram => ...
...
FinalizeUnoptimizedScriptCompilation
(if FLAG_always_sparkplug)
CompileAllWithBaseline =>
CanCompileWithBaseline (check e.g. debugger mode enabled not supported by baseline)
Compiler::CompileSharedWithBaseline =>
GenerateBaselineCode (SharedFunctionInfo -> Code) => ??
SharedFunctionInfo::set_baseline_code
#
# setting TieringState
#
(ignition)
IGNITION_HANDLER(Return, ...) => InterpreterAssembler::UpdateInterruptBudgetOnReturn =>
InterpreterAssembler::UpdateInterruptBudget =>
(if "budget" reaches zero (keep subtracting executed bytecode length from initial budget))
call Runtime::kBytecodeBudgetInterrupt
IGNITION_HANDLER(Jump, ...) => InterpreterAssembler::Jump =>
InterpreterAssembler::UpdateInterruptBudget => ...
(sparkplug)
BaselineAssembler::EmitReturn (e.g. baseline-assembler-x64-inl.h) =>
call Runtime::kBytecodeBudgetInterrupt
...
RUNTIME_FUNCTION(Runtime_BytecodeBudgetInterrupt) => TieringManager::OnInterruptTick =>
(if FLAG_baseline_batch_compilation (default true))
BaselineBatchCompiler::EnqueueFunction => ...
(otherwise)
Compiler::CompileBaseline =>
CompileSharedWithBaseline => ...
JSFunction::set_code
FeedbackVector::SaturatingIncrementProfilerTicks
JSFunction::GetActiveTier (e.g. CodeKind::INTERPRETED_FUNCTION, BASELINE, MAGLEV, TURBOFAN)
MaybeOptimizeFrame =>
ShouldOptimize =>
(if INTERPRETED_FUNCTION or BASELINE)
OptimizationDecision::Maglev
(decide based on "FeedbackVector::profiler_ticks" and bytecode length)
OptimizationDecision::TurbofanHotAndStable or TurbofanSmallFunction
Optimize => JSFunction::MarkForOptimization =>
TieringStateFor(CodeKind, ConcurrencyMode) (return e.g. TieringState::kRequestTurbofan_Synchronous)
(is this only for testing/debugging?)
RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) =>
OptimizeFunctionOnNextCall => JSFunction::MarkForOptimization => ...
#
# tiering up via `CompileLazy`
#
TF_BUILTIN(CompileLazy) (see above "closure construction") =>
LazyBuiltinsAssembler::CompileLazy =>
MaybeTailCallOptimizedCodeSlot =>
# extracting TieringState from FeedbackVector
(if TieringState::kRequestTurbofan_Synchronous)
tailcall to Runtime::kCompileTurbofan_Synchronous
...
(tail call to shared function code if any (e.g. baseline or bytecode trampoline))
(otherwise go compiling to bytecode)
GenerateTailCallToReturnedCode(Runtime::kCompileLazy)
#
# tiering up via interpreter trampoline builtin (architecture dependent e.g. builtins-x64.cc)
#
Builtins::Generate_InterpreterEntryTrampoline =>
MaybeOptimizeCodeOrTailCallOptimizedCodeSlot =>
MaybeOptimizeCode =>
# similar to `CompileLazy`
# check tiering_state in feedback verctor and tail call to e.g. Runtime::kCompileTurbofan_Synchronous
#
# optimize (maglev/turbofan)
#
RUNTIME_FUNCTION(Runtime_CompileTurbofan_Synchronous) =>
CompileOptimized(... JSFunction, CodeKind, ...) => Compiler::CompileOptimized => GetOrCompileOptimized =>
(if CodeKind::TURBOFAN)
CompileTurbofan => ... (see below "turbofan")
(if CodeKind::MAGLEV)
CompileMaglev => ??
#
# data structure
#
Isolate
TieringManager
JSFunction
feedback_cell_ (as FeedbackVector)
TieringState
profiler_ticks
FeedbackCell
interrupt_budget
- turbofan graph
test-run-bytecode-graph-builder.cc
- node iterator
- reduction algorithm
- optimization
- the use of feedback vector
- deoptimization
- concurrent mode
- tests
test/unittests/compiler
test/cctest/compiler
- https://v8.dev/docs/turbofan
- TurboFan’s JIT Design (https://docs.google.com/presentation/d/1sOEF4MlF7LeO7uq-uThJSulJlTh--wgLeaVibsbb3tc)
- TurboFan IR (https://docs.google.com/presentation/d/1Z9iIHojKDrXvZ27gRX51UxHD-bKf1QcPzSijntpMJBM)
- Deoptimization in V8 (https://docs.google.com/presentation/d/1Z6oCocRASCfTqGq1GCo1jbULDGS-w-nzxkbVF7Up0u0)
# e.g. ./out/x64.debug/cctest test-api/PromiseRejectCallbackConstructError
CompileTurbofan =>
compiler::Pipeline::NewCompilationJob (instantiate PipelineCompilationJob)
CompileTurbofan_NotConcurrent =>
PrepareJobWithHandleScope => OptimizedCompilationJob::PrepareJob
OptimizedCompilationJob::ExecuteJob => PipelineCompilationJob::ExecuteJobImpl =>
PipelineImpl::CreateGraph =>
GraphBuilderPhase::Run => .. => BytecodeGraphBuilder::CreateGraph =>
VisitBytecodes => ...
InliningPhase::Run => ??
PipelineImpl::OptimizeGraph => ...
PipelineImpl::AssembleCode =>
PipelineData::InitializeCodeGenerator => new CodeGenerator
AssembleCodePhase::Run => CodeGenerator::AssembleCode => ??
OptimizedCompilationJob::FinalizeJob => PipelineCompilationJob::FinalizeJobImpl =>
PipelineImpl::FinalizeCode => ??
#
# data structure
#
PipelineCompilationJob < TurbofanCompilationJob < OptimizedCompilationJob < CompilationJob
PipelineImpl
PipelineData
Graph
Typer
OptimizedCompilationInfo
BytecodeArray
SharedFunctionInfo
JSFunction
Code
osr_offset_
BytecodeGraphBuilder
FeedbackVectorRef (from JSFunction?)
BytecodeArrayRef
CodeGenerator
TurboAssembler
- bytecode -> graph -> optimize -> schedule -> assemble
#
# bytecode -> graph
#
BytecodeGraphBuilder::VisitAdd =>
CreateFeedbackSource
JSOperatorBuilder::Add
BuildBinaryOp =>
PrepareEagerCheckpoint => ??
TryBuildSimplifiedBinaryOp => ??
#
# optimize
#
PipelineImpl::OptimizeGraph =>
TyperPhase::Run => Typer::Run =>
GraphReducer::AddReducer(Typer::Visitor)
GraphReducer::ReduceNode(root) => .. => Reduce => Typer::Visitor::Reduce =>
TypeNode => UpdateType => NodeProperties::SetType
GraphReducer::ReduceGraph => ReduceNode(end)
TypedLoweringPhase::Run =>
AddReducer (e.g. JSTypedLowering, TypedOptimization, etc...)
ComputeScheduledGraph::Run => Scheduler::ComputeSchedule => ??
SelectInstructions => ??
#
# example reductions
#
TypeNode =>
# e.g. if IrOpcode::kJsAdd
TypeJsAdd (generated via `JS_SIMPLE_BINOP_LIST` macro) => TypeBinaryOp => JSAddTyper =>
# if lhs or rhs is string, then Type::String
# otherwise
BinaryNumberOpTyper(.., NumberAdd) =>
# if both lhs and rhs are Number
NumberAdd => OperationTyper.NumberAdd (OperationTyper is for "simplified" ops) =>
NaN, -0 (minus zero) check, etc...
integer range type analysis
JSTypedLowering::Reduce =>
# if IrOpcode::kJSAdd
JSTypedLowering::ReduceJSAdd =>
# if BothInputsAre(Type::Number())
SimplifiedOperatorBuilder::NumberAdd
JSBinopReduction::GetBinaryOperationHint => GetFeedbackForBinaryOperation =>
JSHeapBroker::GetFeedbackForBinaryOperation
??
#
# data structure
#
Graph
Node
Operator
Type
Mark
Node::Inputs (actual memory layout is optimized e.g. via inline/outline)
Effect < NodeWrapper
Control < NodeWrapper
Edge
GraphReducer
Reduction
Typer
Typer::Visitor < Reducer
FeedbackSource
JSTypedLowering
JSHeapBroker
JSGraph
Schedule
#
# FunctionTester (./out/x64.debug/cctest test-run-jsops/BinopAdd)
#
TEST(BinopAdd) =>
FuntionTester =>
NewFunction => CompileRun => v8_compile => v8::Script::Compile (see above)
Compile => Optimize =>
Pipeline::GenerateCodeForTesting => ??
JSFunction::set_code
FuntionTester::CheckCall => ??
#
# data structure
#
FunctionTester
JSFunction
- docs
- relevant examples/tests
- v8 api e.g.
EnqueueMicrotask
- builtin
EnqueueMicrotask
- unittest
test/unittests/execution/microtask-queue-unittest.cc
runtime-promise.cc
new Promise(r => r("ok")).then(print)
new Promise(() => { throw "oops"; }).catch(print)
node -e 'new Promise(r => r(console.log("1"))).then(() => console.log("3")); console.log("2")'
- v8 api e.g.
- promise (not exist on bytecode level)
promise-constructor.tq
,runtime-promise.cc
, ...- global builtin
- construction
- microtask execution
- turbofan optimization?
#
# Promise (promise.tq, js-promise.tq)
#
# new Promise(executor)
PromiseConstructor (builtins/promise-constructor.tq) =>
NewJSPromise (builtins/promise-misc.tq) =>
InnerNewJSPromise
PromiseInit (set PromiseState::kPending, etc...)
CreatePromiseResolvingFunctions (builtins/promise-abstract-operations.tq) =>
PromiseCapabilityDefaultResolveSharedFunConstant (TODO: does torque generate it for javascript builtin PromiseCapabilityDefaultResolve?)
PromiseCapabilityDefaultRejectSharedFunConstant
Call(... executor ...) => ...
# resolve (https://tc39.es/ecma262/multipage/control-abstraction-objects.html#sec-promise-resolve-functions)
PromiseCapabilityDefaultResolve (promise-abstract-operations.tq) =>
# for normal case
ResolvePromise (promise-resolve.tq) =>
# if not "thenable"
FulfillPromise =>
set PromiseState::kFulfilled
TriggerPromiseReactions with JSPromise::reactions_or_result (aka [[PromiseFulfillReactions]]) =>
MorphAndEnqueuePromiseReaction =>
EnqueueMicrotask(... PromiseFulfillReactionJobTask) => ...
# otherwise
NewPromiseResolveThenableJobTask(... thenAction) => ...
EnqueueMicrotask => ...
# reject
PromiseCapabilityDefaultReject => ...
# promise.then https://tc39.es/ecma262/multipage/control-abstraction-objects.html#sec-promise.prototype.then
PromisePrototypeThen =>
NewJSPromise (aka "resultPromise" as a return value of "then")
PerformPromiseThenImpl =>
# if PromiseState::kPending
NewPromiseReaction and set it to JSPromise::reactions_or_result
# if PromiseState::kFulfilled
EnqueueMicrotask onFullfilled
# if PromiseState::kRejected
EnqueueMicrotask onRejected
# src/builtins/builtins-microtask-queue-gen.cc
TF_BUILTIN(EnqueueMicrotask, ..) (CSA version of MicrotaskQueue::EnqueueMicrotask)
#
# Running Microtask (three patterns to invoke microtasks? cf. `MicrotasksPolicy`)
#
(see e.g. d8 below)
Shell::CompleteMessageLoop => ProcessMessages =>
v8::platform::PumpMessageLoop
MicrotasksScope::PerformCheckpoint => MicrotaskQueue::PerformCheckpoint => PerformCheckpointInternal =>
RunMicrotasks => Execution::TryRunMicrotasks =>
InvokeParams::SetUpForRunMicrotasks (set Execution::Target::kRunMicrotasks)
InvokeWithTryCatch
Invoke (cf. above where we saw Execution::Target::kCallable) =>
JSEntry => builtin JSRunMicrotasksEntry
...
Builtins::Generate_JSRunMicrotasksEntry
Builtins::Generate_RunMicrotasksTrampoline =>
BUILTIN_CODE(..., RunMicrotasks)
TF_BUILTIN(RunMicrotasks, ...) =>
MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask =>
# only 5 kinds of Microtask
# (CallbackTask, CallableTask, PromiseFulfillReactionJobTask, PromiseRejectReactionJobTask, PromiseResolveThenableJobTask)
# e.g. if PromiseFulfillReactionJobTask
Builtin::kPromiseFulfillReactionJob (promise-reaction-job.tq) =>
PromiseReactionJob(.. kPromiseReactionFulfill) =>
result = Call(... handler) (call "then handler" as in `nextPromise = somePromise.then(handler)`)
FuflfillPromiseReactionJob (with `nextPromise` and `result`) => ResolvePromise
#
# data structure
#
internal::MicrotaskQueue < v8::MicrotaskQueue
JSPromise
reactions_or_result
JSPromiseFlags
PromiseState
has_handler
PromiseReaction
reject_handler
fulfill_handler
promise_or_capability (e.g. "resultPromise" of `then`)
PromiseFulfillReactionJobTask < PromiseReactionJobTask < Microtask
MicrotaskQueue
MicrotasksPolicy (kExplicit, kScoped, kAuto)
- docs
- examples
test-bytecode-generator.cc
Generators
,AsyncGenerators
,AsyncModules
runtime-generator.cc
builtins-async-function-gen.cc
node -e 'async function g() { console.log(2); }; async function f(x) { console.log(1); await g(); console.log(4); }; f().then(() => console.log(5)); console.log(3)'
./out/x64.debug/d8 --print-bytecode --print-bytecode-filter=f2 -e 'async function f1(x) { return 2 * x; } async function f2() { const x = await f1(1); return x + x; }; f2()'
- generator
- construction
Generator
andGeneratorFunction
(cf.Genesis::CreateIteratorMaps
)
- execution (
next
iterator protocol)
- construction
- async/await
- prototype (
AsyncFunction
,async_function_object_map
, etc... initialized inGenesis::InitializeIteratorFunctions
) - instantiate
AsyncFunction
object - awaited value resolve/reject
- return result
- prototype (
-
yield*
(see comments inBytecodeGenerator::VisitYieldStar
)
#
# generator/async ast rewrite
#
ParseAndRewriteGeneratorFunctionBody =>
# this corresponds initial suspend/resume pair right after `CreateJSGeneratorObject`
# which will return `JSGeneratorObject` itself on generator function call
BuildInitialYield => AstNodeFactory::NewYield
ParseStatementList (parse later so that `yield` appears first)
ParseAsyncFunctionBody =>
ParseStatementList (parse first and wrapped in a block for rewrite)
RewriteAsyncFunctionBody (see comments for desugaring pseudo code) =>
# inject `return undefined` so that async function can resolve without it
NewSyntheticAsyncReturnStatement (append ReturnStatement::kSyntheticAsyncReturn)
BuildRejectPromiseOnException =>
NewHiddenCatchScope
NewCallRuntime(.. InlineAsyncFunctionReject ..)
#
# BytecodeGenerator
#
BytecodeGenerator::GenerateBytecode =>
# if resumable function
BytecodeGenerator::BuildGeneratorPrologue =>
BytecodeArrayBuilder::AllocateJumpTable
BytecodeArrayBuilder::SwitchOnGeneratorState
GenerateBytecodeBody =>
BuildGeneratorObjectVariableInitialization =>
# TODO: is inline verson only for tagging to be used by turbofan in `JSIntrinsicLowering::Reduce`?
CallRuntime with kInlineCreateJSGeneratorObject or kInlineAsyncFunctionEnter
BytecodeGenerator::VisitYield =>
CallRuntime with kInlineCreateIterResultObject or kInlineAsyncGeneratorYield
BuildSuspendPoint =>
# increment `suspend_count_` and use it as `suspend_id`
BytecodeArrayBuilder::SuspendGenerator (with suspend id)
BytecodeArrayBuilder::Bind(BytecodeJumpTable, suspend id)
BytecodeArrayBuilder::ResumeGenerator
AllocateJumpTable (for switching by ResumeMode throw/return/next)
# note that `async` function executes until first `await` without suspending
BytecodeGenerator::VisitAwait =>
VisitForAccumulatorValue # evaluate `await`-ed expression
BytecodeGenerator::BuildAwait =>
CallRuntime(kInlineAsyncFunctionAwaitUncaught, ...)
# TODO: do we have `JSAsyncFunctionObject::promise` in the accumulator at this point?
BuildSuspendPoint => ...
CallRuntime(Runtime::kInlineGeneratorGetResumeMode, ...)
BytecodeGenerator::VisitReturnStatement =>
ControlScope::AsyncReturnAccumulator => PerformCommand(CMD_ASYNC_RETURN ..) =>
ControlScopeForTopLevel::Execute => BytecodeGenerator::BuildAsyncReturn =>
CallRuntime(Runtime::kInlineAsyncFunctionResolve ..)
BuildReturn
#
# generator execution
#
IGNITION_HANDLER(SwitchOnGeneratorState, InterpreterAssembler) =>
jump to JSGeneratorObject::continuation
RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) =>
NewJSGeneratorObject =>
JSFunction::EnsureHasInitialMap =>
# InstanceType is either JS_OBJECT_TYPE, JS_GENERATOR_OBJECT_TYPE, or JS_ASYNC_GENERATOR_OBJECT_TYPE
NewMap
Factory::NewFunctionPrototype =>
# instantiate prototype
NewJSObjectFromMap with either
NativeContext::async_generator_object_prototype_map
NativeContext::generator_object_prototype_map (initialized during Genesis::CreateIteratorMaps)
NativeContext::object_function's initial_map
JSFunction::SetInitialMap
NewJSObjectFromMap
set properties e.g. ResumeMode::kNext, kGeneratorExecuting
IGNITION_HANDLER(SuspendGenerator, InterpreterAssembler) =>
ExportParametersAndRegisterFile
store `suspend_id` in `JSGeneratorObject::continuation`
Return(GetAccumulator()) # e.g. accumulator will be `yield` result if `CreateIterResultObject` opcode is right before `SuspendGenerator`
IGNITION_HANDLER(ResumeGenerator, InterpreterAssembler) =>
ImportRegisterFile
# yield
RUNTIME_FUNCTION(Runtime_CreateIterResultObject) => NewJSIteratorResult
# next
TF_BUILTIN(GeneratorPrototypeNext, GeneratorBuiltinsAssembler) =>
GeneratorBuiltinsAssembler::GeneratorPrototypeNext =>
# assert receiver is JS_GENERATOR_OBJECT_TYPE
InnerResume =>
set JSGeneratorObject::resume_mode (here JSGeneratorObject::kNext)
CodeFactory::ResumeGenerator => Builtin::kResumeGeneratorTrampoline => ...
CodeStubArguments::PopAndReturn
(e.g. builtins-x64.cc)
Builtins::Generate_ResumeGeneratorTrampoline => ...
#
# async/await
#
# initial call of async function
TF_BUILTIN(AsyncFunctionEnter, AsyncFunctionBuiltinsAssembler) =>
NewJSPromise (aka "implicit promise" which becomes a return value of async function call)
# instantiate JSAsyncFunctionObject with async_function_object_map from native context
# set JSAsyncFunctionObject::promise
Return(async_function_object)
# await
TF_BUILTIN(AsyncFunctionAwaitUncaught ..) => AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait =>
AsyncFunctionAwaitResolveSharedFunConstant (corresponds to Builtin::kAsyncFunctionAwaitResolveClosure (setup in `Heap::CreateInitialObjects`))
Await =>
# if awaited value is not promise (this is a non-optimized path as explained in https://v8.dev/blog/fast-async)
NewJSPromise to wrap non-promise value (what does "parent" do? only for debugging purpose? i.e. non-spec purpose?)
Builtin::kResolvePromise (wrapping promise will resolve non-promise value awaited)
# initialize dedicated `await_context` and store `JSAsyncFunctionObject` in `EXTENSION_INDEX`
Builtin::kPerformPromiseThen (similar to <awaited-promise>.then(onResolve, onReject)) # see `PromisePrototypeThen` above
Return(outer_promise) # aka. JSAsyncFunctionObject::promise which will be put on the accumulator and then returned to the caller by `SuspendGenerator`
# resolve callback of awaited value
TF_BUILTIN(AsyncFunctionAwaitResolveClosure ..) =>
AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResumeClosure(... JSGeneratorObject::kNext) =>
# retrieve JSAsyncFunctionObject from context
# save JSGeneratorObject::resume_mode (here JSGeneratorObject::kNext)
CodeFactory::ResumeGenerator (call `Builtin::kResumeGeneratorTrampoline` similar to `Generator.prototype.next`)
# reject callback of awaited value
TF_BUILTIN(AsyncFunctionAwaitRejectClosure ..) =>
AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResumeClosure(... JSGeneratorObject::kThrow) => ...
# return async function by finally resolving `JSAsyncFunctionObject::promise`
TF_BUILTIN(AsyncFunctionResolve, AsyncFunctionBuiltinsAssembler) =>
Builtin::kResolvePromise (resolve JSAsyncFunctionObject::promise with "value" (TODO: where does this come from?))
Return(promise)
# return error as rejection (via parser rewrite)
AsyncFunctionReject => ??
#
# data structure
#
BytecodeGenerator
incoming_new_target_or_generator_
generator_jump_table_
suspend_count_
FunctionLiteral
FunctionKind (e.g. kAsyncArrowFunction)
JSGeneratorObject < JSObject
JSFunction
Context
resume_mode: Smi
continuation: Smi (used as jump destination when resuming generator (cf. `SwitchOnGeneratorState`))
parameters_and_registers
JSAsyncFunctionObject < JSGeneratorObject
JSPromise
JSAsyncGeneratorObject < JSGeneratorObject
-
snapshot
- snaphsot generation
interpreter::GenerateBytecodeHandler
- run without snapshot
- snaphsot generation
-
global object
-
tests
./out/x64.debug/d8 -e 'new Promise(resolve => { console.log(1), resolve(); }).then(() => console.log(3)); console.log(2);'
v8::Shell::Main =>
v8::V8::Initialize => ??
RunMain =>
CreateEvaluationContext =>
CreateGlobalTemplate (setup print, load, etc...)
Context::New => NewContext (context_snapshot_index = 0) => CreateEnvironment =>
InvokeBootstrapper::Invoke => Bootstrapper::CreateEnvironment =>
Genesis::Genesis =>
(if Isolate::initialized_from_snapshot)
Snapshot::NewContextFromSnapshot => ??
(if snapshot)
CreateNewGlobals => ??
HookUpGlobalObject => Context::extension as global object
(otherwise)
InitializeGlobal =>
# define JS runtime e.g. Object, Promise, etc...
# cf. https://tc39.es/ecma262/multipage/global-object.html#sec-value-properties-of-the-global-object
(Promise)
InstallFunction(..., "Promise", ..., Builtin::kPromiseConstructor) => ??
InstallWithIntrinsicDefaultProto(..., Context::PROMISE_FUNCTION_INDEX)
NativeContext::set_microtask_queue
# if source is given on CLI e.g. "-e" option
SourceGroup::Execute => Shell::ExecuteString =>
CompileString => ...
Script::Run => ...
CompleteMessageLoop => ??
RunShell => ??
SourceGroup::Execute => ??
#
# data structure
#
JSGlobalObject < JSSpecialObject < JSCustomElementsObject < JSObject
- e.g. via
out/x64.debug/cctest test-elements-kind/JSObjectAddingProperties
main =>
cppgc::InitializeProcess
V8::Initialize
CcTest::Run =>
Isolate::New
Isolate::Enter
internal::test_elements_kind::TestJSObjectAddingProperties =>
CcTest::InitializeVM =>
Context::New => NewContext => CreateEnvironment
Context::Enter =>
Utils::OpenHandle
HandleScopeImplementer::EnterContext
i::Isolate::set_context
...
Factory::NewFunctionForTesting =>
JSFunctionBuilder::Build =>
BuildRaw =>
Factory::New(Map, AllocationType) : HeapObject =>
Heap::AllocateRawWith
HeapObject::set_map_after_allocation
Compiler::PostInstantiation
...
Factory::NewJSObject => ???
...
Isolate::Exit
V8::Dispose
main =>
platform::NewDefaultPlatform => DefaultPlatform::DefaultPlatform =>
EnsureBackgroundTaskRunnerInitialized => DefaultWorkerThreadsTaskRunner => WorkerThread
V8::Initialize ... internal::V8::Initialize =>
various FLAG checks (NOTE: global options set via e.g. V8::SetFlagsFromCommandLine)
base::OS::Initialize
IsolateAllocator::InitializeOncePerProcess => VirtualMemoryCage::InitReservation => ???
Isolate::InitializeOncePerProcess
ElementsAccessor, Bootstrapper, WasmEngine, etc... with `InitializeOncePerProcess`
Isolate::new => Isolate::Initialize => ???
Isolate::Scope
Context::New
Context::Scope
Script::Compile
Script::Run
- examples
Math
builtins migration https://github.com/v8/v8/commit/e8986a4e065aa5f33119713f78338ba7ec4938a7
- build system
run_torque
inBUILD.gn
- output
out/x64.debug/gen/torque-generated
builtin-definitions.h
(BUILTIN_LIST_FROM_TORQUE
)src/builtins/math-tq-csa.cc
(TF_BUILTIN(MathAbs, ...)
etc..)
- output
# we can use local ninja (not from depot tools)
./configure --ninja -C
ninja -C out/Debug
.vscode/c_cpp_properties.json
{
"version": 4,
"configurations": [
{
"name": "Linux",
"compileCommands": "${workspaceFolder}/out/Debug/compile_commands.json"
}
]
}