Skip to content

Commit 6e34ddd

Browse files
authored
Add files via upload
1 parent 2b9c6d1 commit 6e34ddd

File tree

28 files changed

+2447
-0
lines changed

28 files changed

+2447
-0
lines changed

chap43/f1.png

101 KB
Loading

chap43/readme.md

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
# 《Chrome V8 源码》43. Turbofan 源码分析
2+
![avatar](../v8.png)
3+
# 1 介绍
4+
接上一篇文章继续说,本文讲解 Turbofan 的工作流程、梳理 PrepareJob、ExecuteJob 和 FinalizeJob 的主要功能以及重要数据结构。
5+
# 2 Turbofan 工作流程
6+
前文提到,Turbofan 分为 NotConcurrent 和 Concurrent 两种工作方式,它们的区别是 NotConcurrent 立即启动优化工作,而 Concurrent 把工作放进同步分发队列。
7+
Concurrent 方式由 GetOptimizedCodeLater() 函数负责,其源码如下:
8+
```c++
9+
1. bool GetOptimizedCodeLater(OptimizedCompilationJob* job, Isolate* isolate) {
10+
2. OptimizedCompilationInfo* compilation_info = job->compilation_info();
11+
3. if (!isolate->optimizing_compile_dispatcher()->IsQueueAvailable()) {
12+
4. if (FLAG_trace_concurrent_recompilation) {
13+
5. //省略................
14+
6. }
15+
7. return false;
16+
8. }
17+
9. if (isolate->heap()->HighMemoryPressure()) {
18+
10. if (FLAG_trace_concurrent_recompilation) {
19+
11. //省略................
20+
12. }
21+
13. return false;
22+
14. }
23+
15. TimerEventScope<TimerEventRecompileSynchronous> timer(isolate);
24+
16. RuntimeCallTimerScope runtimeTimer(
25+
17. isolate, RuntimeCallCounterId::kOptimizeConcurrentPrepare);
26+
18. TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
27+
19. "V8.OptimizeConcurrentPrepare");
28+
20. if (job->PrepareJob(isolate) != CompilationJob::SUCCEEDED) return false;
29+
21. isolate->optimizing_compile_dispatcher()->QueueForOptimization(job);
30+
22. if (FLAG_trace_concurrent_recompilation) {
31+
23. PrintF(" ** Queued ");
32+
24. compilation_info->closure()->ShortPrint();
33+
25. PrintF(" for concurrent optimization.\n");
34+
26. }
35+
27. return true;
36+
28. }
37+
```
38+
上述代码中,第 4-14 行检测工作队列和内存是否满足要求,不满足则停止优化编译。停止优化编译不影响当前 JavaScript 程序的运行,因为 JavaScript 程序正在被解释执行。
39+
第 15-20 行统计 V8 运行信息,与优化编译的功能无关;
40+
第 21 行把优化编译工作 job 添加到工作队列中,并返回结果 true。
41+
NotConcurrent 方式由 GetOptimizedCodeNow() 函数负责,其源码如下:
42+
```c++
43+
1. bool GetOptimizedCodeNow(OptimizedCompilationJob* job, Isolate* isolate) {
44+
2. TimerEventScope<TimerEventRecompileSynchronous> timer(isolate);
45+
3. RuntimeCallTimerScope runtimeTimer(
46+
4. isolate, RuntimeCallCounterId::kOptimizeNonConcurrent);
47+
5. OptimizedCompilationInfo* compilation_info = job->compilation_info();
48+
6. TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
49+
7. "V8.OptimizeNonConcurrent");
50+
8. if (job->PrepareJob(isolate) != CompilationJob::SUCCEEDED ||
51+
9. job->ExecuteJob(isolate->counters()->runtime_call_stats()) !=
52+
10. CompilationJob::SUCCEEDED ||
53+
11. job->FinalizeJob(isolate) != CompilationJob::SUCCEEDED) {
54+
12. if (FLAG_trace_opt) {
55+
13. CodeTracer::Scope scope(isolate->GetCodeTracer());
56+
14. PrintF(scope.file(), "[aborted optimizing ");
57+
15. compilation_info->closure()->ShortPrint(scope.file());
58+
16. PrintF(scope.file(), " because: %s]\n",
59+
17. GetBailoutReason(compilation_info->bailout_reason()));
60+
18. }
61+
19. return false;
62+
20. }
63+
21. // Success!
64+
22. job->RecordCompilationStats(OptimizedCompilationJob::kSynchronous, isolate);
65+
23. DCHECK(!isolate->has_pending_exception());
66+
24. InsertCodeIntoOptimizedCodeCache(compilation_info);
67+
25. job->RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, isolate);
68+
26. return true;
69+
27. }
70+
```
71+
上述代码中, 第 2-7 行统计 V8 运行信息,与优化编译的功能无关;
72+
第 8-9 行完成优化编译的所有工作,这些工作由 PrepareJob、ExecuteJob 以及 FinalizeJob 三个函数负责;
73+
第 10-25 行更新编译状态等信息并返回 true。 优化编译同步进行,也就意味着暂停解释执行并等待优化编译的结果。
74+
# 3 准备 PrepareJob
75+
源码如下:
76+
```c++
77+
1. CompilationJob::Status OptimizedCompilationJob::PrepareJob(Isolate* isolate) {
78+
2. DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
79+
3. DisallowJavascriptExecution no_js(isolate);
80+
4. if (FLAG_trace_opt && compilation_info()->IsOptimizing()) {
81+
5. //省略..............
82+
6. }
83+
7. // Delegate to the underlying implementation.
84+
8. DCHECK_EQ(state(), State::kReadyToPrepare);
85+
9. ScopedTimer t(&time_taken_to_prepare_);
86+
10. return UpdateState(PrepareJobImpl(isolate), State::kReadyToExecute);
87+
11. }
88+
```
89+
上述代码中,第 2-3 行做状态检测、第 4-6 行设置打印出输信息;第 10 行 UpdateState 更新状态信息,PrepareJobImpl 完成初始化工作,其源码如下:
90+
```c++
91+
1. PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl(
92+
2. Isolate* isolate) {
93+
3. PipelineJobScope scope(&data_, isolate->counters()->runtime_call_stats());
94+
4. if (compilation_info()->bytecode_array()->length() >
95+
5. FLAG_max_optimized_bytecode_size) {
96+
6. return AbortOptimization(BailoutReason::kFunctionTooBig);
97+
7. }
98+
8. if (!FLAG_always_opt) {
99+
9. compilation_info()->MarkAsBailoutOnUninitialized();
100+
10. }
101+
11. if (FLAG_turbo_loop_peeling) {
102+
12. compilation_info()->MarkAsLoopPeelingEnabled();
103+
13. }
104+
14. if (FLAG_turbo_inlining) {
105+
15. compilation_info()->MarkAsInliningEnabled();
106+
16. }
107+
17. PoisoningMitigationLevel load_poisoning =
108+
18. PoisoningMitigationLevel::kDontPoison;
109+
19. if (FLAG_untrusted_code_mitigations) {
110+
20. load_poisoning = PoisoningMitigationLevel::kPoisonCriticalOnly;
111+
21. }
112+
22. compilation_info()->SetPoisoningMitigationLevel(load_poisoning);
113+
23. if (FLAG_turbo_allocation_folding) {
114+
24. compilation_info()->MarkAsAllocationFoldingEnabled();
115+
25. }
116+
26. if (compilation_info()->closure()->raw_feedback_cell().map() ==
117+
27. ReadOnlyRoots(isolate).one_closure_cell_map() &&
118+
28. !compilation_info()->is_osr()) {
119+
29. compilation_info()->MarkAsFunctionContextSpecializing();
120+
30. data_.ChooseSpecializationContext();
121+
31. }
122+
32. if (compilation_info()->is_source_positions_enabled()) {
123+
33. SharedFunctionInfo::EnsureSourcePositionsAvailable(
124+
34. isolate, compilation_info()->shared_info());
125+
35. }
126+
36. data_.set_start_source_position(
127+
37. compilation_info()->shared_info()->StartPosition());
128+
38. linkage_ = new (compilation_info()->zone()) Linkage(
129+
39. Linkage::ComputeIncoming(compilation_info()->zone(), compilation_info()));
130+
40. if (compilation_info()->is_osr()) data_.InitializeOsrHelper();
131+
41. Deoptimizer::EnsureCodeForDeoptimizationEntries(isolate);
132+
42. pipeline_.Serialize();
133+
43. if (!data_.broker()->is_concurrent_inlining()) {
134+
44. if (!pipeline_.CreateGraph()) {
135+
45. CHECK(!isolate->has_pending_exception());
136+
46. return AbortOptimization(BailoutReason::kGraphBuildingFailed);
137+
47. }
138+
48. }
139+
49. return SUCCEEDED;
140+
50. }
141+
```
142+
上述代码中,第 4-7 行检查 BytecodeArray 的长度是否超过最大长度限制;
143+
第 8-10 行检查 always_optimization 使能标记,它的作用是 always try to optimize functions;
144+
第 11-25 行检测 loop_peeling、inling、allocation_folding 使能标记,详细说明参见 flag-definitions.h 文件;
145+
第 26-37 行设置 context、OSR、源码信息;
146+
第 38 行创建编译需要的 link 信息;
147+
第 44 行创建 V8.TFGraph,这之后不再需要 `T<Node>`了;
148+
# 4 编译 ExecuteJob
149+
ExecuteJob() 中调用 ExecuteJobImpl() 来完成优化编译的主体工作,其源码如下:
150+
```c++
151+
1. PipelineCompilationJob::Status PipelineCompilationJob::ExecuteJobImpl(
152+
2. RuntimeCallStats* stats) {
153+
3. PipelineJobScope scope(&data_, stats);
154+
4. if (data_.broker()->is_concurrent_inlining()) {
155+
5. //省略.....
156+
6. }
157+
7. bool success;
158+
8. if (FLAG_turboprop) {
159+
9. success = pipeline_.OptimizeGraphForMidTier(linkage_);
160+
10. } else {
161+
11. success = pipeline_.OptimizeGraph(linkage_);
162+
12. }
163+
13. if (!success) return FAILED;
164+
14. pipeline_.AssembleCode(linkage_);
165+
15. return SUCCEEDED;
166+
```
167+
上述代码的核心功能就两个,一个基于图的优化功能(OptimizeGraphForMidTier 和 OptimizeGraph),另一个汇编生成器(AssembleCode)。优化功能的源码如下:
168+
```c++
169+
bool PipelineImpl::OptimizeGraphForMidTier(Linkage* linkage) {
170+
Run<TyperPhase>(data->CreateTyper());
171+
RunPrintAndVerify(TyperPhase::phase_name());
172+
Run<TypedLoweringPhase>();
173+
RunPrintAndVerify(TypedLoweringPhase::phase_name());
174+
Run<LoopExitEliminationPhase>();
175+
//省略..............
176+
}
177+
//分隔线....................
178+
bool PipelineImpl::OptimizeGraph(Linkage* linkage) {
179+
PipelineData* data = this->data_;
180+
data->BeginPhaseKind("V8.TFLowering");
181+
Run<TyperPhase>(data->CreateTyper());
182+
RunPrintAndVerify(TyperPhase::phase_name());
183+
Run<TypedLoweringPhase>();
184+
RunPrintAndVerify(TypedLoweringPhase::phase_name());
185+
//省略..............
186+
}
187+
```
188+
上述代码中,每一个 Run 方法代表过了一种优化技术,每种优化技术的实现都有对应的数据结构,本文不做讲解。
189+
汇编生成器(AssembleCode)的源码如下:
190+
```c++
191+
1. void PipelineImpl::AssembleCode(Linkage* linkage,
192+
2. std::unique_ptr<AssemblerBuffer> buffer) {
193+
3. PipelineData* data = this->data_;
194+
4. data->BeginPhaseKind("V8.TFCodeGeneration");
195+
5. data->InitializeCodeGenerator(linkage, std::move(buffer));
196+
6. Run<AssembleCodePhase>();
197+
7. //省略.....
198+
8. }
199+
9. //分隔.................
200+
10. CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
201+
11. Instruction* instr) {
202+
12. switch (arch_opcode) {
203+
13. case kArchCallCodeObject: {
204+
14. if (HasImmediateInput(instr, 0)) {
205+
15. //省略.......................
206+
16. } else {
207+
17. Register reg = i.InputRegister(0);
208+
18. DCHECK_IMPLIES(
209+
19. HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister),
210+
20. reg == kJavaScriptCallCodeStartRegister);
211+
21. __ LoadCodeObjectEntry(reg, reg);
212+
22. if (HasCallDescriptorFlag(instr, CallDescriptor::kRetpoline)) {
213+
23. __ RetpolineCall(reg);
214+
24. } else {
215+
25. __ call(reg);
216+
26. } }
217+
27. RecordCallPosition(instr);
218+
28. frame_access_state()->ClearSPDelta();
219+
29. break;
220+
30. }
221+
31. case kArchCallBuiltinPointer: {
222+
32. //省略.......................
223+
33. break;
224+
34. }}
225+
35. }
226+
```
227+
上述第 5 行代码初始 CodeGenerator,第 6 行代码 Run() 方法最终会调用第 10 行 AssembleArchInstruction() 方法以完成汇编码的生成。第 12-34 行代码采用 switch-case 为每条操作码(OPCODE)编写不同的汇编码生成规则。每条操作码对应一个 case,这个 case 描绘了把操作码转换为汇编码的规则。图 1 给出了 AssembleArchInstruction 的调用堆栈。
228+
![avatar](f1.png)
229+
V8 中 OPCODE 分为两类,一类是体系结构通用的操作码(COMMON_ARCH_OPCODE_LIST),另一类是体系结构专用的操作码(TARGET_ARCH_OPCODE_LIST),具体参见宏模板。
230+
# 5 收尾 FinalizeJob
231+
收尾工作由 FinalizeJobImpl() 负责,源码如下:
232+
```c++
233+
1. PipelineCompilationJob::Status PipelineCompilationJob::FinalizeJobImpl(
234+
2. Isolate* isolate) {
235+
3. //省略.................
236+
4. MaybeHandle<Code> maybe_code = pipeline_.FinalizeCode();
237+
5. Handle<Code> code;
238+
6. if (!maybe_code.ToHandle(&code)) {
239+
7. //省略.................
240+
8. }
241+
9. if (!pipeline_.CommitDependencies(code)) {
242+
10. //省略.................
243+
11. }
244+
12. compilation_info()->SetCode(code);
245+
13. compilation_info()->native_context().AddOptimizedCode(*code);
246+
14. RegisterWeakObjectsInOptimizedCode(code, isolate);
247+
15. return SUCCEEDED;
248+
16. }
249+
```
250+
上述第 4 行代码接收优化编译的结果;第 6-8 行代码优化编译失败并返回 false;第 9-11 行代码重试优化编译;第 12 行代码将优化编译结果存储进 Cache,下次再优化该 SharedFunction 时将直接使用 Cache 结果。
251+
**技术总结**
252+
**(1)** --Trace-XXX 用于打印编译状态和结果,参见 d8 --help 或 flag-definitions.h;
253+
**(2)** 优化编译的使能标记的定义在 flag-definitions.h 中;
254+
**(3)** On-Stack Replacement(OSR)是一种运行时替换函数的栈帧的方法。
255+
# 新文章介绍
256+
**《Chrome V8 Bug》** 系列文章即将上线。
257+
《Chrome V8 Bug》系列文章的目的是解释漏洞的产生原因,并向你展示这些漏洞如何影响 V8 的正确性。其他的漏洞文章大多从安全研究的角度分析,讲述如何设计与使用 PoC。而本系列文章是从源码研究的角度来写的,分析 PoC 在 V8 中的执行细节,讲解为什么 Poc 要这样设计。当然,学习 Poc 的设计与使用,是 V8 安全研究的很好的出发点,所以,对于希望深入学习 V8 源码和 PoC 原理的人来说,本系列文章也是很有价值的介绍性读物。
258+
本系列文章主要讲解 https://bugs.chromium.org/p/v8/issues 的内容,每篇文章讲解一个 issue。如果你有想学习的 issue 也可以告诉我,我会优先分析讲解。
259+
260+
好了,今天到这里,下次见。
261+
**个人能力有限,有不足与纰漏,欢迎批评指正**
262+
**微信:qq9123013 备注:v8交流 邮箱:v8blink@outlook.com**
263+

chap44/f1.png

266 KB
Loading

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy