前言
前面已經看過許多滿基本的操作,這一篇就讓我們從 class 以及 prototype 的觀點來看 bytecode 吧!
prototype
先來個簡單的範例,宣告一個簡單的 class 然後有簡單的 method,因為要讓 filter 找到的關係,所以必須在很多地方都加上 find_me
prefix:
function find_me_test() {
function find_me_Person(name) {
this.name = name
}
find_me_Person.prototype.sayHello = function find_me_sayHello() {
console.log(this.name)
}
var p = new find_me_Person('yo')
p.sayHello()
}
find_me_test()
產生出來的結果:
[generated bytecode for function: find_me_test]
Parameter count 1
Frame size 32
0x262e8849deba @ 0 : 81 00 00 02 CreateClosure [0], [0], #2
0x262e8849debe @ 4 : 26 fb Star r0
21 E> 0x262e8849dec0 @ 6 : a5 StackCheck
103 S> 0x262e8849dec1 @ 7 : 28 fb 01 01 LdaNamedProperty r0, [1], [1]
0x262e8849dec5 @ 11 : 26 f9 Star r2
0x262e8849dec7 @ 13 : 81 02 03 01 CreateClosure [2], [3], #1
122 E> 0x262e8849decb @ 17 : 2d f9 03 04 StaNamedProperty r2, [3], [4]
196 S> 0x262e8849decf @ 21 : 12 04 LdaConstant [4]
0x262e8849ded1 @ 23 : 26 f8 Star r3
0x262e8849ded3 @ 25 : 25 fb Ldar r0
196 E> 0x262e8849ded5 @ 27 : 65 fb f8 01 06 Construct r0, r3-r3, [6]
0x262e8849deda @ 32 : 26 fa Star r1
225 S> 0x262e8849dedc @ 34 : 28 fa 03 08 LdaNamedProperty r1, [3], [8]
0x262e8849dee0 @ 38 : 26 f9 Star r2
225 E> 0x262e8849dee2 @ 40 : 58 f9 fa 0a CallProperty0 r2, r1, [10]
0x262e8849dee6 @ 44 : 0d LdaUndefined
236 S> 0x262e8849dee7 @ 45 : a9 Return
Constant pool (size = 5)
0x262e8849de21: [FixedArray] in OldSpace
- map: 0x262ee5d807b1 <Map>
- length: 5
0: 0x262e8849dd61 <SharedFunctionInfo find_me_Person>
1: 0x262ee5d84371 <String[#9]: prototype>
2: 0x262e8849ddb9 <SharedFunctionInfo find_me_sayHello>
3: 0x262e8849d909 <String[#8]: sayHello>
4: 0x262e8849dcf9 <String[#2]: yo>
Handler Table (size = 0)
[generated bytecode for function: find_me_Person]
Parameter count 2
Frame size 0
51 E> 0x262e8849e0c2 @ 0 : a5 StackCheck
64 S> 0x262e8849e0c3 @ 1 : 25 02 Ldar a0
74 E> 0x262e8849e0c5 @ 3 : 2d 03 00 00 StaNamedProperty <this>, [0], [0]
0x262e8849e0c9 @ 7 : 0d LdaUndefined
83 S> 0x262e8849e0ca @ 8 : a9 Return
Constant pool (size = 1)
0x262e8849e051: [FixedArray] in OldSpace
- map: 0x262ee5d807b1 <Map>
- length: 1
0: 0x262ee5d84059 <String[#4]: name>
Handler Table (size = 0)
[generated bytecode for function: find_me_sayHello]
Parameter count 1
Frame size 24
149 E> 0x262e8849e24a @ 0 : a5 StackCheck
158 S> 0x262e8849e24b @ 1 : 13 00 00 LdaGlobal [0], [0]
0x262e8849e24e @ 4 : 26 fa Star r1
166 E> 0x262e8849e250 @ 6 : 28 fa 01 02 LdaNamedProperty r1, [1], [2]
0x262e8849e254 @ 10 : 26 fb Star r0
175 E> 0x262e8849e256 @ 12 : 28 02 02 04 LdaNamedProperty <this>, [2], [4]
0x262e8849e25a @ 16 : 26 f9 Star r2
166 E> 0x262e8849e25c @ 18 : 59 fb fa f9 06 CallProperty1 r0, r1, r2, [6]
0x262e8849e261 @ 23 : 0d LdaUndefined
183 S> 0x262e8849e262 @ 24 : a9 Return
Constant pool (size = 3)
0x262e8849e1c9: [FixedArray] in OldSpace
- map: 0x262ee5d807b1 <Map>
- length: 3
0: 0x262e81e900e9 <String[#7]: console>
1: 0x262e81e8fbe9 <String[#3]: log>
2: 0x262ee5d84059 <String[#4]: name>
Handler Table (size = 0)
yo
產生出來的 bytecode 比想像中少滿多的,find_me_Person
跟find_me_sayHello
的部分應該可以不用多提了,程式碼滿少滿簡單的。主要是因為有 <this>
這個關鍵字,所以就只是利用了這個關鍵字而已。
其他部分我簡單翻譯了一下:
CreateClosure [0], [0], #2
Star r0 // r0 = find_me_Person
StackCheck
LdaNamedProperty r0, [1], [1]
Star r2 // r2 = find_me_Person.prototype
CreateClosure [2], [3], #1
StaNamedProperty r2, [3], [4] // r2.sayHello = find_me_sayHello
LdaConstant [4]
Star r3 // r3 = yo
Ldar r0
Construct r0, r3-r3, [6]
Star r1 // r1 = new find_me_Person(r3)
LdaNamedProperty r1, [3], [8]
Star r2 // r2 = r1.sayHello
CallProperty0 r2, r1, [10] // r1.sayHello()
LdaUndefined
Return
突然發現這樣拆成一步一步來,就瞬間清楚了很多。就是一連串的讀取 property 然後呼叫 function,唯一比較特別的地方就是 new
的時候會呼叫 Construct
,其他的部分沒有什麼太特別的地方。
class
接著我們來看看 class 的版本,功能都一樣,只差在從 class 的語法變成 prototype 而已:
function find_me_test() {
class find_me_Person {
constructor(name){
this.name = name
}
sayHello() {
console.log(this.name)
}
}
var p = new find_me_Person('yo')
p.sayHello()
}
find_me_test()
結果:
[generated bytecode for function: find_me_test]
Parameter count 1
Frame size 72
21 E> 0x1f61be31deea @ 0 : a5 StackCheck
0x1f61be31deeb @ 1 : 82 00 CreateBlockContext [0]
0x1f61be31deed @ 3 : 16 f8 PushContext r3
0x1f61be31deef @ 5 : 0f LdaTheHole
0x1f61be31def0 @ 6 : 26 f4 Star r7
0x1f61be31def2 @ 8 : 81 02 00 02 CreateClosure [2], [0], #2
0x1f61be31def6 @ 12 : 26 f7 Star r4
0x1f61be31def8 @ 14 : 12 01 LdaConstant [1]
0x1f61be31defa @ 16 : 26 f6 Star r5
0x1f61be31defc @ 18 : 81 03 01 02 CreateClosure [3], [1], #2
0x1f61be31df00 @ 22 : 26 f3 Star r8
0x1f61be31df02 @ 24 : 27 f7 f5 Mov r4, r6
0x1f61be31df05 @ 27 : 61 27 00 f6 04 CallRuntime [DefineClass], r5-r8
0x1f61be31df0a @ 32 : 26 f6 Star r5
0x1f61be31df0c @ 34 : 27 f5 fb Mov r6, r0
0x1f61be31df0f @ 37 : 17 f8 PopContext r3
0x1f61be31df11 @ 39 : 27 fb fa Mov r0, r1
156 S> 0x1f61be31df14 @ 42 : 12 04 LdaConstant [4]
0x1f61be31df16 @ 44 : 26 f7 Star r4
0x1f61be31df18 @ 46 : 25 fa Ldar r1
156 E> 0x1f61be31df1a @ 48 : 65 fa f7 01 02 Construct r1, r4-r4, [2]
0x1f61be31df1f @ 53 : 26 f9 Star r2
185 S> 0x1f61be31df21 @ 55 : 28 f9 05 04 LdaNamedProperty r2, [5], [4]
0x1f61be31df25 @ 59 : 26 f8 Star r3
185 E> 0x1f61be31df27 @ 61 : 58 f8 f9 06 CallProperty0 r3, r2, [6]
0x1f61be31df2b @ 65 : 0d LdaUndefined
196 S> 0x1f61be31df2c @ 66 : a9 Return
Constant pool (size = 6)
0x1f61be31de51: [FixedArray] in OldSpace
- map: 0x1f61ea3807b1 <Map>
- length: 6
0: 0x1f61be31dd69 <ScopeInfo BLOCK_SCOPE [3]>
1: 0x1f618190b089 <FixedArray[7]>
2: 0x1f61be31dd91 <SharedFunctionInfo find_me_Person>
3: 0x1f61be31dde9 <SharedFunctionInfo sayHello>
4: 0x1f61be31dd01 <String[#2]: yo>
5: 0x1f61be31d909 <String[#8]: sayHello>
Handler Table (size = 0)
[generated bytecode for function: find_me_Person]
Parameter count 2
Frame size 0
64 E> 0x1f61be31e0b2 @ 0 : a5 StackCheck
76 S> 0x1f61be31e0b3 @ 1 : 25 02 Ldar a0
86 E> 0x1f61be31e0b5 @ 3 : 2d 03 00 00 StaNamedProperty <this>, [0], [0]
0x1f61be31e0b9 @ 7 : 0d LdaUndefined
95 S> 0x1f61be31e0ba @ 8 : a9 Return
Constant pool (size = 1)
0x1f61be31e041: [FixedArray] in OldSpace
- map: 0x1f61ea3807b1 <Map>
- length: 1
0: 0x1f61ea384059 <String[#4]: name>
Handler Table (size = 0)
yo
長得滿複雜的 bytecode,而重點大概是這一行:CallRuntime [DefineClass], r5-r8
,總之就是把 function 載入以後呼叫這一行去定義 class。那如果把 class 的定義移到外面呢?
class find_me_Person {
constructor(name){
this.name = name
}
sayHello() {
console.log(this.name)
}
}
function find_me_test() {
var p = new find_me_Person('yo')
p.sayHello()
}
find_me_test()
結果:
[generated bytecode for function: find_me_test]
Parameter count 1
Frame size 24
140 E> 0x28bfd949dec2 @ 0 : a5 StackCheck
155 S> 0x28bfd949dec3 @ 1 : 1a 04 LdaCurrentContextSlot [4]
0x28bfd949dec5 @ 3 : aa 00 ThrowReferenceErrorIfHole [0]
0x28bfd949dec7 @ 5 : 26 fa Star r1
0x28bfd949dec9 @ 7 : 12 01 LdaConstant [1]
0x28bfd949decb @ 9 : 26 f9 Star r2
0x28bfd949decd @ 11 : 25 fa Ldar r1
155 E> 0x28bfd949decf @ 13 : 65 fa f9 01 00 Construct r1, r2-r2, [0]
0x28bfd949ded4 @ 18 : 26 fb Star r0
184 S> 0x28bfd949ded6 @ 20 : 28 fb 02 02 LdaNamedProperty r0, [2], [2]
0x28bfd949deda @ 24 : 26 fa Star r1
184 E> 0x28bfd949dedc @ 26 : 58 fa fb 04 CallProperty0 r1, r0, [4]
0x28bfd949dee0 @ 30 : 0d LdaUndefined
195 S> 0x28bfd949dee1 @ 31 : a9 Return
Constant pool (size = 3)
0x28bfd949de41: [FixedArray] in OldSpace
- map: 0x28bfd59807b1 <Map>
- length: 3
0: 0x28bfd949d8c9 <String[#14]: find_me_Person>
1: 0x28bfd949ddc1 <String[#2]: yo>
2: 0x28bfd949d8e9 <String[#8]: sayHello>
Handler Table (size = 0)
[generated bytecode for function: find_me_Person]
Parameter count 2
Frame size 0
36 E> 0x28bfd949e032 @ 0 : a5 StackCheck
48 S> 0x28bfd949e033 @ 1 : 25 02 Ldar a0
58 E> 0x28bfd949e035 @ 3 : 2d 03 00 00 StaNamedProperty <this>, [0], [0]
0x28bfd949e039 @ 7 : 0d LdaUndefined
67 S> 0x28bfd949e03a @ 8 : a9 Return
Constant pool (size = 1)
0x28bfd949dfc1: [FixedArray] in OldSpace
- map: 0x28bfd59807b1 <Map>
- length: 1
0: 0x28bfd5984059 <String[#4]: name>
Handler Table (size = 0)
yo
程式碼看起來乾淨許多,而且因為 find_me_Person
是宣告在 function 外面的緣故,所以要用 LdaCurrentContextSlot
從 context 裡面把這個東西給讀進來。
當我們把 class 宣告在外面的時候,雖然我們是寫 class find_me_Person
,不過若是你有注意到,它依然被當作一個 function 來看待。
不過我還是很好奇到底是如何處理 class 的宣告,因此我們可以把 filter 拿掉,把所有 bytecode 印出來:
[generated bytecode for function: ]
Parameter count 1
Frame size 72
0x2cf5f961dbe2 @ 0 : 12 00 LdaConstant [0]
0x2cf5f961dbe4 @ 2 : 26 f9 Star r2
0x2cf5f961dbe6 @ 4 : 61 36 01 f9 01 CallRuntime [NewScriptContext], r2-r2
0x2cf5f961dbeb @ 9 : 16 f9 PushContext r2
0x2cf5f961dbed @ 11 : 0f LdaTheHole
0x2cf5f961dbee @ 12 : 1d 04 StaCurrentContextSlot [4]
0x2cf5f961dbf0 @ 14 : 12 01 LdaConstant [1]
0x2cf5f961dbf2 @ 16 : 26 f8 Star r3
0x2cf5f961dbf4 @ 18 : 0b LdaZero
0x2cf5f961dbf5 @ 19 : 26 f7 Star r4
0x2cf5f961dbf7 @ 21 : 27 fe f6 Mov <closure>, r5
0x2cf5f961dbfa @ 24 : 61 2d 01 f8 03 CallRuntime [DeclareGlobals], r3-r5
0 E> 0x2cf5f961dbff @ 29 : a5 StackCheck
0x2cf5f961dc00 @ 30 : 82 02 CreateBlockContext [2]
0x2cf5f961dc02 @ 32 : 16 f8 PushContext r3
0x2cf5f961dc04 @ 34 : 0f LdaTheHole
0x2cf5f961dc05 @ 35 : 26 f4 Star r7
0x2cf5f961dc07 @ 37 : 81 04 03 00 CreateClosure [4], [3], #0
0x2cf5f961dc0b @ 41 : 26 f7 Star r4
0x2cf5f961dc0d @ 43 : 12 03 LdaConstant [3]
0x2cf5f961dc0f @ 45 : 26 f6 Star r5
0x2cf5f961dc11 @ 47 : 81 05 04 00 CreateClosure [5], [4], #0
0x2cf5f961dc15 @ 51 : 26 f3 Star r8
0x2cf5f961dc17 @ 53 : 27 f7 f5 Mov r4, r6
0x2cf5f961dc1a @ 56 : 61 27 00 f6 04 CallRuntime [DefineClass], r5-r8
0x2cf5f961dc1f @ 61 : 26 f6 Star r5
0x2cf5f961dc21 @ 63 : 27 f5 fb Mov r6, r0
0x2cf5f961dc24 @ 66 : 17 f8 PopContext r3
0x2cf5f961dc26 @ 68 : 25 fb Ldar r0
0 E> 0x2cf5f961dc28 @ 70 : 1d 04 StaCurrentContextSlot [4]
198 S> 0x2cf5f961dc2a @ 72 : 0d LdaUndefined
0x2cf5f961dc2b @ 73 : 26 f7 Star r4
0x2cf5f961dc2d @ 75 : 13 06 00 LdaGlobal [6], [0]
0x2cf5f961dc30 @ 78 : 26 f8 Star r3
198 E> 0x2cf5f961dc32 @ 80 : 5f f8 f7 01 CallNoFeedback r3, r4-r4
0x2cf5f961dc36 @ 84 : 26 fa Star r1
212 S> 0x2cf5f961dc38 @ 86 : a9 Return
Constant pool (size = 7)
0x2cf5f961db41: [FixedArray] in OldSpace
- map: 0x2cf5190807b1 <Map>
- length: 7
0: 0x2cf5f961d939 <ScopeInfo SCRIPT_SCOPE [9]>
1: 0x2cf5f961d9f9 <FixedArray[4]>
2: 0x2cf5f961d991 <ScopeInfo BLOCK_SCOPE [4]>
3: 0x2cf5a8b8b059 <FixedArray[7]>
4: 0x2cf5f961da81 <SharedFunctionInfo find_me_Person>
5: 0x2cf5f961dad9 <SharedFunctionInfo sayHello>
6: 0x2cf5f961d901 <String[#12]: find_me_test>
Handler Table (size = 0)
[generated bytecode for function: find_me_test]
Parameter count 1
Frame size 24
140 E> 0x2cf5f961dec2 @ 0 : a5 StackCheck
155 S> 0x2cf5f961dec3 @ 1 : 1a 04 LdaCurrentContextSlot [4]
0x2cf5f961dec5 @ 3 : aa 00 ThrowReferenceErrorIfHole [0]
0x2cf5f961dec7 @ 5 : 26 fa Star r1
0x2cf5f961dec9 @ 7 : 12 01 LdaConstant [1]
0x2cf5f961decb @ 9 : 26 f9 Star r2
0x2cf5f961decd @ 11 : 25 fa Ldar r1
155 E> 0x2cf5f961decf @ 13 : 65 fa f9 01 00 Construct r1, r2-r2, [0]
0x2cf5f961ded4 @ 18 : 26 fb Star r0
184 S> 0x2cf5f961ded6 @ 20 : 28 fb 02 02 LdaNamedProperty r0, [2], [2]
0x2cf5f961deda @ 24 : 26 fa Star r1
184 E> 0x2cf5f961dedc @ 26 : 58 fa fb 04 CallProperty0 r1, r0, [4]
0x2cf5f961dee0 @ 30 : 0d LdaUndefined
195 S> 0x2cf5f961dee1 @ 31 : a9 Return
Constant pool (size = 3)
0x2cf5f961de41: [FixedArray] in OldSpace
- map: 0x2cf5190807b1 <Map>
- length: 3
0: 0x2cf5f961d8c9 <String[#14]: find_me_Person>
1: 0x2cf5f961ddc1 <String[#2]: yo>
2: 0x2cf5f961d8e9 <String[#8]: sayHello>
Handler Table (size = 0)
[generated bytecode for function: find_me_Person]
Parameter count 2
Frame size 0
36 E> 0x2cf5f961e032 @ 0 : a5 StackCheck
48 S> 0x2cf5f961e033 @ 1 : 25 02 Ldar a0
58 E> 0x2cf5f961e035 @ 3 : 2d 03 00 00 StaNamedProperty <this>, [0], [0]
0x2cf5f961e039 @ 7 : 0d LdaUndefined
67 S> 0x2cf5f961e03a @ 8 : a9 Return
Constant pool (size = 1)
0x2cf5f961dfc1: [FixedArray] in OldSpace
- map: 0x2cf5190807b1 <Map>
- length: 1
0: 0x2cf519084059 <String[#4]: name>
Handler Table (size = 0)
[generated bytecode for function: sayHello]
Parameter count 1
Frame size 24
80 E> 0x2cf5f961e1c2 @ 0 : a5 StackCheck
89 S> 0x2cf5f961e1c3 @ 1 : 13 00 00 LdaGlobal [0], [0]
0x2cf5f961e1c6 @ 4 : 26 fa Star r1
97 E> 0x2cf5f961e1c8 @ 6 : 28 fa 01 02 LdaNamedProperty r1, [1], [2]
0x2cf5f961e1cc @ 10 : 26 fb Star r0
106 E> 0x2cf5f961e1ce @ 12 : 28 02 02 04 LdaNamedProperty <this>, [2], [4]
0x2cf5f961e1d2 @ 16 : 26 f9 Star r2
97 E> 0x2cf5f961e1d4 @ 18 : 59 fb fa f9 06 CallProperty1 r0, r1, r2, [6]
0x2cf5f961e1d9 @ 23 : 0d LdaUndefined
114 S> 0x2cf5f961e1da @ 24 : a9 Return
Constant pool (size = 3)
0x2cf5f961e141: [FixedArray] in OldSpace
- map: 0x2cf5190807b1 <Map>
- length: 3
0: 0x2cf5d1e100e9 <String[#7]: console>
1: 0x2cf5d1e0fbe9 <String[#3]: log>
2: 0x2cf519084059 <String[#4]: name>
Handler Table (size = 0)
yo
第一個沒有名字的 function bytecode 就是我們整個 script 了,可以看到裡面依然呼叫了 CallRuntime [DefineClass]
。雖然常說 class 只是 prototype 的語法糖,但是在 bytecode 的層面上,兩個依然是不同的東西(或許在 TurboFan 裡面會再做處理)。
不過只研究到這邊我還不甘心,明明可以再繼續往下深入研究看看,因此我們可以先獨立看 bytecode 建立 class 的那一段:
LdaTheHole
Star r7
CreateClosure [4], [3], #0
Star r4
LdaConstant [3]
Star r5
CreateClosure [5], [4], #0
Star r8
Mov r4, r6
CallRuntime [DefineClass], r5-r8
// r5: <FixedArray[7]>
// r6: <SharedFunctionInfo find_me_Person>
// r7: TheHole
// r8: <SharedFunctionInfo sayHello>
底下我把 r5-r8 的內容都整理出來了,會用這幾個參數去呼叫 DefineClass
。那這個 DefineClass
到底是什麼呢?可以直接去 V8 的 source code 裡面搜尋一下,發現被定義在 src/runtime/runtime-classes.cc 裡面:
RUNTIME_FUNCTION(Runtime_DefineClass) {
HandleScope scope(isolate);
DCHECK_LE(ClassBoilerplate::kFirstDynamicArgumentIndex, args.length());
CONVERT_ARG_HANDLE_CHECKED(ClassBoilerplate, class_boilerplate, 0);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, super_class, 2);
DCHECK_EQ(class_boilerplate->arguments_count(), args.length());
RETURN_RESULT_OR_FAILURE(
isolate,
DefineClass(isolate, class_boilerplate, super_class, constructor, args));
}
從這邊就可以很明顯看出來我們傳進去的四個參數是如何被處理,第一個 <FixedArray[7]>
是 class_boilerplate,應該是建立 class 時需要的一些資訊,可以先不管它。第二個參數 <SharedFunctionInfo find_me_Person>
就是 constructor,第三個 TheHole
是 super_class
,最後一個 <SharedFunctionInfo sayHello>
則是額外的參數 args。
而 DefineClass 的詳細內容,也可以在上面一點的地方找到:
MaybeHandle<Object> DefineClass(Isolate* isolate,
Handle<ClassBoilerplate> class_boilerplate,
Handle<Object> super_class,
Handle<JSFunction> constructor,
Arguments& args) {
Handle<Object> prototype_parent;
Handle<Object> constructor_parent;
if (super_class->IsTheHole(isolate)) {
prototype_parent = isolate->initial_object_prototype();
} else {
if (super_class->IsNull(isolate)) {
prototype_parent = isolate->factory()->null_value();
} else if (super_class->IsConstructor()) {
DCHECK(!super_class->IsJSFunction() ||
!IsResumableFunction(
Handle<JSFunction>::cast(super_class)->shared()->kind()));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, prototype_parent,
Runtime::GetObjectProperty(isolate, super_class,
isolate->factory()->prototype_string()),
Object);
if (!prototype_parent->IsNull(isolate) &&
!prototype_parent->IsJSReceiver()) {
THROW_NEW_ERROR(
isolate, NewTypeError(MessageTemplate::kPrototypeParentNotAnObject,
prototype_parent),
Object);
}
// Create new handle to avoid |constructor_parent| corruption because of
// |super_class| handle value overwriting via storing to
// args[ClassBoilerplate::kPrototypeArgumentIndex] below.
constructor_parent = handle(*super_class, isolate);
} else {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kExtendsValueNotConstructor,
super_class),
Object);
}
}
Handle<JSObject> prototype = CreateClassPrototype(isolate);
DCHECK_EQ(*constructor, args[ClassBoilerplate::kConstructorArgumentIndex]);
args.set_at(ClassBoilerplate::kPrototypeArgumentIndex, *prototype);
if (!InitClassConstructor(isolate, class_boilerplate, constructor_parent,
constructor, args) ||
!InitClassPrototype(isolate, class_boilerplate, prototype,
prototype_parent, constructor, args)) {
DCHECK(isolate->has_pending_exception());
return MaybeHandle<Object>();
}
if (FLAG_trace_maps) {
LOG(isolate,
MapEvent("InitialMap", Map(), constructor->map(),
"init class constructor", constructor->shared()->DebugName()));
LOG(isolate, MapEvent("InitialMap", Map(), prototype->map(),
"init class prototype"));
}
return prototype;
}
若是把一些不會進入的分支去掉,就會變成這樣:
MaybeHandle<Object> DefineClass(Isolate* isolate,
Handle<ClassBoilerplate> class_boilerplate,
Handle<Object> super_class,
Handle<JSFunction> constructor,
Arguments& args) {
Handle<Object> prototype_parent;
Handle<Object> constructor_parent;
// 沒有 super class 的話,就把 prototype parent 設成 Object.prototype
if (super_class->IsTheHole(isolate)) {
prototype_parent = isolate->initial_object_prototype();
}
Handle<JSObject> prototype = CreateClassPrototype(isolate);
DCHECK_EQ(*constructor, args[ClassBoilerplate::kConstructorArgumentIndex]);
args.set_at(ClassBoilerplate::kPrototypeArgumentIndex, *prototype);
// 初始化 ClassConstructor 與 ClassPrototype
if (!InitClassConstructor(isolate, class_boilerplate, constructor_parent,
constructor, args) ||
!InitClassPrototype(isolate, class_boilerplate, prototype,
prototype_parent, constructor, args)) {
DCHECK(isolate->has_pending_exception());
return MaybeHandle<Object>();
}
return prototype;
}
總而言之呢,有關 class 的所有東西都會在這邊被處理好,若是想要深入細節的話可以再往下研究,但是我功力有限,追到這邊就差不多了...於是只好就此打住,只要知道是在這邊被處理的就行了。