blob: fe8cfbd2d438ffae06accfb6783cabf4bbd1eb7c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file java_lang_reflect_VMReflection.cpp
*
* This file is a part of kernel class natives VM core component.
* It contains implementation for native methods of
* java.lang.reflect.VMReflection class.
*/
#define LOG_DOMAIN "vm.core.reflection"
#include "cxxlog.h"
#include "reflection.h"
#include "open/vm_field_access.h"
#include "open/vm_method_access.h"
#include "open/vm_class_manipulation.h"
#include "environment.h"
#include "exceptions.h"
#include "vm_strings.h"
#include "primitives_support.h"
#include "jni_utils.h"
#include "Class.h"
#include "classloader.h"
#include "java_lang_VMClassRegistry.h"
#include "java_lang_reflect_VMReflection.h"
JNIEXPORT jobjectArray JNICALL Java_java_lang_reflect_VMReflection_getExceptionTypes
(JNIEnv *jenv, jclass, jlong member)
{
Method_Handle method = (Method_Handle) ((POINTER_SIZE_INT) member);
jclass jlc_class = struct_Class_to_java_lang_Class_Handle(
VM_Global_State::loader_env->JavaLangClass_Class);
// Create and fill exceptions array
int n_exceptions = method->num_exceptions_method_can_throw();
jobjectArray exceptionTypes = NewObjectArray(jenv, n_exceptions, jlc_class, NULL);
if (!exceptionTypes) {
assert(exn_raised());
return NULL;
}
for (int i = 0; i < n_exceptions; i++) {
Class_Handle exclass = method->get_class()->get_class_loader()->
LoadVerifyAndPrepareClass(VM_Global_State::loader_env, method->get_exception_name(i));
if (!exclass) {
assert(exn_raised());
return NULL;
}
SetObjectArrayElement(jenv, exceptionTypes, i,
struct_Class_to_java_lang_Class_Handle(exclass));
}
return exceptionTypes;
}
JNIEXPORT jobjectArray JNICALL Java_java_lang_reflect_VMReflection_getParameterTypes
(JNIEnv *jenv, jclass, jlong member)
{
Method_Handle mh = (Method_Handle) ((POINTER_SIZE_INT) member);
return reflection_get_parameter_types(jenv, mh);
}
JNIEXPORT jclass JNICALL Java_java_lang_reflect_VMReflection_getMethodReturnType
(JNIEnv *jenv, jclass, jlong member)
{
Method_Handle method = (Method_Handle) ((POINTER_SIZE_INT) member);
Method_Signature_Handle msh = method_get_signature(method);
Type_Info_Handle ret_type = method_ret_type_get_type_info(msh);
return descriptor_to_jclass(ret_type);
}
JNIEXPORT jclass JNICALL Java_java_lang_reflect_VMReflection_getFieldType
(JNIEnv *jenv, jclass, jlong member)
{
Field_Handle fh = (Field_Handle) ((POINTER_SIZE_INT) member);
Type_Info_Handle fti = field_get_type_info(fh);
return descriptor_to_jclass(fti);
}
/*
* Returns false if no exception is set. If exception is set and is not
* an OOME instance, wraps it into new InvocationTargetException.
*/
static bool rethrow_invocation_exception(JNIEnv* jenv)
{
Class* exn_class = exn_get_class();
if (!exn_class)
return false;
Global_Env* genv = VM_Global_State::loader_env;
if (exn_class == genv->java_lang_OutOfMemoryError_Class) {
return true;
}
jthrowable exn = exn_get();
//FIXME need better handling for lazy exceptions
if (!exn) {
LWARN(40, "ATTENTION! Could not get cause exception from lazy machinery");
}
exn_clear();
//static Class* ITE_class = genv->LoadCoreClass(
// genv->string_pool.lookup("java/lang/reflect/InvocationTargetException"));
exn_raise_by_name("java/lang/reflect/InvocationTargetException", exn);
return true;
}
// Invoke method with primitive return type. Return result in wrapper. For void return NULL.
static jobject invoke_primitive_method(JNIEnv* jenv, jobject obj, jclass declaring_class, Method* method, jvalue* jvalue_args)
{
jmethodID method_id = (jmethodID) method;
bool is_static = method->is_static();
Java_Type return_type = method->get_return_java_type();
jvalue result;
switch(return_type) {
case JAVA_TYPE_BOOLEAN:
if (is_static)
result.z = CallStaticBooleanMethodA(jenv, declaring_class, method_id, jvalue_args);
else
result.z = CallBooleanMethodA(jenv, obj, method_id, jvalue_args);
break;
case JAVA_TYPE_BYTE:
if (is_static)
result.b = CallStaticByteMethodA(jenv, declaring_class, method_id, jvalue_args);
else
result.b = CallByteMethodA(jenv, obj, method_id, jvalue_args);
break;
case JAVA_TYPE_CHAR:
if (is_static)
result.c = CallStaticCharMethodA(jenv, declaring_class, method_id, jvalue_args);
else
result.c = CallCharMethodA(jenv, obj, method_id, jvalue_args);
break;
case JAVA_TYPE_SHORT:
if (is_static)
result.s = CallStaticShortMethodA(jenv, declaring_class, method_id, jvalue_args);
else
result.s = CallShortMethodA(jenv, obj, method_id, jvalue_args);
break;
case JAVA_TYPE_INT:
if (is_static)
result.i = CallStaticIntMethodA(jenv, declaring_class, method_id, jvalue_args);
else
result.i = CallIntMethodA(jenv, obj, method_id, jvalue_args);
break;
case JAVA_TYPE_LONG:
if (is_static)
result.j = CallStaticLongMethodA(jenv, declaring_class, method_id, jvalue_args);
else
result.j = CallLongMethodA(jenv, obj, method_id, jvalue_args);
break;
case JAVA_TYPE_FLOAT:
if (is_static)
result.f = CallStaticFloatMethodA(jenv, declaring_class, method_id, jvalue_args);
else
result.f = CallFloatMethodA(jenv, obj, method_id, jvalue_args);
break;
case JAVA_TYPE_DOUBLE:
if (is_static)
result.d = CallStaticDoubleMethodA(jenv, declaring_class, method_id, jvalue_args);
else
result.d = CallDoubleMethodA(jenv, obj, method_id, jvalue_args);
break;
case JAVA_TYPE_VOID:
if (is_static)
CallStaticVoidMethodA(jenv, declaring_class, method_id, jvalue_args);
else
CallVoidMethodA(jenv, obj, method_id, jvalue_args);
return NULL;
break;
default:
LDIE(53, "Unexpected java type");
}
return exn_raised() ? NULL : wrap_primitive(jenv, result, (char)return_type);
}
JNIEXPORT jobject JNICALL Java_java_lang_reflect_VMReflection_invokeMethod
(JNIEnv *jenv, jclass, jlong member, jobject obj, jobjectArray args)
{
Class* type = VM_Global_State::loader_env->java_lang_reflect_Method_Class;
Method_Handle method = (Method_Handle) ((POINTER_SIZE_INT) member);
TRACE("invoke : " << method->get_class()->get_name()->bytes << "." << method->get_name()->bytes << "()");
unsigned num_args = method->get_num_args();
jvalue *jvalue_args = (jvalue *)STD_ALLOCA(num_args * sizeof(jvalue));
if (!jobjectarray_to_jvaluearray(jenv, &jvalue_args, method, args)) {
return NULL;
}
jobject jresult;
// In a case of class initialization error, it must be thrown directly
if (!ensure_initialised(jenv, method->get_class())) {
assert(exn_raised());
return NULL;
}
jclass declaring_class = struct_Class_to_java_lang_Class_Handle(method->get_class());
Java_Type return_type = method->get_return_java_type();
if (return_type != JAVA_TYPE_CLASS && return_type != JAVA_TYPE_ARRAY)
{
jresult = invoke_primitive_method(jenv, obj, declaring_class, method, jvalue_args);
}
else if (method->is_static())
{
jresult = CallStaticObjectMethodA(jenv, declaring_class, (jmethodID)method, jvalue_args);
}
else
{
jresult = CallObjectMethodA(jenv, obj, (jmethodID)method, jvalue_args);
}
// check and chain exception, if occurred
if (rethrow_invocation_exception(jenv)) {
return NULL;
}
return jresult;
} // Java_java_lang_reflect_VMReflection_invokeMethod
// create multidimensional array with depth dimensions specified by dims
jobject createArray(JNIEnv *jenv, Class* arrType, jint *dims, int depth)
{
jint size = dims[0];
jobjectArray jarray = NewObjectArray(jenv, size,
struct_Class_to_java_lang_Class_Handle(arrType), NULL);
if (exn_raised()) {
return NULL;
}
if (depth > 1)
{
Class* compType = arrType->get_array_element_class();
for (int i = 0; i < size; i++)
{
jobject elem = createArray(jenv, compType, dims + 1, depth - 1);
SetObjectArrayElement(jenv, jarray, i, elem);
}
}
return jarray;
}
JNIEXPORT jobject JNICALL Java_java_lang_reflect_VMReflection_newArrayInstance
(JNIEnv *jenv, jclass, jclass compType, jintArray jdims)
{
jint depth = GetArrayLength(jenv, jdims);
TRACE("new array: depth=" << depth);
if (depth <= 0 || depth > 255) {
const char *message = (depth <= 0) ? "negative or zero dimensional array specified." :
"requested dimensions number exceeds 255 supported limit." ;
ThrowNew_Quick(jenv, "java/lang/IllegalArgumentException", message);
return NULL;
}
jint* dims = GetIntArrayElements(jenv, jdims, NULL);
for (int i = 0; i < depth; i++) {
if (dims[i] < 0) {
ReleaseIntArrayElements(jenv, jdims, dims, JNI_ABORT);
ThrowNew_Quick(jenv, "java/lang/NegativeArraySizeException",
"one of the specified dimensions is negative.");
return NULL;
}
}
Class* arrClss = jclass_to_struct_Class(compType);
for (int i = depth - 1; i > 0; --i) {
arrClss = class_get_array_of_class(arrClss);
if (!arrClss) {
assert(exn_raised());
break;
}
}
jobject jarray = arrClss ? createArray(jenv, arrClss, dims, depth) : NULL;
ReleaseIntArrayElements(jenv, jdims, dims, JNI_ABORT);
return jarray;
}
JNIEXPORT jobject JNICALL Java_java_lang_reflect_VMReflection_newClassInstance
(JNIEnv *jenv, jclass, jlong member, jobjectArray args)
{
Method_Handle method = (Method_Handle) ((POINTER_SIZE_INT) member);
TRACE("new class instance : " << method->get_class()->get_name()->bytes);
unsigned num_args = method->get_num_args();
jvalue *jvalue_args = (jvalue *)STD_ALLOCA(num_args * sizeof(jvalue));
if (!jobjectarray_to_jvaluearray(jenv, &jvalue_args, method, args)) {
return NULL;
}
jclass declaring_class = struct_Class_to_java_lang_Class_Handle(method->get_class());
// In a case of class initialization error, it must be thrown directly
if (!ensure_initialised(jenv, method->get_class()))
return NULL;
// Create object
jobject new_object = NewObjectA(jenv, declaring_class, (jmethodID) method, jvalue_args);
// check and chain exception, if occurred
if (rethrow_invocation_exception(jenv)) {
return NULL;
}
return new_object;
} // Java_java_lang_reflect_VMReflection_newClassInstance