3.1 DartVM 自举

runtime/vm/bootstrap.cc 文件是 Dart VM 引导过程的核心部分,主要职责是初始化 Dart VM 的核心状态,加载基础库,并为后续的 Dart 代码执行准备必要的环境。这个文件在 Dart VM 的启动过程中起着关键作用,确保 VM 能够正确加载和初始化所有必要的组件。主要功能:

  1. DoBootstrapping 函数:这是引导过程的主入口函数。它接收一个 kernel 二进制文件作为输入,并完成以下任务:

    1. 创建并注册所有引导库(bootstrap libraries)的 Library 对象。
    2. 调用 BootstrapFromKernel 函数来从 kernel 文件加载实际的库内容。
  2. BootstrapFromKernel 函数:这个函数负责从 kernel 二进制文件中读取和加载库的内容。主要步骤包括:

    1. 使用 kernel::Program::ReadFromBuffer 解析 kernel 二进制数据。
    2. 创建 kernel::KernelLoader 对象来加载库。
    3. 按照预定义的顺序加载所有引导库。
    4. 调用 Finish 函数完成引导过程。
    5. 初始化对象存储(object store)中的已知对象。
    6. 加载平台二进制文件中可能包含的其他库(如 dart:_builtindart:io)。
  3. Finish 函数:这个函数完成引导过程的最后阶段:

    1. 设置本地解析器(native resolver)。
    2. 处理待定类(pending classes)的最终化(finalization)。
    3. 确保 _Closure 类被急切编译(eagerly compiled),因为它是所有闭包实例的类。
  4. CollectTokenPositionsFor 函数:这个函数收集给定脚本的所有标记位置(token positions)。它遍历所有库和类,收集函数、字段和类的标记位置信息。

  5. CollectConstConstructorCoverageFrom 函数:这个函数收集给定脚本中的常量构造函数覆盖信息。它用于支持常量覆盖分析。


BootstrapLibProps

定义 BootstrapLibProps 结构体,用于存储引导库的属性

struct BootstrapLibProps {
  ObjectStore::BootstrapLibraryId index;
  const char* uri;
};

枚举

定义一些常量,用于在后续操作中索引数组:

enum { 
	kPathsUriOffset = 0, 
	kPathsSourceOffset = 1, 
	kPathsEntryLength = 2 
};

创建引导库的属性

定义一个宏,用于创建引导库的属性

#if !defined(DART_PRECOMPILED_RUNTIME)
#define MAKE_PROPERTIES(CamelName, name)                                       \
  {ObjectStore::k##CamelName, "dart:" #name},

static const BootstrapLibProps bootstrap_libraries[] = {
    FOR_EACH_BOOTSTRAP_LIBRARY(MAKE_PROPERTIES)};

#undef MAKE_PROPERTIES

注:FOR_EACH_BOOTSTRAP_LIBRARY 的声明:

// A list of the bootstrap libraries including CamelName and name.
//
// These are listed in the order that they are compiled (see vm/bootstrap.cc).
#define FOR_EACH_BOOTSTRAP_LIBRARY(M)                                          \
  M(Core, core)                                                                \
  M(Async, async)                                                              \
  M(Collection, collection)                                                    \
  M(Convert, convert)                                                          \
  M(Developer, developer)                                                      \
  M(Ffi, ffi)                                                                  \
  M(Internal, _internal)                                                       \
  M(Isolate, isolate)                                                          \
  M(Math, math)                                                                \
  M(Mirrors, mirrors)                                                          \
  M(TypedData, typed_data)                                                     \
  M(VMService, _vmservice)

计算引导库的数量

// 计算引导库的数量
static constexpr intptr_t kBootstrapLibraryCount =
    ARRAY_SIZE(bootstrap_libraries);

BootstrapFromKernel

static ErrorPtr BootstrapFromKernel(Thread* thread,
                                    const uint8_t* kernel_buffer,
                                    intptr_t kernel_buffer_size) {
  Zone* zone = thread->zone();
  const char* error = nullptr;
  
  // 从 kernel buffer 读取程序
  std::unique_ptr<kernel::Program> program = kernel::Program::ReadFromBuffer(
      kernel_buffer, kernel_buffer_size, &error);
  if (program == nullptr) {
    // 如果读取失败,创建并返回错误信息
    const intptr_t kMessageBufferSize = 512;
    char message_buffer[kMessageBufferSize];
    Utils::SNPrint(message_buffer, kMessageBufferSize,
                   "Can't load Kernel binary: %s.", error);
    const String& msg = String::HandleNew(message_buffer, Heap::kOld);
    return ApiError::New(msg, Heap::kOld);
  }

  // 使用长跳转设置错误处理
  LongJumpScope jump;
  if (setjmp(*jump.Set()) == 0) {
    // 创建 KernelLoader 对象
    kernel::KernelLoader loader(
	    program.get(), 
	    /*uri_to_source_table=*/nullptr);

    auto isolate_group = thread->isolate_group();

    // 如果需要混淆,读取混淆禁止列表
    if (isolate_group->obfuscate()) {
      loader.ReadObfuscationProhibitions();
    }

    // 按顺序加载引导库
    Library& library = Library::Handle(zone);
    for (intptr_t i = 0; i < kBootstrapLibraryCount; ++i) {
      ObjectStore::BootstrapLibraryId id = bootstrap_libraries[i].index;
      library = isolate_group->object_store()->bootstrap_library(id);
      loader.LoadLibrary(library);
    }

    // 完成引导过程,包括类的最终化
    Finish(thread);

    isolate_group->object_store()->InitKnownObjects();

    // 加载平台二进制文件中可能包含的其他库
    const Object& result = Object::Handle(zone, loader.LoadProgram());
    program.reset();
    if (result.IsError()) {
      return Error::Cast(result).ptr();
    }

    // 如果是预编译模式,读取加载单元
    if (FLAG_precompiled_mode) {
      loader.ReadLoadingUnits();
    }

    return Error::null();
  }

  // 如果发生错误,返回粘性错误
  return Thread::Current()->StealStickyError();
}

本文作者:Maeiee

本文链接:3.1 DartVM 自举

版权声明:如无特别声明,本文即为原创文章,版权归 Maeiee 所有,未经允许不得转载!


喜欢我文章的朋友请随缘打赏,鼓励我创作更多更好的作品!