This is the 8th day of my participation in the August More text Challenge. For details, see: August More Text Challenge. In response to the nuggets’ August challenge,
Run the source code through the JIT
This section describes what happens when Dart is executed from the command line:
// hello.dart main() => print('Hello, World! '); $ dart hello.dart Hello, World!Copy the code
“The Dart 2 VM begins to no longer have the ability to execute Dart directly from the original code, instead the VM expects to get the kernel binary (also known as a DILL file) that contains the serialized kernel AST.” The task of translating the Dart source code into the Kernel AST is handled by the common front end (CFE), which is written in Dart and shared across different Dart tools (e.g., VM, Dart2JS, Dart Dev Compiler).
To keep executing Dart directly from source code, an auxiliary ISOLATE called Kernel Service is hosted here, which handles compiling the Dart source code into the kernel, and then the VM runs the resulting kernel binaries.
However, this setup is not the only way CFE and VM can run Dart code. For example, “Flutter is a complete separation of the processes that are compiled to the Kernel from the processes that are executed from the Kernel,” and implement them on different devices: Compilation occurs on the developer machine (host) and is performed on the target mobile device, which receives the kernel binaries sent to it by the Flutter tool.
Note here that the Flutter tool does not handle the parsing of Dart itself; instead it generates another persistent process, frontend_Server, which is essentially a wrapper around CFE and some of the Kernel-to-kernel transformations specific to Flutter.
Frontend_server compiles the Dart source code into a kernel file, which the Flutter sends to the device. Frontend_server comes into play when developers request hot overloads: In this case, the Frontend_Server can reuse the CFE state from the previous compilation and recompile the actual changed library.
“Once the kernel binary file is loaded into the VM, it would be parsed to create on behalf of all kinds of application entity object, but the process is done by inert” : first, only load about the basic information of the library and class, each entity are derived from the kernel binary keep a pointer to a binary file, so that you can according to need to load more information later.
❝
We use the Untagged prefix whenever we refer to objects that are internally allocated by the VM because it follows the VM’s own naming convention: the layout of internal VM objects is defined by C++ classes with names beginning with the Untagged header, runtime/ VM /raw_object.h. For example, dart::UntaggedClass describes a DART class VM object, and DART ::UntaggedField is a VM object
❞
“Information about a class is only fully deserialized when it is needed at runtime (for example, to find a class member, allocate an instance, etc.).” At this stage, the class members are read from the kernel binary. However, at this stage, the complete function bodies are not deserialized, only their signatures are deserialized.
At this point methods can be successfully parsed and called at runtime because enough information has been loaded from the kernel binaries, such that it can parse and call functions in the main library.
❝
Package :kernel/ast.dart defines classes that describe kernel ast; Package :front_end processing parses the Dart source code and builds the kernel AST from it. Dart: : the kernel: : KernelLoader: : LoadEntireProgram is the kernel AST deserialize the entry point for corresponding VM object; PKG/VM /bin/kernel_service.dart implements kernel service isolation, and Runtime/VM/kernel_ISOLate. cc binds the DART implementation to the rest of the VM. Package: VM hosts most of the KERnel-based VM specific functions, such as various kernel-to-kernel transformations; Some VM-specific transformations still exist in the Package :kernel for historical reasons.
❞
Initially all functions will have a placeholder other than the actual executable code of their body: they point to LazyCompileStub, which simply asks the runtime system to generate executable code for the current function and then tail-calls this newly generated code.
The first time a function is compiled, it is done through an unoptimized compiler.