从 Native 函数调用 Java 函数

从一个Native调用java方法的实例开始:

(gdb) bt
#0  art_quick_invoke_stub () at art/runtime/arch/arm64/quick_entrypoints_arm64.S:667
#1  0x0000007f8265ae54 in art::ArtMethod::Invoke (this=0x7148dd88, self=0x7f75260c00, args=0x7f7a5fedb0, args_size=28, result=0x7f7a5fed90, shorty=0x73654521 "ZIJJI")
    at art/runtime/art_method.cc:289
#2  0x0000007f829f2b5c in art::InvokeWithArgArray (soa=..., method=<optimized out>, arg_array=<optimized out>, result=<optimized out>, shorty=<optimized out>)
    at art/runtime/reflection.cc:439
#3  0x0000007f829f4574 in art::InvokeVirtualOrInterfaceWithVarArgs (soa=..., obj=<optimized out>, mid=<optimized out>, args=...) at art/runtime/reflection.cc:557
#4  0x0000007f828e357c in art::JNI::CallBooleanMethodV (env=<optimized out>, obj=<optimized out>, mid=<optimized out>, args=...) at art/runtime/jni_internal.cc:717
#5  0x0000007f8665d97c in _JNIEnv::CallBooleanMethod (this=this@entry=0x7f75302900, obj=<optimized out>, methodID=<optimized out>) at libnativehelper/include/nativehelper/jni.h:620
#6  0x0000007f866b4454 in JavaBBinder::onTransact (this=0x7f752b0780, code=50, data=..., reply=0x7f7a5ff100, flags=17) at frameworks/base/core/jni/android_util_Binder.cpp:265
#7  0x0000007f85d77174 in android::BBinder::transact (this=0x7f752b0780, code=50, data=..., reply=0x7f7a5ff100, flags=17) at frameworks/native/libs/binder/Binder.cpp:126
#8  0x0000007f85d831a8 in android::IPCThreadState::executeCommand (this=0x7f82d06780, cmd=<optimized out>) at frameworks/native/libs/binder/IPCThreadState.cpp:1115
#9  0x0000007f85d82d04 in android::IPCThreadState::getAndExecuteCommand (this=0x7f82d06780) at frameworks/native/libs/binder/IPCThreadState.cpp:447
#10 0x0000007f85d833fc in android::IPCThreadState::joinThreadPool (this=<optimized out>, isMain=<optimized out>) at frameworks/native/libs/binder/IPCThreadState.cpp:517
#11 0x0000007f85da17e8 in android::PoolThread::threadLoop (this=0x7f77b08b80) at frameworks/native/libs/binder/ProcessState.cpp:63
#12 0x0000007f849f093c in android::Thread::_threadLoop (user=<optimized out>, user@entry=0x7f77b08b80) at system/core/libutils/Threads.cpp:751
#13 0x0000007f86655d1c in android::AndroidRuntime::javaThreadShell (args=<optimized out>) at frameworks/base/core/jni/AndroidRuntime.cpp:1201
#14 0x0000007f851a7c58 in __pthread_start (arg=<optimized out>) at bionic/libc/bionic/pthread_create.cpp:198
#15 0x0000007f85150100 in __start_thread (fn=0x1, arg=0x7148dd88) at bionic/libc/bionic/clone.cpp:41
#16 0x0000000000000000 in ?? ()
(gdb) f 6
#6  0x0000007f866b4454 in JavaBBinder::onTransact (this=0x7f752b0780, code=50, data=..., reply=0x7f7a5ff100, flags=17) at frameworks/base/core/jni/android_util_Binder.cpp:265
warning: Source file is more recent than executable.
265             code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
 
(gdb) list 263,266
263         //printf("\n");
264         jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
265             code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
266


在 f6:android_util_Binder.cpp:265 Native的 JavaBBinder::onTransact 函数中,通过 CallBooleanMethod 来调用 gBinderOffsets.mExecTransact (methodID,其初始化就不做介绍了)这个java 方法;

从 f6 到 f0,仍然都是Native函数,其遵循的仍然是 ARM调用约定,且目前还没有真正跳转到 gBinderOffsets.mExecTransact 这个java函数,


在开始跳转之前,有一点需要关注的是: 线程的状态(这里指该线程在虚拟机中的状态)的切换;

在 f4 中:

(gdb) down
#4  0x0000007f86ae357c in art::JNI::CallBooleanMethodV (env=<optimized out>, obj=<optimized out>, mid=<optimized out>, args=...) at art/runtime/jni_internal.cc:717
warning: Source file is more recent than executable.
717     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetZ();
(gdb) list 713,718
713   static jboolean CallBooleanMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
714     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
715     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
716     ScopedObjectAccess soa(env);
717     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetZ();
718   }


在 line 716: ScopedObjectAccess soa(env); 中完成了 Thread 状态的切换(具体的切换代码在 ScopedObjectAccess以及其父类的构造函数中完成),

把线程状态切换成了 Runnable状态,并且 Shared Hold mutator_lock_; 即线程在开始执行 Java代码之前已经提前把线程状态切换成了 Runnable 状态;

说明:当线程在虚拟机中对应的状态是 Runnable状态时,才能执行 java 代码;当需要执行 Native 代码时,同样提前切换线程状态到 Native状态;


gdb) down
#1  0x0000007f8265ae54 in art::ArtMethod::Invoke (this=0x7148dd88, self=0x7f75260c00, args=0x7f7a5fedb0, args_size=28, result=0x7f7a5fed90, shorty=0x73654521 "ZIJJI")
    at art/runtime/art_method.cc:289
(gdb) art_get_method_name_by_method_id this
android.os.Binder.execTransact "(IJJI)Z"
(gdb) list 288,292
288       if (!IsStatic()) {
289         (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
290       } else {
291         (*art_quick_invoke_static_stub)(this, args, args_size, self, result, shorty);
292       }
private boolean execTransact(int code, long dataObj, long replyObj, int flags);

非 static的java 函数调用前的准备工作是 art_quick_invoke_stub 来做的,而静态的调用,其准备工作是 art_quick_invoke_static_stub负责;

看其参数个数及顺序,发现并无区别;依次是:art::ArtMethod指针,参数指针,参数大小(byte),art::Thread指针,指向栈上存放返回值的指针 result,java函数对应的 short signature;

我们查一下 args这个参数在哪准备的,因为这个args里面保存着 execTransact(int code, long dataObj, long replyObj, int flags);这个java函数的所有参数;

(gdb) f 3
#3  0x0000007f829f4574 in art::InvokeVirtualOrInterfaceWithVarArgs (soa=..., obj=<optimized out>, mid=<optimized out>, args=...) at art/runtime/reflection.cc:557
557   InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
(gdb) list 553,557
553   const char* shorty = method->GetInterfaceMethodIfProxy(sizeof(void*))->GetShorty(&shorty_len);
554   JValue result;
555   ArgArray arg_array(shorty, shorty_len);
556   arg_array.BuildArgArrayFromVarArgs(soa, receiver, args);
557   InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
 
 
@art/runtime/reflection.cc
 
 
  void Append(uint32_t value) {
    arg_array_[num_bytes_ / 4] = value;
    num_bytes_ += 4;
  }
 
 
  void BuildArgArrayFromVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
                                mirror::Object* receiver, va_list ap)
      SHARED_REQUIRES(Locks::mutator_lock_) {
    // Set receiver if non-null (method is not static)
    if (receiver != nullptr) {
      Append(receiver);
    }
    for (size_t i = 1; i < shorty_len_; ++i) {
      switch (shorty_[i]) {
        case 'Z':
        case 'B':
        case 'C':
        case 'S':
        case 'I':
          Append(va_arg(ap, jint));
          break;
        case 'F':
          AppendFloat(va_arg(ap, jdouble));
          break;
        case 'L':
          Append(soa.Decode<mirror::Object*>(va_arg(ap, jobject)));
          break;
        case 'D':
          AppendDouble(va_arg(ap, jdouble));
          break;
        case 'J':
          AppendWide(va_arg(ap, jlong));
          break;
#ifndef NDEBUG
        default:
          LOG(FATAL) << "Unexpected shorty character: " << shorty_[i];
#endif
      }
    }
  }
除了 double,long,都是 4byte;
    // Primitives.
    case JDWP::JT_BYTE:    return 'B';
    case JDWP::JT_CHAR:    return 'C';
    case JDWP::JT_FLOAT:   return 'F';
    case JDWP::JT_DOUBLE:  return 'D';   8byte
    case JDWP::JT_INT:     return 'I';
    case JDWP::JT_LONG:    return 'J';   8byte
    case JDWP::JT_SHORT:   return 'S';
    case JDWP::JT_VOID:    return 'V';
    case JDWP::JT_BOOLEAN: return 'Z';
    // Reference types.
    case JDWP::JT_ARRAY:
    case JDWP::JT_OBJECT:
    case JDWP::JT_STRING:
    case JDWP::JT_THREAD:
    case JDWP::JT_THREAD_GROUP:
    case JDWP::JT_CLASS_LOADER:
    case JDWP::JT_CLASS_OBJECT:
      return 'L';

参数是通过 ArgArray 的 BuildArgArrayFromVarArgs()这个函数准备的,保存在其成员 arg_array_数组里,通过AppendXXX()来填充数组;

从这个函数里,可以看到数据的顺序:

非static方法时,传递的receiver(java 类对象)不是 nullptr,会把this指针放在 arg_array_的第一个元素里;

而调用static方法时,参数列表中是没有this对象的,arg_array_的第一个元素就是对应 static函数的第一个参数;

对于我们正在分析的函数 private boolean execTransact(int code, long dataObj, long replyObj, int flags);为其构建的 arg_array_的情况是:

this(Binder.java)
code dataObj replyObj flags


在接下来的调用 (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);时, args就是 arg_array_首地址;


我们看下,在art::ArtMethod::Invoke函数跳转到 art_quick_invoke_stub之前的参数:

0x0000007f8265ae38 <+184>: mov x0, x20  ;this(ArtMethod)
0x0000007f8265ae3c <+188>: mov x1, x22  ; args
0x0000007f8265ae40 <+192>: mov w2, w24  ; args_size
0x0000007f8265ae44 <+196>: mov x3, x21  ; self(art::Thread*)
0x0000007f8265ae48 <+200>: mov x4, x19  ; result
0x0000007f8265ae4c <+204>: mov x5, x23  ; shorty
0x0000007f8265ae50 <+208>: bl  0x7f8264daf0 <art_quick_invoke_stub>

ARM64的调用约定,前面的 6个参数依次存放在 x0~x5;

函数 art_quick_invoke_stub ,是为了执行 java 函数之前做一个准备工作;

接下来,我们跳转到 art_quick_invoke_stub:

(gdb) disassemble
Dump of assembler code for function art_quick_invoke_stub:
=> 0x0000007f8264daf0 <+0>:    mov x9, sp                          ;x9保存函数 art::ArtMethod::Invoke 的sp
   0x0000007f8264daf4 <+4>:   add x10, x2, #0x80                  ;x2是 arg_size, x10=x2+0x80
   0x0000007f8264daf8 <+8>:   sub x10, sp, x10                    ;x10=sp - x10
   0x0000007f8264dafc <+12>:  and x10, x10, #0xfffffffffffffff0   ;x10进行16字节对齐
   0x0000007f8264db00 <+16>:  mov sp, x10                         ;sp移动,相当于开辟了 (x9-x10)byte的栈空间,用来存放:1.args (arg_size byte) 2.ArtMethod(8 byte) 3.保存 callee save register (0x78 byte)
   0x0000007f8264db04 <+20>:  sub x10, x9, #0x78                  ;临近上一个frame的 0x78的栈空间,下面的关于 x10的操作,都是在保存reg到,这个range的栈上
   0x0000007f8264db08 <+24>:  str x28, [x10,#112]                
   0x0000007f8264db0c <+28>:  stp x26, x27, [x10,#96]
   0x0000007f8264db10 <+32>:  stp x24, x25, [x10,#80]
   0x0000007f8264db14 <+36>:  stp x22, x23, [x10,#64]
   0x0000007f8264db18 <+40>:  stp x20, x21, [x10,#48]
   0x0000007f8264db1c <+44>:  stp x9, x19, [x10,#32]
   0x0000007f8264db20 <+48>:  stp x4, x5, [x10,#16]               ;其中x4,存放的是 JValue result的地址,最终java函数的返回值要存入 result中
   0x0000007f8264db24 <+52>:  stp x29, x30, [x10]                 ;紧邻上一个 frame的 0x78的空间填充完成;
   0x0000007f8264db28 <+56>:  mov x29, x10                        ;记录 frame pointer
   0x0000007f8264db2c <+60>:  mov x19, x3                         ;把 Thread* 放到 x19 来保存
   0x0000007f8264db30 <+64>:  add x9, sp, #0x8                    ;跳过当前frame栈顶的第一个数据,即跳过 ArtMethod,x9指向第二个数据
 
   0x0000007f8264db34 <+68>:  cmp w2, #0x0                                       ; 如果 arg_size 等于 0则跳转,否则从 arg_array 拷贝数据到栈上,直到arg_array中所有数据拷贝到栈上
   0x0000007f8264db38 <+72>:  b.eq    0x7f8264db4c <art_quick_invoke_stub+92>
   0x0000007f8264db3c <+76>:  sub w2, w2, #0x4                                   ; index = arg_size - 4,index = index -4
   0x0000007f8264db40 <+80>:  ldr w10, [x1,x2]                                   ; 从 arg_array取出index对应的arg,从后向前获取数组元素
   0x0000007f8264db44 <+84>:  str w10, [x9,x2]                                   ; 将 arg存放到栈上的 args区域,每次拷贝 4 byte,先拷贝到高地址,再拷贝到低地址
   0x0000007f8264db48 <+88>:  b   0x7f8264db34 <art_quick_invoke_stub+68>        ; 继续拷贝
 
   0x0000007f8264db4c <+92>:  str xzr, [sp]                                      ; 把栈顶的第一个数据填充0,实际上这个数据对应一个 ArtMethod指针
   0x0000007f8264db50 <+96>:  adr x11, 0x7f8264dbe0 <art_quick_invoke_stub+240>  ; 记录该函数的几个入口
   0x0000007f8264db54 <+100>: adr x12, 0x7f8264dc28 <art_quick_invoke_stub+312>
   0x0000007f8264db58 <+104>: adr x13, 0x7f8264dc70 <art_quick_invoke_stub+384>
   0x0000007f8264db5c <+108>: adr x14, 0x7f8264dcd0 <art_quick_invoke_stub+480>
   0x0000007f8264db60 <+112>: mov x8, #0x0                    // #0              ; integer offset
   0x0000007f8264db64 <+116>: mov x15, #0x0                       // #0          ; floating offset
   0x0000007f8264db68 <+120>: add x10, x5, #0x1                                  ; short signatur的地址,+0x1是因为第一个是 return value的shorty,我们是准备参数,所以要跳过: shorty=0x73654521 "ZIJJI"
   0x0000007f8264db6c <+124>: ldr w1, [x9],#4                                    ; x9指向栈上的第一个参数,当函数不是static时,第一个参数是函数对应的类this对象,这里把 this放到 r1作为参数传递
   0x0000007f8264db70 <+128>: ldrb    w17, [x10],#1
   0x0000007f8264db74 <+132>: cbz w17, 0x7f8264dd30 <art_quick_invoke_stub+576>

在此时,art_quick_invoke_stub 的栈空间情况:

由于 arg_size = 28 = 4(append(this)) + (4+8+8+4)"IJJI" (遍历shorty时从1开始,忽略返回值);

所以 x2+0x80 = 28+0x80 =  0x1c+0x80 = 0x9c,所以 framesize = 0xa0 = 160 byte;

讲一下这里的对齐,很显然,x10= sp - 10  过后,要和 #0xfffffffffffffff0 做and运算,运算后会把末尾丢掉,由于栈是从高地址向低地址开辟,所以相当于多开辟了部分空间;

栈空间如下:



已经贴出来的  art_quick_invoke_stub 的这段代码就已经把栈空间准备好了;

此时的寄存器情况:

x0: ArtMethod*

x1: this (Binder.java)

其余参数还没有完成准备;

ARM64 上 art_quick_invoke_stub调用 java 函数的调用约定:

* Outgoing registers:
* x0 - Method*
* x1-x7 - integer parameters.
* d0-d7 - Floating point parameters.
* xSELF = self
* SP = & of ArtMethod*
* x1 = "this" pointer.
*

看起来我们才刚刚准备好 x0,x1 ,xSELF(x19) 和 SP;继续看剩下的部分代码:

   0x0000007f8264db68 <+120>: add x10, x5, #0x1                                  ; short signatur的地址,+0x1是因为第一个是 return value的shorty,我们是准备参数,所以要跳过: shorty=0x73654521 "ZIJJI"
   0x0000007f8264db6c <+124>: ldr w1, [x9],#4                                    ; x9指向栈上的第一个参数,当函数不是static时,第一个参数是函数对应的类this对象,这里把 this放到 r1作为参数传递,并且x9=x9+4,指向arg1
   0x0000007f8264db70 <+128>: ldrb    w17, [x10],#1                              ; 从shorty signature获取一个byte到 w17,并且 x10=x10+1,指向signature下一个字节
   0x0000007f8264db74 <+132>: cbz w17, 0x7f8264dd30 <art_quick_invoke_stub+576>  ; 0,字符串结束,signature结束,参数准备完成,跳转到 +576位置,准备执行
   0x0000007f8264db78 <+136>: cmp w17, #0x46                                     ; 是否是字符 'F',floating 参数
   0x0000007f8264db7c <+140>: b.ne    0x7f8264db90 <art_quick_invoke_stub+160>   ; 如果不是字符 'F',进行下一步判断是否字符 'D'
   0x0000007f8264db80 <+144>: cmp x15, #0x60                                     ; 判断 floating register是否用完了
   0x0000007f8264db84 <+148>: b.eq    0x7f8264dbd0 <art_quick_invoke_stub+224>   ; 如
   0x0000007f8264db88 <+152>: add x17, x13, x15
   0x0000007f8264db8c <+156>: br  x17
   0x0000007f8264db90 <+160>: cmp w17, #0x44                                     ; 是否是字符 'D',double 参数
   0x0000007f8264db94 <+164>: b.ne    0x7f8264dba8 <art_quick_invoke_stub+184>   ; 如果不是字符 'D',进行下一步判断是否字符 'J'
   0x0000007f8264db98 <+168>: cmp x15, #0x60                                     ; 判断 floating register是否用完了
   0x0000007f8264db9c <+172>: b.eq    0x7f8264dbd8 <art_quick_invoke_stub+232>
   0x0000007f8264dba0 <+176>: add x17, x14, x15
   0x0000007f8264dba4 <+180>: br  x17
   0x0000007f8264dba8 <+184>: cmp w17, #0x4a                                     ; 是否是字符 'J',long 参数
   0x0000007f8264dbac <+188>: b.ne    0x7f8264dbc0 <art_quick_invoke_stub+208>   ; 如果不是字符 'J',进入 else分支
   0x0000007f8264dbb0 <+192>: cmp x8, #0x48                                      ; 判断 integer register是否用完了
   0x0000007f8264dbb4 <+196>: b.eq    0x7f8264dbd8 <art_quick_invoke_stub+232>
   0x0000007f8264dbb8 <+200>: add x17, x12, x8                                   ; 如果是 long参数,跳转到 x12 + x8(code offset)处,进行load参数;x12= 0x7f8264dc28 <art_quick_invoke_stub+312>
   0x0000007f8264dbbc <+204>: br  x17
   0x0000007f8264dbc0 <+208>: cmp x8, #0x48                                      ; 不是字符 'F', 'D', 'J',判断 integer register是否用完了
   0x0000007f8264dbc4 <+212>: b.eq    0x7f8264dbd0 <art_quick_invoke_stub+224>
   0x0000007f8264dbc8 <+216>: add x17, x11, x8                                   ; 这个实例中,shorty "IJJI",第一个参数进入else分支, x17=x11+0,而x11在上面初始化过,是 0x7f8264dbe0 <art_quick_invoke_stub+240>
   0x0000007f8264dbcc <+220>: br  x17
   0x0000007f8264dbd0 <+224>: add x9, x9, #0x4                                   ; x9向栈底移动 4byte,(上一个参数是floating,会走到该分支),移动后,x9指向floating参数后的下一个参数
   0x0000007f8264dbd4 <+228>: b   0x7f8264db70 <art_quick_invoke_stub+128>       ; 跳转到 +128处,获取第二个参数对应的 shorty,并进行过滤
   0x0000007f8264dbd8 <+232>: add x9, x9, #0x8                                   ; x9向栈底移动 8byte,(当上一个参数是 double/long时,会走到该分支),移动后,x9指向 double/long 参数后的下一个参数
   0x0000007f8264dbdc <+236>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dbe0 <+240>: ldr w2, [x9],#4                                    ; load java method的第2个参数, *************当需要load的参数是 4 byte且是integer,对应的分支****************************
   0x0000007f8264dbe4 <+244>: add x8, x8, #0xc                                   ; x8 = x8+12,代码偏移
   0x0000007f8264dbe8 <+248>: b   0x7f8264db70 <art_quick_invoke_stub+128>       ; 准备下一个参数
   0x0000007f8264dbec <+252>: ldr w3, [x9],#4
   0x0000007f8264dbf0 <+256>: add x8, x8, #0xc
   0x0000007f8264dbf4 <+260>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dbf8 <+264>: ldr w4, [x9],#4
   0x0000007f8264dbfc <+268>: add x8, x8, #0xc
   0x0000007f8264dc00 <+272>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dc04 <+276>: ldr w5, [x9],#4                                    ; load java method的第5个参数
   0x0000007f8264dc08 <+280>: add x8, x8, #0xc
   0x0000007f8264dc0c <+284>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dc10 <+288>: ldr w6, [x9],#4
   0x0000007f8264dc14 <+292>: add x8, x8, #0xc
   0x0000007f8264dc18 <+296>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dc1c <+300>: ldr w7, [x9],#4
   0x0000007f8264dc20 <+304>: add x8, x8, #0xc
   0x0000007f8264dc24 <+308>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dc28 <+312>: ldr x2, [x9],#8                                    ; ****************************当需要load的参数是 8 byte且是integer ,对应的分支****************************
   0x0000007f8264dc2c <+316>: add x8, x8, #0xc
   0x0000007f8264dc30 <+320>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dc34 <+324>: ldr x3, [x9],#8                                    ; load java method的第3个参数
   0x0000007f8264dc38 <+328>: add x8, x8, #0xc                                   ; x8 = x8+12,代码偏移
   0x0000007f8264dc3c <+332>: b   0x7f8264db70 <art_quick_invoke_stub+128>       ; 准备下一个参数
   0x0000007f8264dc40 <+336>: ldr x4, [x9],#8                                    ; load java method的第4个参数
   0x0000007f8264dc44 <+340>: add x8, x8, #0xc
   0x0000007f8264dc48 <+344>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dc4c <+348>: ldr x5, [x9],#8
   0x0000007f8264dc50 <+352>: add x8, x8, #0xc
   0x0000007f8264dc54 <+356>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dc58 <+360>: ldr x6, [x9],#8
   0x0000007f8264dc5c <+364>: add x8, x8, #0xc
   0x0000007f8264dc60 <+368>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dc64 <+372>: ldr x7, [x9],#8
   0x0000007f8264dc68 <+376>: add x8, x8, #0xc
   0x0000007f8264dc6c <+380>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dc70 <+384>: ldr s0, [x9],#4                                    ;****************************当需要load的参数是 4 byte且是 floating 时的分支****************************
   0x0000007f8264dc74 <+388>: add x15, x15, #0xc
   0x0000007f8264dc78 <+392>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dc7c <+396>: ldr s1, [x9],#4
   0x0000007f8264dc80 <+400>: add x15, x15, #0xc
---Type <return> to continue, or q <return> to quit---
   0x0000007f8264dc84 <+404>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dc88 <+408>: ldr s2, [x9],#4
   0x0000007f8264dc8c <+412>: add x15, x15, #0xc
   0x0000007f8264dc90 <+416>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dc94 <+420>: ldr s3, [x9],#4
   0x0000007f8264dc98 <+424>: add x15, x15, #0xc
   0x0000007f8264dc9c <+428>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dca0 <+432>: ldr s4, [x9],#4
   0x0000007f8264dca4 <+436>: add x15, x15, #0xc
   0x0000007f8264dca8 <+440>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dcac <+444>: ldr s5, [x9],#4
   0x0000007f8264dcb0 <+448>: add x15, x15, #0xc
   0x0000007f8264dcb4 <+452>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dcb8 <+456>: ldr s6, [x9],#4
   0x0000007f8264dcbc <+460>: add x15, x15, #0xc
   0x0000007f8264dcc0 <+464>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dcc4 <+468>: ldr s7, [x9],#4
   0x0000007f8264dcc8 <+472>: add x15, x15, #0xc
   0x0000007f8264dccc <+476>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dcd0 <+480>: ldr d0, [x9],#8                                    ;****************************当需要load的参数是 8 byte,且是 double 时的分支****************************
   0x0000007f8264dcd4 <+484>: add x15, x15, #0xc
   0x0000007f8264dcd8 <+488>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dcdc <+492>: ldr d1, [x9],#8
   0x0000007f8264dce0 <+496>: add x15, x15, #0xc
   0x0000007f8264dce4 <+500>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dce8 <+504>: ldr d2, [x9],#8
   0x0000007f8264dcec <+508>: add x15, x15, #0xc
   0x0000007f8264dcf0 <+512>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dcf4 <+516>: ldr d3, [x9],#8
   0x0000007f8264dcf8 <+520>: add x15, x15, #0xc
   0x0000007f8264dcfc <+524>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dd00 <+528>: ldr d4, [x9],#8
   0x0000007f8264dd04 <+532>: add x15, x15, #0xc
   0x0000007f8264dd08 <+536>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dd0c <+540>: ldr d5, [x9],#8
   0x0000007f8264dd10 <+544>: add x15, x15, #0xc
   0x0000007f8264dd14 <+548>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dd18 <+552>: ldr d6, [x9],#8
   0x0000007f8264dd1c <+556>: add x15, x15, #0xc
   0x0000007f8264dd20 <+560>: b   0x7f8264db70 <art_quick_invoke_stub+128>
   0x0000007f8264dd24 <+564>: ldr d7, [x9],#8
   0x0000007f8264dd28 <+568>: add x15, x15, #0xc                               
   0x0000007f8264dd2c <+572>: b   0x7f8264db70 <art_quick_invoke_stub+128>       ;**************** 准备参数的代码,至此结束,参数已经准备完毕 *****************
 
   0x0000007f8264dd30 <+576>: ldr x9, [x0,#48]                                   ; x0是 ArtMethod*,48是64bit时METHOD_QUICK_CODE_OFFSET对应的值,这条指令执行结束后,x9的值是 entry_point_from_quick_compiled_code_
   0x0000007f8264dd34 <+580>: blr x9                                             ; 跳转到 entry_point_from_quick_compiled_code_
 
   0x0000007f8264dd38 <+584>: ldp x4, x5, [x29,#16]                              ; 恢复寄存器,准备返回,其中x4 是 JValue result的地址;x5是shorty addr
   0x0000007f8264dd3c <+588>: ldr x28, [x29,#112]
   0x0000007f8264dd40 <+592>: ldp x26, x27, [x29,#96]
   0x0000007f8264dd44 <+596>: ldp x24, x25, [x29,#80]
   0x0000007f8264dd48 <+600>: ldp x22, x23, [x29,#64]
   0x0000007f8264dd4c <+604>: ldp x20, x21, [x29,#48]
   0x0000007f8264dd50 <+608>: ldrb    w10, [x5]                                   ;从x5获取 shorty第一个字节(代表返回值)
   0x0000007f8264dd54 <+612>: cmp w10, #0x56                                      ;返回值的shorty是否 'V',即void
   0x0000007f8264dd58 <+616>: b.eq    0x7f8264dd80 <art_quick_invoke_stub+656>
   0x0000007f8264dd5c <+620>: cmp w10, #0x44                                      ;'D' 是否 double 返回值
   0x0000007f8264dd60 <+624>: b.ne    0x7f8264dd6c <art_quick_invoke_stub+636>
   0x0000007f8264dd64 <+628>: str d0, [x4]                                        ;保存double值到 result中
   0x0000007f8264dd68 <+632>: b   0x7f8264dd80 <art_quick_invoke_stub+656>
   0x0000007f8264dd6c <+636>: cmp w10, #0x46                                      ;'F' 是否 floating 返回值
   0x0000007f8264dd70 <+640>: b.ne    0x7f8264dd7c <art_quick_invoke_stub+652>
   0x0000007f8264dd74 <+644>: str s0, [x4]                                        ;保存 floating值到 result中
   0x0000007f8264dd78 <+648>: b   0x7f8264dd80 <art_quick_invoke_stub+656>
   0x0000007f8264dd7c <+652>: str x0, [x4]                                        ;返回值类型不是 'V','D','F', 保存 x0到result中,不关注 32bit/64bit
   0x0000007f8264dd80 <+656>: ldp x2, x19, [x29,#32]
   0x0000007f8264dd84 <+660>: mov sp, x2
   0x0000007f8264dd88 <+664>: ldp x29, x30, [x29]
   0x0000007f8264dd8c <+668>: ret

TODO:

1.从Native调用 java method时,总是跳转到 ArtMethod的 entry_point_from_quick_compiled_code_,假如这个method没有被编译,那么它就没有对应的 native code,那怎么执行呢,后续分析 trampoline;


答:在 ClassLinker::LinkCode的时候,如果一个非static,非jni的method 没有编译 quick code,那么其就会通过:

       method→SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());把 entry_point_from_quick_compiled_code_ 设置为 art_quick_to_interpreter_bridge,

       最终调用 art_quick_to_interpreter_bridge时会跳转到 artQuickToInterpreterBridge() →  interpreter::EnterInterpreterFromEntryPoint() → interpreter::Execute() → ExecuteMterpImp()进行解释执行代码;

流程图:



  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值