1. 程式人生 > >[三] java虛擬機器 JVM位元組碼 指令集 bytecode 操作碼 指令分類用法 助記符

[三] java虛擬機器 JVM位元組碼 指令集 bytecode 操作碼 指令分類用法 助記符

上面關於dup的描述摘自 虛擬機器規範,很難理解
看起來是非常難以理解的,不妨換一個角度
我們知道區域性變數的空間分配分為兩種long 和 double 佔用2個slot  其他佔用一個
運算元棧,每個單位可以表示虛擬機器支援的任何的一個數據型別
不過運算元棧其實同區域性變數一樣,他也是被組織一個數組, 每個元素的資料寬度和區域性變數的寬度是一致的
所以對於long 和double佔用2個單位長度  對於其他型別佔用一個單位長度
雖然外部呈現上任何一個運算元棧可以表示任何一種資料型別,但是內部是有所區分的
如同區域性變量表使用兩個單位儲存時,訪問元素使用兩個中索引小的那個類似的道理
所以可以把棧理解成線性的陣列,

來一個long或者double 就分配兩個單位空間作為一個元素
其餘型別就分配一個單位空間作為元素

既然棧本身的結構中,線性空間的最小單位的資料寬度同區域性變數,
long和double佔用兩個  也就是下面涉及說到的資料型別的分類1  和  分類2

假設棧的示意結構如下圖所示,(只是給出來一種可能每個元素的型別都可能是隨機的) 左邊表示呈現出來的棧元素 右邊是內部的線性形式  我們當做陣列好了 image_5b869c5d_3c9b 對棧元素的處理,顯然指的是對於棧元素內部陣列的處理 所以自然要分為     到底是直接複製一個單位的資料        
還是直接複製兩個單位的資料  一次複製佔用一個單位空間   的指令 使用dup   一次複製佔用兩個單位空間   的指令 使用dup2 一次複製佔用一個單位空間 時 假設複製的棧頂是array[0]  dup 可以理解為dup_x0     插入到他棧頂的內部線性結構的第(1+0)個元素下面 所以array[0] 對應的必然是一個完整的棧元素 ,必然是分類1 不可能是分類2的一半! image_5b869c5d_24b7 dup_x1                            插入到他棧頂的內部線性結構的第(1+1)個元素下面 也就是插到第二個下面  因為array[0] 對應value1為分類1  
如果接下來的是分類2的資料,必然接下來的兩個單元array[1] 和array[2]是不可分割的,也就是不可能插入到array[1] 後面,所以array[1] 對應value2 也必須是分類1 也就是兩個都是分類1 image_5b869c5d_5c27 dup_x2                           插入到他棧頂的內部線性結構的第(1+2)個元素下面 也就是插到第三個後面,array[0] 對應value1為分類1 為分類1   那麼接下來的兩個單位array[1] 和array[2],可以是一個分類2  也可以是兩個分類1,都是可以的 image_5b869c5d_3651 image_5b869c5d_7212 一次複製佔用兩個單位的資料型別 時
dup2 可以理解為dup2_x0    插入到他棧頂的內部線性結構的第(2+0)個元素下面  這一次複製的兩個單位array[0] 和 array[1],  到 array[1]下面   可能是對應value1 和value2 表示兩個分類1  也可能是對應一個value1 表示型別為分類2  image_5b869c5d_3101
image_5b869c5d_6ad0
 
dup2_x1   插入到他棧頂的內部線性結構的第(2+1)個元素下面 也就是複製array[0] 和 array[1] 到第三個元素 array[2]的下面
array[0] 和 array[1] 可能分別對應value1 和value2 表示兩個分類1 資料  也可能是對應著一個value1表示一個分類2資料
但是array[2] 作為第三個單位,既然能被分割,自然他必須是分類1
所以要麼三個都是分類1,要麼value1 分類2  value2 分類1
image_5b869c5d_3201
image_5b869c5d_3543


dup2_x2  插入到他棧頂的內部線性結構的第(2+2)個元素下面 也就是複製array[0] 和 array[1] 到第四個內部元素 array[3]的下面
一次複製兩個,放到第四個下面
這種情形下的組合就非常多了
全都是分類1的資料
image_5b869c5d_3cea

全部都是分類2
array[0]  和 array[1]  對應value1 表示一個分類2資料
array[2]  和 array[3]     對應value2 表示一個分類2資料
image_5b869c5d_5ddd

array[0]  和 array[1]  對應value1 表示一個分類2資料 array[2]  和 array[3]     對應value2 和 value3表示兩個分類1資料 image_5b869c5d_4ebd

array[0]  和 array[1]  對應value1 和value2 表示兩個分類1 資料 array[2]  和 array[3]    對應value3表示一個分類2資料 image_5b869c5d_4ea4

所以說只需要明確以下幾點,就不難理解dup指令
運算元棧指令操作的是棧內部的儲存單元,而不是以一個棧元素為單位的
long和double在棧元素內部需要兩個儲存單元,其餘一個儲存單元
兩個相鄰的內部單位組合起來表示一個棧元素時,是不能拆分的

再回過頭看,所有的dup指令,不過是根據棧元素的實際存放的型別的排列組合,梳理出來的一些複製一個或者兩個棧頂元素的實際操作方式而已
就是因為他是逆向推導的,所以看起來不好理解