Chinaunix首页 | 论坛 | 博客
  • 博客访问: 123226
  • 博文数量: 29
  • 博客积分: 652
  • 博客等级: 上士
  • 技术积分: 340
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-03 21:26
文章分类

全部博文(29)

文章存档

2013年(8)

2012年(21)

分类: C/C++

2012-02-10 16:43:14

//////// is key file for dalvik interpreter.
 
The general way to interpreting vm code is "switch-case" statement, like:
 
  1. while(true)
  2. {
  3.     switch opcode:
  4.     case 0x1: /*move op-code*/
  5.         doMove();
  6.         break;
  7.     case 0x2: /*load data from memory*/
  8.         doLoadFromMemory();
  9.         break;
  10.         ...
  11.     opcode = nextInstruction();
  12. }
Dalvik improves the switch-case way by using "goto" way. The basic ideas is to limit the size of executable code  for dalvik code to less than 64bytes. That is, the begin address of each executable code for dalvik code start from (64*op-code + base_addr). VM can go to special the executable code for respective dalvik code by calculating (op-code<<6 + opcode_base_addr). For example, dalvik code is
    mov r2, r3
   
The dalvik interpreter get 1st dalvik code 0x2 and make calculation (0x2<<6+opcode_base_addr). The code on that address exactly define how to execute dalvik code(0x1)-move operation. When this op-code is done, next op-code address is calculated in same way.

Obviously, the "goto" way has less jmp instructions than ones in "switch-case" way.


invoke opcode:0x70
1) Find out Method struct according to ClassObject, methodID, methodType, detail in:
  1. Method* dvmResolveMethod(const ClassObject* referrer, u4 methodIdx, MethodType methodType)
  2. {
  3.     ....
  4. }
2) If method is native, 
  1.    26827 .LinvokeNative:
  2.    26828 @ Prep for the native call
  3.    26829 @ r0=methodToCall, r1=newFp, r10=newSaveArea
  4.    26830 ldrh lr, [rSELF, #offThread_subMode]
  5.    26831 ldr r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
  6.    26832 str r1, [rSELF, #offThread_curFrame] @ curFrame = newFp
  7.    26833 str r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
  8.    26834 mov r2, r0 @ r2<- methodToCall
  9.    26835 mov r0, r1 @ r0<- newFp (points to args)
  10.    26836 add r1, rSELF, #offThread_retval @ r1<- &retval
  11.    26837 mov r3, rSELF @ arg3<- self
  12.    26838 ....
  13.    26852 mov lr, pc @ set return addr
  14.    26853 ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
  15.    26856 @ native return; r10=newSaveArea
  16.    26857 @ equivalent to dvmPopJniLocals
  17.    26858 ldr r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
  18.    26859 ldr r1, [rSELF, #offThread_exception] @ check for exception
  19.    26860 str rFP, [rSELF, #offThread_curFrame] @ curFrame = fp
  20.    26861 cmp r1, #0 @ null?
  21.    26862 str r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
  22.    26863 bne common_exceptionThrown @ no, handle exception
  23.    26864 
  24.    26865 FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
  25.    26866 GET_INST_OPCODE(ip) @ extract opcode from rINST
  26.    26867 GOTO_OPCODE(ip) @ jump to next instruction
Line 26833 setup new local reference top index. Line 26862 restore the old cookie top index. This make all the local reference located in called function became invalid.
Line 26867 jump to next op-code;

Actually, the native function call by line 26853 is not real jni function, which is  or . Please refer to
  1. 834 void dvmUseJNIBridge(Method* method, void* func) {
  2.     835 method->shouldTrace = shouldTrace(method);
  3.     836 ....
  4.     847 DalvikBridgeFunc bridge = gDvmJni.useCheckJni ? dvmCheckCallJNIMethod : dvmCallJNIMethod;
  5.     848 dvmSetNativeFunc(method, bridge, (const u2*) func);
  6.     849 }
In dvmCallJNIMethod,
  1.    1177 ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
  2.    1178 
  3.    1179 ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
  4.    1180 assert(method->insns != NULL);
  5.    1181 
  6.    1182 JNIEnv* env = self->jniEnv;
  7.    1183 COMPUTE_STACK_SUM(self);
  8.    1184 dvmPlatformInvoke(env,
  9.    1185     (ClassObject*) staticMethodClass,
  10.    1186     method->jniArgInfo, method->insSize, modArgs, method->shorty,
  11.    1187     (void*) method->insns, pResult);
  12.    1188 CHECK_STACK_SUM(self);
  13.    1189 
  14.    1190 dvmChangeStatus(self, oldStatus);
Line 1184 make the real jni call.

3) If method is java code, and it has no JIT translation code.
  1.    26488 common_updateProfile:
  2.    26489    eor r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
  3.    26490    lsl r3,r3,#(32 - JIT_PROF_SIZE_LOG_2) @ shift out excess bits
  4.    26491    ldrb r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ get counter
  5.    26492    GET_INST_OPCODE(ip)
  6.    26493    subs r1,r1,#1 @ decrement counter
  7.    26494    strb r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ and store it
  8.    26495    GOTO_OPCODE_IFNE(ip) @ if not threshold, fallthrough otherwise */
 Line 26495 go into java function.

if it has JIT translation code, interpreter call () to get translation code, and jmp to it.








阅读(2147) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~