mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
7082263: Reflection::resolve_field/field_get/field_set are broken
Reviewed-by: kvn, dholmes, stefank, coleenp
This commit is contained in:
parent
e3342531b4
commit
cebdce4479
15 changed files with 6 additions and 1025 deletions
|
@ -844,16 +844,6 @@ oop Reflection::new_field(fieldDescriptor* fd, bool intern_name, TRAPS) {
|
|||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Supporting routines for old native code-based reflection (pre-JDK 1.4).
|
||||
//
|
||||
// See reflection.hpp for details.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#ifdef SUPPORT_OLD_REFLECTION
|
||||
|
||||
methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, methodHandle method,
|
||||
KlassHandle recv_klass, Handle receiver, TRAPS) {
|
||||
assert(!method.is_null() , "method should not be null");
|
||||
|
@ -1081,519 +1071,6 @@ BasicType Reflection::basic_type_mirror_to_basic_type(oop basic_type_mirror, TRA
|
|||
return java_lang_Class::primitive_type(basic_type_mirror);
|
||||
}
|
||||
|
||||
|
||||
bool Reflection::match_parameter_types(methodHandle method, objArrayHandle types, int parameter_count, TRAPS) {
|
||||
int types_len = types.is_null() ? 0 : types->length();
|
||||
if (types_len != parameter_count) return false;
|
||||
if (parameter_count > 0) {
|
||||
objArrayHandle method_types = get_parameter_types(method, parameter_count, NULL, CHECK_false);
|
||||
for (int index = 0; index < parameter_count; index++) {
|
||||
if (types->obj_at(index) != method_types->obj_at(index)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
oop Reflection::new_field(FieldStream* st, TRAPS) {
|
||||
Symbol* field_name = st->name();
|
||||
Handle name = java_lang_String::create_from_symbol(field_name, CHECK_NULL);
|
||||
Symbol* signature = st->signature();
|
||||
Handle type = new_type(signature, st->klass(), CHECK_NULL);
|
||||
Handle rh = java_lang_reflect_Field::create(CHECK_NULL);
|
||||
oop result = rh();
|
||||
|
||||
java_lang_reflect_Field::set_clazz(result, st->klass()->java_mirror());
|
||||
java_lang_reflect_Field::set_slot(result, st->index());
|
||||
java_lang_reflect_Field::set_name(result, name());
|
||||
java_lang_reflect_Field::set_type(result, type());
|
||||
// Note the ACC_ANNOTATION bit, which is a per-class access flag, is never set here.
|
||||
java_lang_reflect_Field::set_modifiers(result, st->access_flags().as_int() & JVM_RECOGNIZED_FIELD_MODIFIERS);
|
||||
java_lang_reflect_Field::set_override(result, false);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool Reflection::resolve_field(Handle field_mirror, Handle& receiver, fieldDescriptor* fd, bool check_final, TRAPS) {
|
||||
if (field_mirror.is_null()) {
|
||||
THROW_(vmSymbols::java_lang_NullPointerException(), false);
|
||||
}
|
||||
|
||||
instanceKlassHandle klass (THREAD, java_lang_Class::as_klassOop(java_lang_reflect_Field::clazz(field_mirror())));
|
||||
int slot = java_lang_reflect_Field::slot(field_mirror());
|
||||
|
||||
// Ensure klass is initialized
|
||||
klass->initialize(CHECK_false);
|
||||
fd->initialize(klass(), slot);
|
||||
|
||||
bool is_static = fd->is_static();
|
||||
KlassHandle receiver_klass;
|
||||
|
||||
if (is_static) {
|
||||
receiver = KlassHandle(THREAD, klass());
|
||||
receiver_klass = klass;
|
||||
} else {
|
||||
// Check object is a non-null instance of declaring class
|
||||
if (receiver.is_null()) {
|
||||
THROW_(vmSymbols::java_lang_NullPointerException(), false);
|
||||
}
|
||||
if (!receiver->is_a(klass())) {
|
||||
THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "object is not an instance of declaring class", false);
|
||||
}
|
||||
receiver_klass = KlassHandle(THREAD, receiver->klass());
|
||||
}
|
||||
|
||||
// Access checking (unless overridden by Field)
|
||||
if (!java_lang_reflect_Field::override(field_mirror())) {
|
||||
if (!(klass->is_public() && fd->is_public())) {
|
||||
bool access_check = reflect_check_access(klass(), fd->access_flags(), receiver_klass(), false, CHECK_false);
|
||||
if (!access_check) {
|
||||
return false; // exception
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (check_final && fd->is_final()) {
|
||||
// In 1.3 we always throw an error when attempting to set a final field.
|
||||
// In 1.2.x, this was allowed in the override bit was set by calling Field.setAccessible(true).
|
||||
// We currently maintain backwards compatibility. See bug 4250960.
|
||||
bool strict_final_check = !JDK_Version::is_jdk12x_version();
|
||||
if (strict_final_check || !java_lang_reflect_Field::override(field_mirror())) {
|
||||
THROW_MSG_(vmSymbols::java_lang_IllegalAccessException(), "field is final", false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
BasicType Reflection::field_get(jvalue* value, fieldDescriptor* fd, Handle receiver) {
|
||||
BasicType field_type = fd->field_type();
|
||||
int offset = fd->offset();
|
||||
switch (field_type) {
|
||||
case T_BOOLEAN:
|
||||
value->z = receiver->bool_field(offset);
|
||||
break;
|
||||
case T_CHAR:
|
||||
value->c = receiver->char_field(offset);
|
||||
break;
|
||||
case T_FLOAT:
|
||||
value->f = receiver->float_field(offset);
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
value->d = receiver->double_field(offset);
|
||||
break;
|
||||
case T_BYTE:
|
||||
value->b = receiver->byte_field(offset);
|
||||
break;
|
||||
case T_SHORT:
|
||||
value->s = receiver->short_field(offset);
|
||||
break;
|
||||
case T_INT:
|
||||
value->i = receiver->int_field(offset);
|
||||
break;
|
||||
case T_LONG:
|
||||
value->j = receiver->long_field(offset);
|
||||
break;
|
||||
case T_OBJECT:
|
||||
case T_ARRAY:
|
||||
value->l = (jobject) receiver->obj_field(offset);
|
||||
break;
|
||||
default:
|
||||
return T_ILLEGAL;
|
||||
}
|
||||
return field_type;
|
||||
}
|
||||
|
||||
|
||||
void Reflection::field_set(jvalue* value, fieldDescriptor* fd, Handle receiver, BasicType value_type, TRAPS) {
|
||||
BasicType field_type = fd->field_type();
|
||||
if (field_type != value_type) {
|
||||
widen(value, value_type, field_type, CHECK);
|
||||
}
|
||||
|
||||
int offset = fd->offset();
|
||||
switch (field_type) {
|
||||
case T_BOOLEAN:
|
||||
receiver->bool_field_put(offset, value->z);
|
||||
break;
|
||||
case T_CHAR:
|
||||
receiver->char_field_put(offset, value->c);
|
||||
break;
|
||||
case T_FLOAT:
|
||||
receiver->float_field_put(offset, value->f);
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
receiver->double_field_put(offset, value->d);
|
||||
break;
|
||||
case T_BYTE:
|
||||
receiver->byte_field_put(offset, value->b);
|
||||
break;
|
||||
case T_SHORT:
|
||||
receiver->short_field_put(offset, value->s);
|
||||
break;
|
||||
case T_INT:
|
||||
receiver->int_field_put(offset, value->i);
|
||||
break;
|
||||
case T_LONG:
|
||||
receiver->long_field_put(offset, value->j);
|
||||
break;
|
||||
case T_OBJECT:
|
||||
case T_ARRAY: {
|
||||
Handle obj(THREAD, (oop) value->l);
|
||||
if (obj.not_null()) {
|
||||
Symbol* signature = fd->signature();
|
||||
Handle loader (THREAD, fd->loader());
|
||||
Handle protect (THREAD, Klass::cast(fd->field_holder())->protection_domain());
|
||||
klassOop k = SystemDictionary::resolve_or_fail(signature, loader, protect, true, CHECK); // may block
|
||||
if (!obj->is_a(k)) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "field type mismatch");
|
||||
}
|
||||
}
|
||||
receiver->obj_field_put(offset, obj());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "field type mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
oop Reflection::reflect_field(oop mirror, Symbol* field_name, jint which, TRAPS) {
|
||||
// Exclude primitive types and array types
|
||||
if (java_lang_Class::is_primitive(mirror)) return NULL;
|
||||
if (Klass::cast(java_lang_Class::as_klassOop(mirror))->oop_is_array()) return NULL;
|
||||
|
||||
instanceKlassHandle k(THREAD, java_lang_Class::as_klassOop(mirror));
|
||||
bool local_fields_only = (which == DECLARED);
|
||||
|
||||
// Ensure class is linked
|
||||
k->link_class(CHECK_NULL);
|
||||
|
||||
// Search class and interface fields
|
||||
for (FieldStream st(k, local_fields_only, false); !st.eos(); st.next()) {
|
||||
if (st.name() == field_name) {
|
||||
if (local_fields_only || st.access_flags().is_public()) {
|
||||
return new_field(&st, THREAD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
objArrayOop Reflection::reflect_fields(oop mirror, jint which, TRAPS) {
|
||||
// Exclude primitive types and array types
|
||||
if (java_lang_Class::is_primitive(mirror)
|
||||
|| Klass::cast(java_lang_Class::as_klassOop(mirror))->oop_is_array()) {
|
||||
Symbol* name = vmSymbols::java_lang_reflect_Field();
|
||||
klassOop klass = SystemDictionary::resolve_or_fail(name, true, CHECK_NULL);
|
||||
return oopFactory::new_objArray(klass, 0, CHECK_NULL); // Return empty array
|
||||
}
|
||||
|
||||
instanceKlassHandle k(THREAD, java_lang_Class::as_klassOop(mirror));
|
||||
|
||||
// Ensure class is linked
|
||||
k->link_class(CHECK_NULL);
|
||||
|
||||
bool local_fields_only = (which == DECLARED);
|
||||
int count = 0;
|
||||
{ // Compute fields count for class and interface fields
|
||||
for (FieldStream st(k, local_fields_only, false); !st.eos(); st.next()) {
|
||||
if (local_fields_only || st.access_flags().is_public()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate result
|
||||
Symbol* name = vmSymbols::java_lang_reflect_Field();
|
||||
klassOop klass = SystemDictionary::resolve_or_fail(name, true, CHECK_NULL);
|
||||
objArrayOop r = oopFactory::new_objArray(klass, count, CHECK_NULL);
|
||||
objArrayHandle result (THREAD, r);
|
||||
|
||||
// Fill in results backwards
|
||||
{
|
||||
for (FieldStream st(k, local_fields_only, false); !st.eos(); st.next()) {
|
||||
if (local_fields_only || st.access_flags().is_public()) {
|
||||
oop field = new_field(&st, CHECK_NULL);
|
||||
result->obj_at_put(--count, field);
|
||||
}
|
||||
}
|
||||
assert(count == 0, "just checking");
|
||||
}
|
||||
return result();
|
||||
}
|
||||
|
||||
|
||||
oop Reflection::reflect_method(oop mirror, Symbol* method_name, objArrayHandle types, jint which, TRAPS) {
|
||||
if (java_lang_Class::is_primitive(mirror)) return NULL;
|
||||
klassOop klass = java_lang_Class::as_klassOop(mirror);
|
||||
if (Klass::cast(klass)->oop_is_array() && which == MEMBER_DECLARED) return NULL;
|
||||
|
||||
if (Klass::cast(java_lang_Class::as_klassOop(mirror))->oop_is_array()) {
|
||||
klass = SystemDictionary::Object_klass();
|
||||
}
|
||||
instanceKlassHandle h_k(THREAD, klass);
|
||||
|
||||
// Ensure klass is linked (need not be initialized)
|
||||
h_k->link_class(CHECK_NULL);
|
||||
|
||||
// For interfaces include static initializers under jdk1.2.x (since classic does that)
|
||||
bool include_clinit = JDK_Version::is_jdk12x_version() && h_k->is_interface();
|
||||
|
||||
switch (which) {
|
||||
case MEMBER_PUBLIC:
|
||||
// First the public non-static methods (works if method holder is an interface)
|
||||
// Note that we can ignore checks for overridden methods, since we go up the hierarchy.
|
||||
{
|
||||
for (MethodStream st(h_k, false, false); !st.eos(); st.next()) {
|
||||
methodHandle m(THREAD, st.method());
|
||||
// For interfaces include static initializers since classic does that!
|
||||
if (method_name == m->name() && (include_clinit || (m->is_public() && !m->is_static() && !m->is_initializer()))) {
|
||||
Symbol* signature = m->signature();
|
||||
bool parameter_match = match_parameter_types(m, types, ArgumentCount(signature).size(), CHECK_NULL);
|
||||
if (parameter_match) {
|
||||
return new_method(m, false, false, THREAD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Then the public static methods (works if method holder is an interface)
|
||||
{
|
||||
for (MethodStream st(h_k, false, false); !st.eos(); st.next()) {
|
||||
methodHandle m(THREAD, st.method());
|
||||
if (method_name == m->name() && m->is_public() && m->is_static() && !m->is_initializer()) {
|
||||
Symbol* signature = m->signature();
|
||||
bool parameter_match = match_parameter_types(m, types, ArgumentCount(signature).size(), CHECK_NULL);
|
||||
if (parameter_match) {
|
||||
return new_method(m, false, false, THREAD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MEMBER_DECLARED:
|
||||
// All local methods
|
||||
{
|
||||
for (MethodStream st(h_k, true, true); !st.eos(); st.next()) {
|
||||
methodHandle m(THREAD, st.method());
|
||||
if (method_name == m->name() && !m->is_initializer()) {
|
||||
Symbol* signature = m->signature();
|
||||
bool parameter_match = match_parameter_types(m, types, ArgumentCount(signature).size(), CHECK_NULL);
|
||||
if (parameter_match) {
|
||||
return new_method(m, false, false, THREAD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
objArrayOop Reflection::reflect_methods(oop mirror, jint which, TRAPS) {
|
||||
// Exclude primitive types
|
||||
if (java_lang_Class::is_primitive(mirror) ||
|
||||
(Klass::cast(java_lang_Class::as_klassOop(mirror))->oop_is_array() && (which == MEMBER_DECLARED))) {
|
||||
klassOop klass = SystemDictionary::reflect_Method_klass();
|
||||
return oopFactory::new_objArray(klass, 0, CHECK_NULL); // Return empty array
|
||||
}
|
||||
|
||||
klassOop klass = java_lang_Class::as_klassOop(mirror);
|
||||
if (Klass::cast(java_lang_Class::as_klassOop(mirror))->oop_is_array()) {
|
||||
klass = SystemDictionary::Object_klass();
|
||||
}
|
||||
instanceKlassHandle h_k(THREAD, klass);
|
||||
|
||||
// Ensure klass is linked (need not be initialized)
|
||||
h_k->link_class(CHECK_NULL);
|
||||
|
||||
// We search the (super)interfaces only if h_k is an interface itself
|
||||
bool is_interface = h_k->is_interface();
|
||||
|
||||
// For interfaces include static initializers under jdk1.2.x (since classic does that)
|
||||
bool include_clinit = JDK_Version::is_jdk12x_version() && is_interface;
|
||||
|
||||
switch (which) {
|
||||
case MEMBER_PUBLIC:
|
||||
{
|
||||
|
||||
// Count public methods (non-static and static)
|
||||
int count = 0;
|
||||
{
|
||||
for (MethodStream st(h_k, false, false); !st.eos(); st.next()) {
|
||||
methodOop m = st.method();
|
||||
// For interfaces include static initializers since classic does that!
|
||||
if (include_clinit || (!m->is_initializer() && m->is_public() && !m->is_overridden_in(h_k()))) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate result
|
||||
klassOop klass = SystemDictionary::reflect_Method_klass();
|
||||
objArrayOop r = oopFactory::new_objArray(klass, count, CHECK_NULL);
|
||||
objArrayHandle h_result (THREAD, r);
|
||||
|
||||
// Fill in results backwards
|
||||
{
|
||||
// First the non-static public methods
|
||||
for (MethodStream st(h_k, false, false); !st.eos(); st.next()) {
|
||||
methodHandle m (THREAD, st.method());
|
||||
if (!m->is_static() && !m->is_initializer() && m->is_public() && !m->is_overridden_in(h_k())) {
|
||||
oop method = new_method(m, false, false, CHECK_NULL);
|
||||
if (method == NULL) {
|
||||
return NULL;
|
||||
} else {
|
||||
h_result->obj_at_put(--count, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// Then the static public methods
|
||||
for (MethodStream st(h_k, false, !is_interface); !st.eos(); st.next()) {
|
||||
methodHandle m (THREAD, st.method());
|
||||
if (m->is_static() && (include_clinit || (!m->is_initializer()) && m->is_public() && !m->is_overridden_in(h_k()))) {
|
||||
oop method = new_method(m, false, false, CHECK_NULL);
|
||||
if (method == NULL) {
|
||||
return NULL;
|
||||
} else {
|
||||
h_result->obj_at_put(--count, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(count == 0, "just checking");
|
||||
return h_result();
|
||||
}
|
||||
|
||||
case MEMBER_DECLARED:
|
||||
{
|
||||
// Count all methods
|
||||
int count = 0;
|
||||
{
|
||||
for (MethodStream st(h_k, true, !is_interface); !st.eos(); st.next()) {
|
||||
methodOop m = st.method();
|
||||
if (!m->is_initializer()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Allocate result
|
||||
klassOop klass = SystemDictionary::reflect_Method_klass();
|
||||
objArrayOop r = oopFactory::new_objArray(klass, count, CHECK_NULL);
|
||||
objArrayHandle h_result (THREAD, r);
|
||||
|
||||
// Fill in results backwards
|
||||
{
|
||||
for (MethodStream st(h_k, true, true); !st.eos(); st.next()) {
|
||||
methodHandle m (THREAD, st.method());
|
||||
if (!m->is_initializer()) {
|
||||
oop method = new_method(m, false, false, CHECK_NULL);
|
||||
if (method == NULL) {
|
||||
return NULL;
|
||||
} else {
|
||||
h_result->obj_at_put(--count, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(count == 0, "just checking");
|
||||
return h_result();
|
||||
}
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
oop Reflection::reflect_constructor(oop mirror, objArrayHandle types, jint which, TRAPS) {
|
||||
|
||||
// Exclude primitive, interface and array types
|
||||
bool prim = java_lang_Class::is_primitive(mirror);
|
||||
Klass* klass = prim ? NULL : Klass::cast(java_lang_Class::as_klassOop(mirror));
|
||||
if (prim || klass->is_interface() || klass->oop_is_array()) return NULL;
|
||||
|
||||
// Must be instance klass
|
||||
instanceKlassHandle h_k(THREAD, java_lang_Class::as_klassOop(mirror));
|
||||
|
||||
// Ensure klass is linked (need not be initialized)
|
||||
h_k->link_class(CHECK_NULL);
|
||||
|
||||
bool local_only = (which == MEMBER_DECLARED);
|
||||
for (MethodStream st(h_k, true, true); !st.eos(); st.next()) {
|
||||
methodHandle m(THREAD, st.method());
|
||||
if (m->name() == vmSymbols::object_initializer_name() && (local_only || m->is_public())) {
|
||||
Symbol* signature = m->signature();
|
||||
bool parameter_match = match_parameter_types(m, types, ArgumentCount(signature).size(), CHECK_NULL);
|
||||
if (parameter_match) {
|
||||
return new_constructor(m, THREAD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
objArrayOop Reflection::reflect_constructors(oop mirror, jint which, TRAPS) {
|
||||
// Exclude primitive, interface and array types
|
||||
bool prim = java_lang_Class::is_primitive(mirror);
|
||||
Klass* k = prim ? NULL : Klass::cast(java_lang_Class::as_klassOop(mirror));
|
||||
if (prim || k->is_interface() || k->oop_is_array()) {
|
||||
return oopFactory::new_objArray(SystemDictionary::reflect_Constructor_klass(), 0, CHECK_NULL); // Return empty array
|
||||
}
|
||||
|
||||
// Must be instanceKlass at this point
|
||||
instanceKlassHandle h_k(THREAD, java_lang_Class::as_klassOop(mirror));
|
||||
|
||||
// Ensure klass is linked (need not be initialized)
|
||||
h_k->link_class(CHECK_NULL);
|
||||
|
||||
bool local_only = (which == MEMBER_DECLARED);
|
||||
int count = 0;
|
||||
{
|
||||
for (MethodStream st(h_k, true, true); !st.eos(); st.next()) {
|
||||
methodOop m = st.method();
|
||||
if (m->name() == vmSymbols::object_initializer_name() && (local_only || m->is_public())) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate result
|
||||
Symbol* name = vmSymbols::java_lang_reflect_Constructor();
|
||||
klassOop klass = SystemDictionary::resolve_or_fail(name, true, CHECK_NULL);
|
||||
objArrayOop r = oopFactory::new_objArray(klass, count, CHECK_NULL);
|
||||
objArrayHandle h_result (THREAD, r);
|
||||
|
||||
// Fill in results backwards
|
||||
{
|
||||
for (MethodStream st(h_k, true, true); !st.eos(); st.next()) {
|
||||
methodHandle m (THREAD, st.method());
|
||||
if (m->name() == vmSymbols::object_initializer_name() && (local_only || m->is_public())) {
|
||||
oop constr = new_constructor(m, CHECK_NULL);
|
||||
if (constr == NULL) {
|
||||
return NULL;
|
||||
} else {
|
||||
h_result->obj_at_put(--count, constr);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(count == 0, "just checking");
|
||||
}
|
||||
return h_result();
|
||||
}
|
||||
|
||||
|
||||
// This would be nicer if, say, java.lang.reflect.Method was a subclass
|
||||
// of java.lang.reflect.Constructor
|
||||
|
||||
|
@ -1647,6 +1124,3 @@ oop Reflection::invoke_constructor(oop constructor_mirror, objArrayHandle args,
|
|||
invoke(klass, method, receiver, override, ptypes, T_VOID, args, false, CHECK_NULL);
|
||||
return receiver();
|
||||
}
|
||||
|
||||
|
||||
#endif /* SUPPORT_OLD_REFLECTION */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue