Chrome V8 ทำงานอย่างไร และทำไม JavaScript ไม่ได้รวบรวม JIT ตั้งแต่แรก?


19

ฉันได้ทำการค้นคว้าล่าม / คอมไพเลอร์แล้วฉันก็สะดุดกับ JIT-Compilation โดยเฉพาะ V8 Javascript Engine ของ Google Chrome

คำถามของฉันคือ -

  1. จะเร็วกว่าการตีความมาตรฐานอย่างไร
  2. ทำไมการรวบรวม JIT จึงไม่ถูกใช้ตั้งแต่แรก?


ความเข้าใจปัจจุบันของฉัน

  1. โปรแกรม Javascript ทุกตัวจะเริ่มต้นเป็นซอร์สโค้ดไม่ว่าวิธีการดำเนินการจะถูกแปลเป็นรหัสเครื่องในที่สุด
    ทั้งการรวบรวม JITและการตีความต้องเป็นไปตามเส้นทางนี้ดังนั้นการรวบรวม JIT จะเร็วขึ้นอย่างไร

  2. มันดูเหมือนว่า JIT รวบรวมเป็นนวัตกรรมที่ค่อนข้างเก่า , ตามออกของวิกิพีเดียJIT รวบรวมบทความ

"คอมไพเลอร์ JIT ที่ได้รับการตีพิมพ์ครั้งแรกนั้นมีสาเหตุมาจากการทำงานบน LISP โดย McCarthy ในปี 1960 "

"Smalltalk (c. 1983 ) เป็นผู้บุกเบิกด้านใหม่ของการรวบรวม JIT ตัวอย่างเช่นการแปลรหัสเครื่องทำได้ตามความต้องการและผลลัพธ์ถูกแคชไว้เพื่อใช้ในภายหลังเมื่อหน่วยความจำขาดแคลนระบบจะลบรหัสนี้และสร้างใหม่ เมื่อมันต้องการอีกครั้ง "

เหตุใดจึงต้องได้รับการตีความ Javascript จะเริ่มต้นด้วย ?


ฉันสับสนมากและฉันได้ทำการวิจัยมากมายเกี่ยวกับเรื่องนี้ แต่ฉันไม่พบคำตอบที่น่าพอใจ

คำตอบที่ชัดเจนและกระชับจะได้รับการชื่นชม และหากต้องการคำอธิบายเพิ่มเติมเกี่ยวกับล่ามจำเป็นต้องรวบรวม JIT-Compilers และอื่น ๆ เข้ามาด้วยเช่นกัน


2
# 2 และ # 3 สามารถตอบได้ แต่ "Chrome V8 Engine ทำงานอย่างไร" ไม่มีคุณสมบัติใดที่กว้างเกินไป คำตอบที่ถูกต้องเพียงอย่างเดียวคือลิงก์ไปยังซอร์สโค้ด V8 คุณหมายถึงถามคำถามเฉพาะเกี่ยวกับ V8 เพิ่มเติมหรือไม่ (ถ้าไม่ได้มันจะดีที่สุดเพื่อลบส่วนหนึ่งของคำถามที่)
Ixrec

จากการมองแวบ ๆ ครั้งที่สองสิ่งเดียวที่ฉันขอให้ # 1 คือเข้าใจ # 2 ดังนั้นฉันจะลบออก ขอบคุณสำหรับการป้อนข้อมูล
Anton Paras

นี่ไม่ได้กล่าวถึงในคำตอบอื่น ๆ แต่การรวบรวม JIT นั้นยาก ไม่ใช่เรื่องง่ายที่จะทำเพราะข้อผิดพลาดที่เกิดจากการรวบรวม JIT ส่งผลให้เกิด segfaults แทนข้อผิดพลาด - โปรแกรมขัดข้องแทนที่จะทิ้งข้อผิดพลาดในคอนโซล ใช่สำหรับโปรแกรมเมอร์ C ที่มีความสามารถซึ่งสะดวกสบายกับ gdb นี่ไม่ใช่ปัญหา แต่โปรแกรมเมอร์ C ที่มีความสามารถเกือบทั้งหมดจะคุ้นเคยกับ gdb ได้รับเงินเพื่อทำงานในโครงการอื่น ๆ ภาษาอื่น ๆ เช่น Perl และ Ruby ยังไม่มีล่าม JIT หลัก
slebetman

ในกรณีที่คุณสงสัย ฉันกำลังพูดถึงเรื่องนี้จากมุมมองของนักพัฒนา / ผู้ดูแลหลักสำหรับภาษาโปรแกรม สองสามปีฉันถูกจ้างให้รักษาภาษาการเขียนโปรแกรม Ferite หนึ่งในรายการความปรารถนาที่เรามีคือการใช้ JIT ไม่เคยเกิดขึ้น - เราย้ายไปแทน PHP เพิ่งได้รับ JIT คอมไพเลอร์ (HVVM) เมื่อเร็ว ๆ นี้ขอบคุณ Facebook เทเงินมากพอที่จะทำให้มันเกิดขึ้น
slebetman

คำตอบ:


43

คำตอบสั้น ๆ คือ JIT มีเวลาในการเริ่มต้นนานกว่า แต่เร็วกว่ามากในระยะยาวและ JavaScript ไม่ได้มีไว้สำหรับใช้ในระยะยาว

ในยุค 90 จาวาสคริปต์ทั่วไปบนเว็บไซต์จะมีจำนวนหนึ่งหรือสองฟังก์ชั่นในส่วนหัวและโค้ดจำนวนหนึ่งฝังตัวอยู่ในonclickคุณสมบัติโดยตรง โดยทั่วไปแล้วจะทำงานทันทีเมื่อผู้ใช้คาดว่าจะมีการโหลดหน้าเว็บล่าช้ามาก คิดว่าการตรวจสอบรูปแบบขั้นพื้นฐานอย่างยิ่งหรืออรรถประโยชน์ทางคณิตศาสตร์เล็ก ๆ เช่นเครื่องคำนวณดอกเบี้ย

การตีความตามความจำเป็นนั้นง่ายกว่ามากและให้ประสิทธิภาพที่เพียงพออย่างสมบูรณ์สำหรับกรณีการใช้งานประจำวัน หากคุณต้องการบางสิ่งที่มีประสิทธิภาพในระยะยาวคุณใช้แฟลชหรือแอปเพล็ต java

Google maps ในปี 2004 เป็นหนึ่งในแอพนักฆ่าคนแรกที่ใช้จาวาสคริปต์อย่างหนัก มันเป็นเรื่องที่เห็นได้ชัดถึงความเป็นไปได้ของ JavaScript แต่ยังเน้นถึงปัญหาด้านประสิทธิภาพ Google ใช้เวลาพยายามเบราว์เซอร์เพื่อปรับปรุงประสิทธิภาพ JavaScript ของพวกเขาจากนั้นในที่สุดก็ตัดสินใจว่าการแข่งขันจะเป็นแรงจูงใจที่ดีที่สุดและจะทำให้พวกเขามีที่นั่งที่ดีที่สุดในตารางมาตรฐานของเบราว์เซอร์ ผลที่ตามมาก็คือ Chrome และ V8 ได้เปิดตัวในปี 2008 ตอนนี้ 11 ปีหลังจากที่ Google Maps เข้ามาในฉากเรามีนักพัฒนาใหม่ที่จำไม่ได้ว่า JavaScript ถูกพิจารณาว่าไม่เพียงพอสำหรับงานประเภทนั้น

animateDraggedMapสมมติว่าคุณมีฟังก์ชั่น อาจใช้เวลา 500 ms ในการแปลความหมายและ 700 ms ในการรวบรวม JIT อย่างไรก็ตามหลังจากการรวบรวม JIT อาจใช้เวลาเพียง 100 ms ในการทำงานจริง หากเป็นยุค 90 และคุณเรียกใช้ฟังก์ชันเพียงครั้งเดียวแล้วโหลดหน้าใหม่ JIT จะไม่คุ้มค่าเลย หากเป็นวันนี้และคุณกำลังเรียกanimateDraggedMapหลายร้อยหรือหลายพันครั้งการเพิ่มค่าเริ่มต้น 200 ms นั้นไม่สามารถทำได้และมันสามารถทำได้หลังฉากก่อนที่ผู้ใช้จะพยายามลากแผนที่


2

ด้วยความเข้าใจในสิ่งที่เกิดขึ้นขณะรันไทม์เป็นไปได้ที่จะทำการเปลี่ยนแปลงโค้ดหรือการตีความโค้ดที่อนุญาตให้เรียกใช้งานได้เร็วขึ้นหรือรวบรวมได้ดีกว่าสิ่งที่ทราบล่วงหน้าในเวลารวบรวม

สามารถพูดได้ค่อนข้างน้อยในเรื่องนี้ - มันเป็นเรื่องของการวิจัยจำนวนมาก คำอธิบายของฉันเองที่นี่ฉันเริ่มเขียน pales เปรียบเทียบกับคำตอบที่ให้ไว้ในการทำความเข้าใจความแตกต่าง: ล่ามแบบดั้งเดิมคอมไพเลอร์ JIT ล่าม JIT และคอมไพเลอร์ AOT


ค่อนข้างง่าย JavaScript ไม่ได้ถูกคอมไพล์หรือมองหา JIT ในตอนแรกเพราะมันไม่เคยมีความหมายว่าซับซ้อนหรือสำคัญ

เจตนาดั้งเดิมของจาวาสคริปต์คือการเชื่อมโยงไปยัง Java applets บนหน้าเว็บ ความสามารถในการคลิกที่ปุ่มบางส่วนหรือป้อนค่าในเขตข้อมูลฟอร์มแล้วทำผลงานในวิธีการที่แอปเพล็ Java สามารถเห็นได้ในการเรียก Applet วิธีจากรหัส มันก็ยังเป็นไปได้ผ่าน JavaScript เพื่อไปทางอื่นของการเรียกรหัส JavaScript จากแอปเพล็

ความตั้งใจดั้งเดิมของ JavaScript คือการเชื่อมโยงแอพเพล็ตและหน้า html ที่มีอยู่ สำหรับงานเล็ก ๆ เช่นนี้คุณไม่ต้องการประสิทธิภาพที่ยอดเยี่ยม (ถ้าคุณต้องการประสิทธิภาพให้เรียกใช้แอปเพล็ตซึ่งเป็น JIT'ed)

มันเป็นเพียงหลังจาก Netscape เริ่มทำงานอย่างมีนัยสำคัญกับ JavaScript เป็นภาษาของตนเองและส่งเสริมการพัฒนา (รวมถึงServer Side JavaScriptใน Netscape Enterprise Server - ซึ่งโดยไม่ได้ตั้งใจล่วงหน้าก่อนการรวบรวมเวลา) ที่ JavaScript เข้ามาเป็นเป้าหมายที่จริงจัง . ใช้เวลาหลายปีหลังจากนั้นสำหรับเครื่องมือที่จำเป็นในการทำให้มีประโยชน์


1
ไม่ Javascript ไม่เกี่ยวข้องกับ Java และ Java applets คือ JVM bytecode
Basile Starynkevitch

@BasileStarynkevitch JavaScript ถูกออกแบบมาเพื่อทำงานกับ Java applets ในหน้าแฮมเล็ต - ทำหน้าที่เป็นตัวเชื่อมระหว่าง html dom และวิธีการที่มีอยู่ในวัตถุ Java มันไม่ได้และไม่เคยตั้งใจที่จะเป็นจาวา

เดิมที JavaScript เรียกว่า ECMAScript (หรืออะไรทำนองนั้น) และไม่มีส่วนเกี่ยวข้องกับ Java วิธีที่จะเรียกว่า JavaScript เป็นหัวข้อของการวิจัยแยกต่างหากสำหรับผู้ที่สนใจ สิ่งนี้ทำให้เกิดความสับสนนับจากนี้เป็นต้นไป
quick_now

1
@quickly_now และยังคงเป็นtc39.github.io/ecma262
caub

ใช่. และด้วยเหตุผลแปลก ๆ บางอย่างเมื่อฉันชี้ให้เห็นว่าข้างต้นฉันได้ลงคะแนนมัน
quick_now

1

JIT นั้นเร็วสำหรับ JavaScript เพราะมันเป็นไปไม่ได้ที่จะสร้างรหัสเครื่องที่รวดเร็วเมื่อคุณไม่ทราบชนิดของตัวแปรของคุณ

เมื่อคุณไม่มีข้อมูลประเภทการคำนวณมีราคาแพง ตัวอย่างเช่น,

x + y

ค่อนข้างซับซ้อนถ้าคุณไม่รู้อะไรเกี่ยวกับ x และ y พวกเขาอาจเป็นจำนวนเต็มคู่สายอักขระหรือแม้กระทั่งวัตถุที่การคำนวณนี้มีผลข้างเคียง เนื่องจากเราไม่มีการพิมพ์คงที่นี่คือการคำนวณที่มีราคาแพง

ด้วยการรวบรวมแบบทันเวลาเราสามารถใช้ข้อมูลรันไทม์และทำให้สิ่งนี้กลายเป็นการคำนวณที่เร็วขึ้น ที่รันไทม์ V8 จะติดตามชนิดของตัวแปร หากโค้ดข้างต้นจะถูกดำเนินการหลายครั้งด้วย, พูด, สตริง, คอมไพเลอร์สามารถดำเนินการคำแนะนำที่ง่ายมากสำหรับการต่อสตริง ดังนั้นเมื่อคอมไพเลอร์มาถึงx + yแทนที่จะเรียกใช้โค้ดจำนวนมากที่แยกสาขาสำหรับ x และ y หลายประเภทคอมไพเลอร์จะตรวจสอบอย่างรวดเร็วว่าเรามีสตริงอีกครั้งหรือไม่จากนั้นเรียกใช้รหัสเครื่องสองสามบรรทัด

ในตัวอย่าง C ++ คอมไพเลอร์รู้ประเภทของ x และ y ล่วงหน้าเนื่องจากเราต้องประกาศตัวแปร ดังนั้นจึงสามารถสร้างรหัสเครื่องที่ได้รับการปรับให้เหมาะสมสำหรับการเชื่อมสตริงก่อนที่จะรันโค้ด


0

1) การตีความมาตรฐานทำได้เร็วขึ้นอย่างไร ตัวอย่างความคิดจะเป็นดังนี้ สมมติว่าเรามี 2 แอปพลิเคชัน ApplicationCompiled และ ApplicationInter ตีความ ทั้งสองโปรแกรมทำสิ่งเดียวกันอย่างแน่นอนและแบ่งปันซอร์สโค้ดเดียวกัน ApplicationCompiled ใช้เวลารวบรวม 6 วินาที

สมมติว่าการกำหนดเวลาของสถานการณ์จำลอง A คือ:

  • สำหรับ ApplicationCompiled: 4 วินาที
  • สำหรับ ApplicationInter ตีความแล้ว: 12 วินาที

ดังนั้นใน ApplicationCompiled ทั้งหมดใช้เวลา 10 วินาทีในการรันสถานการณ์จำลอง A (การรวบรวม 6 วินาที, ทำงาน 4 วินาที) และ ApplicationInterpreted ใช้เวลารวม 12 วินาทีในการรัน ฉันไม่มีตัวอย่างที่เฉพาะเจาะจงที่จะแสดงให้คุณเห็นและฉันไม่แน่ใจว่ากรณีใดที่กล่าวข้างต้นจะเป็นจริง - มันขึ้นอยู่กับความฉลาดในการตีความและคอมไพเลอร์ด้วยเช่นกัน

เห็นได้ชัดว่านี่ง่ายมาก แต่ imho สามารถนำความคิดเดียวกันไปใช้ในการรวบรวม / ตีความ JIT คำถามต่อไปก็คือ "เราจะกำหนดได้อย่างไร - ด้วยต้นทุนต่ำ - ถ้าสาขานี้ควรจะรวบรวมหรือตีความ JIT"? ฉันออกจากลีกของฉันที่นี่ :)

2) ทำไม JIT-Compilation ไม่ได้ถูกใช้ตั้งแต่แรก ไม่ทราบ แต่ฉันกลับมาอีกครั้งว่าเป็นเรื่องของทรัพยากรและการครบกำหนดของความก้าวหน้าที่มีอยู่ในการสร้างภาษาที่ยากต่อการเพิ่มประสิทธิภาพเช่นจาวาสคริปต์ใช้เทคนิคขั้นสูงเช่นนี้ อาจมีผลไม้ห้อยแขวนจำนวนมากในเวลานั้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.