Skip to content

Commit a94552d

Browse files
Create README.md for chap 33
[old version of v8] use Google Translate
1 parent 83a2679 commit a94552d

File tree

1 file changed

+219
-0
lines changed

1 file changed

+219
-0
lines changed

chap33/README.md

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
Google Translate version :))
2+
Old version of V8
3+
4+
"Chrome V8 Source Code" 33. Technical details of Lazy Compile
5+
6+
7+
# 1. Summary
8+
This article is the eighth in the Builtin topic. This article will track the execution process of Bytecode, explain the startup method, workflow, and important data structures of Lazy Compile, and also introduce Builtins related to Lazy Compile.
9+
10+
# 2. Starting Lazy Compile
11+
Before entering Lazy Compile, you must first understand the Bytecode execution process, and use this process to understand how to start Lazy Compile. The source code is as follows:
12+
```cpp
13+
```text
14+
1. function ignition(s) {
15+
2. this.slogan=s;
16+
3. this.start=function(){eval('console.log(this.slogan);')}
17+
4. }
18+
5. worker = new ignition("here we go!");
19+
6. worker.start();
20+
7. //............分隔线................
21+
8. --- AST ---
22+
9. . . FUNCTION "ignition" = function ignition
23+
10. . EXPRESSION STATEMENT at 106
24+
11. . . ASSIGN at 113
25+
12. . . . VAR PROXY unallocated (0000016B96A17A78) (mode = DYNAMIC_GLOBAL, assigned = true) "worker"
26+
13. . . . CALL NEW at 115
27+
14. . . . . VAR PROXY unallocated (0000016B96A17790) (mode = VAR, assigned = true) "ignition"
28+
15. . . . . LITERAL "here we go!"//...........省略..............
29+
16. //...............分隔线.................
30+
17. 0000025885361EAE @ 0 : 13 00 LdaConstant [0]
31+
18. 0000025885361EB0 @ 2 : c2 Star1
32+
19. 0000025885361EB1 @ 3 : 19 fe f8 Mov <closure>, r2
33+
20. 0000025885361EB4 @ 6 : 64 51 01 f9 02 CallRuntime [DeclareGlobals], r1-r2
34+
21. 0000025885361EB9 @ 11 : 21 01 00 LdaGlobal [1], [0]
35+
22. 0000025885361EBC @ 14 : c2 Star1
36+
23. 0000025885361EBD @ 15 : 13 02 LdaConstant [2]
37+
24. 0000025885361EBF @ 17 : c1 Star2
38+
25. 0000025885361EC0 @ 18 : 0b f9 Ldar r1
39+
26. 0000025885361EC2 @ 20 : 68 f9 f8 01 02 Construct r1, r2-r2, [2]
40+
27. 0000025885361EC7 @ 25 : 23 03 04 StaGlobal [3], [4]
41+
28. 0000025885361ECA @ 28 : 21 03 06 LdaGlobal [3], [6]
42+
29. 0000025885361ECD @ 31 : c1 Star2
43+
30. 0000025885361ECE @ 32 : 2d f8 04 08 LdaNamedProperty r2, [4], [8]
44+
31. 0000025885361ED2 @ 36 : c2 Star1
45+
32. 0000025885361ED3 @ 37 : 5c f9 f8 0a CallProperty0 r1, r2, [10]
46+
33. 0000025885361ED7 @ 41 : c3 Star0
47+
34. 0000025885361ED8 @ 42 : a8 Return
48+
35. //..............省略................
49+
36. - length: 5
50+
37. 0: 0x02841b4e1d31 <FixedArray[2]>
51+
38. 1: 0x02841b4e1c09 <String[8]: #ignition>
52+
39. 2: 0x02841b4e1c51 <String[11]: #here we go!>
53+
40. 3: 0x02841b4e1c39 <String[6]: #worker>
54+
41. 4: 0x02841b4e1c71 <String[5]: #start>
55+
``````
56+
57+
The above code is divided into three parts.
58+
The first part (lines 1-6) is the test code used in this article, where line 5 starts Lazy Compile;
59+
the second part (lines 8-15) is the AST of the test code;
60+
the third part (lines 17-41) is the Bytecode of the test code.
61+
62+
Let's start with the Bytecode: (1) LdaGlobal [1], [0] (line 21) uses the string in the constant pool [1] as the key to obtain the global object, that is, to obtain the ignition function;
63+
Star1 (line 22) stores ignition in r1;
64+
Ldar r1 (line 25) takes ignition from r1 and stores it in the accumulator register;
65+
(2) LdaConstant [2] (line 23) and Star2 (line 24) store the string "here we go!" in r2. Construct r1, r2-r2, [2] (26 lines) The Compiler is started when constructing the ignition function. The source code is as follows:
66+
67+
```cpp
68+
```text
69+
1. RUNTIME_FUNCTION(Runtime_NewObject) {
70+
2. HandleScope scope(isolate);
71+
3. DCHECK_EQ(2, args.length());
72+
4. CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
73+
5. CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, 1);
74+
6. RETURN_RESULT_OR_FAILURE(
75+
7. isolate,
76+
8. JSObject::New(target, new_target, Handle<AllocationSite>::null()));
77+
9. }
78+
10. //.............分隔线...............
79+
11. int JSFunction::CalculateExpectedNofProperties(Isolate* isolate,
80+
12. Handle<JSFunction> function) {
81+
13. int expected_nof_properties = 0;
82+
14. for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
83+
15. !iter.IsAtEnd(); iter.Advance()) {
84+
16. Handle<JSReceiver> current =
85+
17. PrototypeIterator::GetCurrent<JSReceiver>(iter);
86+
18. if (!current->IsJSFunction()) break;
87+
19. Handle<JSFunction> func = Handle<JSFunction>::cast(current);
88+
20. // The super constructor should be compiled for the number of expected
89+
21. // properties to be available.
90+
22. Handle<SharedFunctionInfo> shared(func->shared(), isolate);
91+
23. IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate));
92+
24. if (is_compiled_scope.is_compiled() ||
93+
25. Compiler::Compile(isolate, func, Compiler::CLEAR_EXCEPTION,
94+
26. &is_compiled_scope)) {
95+
27. } else {
96+
28. }
97+
29. }
98+
30. }
99+
``````
100+
101+
The above code is divided into two parts. New() (line 8) in Runtime_NewObject creates a new object, that is, creates the ignition function. The second part of the code (lines 11-30) is called in New(). When line 24 calculates the properties of ignition, the Compiler is started to generate and execute bytecode. The source code is as follows:
102+
103+
```
104+
00000258853621BE @ 0 : 82 00 04 CreateFunctionContext [0], [4]
105+
00000258853621C1 @ 3 : 1a f9 PushContext r1
106+
//...省略............
107+
00000258853621E7 @ 41 : a8 Return
108+
```
109+
110+
The Compiler will not be started when the above code is executed, so the Return instruction will return to the test code and execute line 32 CallProperty0 r1, r2, [10]. The source code is as follows:
111+
112+
113+
```cpp
114+
1. IGNITION_HANDLER(CallProperty0, InterpreterJSCallAssembler) {
115+
2. JSCallN(0, ConvertReceiverMode::kNotNullOrUndefined);
116+
3. }
117+
4. //.............分隔线......................
118+
5. void JSCallN(int arg_count, ConvertReceiverMode receiver_mode) {
119+
6. Comment("sea node1");
120+
7. const int kFirstArgumentOperandIndex = 1;
121+
8. const int kReceiverOperandCount = (receiver_mode == ConvertReceiverMode::kNullOrUndefined) ? 0 : 1;
122+
9. const int kReceiverAndArgOperandCount = kReceiverOperandCount + arg_count;
123+
10. const int kSlotOperandIndex = kFirstArgumentOperandIndex + kReceiverAndArgOperandCount;
124+
11. TNode<Object> function = LoadRegisterAtOperandIndex(0);
125+
12. LazyNode<Object> receiver = [=] {return receiver_mode == ConvertReceiverMode::kNullOrUndefined
126+
13. ? UndefinedConstant() : LoadRegisterAtOperandIndex(1); };
127+
14. TNode<UintPtrT> slot_id = BytecodeOperandIdx(kSlotOperandIndex);
128+
15. TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
129+
16. TNode<Context> context = GetContext();
130+
17. CollectCallFeedback(function, receiver, context, maybe_feedback_vector,
131+
18. slot_id);
132+
19. switch (kReceiverAndArgOperandCount) {
133+
20. case 0:
134+
21. CallJSAndDispatch(function, context, Int32Constant(arg_count),
135+
22. receiver_mode);
136+
23. break;
137+
24. case 1:
138+
25. CallJSAndDispatch(
139+
26. function, context, Int32Constant(arg_count), receiver_mode,
140+
27. LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex));
141+
28. break;//....省略.......
142+
29. default:
143+
30. UNREACHABLE();
144+
31. }
145+
32. }
146+
33. };
147+
```
148+
149+
In the above code, the value of register r1 is JSFunction start, and the value of register r2 is ignition map. Line 2 calls JSCallN(); line 9 calls kReceiverAndArgOperandCount to 2; line 11 calls function to JSFunction start; line 25 calls CallJSAndDIspatch(), which uses TailCallN() to complete the function call and finally enters Lazy Compile. Figure 1 shows the call stack at this time.
150+
151+
![enter image description here](https://pica.zhimg.com/v2-0faaa1cc4a827287242880f78bc17ad6_1440w.jpg)
152+
153+
# 3. Lazy Compile
154+
The way to start Lazy Compile in the test code is Runtime. The source code is as follows:
155+
```cpp
156+
1. RUNTIME_FUNCTION(Runtime_CompileLazy) {
157+
2. HandleScope scope(isolate);
158+
3. DCHECK_EQ(1, args.length());
159+
4. CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
160+
5. Handle<SharedFunctionInfo> sfi(function->shared(), isolate);
161+
6. #ifdef DEBUG
162+
7. if (FLAG_trace_lazy && !sfi->is_compiled()) {
163+
8. PrintF("[unoptimized: ");
164+
9. function->PrintName();
165+
10. PrintF("]\n");
166+
11. }
167+
12. #endif
168+
13. StackLimitCheck check(isolate);
169+
14. if (check.JsHasOverflowed(kStackSpaceRequiredForCompilation * KB)) {
170+
15. return isolate->StackOverflow();
171+
16. }
172+
17. IsCompiledScope is_compiled_scope;
173+
18. if (!Compiler::Compile(isolate, function, Compiler::KEEP_EXCEPTION,
174+
19. &is_compiled_scope)) {
175+
20. return ReadOnlyRoots(isolate).exception();
176+
21. }
177+
22. DCHECK(function->is_compiled());
178+
23. return function->code();
179+
24. }
180+
```
181+
182+
The value of function in line 3 of the above code is JSFunction start; line 18 starts the compilation process. The source code is as follows:
183+
```cpp
184+
1. bool Compiler::Compile(...省略....) {
185+
2. Handle<Script> script(Script::cast(shared_info->script()), isolate);
186+
3. UnoptimizedCompileFlags flags =
187+
4. UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared_info);
188+
5. UnoptimizedCompileState compile_state(isolate);
189+
6. ParseInfo parse_info(isolate, flags, &compile_state);
190+
7. LazyCompileDispatcher* dispatcher = isolate->lazy_compile_dispatcher();
191+
8. if (dispatcher->IsEnqueued(shared_info)) {
192+
9. }
193+
10. if (shared_info->HasUncompiledDataWithPreparseData()) {
194+
11. }
195+
12. if (!parsing::ParseAny(&parse_info, shared_info, isolate,
196+
13. parsing::ReportStatisticsMode::kYes)) {
197+
14. return FailWithPendingException(isolate, script, &parse_info, flag);
198+
15. }//..........省略........
199+
16. FinalizeUnoptimizedCompilationDataList
200+
17. finalize_unoptimized_compilation_data_list;
201+
18. if (!IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
202+
19. isolate, shared_info, script, &parse_info, isolate->allocator(),
203+
20. is_compiled_scope, &finalize_unoptimized_compilation_data_list,
204+
21. nullptr)) {
205+
22. return FailWithPendingException(isolate, script, &parse_info, flag);
206+
23. }
207+
24. FinalizeUnoptimizedCompilation(isolate, script, flags, &compile_state,
208+
25. finalize_unoptimized_compilation_data_list);
209+
26. if (FLAG_always_sparkplug) {
210+
27. CompileAllWithBaseline(isolate, finalize_unoptimized_compilation_data_list);
211+
28. }
212+
29. return true;
213+
30. }
214+
```
215+
216+
The above code is consistent with the compilation process described above, please analyze it yourself. Note: Line 27 is the new compilation component added by V8, which is located between Ignition and Turbofan. Figure 2 shows the call stack at this time.
217+
![enter image description here](https://pic2.zhimg.com/v2-efe9f8970088437a76c5a8616692e30f_1440w.jpg)
218+
219+
Technical summary (1) This article involves two compiles, one for calculating object properties and the other for Lazy Compile; (2) TailCallN() is used to add a Node to the end of the current Block and complete the function call, see sea of ​​nodes for details.

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