تتكون تعليمات آلة Java الافتراضية من رمز تشغيل بطول البايت (Opcode) يمثل معنى محددًا، متبوعًا بصفر أو أكثر من المعاملات التي تمثل معلمات العملية. لا تحتوي العديد من التعليمات الموجودة في الجهاز الظاهري على معاملات، بل تحتوي فقط على كود تشغيل. إذا تم تجاهل الاستثناء، فيمكن لمترجم JVM العمل بفعالية باستخدام كود واحد فقط.
انسخ رمز الكود كما يلي:
يفعل{
قم بحساب سجل الكمبيوتر تلقائيًا واسترجاع كود التشغيل من موقع تسجيل الكمبيوتر
إذا (المعامل موجود) أخرج المعامل؛
تنفيذ العملية المحددة بواسطة كود التشغيل؛
}أثناء (معالجة الحلقة التالية)
يعتمد عدد المعاملات وطولها على كود التشغيل. إذا تجاوز طول المعامل بايتًا واحدًا، فسيتم تخزينه بترتيب Big-Endian (رمز البايت الأول المتطور)، ويجب أن تكون قيمته (byte1<<8) | بايت2.
يتم محاذاة دفق تعليمات الكود الثانوي ببايت واحد، باستثناء تعليمات "tableswitch" و"lookupswitch". تعتبر معاملاتها خاصة ومقسمة على 4 بايتات، ويجب حجز الفجوات المقابلة لتحقيق المحاذاة.
إن الحد من طول كود تشغيل جهاز Java الظاهري إلى بايت واحد والتخلي عن محاذاة طول المعلمة للتعليمات البرمجية المترجمة هو الحصول على تعليمات برمجية قصيرة ومترجمة، على الرغم من أن ذلك قد يكلف تنفيذ JVM تكلفة أداء معينة. نظرًا لأن طول كود التشغيل يمكن أن يبلغ بايتًا واحدًا فقط، فإنه يحد من عدد مجموعات التعليمات، ولا يفترض أن البيانات متسقة بشكل جيد، مما يعني أنه عندما تتجاوز البيانات بايتًا واحدًا، يجب إعادة بناء بنية البيانات المحددة من سيتم فقدان بعض الأداء.
أنواع البيانات وآلة جافا الافتراضية
في مجموعة التعليمات في JVM، تحتوي معظم التعليمات على معلومات نوع البيانات المقابلة لعملياتها. على سبيل المثال، تقوم تعليمات iload بتحميل بيانات النوع int من جدول المتغير المحلي إلى مكدس المعامل، بينما يقوم fload بتحميل بيانات النوع العائم.
بالنسبة لمعظم تعليمات الكود الثانوي المتعلقة بأنواع البيانات، تحتوي أساليب استذكار كود التشغيل الخاصة بها على أحرف خاصة للإشارة إلى: i يمثل النوع int، وl يمثل طويلًا، وs يمثل القصير، ويمثل b بايت، ويمثل c char، و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 OR: ior، lor
9) تعليمات Bitwise AND: iand، ground
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 OR: ior، lor
9) تعليمات Bitwise AND: iand، ground
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) تحقق من تعليمات نوع المثيل: مثيل، 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) الفرع الشرطي المركب: tablewitch، lookupwitch
3) الفرع غير المشروط: goto,goto_w,jsr,jsr_w,ret
توجد مجموعة تعليمات خاصة في JVM للتعامل مع عمليات مقارنة الفروع الشرطية لأنواع int والمراجع من أجل الإشارة بوضوح إلى ما إذا كانت قيمة الكيان فارغة، هناك تعليمات خاصة للكشف عن القيم الخالية. يتم إكمال جميع عمليات مقارنة الفروع الشرطية من النوع المنطقي ونوع البايت ونوع char والنوع القصير باستخدام تعليمات مقارنة النوع int، في حين يتم تنفيذ عمليات مقارنة الفروع الشرطية الطويلة والعائمة والمزدوجة من خلال تعليمات عملية المقارنة من النوع المقابل، ويتم تنفيذ العملية ستُرجع التعليمات قيمة عددية مضافة إلى مكدس المعامل، ثم يتم إجراء عملية مقارنة مشروطة من النوع int لإكمال قفزة الفرع بالكامل. سيتم في النهاية تحويل جميع أنواع المقارنات إلى عمليات مقارنة من النوع int.
طريقة استدعاء وتعليمات العودة
استدعاء التعليمات الافتراضية: استدعاء أسلوب مثيل الكائن وإرساله وفقًا للنوع الفعلي للكائن (إرسال الجهاز الافتراضي).
تعليمات استدعاء الواجهة: استدعاء طريقة الواجهة، والبحث عن كائن ينفذ طريقة الواجهة هذه في وقت التشغيل، والعثور على الطريقة المناسبة للاتصال.
استدعاء خاص: استدعاء أساليب المثيل التي تتطلب معالجة خاصة، بما في ذلك أساليب تهيئة المثيل والطرق الخاصة وأساليب الفئة الأصلية
invocstatic: طريقة فئة الاتصال (ثابت)
يتم تمييز تعليمات إرجاع الطريقة وفقًا لنوع قيمة الإرجاع، بما في ذلك ireturn (قيمة الإرجاع هي boolean وbyte وchar وshort وint) وlreturn وfreturn وdrturn وareturn يتم استخدام طريقة تهيئة الفئة i للواجهة.
متزامن
يدعم JVM المزامنة على مستوى الطريقة ومزامنة سلسلة من التعليمات داخل الطريقة، وكلاهما يتم تنفيذهما من خلال الشاشات.
المزامنة على مستوى الطريقة ضمنية ولا تحتاج إلى التحكم فيها من خلال تعليمات الرمز الثانوي، ويتم تنفيذها في استدعاءات الطريقة وعمليات الإرجاع. يميز الجهاز الظاهري ما إذا كان أسلوبًا متزامنًا من علامة ACC_SYNCHRONIZED في البنية القياسية للطريقة في التجمع الثابت للطريقة. عند استدعاء الطريقة، ستتحقق تعليمات الاستدعاء مما إذا تم تعيين العلامة، وإذا تم تعيينها، فإن مؤشر ترابط التنفيذ يحمل الشاشة، ثم ينفذ الطريقة، ويحرر الشاشة أخيرًا عند اكتمال الطريقة.
مزامنة سلسلة من مجموعات التعليمات، والتي يتم تمييزها عادةً بكتلة متزامنة. تحتوي مجموعة تعليمات JVM على Monitorenter وMonitorExit لدعم الدلالات المتزامنة.
يتم القفل المنظم عندما يتطابق خروج كل شاشة أثناء استدعاء الأسلوب مع إدخال الشاشة السابق. يضمن JVM إنشاء الأقفال المنظمة من خلال القاعدتين التاليتين (يمثل T خيطًا، ويمثل M شاشة):
1) يجب أن يكون عدد المرات التي يحمل فيها T M أثناء تنفيذ الطريقة مساوياً لعدد المرات التي يطلق فيها T M عند اكتمال الطريقة.
2) في أي وقت، لن يكون هناك موقف حيث يقوم T بتحرير M أكثر من T الذي يحمل M.