1,研究用vs编译v875的时候遇到了两个小问题。
新版本v8,基本上没考虑过vs来编译。
现在遇到了:
(1)v8有部分代码是py预编译生成的。而在编译x86和x64的时候,居然这个预编译的代码还稍微有点不一样。具体是在
gen\v8\torque-generated\builtins-array-from-dsl-gen.cc
gen\v8\torque-generated\builtins-base-from-dsl-gen.cc
gen\v8\torque-generated\builtins-test-from-dsl-gen.cc
这三文件。里面主要是有些涉及到指针的运算,有些常量值不同了。当时没注意到这个问题,导致我在编译x64版本的时候,疯狂崩溃,而且都是崩溃在JIT的汇编代码里,极其难以调试。最后也是灵机一动才想到这个可能性。
(2)vs的编译优化似乎有问题。开启性能优先优化的时候,一运行又崩溃了。最后跟踪发现在某些函数(比如Map::NumberOfFields())通过加上#pragma optimize("", off)居然就没事了。百思不得其解,最后只能归结为vs的编译工具链的bug。我是用的vs2017 for xp的toolset。最后解决方案是编译选项里加入 /d2SSAOptimizer- 即可解决。
2,切换v8到75的时候,发现MessagePort 老是被析构。
后来发现新版本blink的内存回收的trace,是在ScriptWrappableVisitor::EnterFinalPause里对一些绑定给v8的对象里进行的。
以前blink是在V8GCController::gcPrologue里主动询问v8有哪些全局对象。然后v8回调DOMWrapperTracer::VisitPersistentHandle。然后在MajorGCWrapperVisitor::VisitPersistentHandle里blink会通过询问这些对象的MajorGCWrapperVisitor::hasPendingActivity虚函数,判断要不要让v8里trace这个对象。这个流程比较简单直接
而新版本v8稍微变了。分了好几个步骤。比如,先在ScriptWrappableVisitor::EnterFinalPause里调用MajorGCWrapperVisitor::hasPendingActivity判断是否需要trace,如果是的话,就记录下来(通过ScriptWrappableVisitor::RegisterV8Reference,然后放到ScriptWrappableVisitor::pushToMarkingDeque的队列里),然后v8在某个时刻又回调ScriptWrappableVisitor::AdvanceTracing,从上面pushToMarkingDeque的队列里取出,注册给v8,堆栈是:
v8::PersistentBase<v8::Value>::RegisterExternalReference
blink::ScriptWrappableVisitor::markWrapper
blink::ScriptWrappable::markWrapper
blink::DOMWrapperWorld::markWrappersInAllWorlds
blink::ScriptWrappableVisitor::markWrappersInAllWorlds
blink::TraceTrait<blink::MessagePort>::traceMarkedWrapper
blink::WrapperMarkingData::traceWrappers
blink::ScriptWrappableVisitor::AdvanceTracing
然后在另外某个时刻,v8会把上次注册的,回调给blink,让blink自己去trace。猜测这样是为了分代GC。
总结一下,老blink是v8直接询问那些v8保存的blink绑定进去的全局对象哪些需要trace,然后当场trace。而新blink是blink内部记录了ActiveScriptWrappableBase到全局数组,然后v8询问了blink以后,blink内部先通过hasPendingActivity判断是否需要回收,不回收的话,给v8里记录一下。然后找个时机,再回调blink,把标记了的这些对象让blink去trace。过程麻烦了一些。
所以刚开头提到的问题,是我没实现ScriptWrappableVisitor::EnterFinalPause,导致这些对象没被trace,所以就被blink析构了。