第四章 系統軟體介紹
4.4. ISR介紹
4.4.3. 原生方法的機制(N ATIVE METHOD )說明
因為原生方法的呼叫在 bytecode 層級來看是與一般呼叫方法是相同的,透過 invokevirtual、
invokestatic 指令後面接的常數索引區段索引值,一樣以間接的方式最後取到參照資料在記憶 體中的位置,並抓取參照資料,而我們實作原生方法的機制是透過在物件型別解析時,檢察 所屬其物件型別的方法是否為原生方法,如果是的話,我們則會在參照資料裡上放入屬於原 生方法格式的資料,格式如圖 40,我們會犧牲 0xFF 開頭的 Class ID 用以表示此參照資料為
Before Process After
: : Class ID | 0x0000
: Class ID | Offset
: : hos_a rg1
hos_a rg3 hos_a rg4 hos_a rg2
Reference data
hos_a rg5
我們在 ISR 的 ID 上會用前 16bit 以 0 或 1 區分是否會為 Native method 所觸發,當 JAIP 發出中斷時,我們會先確認其是否為 Native method 所觸發的,之後跳去執行我們建立的 native method table 上對應到的 function,機制如 0 所示,其執行 Native method 實的系統變化如 0 所示。
圖41. Native method 機制
圖42. Invoke native method 執行時的狀態變化
Native method table 0 Function ptr
1 :
: :
ISR ID
Definition Native flag ID
Space(bit) 16 16 Native method code
void method(){
: implementation ;
: }
ind ex
Parameter N-3 : Parameter 1
stack
Before After
Parameter N-3 : Parameter 1
:
process
host_arg
hos_a rg5 :
hos_a rg1
Parameter N : Parameter N-2
: : Return value TOS_A
TOS_B TOS_C
:
而為了配合電路在 native method 的結束時對 stack 的整理操作方便,我們在傳遞不同個 數的參數時,擺放在 register file 上的順序也不同,擺放順序如表 3 所示,而目前實作的原生 方法如表 4 所列。
表 3 傳遞不同參數個數時,參數位在 register file 上的位置,最多支援 8 個參數
Parameter order
Parameter count 1 2 3 4 5 6 7 8
TOS_A ○3 ○4 ○5 ○6 ○7 ○8
TOS_B ○2 ○2 ○3 ○4 ○5 ○6 ○7
TOS_C ○1 ○1 ○1 ○2 ○3 ○4 ○5 ○6
Host_Arg 5 ○5
Host_Arg 4 ○4 ○4
Host_Arg 3 ○3 ○3 ○3
Host_Arg 2 ○2 ○2 ○2 ○2
Host_Arg 1 ○1 ○1 ○1 ○1 ○1
表 4 目前對 System Class 所支援的原生方法
Java_java_lang_Object_getClass Java_java_lang_Class_forName Java_java_lang_Class_newInstance Java_java_lang_Thread_yield Java_java_lang_System_arraycopy
Java_java_lang_System_currentTimeMillis
實作原生方法的依據主要參考自 KVM 當中實作的原生方法的邏輯,並撰寫符合我們平 台的版本,接下來會說明各原生方法的實作內容。
java/lang/Object/getClass
因為在我們配置一個新產生的物件時,其在記憶體中最前面 32bit 的資料就是存放此物件所 屬的 Class ID,所以當我們今天取得 Object reference 時,我們即可以透過這個位址讀取 Class ID,並回傳給 JAIP。
java/lang/Class/forName
透過取得的 String Object 參數,我們取出其字串的 field data,並以此為要解析的物件型別名 稱呼叫物件型別解析器,最後再回傳一個 Class Object 給 JAIP,但是其所屬的 Class ID 我們 會填入此次解析物件型別的 Class ID,而非 Class 這個物件型別的 Class ID。
java/lang/Class/newInstance
透過傳遞出的由 Class 造出的 Object,我們取出其存放的 Class ID,再透過此 Class ID 去配置 一個新物件記憶體空間,並回傳 object reference 給 JAIP。
java/lang/Thread/yield
目前平台尚未提供多執行緒的功能,但此方法會去確認目前系統中的執行緒個數,當個數大 於一時,我們會去設定切換執行緒的訊號,之後可以延伸做為觸發電路做切換執行緒的機制。
java/lang/System/currentTimeMillis
這邊我是透過讀取 JAIP 內部的 timer 暫存器的值,再去對系統頻率換算得到 JAIP 啟動之後 的毫秒數,再將這個時間資訊傳回給 JAIP。
java/lang/System/arraycopy
arraycopy 會使用到五個參數,其中兩個分別代表陣列的記憶體位址、另外兩個表示從陣列上 要開始複製及貼上的起始位置,最後一個表示要複製資料的長度,在這部分實作兩個遞迴呼
叫的函式 copy_obj 及 copy_array 來實作,這兩個函式的流程如圖 43、圖 44 所示,當呼叫 arraycopy 時會根據 array tag 去決定呼叫 copy_obj、copy_array 或是直接複製內容,也因為實 作這個原生方法,所以我們對陣列及 field data 都做了額外的 tag 表示其中的意義,來幫助我 們在複製物件及陣列時,使用正確的複製的方式。
圖43. copy_array(ref)流程
Check all elements are finished Check all elements
are finished Check element is
array type Yes
Check element is object type
Call copy_obj(ref)
Yes No
Call copy_array(ref) Copy primitive data
Get array t ag
No
No No
Yes Yes
圖44. copy_obj(ref)流程
java/lang/System/getProperty0
透過取得的 String Object 參數,取出其字串內容的資訊,這邊參考自 KVM 中實作的方式會 再呼叫 getSystemProperty 的函式,取得表示系統資訊的字串,並以此字串產生一個 String Object 回傳給 JAIP。
java/lang/String/charAt
在 String 的 field data 中,其中一項是用來描述另一個 field data 字元陣列的有效起始位置,當 我們得到 String Object 參數時,會在其字元陣列中,將其起始位移量加上索引值得字元回傳 給 JAIP。
Check all field d ata is finished
Get field tag
Check field data is
array type
Yes
Check field data is object type
Copy field data
Yes
No
Call copy_array(ref)Yes No
Call copy_obj(ref)
No
java/lang/String/equals
比對兩個 String Object 在字元陣列的起始位置之後的內容是否相同,並將結果回傳給 JAIP。
java/lang/String/indexOf__I
在 String Object 上的 field data 中,從字元陣列的起始位置開始搜尋指定字元出現的索引值,
並回傳給 JAIP。
java/lang/String/indexOf__II
在 String Object 上的 field data 中,從字元陣列的起始位置加上一個指定搜尋的位移量,開始 搜尋指定字元出現的索引值,並回傳給 JAIP。
java/lang/StringBuffer/append__I
產生新的字元陣列,並將數值轉成字元附加在原來在 String Object 的字元陣列之後,再存回 原 String Object 的 field data 中。
java/lang/StringBuffer/append__Ljava_lang_String_2
將欲附加的 String Object 的字元陣列附加在原來在 String Object 的字元陣列之後,再存回原 String Object 的 field data 中。
java/lang/StringBuffer/toString
透過取得的 StringBuffer Object 參數,修改其所屬Class ID 並對其 field data 的順序做調整,
修改成符合 String 的格式。