vm/vmcore/include/class_member.h (477 lines of code) (raw):
/*
* 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.
*/
#ifndef __CLASS_MEMBER_H__
#define __CLASS_MEMBER_H__
#include "open/rt_types.h"
#include "annotation.h"
#include "Class.h"
#include "vm_java_support.h"
typedef std::vector<Method*> MethodSet;
struct String;
class ByteReader;
class JIT;
class CodeChunkInfo;
struct Global_Env;
///////////////////////////////////////////////////////////////////////////////
// class file attributes
///////////////////////////////////////////////////////////////////////////////
enum Attributes {
ATTR_SourceFile, // Class (no more than 1 in each class file)
ATTR_InnerClasses, // Class
ATTR_ConstantValue, // Field (no more than 1 for each field)
ATTR_Code, // Method
ATTR_Exceptions, // Method
ATTR_LineNumberTable, // Code
ATTR_LocalVariableTable, // Code
ATTR_Synthetic, // Class/Field/Method
ATTR_Deprecated, // Class/Field/Method
ATTR_SourceDebugExtension, // Class (no more than 1 in each class file)
ATTR_Signature, // Class/Field/Method (spec does not limit number???)
ATTR_EnclosingMethod, // Class (1 at most)
ATTR_LocalVariableTypeTable, // Code
ATTR_RuntimeVisibleAnnotations, // Class/Field/Method (at most 1 per entity)
ATTR_RuntimeInvisibleAnnotations, // Class/Field/Method
ATTR_RuntimeVisibleParameterAnnotations, // Method
ATTR_RuntimeInvisibleParameterAnnotations, // Method
ATTR_AnnotationDefault, // Method (spec does not limit number???)
ATTR_StackMapTable, // Method
N_ATTR,
ATTR_UNDEF,
ATTR_ERROR
};
///////////////////////////////////////////////////////////////////////////////
// A class' members are its fields and methods. Class_Member is the base
// class for Field and Method, and factors out the commonalities in these
// two classes.
///////////////////////////////////////////////////////////////////////////////
class Class_Member {
public:
//
// access modifiers
//
bool is_public() {return (_access_flags&ACC_PUBLIC)?true:false;}
bool is_private() {return (_access_flags&ACC_PRIVATE)?true:false;}
bool is_protected() {return (_access_flags&ACC_PROTECTED)?true:false;}
bool is_package_private() {return !(is_public()||is_protected()||is_public())?true:false;}
bool is_static() {return (_access_flags&ACC_STATIC)?true:false;}
bool is_final() {return (_access_flags&ACC_FINAL)?true:false;}
bool is_strict() {return (_access_flags&ACC_STRICT)?true:false;}
bool is_synthetic() {return (_access_flags&ACC_SYNTHETIC)?true:_synthetic;}
bool is_deprecated() {return _deprecated;}
unsigned get_access_flags() {return _access_flags;}
//
// field get/set methods
//
unsigned get_offset() const {return _offset;}
Class *get_class() const {return _class;}
String *get_name() const {return _name;}
// Get the type descriptor (Sec. 4.3.2)
String *get_descriptor() const {return _descriptor;}
String *get_signature() const {return _signature;}
AnnotationTable* get_declared_annotations() const {return _annotations;}
AnnotationTable* get_declared_invisible_annotations() const {
return _invisible_annotations;
}
friend void assign_offsets_to_class_fields(Class *);
friend void add_new_fake_method(Class *clss, Class *example, unsigned *next);
friend void add_any_fake_methods(Class *);
/**
* Allocate a memory from a class loader pool using the class
* loader lock.
*/
void* Alloc(size_t size);
protected:
Class_Member()
{
_access_flags = 0;
_class = NULL;
_offset = 0;
#ifdef VM_STATS
num_accesses = 0;
num_slow_accesses = 0;
#endif
_synthetic = _deprecated = false;
_annotations = NULL;
_invisible_annotations = NULL;
_signature = NULL;
}
// offset of class member;
// for virtual methods, the method's offset within the vtable
// for static methods, not used, always zero
// for instance data, offset within the instance's data block
// for static data, offset within the class' static data block
unsigned _offset;
bool _synthetic;
bool _deprecated;
AnnotationTable* _annotations;
AnnotationTable* _invisible_annotations;
uint16 _access_flags;
String* _name;
String* _descriptor;
String* _signature;
Class* _class;
bool parse(Class* clss, ByteReader& cfs);
public:
#ifdef VM_STATS
uint64 num_accesses;
uint64 num_slow_accesses;
#endif
}; // Class_Member
///////////////////////////////////////////////////////////////////////////////
// Fields within Class structures.
///////////////////////////////////////////////////////////////////////////////
struct Field : public Class_Member{
public:
//-----------------------
// For all fields
bool is_offset_computed() { return (_offset_computed != 0); }
void set_offset(unsigned off) { _offset = off; _offset_computed = 1; }
// For static fields
void* get_address();
// Return the type of this field.
Java_Type get_java_type() {
return (Java_Type)(get_descriptor()->bytes[0]);
};
Const_Java_Value get_const_value() { return const_value; };
uint16 get_const_value_index() { return _const_value_index; };
//-----------------------
Field() {
_const_value_index = 0;
_field_type_desc = 0;
_offset_computed = 0;
_is_injected = 0;
_is_magic_type = 0;
track_access = 0;
track_modification = 0;
}
void Reset() { }
void set(Class *cl, String* name, String* desc, unsigned short af) {
_class = cl; _access_flags = af; _name = name; _descriptor = desc;
}
Field& operator = (const Field& fd) {
// copy Class_Member fields
_access_flags = fd._access_flags;
_class = fd._class;
_offset = fd._offset;
_name = fd._name;
_descriptor = fd._descriptor;
_deprecated = fd._deprecated;
_synthetic = fd._synthetic;
_annotations = fd._annotations;
_signature = fd._signature;
// copy Field fields
_const_value_index = fd._const_value_index;
_field_type_desc = fd._field_type_desc;
_is_injected = fd._is_injected;
_is_magic_type = fd._is_magic_type;
_offset_computed = fd._offset_computed;
const_value = fd.const_value;
track_access = fd.track_access;
track_modification = fd.track_modification;
return *this;
}
//
// access modifiers
//
unsigned is_volatile() {return (_access_flags&ACC_VOLATILE);}
unsigned is_transient() {return (_access_flags&ACC_TRANSIENT);}
bool is_enum() {return (_access_flags&ACC_ENUM)?true:false;}
bool parse(Global_Env& env, Class* clss, ByteReader& cfs, bool is_trusted_cl);
unsigned calculate_size();
TypeDesc* get_field_type_desc() { return _field_type_desc; }
void set_field_type_desc(TypeDesc* td) { _field_type_desc = td; }
Boolean is_injected() {return _is_injected;}
void set_injected() { _is_injected = 1; }
Boolean is_magic_type() {return _is_magic_type;}
void set_track_access(bool value) {
track_access = value ? 1 : 0 ;
}
void set_track_modification(bool value) {
track_modification = value ? 1 : 0 ;
}
void get_track_access_flag(char** address, char* mask) {
*address = &track_access;
*mask = TRACK_ACCESS_MASK;
}
void get_track_modification_flag(char** address, char* mask) {
*address = &track_modification;
*mask = TRACK_MODIFICATION_MASK;
}
private:
//
// The initial values of static fields. This is defined by the
// ConstantValue attribute in the class file.
//
// If there was not ConstantValue attribute for that field then _const_value_index==0
//
uint16 _const_value_index;
Const_Java_Value const_value;
TypeDesc* _field_type_desc;
unsigned _is_injected : 1;
unsigned _is_magic_type : 1;
unsigned _offset_computed : 1;
/** Turns on sending FieldAccess events on access to this field */
char track_access;
const static char TRACK_ACCESS_MASK = 1;
/** Turns on sending FieldModification events on modification of this field */
char track_modification;
const static char TRACK_MODIFICATION_MASK = 1;
//union {
// char bit_flags;
// struct {
// /** Turns on sending FieldAccess events on access to this field */
// char track_access : 1;
// const static char TRACK_ACCESS_MASK = 4;
// /** Turns on sending FieldModification events on modification of this field */
// char track_modification : 1;
// const static char TRACK_MODIFICATION_MASK = 8;
// };
//};
}; // Field
///////////////////////////////////////////////////////////////////////////////
// Handler represents a catch block in a method's code array
///////////////////////////////////////////////////////////////////////////////
class Handler {
public:
Handler();
bool parse(Class* clss, unsigned code_length, ByteReader& cfs, Method* method);
uint16 get_start_pc() {return _start_pc;}
uint16 get_end_pc() {return _end_pc;}
uint16 get_handler_pc() {return _handler_pc;}
uint16 get_catch_type_index() {return _catch_type_index;}
private:
uint16 _start_pc;
uint16 _end_pc;
uint16 _handler_pc;
uint16 _catch_type_index;
String* _catch_type;
}; //Handler
// Representation of target handlers in the generated code.
class Target_Exception_Handler {
public:
Target_Exception_Handler(NativeCodePtr start_ip, NativeCodePtr end_ip, NativeCodePtr handler_ip, Class_Handle exn_class, bool exn_is_dead);
NativeCodePtr get_start_ip();
NativeCodePtr get_end_ip();
NativeCodePtr get_handler_ip();
Class_Handle get_exc();
bool is_exc_obj_dead();
bool is_in_range(NativeCodePtr eip, bool is_ip_past);
bool is_assignable(Class_Handle exn_class);
void update_catch_range(NativeCodePtr new_start_ip, NativeCodePtr new_end_ip);
void update_handler_address(NativeCodePtr new_handler_ip);
private:
NativeCodePtr _start_ip;
NativeCodePtr _end_ip;
NativeCodePtr _handler_ip;
Class_Handle _exc;
bool _exc_obj_is_dead;
}; //Target_Exception_Handler
typedef class Target_Exception_Handler* Target_Exception_Handler_Ptr;
#define MAX_VTABLE_PATCH_ENTRIES 10
class VTable_Patches {
public:
void *patch_table[MAX_VTABLE_PATCH_ENTRIES];
VTable_Patches *next;
};
// Used to notify interested JITs whenever a method is changed: overwritten, recompiled,
// or initially compiled.
struct Method_Change_Notification_Record {
Method *caller;
JIT *jit;
void *callback_data;
Method_Change_Notification_Record *next;
inline bool equals(JIT *jit_, void *callback_data_) {
if ((callback_data == callback_data_) &&
(jit == jit_)) {
return true;
}
return false;
}
};
// 20020222 This is only temporary to support the new JIT interface.
// We will reimplement the signature support.
struct Method_Signature {
public:
TypeDesc* return_type_desc;
unsigned num_args;
TypeDesc** arg_type_descs;
Method *method;
String *sig;
void initialize_from_method(Method *method);
void reset();
private:
void initialize_from_java_method(Method *method);
};
///////////////////////////////////////////////////////////////////////////////
// Methods defined in a class.
///////////////////////////////////////////////////////////////////////////////
struct Line_Number_Entry {
uint16 start_pc;
uint16 line_number;
};
struct Line_Number_Table {
uint16 length;
Line_Number_Entry table[1];
};
struct Local_Var_Entry {
uint16 start_pc;
uint16 length;
uint16 index;
String* name;
String* type;
String* generic_type;
};
struct Local_Var_Table {
uint16 length;
Local_Var_Entry table[1];
};
class InlineInfo;
struct Method : public Class_Member {
friend void add_new_fake_method(Class* clss, Class* example, unsigned* next);
friend void add_any_fake_methods(Class* clss);
//-----------------------
public:
//
// state of this method
//
enum State {
ST_NotCompiled, // initial state
ST_NotLinked = ST_NotCompiled, // native not linked to implementation
ST_Compiled, // compiled by JIT
ST_Linked = ST_Compiled // native linked to implementation
};
State get_state() {return _state;}
void set_state(State st) {_state=st;}
struct LocalVarOffset{
int value;
LocalVarOffset* next;
};
// "Bytecode" exception handlers, i.e., those from the class file
unsigned num_bc_exception_handlers() const { return _n_handlers; }
Handler* get_bc_exception_handler_info(unsigned eh_number) {
assert(eh_number < _n_handlers);
return _handlers + eh_number;
}
// "Target" exception handlers, i.e., those in the code generated by the JIT.
void set_num_target_exception_handlers(JIT *jit, unsigned n);
unsigned get_num_target_exception_handlers(JIT *jit);
// Arguments:
// ...
// catch_clss -- class of the exception or null (for "catch-all")
// ...
void set_target_exception_handler_info(JIT *jit,
unsigned eh_number,
void *start_ip,
void *end_ip,
void *handler_ip,
Class *catch_clss,
bool exc_obj_is_dead = false);
Target_Exception_Handler_Ptr get_target_exception_handler_info(JIT *jit, unsigned eh_num);
unsigned num_exceptions_method_can_throw();
String *get_exception_name (int n);
// Address of the memory block containing bytecodes. For best performance
// the bytecodes should not be destroyed even after the method has been
// jitted to allow re-compilation. However the interface allows for such
// deallocation. The effect would be that re-optimizing JITs would not
// show their full potential, but that may be acceptable for low-end systems
// where memory is at a premium.
// The value returned by getByteCodeAddr may be NULL in which case the
// bytecodes are not available (presumably they have been garbage collected by VM).
const U_8* get_byte_code_addr() {return _byte_codes;}
unsigned get_byte_code_size() {return _byte_code_length;}
// From the class file (Sec. 4.7.4)
unsigned get_max_stack() { return _max_stack; }
unsigned get_max_locals() { return _max_locals; }
// Returns an iterator for the argument list.
Arg_List_Iterator get_argument_list();
// Returns number of bytes of arguments pushed on the stack.
// This value depends on the descriptor and the calling convention.
unsigned get_num_arg_slots() const { return _arguments_slot_num; }
// Returns number of arguments. For non-static methods, the this pointer
// is included in this number
unsigned get_num_args();
// Number of arguments which are references.
unsigned get_num_ref_args();
// Return the return type of this method.
Java_Type get_return_java_type() {
const char *descr = get_descriptor()->bytes;
while(*descr != ')') descr++;
return (Java_Type)*(descr + 1);
}
// For non-primitive types (i.e., classes) get the class type information.
Class *get_return_class_type();
// Address of the memory location containing the address of the code.
// Used for static and special methods which have been resolved but not jitted.
// The call would be:
// call dword ptr [addr]
void *get_indirect_address() { return &_code; }
// Entry address of the method. Points to an appropriate stub or directly
// to the code if no stub is necessary.
void *get_code_addr() { return _code; }
void set_code_addr(void *code_addr) { _code = code_addr; }
void add_vtable_patch(void *);
void apply_vtable_patches();
NativeCodePtr get_registered_native_func()
{ return _registered_native_func; }
void set_registered_native_func(NativeCodePtr native_func)
{ _registered_native_func = native_func; }
/**
* This returns a block for jitted code. It is not used for native methods.
* It is safe to call this function from multiple threads.
*/
void *allocate_code_block_mt(size_t size, size_t alignment, JIT *jit, unsigned heat,
int id, Code_Allocation_Action action);
void *allocate_rw_data_block(size_t size, size_t alignment, JIT *jit);
// The JIT can store some information in a JavaMethod object.
void *allocate_jit_info_block(size_t size, JIT *jit);
// JIT-specific data blocks.
// Access should be protected with _lock.
// FIXME
// Think about moving lock aquisition inside public methods.
void *allocate_JIT_data_block(size_t size, JIT *jit, size_t alignment);
CodeChunkInfo *get_first_JIT_specific_info() { return _jits; };
CodeChunkInfo *get_JIT_specific_info_no_create(JIT *jit);
/**
* Find a chunk info for specific JIT. If no chunk exist for this JIT,
* create and return one. This method is safe to call
* from multiple threads.
*/
CodeChunkInfo *get_chunk_info_mt(JIT *jit, int id);
/**
* Find a chunk info for specific JIT, or <code>NULL</code> if
* no chunk info is created for this JIT. This method is safe to call
* from multiple threads.
*/
CodeChunkInfo *get_chunk_info_no_create_mt(JIT *jit, int id);
/**
* Allocate a new chunk info. This method is safe to call
* from multiple threads.
*/
CodeChunkInfo *create_code_chunk_info_mt();
// Notify JITs whenever this method is recompiled or initially compiled.
void register_jit_recompiled_method_callback(JIT *jit_to_be_notified, Method* caller, void *callback_data);
void do_jit_recompiled_method_callbacks();
void unregister_jit_recompiled_method_callbacks(const Method* caller);
Method_Side_Effects get_side_effects() { return _side_effects; }
void set_side_effects(Method_Side_Effects mse) { _side_effects = mse; }
Method_Signature *get_method_sig() { return _method_sig; }
void set_method_sig(Method_Signature *msig) { _method_sig = msig; }
/// Sets index in vtable and offset from the base of vtable for this method
/// @param index - index in vtable
/// @param offset - for instance methods: offset from the base of vtable
void set_position_in_vtable(unsigned index, unsigned offset) {
assert(!is_static());
_index = index;
_offset = offset;
}
private:
State _state;
void *_code;
VTable_Patches *_vtable_patch;
NativeCodePtr _counting_stub;
CodeChunkInfo *_jits;
Method_Side_Effects _side_effects;
Method_Signature *_method_sig;
/** set by JNI RegisterNatives() funcs */
NativeCodePtr _registered_native_func;
public:
Method();
// destructor should be instead of this function, but it's not allowed to use it because copy for Method class is
// done with memcpy, and old value is destroyed with delete operator.
void MethodClearInternals();
void NotifyUnloading();
//
// access modifiers
//
bool is_synchronized() {return (_access_flags&ACC_SYNCHRONIZED)?true:false;}
bool is_native() {return (_access_flags&ACC_NATIVE)?true:false;}
bool is_abstract() {return (_access_flags&ACC_ABSTRACT)?true:false;}
bool is_varargs() {return (_access_flags&ACC_VARARGS)?true:false;}
bool is_bridge() {return (_access_flags&ACC_BRIDGE)?true:false;}
// method flags
bool is_init() {return _flags.is_init?true:false;}
bool is_clinit() {return _flags.is_clinit?true:false;}
bool is_finalize() {return _flags.is_finalize?true:false;}
bool is_overridden() {return _flags.is_overridden?true:false;}
Boolean is_nop() {return _flags.is_nop;}
unsigned get_index() {return _index;}
// Fake methods are interface methods inherited by an abstract class that are not (directly or indirectly)
// implemented by that class. They are added to the class to ensure they have thecorrect vtable offset.
// These fake methods point to the "real" interface method for which they are surrogates; this information
// is used by reflection methods.
bool is_fake_method() {return (_intf_method_for_fake_method != NULL);}
Method *get_real_intf_method() {return _intf_method_for_fake_method;}
bool parse(Global_Env& env, Class* clss, ByteReader& cfs, bool is_trusted_cl);
void calculate_arguments_slot_num();
unsigned calculate_size() {
unsigned size = sizeof(Class_Member) + sizeof(Method);
if(_local_vars_table)
size += sizeof(uint16) + _local_vars_table->length*sizeof(Local_Var_Entry);
if(_line_number_table)
size += sizeof(uint16) + _line_number_table->length*sizeof(Line_Number_Entry);
size += _n_exceptions*sizeof(String*);
size += _n_handlers*sizeof(Handler);
size += _byte_code_length;
return size;
}
unsigned get_num_param_annotations() {return _num_param_annotations;}
AnnotationTable * get_param_annotations(unsigned index) {
return index < _num_param_annotations ? _param_annotations[index] : NULL;
}
unsigned get_num_invisible_param_annotations() {
return _num_invisible_param_annotations;
}
AnnotationTable * get_invisible_param_annotations(unsigned index) {
return index < _num_invisible_param_annotations ?
_invisible_param_annotations[index] : NULL;
}
AnnotationValue * get_default_value() {return _default_value; }
private:
U_8 _num_param_annotations;
AnnotationTable ** _param_annotations;
U_8 _num_invisible_param_annotations;
AnnotationTable ** _invisible_param_annotations;
AnnotationValue * _default_value;
unsigned _index; // index in method table
unsigned _arguments_slot_num; // number of slots for method arguments
uint16 _max_stack;
uint16 _max_locals;
uint16 _n_exceptions; // num exceptions method can throw
uint16 _n_handlers; // num exception handlers in byte codes
String** _exceptions; // array of exceptions method can throw
U_32 _byte_code_length; // num bytes of byte code
U_8* _byte_codes; // method's byte codes
Handler *_handlers; // array of exception handlers in code
Method *_intf_method_for_fake_method;
struct {
unsigned is_init : 1;
unsigned is_clinit : 1;
unsigned is_finalize : 1; // is finalize() method
unsigned is_overridden : 1; // has this virtual method been overridden by a loaded subclass?
unsigned is_nop : 1;
} _flags;
//
// private methods for parsing methods
//
bool _parse_code(Global_Env& env, ConstantPool& cp, unsigned code_attr_len, ByteReader &cfs);
bool _parse_line_numbers(unsigned attr_len, ByteReader &cfs);
bool _parse_exceptions(ConstantPool& cp, unsigned attr_len, ByteReader &cfs);
void _set_nop();
//
// debugging info
//
Line_Number_Table *_line_number_table;
Local_Var_Table *_local_vars_table;
bool _parse_local_vars(Local_Var_Table* table, LocalVarOffset* offset_list,
Global_Env& env, ConstantPool& cp, ByteReader &cfs, const char* attr_name, Attributes attr);
// This is the number of breakpoints which should be set in the
// method when it is compiled. This number does not reflect
// multiple breakpoints that are set in the same location by
// different environments, it counts only unique locations
U_32 pending_breakpoints;
/** Information about methods inlined to this. */
InlineInfo* _inline_info;
MethodSet* _recompilation_callbacks;
public:
/**
* Gets inlined methods information.
* @return InlineInfo object pointer.
*/
InlineInfo* get_inline_info() {
return _inline_info;
}
/**
* Adds information about inlined method.
* @param[in] method - method which is inlined
* @param[in] codeSize - size of inlined code block
* @param[in] codeAddr - size of inlined code block
* @param[in] mapLength - number of AddrLocation elements in addrLocationMap
* @param[in] addrLocationMap - native address to bytecode location
* correspondence table
*/
void add_inline_info_entry(Method* method, U_32 codeSize, void* codeAddr,
U_32 mapLength, AddrLocation* addrLocationMap);
/**
* Sends JVMTI_EVENT_COMPILED_METHOD_LOAD event for every inline method
* recorded in this InlineInfo object.
* @param[in] method - outer method this InlineInfo object belogs to.
*/
void send_inlined_method_load_events(Method *method);
unsigned get_line_number_table_size() {
return (_line_number_table) ? _line_number_table->length : 0;
}
bool get_line_number_entry(unsigned index, jlong* pc, jint* line);
unsigned get_local_var_table_size() {
return (_local_vars_table) ? _local_vars_table->length : 0;
}
bool get_local_var_entry(unsigned index, jlong* pc,
jint* length, jint* slot, String** name, String** type,
String** generic_type);
// XXX
//bool get_local_var_entry(unsigned index, jlong* pc,
// jint* length, jint* slot, String** name, String** type);
// Returns number of line in the source file, to which the given bytecode offset
// corresponds, or -1 if it is unknown.
int get_line_number(uint16 bc) {
if(!_line_number_table) return -1;
Line_Number_Table* lnt = _line_number_table;
for(int i = 0; i < lnt->length - 1; i++) {
if(bc >= lnt->table[i].start_pc && bc < lnt->table[i+1].start_pc)
return lnt->table[i].line_number;
}
if(bc >= lnt->table[lnt->length-1].start_pc && bc < _byte_code_length)
return lnt->table[lnt->length-1].line_number;
return -1;
}
void method_was_overridden();
// Records JITs to be notified when a method is recompiled or initially compiled.
Method_Change_Notification_Record *_notify_recompiled_records;
void lock();
void unlock();
U_32 get_pending_breakpoints()
{
return pending_breakpoints;
}
void insert_pending_breakpoint()
{
pending_breakpoints++;
}
void remove_pending_breakpoint()
{
pending_breakpoints--;
}
U_8* m_stackmap;
public:
U_8* get_stackmap() {
return m_stackmap;
}
}; // Method
struct _jmethodID : public Method
{
// Empty declaration to make jmethodID
// autoconvertable to struct Method*
};
#endif