- 原文地址:Tracing Patterns that Might Hinder Performance
- 原文作者:Jakub Rożek
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:薛定諤的貓
- 校對者:AceLeeWinnie、HydeSong
找出可能影響效能的程式碼(模式)
現在你很可能會遇到不止一個響應遲鈍的 app 或載入緩慢的頁面。已經是 2017 年了,我們當然希望一切變的很快,但我們仍然會體驗到惱人的延時。怎麼會這樣呢?難道我們的網路連線不是逐年變快的麼?我們的瀏覽器效能不是也變的更好?我們將在下文中討論這些。
事實上,瀏覽器和引擎越來越快,新特性也在不停的增加,一些過時的特性也在被廢棄。網站和 app 也是如此。同時,它們也更大、更重了,因此即使瀏覽器和硬體越來越好,我們也需要考慮效能 -- 至少在某種程度上。我們來看看如何找出常見的效能陷阱,來改善網站和 app 的效能,但在此之前,我們先來看一下概覽。
優化
關於流水線(pipeline)我可以寫一本書,但本文中我還是想關注有助於優化過程的關鍵點。我會闡述一些會極大影響效能的常見錯誤。為了簡潔,我不會討論 parsing、AST、機器碼生成、GC(垃圾收集)、反饋收集、OSR(on-stack replacement) -- 別擔心,我會在未來的文章中解釋它們。
舊版本
舊版本使用的基準編譯器(baseline compiler)和優化編譯器 Crankshaft,已經在 Chrome M59 中被廢棄。
基準編譯器並不會進行任何優化,它僅僅是快速編譯程式碼,然後使其被執行。需要注意的是,生成優化程式碼嚴重依賴於假設,它反過來又需要假設型別反饋,因此需要首先執行基準編譯器。
一旦某個函式被頻繁執行(hot,通常引擎認為它值得優化),Crankshaft 就發揮(優化)作用了。它生成的程式碼效能非常好,接近於 Java。這種優化方式是業內第一,它帶來了巨大的效能提升。因此 JS 才能有較好的效能,前端開發者也能夠用它來建立複雜的 web 應用。
新版本
隨著 web 的發展,新的框架誕生,規範也在更新升級,在 Crankshaft 基礎上擴充套件變得非常困難。有的程式碼不會被 Crankshaft 優化,比如操作 arguments 物件的某些方法(安全的方式有 unmonkey-patched Function.prototype.apply、length屬性、未越界的下標),try-catch 語句和其它。幸運的是,新的架構 Ignition 和 TurboFan 可以解決其中一些效能瓶頸。現在,有一些模式可以得到更好的優化。如前文所述,優化也是有成本的,需要耗費一些資源(在低端的移動裝置上資源可能很有限)。但在多數情況下,你還是希望你的函式能夠得到優化。
引入 TurboFan 的原因有:
- 提供統一的程式碼生成架構
- 減少 V8 的移植/維護成本
- 去除效能陷阱
- 新特性實驗更容易 (i.e. changes to load/store ICs, bootstrapping an interpreter)
當然,前提是不犧牲效能。生成位元組碼相對很快,但解釋位元組碼可能比執行優化後的程式碼慢 100 倍。它顯然取決於編譯器的複雜度。基準編譯器的目的從來就不是生成很快的程式碼,但將執行時間考慮在內的話,它仍然比 Ignition 快(不是快很多,在某些場景下快 3-4 倍)。TurboFan 的目的是取代上一代的優化編譯器 -- Crankshaft。
我們需要優化嗎?
不一定。
如果一個函式只會執行一兩次,並不值得優化。但如果可能執行多次,值型別和物件結構固定的話,你就很可能需要考慮優化你的程式碼了。我們可能不會意識到規範中的一些異常。而引擎需要處理(這些異常),通常很難理解。舉例:讀取屬性時,引擎需要考慮到各種邊界情況,通常在真實場景下不會發生。為什麼會這樣呢?有時是為了向後相容,有時是其它原因 -- 每種情況都有不同。如果發現多餘的操作,我們根本就不需要執行!優化引擎會發現這樣的場景,嘗試去除掉多餘的操作。去除後的函式就稱為 stub。
由於 JS 是動態型別語言,我們需要做很多假設。所以最好讓屬性保持單態 -- 換句話說,應該只有一個路徑。一旦假設不匹配,就會發生反優化(deopt),優化過的函式也就不再生效。這無疑是我們要避免的。每次優化都是或多或少需要耗費資源,再次優化時就需要考慮到之前的情況,以避免屬性不是單態。只要不多於 4 條路徑,它就會保持多型(polymorphic)。多於 4 條路徑的話,稱為 megamorphic。
開始之前
只有傳遞了引數 --allow-natives-syntax
, 才可以使用 %
為字首的函式。
一般情況下,你不應該使用它們。在 V8 的原始碼(src/runtime)中可以找到它們的定義。所有會引起反優化的原因(bailout/deopt reasons):cs.chromium.org/chromium/sr…)
傳遞引數 --trace-opt
,可以檢視你的函式是否被優化;傳遞 --trace-deopt
,檢視已優化的函式出現反優化的情況。
舉例
例子 1
先來看一個非常簡單的例子。
首先我們定義一個計算加法的函式 add,它接收 2 個加數,返回它們相加後的結果。很簡單,對吧?繼續看後面的程式碼:
function add(a, b) {
return a + b;
}
// 1. IC feedback unitialized
add(23, 44);
// 2. now it's pre-monomorphic
add(2, 88);
// let’s optimize 'add' on its next call
%OptimizeFunctionOnNextCall(add);
add(2, 7); // now we call our optimized function, feedback has been collected, let's see whether we can retrieve some deopts reason.複製程式碼
d8 --trace-deopt --print-opt-code --allow-natives-syntax --code-comments --turbo add.js複製程式碼
如果執行的 V8 版本低於 5.9,必須顯式傳遞 --turbo
引數,以呼叫 TurboFan。
執行上面的命令,會得到以下類似輸出:
--- Raw source ---
(a, b) {
return a + b;
}
--- Optimized code ---
optimization_id = 0
source_position = 12
kind = OPTIMIZED_FUNCTION
name = add
stack_slots = 4
compiler = turbofan
Instructions (size = 151)
-- <add.js:1:13> --
-- B0 start (construct frame) --
0x19b11ce84220 0 55 push rbp
0x19b11ce84221 1 4889e5 REX.W movq rbp,rsp
0x19b11ce84224 4 56 push rsi
0x19b11ce84225 5 57 push rdi
0x19b11ce84226 6 493ba5700c0000 REX.W cmpq rsp,[r13+0xc70]
0x19b11ce8422d 13 0f863d000000 jna 80 (0x19b11ce84270)
-- B2 start --
-- B3 start (deconstruct frame) --
-- <add.js:2:12> --
0x19b11ce84233 19 488b4518 REX.W movq rax,[rbp+0x18]
0x19b11ce84237 23 a801 test al,0x1
0x19b11ce84239 25 0f8548000000 jnz 103 (0x19b11ce84287)
0x19b11ce8423f 31 488b5d10 REX.W movq rbx,[rbp+0x10]
0x19b11ce84243 35 f6c301 testb rbx,0x1
0x19b11ce84246 38 0f8540000000 jnz 108 (0x19b11ce8428c)
0x19b11ce8424c 44 488bd3 REX.W movq rdx,rbx
0x19b11ce8424f 47 48c1ea20 REX.W shrq rdx, 32
0x19b11ce84253 51 488bc8 REX.W movq rcx,rax
0x19b11ce84256 54 48c1e920 REX.W shrq rcx, 32
0x19b11ce8425a 58 03d1 addl rdx,rcx
0x19b11ce8425c 60 0f802f000000 jo 113 (0x19b11ce84291)
-- <add.js:3:1> --
0x19b11ce84262 66 48c1e220 REX.W shlq rdx, 32
0x19b11ce84266 70 488bc2 REX.W movq rax,rdx
0x19b11ce84269 73 488be5 REX.W movq rsp,rbp
0x19b11ce8426c 76 5d pop rbp
0x19b11ce8426d 77 c21800 ret 0x18
-- B4 start (no frame) --
-- B1 start (deferred) --
-- <add.js:1:13> --
0x19b11ce84270 80 48bb00d66b0201000000 REX.W movq rbx,0x1026bd600 ;; external reference (Runtime::StackGuard)
0x19b11ce8427a 90 33c0 xorl rax,rax
0x19b11ce8427c 92 488b75f8 REX.W movq rsi,[rbp-0x8]
0x19b11ce84280 96 e81bffdfff call 0x19b11cc841a0 ;; code: STUB, CEntryStub, minor: 8
0x19b11ce84285 101 ebac jmp 19 (0x19b11ce84233)
0x19b11ce84287 103 e874fdc7ff call 0x19b11cb04000 ;; debug: deopt position, script offset '32'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'not a Smi'
;; debug: deopt index 0
;; deoptimization bailout 0
0x19b11ce8428c 108 e879fdc7ff call 0x19b11cb0400a ;; debug: deopt position, script offset '32'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'not a Smi'
;; debug: deopt index 1
;; deoptimization bailout 1
0x19b11ce84291 113 e87efdc7ff call 0x19b11cb04014 ;; debug: deopt position, script offset '32'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'overflow'
;; debug: deopt index 2
;; deoptimization bailout 2
0x19b11ce84296 118 90 nop
0x19b11ce84297 119 90 nop
0x19b11ce84298 120 90 nop
0x19b11ce84299 121 90 nop
0x19b11ce8429a 122 90 nop
0x19b11ce8429b 123 90 nop
0x19b11ce8429c 124 90 nop
0x19b11ce8429d 125 90 nop
0x19b11ce8429e 126 90 nop
0x19b11ce8429f 127 90 nop
0x19b11ce842a0 128 90 nop
0x19b11ce842a1 129 90 nop
0x19b11ce842a2 130 90 nop
0x19b11ce842a3 131 90 nop
;;; Safepoint table.
Source positions:
pc offset position
0 12
19 32
66 37
80 12
Inlined functions (count = 0)
Deoptimization Input Data (deopt points = 4)
index ast id argc pc
0 0 0 -1
1 0 0 -1
2 0 0 -1
3 0 0 101
Safepoints (size = 19)
0x19b11ce84285 101 0000 (sp -> fp) 3
RelocInfo (size = 169)
0x19b11ce84220 comment (-- <add.js:1:13> --)
0x19b11ce84220 comment (-- B0 start (construct frame) --)
0x19b11ce84233 comment (-- B2 start --)
0x19b11ce84233 comment (-- B3 start (deconstruct frame) --)
0x19b11ce84233 comment (-- <add.js:2:12> --)
0x19b11ce84262 comment (-- <add.js:3:1> --)
0x19b11ce84270 comment (-- B4 start (no frame) --)
0x19b11ce84270 comment (-- B1 start (deferred) --)
0x19b11ce84270 comment (-- <add.js:1:13> --)
0x19b11ce84272 external reference (Runtime::StackGuard) (0x1026bd600)
0x19b11ce84281 code target (STUB) (0x19b11cc841a0)
0x19b11ce84287 deopt script offset (32)
0x19b11ce84287 deopt inlining id (-1)
0x19b11ce84287 deopt reason (not a Smi)
0x19b11ce84287 deopt index
0x19b11ce84288 runtime entry (deoptimization bailout 0)
0x19b11ce8428c deopt script offset (32)
0x19b11ce8428c deopt inlining id (-1)
0x19b11ce8428c deopt reason (not a Smi)
0x19b11ce8428c deopt index
0x19b11ce8428d runtime entry (deoptimization bailout 1)
0x19b11ce84291 deopt script offset (32)
0x19b11ce84291 deopt inlining id (-1)
0x19b11ce84291 deopt reason (overflow)
0x19b11ce84291 deopt index
0x19b11ce84292 runtime entry (deoptimization bailout 2)
0x19b11ce842a4 comment (;;; Safepoint table.)
--- End code ---複製程式碼
如你所見,這裡有至少 3 種不同情況,我們的函式(add)出現反優化(deopt)。
如果將 lazy deopt 考慮在內,會發現更多,但我們還是關注 eager deopt。
順便講一句,此時這裡有三種型別的反優化:eager、lazy、soft。
可能看起來有些難懂可怕,別擔心,你很快就會明白的!
從第一個反優化開始:
// ;; debug: deopt index 0複製程式碼
原因是:“not a Smi”。如果已經聽說過 Smi,你就可以直接跳過這一段了。
Smi 本質上就是小整數的縮寫(small integer)。它與 V8 中其它物件有很多不同。在 V8 的原始碼中位於 objects.h: chromium.googlesource.com/v8/v8.git/+…
你會發現,Smi不是堆物件。
堆物件,指所有分配於堆上的變數的超類。我們(前端開發者)能夠存取的變數本質上是 JSReceiver 的子類。
比如,我們經常用的陣列(JSArray)和函式(JSFunction)就繼承自這個類(JSReceiver)。
查詢 Javascript schemes 標籤的相關資訊,你會發現 Smi 不同於它們。
在 64 位機器上,Smi 是 32 位有符號整數;而在 32 位機器上,它是 31 位有符號整數。
如果傳給它這個這個範圍之外的值,這個函式就會發生反優化。
比如:
add(2 ** 31, 0)複製程式碼
因為 2**31 大於 2**31 - 1,所以會發生反優化。
當然,如果傳給它數字之外的值,比如字串、陣列或其它型別的值,也會發生反優化。例如:
add([], 0);
add({ foo: 'bar' }, 2);複製程式碼
接下來看第二個反優化的情況。
;; debug: deopt index 1複製程式碼
與上面的情況類似,唯一的區別是它檢查的是第二個引數 b
。
add(0, 2 ** 31) // would cause a deopt as well.複製程式碼
好,來看最後一個情況:
;; debug: deopt index 2複製程式碼
'Overlow'
你已經明白 Smi 是什麼了,這兒就很容易理解了。
根本原因是,引數檢查通過了,但函式的返回值卻不是 Smi。例子:
add(1, 2 ** 31 - 1); // returned value higher than 2 ** 31 - 1複製程式碼
例子2
我們繼續來宣告一個看起來相同的函式。
function concat(a, b) {
return a + b;
}
concat('netguru', ' .com');
concat('p0lip loves ', 'v8');
%OptimizeFunctionOnNextCall(concat);
concat('optimized now! ', 'wooohooo');複製程式碼
看起來一樣的函式,結果卻不相同。為什麼呢?同樣的函式檢查卻不相同?
不!這些檢查是型別相關的,也就是說 -- 引擎並不會提前做出假設,它僅在函式執行過程中做出調整和優化。因此,即使這兩個函式看起來一樣,但是路徑(path)卻不相同。
這個例子中,我們的函式是由 Crankshaft 優化。
--- Raw source ---
(a, b) {
return a + b;
}
--- Optimized code ---
optimization_id = 0
source_position = 15
kind = OPTIMIZED_FUNCTION
name = concat
stack_slots = 5
compiler = crankshaft
Instructions (size = 194)
0x3ba8de705000 0 55 push rbp
0x3ba8de705001 1 4889e5 REX.W movq rbp,rsp
0x3ba8de705004 4 56 push rsi
0x3ba8de705005 5 57 push rdi
0x3ba8de705006 6 4883ec08 REX.W subq rsp,0x8
0x3ba8de70500a 10 50 push rax
0x3ba8de70500b 11 b801000000 movl rax,0x1
0x3ba8de705010 16 49baefdeefbeaddeefbe REX.W movq r10,0xbeefdeadbeefdeef
0x3ba8de70501a 26 4c8914c4 REX.W movq [rsp+rax*8],r10
0x3ba8de70501e 30 ffc8 decl rax
0x3ba8de705020 32 75f8 jnz 26 (0x3ba8de70501a)
0x3ba8de705022 34 58 pop rax
;;; <@0,#0> -------------------- B0 --------------------
;;; <@8,#5> prologue
;;; Prologue begin
;;; Prologue end
;;; <@12,#7> -------------------- B1 --------------------
;;; <@14,#8> context
0x3ba8de705023 35 488b45f8 REX.W movq rax,[rbp-0x8]
;;; <@15,#8> gap
0x3ba8de705027 39 488945e8 REX.W movq [rbp-0x18],rax
;;; <@18,#12> -------------------- B2 --------------------
;;; <@19,#12> gap
0x3ba8de70502b 43 488bf0 REX.W movq rsi,rax
;;; <@20,#14> stack-check
0x3ba8de70502e 46 493ba5700c0000 REX.W cmpq rsp,[r13+0xc70]
0x3ba8de705035 53 7305 jnc 60 (0x3ba8de70503c)
0x3ba8de705037 55 e86426efff call StackCheck (0x3ba8de5f76a0) ;; code: BUILTIN
;;; <@22,#14> lazy-bailout
;;; <@23,#14> gap
0x3ba8de70503c 60 488b5d18 REX.W movq rbx,[rbp+0x18]
;;; <@24,#16> check-non-smi
0x3ba8de705040 64 f6c301 testb rbx,0x1
0x3ba8de705043 67 0f8447000000 jz 144 (0x3ba8de705090)
;;; <@26,#17> check-instance-type
0x3ba8de705049 73 4c8b53ff REX.W movq r10,[rbx-0x1]
0x3ba8de70504d 77 41f6420b80 testb [r10+0xb],0x80
0x3ba8de705052 82 0f853d000000 jnz 149 (0x3ba8de705095)
;;; <@27,#17> gap
0x3ba8de705058 88 488b4d10 REX.W movq rcx,[rbp+0x10]
;;; <@28,#18> check-non-smi
0x3ba8de70505c 92 f6c101 testb rcx,0x1
0x3ba8de70505f 95 0f8435000000 jz 154 (0x3ba8de70509a)
;;; <@30,#19> check-instance-type
0x3ba8de705065 101 4c8b51ff REX.W movq r10,[rcx-0x1]
0x3ba8de705069 105 41f6420b80 testb [r10+0xb],0x80
0x3ba8de70506e 110 0f852b000000 jnz 159 (0x3ba8de70509f)
;;; <@31,#19> gap
0x3ba8de705074 116 488b75e8 REX.W movq rsi,[rbp-0x18]
0x3ba8de705078 120 488bd3 REX.W movq rdx,rbx
0x3ba8de70507b 123 488bc1 REX.W movq rax,rcx
;;; <@32,#20> string-add
0x3ba8de70507e 126 e8fd63e2ff call 0x3ba8de52b480 ;; code: STUB, StringAddStub, minor: 0
;;; <@34,#20> lazy-bailout
;;; <@36,#22> return
0x3ba8de705083 131 488be5 REX.W movq rsp,rbp
0x3ba8de705086 134 5d pop rbp
0x3ba8de705087 135 c21800 ret 0x18
0x3ba8de70508a 138 660f1f440000 nop
;;; -------------------- Jump table --------------------
0x3ba8de705090 144 e875efc7ff call 0x3ba8de38400a ;; debug: deopt position, script offset '35'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'Smi'
;; debug: deopt index 1
;; deoptimization bailout 1
0x3ba8de705095 149 e87aefc7ff call 0x3ba8de384014 ;; debug: deopt position, script offset '35'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'wrong instance type'
;; debug: deopt index 2
;; deoptimization bailout 2
0x3ba8de70509a 154 e87fefc7ff call 0x3ba8de38401e ;; debug: deopt position, script offset '35'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'Smi'
;; debug: deopt index 3
;; deoptimization bailout 3
0x3ba8de70509f 159 e884efc7ff call 0x3ba8de384028 ;; debug: deopt position, script offset '35'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'wrong instance type'
;; debug: deopt index 4
;; deoptimization bailout 4
;;; Safepoint table.
Source positions:
pc offset position
64 35
73 35
73 35
88 35
92 35
101 35
101 35
116 35
126 35
131 35
131 35
131 35
131 35
138 35
Inlined functions (count = 0)
Deoptimization Input Data (deopt points = 6)
index ast id argc pc
0 4 0 60
1 4 0 -1
2 4 0 -1
3 4 0 -1
4 4 0 -1
5 4 0 131
Safepoints (size = 30)
0x3ba8de70503c 60 10000 (sp -> fp) 0
0x3ba8de705083 131 10000 (sp -> fp) 5
RelocInfo (size = 320)
0x3ba8de705023 comment (;;; <@0,#0> -------------------- B0 --------------------)
0x3ba8de705023 comment (;;; <@8,#5> prologue)
0x3ba8de705023 comment (;;; Prologue begin)
0x3ba8de705023 comment (;;; Prologue end)
0x3ba8de705023 comment (;;; <@12,#7> -------------------- B1 --------------------)
0x3ba8de705023 comment (;;; <@14,#8> context)
0x3ba8de705027 comment (;;; <@15,#8> gap)
0x3ba8de70502b comment (;;; <@18,#12> -------------------- B2 --------------------)
0x3ba8de70502b comment (;;; <@19,#12> gap)
0x3ba8de70502e comment (;;; <@20,#14> stack-check)
0x3ba8de705038 code target (BUILTIN) (0x3ba8de5f76a0)
0x3ba8de70503c comment (;;; <@22,#14> lazy-bailout)
0x3ba8de70503c comment (;;; <@23,#14> gap)
0x3ba8de705040 comment (;;; <@24,#16> check-non-smi)
0x3ba8de705049 comment (;;; <@26,#17> check-instance-type)
0x3ba8de705058 comment (;;; <@27,#17> gap)
0x3ba8de70505c comment (;;; <@28,#18> check-non-smi)
0x3ba8de705065 comment (;;; <@30,#19> check-instance-type)
0x3ba8de705074 comment (;;; <@31,#19> gap)
0x3ba8de70507e comment (;;; <@32,#20> string-add)
0x3ba8de70507f code target (STUB) (0x3ba8de52b480)
0x3ba8de705083 comment (;;; <@34,#20> lazy-bailout)
0x3ba8de705083 comment (;;; <@36,#22> return)
0x3ba8de705090 comment (;;; -------------------- Jump table --------------------)
0x3ba8de705090 deopt script offset (35)
0x3ba8de705090 deopt inlining id (-1)
0x3ba8de705090 deopt reason (Smi)
0x3ba8de705090 deopt index
0x3ba8de705091 runtime entry (deoptimization bailout 1)
0x3ba8de705095 deopt script offset (35)
0x3ba8de705095 deopt inlining id (-1)
0x3ba8de705095 deopt reason (wrong instance type)
0x3ba8de705095 deopt index
0x3ba8de705096 runtime entry (deoptimization bailout 2)
0x3ba8de70509a deopt script offset (35)
0x3ba8de70509a deopt inlining id (-1)
0x3ba8de70509a deopt reason (Smi)
0x3ba8de70509a deopt index
0x3ba8de70509b runtime entry (deoptimization bailout 3)
0x3ba8de70509f deopt script offset (35)
0x3ba8de70509f deopt inlining id (-1)
0x3ba8de70509f deopt reason (wrong instance type)
0x3ba8de70509f deopt index
0x3ba8de7050a0 runtime entry (deoptimization bailout 4)
0x3ba8de7050a4 comment (;;; Safepoint table.)
--- End code ---複製程式碼
;; debug: deopt index 1複製程式碼
一旦你不傳給它 Smi,而是傳遞一個堆物件時,就會發生反優化。事實上,它與 “Not a Smi” 相反,所以我不會詳細解釋它。它僅僅檢查了引數“a”?
;; debug: deopt index 2複製程式碼
'wrong instance type' – 有趣!目前為止,我們還沒見過它!
很容易猜到,這次檢查失敗是因為你沒有傳遞 string,或者沒有傳值。
concat([], 'd');
concat(new String('d'), 'xx');複製程式碼
最後 2 個原因和上面相同,但是檢查第 2 個引數 “b”。
例子 3
我們來看一個稍微不同的例子。
function elemAt(arr, index) {
return arr[index];
}
elemAt([2, 3, 4], 0);
elemAt([9, 4, 1], 2);
%OptimizeFunctionOnNextCall(elemAt);
elemAt([2], 0);複製程式碼
d8 --trace-deopt --code-comments --print-opt-code --allow-natives-syntax --turbo elem-at.js複製程式碼
--- Raw source ---
(arr, index) {
return arr[index];
}
--- Optimized code ---
optimization_id = 0
source_position = 15
kind = OPTIMIZED_FUNCTION
name = elemAt
stack_slots = 6
compiler = turbofan
Instructions (size = 327)
-- <elemAt.js:1:16> --
-- B0 start (construct frame) --
0x1aa58ba04220 0 55 push rbp
0x1aa58ba04221 1 4889e5 REX.W movq rbp,rsp
0x1aa58ba04224 4 56 push rsi
0x1aa58ba04225 5 57 push rdi
0x1aa58ba04226 6 4883ec10 REX.W subq rsp,0x10
0x1aa58ba0422a 10 493ba5700c0000 REX.W cmpq rsp,[r13+0xc70]
0x1aa58ba04231 17 0f8675000000 jna 140 (0x1aa58ba042ac)
-- B2 start --
-- B3 start --
-- <elemAt.js:2:14> --
0x1aa58ba04237 23 488b4518 REX.W movq rax,[rbp+0x18]
0x1aa58ba0423b 27 a801 test al,0x1
0x1aa58ba0423d 29 0f84e3000000 jz 262 (0x1aa58ba04326)
0x1aa58ba04243 35 48bb793c503e5d080000 REX.W movq rbx,0x85d3e503c79 ;; object: 0x85d3e503c79 <Map(FAST_SMI_ELEMENTS)>
0x1aa58ba0424d 45 483958ff REX.W cmpq [rax-0x1],rbx
0x1aa58ba04251 49 0f85d4000000 jnz 267 (0x1aa58ba0432b)
0x1aa58ba04257 55 488b580f REX.W movq rbx,[rax+0xf]
0x1aa58ba0425b 59 488b5017 REX.W movq rdx,[rax+0x17]
0x1aa58ba0425f 63 488b4d10 REX.W movq rcx,[rbp+0x10]
0x1aa58ba04263 67 f6c101 testb rcx,0x1
0x1aa58ba04266 70 0f855a000000 jnz 166 (0x1aa58ba042c6)
-- B8 start --
0x1aa58ba0426c 76 488bf1 REX.W movq rsi,rcx
0x1aa58ba0426f 79 48c1ee20 REX.W shrq rsi, 32
-- B9 start (deconstruct frame) --
0x1aa58ba04273 83 48c1ea20 REX.W shrq rdx, 32
0x1aa58ba04277 87 8bfe movl rdi,rsi
0x1aa58ba04279 89 49ba0000000001000000 REX.W movq r10,0x100000000
0x1aa58ba04283 99 4c3bd7 REX.W cmpq r10,rdi
0x1aa58ba04286 102 7310 jnc 120 (0x1aa58ba04298)
Abort message:
32 bit value in register is not zero-extended
0x1aa58ba04288 104 48ba0000000001000000 REX.W movq rdx,0x100000000
0x1aa58ba04292 114 e889fedfff call Abort (0x1aa58b804120) ;; code: BUILTIN
0x1aa58ba04297 119 cc int3l
0x1aa58ba04298 120 3bf2 cmpl rsi,rdx
0x1aa58ba0429a 122 0f8390000000 jnc 272 (0x1aa58ba04330)
0x1aa58ba042a0 128 488b44fb0f REX.W movq rax,[rbx+rdi*8+0xf]
-- <elemAt.js:3:1> --
0x1aa58ba042a5 133 488be5 REX.W movq rsp,rbp
0x1aa58ba042a8 136 5d pop rbp
0x1aa58ba042a9 137 c21800 ret 0x18
-- B10 start (no frame) --
-- B1 start (deferred) --
-- <elemAt.js:1:16> --
0x1aa58ba042ac 140 48bb00f6900701000000 REX.W movq rbx,0x10790f600 ;; external reference (Runtime::StackGuard)
0x1aa58ba042b6 150 33c0 xorl rax,rax
0x1aa58ba042b8 152 488b75f8 REX.W movq rsi,[rbp-0x8]
0x1aa58ba042bc 156 e8dffedfff call 0x1aa58b8041a0 ;; code: STUB, CEntryStub, minor: 8
0x1aa58ba042c1 161 e971ffffff jmp 23 (0x1aa58ba04237)
-- B4 start (deferred) --
-- <elemAt.js:2:14> --
0x1aa58ba042c6 166 488b41ff REX.W movq rax,[rcx-0x1]
0x1aa58ba042ca 170 49394550 REX.W cmpq [r13+0x50],rax
0x1aa58ba042ce 174 0f8561000000 jnz 277 (0x1aa58ba04335)
0x1aa58ba042d4 180 c5fb104107 vmovsd xmm0,[rcx+0x7]
0x1aa58ba042d9 185 c5fb2cf0 vcvttsd2si rsi,xmm0
0x1aa58ba042dd 189 c5f157c9 vxorpd xmm1,xmm1,xmm1
0x1aa58ba042e1 193 c5f32ace vcvtlsi2sd xmm1,xmm1,rsi
0x1aa58ba042e5 197 c5f92ec8 vucomisd xmm1,xmm0
0x1aa58ba042e9 201 0f8a4b000000 jpe 282 (0x1aa58ba0433a)
0x1aa58ba042ef 207 0f8545000000 jnz 282 (0x1aa58ba0433a)
0x1aa58ba042f5 213 48895de8 REX.W movq [rbp-0x18],rbx
0x1aa58ba042f9 217 488955e0 REX.W movq [rbp-0x20],rdx
0x1aa58ba042fd 221 83fe00 cmpl rsi,0x0
0x1aa58ba04300 224 0f850f000000 jnz 245 (0x1aa58ba04315)
-- B5 start (deferred) --
-- B6 start (deferred) --
0x1aa58ba04306 230 660f3a16c001 pextrd rax,xmm0,1
0x1aa58ba0430c 236 83f800 cmpl rax,0x0
0x1aa58ba0430f 239 0f8c2a000000 jl 287 (0x1aa58ba0433f)
-- B7 start (deferred) --
0x1aa58ba04315 245 488b5de8 REX.W movq rbx,[rbp-0x18]
0x1aa58ba04319 249 488b4518 REX.W movq rax,[rbp+0x18]
0x1aa58ba0431d 253 488b55e0 REX.W movq rdx,[rbp-0x20]
0x1aa58ba04321 257 e94dffffff jmp 83 (0x1aa58ba04273)
0x1aa58ba04326 262 e8d5fcc7ff call 0x1aa58b684000 ;; debug: deopt position, script offset '43'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'Smi'
;; debug: deopt index 0
;; deoptimization bailout 0
0x1aa58ba0432b 267 e8dafcc7ff call 0x1aa58b68400a ;; debug: deopt position, script offset '43'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'wrong map'
;; debug: deopt index 1
;; deoptimization bailout 1
0x1aa58ba04330 272 e8dffcc7ff call 0x1aa58b684014 ;; debug: deopt position, script offset '43'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'out of bounds'
;; debug: deopt index 2
;; deoptimization bailout 2
0x1aa58ba04335 277 e8eefcc7ff call 0x1aa58b684028 ;; debug: deopt position, script offset '43'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'not a heap number'
;; debug: deopt index 4
;; deoptimization bailout 4
0x1aa58ba0433a 282 e8f3fcc7ff call 0x1aa58b684032 ;; debug: deopt position, script offset '43'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'lost precision or NaN'
;; debug: deopt index 5
;; deoptimization bailout 5
0x1aa58ba0433f 287 e8f8fcc7ff call 0x1aa58b68403c ;; debug: deopt position, script offset '43'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'minus zero'
;; debug: deopt index 6
;; deoptimization bailout 6
0x1aa58ba04344 292 90 nop
0x1aa58ba04345 293 90 nop
0x1aa58ba04346 294 90 nop
0x1aa58ba04347 295 90 nop
0x1aa58ba04348 296 90 nop
0x1aa58ba04349 297 90 nop
0x1aa58ba0434a 298 90 nop
0x1aa58ba0434b 299 90 nop
0x1aa58ba0434c 300 90 nop
0x1aa58ba0434d 301 90 nop
0x1aa58ba0434e 302 90 nop
0x1aa58ba0434f 303 90 nop
0x1aa58ba04350 304 90 nop
0x1aa58ba04351 305 0f1f00 nop
;;; Safepoint table.
Source positions:
pc offset position
0 15
23 43
133 51
140 15
166 43
Inlined functions (count = 0)
Deoptimization Input Data (deopt points = 7)
index ast id argc pc
0 0 0 -1
1 0 0 -1
2 0 0 -1
3 0 0 161
4 0 0 -1
5 0 0 -1
6 0 0 -1
Safepoints (size = 19)
0x1aa58ba042c1 161 000000 (sp -> fp) 3
RelocInfo (size = 329)
0x1aa58ba04220 comment (-- <elemAt.js:1:16> --)
0x1aa58ba04220 comment (-- B0 start (construct frame) --)
0x1aa58ba04237 comment (-- B2 start --)
0x1aa58ba04237 comment (-- B3 start --)
0x1aa58ba04237 comment (-- <elemAt.js:2:14> --)
0x1aa58ba04245 embedded object (0x85d3e503c79 <Map(FAST_SMI_ELEMENTS)>)
0x1aa58ba0426c comment (-- B8 start --)
0x1aa58ba04273 comment (-- B9 start (deconstruct frame) --)
0x1aa58ba04288 comment (Abort message: )
0x1aa58ba04288 comment (32 bit value in register is not zero-extended)
0x1aa58ba04293 code target (BUILTIN) (0x1aa58b804120)
0x1aa58ba042a5 comment (-- <elemAt.js:3:1> --)
0x1aa58ba042ac comment (-- B10 start (no frame) --)
0x1aa58ba042ac comment (-- B1 start (deferred) --)
0x1aa58ba042ac comment (-- <elemAt.js:1:16> --)
0x1aa58ba042ae external reference (Runtime::StackGuard) (0x10790f600)
0x1aa58ba042bd code target (STUB) (0x1aa58b8041a0)
0x1aa58ba042c6 comment (-- B4 start (deferred) --)
0x1aa58ba042c6 comment (-- <elemAt.js:2:14> --)
0x1aa58ba04306 comment (-- B5 start (deferred) --)
0x1aa58ba04306 comment (-- B6 start (deferred) --)
0x1aa58ba04315 comment (-- B7 start (deferred) --)
0x1aa58ba04326 deopt script offset (43)
0x1aa58ba04326 deopt inlining id (-1)
0x1aa58ba04326 deopt reason (Smi)
0x1aa58ba04326 deopt index
0x1aa58ba04327 runtime entry (deoptimization bailout 0)
0x1aa58ba0432b deopt script offset (43)
0x1aa58ba0432b deopt inlining id (-1)
0x1aa58ba0432b deopt reason (wrong map)
0x1aa58ba0432b deopt index
0x1aa58ba0432c runtime entry (deoptimization bailout 1)
0x1aa58ba04330 deopt script offset (43)
0x1aa58ba04330 deopt inlining id (-1)
0x1aa58ba04330 deopt reason (out of bounds)
0x1aa58ba04330 deopt index
0x1aa58ba04331 runtime entry (deoptimization bailout 2)
0x1aa58ba04335 deopt script offset (43)
0x1aa58ba04335 deopt inlining id (-1)
0x1aa58ba04335 deopt reason (not a heap number)
0x1aa58ba04335 deopt index
0x1aa58ba04336 runtime entry (deoptimization bailout 4)
0x1aa58ba0433a deopt script offset (43)
0x1aa58ba0433a deopt inlining id (-1)
0x1aa58ba0433a deopt reason (lost precision or NaN)
0x1aa58ba0433a deopt index
0x1aa58ba0433b runtime entry (deoptimization bailout 5)
0x1aa58ba0433f deopt script offset (43)
0x1aa58ba0433f deopt inlining id (-1)
0x1aa58ba0433f deopt reason (minus zero)
0x1aa58ba0433f deopt index
0x1aa58ba04340 runtime entry (deoptimization bailout 6)
0x1aa58ba04354 comment (;;; Safepoint table.)
--- End code ---複製程式碼
在解釋這個之前,我們要先確保已經瞭解 hidden map(也稱 hidden class)。如上文中提到的,引擎會做很多假設來減少一些無用操作花費的時間。然而,我們也要了解元素 -- 每個元素都有型別。V8 實現了 TypeFeedbackVector。推薦你閱讀這篇文章瞭解更多詳情。已知型別見 chromium.googlesource.com/v8/v8.git/+…
也有一些原生函式可以幫助我們檢查元素是否匹配已有型別。它們的定義見上段連結,對應的原生名稱見 chromium.googlesource.com/v8/v8.git/+… 。
現在再來看反優化。
;; debug: deopt reason 'Smi'
;; debug: deopt index 0複製程式碼
顯而易見。這是由於你給函式的第一個引數 “arr” 傳遞了 Smi。
;; debug: deopt reason 'wrong map'
;; debug: deopt index 1複製程式碼
很不幸,這種情況經常發生。
我們的 map(型別)是: <Map(FAST_SMI_ELEMENTS)>
因此,一旦“arr”中的元素不同於 Smi 元素,map 就不再匹配。當我們向它傳遞的引數不是普通陣列而是其它型別時,這種情況就會發生。比如:
elemAt([‘netguru’], 0);
elemAt({ 0: ‘netguru’ }, 0);複製程式碼
如果你想檢查陣列是否由 Smi 元素組成,可以使用上面提到的原生函式 %HasFastSmiElements
。
print(%HasFastSmiElements([2, 4, 5])); // prints true
print(%HasFastSmiElements([2, 4, 'd'])); // prints false
print(%HasFastSmiElements([2.1])); // prints false
print(%HasFastSmiElements({})); // prints false複製程式碼
好,我們現在來檢查第二個引數 index
,你很快就發現,它的反優化依賴於第二個引數。
;; debug: deopt reason 'out of bounds'
;; debug: deopt index 2複製程式碼
“Out of bounds“,從字面上看,當索引大於陣列的長度,或者小於 0 時,就會導致反優化。
也就是說,你在試圖讀取索引不屬於陣列的元素。
舉例:
elemAt([2,3,5], 4);複製程式碼
;; debug: deopt reason 'not a heap number'
;; debug: deopt index 4複製程式碼
'not a heap number' – 不是數字(注意不要與 Smi 混淆),舉例:
elemAt([2,3,5], '2');
elemAt([2,3,5], new Number(5));複製程式碼
;; debug: deopt reason 'lost precision or NaN'
;; debug: deopt index 5複製程式碼
如果你遇到這種檢查,意味著你傳遞了一個數字,但不是正常值。
丟失精度 -- 不是整數, 例子 1.1
elemAt([0, 1], 1.1);
elemAt([0], NaN);複製程式碼
;; debug: deopt reason 'minus zero'
;; debug: deopt index 6複製程式碼
太容易了!
add(0, -0); // weird, I know複製程式碼
也很容易理解!
還有一個例子 -- 上面例子組合的情況。這兒就不詳細解釋了,還是留給你做練習吧 :)
let secondIndex = 0;
function elemAtComplex(arr, index) {
return arr[secondIndex + index];
}
elemAtComplex(['v8 ',' is',' awesome'], 0);
secondIndex++;
elemAtComplex(['netguru ',' loves',' Node.js'], 1);
secondIndex++;
%OptimizeFunctionOnNextCall(elemAtComplex);
elemAtComplex(['wooo','dooo','dooboo'], 0);複製程式碼
給出結果,以免你沒有安裝 d8 :)
--- Raw source ---
(arr, index) {
return arr[secondIndex + index];
}
--- Optimized code ---
optimization_id = 0
source_position = 44
kind = OPTIMIZED_FUNCTION
name = elemAtComplex
stack_slots = 4
compiler = turbofan
Instructions (size = 314)
0xc145e604220 0 55 push rbp
0xc145e604221 1 4889e5 REX.W movq rbp,rsp
0xc145e604224 4 56 push rsi
0xc145e604225 5 57 push rdi
0xc145e604226 6 493ba5700c0000 REX.W cmpq rsp,[r13+0xc70]
0xc145e60422d 13 0f86c1000000 jna 212 (0xc145e6042f4)
0xc145e604233 19 48b8c11323e96e3f0000 REX.W movq rax,0x3f6ee92313c1 ;; object: 0x3f6ee92313c1 <FixedArray[5]>
0xc145e60423d 29 488b402f REX.W movq rax,[rax+0x2f]
0xc145e604241 33 493945a8 REX.W cmpq [r13-0x58],rax
0xc145e604245 37 0f8523000000 jnz 78 (0xc145e60426e)
0xc145e60424b 43 48b8690c23e96e3f0000 REX.W movq rax,0x3f6ee9230c69 ;; object: 0x3f6ee9230c69 <String[11]: secondIndex>
0xc145e604255 53 50 push rax
0xc145e604256 54 48bb50680d0501000000 REX.W movq rbx,0x1050d6850 ;; external reference (Runtime::ThrowReferenceError)
0xc145e604260 64 b801000000 movl rax,0x1
0xc145e604265 69 488b75f8 REX.W movq rsi,[rbp-0x8]
0xc145e604269 73 e832ffdfff call 0xc145e4041a0 ;; code: STUB, CEntryStub, minor: 8
0xc145e60426e 78 a801 test al,0x1
0xc145e604270 80 0f8598000000 jnz 238 (0xc145e60430e)
0xc145e604276 86 488b5d10 REX.W movq rbx,[rbp+0x10]
0xc145e60427a 90 f6c301 testb rbx,0x1
0xc145e60427d 93 0f8590000000 jnz 243 (0xc145e604313)
0xc145e604283 99 488bd3 REX.W movq rdx,rbx
0xc145e604286 102 48c1ea20 REX.W shrq rdx, 32
0xc145e60428a 106 488bc8 REX.W movq rcx,rax
0xc145e60428d 109 48c1e920 REX.W shrq rcx, 32
0xc145e604291 113 03d1 addl rdx,rcx
0xc145e604293 115 0f807f000000 jo 248 (0xc145e604318)
0xc145e604299 121 488b4d18 REX.W movq rcx,[rbp+0x18]
0xc145e60429d 125 f6c101 testb rcx,0x1
0xc145e6042a0 128 0f8477000000 jz 253 (0xc145e60431d)
0xc145e6042a6 134 48be713be83d350d0000 REX.W movq rsi,0xd353de83b71 ;; object: 0xd353de83b71 <Map(FAST_ELEMENTS)>
0xc145e6042b0 144 483971ff REX.W cmpq [rcx-0x1],rsi
0xc145e6042b4 148 0f8568000000 jnz 258 (0xc145e604322)
0xc145e6042ba 154 488b710f REX.W movq rsi,[rcx+0xf]
0xc145e6042be 158 8b791b movl rdi,[rcx+0x1b]
0xc145e6042c1 161 49ba0000000001000000 REX.W movq r10,0x100000000
0xc145e6042cb 171 4c3bd7 REX.W cmpq r10,rdi
0xc145e6042ce 174 7310 jnc 192 (0xc145e6042e0)
0xc145e6042d0 176 48ba0000000001000000 REX.W movq rdx,0x100000000
0xc145e6042da 186 e841fedfff call Abort (0xc145e404120) ;; code: BUILTIN
0xc145e6042df 191 cc int3l
0xc145e6042e0 192 3bd7 cmpl rdx,rdi
0xc145e6042e2 194 0f833f000000 jnc 263 (0xc145e604327)
0xc145e6042e8 200 488b44d60f REX.W movq rax,[rsi+rdx*8+0xf]
0xc145e6042ed 205 488be5 REX.W movq rsp,rbp
0xc145e6042f0 208 5d pop rbp
0xc145e6042f1 209 c21800 ret 0x18
0xc145e6042f4 212 48bb00b60d0501000000 REX.W movq rbx,0x1050db600 ;; external reference (Runtime::StackGuard)
0xc145e6042fe 222 33c0 xorl rax,rax
0xc145e604300 224 488b75f8 REX.W movq rsi,[rbp-0x8]
0xc145e604304 228 e897fedfff call 0xc145e4041a0 ;; code: STUB, CEntryStub, minor: 8
0xc145e604309 233 e925ffffff jmp 19 (0xc145e604233)
0xc145e60430e 238 e801fdc7ff call 0xc145e284014 ;; debug: deopt position, script offset '84'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'not a Smi'
;; debug: deopt index 2
;; deoptimization bailout 2
0xc145e604313 243 e806fdc7ff call 0xc145e28401e ;; debug: deopt position, script offset '84'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'not a Smi'
;; debug: deopt index 3
;; deoptimization bailout 3
0xc145e604318 248 e80bfdc7ff call 0xc145e284028 ;; debug: deopt position, script offset '84'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'overflow'
;; debug: deopt index 4
;; deoptimization bailout 4
0xc145e60431d 253 e810fdc7ff call 0xc145e284032 ;; debug: deopt position, script offset '84'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'Smi'
;; debug: deopt index 5
;; deoptimization bailout 5
0xc145e604322 258 e815fdc7ff call 0xc145e28403c ;; debug: deopt position, script offset '84'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'wrong map'
;; debug: deopt index 6
;; deoptimization bailout 6
0xc145e604327 263 e81afdc7ff call 0xc145e284046 ;; debug: deopt position, script offset '84'
;; debug: deopt position, inlining id '-1'
;; debug: deopt reason 'out of bounds'
;; debug: deopt index 7
;; deoptimization bailout 7
0xc145e60432c 268 90 nop
0xc145e60432d 269 90 nop
0xc145e60432e 270 90 nop
0xc145e60432f 271 90 nop
0xc145e604330 272 90 nop
0xc145e604331 273 90 nop
0xc145e604332 274 90 nop
0xc145e604333 275 90 nop
0xc145e604334 276 90 nop
0xc145e604335 277 90 nop
0xc145e604336 278 90 nop
0xc145e604337 279 90 nop
0xc145e604338 280 90 nop
0xc145e604339 281 0f1f00 nop
Source positions:
pc offset position
0 44
19 61
54 72
78 84
205 94
212 44
Inlined functions (count = 0)
Deoptimization Input Data (deopt points = 9)
index ast id argc pc
0 12 0 78
1 12 0 -1
2 21 0 -1
3 21 0 -1
4 21 0 -1
5 21 0 -1
6 21 0 -1
7 21 0 -1
8 0 0 233
Safepoints (size = 30)
0xc145e60426e 78 0000 (sp -> fp) 1
0xc145e604309 233 0000 (sp -> fp) 8
RelocInfo (size = 142)
0xc145e604235 embedded object (0x3f6ee92313c1 <FixedArray[5]>)
0xc145e60424d embedded object (0x3f6ee9230c69 <String[11]: secondIndex>)
0xc145e604258 external reference (Runtime::ThrowReferenceError) (0x1050d6850)
0xc145e60426a code target (STUB) (0xc145e4041a0)
0xc145e6042a8 embedded object (0xd353de83b71 <Map(FAST_ELEMENTS)>)
0xc145e6042db code target (BUILTIN) (0xc145e404120)
0xc145e6042f6 external reference (Runtime::StackGuard) (0x1050db600)
0xc145e604305 code target (STUB) (0xc145e4041a0)
0xc145e60430e deopt script offset (84)
0xc145e60430e deopt inlining id (-1)
0xc145e60430e deopt reason (not a Smi)
0xc145e60430e deopt index
0xc145e60430f runtime entry (deoptimization bailout 2)
0xc145e604313 deopt script offset (84)
0xc145e604313 deopt inlining id (-1)
0xc145e604313 deopt reason (not a Smi)
0xc145e604313 deopt index
0xc145e604314 runtime entry (deoptimization bailout 3)
0xc145e604318 deopt script offset (84)
0xc145e604318 deopt inlining id (-1)
0xc145e604318 deopt reason (overflow)
0xc145e604318 deopt index
0xc145e604319 runtime entry (deoptimization bailout 4)
0xc145e60431d deopt script offset (84)
0xc145e60431d deopt inlining id (-1)
0xc145e60431d deopt reason (Smi)
0xc145e60431d deopt index
0xc145e60431e runtime entry (deoptimization bailout 5)
0xc145e604322 deopt script offset (84)
0xc145e604322 deopt inlining id (-1)
0xc145e604322 deopt reason (wrong map)
0xc145e604322 deopt index
0xc145e604323 runtime entry (deoptimization bailout 6)
0xc145e604327 deopt script offset (84)
0xc145e604327 deopt inlining id (-1)
0xc145e604327 deopt reason (out of bounds)
0xc145e604327 deopt index
0xc145e604328 runtime entry (deoptimization bailout 7)
--- End code ---複製程式碼
就到這兒,結束了!
我們看了 2 個非常簡單的例子,希望你能明白總的思想。
想看你的函式反優化的情況,只要傳遞 --trace-opt
就好。
總的來說,不要過度優化,因為可能會傷害程式碼可讀性(比如函式 ele-at 的第 3 個例子)。你也可以傳遞字串陣列或其它,這沒問題。然而,如果真的不需要優化,就不要(優化)。就第 1 個例子而言,我認為即使 2 個函式看起來相同,最好還是能分成 2 個不同名稱的函式,這樣其他開發者看到 concat 或者 sum,馬上就知道這個函式的作用。
未來,你可以新增 string 特有的操作,比如 (a + b).toUpperCase(),而不需要對 sum 函式做任何特殊處理。
最後,你應該牢記過度優化可能會傷害可讀性,最終導致不可維護的程式碼。儘量不要使用任何編譯語言中不適用的奇怪模式。
最後的最後,我要感謝 Google 的軟體工程師、V8 團隊軟體工程師兼技術領導 Benedikt Meurer,是他幫助校對了本文。這裡是他的部落格:benediktmeurer.de/
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、React、前端、後端、產品、設計 等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。