คำสั่งเครื่องเสมือน Java ประกอบด้วยโค้ดการดำเนินการที่มีความยาวไบต์ (Opcode) ที่แสดงความหมายเฉพาะ ตามด้วยตัวถูกดำเนินการเป็นศูนย์หรือมากกว่าที่แสดงถึงพารามิเตอร์การดำเนินการ คำแนะนำมากมายในเครื่องเสมือนไม่มีตัวถูกดำเนินการ มีเพียง opcode เท่านั้น หากละเว้นข้อยกเว้น ตัวแปล JVM จะสามารถทำงานได้อย่างมีประสิทธิภาพด้วยโค้ดเพียงโค้ดเดียว
คัดลอกรหัสรหัส ดังต่อไปนี้:
ทำ{
คำนวณการลงทะเบียน PC โดยอัตโนมัติและดึง opcode จากตำแหน่งการลงทะเบียน PC
ถ้า (มีตัวถูกดำเนินการ) ให้ลบตัวถูกดำเนินการออก
ดำเนินการตามที่กำหนดโดย opcode
} ในขณะที่ (ประมวลผลลูปถัดไป)
จำนวนและความยาวของตัวถูกดำเนินการขึ้นอยู่กับ opcode หากความยาวของตัวถูกดำเนินการเกินหนึ่งไบต์ มันจะถูกจัดเก็บในลำดับ Big-Endian (โค้ดไบต์แรกระดับไฮเอนด์) และค่าควรเป็น (byte1<<8) | ไบต์2.
สตรีมคำสั่ง bytecode ถูกจัดตำแหน่งแบบไบต์เดียว ยกเว้นคำสั่ง "tableswitch" และ "lookupswitch" ตัวถูกดำเนินการเป็นแบบพิเศษและถูกหารด้วย 4 ไบต์ที่สอดคล้องกันเพื่อให้บรรลุการจัดตำแหน่ง
การจำกัดความยาวของ opcode เครื่องเสมือน Java ไว้ที่หนึ่งไบต์ และละทิ้งการจัดตำแหน่งความยาวพารามิเตอร์ของโค้ดที่คอมไพล์แล้วคือการได้รับโค้ดที่คอมไพล์แบบสั้นและแบบ Lean แม้ว่าการดำเนินการ JVM อาจทำให้ต้นทุนด้านประสิทธิภาพบางอย่างต้องเสียค่าใช้จ่ายก็ตาม เนื่องจาก opcode สามารถมีความยาวได้เพียง 1 ไบต์เท่านั้น จึงจำกัดจำนวนชุดคำสั่ง และไม่ถือว่าข้อมูลได้รับการจัดเรียงอย่างดี ซึ่งหมายความว่าเมื่อข้อมูลมีขนาดเกิน 1 ไบต์ โครงสร้างข้อมูลเฉพาะจะต้องถูกสร้างขึ้นใหม่จาก ไบต์ ประสิทธิภาพบางอย่างจะหายไป
ชนิดข้อมูลและ Java Virtual Machine
ในชุดคำสั่งใน JVM คำสั่งส่วนใหญ่จะมีข้อมูลประเภทข้อมูลที่สอดคล้องกับการดำเนินการ ตัวอย่างเช่น คำสั่ง iload จะโหลดข้อมูลประเภท int จากตารางตัวแปรโลคัลลงในสแต็กตัวถูกดำเนินการ ในขณะที่ fload จะโหลดข้อมูลประเภท float
สำหรับคำสั่งไบต์โค้ดส่วนใหญ่ที่เกี่ยวข้องกับประเภทข้อมูล ตัวช่วยจำ opcode จะมีอักขระพิเศษเพื่อระบุ: i หมายถึงประเภท int, l หมายถึงยาว, s หมายถึงสั้น, b หมายถึงไบต์, c หมายถึงถ่าน, f หมายถึง float, d หมายถึง double และ ย่อมาจากการอ้างอิง มีคำสั่งแยกต่างหากที่สามารถใช้เพื่อแปลงประเภทที่ไม่รองรับเป็นประเภทที่รองรับเมื่อจำเป็น
คำแนะนำในการโหลดและจัดเก็บ
คำแนะนำในการโหลดและจัดเก็บใช้เพื่อถ่ายโอนข้อมูลเข้าและออกจากตารางตัวแปรโลคัลของเฟรมสแต็กและสแต็กตัวถูกดำเนินการ
1) คำแนะนำในการโหลดตัวแปรโลคัลลงในโอเปอเรเตอร์สแต็ก ได้แก่: iload, iload_<n>, lload, lload_<n>, float, fload_<n>, dload, dload_<n>, aload, aload_<n>
2) คำแนะนำในการจัดเก็บค่าจากสแต็กตัวถูกดำเนินการไปยังตัวแปรโลคัล: istore,istore_<n>,lstore,lstore_<n>,fstore,fstore_<n>,dstore,dstore_<n>,astore,astore_<n>
3) คำแนะนำในการโหลดค่าคงที่ลงในสแต็กตัวถูกดำเนินการ: bipush, sipush, ldc, ldc_w, ldc2_w, aconst_null, Iconst_ml, Iconst_<i>, lconst_<l>, fconst_<f>, dconst_<d>
4) คำสั่งดัชนีการเข้าถึงของตารางตัวแปรท้องถิ่น: กว้าง
คำสั่งบางคำสั่งที่ลงท้ายด้วยวงเล็บมุมแสดงถึงกลุ่มของคำสั่ง เช่น iload_<i> ซึ่งหมายถึง iload_0, iload_1 เป็นต้น กลุ่มคำสั่งเหล่านี้เป็นคำสั่งทั่วไปที่มีตัวถูกดำเนินการเพียงตัวเดียว
คำแนะนำการใช้งาน
คำสั่งทางคณิตศาสตร์ใช้เพื่อดำเนินการเฉพาะกับค่าบนสแต็กตัวถูกดำเนินการทั้งสองและจัดเก็บผลลัพธ์ไว้ที่ด้านบนของสแต็กการดำเนินการ
1) คำแนะนำเพิ่มเติม: iadd,ladd,fadd,dadd
2) คำแนะนำการลบ: isub, lsub, fsub, dsub
3) คำแนะนำการคูณ: imul, lmul, fmul, dmul
4) คำแนะนำการแบ่ง: idiv, ldiv, fdiv, ddiv
5) คำแนะนำที่เหลือ: irem, lrem, frem, drem
6) คำแนะนำเชิงลบ: ineg, length, fneg, dneg
7) คำแนะนำในการเคลื่อนที่: ishl,ishr,iushr,lshl,lshr,lusr
8) Bitwise หรือคำสั่ง: ior, lor
9) Bitwise และคำสั่ง: iand, land
10) คำสั่ง Bitwise XOR: ixor, lxor
11) คำสั่งการเพิ่มตัวแปรโลคัล: iinc
12) คำแนะนำในการเปรียบเทียบ: dcmpg, dcmpl, fcmpg, fcmpl, lcmp
เครื่องเสมือน Java ไม่ได้กำหนดอย่างชัดเจนถึงการล้นของข้อมูลจำนวนเต็ม แต่กำหนดว่าเมื่อประมวลผลข้อมูลจำนวนเต็ม คำสั่งการหารและเศษเท่านั้นที่จะทำให้เครื่องเสมือนส่งข้อยกเว้นเมื่อตัวหารเป็น 0
คำแนะนำในการโหลดและจัดเก็บ
คำแนะนำในการโหลดและจัดเก็บใช้เพื่อถ่ายโอนข้อมูลเข้าและออกจากตารางตัวแปรโลคัลของเฟรมสแต็กและสแต็กตัวถูกดำเนินการ
1) คำแนะนำในการโหลดตัวแปรโลคัลลงในโอเปอเรเตอร์สแต็ก ได้แก่: iload, iload_<n>, lload, lload_<n>, float, fload_<n>, dload, dload_<n>, aload, aload_<n>
2) คำแนะนำในการจัดเก็บค่าจากสแต็กตัวถูกดำเนินการไปยังตัวแปรโลคัล: istore,istore_<n>,lstore,lstore_<n>,fstore,fstore_<n>,dstore,dstore_<n>,astore,astore_<n>
3) คำแนะนำในการโหลดค่าคงที่ลงในสแต็กตัวถูกดำเนินการ: bipush, sipush, ldc, ldc_w, ldc2_w, aconst_null, Iconst_ml, Iconst_<i>, lconst_<l>, fconst_<f>, dconst_<d>
4) คำสั่งดัชนีการเข้าถึงของตารางตัวแปรท้องถิ่น: กว้าง
คำสั่งบางคำสั่งที่ลงท้ายด้วยวงเล็บมุมแสดงถึงกลุ่มของคำสั่ง เช่น iload_<i> ซึ่งหมายถึง iload_0, iload_1 เป็นต้น กลุ่มคำสั่งเหล่านี้เป็นคำสั่งทั่วไปที่มีตัวถูกดำเนินการเพียงตัวเดียว
คำแนะนำการใช้งาน
คำสั่งทางคณิตศาสตร์ใช้เพื่อดำเนินการเฉพาะกับค่าบนสแต็กตัวถูกดำเนินการทั้งสองและจัดเก็บผลลัพธ์ไว้ที่ด้านบนของสแต็กการดำเนินการ
1) คำแนะนำเพิ่มเติม: iadd,ladd,fadd,dadd
2) คำแนะนำการลบ: isub, lsub, fsub, dsub
3) คำแนะนำการคูณ: imul, lmul, fmul, dmul
4) คำแนะนำการแบ่ง: idiv, ldiv, fdiv, ddiv
5) คำแนะนำที่เหลือ: irem, lrem, frem, drem
6) คำแนะนำเชิงลบ: ineg, length, fneg, dneg
7) คำแนะนำในการเคลื่อนที่: ishl,ishr,iushr,lshl,lshr,lusr
8) Bitwise หรือคำสั่ง: ior, lor
9) Bitwise และคำสั่ง: iand, land
10) คำสั่ง Bitwise XOR: ixor, lxor
11) คำสั่งการเพิ่มตัวแปรโลคัล: iinc
12) คำแนะนำในการเปรียบเทียบ: dcmpg, dcmpl, fcmpg, fcmpl, lcmp
เครื่องเสมือน Java ไม่ได้กำหนดอย่างชัดเจนถึงการล้นของข้อมูลจำนวนเต็ม แต่กำหนดว่าเมื่อประมวลผลข้อมูลจำนวนเต็ม คำสั่งการหารและเศษเท่านั้นที่จะทำให้เครื่องเสมือนส่งข้อยกเว้นเมื่อตัวหารเป็น 0
คำแนะนำการแปลงประเภท
คำแนะนำในการแปลงประเภทจะแปลงประเภทตัวเลขของเครื่องเสมือน Java สองประเภทให้กันและกัน โดยทั่วไปการดำเนินการเหล่านี้จะใช้เพื่อดำเนินการแปลงประเภทที่ชัดเจนในโค้ดผู้ใช้
JVM รองรับการแปลงประเภทที่กว้างขึ้น (การแปลงประเภทช่วงขนาดเล็กเป็นการแปลงประเภทช่วงขนาดใหญ่):
1) ประเภท Int เป็นประเภทยาว, ลอย, ประเภทคู่
2) แบบยาวแบบลอย แบบดับเบิ้ล
3) ลอยเป็นประเภทคู่
คำแนะนำการแปลงแบบแคบ: i2b, i2c, i2s, l2i, f2i, f2l, d2l และ d2f การแปลงแบบแคบอาจทำให้ผลลัพธ์การแปลงสร้างสัญญาณและลำดับความสำคัญที่แตกต่างกัน ตัวอย่างเช่น เมื่อแปลงประเภท int หรือ long เป็นจำนวนเต็มประเภท T กระบวนการแปลงจะละทิ้งเนื้อหาที่ไม่คาดคิดซึ่งมีขนาด N ไบต์ต่ำสุดเท่านั้น (N คือความยาวของประเภทข้อมูลประเภท T)
การสร้างและการจัดการวัตถุ
แม้ว่าคลาสอินสแตนซ์และอาร์เรย์จะเป็นทั้งอ็อบเจ็กต์ แต่เครื่องเสมือน Java จะใช้คำสั่งรหัสไบต์ที่แตกต่างกันสำหรับการสร้างและการทำงานของอินสแตนซ์คลาสและอาร์เรย์
1) คำแนะนำในการสร้างอินสแตนซ์: ใหม่
2) คำแนะนำสำหรับการสร้างอาร์เรย์: newarray, anewarray, multianewarray
3) คำแนะนำในการเข้าถึงฟิลด์: getfield, putfield, getstatic, putstatic
4) โหลดองค์ประกอบอาร์เรย์ลงในคำสั่งสแต็กตัวถูกดำเนินการ: baload, caload, saload, iaload, laload, faload, daload, aaload
5) เก็บค่าของสแต็กตัวถูกดำเนินการลงในองค์ประกอบอาร์เรย์และดำเนินการ: bastore,castore,castore,sastore,iastore,fastore,dastore,aastore
6) รับคำสั่งความยาวอาเรย์: arraylength
7) ตรวจสอบคำแนะนำประเภทอินสแตนซ์: instanceof, checkcast
คำแนะนำการจัดการสแต็กตัวถูกดำเนินการ
คำแนะนำที่ใช้งานสแต็กตัวถูกดำเนินการโดยตรง: pop, pop2, dup, dup2, dup_x1, dup2_x1, dup_x2, dup2_x2 และ swap
ควบคุมคำสั่งการถ่ายโอน
อนุญาตให้ JVM ดำเนินการโปรแกรมต่อแบบมีเงื่อนไขหรือไม่มีเงื่อนไขจากคำสั่งตามคำสั่งที่ระบุ แทนที่จะใช้คำสั่งถ่ายโอนการควบคุม คำแนะนำในการถ่ายโอนการควบคุมประกอบด้วย:
1) สาขาแบบมีเงื่อนไข: ifeq, iflt, ifle, ifne, ifgt, ifge, ifnull, ifnotnull, if_cmpeq, if_icmpne, if_icmlt, if_icmpgt เป็นต้น
2) สาขาเงื่อนไขแบบผสม: tableswitch, lookupswitch
3) สาขาที่ไม่มีเงื่อนไข: goto,goto_w,jsr,jsr_w,ret
มีชุดคำสั่งพิเศษใน JVM เพื่อจัดการการดำเนินการเปรียบเทียบสาขาแบบมีเงื่อนไขของ int และประเภทการอ้างอิง เพื่อระบุอย่างชัดเจนว่าค่าเอนทิตีเป็นโมฆะหรือไม่ มีคำสั่งพิเศษในการตรวจจับค่า null การดำเนินการเปรียบเทียบสาขาแบบมีเงื่อนไขของประเภทบูลีนและประเภทไบต์ ประเภทถ่าน และประเภทสั้นทั้งหมดเสร็จสิ้นโดยใช้คำแนะนำในการเปรียบเทียบประเภท int ในขณะที่การดำเนินการเปรียบเทียบสาขาแบบมีเงื่อนไขแบบยาว ลอย และแบบมีเงื่อนไขสองครั้งจะดำเนินการโดยคำแนะนำการดำเนินการเปรียบเทียบของประเภทที่สอดคล้องกัน และการดำเนินการ คำแนะนำจะส่งคืนค่าจำนวนเต็มจะถูกเพิ่มลงในสแต็กตัวถูกดำเนินการ จากนั้นจะมีการดำเนินการเปรียบเทียบแบบมีเงื่อนไขของประเภท int เพื่อให้การข้ามสาขาทั้งหมดเสร็จสมบูรณ์ การเปรียบเทียบทุกประเภทจะถูกแปลงเป็นการดำเนินการเปรียบเทียบประเภท int ในที่สุด
วิธีการโทรและกลับคำแนะนำ
เรียกใช้คำสั่งเสมือน: เรียกวิธีการอินสแตนซ์ของวัตถุและจัดส่งตามประเภทที่แท้จริงของวัตถุ (การจัดส่งเครื่องเสมือน)
คำสั่งเรียกใช้อินเทอร์เฟซ: เรียกใช้วิธีอินเทอร์เฟซ ค้นหาอ็อบเจ็กต์ที่ใช้วิธีการอินเทอร์เฟซนี้ขณะรันไทม์ และค้นหาวิธีที่เหมาะสมในการโทร
invokespecial: วิธีการเรียกใช้อินสแตนซ์ที่ต้องใช้การประมวลผลพิเศษ รวมถึงวิธีการเริ่มต้นอินสแตนซ์ วิธีการส่วนตัว และวิธีการคลาสพาเรนต์
invinestatic: วิธีการเรียนการโทร (คงที่)
คำแนะนำการส่งคืนเมธอดจะแตกต่างกันตามประเภทของค่าส่งคืน รวมถึง ireturn (ค่าส่งคืนคือบูลีน, ไบต์, ถ่าน, แบบสั้นและ int), lreturn, freturn, drturn และ areturn อีกวิธีหนึ่งที่ส่งคืนสำหรับวิธี void ซึ่งเป็นวิธีการเริ่มต้นอินสแตนซ์ , คลาส และ ใช้วิธีการเริ่มต้นคลาส i ของอินเทอร์เฟซ
ซิงโครนัส
JVM รองรับการซิงโครไนซ์ระดับเมธอดและการซิงโครไนซ์ลำดับของคำสั่งภายในเมธอด ซึ่งทั้งสองอย่างนี้ถูกนำไปใช้ผ่านมอนิเตอร์
การซิงโครไนซ์ระดับเมธอดเป็นแบบโดยนัยและไม่จำเป็นต้องควบคุมผ่านคำสั่งไบต์โค้ด มันถูกนำไปใช้ในการเรียกเมธอดและการดำเนินการส่งคืน เครื่องเสมือนแยกแยะว่าเป็นวิธีการแบบซิงโครนัสจากค่าสถานะ ACC_SYNCHRONIZED ในโครงสร้างมาตรฐานของวิธีการในพูลค่าคงที่ของวิธีการ เมื่อเรียกใช้เมธอด คำสั่งการเรียกจะตรวจสอบว่าตั้งค่าสถานะไว้หรือไม่ เธรดการดำเนินการจะเก็บมอนิเตอร์ จากนั้นรันเมธอด และสุดท้ายจะปล่อยมอนิเตอร์เมื่อเมธอดเสร็จสมบูรณ์
ซิงโครไนซ์ลำดับของชุดคำสั่ง ซึ่งโดยปกติจะทำเครื่องหมายด้วยบล็อกซิงโครไนซ์ ชุดคำสั่ง JVM มี monitorenter และ monitorexit เพื่อรองรับซีแมนทิกส์ที่ซิงโครไนซ์
การล็อคแบบมีโครงสร้างคือเมื่อแต่ละจอภาพออกจากระหว่างการเรียกเมธอดตรงกับรายการจอภาพก่อนหน้า JVM ตรวจสอบให้แน่ใจว่าการล็อคแบบมีโครงสร้างถูกสร้างขึ้นผ่านกฎสองข้อต่อไปนี้ (T หมายถึงเธรด, M หมายถึงมอนิเตอร์):
1) จำนวนครั้งที่ T ถือ M ในระหว่างการดำเนินการวิธีการจะต้องเท่ากับจำนวนครั้งที่ T ปล่อย M เมื่อวิธีการเสร็จสมบูรณ์
2) ไม่ว่าเวลาใดก็ตาม จะไม่มีสถานการณ์ใดที่ T ปล่อย M มากกว่า T ถือ M