1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16/* 17 * This uses the FFI (Foreign Function Interface) library to abstract away 18 * the system-dependent stuff. The FFI code is slower than a custom 19 * assembly version, but has the distinct advantage of having been 20 * written already for several platforms. 21 */ 22#include "Dalvik.h" 23#include "ffi.h" 24 25/* 26 * Convert a signature type character to an FFI type. 27 */ 28static ffi_type* getFfiType(char sigType) 29{ 30 switch (sigType) { 31 case 'V': return &ffi_type_void; 32 case 'F': return &ffi_type_float; 33 case 'D': return &ffi_type_double; 34 case 'J': return &ffi_type_sint64; 35 case '[': 36 case 'L': return &ffi_type_pointer; 37 default: return &ffi_type_uint32; 38 } 39} 40 41/* 42 * Call "func" with the specified arguments. 43 * 44 * The second argument to JNI native functions is either the object (the 45 * "this" pointer) or, for static functions, a pointer to the class object. 46 * The Dalvik instructions will push "this" into argv[0], but it's up to 47 * us to insert the class object. 48 * 49 * Because there is no such thing in as a null "this" pointer, we use 50 * the non-NULL state of "clazz" to determine whether or not it's static. 51 * 52 * For maximum efficiency we should compute the CIF once and save it with 53 * the method. However, this requires storing the data with every native 54 * method. Since the goal is to have custom assembly versions of this 55 * on the platforms where performance matters, I'm recomputing the CIF on 56 * every call. 57 */ 58void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc, 59 const u4* argv, const char* shorty, void* func, JValue* pReturn) 60{ 61 const int kMaxArgs = argc+2; /* +1 for env, maybe +1 for clazz */ 62 ffi_cif cif; 63 ffi_type* types[kMaxArgs]; 64 void* values[kMaxArgs]; 65 ffi_type* retType; 66 const char* sig; 67 char sigByte; 68 int srcArg, dstArg; 69 70 types[0] = &ffi_type_pointer; 71 values[0] = &pEnv; 72 73 types[1] = &ffi_type_pointer; 74 if (clazz != NULL) { 75 values[1] = &clazz; 76 srcArg = 0; 77 } else { 78 values[1] = (void*) argv++; 79 srcArg = 1; 80 } 81 dstArg = 2; 82 83 /* 84 * Scan the types out of the short signature. Use them to fill out the 85 * "types" array. Store the start address of the argument in "values". 86 */ 87 retType = getFfiType(*shorty); 88 while ((sigByte = *++shorty) != '\0') { 89 types[dstArg] = getFfiType(sigByte); 90 values[dstArg++] = (void*) argv++; 91 if (sigByte == 'D' || sigByte == 'J') 92 argv++; 93 } 94 95 /* 96 * Prep the CIF (Call InterFace object). 97 */ 98 if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, dstArg, retType, types) != FFI_OK) { 99 LOGE("ffi_prep_cif failed\n"); 100 dvmAbort(); 101 } 102 103 ffi_call(&cif, FFI_FN(func), pReturn, values); 104} 105