0x00 前言
没了你,我颓废了自己。心里那些苦,都只哽在喉咙里,一想起来就泪如雨下。 ----王国维
0x01 调用栈
Thread 1 "d8" received signal SIGINT, Interrupt.
0x00007ffff4a8ea44 in v8::base::LocalKeyToPthreadKey (local_key=32767) at ../../src/base/platform/platform-posix.cc:856
856 static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) {
(gdb) bt
#0 0x00007ffff4a8ea44 in v8::base::LocalKeyToPthreadKey (local_key=32767) at ../../src/base/platform/platform-posix.cc:856
#1 0x00007ffff4a8ea6a in v8::base::Thread::GetThreadLocal (key=3) at ../../src/base/platform/platform-posix.cc:952
#2 0x00007ffff6929720 in v8::internal::PerThreadAssertData::GetCurrent () at ../../src/common/assert-scope.cc:45
#3 0x00007ffff692ad2b in v8::internal::PerThreadAssertScope<(v8::internal::PerThreadAssertType)2, true>::IsAllowed () at ../../src/common/assert-scope.cc:91
#4 0x00007ffff6ac3a00 in v8::internal::HandleBase::IsDereferenceAllowed (this=0x7fffffffc360) at ../../src/handles/handles.cc:43
#5 0x000055555561a9c5 in v8::internal::HandleBase::location (this=0x7fffffffc360) at ../../src/handles/handles.h:59
#6 0x00007ffff689e560 in v8::internal::Handle<v8::internal::SeqOneByteString>::operator* (this=0x7fffffffc360) at ../../src/handles/handles.h:137
#7 0x00007ffff689e2b5 in v8::internal::Handle<v8::internal::SeqOneByteString>::operator-> (this=0x7fffffffc360) at ../../src/handles/handles.h:131
#8 0x00007ffff6aee3a3 in v8::internal::Factory::NewRawOneByteString (this=0x14e800000000, length=267, allocation=v8::internal::AllocationType::kYoung)
at ../../src/heap/factory.cc:1085
#9 0x00007ffff6aee5cb in v8::internal::Factory::NewStringFromUtf8 (this=0x14e800000000, string=..., allocation=v8::internal::AllocationType::kYoung)
at ../../src/heap/factory.cc:787
#10 0x00007ffff66d0f43 in v8::(anonymous namespace)::NewString (factory=0x14e800000000, type=v8::NewStringType::kNormal, string=...) at ../../src/api/api.cc:6248
#11 0x00007ffff66d0d97 in v8::String::NewFromUtf8 (isolate=0x14e800000000,
data=0x1426612c1000 "127.0.0.1\tlocalhost\n127.0.1.1\tubuntu\n127.0.0.1 chrome-infra-packages.appspot.com\n\n# The following lines are desirable for IPv6 capable hosts\n::1 ip6-localhost ip6-loopback\nfe00::0 ip6-localnet\nf"..., type=v8::NewStringType::kNormal, length=267) at ../../src/api/api.cc:6297
#12 0x00005555555f178e in v8::Shell::ReadFile (isolate=0x14e800000000, name=0x55555570aa30 "/etc/hosts") at ../../src/d8/d8.cc:2358
#13 0x00005555555f83e3 in v8::Shell::Read (args=...) at ../../src/d8/d8.cc:1412
#14 0x00007ffff6081f0f in Builtins_CallApiCallback () from /home/test/git/google/v8/out/x64.debug/libv8.so
#15 0x00007fffffffc768 in ?? ()
#16 0x00007fffffffc798 in ?? ()
#17 0x0000000000000001 in ?? ()
#18 0x0000000000000040 in ?? ()
#19 0x00007fffffffc7a0 in ?? ()
#20 0x00007fffffffc720 in ?? ()
#21 0x0000000000000006 in ?? ()
#22 0x00007fffffffc7f0 in ?? ()
#23 0x000014e800082c3e in ?? ()
#24 0x000014e8083c0119 in ?? ()
#25 0x000014e800000000 in ?? ()
#26 0x000014e808040305 in ?? ()
#27 0x000014e808040305 in ?? ()
#28 0x000014e808040305 in ?? ()
#29 0x000014e808040305 in ?? ()
#30 0x000014e80824fdbd in ?? ()
#31 0x000014e8083c0119 in ?? ()
#32 0x000014e808240ced in ?? ()
#33 0x000014e80824fec1 in ?? ()
#34 0x000014e80824fdbd in ?? ()
#35 0x000014e80824e125 in ?? ()
#36 0x000014e80836a2d9 in ?? ()
#37 0x0000000000000098 in ?? ()
#38 0x000014e80824fe59 in ?? ()
#39 0x000014e80824fec1 in ?? ()
#40 0x000014e808240ced in ?? ()
#41 0x00007fffffffc818 in ?? ()
#42 0x00007ffff60753da in Builtins_JSEntryTrampoline () from /home/test/git/google/v8/out/x64.debug/libv8.so
#43 0x000014e8083c0119 in ?? ()
#44 0x000014e80824fec1 in ?? ()
#45 0x0000000000000022 in ?? ()
#46 0x00007fffffffc880 in ?? ()
#47 0x00007ffff60751b8 in Builtins_JSEntry () from /home/test/git/google/v8/out/x64.debug/libv8.so
0x02 RunMain函数分析
路径
v8\src\d8\d8.cc
源码
int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
//默认d8启动一个线程跑,options.num_isolates默认值为1
for (int i = 1; i < options.num_isolates; ++i) {
options.isolate_sources[i].StartExecuteInThread();
}
bool success = true;
{
SetWaitUntilDone(isolate, false);
// 默认为null,不会走这个分支
if (options.lcov_file) {
debug::Coverage::SelectMode(isolate, debug::CoverageMode::kBlockCount);
}
//创建HandleScope类的实例对象scope
//HandleScope类基于栈分配方式管理所有local句柄,相当于local句柄的作用域。
//所有的本地句柄都由该作用域分配。
//定义位于../../src/api/api.cc:1124
HandleScope scope(isolate);
//可以看见0x02小结的注解
Local<Context> context = CreateEvaluationContext(isolate);
//last_run 此时为true,use_interactive_shell()用于判断是否为交互shell
bool use_existing_context = last_run && use_interactive_shell();
//LZ运行的js文件,所以这里为false,跳过
if (use_existing_context) {
// Keep using the same context in the interactive shell.
evaluation_context_.Reset(isolate, context);
}
{
//创建Scope类型的作用域,用于管理context
Context::Scope cscope(context);
//创建InspectorClient,默认options.enable_inspector为false
InspectorClient inspector_client(context, options.enable_inspector);
//自定义了一个scope
PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
//开始运行第一个isolate孤岛,暂定这样翻译吧
//LZ放了一个死循环,gdb的是否就会停在这里,等待中断
if (!options.isolate_sources[0].Execute(isolate)) success = false;
if (!CompleteMessageLoop(isolate)) success = false;
}
if (!use_existing_context) {
DisposeModuleEmbedderData(context);
}
WriteLcovData(isolate, options.lcov_file);
}
//回收isolate
CollectGarbage(isolate);
//多线程的情况,需要启动或等待每个线程。不太懂last_run是啥意思
// 可以看到索引从1开始,0代表第一个线程,已经执行过了,从1以后需要单独执行
for (int i = 1; i < options.num_isolates; ++i) {
if (last_run) {
options.isolate_sources[i].JoinThread();
} else {
options.isolate_sources[i].WaitForThread();
}
}
//等待所有worker结束
WaitForRunningWorkers();
// In order to finish successfully, success must be != expected_to_throw.
return success == Shell::options.expected_to_throw ? 1 : 0;
}
0x03 CreateEvaluationContext函数分析
这个函数是d8.cc中用于创建一段内置js代码的自定义函数。这里创建shell中内置的arguments参数变量。
Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
// This needs to be a critical section since this is not thread-safe
base::MutexGuard lock_guard(context_mutex_.Pointer());
// Initialize the global objects
//创建全局模板
Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
//创建一个作用域handle
EscapableHandleScope handle_scope(isolate);
//创建一个context上下文
Local<Context> context = Context::New(isolate, nullptr, global_template);
DCHECK(!context.IsEmpty());
if (i::FLAG_perf_prof_annotate_wasm || i::FLAG_vtune_prof_annotate_wasm) {
isolate->SetWasmLoadSourceMapCallback(ReadFile);
}
//初始化嵌入器数据
//在context中指定的索引index位置,预设EmbedderData,用于保存一些自定义数据
InitializeModuleEmbedderData(context);
//d8是否包含参数,就是d8 '--'后面跟随的参数列表
if (options.include_arguments) {
//创建Scope作用域,用于管理context对象
Context::Scope scope(context);
//保存arguments的值
const std::vector<const char*>& args = options.arguments;
//arguments的个数
int size = static_cast<int>(args.size());
//在isolate中创建一个lLocal数组变量
Local<Array> array = Array::New(isolate, size);
//遍历arguments的值
for (int i = 0; i < size; i++) {
//创建一个string类型的Local变量,urf8编码,arguments的值用于初始化
Local<String> arg =
v8::String::NewFromUtf8(isolate, args[i], v8::NewStringType::kNormal)
.ToLocalChecked();
// 创建Number类型的Local变量,保存arguments的索引
Local<Number> index = v8::Number::New(isolate, i);
//给js语言中数据赋上js语言的index和字符串的值。
array->Set(context, index, arg).FromJust();
}
//这个js数组变量还没有名字,此时创建一个Local<String> name,初始值为"arguments",即为我们
//在d8中使用的arguments数组变量
Local<String> name =
String::NewFromUtf8(isolate, "arguments", NewStringType::kInternalized)
.ToLocalChecked();
//在context上下文中加入名为name的array数据
context->Global()->Set(context, name, array).FromJust();
}
//返回带有此上下文的作用域handle_scope句柄
//【q1】擦,为什么escape后就变成一个context了,为什么不直接返回一个context?
return handle_scope.Escape(context);
}
0x04 参考文献
https://v8docs.nodesource.com/node-0.8/df/d69/classv8_1_1_context.html
https://zhuanlan.zhihu.com/p/35371048
https://www.yuque.com/killa/node/v8-api