[V8]找出可能影響效能的程式碼(模式)

薛定諤的貓發表於2017-11-01

找出可能影響效能的程式碼(模式)

現在你很可能會遇到不止一個響應遲鈍的 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/


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOSReact前端後端產品設計 等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章