欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

JavaScript引擎V8執(zhí)行流程概述-創(chuàng)新互聯(lián)

本文首發(fā)于 vivo互聯(lián)網(wǎng)技術(shù) 微信公眾號(hào)?
鏈接:https://mp.weixin.qq.com/s/t__Jqzg1rbTlsCHXKMwh7A
作者:賴勇高

創(chuàng)新互聯(lián)建站是專業(yè)的大洼網(wǎng)站建設(shè)公司,大洼接單;提供成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行大洼網(wǎng)站開發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!

本文主要講解的是V8的技術(shù),是V8的入門篇,主要目的是了解V8的內(nèi)部機(jī)制,希望對(duì)前端,快應(yīng)用,瀏覽器,以及nodejs同學(xué)有些幫助。這里不涉及到如何編寫優(yōu)秀的前端,只是對(duì)JS內(nèi)部引擎技術(shù)的講解。

一、V8來(lái)源

JavaScript 引擎 V8 執(zhí)行流程概述

V8的名字來(lái)源于汽車的“V型8缸發(fā)動(dòng)機(jī)”(V8發(fā)動(dòng)機(jī))。V8發(fā)動(dòng)機(jī)主要是美國(guó)發(fā)展起來(lái),因?yàn)轳R力十足而廣為人知。V8引擎的命名是Google向用戶展示它是一款強(qiáng)力并且高速的JavaScript引擎。

V8未誕生之前,早期主流的JavaScript引擎是JavaScriptCore引擎。JavaScriptCore是主要服務(wù)于Webkit瀏覽器內(nèi)核,他們都是由蘋果公司開發(fā)并開源出來(lái)。據(jù)說Google是不滿意JavaScriptCore和Webkit的開發(fā)速度和運(yùn)行速度,Google另起爐灶開發(fā)全新的JavaScript引擎和瀏覽器內(nèi)核引擎,所以誕生了V8和Chromium兩大引擎,到現(xiàn)在已經(jīng)是最受歡迎的瀏覽器相關(guān)軟件。

二、V8的服務(wù)對(duì)象

V8是依托Chrome發(fā)展起來(lái)的,后面確不局限于瀏覽器內(nèi)核。發(fā)展至今V8應(yīng)用于很多場(chǎng)景,例如流行的nodejs,weex,快應(yīng)用,早期的RN。

三、V8的早期架構(gòu)

V8引擎的誕生帶著使命而來(lái),就是要在速度和內(nèi)存回收上進(jìn)行革命的。JavaScriptCore的架構(gòu)是采用生成字節(jié)碼的方式,然后執(zhí)行字節(jié)碼。Google覺得JavaScriptCore這套架構(gòu)不行,生成字節(jié)碼會(huì)浪費(fèi)時(shí)間,不如直接生成機(jī)器碼快。所以V8在前期的架構(gòu)設(shè)計(jì)上是非常激進(jìn)的,采用了直接編譯成機(jī)器碼的方式。后期的實(shí)踐證明Google的這套架構(gòu)速度是有改善,但是同時(shí)也造成了內(nèi)存消耗問題??梢钥聪耉8的初期流程圖:

JavaScript 引擎 V8 執(zhí)行流程概述

早期的V8有Full-Codegen和Crankshaft兩個(gè)編譯器。V8 首先用 Full-Codegen把所有的代碼都編譯一次,生成對(duì)應(yīng)的機(jī)器碼。JS在執(zhí)行的過程中,V8內(nèi)置的Profiler篩選出熱點(diǎn)函數(shù)并且記錄參數(shù)的反饋類型,然后交給 Crankshaft 來(lái)進(jìn)行優(yōu)化。所以Full-Codegen本質(zhì)上是生成的是未優(yōu)化的機(jī)器碼,而Crankshaft生成的是優(yōu)化過的機(jī)器碼。

四、V8早期架構(gòu)的缺陷

隨著版本的引進(jìn),網(wǎng)頁(yè)的復(fù)雜化,V8也漸漸的暴露出了自己架構(gòu)上的缺陷:

  1. Full-Codegen編譯直接生成機(jī)器碼,導(dǎo)致內(nèi)存占用大

  2. Full-Codegen編譯直接生成機(jī)器碼,導(dǎo)致編譯時(shí)間長(zhǎng),導(dǎo)致啟動(dòng)速度慢

  3. Crankshaft 無(wú)法優(yōu)化try,catch和finally等關(guān)鍵字劃分的代碼塊

  4. Crankshaft新加語(yǔ)法支持,需要為此編寫適配不同的Cpu架構(gòu)代碼

五、V8的現(xiàn)有架構(gòu)

為了解決上述缺點(diǎn),V8采用JavaScriptCore的架構(gòu),生成字節(jié)碼。這里是不是感覺Google又繞回來(lái)了。V8采用生成字節(jié)碼的方式,整體流程如下圖:

JavaScript 引擎 V8 執(zhí)行流程概述

Ignition是V8的解釋器,背后的原始動(dòng)機(jī)是減少移動(dòng)設(shè)備上的內(nèi)存消耗。在Ignition之前,V8的Full-codegen基線編譯器生成的代碼通常占據(jù)Chrome整體JavaScript堆的近三分之一。這為Web應(yīng)用程序的實(shí)際數(shù)據(jù)留下了更少的空間。

Ignition的字節(jié)碼可以直接用TurboFan生成優(yōu)化的機(jī)器代碼,而不必像Crankshaft那樣從源代碼重新編譯。Ignition的字節(jié)碼在V8中提供了更清晰且更不容易出錯(cuò)的基線執(zhí)行模型,簡(jiǎn)化了去優(yōu)化機(jī)制,這是V8 自適應(yīng)優(yōu)化的關(guān)鍵特性。最后,由于生成字節(jié)碼比生成Full-codegen的基線編譯代碼更快,因此激活I(lǐng)gnition通常會(huì)改善腳本啟動(dòng)時(shí)間,從而改善網(wǎng)頁(yè)加載。

TurboFan是V8的優(yōu)化編譯器,TurboFan項(xiàng)目最初于2013年底啟動(dòng),旨在解決Crankshaft的缺點(diǎn)。Crankshaft只能優(yōu)化JavaScript語(yǔ)言的子集。例如,它不是設(shè)計(jì)用于使用結(jié)構(gòu)化異常處理優(yōu)化JavaScript代碼,即由JavaScript的try,catch和finally關(guān)鍵字劃分的代碼塊。很難在Crankshaft中添加對(duì)新語(yǔ)言功能的支持,因?yàn)檫@些功能幾乎總是需要為九個(gè)支持的平臺(tái)編寫特定于體系結(jié)構(gòu)的代碼。

采用新架構(gòu)后的優(yōu)勢(shì)

不同架構(gòu)下V8的內(nèi)存對(duì)比,如圖:

JavaScript 引擎 V8 執(zhí)行流程概述

結(jié)論:可以明顯看出Ignition+TurboFan架構(gòu)比Full-codegen+Crankshaft架構(gòu)內(nèi)存降低一半多。

不同架構(gòu)網(wǎng)頁(yè)速度提升對(duì)比,如圖:

JavaScript 引擎 V8 執(zhí)行流程概述

結(jié)論:可以明顯看出Ignition+TurboFan架構(gòu)比Full-codegen+Crankshaft架構(gòu)70%網(wǎng)頁(yè)速度是有提升的。

接下來(lái)我們大致的講解下現(xiàn)有架構(gòu)的每個(gè)流程:

六、V8的詞法分析和語(yǔ)法分析

學(xué)過編譯原理的同學(xué)可以知道,JS文件只是一個(gè)源碼,機(jī)器是無(wú)法執(zhí)行的,詞法分析就是把源碼的字符串分割出來(lái),生成一系列的token,如下圖可知不同的字符串對(duì)應(yīng)不同的token類型。

JavaScript 引擎 V8 執(zhí)行流程概述

詞法分析完后,接下來(lái)的階段就是進(jìn)行語(yǔ)法分析。語(yǔ)法分析語(yǔ)法分析的輸入就是詞法分析的輸出,輸出是AST抽象語(yǔ)法樹。當(dāng)程序出現(xiàn)語(yǔ)法錯(cuò)誤的時(shí)候,V8在語(yǔ)法分析階段拋出異常。

JavaScript 引擎 V8 執(zhí)行流程概述

七、V8 AST抽象語(yǔ)法樹

下圖是一個(gè)add函數(shù)的抽象語(yǔ)法樹數(shù)據(jù)結(jié)構(gòu)

JavaScript 引擎 V8 執(zhí)行流程概述

V8 Parse階段后,接下來(lái)就是根據(jù)抽象語(yǔ)法樹生成字節(jié)碼。如下圖可以看出add函數(shù)生成對(duì)應(yīng)的字節(jié)碼:

JavaScript 引擎 V8 執(zhí)行流程概述

BytecodeGenerator類的作用是根據(jù)抽象語(yǔ)法樹生成對(duì)應(yīng)的字節(jié)碼,不同的node會(huì)對(duì)應(yīng)一個(gè)字節(jié)碼生成函數(shù),函數(shù)開頭為Visit****。如下圖+號(hào)對(duì)應(yīng)的函數(shù)字節(jié)碼生成:

JavaScript 引擎 V8 執(zhí)行流程概述

void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
  FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot();
  Expression* subexpr;
  Smi* literal;

  if (expr->IsSmiLiteralOperation(&subexpr, &literal)) {
    VisitForAccumulatorValue(subexpr);
    builder()->SetExpressionPosition(expr);
    builder()->BinaryOperationSmiLiteral(expr->op(), literal,
                                         feedback_index(slot));
  } else {
    Register lhs = VisitForRegisterValue(expr->left());
    VisitForAccumulatorValue(expr->right());
    builder()->SetExpressionPosition(expr);  //  保存源碼位置 用于調(diào)試
    builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot)); //  生成Add字節(jié)碼
  }
}

上述可知有個(gè)源碼位置記錄,然后下圖可知源碼和字節(jié)碼位置的對(duì)應(yīng)關(guān)系:

JavaScript 引擎 V8 執(zhí)行流程概述

生成字節(jié)碼,那字節(jié)碼如何執(zhí)行的呢?接下來(lái)講解下:

八、字節(jié)碼

首先說下V8字節(jié)碼:

  1. 每個(gè)字節(jié)碼指定其輸入和輸出作為寄存器操作數(shù)

  2. Ignition 使用registers寄存器 r0,r1,r2... 和累加器寄存器(accumulator register)

  3. registers寄存器:函數(shù)參數(shù)和局部變量保存在用戶可見的寄存器中

  4. 累加器:是非用戶可見寄存器,用于保存中間結(jié)果

如下圖ADD字節(jié)碼:

JavaScript 引擎 V8 執(zhí)行流程概述

字節(jié)碼執(zhí)行

下面一系列圖表示每個(gè)字節(jié)碼執(zhí)行時(shí),對(duì)應(yīng)寄存器和累加器的變化,add函數(shù)傳入10,20的參數(shù),最終累加器返回的結(jié)果是50。

JavaScript 引擎 V8 執(zhí)行流程概述

JavaScript 引擎 V8 執(zhí)行流程概述

JavaScript 引擎 V8 執(zhí)行流程概述

JavaScript 引擎 V8 執(zhí)行流程概述

JavaScript 引擎 V8 執(zhí)行流程概述

JavaScript 引擎 V8 執(zhí)行流程概述

JavaScript 引擎 V8 執(zhí)行流程概述

JavaScript 引擎 V8 執(zhí)行流程概述

每個(gè)字節(jié)碼對(duì)應(yīng)一個(gè)處理函數(shù),字節(jié)碼處理程序保存的地址在dispatch_table_中。執(zhí)行字節(jié)碼時(shí)會(huì)調(diào)用到對(duì)應(yīng)的字節(jié)碼處理程序進(jìn)行執(zhí)行。Interpreter類成員dispatch_table_保存了每個(gè)字節(jié)碼的處理程序地址。

JavaScript 引擎 V8 執(zhí)行流程概述

JavaScript 引擎 V8 執(zhí)行流程概述

例如ADD字節(jié)碼對(duì)應(yīng)的處理函數(shù)是(當(dāng)執(zhí)行ADD字節(jié)碼時(shí)候,會(huì)調(diào)用InterpreterBinaryOpAssembler類):

IGNITION_HANDLER(Add, InterpreterBinaryOpAssembler) {
   BinaryOpWithFeedback(&BinaryOpAssembler::Generate_AddWithFeedback);
}

void BinaryOpWithFeedback(BinaryOpGenerator generator) {
    Node* reg_index = BytecodeOperandReg(0);
    Node* lhs = LoadRegister(reg_index);
    Node* rhs = GetAccumulator();
    Node* context = GetContext();
    Node* slot_index = BytecodeOperandIdx(1);
    Node* feedback_vector = LoadFeedbackVector();
    BinaryOpAssembler binop_asm(state());
    Node* result = (binop_asm.*generator)(context, lhs, rhs, slot_index,                            
feedback_vector, false);
    SetAccumulator(result);  // 將ADD計(jì)算的結(jié)果設(shè)置到累加器中
    Dispatch(); // 處理下一條字節(jié)碼

}

其實(shí)到此JS代碼就已經(jīng)執(zhí)行完成了。在執(zhí)行過程中,發(fā)現(xiàn)有熱點(diǎn)函數(shù),V8會(huì)啟用Turbofan進(jìn)行優(yōu)化編譯,直接生成機(jī)器碼。所以接下來(lái)講解下Turbofan優(yōu)化編譯器:

九、Turbofan

Turbofan是根據(jù)字節(jié)碼和熱點(diǎn)函數(shù)反饋類型生成優(yōu)化后的機(jī)器碼,Turbofan很多優(yōu)化過程,基本和編譯原理的后端優(yōu)化差不多,采用的sea-of-node。

JavaScript 引擎 V8 執(zhí)行流程概述

add函數(shù)優(yōu)化:

function add(x, y) {
  return x+y;
}
add(1, 2);
%OptimizeFunctionOnNextCall(add);
add(1, 2);

V8是有函數(shù)可以直接調(diào)用指定優(yōu)化哪個(gè)函數(shù),執(zhí)行%OptimizeFunctionOnNextCall主動(dòng)調(diào)用Turbofan優(yōu)化add函數(shù),根據(jù)上次調(diào)用的參數(shù)反饋優(yōu)化add函數(shù),很明顯這次的反饋是整型數(shù),所以turbofan會(huì)根據(jù)參數(shù)是整型數(shù)進(jìn)行優(yōu)化直接生成機(jī)器碼,下次函數(shù)調(diào)用直接調(diào)用優(yōu)化好的機(jī)器碼。(注意執(zhí)行V8需要加上 --allow-natives-syntax,OptimizeFunctionOnNextCall為內(nèi)置函數(shù),只有加上 --allow-natives-syntax,JS才能調(diào)用內(nèi)置函數(shù) ,否則執(zhí)行會(huì)報(bào)錯(cuò))。

JS的add函數(shù)生成對(duì)應(yīng)的機(jī)器碼如下:

JavaScript 引擎 V8 執(zhí)行流程概述

這里會(huì)涉及small interger小整數(shù)概念,可以查看這篇文章https://zhuanlan.zhihu.com/p/82854566

如果把a(bǔ)dd函數(shù)的傳入?yún)?shù)改成字符

function add(x, y) {
  return x+y;
}
add(1, 2);
%OptimizeFunctionOnNextCall(add);
add(1, 2);

優(yōu)化后的add函數(shù)生成對(duì)應(yīng)的機(jī)器碼如下:

JavaScript 引擎 V8 執(zhí)行流程概述

對(duì)比上面兩圖,add函數(shù)傳入不同的參數(shù),經(jīng)過優(yōu)化生成不同的機(jī)器碼。

如果傳入的是整型,則本質(zhì)上是直接調(diào)用add匯編指令

如果傳入的是字符串,則本質(zhì)上是調(diào)用V8的內(nèi)置Add函數(shù)

到此V8的整體執(zhí)行流程就結(jié)束了。文章中可能存在理解不正確的地方敬請(qǐng)指出。

  • 參考文章
  1. https://v8.dev/docs

  2. https://docs.google.com/presentation/d/1HgDDXBYqCJNasBKBDf9szap1j4q4wnSHhOYpaNy5mHU/edit#slide=id.g17d335048f\_1\_1105

  3. https://docs.google.com/presentation/d/1Z9iIHojKDrXvZ27gRX51UxHD-bKf1QcPzSijntpMJBM/edit#slide=id.p

  4. https://zhuanlan.zhihu.com/p/82854566

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。

文章標(biāo)題:JavaScript引擎V8執(zhí)行流程概述-創(chuàng)新互聯(lián)
瀏覽地址:http://aaarwkj.com/article46/ccodeg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、面包屑導(dǎo)航、做網(wǎng)站手機(jī)網(wǎng)站建設(shè)、企業(yè)網(wǎng)站制作、服務(wù)器托管

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化
精品不卡一区二区三区| 亚洲av丰满熟妇在线观看| 精品人妻一区二区三区四| 日本女优中文字幕久久| 国产原创av剧情在线观看| 丰满少妇高潮在线视频| 欧美一区二区三区久久妇| 欧美午夜国产在线观看| 日本成人午夜在线观看| 久久99精品久久久国产| 日韩深夜成人在线视频| av福利一区二区三区| 亚洲另类偷拍校园伦理| 国产一区在线免费在线观看| 日本免费在线不卡一区二区| 亚洲精品尤物福利在线一区| 欧美国产综合欧美一区二区三区| 极品人妻少妇精品一区二区| 成人精品国产一区二区| 日韩亚洲欧美精品另类| 正在播放蜜臀av在线| 精品人妻一区二区三区在线av| 丰满人妻中出av在线| 人妻中文字幕av资源| 欧美亚日韩精品视频| 久久久精品国产亚洲av网黑人| 欧美中文字幕精在线不卡| 传媒在线免费观看视频| 日韩在线视频观看一区二区三区| 亚洲欧美日韩香蕉在线观看| 亚洲av优选在线观看精品| 成年人正常性生活频率| 日韩av天堂免费网站| 亚洲精品一区二区播放| 99久久精品国产熟女拳交| 日韩在线一区二区三区电影| 欧美日韩一区二区三区四区高清视频 | 97国产成人精品视频免费| 日本中文有码视频在线观看| 亚洲国产精品一区二区三区在线| av资源在线观看少妇丰满|