D8 源码分析

学习 v8在我看来有两种比较好的方式,一种是通过分析 js 对象或者函数,比如分析 Promise 的实现,另一种方式就是通过分析 d8的源码来进行学习. d8实际上就是一个 v8的开发者工具,已通过 d8来对 js 进行调试和分析.这篇文章主要是通过分析 d8的实现来学习 v8.

在 c 和 c++ 中,大部分程序的入口都是main 函数,因此我们从 main 函数开始分析.

int main(int argc, char* argv[]) { return v8::Shell::Main(argc, argv); }

从 main 函数中我们可以看到, main 函数很简单只调用了 Shell 类的 Main 函数,所有的逻辑都是在 Shell 类里面实现的.Shell 类实际上就是 d8的主要部分.

...
// static
ShellOptions Shell::options;
...
int Shell::Main(int argc, char* argv[]) {
  ...
  if (!SetOptions(argc, argv)) return 1;
  ...
  v8::V8::InitializeICUDefaultLocation(argv[0], options.icu_data_file);
  ...
}

首先,Shell::Main 通过调用 SetOptions 函数解析命令行里面的参数并保存到Shell 类的静态成员变量 options 里面.然后通过相应的参数进行一系列的初始化工作.

InitializeICUDefaultLocation 函数主要是用来初始化 ICU 库的,默认会第一个参数是可执行文件路径,第二个参数是 icu 文件,如果为空,默认是 icudtl.dat 文件.

std::unique_ptr<platform::tracing::TracingController> tracing;
std::ofstream trace_file;
if (options.trace_enabled && !i::FLAG_verify_predictable) {
  tracing_file.open(options.trace_path ? options.trace_path : "v8_trace.json");
  ...
  platform::tracing::TraceBuffer* trace_buffer =
        platform::tracing::TraceBuffer::CreateTraceBufferRingBuffer(
            platform::tracing::TraceBuffer::kRingBufferChunks,
            platform::tracing::TraceWriter::CreateJSONTraceWriter(trace_file));
  tracing->Initialize(trace_buffer);
}

接下来会分析是否需要保存追踪日志,如果与指定日志路径就会将追踪日志保存到 指定的路径,如果没有就会保存在当前的目录下的 v8_tracing.json 文件中.创建好 tracing之后接下来就是创建 v8 platform 实例了.

g_platform = v8::platform::NewDefaultPlatform(
    options.thread_pool_size, v8::platform::IdleTaskSupport::kEnabled,
    in_process_stack_dumping, std::move(tracing));
g_default_platform = g_platform.get();
if (i::FLAG_verify_predictable) {
  g_platform = MakePredictablePlatform(std::move(g_platform));
}
if (options.stress_delay_tasks) {
  int64_t random_seed = i::FLAG_fuzzer_random_seed;
  if (!random_seed) random_seed = i::FLAG_random_seed;
  // If random_seed is still 0 here, the {DelayedTasksPlatform} will choose a
  // random seed.
  g_platform = MakeDelayedTasksPlatform(std::move(g_platform), random_seed);
}

从上面在这段代码可以看到参数不一样会创建不相同的 platform 实例,g_default_platform 是通过 NewDefaultPlatform() 创建的 DefaultPlatform, 通过 MakePredictablePlatform() 创建的是 PredictablePlatform, 通过 MakeDelayedTasksPlatform() 创建的是一个 DelayedTasksPlatform.这里只分析 NewDefaultPlatform() 函数.

std::unique_ptr<v8::Platform> NewDefaultPlatform(
    int thread_pool_size, IdleTaskSupport idle_task_support,
    InProcessStackDumping in_process_stack_dumping,
    std::unique_ptr<v8::TracingController> tracing_controller) {
  if (in_process_stack_dumping == InProcessStackDumping::kEnabled) {
    v8::base::debug::EnableInProcessStackDumping();
  }
  std::unique_ptr<DefaultPlatform> platform(
      new DefaultPlatform(idle_task_support, std::move(tracing_controller)));
  platform->SetThreadPoolSize(thread_pool_size);
  platform->EnsureBackgroundTaskRunnerInitialized();
  return std::move(platform);
}

从 NewDefaultPlatform() 函数以及 Platform 类的注释,我们可以了解什么是 platform是干什么的, 以及platform 有什么用?

从注释来看是一个是对整个嵌入v8的程序的一个抽象概念,看看他的私有变量我们可以大概知道他是干嘛的,Platform用来管理isolate,确定他是在后台线程还是前台线程运行,管理线程池等。

创建完 platform 之后就正式开始进行 v8的初始化工作了.

v8::V8::InitializePlatform(g_platform.get());
v8::V8::Initialize();
if (options.snapshot_blob) { 
  v8::V8::InitializeExternalStartupDataFromFile(options.snapshot_blob);
} else {
  v8::V8::InitializeExternalStartupData(argv[0]);
}

如果options 里面指定了 snapshot_blob 则从指定的 snapshot_blob 文件加载外部的数据,否则从当前执行的文件里面加载外部数据,这里涉及到了 v8的 snapshot 技术,snapshot 就是把之前运行且编译过的代码进行快照,然后保存起来,之后直接从保存的文件中加载,这样可以加快 v8的启动速度.

初始化完成之后,接下来就进入 isolate 创建阶段了.

Isolate::CreateParams create_params;
...
create_params.array_buffer_allocator = Shell::array_buffer_allocator;
create_params.constraints.ConfigureDefaults(
      base::SysInfo::AmountOfPhysicalMemory(),
      base::SysInfo::AmountOfVirtualMemory());
...
Isolate* isolate = Isolate::New(create_params);
isolate->SetHostCleanupFinalizationGroupCallback(
    Shell::HostCleanupFinalizationGroup);
isolate->SetHostImportModuleDynamicallyCallback(
    Shell::HostImportModuleDynamically);
isolate->SetHostInitializeImportMetaObjectCallback(
    Shell::HostInitializeImportMetaObject);

创建 isolate 之前首先需要设置一些信息,比如缓冲区大小,物理内存和虚拟内存的大小等等,这些信息都通过 CreateParams 来保存,v8和 chromium 的代码有很多相似的地方,大部分的内容的初始化都会有一个 CreateParams 类来保存创建信息,比如 Browser::CreateParams, content::CreateParams等等.

在 v8里面创建对象都是通过类的静态成员函数 New 来创建的,而不是直接通过关键字 new 来创建的.

isolate 创建完成之后设置了三个回调函数.

SetHostCleanupFinalizationGroupCallback 指定了在准备清除finalization group并要求在将来的任务中调用FinalizationGroup :: Cleanup() 的回调函数。

SetHostImportModuleDynamicallyCallback 指定通过使用动态import 来加载模块的回调函数。

SetHostInitializeImportMetaObjectCallback 指定通过的 importa.meta 功能检索模块的host-defined元数据时需要调用的回调函数。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容