פורמט Dalvik בייטקוד

עיצוב כללי

  • מודל המכונה וכללי הקריאה מיועדים לחקות באופן גס ארכיטקטורות אמיתיות נפוצות וכללי קריאה בסגנון C:
    • המכונה מבוססת על מרשם, והפריימים קבועים בגודל בזמן היצירה. כל פריים מורכב ממספר מסוים של מרשם (שצוין על ידי השיטה) וכן מנתוני עזר שנדרשים להפעלת השיטה, כמו (בין היתר) מונה התוכנית והפניה לקובץ .dex שמכיל את השיטה.
    • כשמשתמשים ברשמים לערכים של ביטים (כמו מספרים שלמים ומספרים בספרות עשרוניות צפות), רוחב הרשמים נחשב ל-32 ביט. צמדי מרשם צמודים משמשים לערכים של 64 ביט. אין דרישה ליישור של זוגות של רשומות.
    • כשמשתמשים ברשמים להפניות לאובייקטים, הם נחשבים רחבים מספיק כדי להכיל בדיוק הפניה אחת כזו.
    • במונחים של ייצוג בייט-בייט, (Object) null == (int) 0.
    • הארגומנטים N של השיטה נשמרים בN הרשומות האחרונות של מסגרת ההפעלה של השיטה, לפי הסדר. ארגומנטים רחבים תופסים שני מרשמים. לשיטות של מופעים מועברת הפניה ל-this בתור הארגומנט הראשון שלהן.
  • יחידת האחסון במאגר ההוראות היא כמות של 16 ביט ללא סימן. חלק מהביטים בהוראות מסוימות מתעלמים או חייבים להיות אפס.
  • ההוראות לא מוגבלות באופן מיותר לסוג מסוים. לדוגמה, הוראות שמעבירות ערכים של מרשם 32 ביט ללא פרשנות לא צריכות לציין אם הן מעבירות מספרים שלמים או מספרים עשרוניים.
  • יש מאגרי קבועים נפרדים עם מספרים ואינדקסים להפניות למחרוזות, לסוגי נתונים, לשדות ולשיטות.
  • נתונים ליסטים ביטיים מיוצגים בשורה בזרם ההוראות.
  • בפועל, נדיר שמתודולוגיה זקוקה ליותר מ-16 מרשם, וגם נדיר שמתודולוגיה זקוקה ליותר מ-8 מרשם, ולכן הרבה הוראות מוגבלות רק לטיפול ב-16 המרשמים הראשונים. כשהדבר אפשרי באופן סביר, ההוראות מאפשרות הפניות ל-256 הרשומות הראשונות. בנוסף, להוראות מסוימות יש וריאנטים שמאפשרים מספרים גדולים בהרבה של מרשם, כולל זוג הוראות move לכל מקרה אפשרי שיכולות לטפל במרשמים בטווח v0 עד v65535. במקרים שבהם וריאנט של הוראה לא זמין כדי לטפל ברשומה הרצויה, תוכן הרשומה אמור לעבור מהרשומה המקורית לרשומה נמוכה (לפני הפעולה) ו/או לעבור מרשומת תוצאה נמוכה לרשומה גבוהה (אחרי הפעולה).
  • יש כמה "הוראות פסאודו" שמשמשות לאחסון עומסי נתונים באורך משתנה, שמפנים אליהן באמצעות הוראות רגילות (לדוגמה, fill-array-data). אסור לעולם להיתקל בהוראות כאלה במהלך תהליך הביצוע הרגיל. בנוסף, ההוראות צריכות להיות ממוקמות במרווחים של בייטים בקוד בינארי בספרות זוגיות (כלומר, מותאמות ל-4 בייטים). כדי לעמוד בדרישות האלה, כלים ליצירת קובצי dex חייבים להפיק הוראה nop נוספת כמפריד, אם הוראה כזו לא תהיה מותאמת אחרת. לבסוף, למרות שזה לא נדרש, צפוי שרוב הכלים יבחרו להפיק את ההוראות האלה בסוף השיטות, כי אחרת סביר להניח שיהיה צורך בהוראות נוספות כדי לבצע ניתוח נתונים סביבן.
  • כשמתקינים את הספרייה במערכת שפועלת, יכול להיות שחלק מההוראות ישתנו, ושינוי הפורמט שלהן יתבצע כאופטימיזציה של קישור סטטי בזמן ההתקנה. המטרה היא לאפשר ביצוע מהיר יותר ברגע שהקישור ידוע. תוכלו למצוא את הווריאציות המוצעות במסמך הנחיות הפורמטים המשויך. המילה 'הצעות' כתובה בכוונה תחילה, כי לא חובה להטמיע אותן.
  • תחביר אנושי ומונחי mnemotechnic:
    • סדר הארגומנטים הוא 'יעד ואז מקור'.
    • לחלק מקוד הפקודה יש סיומת שם שמאפשרת להבחין בין סוגי הנתונים שהוא פועל עליהם:
      • אופקודים כלליים מסוג 32 ביט לא מסומנים.
      • קוד הפקודה הכללי של 64 ביט מסתיים ב--wide.
      • קוד הפקודה הספציפי לסוג מסוים מקבל סיומת עם הסוג שלו (או עם קיצור פשוט), אחד מהערכים הבאים: -boolean -byte -char -short -int -long -float -double -object -string -class -void.
    • לחלק מקוד הפקודה יש סיומת להסרת עמימות כדי להבדיל בין פעולות זהות לחלוטין שיש להן פריסות או אפשרויות שונות של הוראות. הסיומת הזו מופרדת מהשמות הראשיים באמצעות קו נטוי (/), והיא קיימת בעיקר כדי ליצור מיפוי אחד-לאחד עם קבועים סטטיים בקוד שיוצר ומפרש קובצי הפעלה (כלומר, כדי לצמצם את הבלבול אצל בני אדם).
    • בתיאורים שבהמשך, רוחב הערך (שמציין, למשל, את הטווח של קבוע או את מספר הרשומות שאפשר לטפל בהן) מודגש באמצעות שימוש בתו לכל ארבעת הביטים של רוחב.
    • לדוגמה, בהוראה "move-wide/from16 vAA, vBBBB":
      • move הוא קוד הפקודה הבסיסי, שמציין את הפעולה הבסיסית (העברת הערך של רישום).
      • wide הוא הסיומת של השם, שמציינת שהוא פועל על נתונים רחבים (64 ביט).
      • from16 הוא הסיומת של קוד הפקודה, שמציינת וריאנט שיש לו הפניה למרשם של 16 ביט כמקור.
      • vAA הוא מרשם היעד (הוא משתמע מהפעולה. שוב, הכלל הוא שהארגומנטים של היעד תמיד מופיעים קודם), והוא חייב להיות בטווח v0 עד v255.
      • 'vBBBB' הוא מרשם המקור, שצריך להיות בטווח v0 עד v65535.
  • במסמך בנושא פורמטים של הוראות מפורט מידע נוסף על הפורמטים השונים של ההוראות (רשימת הפורמטים מופיעה בקטע 'Op & Format'), וכן פרטים על תחביר קוד הפקודה.
  • למידע נוסף על המקום שבו קוד בייטקס נכנס לתמונה הגדולה, אפשר לעיין במסמך בנושא פורמט הקובץ .dex.

סיכום של קבוצת קוד באקס (bytecode)

פעולה ופורמט שיטות לזכירה / תחביר ארגומנטים תיאור
00 10x nop   מחזורי פסולת.

הערה: הוראות פסאודו שמכילות נתונים מתויגות באמצעות קוד הפקודה הזה. במקרה כזה, הבית הבכיר של יחידת קוד הפקודה מציין את אופי הנתונים. מידע נוסף זמין בקטע 'פורמט packed-switch-payload', בקטע 'פורמט sparse-switch-payload' ובקטע 'פורמט fill-array-data-payload' שבהמשך.

01 12x move vA, vB A: מרשם היעד (4 ביט)
B: מרשם המקור (4 ביט)
העברת התוכן של מרשם לא אובייקט אחד למרשם אחר.
02 22x move/from16 vAA, vBBBB A: מרשם היעד (8 ביט)
B: מרשם המקור (16 ביט)
העברת התוכן של מרשם לא אובייקט אחד למרשם אחר.
03 32x move/16 vAAAA, vBBBB A: מרשם היעד (16 ביט)
B: מרשם המקור (16 ביט)
העברת התוכן של מרשם לא אובייקט אחד למרשם אחר.
04 12x vA, ‏ vB ברמת התנועה A: צמד מרשם יעד (4 ביט)
B: צמד מרשם מקור (4 ביט)
העברת התוכן של זוג מרשם אחד למשנהו.

הערה: מותר לעבור מ-vN ל-vN-1 או ל-vN+1, ולכן בהטמעות צריך להגדיר ששני החלקים של זוג הרישום יקראו לפני שכותבים משהו.

05 22x move-wide/from16 vAA, vBBBB A: זוג מרשם יעד (8 ביט)
B: זוג מרשם מקור (16 ביט)
העברת התוכן של זוג מרשם אחד למשנהו.

הערה: השיקולים להטמעה זהים לאלה שמפורטים בקטע move-wide למעלה.

06 32x move-wide/16 vAAAA, vBBBB A: זוג מרשם יעד (16 ביט)
B: זוג מרשם מקור (16 ביט)
העברת התוכן של זוג מרשם אחד למשנהו.

הערה: השיקולים להטמעה זהים לאלה שמפורטים בקטע move-wide למעלה.

07 12x move-object vA, vB A: מרשם יעד (4 ביט)
B: מרשם מקור (4 ביט)
העברת התוכן של מרשם אחד שמכיל אובייקטים למרשם אחר.
08 22x move-object/from16 vAA, vBBBB A: מרשם היעד (8 ביט)
B: מרשם המקור (16 ביט)
העברת התוכן של רשם אחד שמכיל אובייקטים לרשום אחר.
09 32x move-object/16 vAAAA, vBBBB A: מרשם יעד (16 ביט)
B: מרשם מקור (16 ביט)
העברת התוכן של רשם אחד שמכיל אובייקטים לרשום אחר.
0a 11x move-result vAA מרשם היעד A: (8 ביט) מעבירים את התוצאה של invoke-kind האחרונה, שהיא מילה אחת שאינה אובייקט, למרשם שצוין. צריך לעשות זאת כהוראה מיד אחרי invoke-kind שהתוצאה שלו (מילה אחת, לא אובייקט) לא מתעלמת. בכל מקום אחר, הפעולה לא חוקית.
0b 11x move-result-wide vAA זוג של מרשם יעד A: (8 ביט) העברת התוצאה של המילה הכפולה של invoke-kind האחרון לזוג הרישום שצוין. צריך לעשות זאת כהוראה מיד אחרי invoke-kind שהתוצאה (מילה כפולה) שלה לא מתעלמת. בכל מקום אחר, הפעולה לא חוקית.
0c 11x move-result-object vAA מרשם היעד A: (8 ביט) העברת תוצאת האובייקט של invoke-kind העדכני ביותר למרשם שצוין. צריך לעשות זאת כהוראה מייד אחרי invoke-kind או filled-new-array שאין להתעלם מהתוצאה (האובייקט) שלו. בכל מקום אחר זה לא תקין.
0 ימים 11x move-exception vAA מרשם היעד A: (8 ביט) שמירת חריגה שנלכדה ביומן הנתון. זו צריכה להיות ההוראה הראשונה של כל מנהל חריגות שלא מתעלם מהחריגה שנלכדה, וההוראה הזו חייבת להופיע רק כהוראה הראשונה של מנהל חריגות. בכל מקום אחר היא לא חוקית.
0e 10x return-void   חזרה משיטה void.
0f 11x return vAA מרשם הערך המוחזר A: (8 ביט) חזרה מפונקציה ברוחב יחיד (32 ביט) שלא מחזירה ערך אובייקט.
10 11x vAA ברמת ההחזרה A: צמד מרשם של ערך המוחזר (8 ביט) יציאה חזרה משיטה שמחזירה ערך ברוחב כפול (64 ביט).
11 11x return-object vAA מרשם הערך המוחזר של A: (8 ביט) חזרה משיטה שמחזירה אובייקט.
12 11n const/4 vA, #+B A: מרשם יעד (4 סיביות)
B: signed int (4 סיביות)
העברת הערך הלטרלי הנתון (עם הרחבת סימן ל-32 ביט) למרשם שצוין.
13 21s const/16 vAA, #+BBBB A: מרשם יעד (8 ביט)
B: signed int‏ (16 ביט)
העברת הערך הלטרלי הנתון (עם הרחבת סימן ל-32 סיביות) למרשם שצוין.
14 31i const vAA, #+BBBBBBBB A: מרשם יעד (8 ביט)
B: קבוע שרירותי של 32 ביט
העברת הערך הלטרלי שצוין למרשם שצוין.
15 21h const/high16 vAA, #+BBBB0000 A: מרשם יעד (8 ביט)
B: signed int‏ (16 ביט)
העברת הערך הלטרלי הנתון (עם הרחבה של אפסים בצד שמאל ל-32 סיביות) למרשם שצוין.
16 21s const-wide/16 vAA, #+BBBB A: מרשם יעד (8 ביט)
B: signed int‏ (16 ביט)
העברת הערך הלטרלי הנתון (עם הרחבת סימן ל-64 ביט) לצמד הרשומות שצוין.
17 31i const-wide/32 vAA, #+BBBBBBBB A: מרשם יעד (8 ביט)
B: signed int‏ (32 ביט)
העברת הערך הלטרלי הנתון (עם הרחבת סימן ל-64 ביט) לצמד הרשומות שצוין.
18 51l const-wide vAA, #+BBBBBBBBBBBBBBBB A: מרשם יעד (8 ביט)
B: קבוע שרירותי ברוחב כפול (64 ביט)
העברת הערך הליליטרלי שצוין לזוג הרשומות שצוין.
19 21h const-wide/high16 vAA, #+BBBB000000000000 A: מרשם יעד (8 ביט)
B: signed int‏ (16 ביט)
העברת הערך הלטרלי הנתון (מורחב לאפסים מימין ל-64 סיביות) לצמד הרשומות שצוין.
1a 21c const-string vAA, string@BBBB A: מרשם היעד (8 ביט)
B: אינדקס המחרוזת
העברת הפניה למחרוזת שצוינה על ידי האינדקס הנתון למרשם שצוין.
1b 31c const-string/jumbo vAA, string@BBBBBBBB A: מרשם היעד (8 ביט)
B: אינדקס המחרוזת
העברת הפניה למחרוזת שצוינה על ידי האינדקס הנתון למרשם שצוין.
1c 21c const-class vAA, type@BBBB A: מרשם יעד (8 ביט)
B: אינדקס סוג
העברת הפניה לכיתה שצוינה על ידי האינדקס הנתון למרשם שצוין. במקרה שהסוג שצוין הוא פרימיטיבי, יישמר כאן הפניה לקלאס המנוון של הסוג הפרימיטיבי.
1d 11x monitor-enter vAA A: מרשם עם ערך הפניה (8 ביט) מקבלים את המוניטור של האובייקט שצוין.
1e 11x monitor-exit vAA A: מרשם עם ערך הפניה (8 ביט) משחררים את המעקב אחרי האובייקט שצוין.

הערה: אם צריך להפעיל חריגה מההוראה הזו, צריך לעשות זאת כאילו המחשב כבר התקדם מעבר להוראה. אפשר לחשוב על זה ככה: ההוראה בוצעה בהצלחה (במובן מסוים), וההודעת החריגה הושלחה אחרי ההוראה, אבל לפני שההוראה הבאה תקבל הזדמנות לפעול. ההגדרה הזו מאפשרת לשיטה להשתמש ב-catch-all לניקוי של צגים (למשל, finally) כבלוק של ניקוי המנטור עצמו, כדי לטפל בחריגות שרירותיות שעשויות להתרחש בגלל ההטמעה ההיסטורית של Thread.stop(), ועדיין לשמור על תקינות המנטור.

1f 21c check-cast vAA, type@BBBB A: מרשם עם הפניה (8 ביט)
B: אינדקס סוג (16 ביט)
גורם להשלכת ClassCastException אם לא ניתן להמיר את ההפניה ברשומה הנתונה לסוג שצוין.

הערה: מכיוון ש-A חייב תמיד להיות הפניה (ולא ערך פרימיטיבי), הפונקציה תיכשל בהכרח במהלך זמן הריצה (כלומר, תוצג חריגה) אם B מפנה לסוג פרימיטיבי.

20 22c instance-of vA, vB, type@CCCC A: מרשם יעד (4 ביט)
B: מרשם עם הפניה (4 ביט)
C: אינדקס סוג (16 ביט)
שומרים ברשומת היעד שצוינה את הערך 1 אם ההפניה שצוינה היא מופע מהטיפוס שצוין, או את הערך 0 אם לא.

הערה: מכיוון ש-B חייב תמיד להיות הפניה (ולא ערך פרימיטיבי), תמיד 0 יישמר אם C מפנה לסוג פרימיטיבי.

21 12x array-length vA, vB A: מרשם יעד (4 ביט)
B: מרשם שמכיל את ההפניה למערך (4 ביט)
שמירת האורך של המערך שצוין, ברשומות, במרשם היעד
22 21c new-instance vAA, type@BBBB A: מרשם יעד (8 ביט)
B: אינדקס סוג
יוצרים מכונה חדשה מהסוג שצוין, ושומרים הפניה אליה ביעד. הטיפוס חייב להפנות לסוג של כיתה שאינה מערך.
23 22c new-array vA, vB, type@CCCC A: מרשם היעד (4 ביט)
B: מרשם הגודל
C: אינדקס הסוג
יצירת מערך חדש מהסוג והגודל שצוינו. הסוג חייב להיות מערך.
24 35c filled-new-array {vC, vD, vE, vF, vG}, type@BBBB A: גודל המערך ומספר המילים של הארגומנט (4 ביט)
B: מדד הסוג (16 ביט)
C..G: מרשם הארגומנטים (4 ביט כל אחד)
יצירה של מערך מהסוג והגודל שצוינו, ומילוי שלו בתוכן שסופק. הסוג חייב להיות מערך. התוכן של המערך חייב להיות מילה אחת (כלומר, אסור להשתמש במערכים של long או double, אבל מותר להשתמש בסוגים של הפניות). המכונה שנוצרה מאוחסנת בתור 'תוצאה' באותו אופן שבו ההוראות להפעלת השיטות מאחסנות את התוצאות שלהן, כך שצריך להעביר את המכונה שנוצרה למרשם באמצעות הוראה move-result-object מיידית לאחר מכן (אם רוצים להשתמש בה).
25 3rc filled-new-array/range {vCCCC .. vNNNN}, type@BBBB A: גודל המערך ומספר המילים של הארגומנט (8 ביט)
B: מדד הסוג (16 ביט)
C: מרשם הארגומנט הראשון (16 ביט)
N = A + C - 1
יצירה של מערך מהסוג והגודל שצוינו, ומילוי שלו בתוכן שסופק. ההבהרות וההגבלות זהות לאלה של filled-new-array, כפי שמתואר למעלה.
26 31t fill-array-data vAA, +BBBBBBBB (עם נתונים משניים כפי שמפורט בהמשך בקטע 'פורמט fill-array-data-payload') A: הפניה למערך (8 ביט)
B: היסט חתום של 'הסתעפות' להוראת פסאודו של נתוני טבלה (32 ביט)
ממלאים את המערך הנתון בנתונים שצוינו. ההפניה חייבת להיות למערך של פרימיטיבים, וטבלת הנתונים חייבת להתאים לה מבחינת סוג ולא לכלול יותר רכיבים ממה שאפשר להכניס למערך. כלומר, המערך יכול להיות גדול יותר מהטבלה, ואם זה המצב, רק הרכיבים הראשונים של המערך מוגדרים, והשאר נשאר ללא שינוי.
27 11x throw vAA A: מרשם שמכיל חריגה (8 ביט)
השלכת החריגה שצוינה.
28 10t goto +AA A: היסט של הסתעפות חתומה (8 ביט) מעבר ללא תנאי להוראה שצוינה.

הערה: אסור שההיסט של ההסתעפות יהיה 0. (אפשר ליצור לולאת spin באופן חוקי באמצעות goto/32 או על ידי הכללת nop כיעד לפני ההסתעפות).

29 20t goto/16 +AAAA A: signed branch offset (16 bits)
מעבר ללא תנאי להוראה שצוינה.

הערה: אסור שההיסט של ההסתעפות יהיה 0. (אפשר ליצור לולאת spin באופן חוקי באמצעות goto/32 או על ידי הכללת nop כיעד לפני ההסתעפות).

2a 30t goto/32 +AAAAAAAA A: signed branch offset (32 bits)
מעבר ללא תנאי להוראה שצוינה.
2b 31t packed-switch vAA, +BBBBBBBB (עם נתונים משניים כפי שמפורט בהמשך בקטע 'packed-switch-payload פורמט') A: register to test
B: signed "branch" offset to table data pseudo-instruction (32 bits)
מעבר להוראה חדשה על סמך הערך ברשומה הנתונה, באמצעות טבלה של שינויי מיקום (offsets) שתואמים לכל ערך בטווח שלם מסוים, או מעבר להוראה הבאה אם אין התאמה.
2c 31t sparse-switch vAA, +BBBBBBBB (עם נתונים משלימים כפי שמפורט בהמשך בקטע 'פורמט sparse-switch-payload') A: register to test
B: signed "branch" offset to table data pseudo-instruction (32 bits)
מעבר להוראה חדשה על סמך הערך ברשומה הנתונה, באמצעות טבלה מסודרת של צמדי ערך-היסט, או מעבר להוראה הבאה אם אין התאמה.
2d..31 23x cmpkind vAA, vBB, vCC
2d: cmpl-float (lt bias)
2e: cmpg-float (gt bias)
2f: cmpl-double (lt bias)
30: cmpg-double (gt bias)
31: cmp-long
A: מרשם יעד (8 ביט)
B: מרשם המקור או הצמד הראשון
C: מרשם המקור או הצמד השני
מבצעים את ההשוואה של long או הנקודה הצפה שצוינה, ומגדירים את a לערך 0 אם b == c, לערך 1 אם b > c או לערך -1 אם b < c. הערך 'bias' שמופיע לפעולות של נקודת צפה מציין את האופן שבו מתבצעת הטיפול בהשוואות של NaN: הוראות 'gt bias' מחזירות את הערך 1 בהשוואות של NaN, והוראות 'lt bias' מחזירות את הערך -1.

לדוגמה, כדי לבדוק אם הערך של x < y הוא נקודה צפה, מומלץ להשתמש ב-cmpg-float. תוצאה של -1 מציינת שהבדיקה הייתה נכונה, והערכים האחרים מצביעים על כך שהבדיקה הייתה שגויה, בין שבגלל השוואה תקינה ובין שבגלל שאחד מהערכים היה NaN.

32..37 22t if-test vA, vB, +CCCC
32: if-eq
33: if-ne
34: if-lt
35: if-ge
36: if-gt
37: if-le
A: הרישום הראשון לבדיקה (4 ביט)
B: הרישום השני לבדיקה (4 ביט)
C: היסט של ענף חתום (16 ביט)
מעבר ליעד שצוין אם הערכים של שני הרשומות הנתונות תואמים כמצוין.

הערה: אסור שההיסט של ההסתעפות יהיה 0. (אפשר ליצור לולאת spin באופן חוקי על ידי יצירת הסתעפות סביב goto לאחור או על ידי הכללת nop כיעד לפני ההסתעפות).

38..3d 21t if-testz vAA, +BBBB
38: if-eqz
39: if-nez
3a: if-ltz
3b: if-gez
3c: if-gtz
3d: if-lez
A: register to test (8 bits)
B: signed branch offset (16 bits)
מעבר ליעד שצוין אם הערך של המרשם הנתון משווה ל-0 כפי שצוין.

הערה: אסור שההיסט של ההסתעפות יהיה 0. (אפשר ליצור לולאת spin באופן חוקי על ידי הוספת הסתעפות סביב goto לאחור או על ידי הוספת nop כיעד לפני ההסתעפות).

3e..43 10x (לא בשימוש)   (לא בשימוש)
44..51 23x arrayop vAA, vBB, vCC
44: aget
45: aget-wide
46: aget-object
47: aget-boolean
48: aget-byte
49: aget-char
4a: aget-short
4b: aput
4c: aput-wide
4d: aput-object
4e: aput-boolean
4f: aput-byte
50: aput-char
51: aput-short
מרשם ערך או צמד של A:; יכול להיות מקור או יעד (8 ביט)
מרשם מערך של B: (8 ביט)
מרשם אינדקס של C: (8 ביט)
ביצוע הפעולה במערך שזוהתה באינדקס שזוהה במערך הנתון, טעינה או אחסון ברשומת הערך.
52..5f 22c iinstanceop vA, vB, field@CCCC
52: iget
53: iget-wide
54: iget-object
55: iget-boolean
56: iget-byte
57: iget-char
58: iget-short
59: iput
5a: iput-wide
5b: iput-object
5c: iput-boolean
5d: iput-byte
5e: iput-char
5f: iput-short
מרשם או זוג ערכים של A:; יכול להיות מקור או יעד (4 ביט)
מרשם אובייקט של B: (4 ביט)
אינדקס הפניה לשדה של מכונה של C: (16 ביט)
ביצוע הפעולה בשדה של מופע האובייקט המזוהה עם השדה המזוהה, טעינה או אחסון ברשומת הערך.

הערה: קוד הפקודות הזה מתאים לקישור סטטי, שבו משנים את ארגומנט השדה כך שיהיה שינוי ישיר יותר.

60..6d 21c sstaticop vAA, field@BBBB
60: sget
61: sget-wide
62: sget-object
63: sget-boolean
64: sget-byte
65: sget-char
66: sget-short
67: sput
68: sput-wide
69: sput-object
6a: sput-boolean
6b: sput-byte
6c: sput-char
6d: sput-short
A: register or pair of values; may be source or dest (8 bits)
B: static field reference index (16 bits)
ביצוע הפעולה בשדה הסטטי של האובייקט המזוהה עם השדה הסטטי המזוהה, טעינה או אחסון ברשומת הערך.

הערה: קוד הפקודות הזה מתאים לקישור סטטי, שבו משנים את ארגומנט השדה כך שיהיה שינוי ישיר יותר.

6e..72 35c invoke-kind {vC, vD, vE, vF, vG}, meth@BBBB
6e: invoke-virtual
6f: invoke-super
70: invoke-direct
71: invoke-static
72: invoke-interface
A: מספר מילים של ארגומנטים (4 ביט)
B: מדד הפניה לשיטה (16 ביט)
C..G: מרשם ארגומנטים (4 ביט כל אחד)
קוראים ל-method שצוין. התוצאה (אם יש כזו) יכולה להיות מאוחסנת עם וריאנט מתאים של move-result* כהוראה הבאה.

invoke-virtual משמש להפעלת שיטה וירטואלית רגילה, כלומר שיטה שאינה static, private או קונסטרוקטור.

כשה-method_id מפנה לשיטה של כיתה שאינה ממשק, ה-invoke-super משמש להפעלת השיטה הווירטואלית של הסופרסור הקרוב ביותר (בניגוד לשיטה עם אותו method_id בכיתה הקוראת). קיימות אותן הגבלות על השיטות כמו ב-invoke-virtual.

בקובצי Dex בגרסה 037 ואילך, אם הערך של method_id מתייחס לשיטת ממשק, הערך של invoke-super משמש להפעלת הגרסה הספציפית ביותר של השיטה שהוגדרה בממשק הזה, שלא הוחלפה. קיימות אותן הגבלות על השיטות כמו ב-invoke-virtual. בקובצי Dex שקדמו לגרסה 037, ממשק method_id הוא לא חוקי ולא מוגדר.

invoke-direct משמש להפעלת שיטה ישירה שאינה static (כלומר, שיטה של מופע שלא ניתן לשנות את התנהגות ברירת המחדל שלה, כלומר שיטה של מופע private או קונסטרוקטור).

invoke-static משמש להפעלת שיטת static (שתמיד נחשבת לשיטה ישירה).

invoke-interface משמש להפעלת שיטה של interface, כלומר על אובייקט שהסוג הפיזי שלו לא ידוע, באמצעות method_id שמפנה ל-interface.

הערה: קוד הפקודות הזה מתאים לקישור סטטי, שבו משנים את ארגומנט השיטה כך שיהיה שינוי ישיר יותר (או זוג של שינוי כזה).

73 10x (לא בשימוש)   (לא בשימוש)
74..78 3rc invoke-kind/range {vCCCC .. vNNNN}, meth@BBBB
74: invoke-virtual/range
75: invoke-super/range
76: invoke-direct/range
77: invoke-static/range
78: invoke-interface/range
A: מספר מילות הארגומנט (8 ביט)
B: מדד של הפניה לשיטה (16 ביט)
C: מרשם הארגומנט הראשון (16 ביט)
N = A + C - 1
קוראים ל-method שצוין. פרטים, אזהרות והצעות מופיעים בתיאור הראשון של invoke-kind למעלה.
79..7a 10x (לא בשימוש)   (לא בשימוש)
7b..8f 12x unop vA, vB
7b: neg-int
7c: not-int
7d: neg-long
7e: not-long
7f: neg-float
80: neg-double
81: int-to-long
82: int-to-float
83: int-to-double
84: long-to-int
85: long-to-float
86: long-to-double
87: float-to-int
88: float-to-long
89: float-to-double
8a: double-to-int
8b: double-to-long
8c: double-to-float
8d: int-to-byte
8e: int-to-char
8f: int-to-short
A: מרשם או צמד של יעד (4 ביט)
B: מרשם או צמד של מקור (4 ביט)
ביצוע הפעולה החד-ערךית שזוהתה ברגולטור המקור, ושמירת התוצאה ברגולטור היעד.
90..af 23x binop vAA, vBB, vCC
90: add-int
91: sub-int
92: mul-int
93: div-int
94: rem-int
95: and-int
96: or-int
97: xor-int
98: shl-int
99: shr-int
9a: ushr-int
9b: add-long
9c: sub-long
9d: mul-long
9e: div-long
9f: rem-long
a0: and-long
a1: or-long
a2: xor-long
a3: shl-long
a4: shr-long
a5: ushr-long
a6: add-float
a7: sub-float
a8: mul-float
a9: div-float
aa: rem-float
ab: add-double
ac: sub-double
ad: mul-double
ae: div-double
af: rem-double
A: מרשם או צמד יעד (8 ביט)
B: מרשם או צמד מקור ראשון (8 ביט)
C: מרשם או צמד מקור שני (8 ביט)
ביצוע הפעולה הבינארית שזוהתה בשני מרשם המקור, ושמירת התוצאה במרשם היעד.

הערה: בניגוד לפעולות מתמטיות אחרות של -long (שדורשות זוגות של מרשם גם למקור הראשון וגם למקור השני), הפונקציות shl-long,‏ shr-long ו-ushr-long דורשות זוג של מרשם למקור הראשון (הערך שרוצים להזיז) אבל מרשם יחיד למקור השני (מרחק ההזזה).

b0..cf 12x binop/2addr vA, vB
b0: add-int/2addr
b1: sub-int/2addr
b2: mul-int/2addr
b3: div-int/2addr
b4: rem-int/2addr
b5: and-int/2addr
b6: or-int/2addr
b7: xor-int/2addr
b8: shl-int/2addr
b9: shr-int/2addr
ba: ushr-int/2addr
bb: add-long/2addr
bc: sub-long/2addr
bd: mul-long/2addr
be: div-long/2addr
bf: rem-long/2addr
c0: and-long/2addr
c1: or-long/2addr
c2: xor-long/2addr
c3: shl-long/2addr
c4: shr-long/2addr
c5: ushr-long/2addr
c6: add-float/2addr
c7: sub-float/2addr
c8: mul-float/2addr
c9: div-float/2addr
ca: rem-float/2addr
cb: add-double/2addr
cc: sub-double/2addr
cd: mul-double/2addr
ce: div-double/2addr
cf: rem-double/2addr
A: יעד ומרשם או צמד מקור ראשון (4 ביט)
B: מרשם או צמד מקור שני (4 ביט)
ביצוע הפעולה הבינארית שזוהתה בשני מרשם המקור, ושמירת התוצאה במרשם המקור הראשון.

הערה: בניגוד לפעולות מתמטיות אחרות של -long/2addr (שדורשות זוגות של מרשם גם ליעד/למקור הראשון וגם למקור השני), הפונקציות shl-long/2addr,‏ shr-long/2addr ו-ushr-long/2addr דורשות זוג של מרשם ליעד/למקור הראשון (הערך שרוצים להזיז), אבל מרשם יחיד למקור השני (מרחק ההזזה).

d0..d7 22s binop/lit16 vA, vB, #+CCCC
d0: add-int/lit16
d1: rsub-int (חיסור הפוך)
d2: mul-int/lit16
d3: div-int/lit16
d4: rem-int/lit16
d5: and-int/lit16
d6: or-int/lit16
d7: xor-int/lit16
A: מרשם יעד (4 ביט)
B: מרשם מקור (4 ביט)
C: קבוע של int signed (16 ביט)
ביצוע הפעולה הבינארית שצוינה ברגולטור שצוין (הארגומנט הראשון) ובערך הלטרלי (הארגומנט השני), ושמירת התוצאה ברגולטור היעד.

הערה: ל-rsub-int אין סיומת כי הגרסה הזו היא קוד הפקודה הראשי של המשפחה. פרטים נוספים על הסמנטיקה מופיעים בהמשך.

d8..e2 22b binop/lit8 vAA, vBB, #+CC
d8: add-int/lit8
d9: rsub-int/lit8
da: mul-int/lit8
db: div-int/lit8
dc: rem-int/lit8
dd: and-int/lit8
de: or-int/lit8
df: xor-int/lit8
e0: shl-int/lit8
e1: shr-int/lit8
e2: ushr-int/lit8
A: מרשם יעד (8 ביט)
B: מרשם מקור (8 ביט)
C: קבוע של int signed (8 ביט)
ביצוע הפעולה הבינארית שצוינה ברגולטור שצוין (הארגומנט הראשון) ובערך הלטרלי (הארגומנט השני), ושמירת התוצאה ברגולטור היעד.

הערה: בהמשך מוסבר על הסמנטיקה של rsub-int.

e3..f9 10x (לא בשימוש)   (לא בשימוש)
fa 45cc invoke-polymorphic {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH A: מספר מילים של ארגומנט (4 ביט)
B: מדד הפניה לשיטה (16 ביט)
C: מקלט (4 ביט)
D..G: מרשם ארגומנטים (4 ביט כל אחד)
H: מדד הפניה לפרוטוטיפ (16 ביט)
קוראים ל-method הפולימורפית של החתימה שצוינה. התוצאה (אם יש כזו) יכולה להישמר עם וריאנט מתאים של move-result* כהוראה הבאה.

ההפניה לשיטה חייבת להיות לשיטה עם חתימה פולימורפית, כמו java.lang.invoke.MethodHandle.invoke או java.lang.invoke.MethodHandle.invokeExact.

הנמען חייב להיות אובייקט שתומך בשיטה הפולימורפית של החתימה שנקראת.

בתיעוד של אב הטיפוס מתוארים סוגי הארגומנטים שסופקו וסוג ההחזרה הצפוי.

הקוד הבינארי של invoke-polymorphic עשוי להעלות חריגות במהלך הביצוע שלו. החריגים מתוארים במסמכי העזרה של ה-API של השיטה הפולימורפית עם החתימה שמפעילים.

נמצא בקובצי Dex מגרסה 038 ואילך.
fb 4rcc invoke-polymorphic/range {vCCCC .. vNNNN}, meth@BBBB, proto@HHHH A: מספר מילות הארגומנט (8 ביט)
B: מדד הפניה לשיטה (16 ביט)
C: מקלט (16 ביט)
H: מדד הפניה לפרוטוטיפ (16 ביט)
N = A + C - 1
קריאה למטמון ה-method שצוין. פרטים נוספים מופיעים בתיאור של invoke-polymorphic למעלה.

הקוד הזה נמצא בקובצי Dex מגרסה 038 ואילך.
fc 35c invoke-custom {vC, vD, vE, vF, vG}, call_site@BBBB A: מספר מילות הארגומנט (4 ביט)
B: מדד הפניה של אתר הקריאה (16 ביט)
C..G: מרשם הארגומנטים (4 ביט כל אחד)
פותר את אתר הקריאה שצוין ומפעיל אותו. התוצאה מהקריאה (אם יש כזו) עשויה להישמר עם וריאנט מתאים של move-result* בתור ההוראה הבאה.

ההוראה הזו מתבצעת בשני שלבים: פתרון של אתר הקריאה והפעלה של אתר הקריאה.

פתרון של אתר קריאה בודק אם לאתר הקריאה שצוין יש מכונה משויכת של java.lang.invoke.CallSite. אם לא, מתבצעת קריאה לשיטת הקישור של ה-bootstrap לאתר הקריאה שצוין באמצעות ארגומנטים שנמצאים בקובץ ה-DEX (ראו call_site_item). השיטה של ה-bootstrap linker מחזירה מופע של java.lang.invoke.CallSite, שישויך לאתר הקריאה שצוין אם אין שיוך. יכול להיות ששרשור אחר כבר ביצע את השיוך קודם, ואם כן, ביצוע ההוראה ימשיך עם המכונה הראשונה של java.lang.invoke.CallSite שמשויכת.

הקריאה לאתר מתבצעת ביעד java.lang.invoke.MethodHandle של המופע java.lang.invoke.CallSite שהתקבל. היעד מופעל כאילו מבצעים את invoke-polymorphic (כפי שמתואר למעלה) באמצעות ה-method handle והארגומנטים של הוראה invoke-custom, בתור הארגומנטים להפעלה מדויקת של ה-method handle.

חריגים שה-method של ה-bootstrap linker מעלה עוטפים ב-java.lang.BootstrapMethodError. הערך BootstrapMethodError מופיע גם במקרים הבאים:
  • השיטה של קישור האתחול לא מצליחה להחזיר מופע של java.lang.invoke.CallSite.
  • ל-java.lang.invoke.CallSite המוחזר יש יעד של null method handle.
  • היעד של ידן השיטה הוא לא מהסוג המבוקש.
הקוד הזה נמצא בקובצי Dex מגרסה 038 ואילך.
fd 3rc invoke-custom/range {vCCCC .. vNNNN}, call_site@BBBB A: מספר מילות הארגומנט (8 ביט)
B: אינדקס הפניה של אתר הקריאה (16 ביט)
C: מרשם הארגומנט הראשון (16 ביט)
N = A + C - 1
פתרון והפעלה של אתר קריאה. פרטים נוספים מופיעים בתיאור של invoke-custom למעלה.

הקוד הזה נמצא בקובצי Dex מגרסה 038 ואילך.
fe 21c const-method-handle vAA, method_handle@BBBB A: מרשם היעד (8 ביט)
B: אינדקס של טיפולי שיטות (16 ביט)
העברת הפניה למטמון השיטה שצוין על ידי האינדקס הנתון למרשם שצוין.

הקוד הזה נמצא בקובצי Dex מגרסה 039 ואילך.
ff 21c const-method-type vAA, proto@BBBB A: מרשם היעד (8 ביט)
B: הפניה לפרוטוטיפ של השיטה (16 ביט)
העברת הפניה לפרוטוטיפ השיטה שצוין על ידי האינדקס הנתון למרשם שצוין.

הקוד הזה נמצא בקובצי Dex מגרסה 039 ואילך.

פורמט packed-switch-payload

שם פורמט תיאור
ident ushort = 0x0100 זיהוי פסאודו-קוד פעולה
size ushort מספר הרשומות בטבלה
first_key INT הערך הראשון (והנמוך ביותר) של מקרה המעבר
יעדים int[] רשימה של size יעדי ההסתעפות היחסיים. היעדים הם יחסיים לכתובת של קוד הפקודה של המתג, ולא לטבלה הזו.

הערה: המספר הכולל של יחידות הקוד למכונה של הטבלה הזו הוא (size * 2) + 4.

פורמט sparse-switch-payload

שם פורמט תיאור
ident ushort = 0x0200 זיהוי פסאודו-קוד פעולה
size ushort מספר הרשומות בטבלה
מפתחות int[] רשימה של ערכי מפתח size, ממוינים מערכים נמוכים לערכים גבוהים
יעדים int[] רשימה של size יעדי הסתעפות יחסיים, שכל אחד מהם תואם לערך המפתח באותו אינדקס. היעדים הם יחסיים לכתובת של קוד הפקודה של המתג, ולא לטבלה הזו.

הערה: המספר הכולל של יחידות הקוד למכונה של הטבלה הזו הוא (size * 4) + 2.

פורמט fill-array-data-payload

שם פורמט תיאור
ident ushort = 0x0300 זיהוי פסאודו-קוד פעולה
element_width ushort מספר הבייטים בכל רכיב
size uint מספר הרכיבים בטבלה
נתונים ubyte[] ערכי נתונים

הערה: המספר הכולל של יחידות הקוד למכונה של הטבלה הזו הוא (size * element_width + 1) / 2 + 4.

פרטי הפעולה המתמטית

הערה: פעולות של נקודות צפות חייבות לפעול לפי הכללים של IEEE 754, באמצעות עיגול לספרה הקרובה ביותר ותת-זרימה הדרגתית, אלא אם צוין אחרת.

קוד פעולה סמנטיקה של C הערות
neg-int int32 a;
int32 result = -a;
משלימים בינאריים חד-ערךיים.
not-int int32 a;
int32 result = ~a;
משלימים חד-ערךיים.
neg-long int64 a;
int64 result = -a;
משלימים בינאריים חד-ערךיים.
not-long int64 a;
int64 result = ~a;
משלימים חד-ערךיים.
neg-float float a;
float result = -a;
ביטול של נקודה צפה (floating-point).
neg-double double a;
double result = -a;
ביטול של נקודה צפה (floating-point).
int-to-long int32 a;
int64 result = (int64) a;
הרחבת סימן של int32 ל-int64.
int-to-float int32 a;
float result = (float) a;
המרה של int32 ל-float באמצעות עיגול לשיא הקרוב. כך פוחת הדיוק של ערכים מסוימים.
int-to-double int32 a;
double result = (double) a;
המרה של int32 ל-double.
long-to-int int64 a;
int32 result = (int32) a;
חיתוך של int64 ל-int32.
long-to-float int64 a;
float result = (float) a;
המרה של int64 ל-float באמצעות עיגול לשיא הקרוב. כך פוחת הדיוק של ערכים מסוימים.
long-to-double int64 a;
double result = (double) a;
המרה של int64 ל-double באמצעות עיגול לשיא הקרוב. כך פוחת הדיוק של ערכים מסוימים.
float-to-int float a;
int32 result = (int32) a;
המרה של float ל-int32, באמצעות בחירת הערך הקרוב לאפס. הערכים NaN ו--0.0 (אפס שלילי) ממירים למספר השלם 0. אינסופיות וערכים עם עוצמה גדולה מדי שלא ניתן לייצג אותם מומרו לערך 0x7fffffff או לערך -0x80000000, בהתאם לסימון.
float-to-long float a;
int64 result = (int64) a;
המרה של float ל-int64, באמצעות בחירת הערך הקרוב לאפס. כאן חלים אותם כללים לטיפול במקרים מיוחדים כמו float-to-int, מלבד העובדה שערכים מחוץ לטווח מומרים ל-0x7fffffffffffffff או ל--0x8000000000000000 בהתאם לסימון.
float-to-double float a;
double result = (double) a;
המרה של float ל-double, תוך שמירה על הערך בדיוק.
double-to-int double a;
int32 result = (int32) a;
המרה של double ל-int32, באמצעות בחירת הערך הקרוב לאפס. כאן חלים אותם כללים לגבי מקרים מיוחדים כמו float-to-int.
double-to-long double a;
int64 result = (int64) a;
המרה של double ל-int64, באמצעות בחירת הערך הקרוב לאפס. כאן חלים אותם כללים לגבי מקרים מיוחדים כמו float-to-long.
double-to-float double a;
float result = (float) a;
המרה של double ל-float באמצעות עיגול לשיא הקרוב. כך פוחת הדיוק של ערכים מסוימים.
int-to-byte int32 a;
int32 result = (a << 24) >> 24;
קיצור של int32 ל-int8, סימן להארכת התוצאה.
int-to-char int32 a;
int32 result = a & 0xffff;
חיתוך של int32 ל-uint16, ללא הרחבת סימן.
int-to-short int32 a;
int32 result = (a << 16) >> 16;
קיצור של int32 ל-int16, סימן להארכת התוצאה.
add-int int32 a, b;
int32 result = a + b;
חיבור של משלימים בשניים.
sub-int int32 a, b;
int32 result = a - b;
חיסור לפי משלימים של 2.
rsub-int int32 a, b;
int32 result = b - a;
חיסור הפוך של השלמה לשניים.
mul-int int32 a, b;
int32 result = a * b;
כפל של השלמה לשניים.
div-int int32 a, b;
int32 result = a / b;
חילוק לפי השלמה לשניים, מעוגל לכיוון האפס (כלומר, חותכים אותו למספר שלם). הפונקציה מפעילה את ArithmeticException אם b == 0.
rem-int int32 a, b;
int32 result = a % b;
השארית של השלמה לשניים אחרי החילוק. סימן התוצאה זהה לסימן של a, והוא מוגדר בצורה מדויקת יותר בתור result == a - (a / b) * b. הפונקציה מפעילה את היוצא ArithmeticException אם b == 0.
and-int int32 a, b;
int32 result = a & b;
ערך AND ברמת הביטים.
or-int int32 a, b;
int32 result = a | b;
ערך OR ברמת הסיביות.
xor-int int32 a, b;
int32 result = a ^ b;
ערך XOR ברמת הביטים.
shl-int int32 a, b;
int32 result = a << (b & 0x1f);
הזזה ביתית שמאלה (עם ארגומנט מוסתר).
shr-int int32 a, b;
int32 result = a >> (b & 0x1f);
הזזה ימינה עם סימן בינארי (עם ארגומנט מוצפן).
ushr-int uint32 a, b;
int32 result = a >> (b & 0x1f);
הזזה ימינה ללא סימן בייט (עם ארגומנט מוצפן).
add-long int64 a, b;
int64 result = a + b;
חיבור של משלימים בשניים.
sub-long int64 a, b;
int64 result = a - b;
חיסור לפי משלימים של 2.
mul-long int64 a, b;
int64 result = a * b;
כפל של השלמה לשניים.
div-long int64 a, b;
int64 result = a / b;
חילוק לפי השלמה לשניים, מעוגל לכיוון האפס (כלומר, חותכים אותו למספר שלם). הפונקציה מפעילה את ArithmeticException אם b == 0.
rem-long int64 a, b;
int64 result = a % b;
השארית של השלמה לשניים אחרי החילוק. סימן התוצאה זהה לסימן של a, והוא מוגדר בצורה מדויקת יותר בתור result == a - (a / b) * b. הפונקציה מפעילה את היוצא ArithmeticException אם b == 0.
and-long int64 a, b;
int64 result = a & b;
ערך AND ברמת הביטים.
or-long int64 a, b;
int64 result = a | b;
ערך OR ברמת הסיביות.
xor-long int64 a, b;
int64 result = a ^ b;
ערך XOR ברמת הביטים.
shl-long int64 a;
int32 b;
int64 result = a << (b & 0x3f);
הזזה ביתית שמאלה (עם ארגומנט מוסתר).
shr-long int64 a;
int32 b;
int64 result = a >> (b & 0x3f);
הזזה ימינה עם סימן בינארי (עם ארגומנט מוצפן).
ushr-long uint64 a;
int32 b;
int64 result = a >> (b & 0x3f);
הזזה ימינה ללא סימן בייט (עם ארגומנט מוצפן).
add-float float a, b;
float result = a + b;
חיבור של נקודה צפה (floating-point).
sub-float float a, b;
float result = a - b;
חיסור של נקודה צפה.
mul-float float a, b;
float result = a * b;
כפל של נקודה צפה (floating-point).
div-float float a, b;
float result = a / b;
חלוקה של נקודה צפה (floating-point).
rem-float float a, b;
float result = a % b;
השארית אחרי החילוק בנקודה צפה. הפונקציה הזו שונה מהיתרה של IEEE 754 ומוגדרת בתור result == a - roundTowardZero(a / b) * b.
add-double double a, b;
double result = a + b;
חיבור של נקודה צפה (floating-point).
sub-double double a, b;
double result = a - b;
חיסור של נקודה צפה.
mul-double double a, b;
double result = a * b;
כפל של נקודה צפה (floating-point).
div-double double a, b;
double result = a / b;
חלוקה של נקודה צפה (floating-point).
rem-double double a, b;
double result = a % b;
השארית אחרי החילוק בנקודה צפה. הפונקציה הזו שונה מהיתרה של IEEE 754 ומוגדרת בתור result == a - roundTowardZero(a / b) * b.