วัตถุประสงค์ของการสแต็คคืออะไร? ทำไมเราต้องการมัน?


320

ดังนั้นฉันกำลังเรียนรู้ MSIL ในขณะนี้เพื่อเรียนรู้การดีบักแอปพลิเคชัน C # .NET ของฉัน

ฉันสงสัยอยู่เสมอ: จุดประสงค์ของกองคืออะไร

เพียงใส่คำถามของฉันในบริบท:
เหตุใดจึงมีการถ่ายโอนจากหน่วยความจำไปกองหรือ "โหลด" ในทางกลับกันเหตุใดจึงมีการถ่ายโอนจากสแต็คไปยังหน่วยความจำหรือ "การจัดเก็บ" ทำไมไม่เพียงแค่วางมันทั้งหมดไว้ในหน่วยความจำ?

  • เป็นเพราะมันเร็วกว่าไหม
  • เป็นเพราะแรมใช้หรือไม่
  • เพื่อประสิทธิภาพ?

ฉันพยายามเข้าใจสิ่งนี้เพื่อช่วยให้ฉันเข้าใจรหัสCILอย่างลึกซึ้งยิ่งขึ้น


28
สแต็คเป็นส่วนหนึ่งของหน่วยความจำเหมือนกับฮีปเป็นอีกส่วนหนึ่งของหน่วยความจำ
CodesInChaos

@CodeInChaos คุณกำลังพูดถึงประเภทค่าเทียบกับประเภทการอ้างอิง? หรือว่าเป็นเช่นเดียวกันในแง่ของรหัส IL? ... ฉันรู้ว่าสแต็กนั้นเร็วกว่าและมีประสิทธิภาพมากกว่าฮีป (แต่นั่นก็อยู่ในโลกประเภทค่า / การอ้างอิง .. ซึ่งฉันไม่รู้ว่าที่นี่เหมือนกันหรือไม่)
Jan Carlo Viray

15
@CodeInChaos - ฉันคิดว่าสแต็คที่การอ้างอิงของแจนเป็นเครื่องสแต็คที่ IL ถูกเขียนเทียบกับพื้นที่ของหน่วยความจำที่ยอมรับเฟรมสแต็กในระหว่างการเรียกใช้ฟังก์ชัน มันเป็นสแต็คสองแบบที่แตกต่างกันและหลังจาก JIT แล้ว IL stack ก็ไม่มีอยู่ (บน x86 ต่อไป)
Damien_The_Unbeliever

4
ความรู้ MSIL จะช่วยให้คุณดีบักแอปพลิเคชัน. NET ได้อย่างไร
Piotr Perak

1
บนเครื่องที่ทันสมัยพฤติกรรมการแคชของโค้ดเป็นตัวสร้างประสิทธิภาพและตัวแบ่ง หน่วยความจำอยู่ทุกที่ สแต็คมักจะอยู่ที่นี่ สมมติว่า stack เป็นของจริงไม่ใช่แค่แนวคิดที่ใช้ในการแสดงการทำงานของโค้ดบางตัว ในการใช้งานแพลตฟอร์มที่ทำงานด้วย MSIL นั้นไม่จำเป็นต้องมีแนวคิดของสแต็กที่ทำให้มันเป็นฮาร์ดแวร์ที่ผลักดันบิตไปรอบ ๆ
Reinstate Monica

คำตอบ:


441

UPDATE: ฉันชอบคำถามนี้มากฉันทำมันเรื่องของบล็อกของฉัน 18 พฤศจิกายน 2011 ขอบคุณสำหรับคำถามที่ยอดเยี่ยม!

ฉันสงสัยอยู่เสมอ: จุดประสงค์ของกองซ้อนคืออะไร

ฉันถือว่าคุณหมายถึงสแต็คการประเมินของภาษา MSIL ไม่ใช่สแต็กต่อเธรดจริงที่รันไทม์

เหตุใดจึงมีการถ่ายโอนจากหน่วยความจำไปยังสแต็กหรือ "กำลังโหลด" ในทางกลับกันเหตุใดจึงมีการถ่ายโอนจากสแต็คไปยังหน่วยความจำหรือ "การจัดเก็บ" ทำไมไม่เพียงแค่วางมันทั้งหมดไว้ในหน่วยความจำ?

MSIL เป็นภาษา "เครื่องเสมือน" คอมไพเลอร์เช่นคอมไพเลอร์ C # สร้างCILจากนั้นที่คอมไพเลอร์อื่นที่เรียกว่าคอมไพเลอร์ JIT (Just In Time) เปลี่ยน IL เป็นรหัสเครื่องจริงที่สามารถดำเนินการได้

ดังนั้นก่อนอื่นลองตอบคำถาม "ทำไมต้องมี MSIL เลย?" ทำไมไม่เพียงให้คอมไพเลอร์ C # เขียนรหัสเครื่อง?

เพราะมันถูกกว่าที่จะทำแบบนี้ สมมติว่าเราไม่ได้ทำเช่นนั้น สมมติว่าแต่ละภาษาจะต้องมีเครื่องสร้างรหัสของตัวเอง คุณมีภาษาต่าง ๆ ยี่สิบภาษา: C #, JScript .NET , Visual Basic, IronPython , F # ... และสมมติว่าคุณมีโปรเซสเซอร์ที่แตกต่างกันสิบตัว คุณต้องเขียนโค้ดกี่ตัว? 20 x 10 = 200 ตัวสร้างโค้ด นั่นเป็นงานจำนวนมาก ตอนนี้สมมติว่าคุณต้องการเพิ่มโปรเซสเซอร์ใหม่ คุณต้องเขียนตัวสร้างโค้ดขึ้นมายี่สิบครั้งโดยแต่ละภาษา

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

ทีนี้สมมติว่าเราทำตามวิธี CIL คุณต้องเขียน CIL กี่ตัว? หนึ่งภาษาต่อหนึ่งภาษา คุณต้องเขียนคอมไพเลอร์ JIT กี่ตัว? หนึ่งตัวต่อโปรเซสเซอร์ ทั้งหมด: 20 + 10 = 30 เครื่องกำเนิดรหัส นอกจากนี้ตัวสร้าง language-to-CIL นั้นเขียนได้ง่ายเนื่องจาก CIL เป็นภาษาที่ง่ายและตัวสร้าง CIL-to-machine-code ก็ง่ายต่อการเขียนเพราะ CIL เป็นภาษาที่ง่าย เรากำจัดความซับซ้อนทั้งหมดของ C # และ VB และ whatnot และ "ลด" ทุกอย่างเป็นภาษาง่าย ๆ ที่ง่ายต่อการเขียนกระวนกระวายใจ

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

ตกลงดังนั้นเราได้พิสูจน์แล้วว่าทำไมเราถึงมี MSIL เพราะการใช้ภาษากลางลดค่าใช้จ่าย ทำไมภาษาจึงเป็น "เครื่องซ้อน"

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

คุณถามว่า "ทำไมมีสแต็คเลย" ทำไมไม่เพียงทำทุกอย่างออกจากหน่วยความจำโดยตรง ลองคิดกันดู สมมติว่าคุณต้องการสร้างรหัส CIL สำหรับ:

int x = A() + B() + C() + 10;

สมมติว่าเรามีการประชุมที่ "เพิ่ม", "โทร", "ร้านค้า" และอื่น ๆ จะเอาอาร์กิวเมนต์ของพวกเขาออกจากสแต็คและวางผลลัพธ์ของพวกเขา (ถ้ามี) บนสแต็ก ในการสร้างรหัส CIL สำหรับ C # เราแค่พูดดังนี้:

load the address of x // The stack now contains address of x
call A()              // The stack contains address of x and result of A()
call B()              // Address of x, result of A(), result of B()
add                   // Address of x, result of A() + B()
call C()              // Address of x, result of A() + B(), result of C()
add                   // Address of x, result of A() + B() + C()
load 10               // Address of x, result of A() + B() + C(), 10
add                   // Address of x, result of A() + B() + C() + 10
store in address      // The result is now stored in x, and the stack is empty.

ตอนนี้สมมติว่าเราทำมันโดยไม่มีสแต็ก เราจะทำมันด้วยวิธีของคุณซึ่งทุก opcode ใช้เวลาที่อยู่ของตัวถูกดำเนินการและที่อยู่ที่จะเก็บผลของมัน :

Allocate temporary store T1 for result of A()
Call A() with the address of T1
Allocate temporary store T2 for result of B()
Call B() with the address of T2
Allocate temporary store T3 for the result of the first addition
Add contents of T1 to T2, then store the result into the address of T3
Allocate temporary store T4 for the result of C()
Call C() with the address of T4
Allocate temporary store T5 for result of the second addition
...

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

เราใช้ opcodes สแต็คที่ใช้เพราะกองแก้ปัญหาที่พบบ่อย คือผมต้องการที่จะจัดสรรการจัดเก็บชั่วคราวบางใช้งานได้ในเร็ว ๆ นี้แล้วกำจัดมันได้อย่างรวดเร็วเมื่อฉันทำ โดยการตั้งสมมติฐานว่าเรามีสแต็คในการกำจัดของเราเราสามารถทำให้ opcodes มีขนาดเล็กมากและรหัสสั้นมาก

ปรับปรุง: ความคิดเพิ่มเติมบางอย่าง

อนึ่งแนวคิดของการลดต้นทุนลงอย่างมากโดย (1) specifing เครื่องเสมือน (2) การเขียนคอมไพเลอร์ที่กำหนดเป้าหมายภาษา VM และ (3) การเขียน implementations ของ VM บนฮาร์ดแวร์ที่หลากหลายไม่ใช่แนวคิดใหม่เลย . มันไม่ได้มีต้นกำเนิดมาจาก MSIL, LLVM, Java bytecode หรือโครงสร้างพื้นฐานที่ทันสมัยอื่น ๆ การใช้กลยุทธ์นี้เร็วที่สุดที่ฉันทราบคือเครื่อง pcodeจากปี 1966

สิ่งแรกที่ฉันได้ยินเกี่ยวกับแนวคิดนี้คือเมื่อฉันได้เรียนรู้ว่าผู้วางระบบ Infocom สามารถจัดการให้Zorkทำงานบนเครื่องที่แตกต่างกันมากมายได้อย่างไร พวกเขาระบุเครื่องเสมือนที่เรียกว่าZ-machineจากนั้นสร้าง Z-machine emulators สำหรับฮาร์ดแวร์ทั้งหมดที่พวกเขาต้องการเรียกใช้เกมของพวกเขา สิ่งนี้มีประโยชน์มากมายมหาศาลที่พวกเขาสามารถใช้การจัดการหน่วยความจำเสมือนบนระบบ 8 บิตดั้งเดิม เกมอาจมีขนาดใหญ่เกินกว่าจะใส่ลงในหน่วยความจำได้เพราะพวกเขาสามารถใส่โค้ดจากดิสก์เมื่อพวกเขาต้องการและละทิ้งมันเมื่อพวกเขาต้องการโหลดโค้ดใหม่


63
ว้าว. นั่นเป็นสิ่งที่ฉันกำลังมองหา วิธีที่ดีที่สุดในการรับคำตอบคือการได้รับจากนักพัฒนาหลักเอง ขอบคุณสำหรับเวลาและฉันแน่ใจว่าสิ่งนี้จะช่วยให้ทุกคนที่สงสัยความซับซ้อนของคอมไพเลอร์และ MSIL ขอบคุณ Eric
Jan Carlo Viray

18
นั่นคือคำตอบที่ดี เตือนฉันว่าทำไมฉันถึงอ่านบล็อกของคุณแม้ว่าฉันจะเป็นคนชวาก็ตาม ;-)
jprete

34
@JanCarloViray: คุณยินดีมาก! ผมทราบว่าผมผู้พัฒนาหลักไม่นักพัฒนาหลัก มีหลายคนในทีมนี้ที่มีตำแหน่งงานนั้นและฉันไม่ได้เป็นคนที่อาวุโสที่สุดของพวกเขา
Eric Lippert

17
@Eric: ถ้า / เมื่อคุณหยุดรักการเขียนโปรแกรมคุณควรพิจารณาไปสอนโปรแกรมเมอร์ นอกจากความสนุกแล้วคุณยังสามารถทำการฆ่าโดยปราศจากแรงกดดันทางธุรกิจ ไหวพริบที่ยอดเยี่ยมคือสิ่งที่คุณได้รับในพื้นที่นั้น (และความอดทนที่ยอดเยี่ยมฉันอาจเพิ่ม) ฉันพูดแบบนั้นในฐานะอดีตอาจารย์มหาวิทยาลัย
อลัน

19
ประมาณ 4 ย่อหน้าที่ฉันพูดกับตัวเองว่า "เสียงนี้เหมือนเอริค" ในวันที่ 5 หรือ 6 ฉันเรียนจบที่ "ใช่แน่นอนเอริค" :) อีกคำตอบที่ครอบคลุมอย่างแท้จริง
Binary Worrier

86

โปรดทราบว่าเมื่อคุณพูดถึง MSIL คุณจะพูดถึงคำแนะนำสำหรับเครื่องเสมือน VM ที่ใช้ใน. NET เป็นเครื่องเสมือนแบบกองซ้อน ตรงข้ามกับ VM ที่ใช้การลงทะเบียนDalvik VM ที่ใช้ในระบบปฏิบัติการ Android เป็นตัวอย่างของสิ่งนั้น

สแต็คใน VM เป็นเสมือนมันขึ้นอยู่กับล่ามหรือคอมไพเลอร์ทันเวลาเพื่อแปลคำสั่ง VM เป็นรหัสจริงที่ทำงานบนโปรเซสเซอร์ ซึ่งในกรณีของ. NET นั้นมักจะกระวนกระวายใจชุดคำสั่ง MSIL ได้รับการออกแบบมาเพื่อให้ถูก jitted จากการเริ่มต้น ตรงกันข้ามกับ Java bytecode ตัวอย่างเช่นมันมีคำแนะนำที่ชัดเจนสำหรับการดำเนินการกับชนิดข้อมูลที่เฉพาะเจาะจง ซึ่งทำให้ปรับให้เหมาะสมที่จะตีความ ตัวแปล MSIL นั้นมีอยู่จริง แต่จะใช้ใน. NET Micro Framework ซึ่งทำงานบนโปรเซสเซอร์ที่มีทรัพยากร จำกัด มากไม่สามารถซื้อ RAM ได้เพื่อจัดเก็บรหัสเครื่อง

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

สแต็กของเครื่องนั้นเป็นหน่วยความจำพื้นฐานที่ได้รับการออกแบบโปรเซสเซอร์เป็นเวลานาน มันมีตำแหน่งอ้างอิงที่ดีมากคุณสมบัติที่สำคัญมากสำหรับซีพียูสมัยใหม่ที่เคี้ยวผ่านข้อมูลเร็วกว่า RAM มากสามารถให้มันและรองรับการเรียกซ้ำ การออกแบบภาษาได้รับอิทธิพลอย่างมากจากการมีสแต็กที่มองเห็นได้ในการสนับสนุนตัวแปรท้องถิ่นและขอบเขต จำกัด ให้วิธีการร่างกาย ปัญหาที่สำคัญของสแต็กคือปัญหาที่ไซต์นี้ตั้งชื่อให้


2
+1 สำหรับคำอธิบายรายละเอียดมากและ 100 (ถ้าฉันสามารถทำได้) เพื่อเปรียบเทียบรายละเอียดเป็นพิเศษกับระบบอื่น ๆ และภาษา :)
ม.ค. คาร์โล Viray

4
ทำไม Dalvik เป็นเครื่องลงทะเบียน Sicne มีเป้าหมายหลักที่ ARM Processors ตอนนี้ x86 มีจำนวนการลงทะเบียนเท่ากัน แต่เป็น CISC มีเพียง 4 คนเท่านั้นที่ใช้งานได้จริงสำหรับการจัดเก็บคนในท้องถิ่นเพราะส่วนที่เหลือนั้นใช้โดยนัยในคำแนะนำทั่วไป ในทางกลับกันสถาปัตยกรรม ARM นั้นมีรีจิสเตอร์จำนวนมากที่สามารถใช้ในการจัดเก็บคนในท้องถิ่นได้
โยฮันเนสรูดอล์ฟ

1
@JohannesRudolph นั่นไม่ได้เป็นจริงมาเกือบสองทศวรรษแล้ว เพียงเพราะคอมไพเลอร์ C ++ ส่วนใหญ่ยังคงตั้งเป้าชุดคำสั่ง x86 90s ไม่ได้หมายความว่า x86 นั้นมีประสิทธิภาพ Haswell มีการลงทะเบียนจำนวนเต็ม 168 จุดประสงค์ทั่วไปและการลงทะเบียน 168 GP AVX ตัวอย่าง - มากกว่า CPU ARM ที่ฉันรู้จัก คุณสามารถใช้ทุกอย่างจากแอสเซมบลี x86 (ทันสมัย) ในแบบที่คุณต้องการ ตำหนิผู้เขียนคอมไพเลอร์ไม่ใช่สถาปัตยกรรม / CPU ในความเป็นจริงนั้นเป็นหนึ่งในสาเหตุที่การรวบรวมระดับกลางมีความน่าสนใจมาก - หนึ่งไบนารีเป็นรหัสที่ดีที่สุดสำหรับ CPU ที่กำหนด ไม่มีการล้อเล่นกับสถาปัตยกรรมยุค 90
Luaan

2
@JohannesRudolph คอมไพเลอร์. NET JIT ใช้การลงทะเบียนค่อนข้างหนัก สแต็กส่วนใหญ่เป็นนามธรรมของเครื่องเสมือน IL รหัสที่ทำงานบน CPU ของคุณแตกต่างกันมาก วิธีการโทรอาจเป็นแบบ pass-by register คนในท้องถิ่นอาจถูกยกขึ้นเพื่อลงทะเบียน ... ประโยชน์หลักของ stack ในรหัสเครื่องคือการแยกมันให้การเรียกรูทีนย่อย - ถ้าคุณใส่ local ใน register การเรียกฟังก์ชันอาจทำได้ คุณสูญเสียคุณค่านั้นไปและคุณบอกไม่ได้จริงๆ
Luaan

1
@RahulAgarwal รหัสเครื่องที่สร้างขึ้นอาจมีหรือไม่มีการใช้สแต็คสำหรับค่าท้องถิ่นหรือค่ากลางที่กำหนด ใน IL ทุกอาร์กิวเมนต์และโลคัลอยู่บนสแต็ก - แต่ในรหัสเครื่องสิ่งนี้ไม่เป็นความจริง (อนุญาต แต่ไม่จำเป็น) บางสิ่งมีประโยชน์ในสแต็กและวางลงบนสแต็ก บางสิ่งมีประโยชน์ในกองและพวกเขาก็วางกอง บางสิ่งบางอย่างไม่จำเป็นเลยหรือต้องการเวลาเพียงเล็กน้อยในการลงทะเบียน สามารถตัดการโทรออกทั้งหมด (inlined) หรืออาจมีการโต้แย้งในการลงทะเบียน JIT มีอิสระมากมาย
Luaan

20

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

  • รหัสวัตถุขนาดกะทัดรัดมาก
  • ตัวแปล / ตัวแปลอย่างง่าย
  • สถานะตัวประมวลผลน้อยที่สุด

-1 @xanatos คุณลองและสรุปหัวเรื่องที่คุณถ่ายได้ไหม?
ทิมลอยด์

@chibacity หากฉันต้องการที่จะสรุปพวกเขาฉันจะทำคำตอบ ฉันพยายามกู้ลิงค์ที่ดีมาก
xanatos

@xanatos ฉันเข้าใจเป้าหมายของคุณ แต่การแชร์ลิงก์ไปยังบทความวิกิพีเดียขนาดใหญ่นั้นไม่ใช่คำตอบที่ดี มันไม่ยากที่จะหาเพียงแค่ googling ในทางกลับกันฮันส์มีคำตอบที่ดี
ทิมลอยด์

@chibacity OP อาจจะขี้เกียจไม่ได้ค้นหาก่อน ผู้ตอบที่นี่ให้ลิงค์ที่ดี (โดยไม่อธิบาย) ความชั่วร้ายสองอย่างทำสิ่งที่ดีอย่างหนึ่ง :-) และฉันจะทำลายฮันส์
xanatos

เพื่อ answerer และ @xanatos +1 สำหรับลิงก์ที่ยอดเยี่ยม ฉันรอให้ใครซักคนสรุปและมีคำตอบชุดความรู้ .. หากฮันส์ไม่ได้ให้คำตอบฉันจะทำให้คุณเป็นคำตอบที่ได้รับการยอมรับ .. มันเป็นแค่ลิงค์เท่านั้นดังนั้นมันจึงไม่ใช่ ยุติธรรมสำหรับฮันส์ที่ใช้ความพยายามอย่างดีกับคำตอบของเขา .. :)
ม.ค. Carlo Viray

8

หากต้องการเพิ่มคำถามอีกเล็กน้อย แนวคิดสแต็กมาจากการออกแบบ CPU โดยที่รหัสเครื่องในหน่วยคำนวณตรรกะ (ALU) ทำงานกับตัวถูกดำเนินการที่อยู่บนสแต็ก ตัวอย่างเช่นการดำเนินการทวีคูณอาจนำตัวถูกดำเนินการสองอันดับแรกจากสแต็กหลายรายการและวางผลลัพธ์กลับมาบนสแต็ก ภาษาเครื่องโดยทั่วไปมีสองฟังก์ชันพื้นฐานเพื่อเพิ่มและลบตัวถูกดำเนินการออกจากสแต็ก ผลักดันและ POP ในซีพียู dsp หลายตัว (ตัวประมวลผลสัญญาณดิจิตอล) และตัวควบคุมเครื่อง (เช่นการควบคุมเครื่องซักผ้า) สแต็กจะอยู่บนชิปตัวเอง ทำให้สามารถเข้าถึง ALU ได้เร็วขึ้นและรวมการทำงานที่จำเป็นไว้ในชิปตัวเดียว


5

หากไม่ได้ติดตามแนวคิดของ stack / heap และข้อมูลถูกโหลดไปยังตำแหน่งหน่วยความจำแบบสุ่มหรือข้อมูลถูกเก็บจากตำแหน่งหน่วยความจำแบบสุ่ม ... มันจะไม่มีโครงสร้างและไม่มีการจัดการมาก

แนวคิดเหล่านี้ใช้เพื่อจัดเก็บข้อมูลในโครงสร้างที่กำหนดไว้ล่วงหน้าเพื่อปรับปรุงประสิทธิภาพการใช้หน่วยความจำ ... และเรียกว่าโครงสร้างข้อมูล


4

หนึ่งสามารถมีระบบการทำงานโดยไม่ต้องกองโดยใช้รูปแบบการส่งต่อของการเข้ารหัส จากนั้นเฟรมการเรียกจะกลายเป็นความต่อเนื่องที่จัดสรรในฮีปที่รวบรวมขยะ (ตัวรวบรวมขยะจะต้องมีสแต็กบางส่วน)

ดูงานเขียนเก่าของ Andrew Appel: การรวบรวมด้วย ContinuationsและGarbage Collection อาจเร็วกว่าการจัดสรรแบบแยกส่วน

(เขาอาจจะผิดเล็กน้อยในวันนี้เนื่องจากปัญหาแคช)


0

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

นอกจากนี้ยังมีครอบครัวของภาษาสแต็คที่เรียกว่าภาษาการเชื่อม พวกเขาเป็นภาษาที่ใช้งานได้ทั้งหมด (ฉันเชื่อ) เพราะสแต็กเป็นพารามิเตอร์ที่ส่งผ่านโดยนัยและสแต็กที่ถูกเปลี่ยนเป็นผลตอบแทนโดยปริยายจากแต่ละฟังก์ชัน ทั้งForthและFactor (ซึ่งยอดเยี่ยม) เป็นตัวอย่างพร้อมกับคนอื่น ๆ ตัวประกอบถูกนำมาใช้คล้ายกับ Lua สำหรับเกมการเขียนสคริปต์และเขียนโดย Slava Pestov อัจฉริยะที่ปัจจุบันทำงานกับ Apple Google TechTalkของเขาใน youtubeฉันได้ดูสองสามครั้ง เขาพูดเกี่ยวกับผู้สร้างโบอา แต่ฉันไม่แน่ใจว่าเขาหมายถึงอะไร ;-)

ฉันคิดว่า VM ปัจจุบันบางอย่างเช่น JVM, CIL ของ Microsoft และแม้แต่ภาษาที่ฉันเห็นถูกเขียนขึ้นสำหรับ Lua ควรเขียนด้วยภาษาสแต็กเหล่านี้เพื่อให้สามารถพกพาไปยังแพลตฟอร์มอื่น ๆ ได้ ฉันคิดว่าภาษาที่ต่อกันเหล่านี้ขาดการเรียกใช้ของพวกเขาเป็นชุดการสร้าง VM และแพลตฟอร์มการพกพา มีแม้แต่ pForth ซึ่งเป็น "พกพา" ที่เขียนใน ANSI C ซึ่งสามารถใช้สำหรับการพกพาที่เป็นสากลมากยิ่งขึ้น มีใครพยายามรวบรวมโดยใช้ Emscripten หรือ WebAssembly?

ด้วยภาษาที่อิงกับสแต็กมีรูปแบบของโค้ดที่เรียกว่า zero-point เนื่องจากคุณสามารถแสดงรายการฟังก์ชันที่จะเรียกได้โดยไม่ต้องผ่านพารามิเตอร์ใด ๆ เลย (ในบางครั้ง) หากฟังก์ชั่นเข้าด้วยกันอย่างสมบูรณ์แบบคุณจะไม่มีอะไรนอกจากรายการฟังก์ชั่น zero-point ทั้งหมดและนั่นเป็นแอปพลิเคชั่นของคุณ หากคุณเจาะลึกลงไปใน Forth หรือ Factor คุณจะเห็นสิ่งที่ฉันกำลังพูดถึง

ที่Easy Forthบทแนะนำออนไลน์ที่ดีที่เขียนด้วย JavaScript นี่คือตัวอย่างเล็ก ๆ (หมายเหตุ "sq sq sq sq" เป็นตัวอย่างของรูปแบบการโทรแบบ zero-point):

: sq dup * ;  ok
2 sq . 4  ok
: ^4 sq sq ;  ok
2 ^4 . 16  ok
: ^8 sq sq sq sq ;  ok
2 ^8 . 65536  ok

นอกจากนี้หากคุณดูที่หน้าเว็บของ Easy Forth คุณจะเห็นด้านล่างว่ามันเป็นโมดูลที่เขียนในไฟล์ JavaScript ประมาณ 8 ไฟล์

ฉันใช้เงินเป็นจำนวนมากในหนังสือ Forth ทุกเล่มที่ฉันสามารถใช้เพื่อพยายามที่จะดูดซึม Forth แต่ตอนนี้ฉันเพิ่งเริ่มจะห้อมล้อมมันได้ดีขึ้น ฉันต้องการให้หัวกับผู้ที่มาหลังจากถ้าคุณต้องการที่จะได้รับจริง ๆ (ฉันพบสิ่งนี้สายเกินไป) รับหนังสือเกี่ยวกับ FigForth และดำเนินการนั้น Forths เชิงพาณิชย์นั้นซับซ้อนเกินไปและสิ่งที่ยิ่งใหญ่ที่สุดเกี่ยวกับ Forth ก็คือมันเป็นไปได้ที่จะเข้าใจทั้งระบบจากบนลงล่าง ยังไงก็เถอะ Forth ใช้สภาพแวดล้อมการพัฒนาทั้งหมดในโปรเซสเซอร์ใหม่และถึงแม้ว่าจะจำเป็นสำหรับสิ่งที่ดูเหมือนว่าจะผ่านกับ C ในทุกสิ่งมันยังคงมีประโยชน์ในฐานะพิธีทางที่จะเขียน Forth ตั้งแต่เริ่มต้น ดังนั้นถ้าคุณเลือกที่จะทำเช่นนี้ลองหนังสือ FigForth - มันเป็น Forth หลายตัวที่นำมาใช้พร้อมกันในโปรเซสเซอร์ที่หลากหลาย หิน Rosetta ชนิดหนึ่งของ Forths

ทำไมเราต้องใช้สแต็ค - ประสิทธิภาพการเพิ่มประสิทธิภาพจุดศูนย์บันทึกการลงทะเบียนเมื่อขัดจังหวะและอัลกอริทึมแบบเรียกซ้ำมันเป็น "รูปร่างที่เหมาะสม"

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