📄 natmethod.cc
字号:
} *arg_types_out = args;}// This is a very rough analog of the JNI CallNonvirtual<type>MethodA// functions. It handles both Methods and Constructors, and it can// handle any return type. In the Constructor case, the `obj'// argument is unused and should be NULL; also, the `return_type' is// the class that the constructor will construct. RESULT is a pointer// to a `jvalue' (see jni.h); for a void method this should be NULL.// This function returns an exception (if one was thrown), or NULL if// the call went ok.jthrowable_Jv_CallAnyMethodA (jobject obj, jclass return_type, jmethodID meth, jboolean is_constructor, JArray<jclass> *parameter_types, jvalue *args, jvalue *result){#ifdef USE_LIBFFI JvAssert (! is_constructor || ! obj); JvAssert (! is_constructor || return_type); // See whether call needs an object as the first argument. A // constructor does need a `this' argument, but it is one we create. jboolean needs_this = false; if (is_constructor || ! java::lang::reflect::Modifier::isStatic(meth->accflags)) needs_this = true; int param_count = parameter_types->length; if (needs_this) ++param_count; ffi_type *rtype; // A constructor itself always returns void. if (is_constructor || return_type == JvPrimClass (void)) rtype = &ffi_type_void; else rtype = get_ffi_type (return_type); ffi_type **argtypes = (ffi_type **) __builtin_alloca (param_count * sizeof (ffi_type *)); jclass *paramelts = elements (parameter_types); // FIXME: at some point the compiler is going to add extra arguments // to some functions. In particular we are going to do this for // handling access checks in reflection. We must add these hidden // arguments here. // Special case for the `this' argument of a constructor. Note that // the JDK 1.2 docs specify that the new object must be allocated // before argument conversions are done. if (is_constructor) { // FIXME: must special-case String, arrays, maybe others here. obj = JvAllocObject (return_type); } const int size_per_arg = sizeof(jvalue); ffi_cif cif; char *p = (char *) __builtin_alloca (param_count * size_per_arg); // Overallocate to get correct alignment. void **values = (void **) __builtin_alloca (param_count * sizeof (void *)); int i = 0; if (needs_this) { // The `NULL' type is `Object'. argtypes[i] = get_ffi_type (NULL); values[i] = p; memcpy (p, &obj, sizeof (jobject)); p += size_per_arg; ++i; } for (int arg = 0; i < param_count; ++i, ++arg) { int tsize; argtypes[i] = get_ffi_type (paramelts[arg]); if (paramelts[arg]->isPrimitive()) tsize = paramelts[arg]->size(); else tsize = sizeof (jobject); // Copy appropriate bits from the jvalue into the ffi array. // FIXME: we could do this copying all in one loop, above, by // over-allocating a bit. // How do we do this without breaking big-endian platforms? values[i] = p; memcpy (p, &args[arg], tsize); p += size_per_arg; } if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, param_count, rtype, argtypes) != FFI_OK) { // FIXME: throw some kind of VirtualMachineError here. } using namespace java::lang; using namespace java::lang::reflect; Throwable *ex = NULL; union { ffi_arg i; jobject o; jlong l; jfloat f; jdouble d; } ffi_result; try { ffi_call (&cif, (void (*)()) meth->ncode, &ffi_result, values); } catch (Throwable *ex2) { // FIXME: this is wrong for JNI. But if we just return the // exception, then the non-JNI cases won't be able to // distinguish it from exceptions we might generate ourselves. // Sigh. ex = new InvocationTargetException (ex2); } // Since ffi_call returns integer values promoted to a word, use // a narrowing conversion for jbyte, jchar, etc. results. // Note that boolean is handled either by the FFI_TYPE_SINT8 or // FFI_TYPE_SINT32 case. if (is_constructor) result->l = obj; else { switch (rtype->type) { case FFI_TYPE_VOID: break; case FFI_TYPE_SINT8: result->b = (jbyte)ffi_result.i; break; case FFI_TYPE_SINT16: result->s = (jshort)ffi_result.i; break; case FFI_TYPE_UINT16: result->c = (jchar)ffi_result.i; break; case FFI_TYPE_SINT32: result->i = (jint)ffi_result.i; break; case FFI_TYPE_SINT64: result->j = (jlong)ffi_result.l; break; case FFI_TYPE_FLOAT: result->f = (jfloat)ffi_result.f; break; case FFI_TYPE_DOUBLE: result->d = (jdouble)ffi_result.d; break; case FFI_TYPE_POINTER: result->l = (jobject)ffi_result.o; break; default: JvFail ("Unknown ffi_call return type"); break; } } return ex;#else throw new java::lang::UnsupportedOperationException; return 0;#endif // USE_LIBFFI}// This is another version of _Jv_CallAnyMethodA, but this one does// more checking and is used by the reflection (and not JNI) code.jobject_Jv_CallAnyMethodA (jobject obj, jclass return_type, jmethodID meth, jboolean is_constructor, JArray<jclass> *parameter_types, jobjectArray args){ // FIXME: access checks. if (parameter_types->length == 0 && args == NULL) { // The JDK accepts this, so we do too. } else if (parameter_types->length != args->length) throw new java::lang::IllegalArgumentException; int param_count = parameter_types->length; jclass *paramelts = elements (parameter_types); jobject *argelts = args == NULL ? NULL : elements (args); jvalue argvals[param_count];#define COPY(Where, What, Type) \ do { \ Type val = (What); \ memcpy ((Where), &val, sizeof (Type)); \ } while (0) for (int i = 0; i < param_count; ++i) { jclass k = argelts[i] ? argelts[i]->getClass() : NULL; if (paramelts[i]->isPrimitive()) { if (! argelts[i] || ! k || ! can_widen (k, paramelts[i])) throw new java::lang::IllegalArgumentException; if (paramelts[i] == JvPrimClass (boolean)) COPY (&argvals[i], ((java::lang::Boolean *) argelts[i])->booleanValue(), jboolean); else if (paramelts[i] == JvPrimClass (char)) COPY (&argvals[i], ((java::lang::Character *) argelts[i])->charValue(), jchar); else { java::lang::Number *num = (java::lang::Number *) argelts[i]; if (paramelts[i] == JvPrimClass (byte)) COPY (&argvals[i], num->byteValue(), jbyte); else if (paramelts[i] == JvPrimClass (short)) COPY (&argvals[i], num->shortValue(), jshort); else if (paramelts[i] == JvPrimClass (int)) COPY (&argvals[i], num->intValue(), jint); else if (paramelts[i] == JvPrimClass (long)) COPY (&argvals[i], num->longValue(), jlong); else if (paramelts[i] == JvPrimClass (float)) COPY (&argvals[i], num->floatValue(), jfloat); else if (paramelts[i] == JvPrimClass (double)) COPY (&argvals[i], num->doubleValue(), jdouble); } } else { if (argelts[i] && ! paramelts[i]->isAssignableFrom (k)) throw new java::lang::IllegalArgumentException; COPY (&argvals[i], argelts[i], jobject); } } jvalue ret_value; java::lang::Throwable *ex = _Jv_CallAnyMethodA (obj, return_type, meth, is_constructor, parameter_types, argvals, &ret_value); if (ex) throw ex; jobject r;#define VAL(Wrapper, Field) (new Wrapper (ret_value.Field)) if (is_constructor) r = ret_value.l; else if (return_type == JvPrimClass (byte)) r = VAL (java::lang::Byte, b); else if (return_type == JvPrimClass (short)) r = VAL (java::lang::Short, s); else if (return_type == JvPrimClass (int)) r = VAL (java::lang::Integer, i); else if (return_type == JvPrimClass (long)) r = VAL (java::lang::Long, j); else if (return_type == JvPrimClass (float)) r = VAL (java::lang::Float, f); else if (return_type == JvPrimClass (double)) r = VAL (java::lang::Double, d); else if (return_type == JvPrimClass (boolean)) r = VAL (java::lang::Boolean, z); else if (return_type == JvPrimClass (char)) r = VAL (java::lang::Character, c); else if (return_type == JvPrimClass (void)) r = NULL; else { JvAssert (return_type == NULL || ! return_type->isPrimitive()); r = ret_value.l; } return r;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -