blob: cef41ebce5bfe326aad28542732dd52801417451 [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.
*/
/**
* @author Pavel Pervov
*/
#define LOG_DOMAIN "class"
#include "cxxlog.h"
#include <cctype>
#include <sstream>
#include "open/vm_class_manipulation.h"
#include "Class.h"
#include "classloader.h"
#include "environment.h"
#include "lock_manager.h"
#include "exceptions.h"
#include "compile.h"
#include "open/gc.h"
#include "nogc.h"
#include "vm_stats.h"
#include "jit_intf_cpp.h"
#include "type.h"
#include "cci.h"
#include "interpreter.h"
#include "port_threadunsafe.h"
#include "vtable.h"
#include "inline_info.h"
#ifdef _IPF_
#include "vm_ipf.h"
#endif // _IPF_
//
// private static variable containing the id of the next class
// access to this needs to be thread safe; also, this will have to
// change if we want to reuse class ids
//
// an id of 0 is reserved to mean null; therefore, ids start from 1
//
// ppervov: FIXME: usage of this variable is not currently thread safe
unsigned class_next_id = 1;
void Class::init_internals(const Global_Env* env, const String* name, ClassLoader* cl)
{
memset(this, 0, sizeof(Class));
m_super_class.name = NULL;
m_name = name;
m_simple_name = m_java_name = m_signature = NULL;
m_allocated_size = 0;
m_array_element_size = 0;
#ifdef POINTER64
m_alignment = ((GC_OBJECT_ALIGNMENT<8)?8:GC_OBJECT_ALIGNMENT);;
#else
m_alignment = GC_OBJECT_ALIGNMENT;
#endif
m_id = class_next_id++;
m_class_loader = cl;
m_class_handle = NULL;
m_is_primitive = 0;
m_is_array = 0;
m_is_array_of_primitives = 0;
m_has_finalizer = 0;
m_can_access_all = 0;
m_is_fast_allocation_possible = 0;
m_num_dimensions = 0;
m_array_base_class = m_array_element_class = NULL;
m_access_flags = 0;
m_num_superinterfaces = 0;
m_num_fields = m_num_static_fields = m_num_methods = 0;
m_declaring_class_index = 0;
m_enclosing_class_index = 0;
m_enclosing_method_index = 0;
m_num_innerclasses = 0;
m_innerclasses = NULL;
m_fields = NULL;
m_methods = NULL;
m_superinterfaces = NULL;
m_const_pool.init();
m_class_file_name = NULL;
m_src_file_name = NULL;
m_state = ST_Start;
m_package = NULL;
m_num_instance_refs = 0;
m_num_virtual_method_entries = m_num_intfc_method_entries = 0;
m_finalize_method = m_static_initializer = m_default_constructor = NULL;
m_static_data_size = 0;
m_static_data_block = NULL;
m_unpadded_instance_data_size = m_instance_data_size = 0;
m_vtable = NULL;
m_allocation_handle = 0;
m_vtable_descriptors = NULL;
m_initializing_thread = NULL;
m_num_class_init_checks = m_num_throws = m_num_instanceof_slow
= m_num_allocations = m_num_bytes_allocated = 0;
m_num_field_padding_bytes = 0;
m_depth = 0;
m_is_suitable_for_fast_instanceof = 0;
m_cha_first_child = m_cha_next_sibling = NULL;
m_sourceDebugExtension = NULL;
m_lock = new Lock_Manager();
m_verify_data = 0;
}
void Class::notify_unloading() {
if(m_methods != NULL) {
for (int i = 0; i < m_num_methods; i++){
m_methods[i].NotifyUnloading();
}
}
}
void Class::clear_internals() {
if(m_fields != NULL)
{
delete[] m_fields;
m_fields = NULL;
}
if(m_methods != NULL) {
for (int i = 0; i < m_num_methods; i++){
m_methods[i].MethodClearInternals();
}
delete[] m_methods;
m_methods = NULL;
}
m_const_pool.clear();
if(m_vtable_descriptors)
delete[] m_vtable_descriptors;
if(m_lock)
delete m_lock;
}
Field* Class::get_field(uint16 index) const
{
assert(index < m_num_fields);
return &(m_fields[index]);
}
Method* Class::get_method(uint16 index) const
{
assert(index < m_num_methods);
return &m_methods[index];
}
bool Class::is_instanceof(Class* clss)
{
assert(!is_interface());
#ifdef VM_STATS
UNSAFE_REGION_START
VM_Statistics::get_vm_stats().num_type_checks++;
if(this == clss)
VM_Statistics::get_vm_stats().num_type_checks_equal_type++;
if(clss->m_is_suitable_for_fast_instanceof)
VM_Statistics::get_vm_stats().num_type_checks_fast_decision++;
else if(clss->is_array())
VM_Statistics::get_vm_stats().num_type_checks_super_is_array++;
else if(clss->is_interface())
VM_Statistics::get_vm_stats().num_type_checks_super_is_interface ++;
else if((unsigned)clss->m_depth >= vm_max_fast_instanceof_depth())
VM_Statistics::get_vm_stats().num_type_checks_super_is_too_deep++;
UNSAFE_REGION_END
#endif // VM_STATS
if(this == clss) return true;
Global_Env* env = VM_Global_State::loader_env;
if(is_array()) {
Class* object_class = env->JavaLangObject_Class;
assert(object_class != NULL);
if(clss == object_class) return true;
if(clss == env->java_io_Serializable_Class) return true;
if(clss == env->java_lang_Cloneable_Class) return true;
if(!clss->is_array()) return false;
return class_is_subtype(get_array_element_class(), clss->get_array_element_class());
} else {
if(clss->m_is_suitable_for_fast_instanceof)
{
return m_vtable->superclasses[clss->m_depth - 1] == clss;
}
if(!clss->is_interface()) {
for(Class *c = this; c; c = c->get_super_class()) {
if(c == clss) return true;
}
} else {
for(Class *c = this; c; c = c->get_super_class()) {
unsigned n_intf = c->get_number_of_superinterfaces();
for(unsigned i = 0; i < n_intf; i++) {
Class* intf = c->get_superinterface(i);
assert(intf);
assert(intf->is_interface());
if(class_is_subtype(intf, clss)) return true;
}
}
}
}
return false;
}
bool Class::load_ancestors(Global_Env* env)
{
m_state = ST_LoadingAncestors;
const String* superName = get_super_class_name();
if(superName == NULL) {
if(env->InBootstrap() || get_name() != env->JavaLangClass_String) {
// This class better be java.lang.Object
if(get_name() != env->JavaLangObject_String) {
// ClassFormatError
std::stringstream ss;
ss << get_name()->bytes
<< ": class does not have superclass "
<< "but the class is not java.lang.Object";
REPORT_FAILED_CLASS_CLASS(m_class_loader, this,
"java/lang/ClassFormatError", ss.str().c_str());
return false;
}
}
} else {
// Load super class
Class* superClass;
m_super_class.name = NULL;
superClass = m_class_loader->LoadVerifyAndPrepareClass(env, superName);
if(superClass == NULL) {
assert(exn_raised());
return false;
}
if(superClass->is_interface()) {
REPORT_FAILED_CLASS_CLASS(m_class_loader, this,
"java/lang/IncompatibleClassChangeError",
"class " << m_name->bytes << " has interface "
<< superClass->get_name()->bytes << " as super class");
return false;
}
if(superClass->is_final()) {
REPORT_FAILED_CLASS_CLASS(m_class_loader, this,
"java/lang/VerifyError",
m_name->bytes << " cannot inherit from final class "
<< superClass->get_name()->bytes);
return false;
}
// super class was successfully loaded
m_super_class.clss = superClass;
if(m_super_class.cp_index) {
m_const_pool.resolve_entry(m_super_class.cp_index, superClass);
}
// if it's an interface, its superclass must be java/lang/Object
if(is_interface()) {
if((env->JavaLangObject_Class != NULL) && (superClass != env->JavaLangObject_Class)) {
std::stringstream ss;
ss << get_name()->bytes << ": interface superclass is not java.lang.Object";
REPORT_FAILED_CLASS_CLASS(m_class_loader, this,
"java/lang/ClassFormatError", ss.str().c_str());
return false;
}
}
// Update the cha_first_child and cha_next_sibling fields.
m_cha_first_child = NULL;
if(has_super_class())
{
m_cha_next_sibling = get_super_class()->m_cha_first_child;
get_super_class()->m_cha_first_child = this;
}
}
//
// load in super interfaces
//
for(unsigned i = 0; i < m_num_superinterfaces; i++ ) {
const String* intfc_name = m_superinterfaces[i].name;
Class* intfc = m_class_loader->LoadVerifyAndPrepareClass(env, intfc_name);
if(intfc == NULL) {
assert(exn_raised());
return false;
}
if(!intfc->is_interface()) {
REPORT_FAILED_CLASS_CLASS(m_class_loader, this,
"java/lang/IncompatibleClassChangeError",
get_name()->bytes << ": " << intfc->get_name()->bytes
<< " is not an interface");
return false;
}
// superinterface was successfully loaded
m_superinterfaces[i].clss = intfc;
if(m_superinterfaces[i].cp_index != 0) {
// there are no constant pool entries for array classes
m_const_pool.resolve_entry(m_superinterfaces[i].cp_index, intfc);
}
}
// class, superclass, and superinterfaces successfully loaded
m_state = ST_Loaded;
if(!is_array())
m_package = m_class_loader->ProvidePackage(env, m_name, NULL);
return true;
}
Class* Class::resolve_declaring_class(Global_Env* env)
{
if(m_declaring_class_index == 0) return NULL;
return _resolve_class(env, m_declaring_class_index);
}
void Class::setup_as_array(Global_Env* env, unsigned char num_dimensions,
bool isArrayOfPrimitives, Class* baseClass, Class* elementClass)
{
m_is_array = 1;
m_num_dimensions = (unsigned char)num_dimensions;
if(m_num_dimensions == 1) {
m_is_array_of_primitives = isArrayOfPrimitives;
} else {
m_is_array_of_primitives = false;
}
m_array_element_class = elementClass;
m_array_base_class = baseClass;
m_state = ST_Initialized;
assert(elementClass);
// insert Java field, required by spec - 'length I'
m_num_fields = 1;
m_fields = new Field[1];
m_fields[0].set(this, env->Length_String,
env->string_pool.lookup("I"), ACC_PUBLIC|ACC_FINAL);
m_fields[0].set_field_type_desc(
type_desc_create_from_java_descriptor("I", NULL));
m_fields[0].set_injected();
m_super_class.name = env->JavaLangObject_String;
m_super_class.cp_index = 0;
m_access_flags = (ACC_FINAL | ACC_ABSTRACT);
if(isArrayOfPrimitives) {
m_access_flags |= ACC_PUBLIC;
} else {
// set array access flags the same as in its base class
m_access_flags = (uint16)(m_access_flags
| (baseClass->get_access_flags()
& (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)));
}
m_package = elementClass->m_package;
// array classes implement two interfaces: Cloneable and Serializable
m_superinterfaces = (Class_Super*) STD_MALLOC(2 * sizeof(Class_Super));
m_superinterfaces[0].name = env->Clonable_String;
m_superinterfaces[0].cp_index = 0;
m_superinterfaces[1].name = env->Serializable_String;
m_superinterfaces[1].cp_index = 0;
m_num_superinterfaces = 2;
}
//
// This function doesn't check for fields inherited from superclasses.
//
Field* Class::lookup_field(const String* name, const String* desc)
{
for(uint16 i = 0; i < m_num_fields; i++) {
if(m_fields[i].get_name() == name && m_fields[i].get_descriptor() == desc)
return &m_fields[i];
}
return NULL;
} // Class::lookup_field
Field* class_lookup_field_recursive(Class* clss,
const char* name,
const char* descr)
{
String *field_name =
VM_Global_State::loader_env->string_pool.lookup(name);
String *field_descr =
VM_Global_State::loader_env->string_pool.lookup(descr);
return clss->lookup_field_recursive(field_name, field_descr);
}
Field* Class::lookup_field_recursive(const String* name, const String* desc)
{
// Step 1: lookup in self
Field* field = lookup_field(name, desc);
if(field) return field;
// Step 2: lookup in direct superinterfaces recursively
for(uint16 in = 0; in < m_num_superinterfaces; in++) {
field = get_superinterface(in)->lookup_field_recursive(name, desc);
if(field) return field;
}
// Step 3: lookup in super classes recursively
if(has_super_class()) {
field = get_super_class()->lookup_field_recursive(name, desc);
}
return field;
} // Class::lookup_field_recursive
Method* Class::lookup_method(const String* name, const String* desc)
{
for(unsigned i = 0; i < m_num_methods; i++) {
if(m_methods[i].get_name() == name && m_methods[i].get_descriptor() == desc)
return &m_methods[i];
}
return NULL;
} // Class::lookup_method
ManagedObject* Class::allocate_instance()
{
assert(!hythread_is_suspend_enabled());
//assert(is_initialized());
ManagedObject* new_instance =
(ManagedObject*)vm_alloc_and_report_ti(m_instance_data_size,
m_allocation_handle, vm_get_gc_thread_local(), this);
if(new_instance == NULL)
{
return NULL;
}
#ifdef VM_STATS
UNSAFE_REGION_START
VM_Statistics::get_vm_stats().num_class_alloc_new_object++;
instance_allocated(m_instance_data_size);
UNSAFE_REGION_END
#endif //VM_STATS
return new_instance;
}
void* Class::helper_get_interface_vtable(ManagedObject* obj, Class* iid)
{
VTable* vt = obj->vt();
Intfc_Table* intfTable = vt->intfc_table;
unsigned num_intfc = intfTable->n_entries;
#ifdef VM_STATS
UNSAFE_REGION_START
VM_Statistics::get_vm_stats().num_invokeinterface_calls++;
switch(num_intfc) {
case 1: VM_Statistics::get_vm_stats().num_invokeinterface_calls_size_1++; break;
case 2: VM_Statistics::get_vm_stats().num_invokeinterface_calls_size_2++; break;
default: VM_Statistics::get_vm_stats().num_invokeinterface_calls_size_many++; break;
}
if(num_intfc > VM_Statistics::get_vm_stats().invokeinterface_calls_size_max)
VM_Statistics::get_vm_stats().invokeinterface_calls_size_max = num_intfc;
UNSAFE_REGION_END
#endif
for(unsigned i = 0; i < num_intfc; i++) {
const Intfc_Table_Entry& intfEntry = intfTable->entry[i];
Class* intfc = intfEntry.intfc_class;
if(intfc == iid) {
#ifdef VM_STATS
UNSAFE_REGION_START
switch(i) {
case 0: VM_Statistics::get_vm_stats().num_invokeinterface_calls_searched_1++; break;
case 1: VM_Statistics::get_vm_stats().num_invokeinterface_calls_searched_2++; break;
default: VM_Statistics::get_vm_stats().num_invokeinterface_calls_searched_many++; break;
}
if(i > VM_Statistics::get_vm_stats().invokeinterface_calls_searched_max)
VM_Statistics::get_vm_stats().invokeinterface_calls_searched_max = i;
UNSAFE_REGION_END
#endif
unsigned char** table = intfEntry.table;
return (void*)table;
}
}
return NULL;
}
Method* class_lookup_method_recursive(Class *clss, const String* name, const String* desc)
{
assert(clss);
Method *m = 0;
Class *oclss = clss;
m = clss->lookup_method(name, desc);
if(m)return m;
for(clss = clss->get_super_class(); clss && !m; clss = clss->get_super_class()) {
m = class_lookup_method_recursive(clss, name, desc);
}
if(m)return m;
//if not found, search in interfaces, that means
// clss itself is also interface
for(int i = 0; i < oclss->get_number_of_superinterfaces(); i++)
if((m = class_lookup_method_recursive(oclss->get_superinterface(i), name, desc)))
return m;
return NULL;
} //class_lookup_method_recursive
Method *class_lookup_method_recursive(Class *clss,
const char *name,
const char *descr)
{
String *method_name =
VM_Global_State::loader_env->string_pool.lookup(name);
String *method_descr =
VM_Global_State::loader_env->string_pool.lookup(descr);
return class_lookup_method_recursive(clss, method_name, method_descr);
} //class_lookup_method_recursive
Method* class_lookup_method(Class* clss,
const char* name,
const char* descr)
{
String* method_name =
VM_Global_State::loader_env->string_pool.lookup(name);
String* method_descr =
VM_Global_State::loader_env->string_pool.lookup(descr);
return clss->lookup_method(method_name, method_descr);
} // class_lookup_method
Method* class_get_method_from_vt_offset(VTable* vt,
unsigned offset)
{
assert(vt);
unsigned index = (offset - VTABLE_OVERHEAD) / sizeof(void*);
return vt->clss->get_method_from_vtable(index);
} // class_get_method_from_vt_offset
void* Field::get_address()
{
assert(is_static());
assert(is_offset_computed());
return (char*)(get_class()->get_static_data_address()) + get_offset();
} // Field::get_address
unsigned Field::calculate_size() {
static unsigned size = sizeof(Field) + sizeof(TypeDesc);
return size;
}
Method::Method()
{
//
// _vtable_patch may be in one of three states:
// 1. NULL -- before a vtable is initialized or after all patching is done.
// 2. Points to a vtable entry which must be patched.
// This state can be recognized because *_vtable_patch == _code
// 3. Otherwise it points to a list containing multiple vtable patch info.
//
_vtable_patch = 0;
_code = NULL;
_registered_native_func = NULL;
_state = ST_NotCompiled;
_jits = NULL;
_side_effects = MSE_Unknown;
_method_sig = 0;
_notify_recompiled_records = NULL;
_recompilation_callbacks = NULL;
_index = 0;
_max_stack=_max_locals=_n_exceptions=_n_handlers=0;
_exceptions = NULL;
_byte_code_length = 0;
_byte_codes = NULL;
_handlers = NULL;
_flags.is_init = 0;
_flags.is_clinit = 0;
_flags.is_overridden = 0;
_flags.is_finalize = 0;
_flags.is_nop = FALSE;
_line_number_table = NULL;
_local_vars_table = NULL;
_num_param_annotations = 0;
_num_invisible_param_annotations = 0;
_param_annotations = NULL;
_invisible_param_annotations = NULL;
_default_value = NULL;
pending_breakpoints = 0;
_inline_info = NULL;
} //Method::Method
void Method::NotifyUnloading()
{
if (_recompilation_callbacks != NULL) {
MethodSet::const_iterator it;
for (it = _recompilation_callbacks->begin(); it != _recompilation_callbacks->end(); it++)
{
(*it)->unregister_jit_recompiled_method_callbacks(this);
}
}
}
void Method::MethodClearInternals()
{
CodeChunkInfo *jit_info;
for (jit_info = _jits; jit_info; jit_info = jit_info->_next) {
Boolean result = VM_Global_State::loader_env->em_interface->UnregisterCodeChunk(
jit_info->get_code_block_addr());
assert(TRUE == result);
// ensure that jit_info was deleted
assert (VM_Global_State::loader_env->em_interface->LookupCodeChunk(
jit_info->get_code_block_addr(), FALSE, NULL, NULL, NULL) == NULL);
for(unsigned k = 0; k < jit_info->_num_target_exception_handlers; k++) {
delete jit_info->_target_exception_handlers[k];
jit_info->_target_exception_handlers[k] = NULL;
}
jit_info->_target_exception_handlers = NULL;
}
if (_recompilation_callbacks != NULL) {
delete _recompilation_callbacks;
}
if (_notify_recompiled_records != NULL)
{
Method_Change_Notification_Record *nr, *prev_nr;
nr = _notify_recompiled_records;
while(nr != NULL) {
prev_nr = nr;
nr = nr->next;
STD_FREE(prev_nr);
}
_notify_recompiled_records = NULL;
}
if (_line_number_table != NULL)
{
STD_FREE(_line_number_table);
_line_number_table = NULL;
}
if (_byte_codes != NULL)
{
delete []_byte_codes;
_byte_codes = NULL;
}
/*if (_local_vars_table != NULL)
{
STD_FREE(_local_vars_table);
_local_vars_table = NULL;
}*/
if (_handlers != NULL)
{
delete []_handlers;
_handlers = NULL;
}
if (_method_sig != 0)
{
_method_sig->reset();
delete _method_sig;
}
if (_exceptions != NULL)
delete []_exceptions;
VTable_Patches *patch = NULL;
while (_vtable_patch)
{
patch = _vtable_patch;
_vtable_patch = _vtable_patch->next;
STD_FREE(patch);
}
delete _inline_info;
}
void Method::lock()
{
_class->lock();
}
void Method::unlock()
{
_class->unlock();
}
void Method::add_inline_info_entry(Method* method, U_32 codeSize, void* codeAddr,
U_32 mapLength, AddrLocation* addrLocationMap) {
if (NULL == _inline_info)
_inline_info = new InlineInfo();
_inline_info->add(method, codeSize, codeAddr, mapLength,
addrLocationMap);
}
void Method::send_inlined_method_load_events(Method *method) {
if (NULL == _inline_info)
return;
_inline_info->send_compiled_method_load_event(method);
}
////////////////////////////////////////////////////////////////////
// beginpointers between struct Class and java.lang.Class
// 20020419
// Given a struct Class, find its corresponding java.lang.Class instance.
//
// To split struct Class and java.lang.Class into two separate data
// structures, we have to replace all places in the VM source code where
// we map struct Class to java.lang.Class and vice versa by performing a cast.
// Here's an example from FindClass()
// --- begin old code
// new_handle->java_reference = (ManagedObject *)clss;
// --- end old code
// --- begin new code
// tmn_suspend_disable(); //---------------------------------v
// new_handle->java_reference = struct_Class_to_java_lang_Class(clss);
// tmn_suspend_enable(); //---------------------------------^
// --- end new code
// NB: in the past instances of java.lang.Class were guaranteed to be
// allocated in the fixed space. Instances of java.lang.Class are now treated
// by GC the same way as any other Java objects and the GC may choose to move them.
// This is the reason for disabling GC in the example above.
//
ManagedObject *struct_Class_to_java_lang_Class(Class *clss)
{
//sundr printf("struct to class %s, %p, %p\n", clss->name->bytes, clss, clss->super_class);
assert(!hythread_is_suspend_enabled());
assert(clss);
ManagedObject** hjlc = clss->get_class_handle();
assert(hjlc);
ManagedObject* jlc = *hjlc;
assert(jlc != NULL);
assert(jlc->vt());
assert(jlc->vt()->clss == VM_Global_State::loader_env->JavaLangClass_Class);
assert(java_lang_Class_to_struct_Class(jlc) == clss); // else clss's java.lang.Class had a bad "back" pointer
return jlc;
} //struct_Class_to_java_lang_Class
/**
* this function returns the reference to the Class->java_lang_Class
*
* @note The returned handle is unsafe in respect to DeleteLocalRef,
* and should not be passed to user JNI functions.
*/
jobject struct_Class_to_java_lang_Class_Handle(Class *clss) {
// used only for protecting assertions
#ifndef NDEBUG
tmn_suspend_disable_recursive();
#endif
assert(clss);
assert(clss->get_class_handle());
ManagedObject* UNUSED jlc = *(clss->get_class_handle());
assert(jlc);
assert(jlc->vt());
//assert(jlc->vt()->clss == VM_Global_State::loader_env->JavaLangClass_Class);
#ifndef NDEBUG
// gc disabling was needed only to protect assertions
tmn_suspend_enable_recursive();
#endif
// salikh 2005-04-11
// this operation is safe because
// 1 Class.java_lang_Class is enumerated during GC
// 2 no access to pointer is being made, only slot address is taken
//
// However, it would be unsafe to pass this local reference to JNI code,
// as user may want to call DeleteLocalRef on it, and it would reset
// java_lang_Class field of the struct Class
// return (jclass)(&clss->java_lang_Class);
//
// ppervov 2005-04-18
// redone struct Class to contain class handle instead of raw ManagedObject*
return (jclass)(clss->get_class_handle());
}
/* The following two utility functions to ease
conversion between struct Class and jclass
*/
jclass struct_Class_to_jclass(Class *c)
{
assert(hythread_is_suspend_enabled());
tmn_suspend_disable(); // ----------vvv
ObjectHandle h = oh_allocate_local_handle();
h->object = struct_Class_to_java_lang_Class(c);
tmn_suspend_enable(); // ----------^^^
return (jclass)h;
}
Class *jclass_to_struct_Class(jclass jc)
{
Class *c;
tmn_suspend_disable_recursive();
c = java_lang_Class_to_struct_Class(jc->object);
tmn_suspend_enable_recursive();
return c;
}
Class *jobject_to_struct_Class(jobject jobj)
{
tmn_suspend_disable();
assert(jobj->object);
assert(jobj->object->vt());
Class *clss = jobj->object->vt()->clss;
assert(clss);
tmn_suspend_enable();
return clss;
}
// Given a class instance, find its corresponding struct Class.
Class *java_lang_Class_to_struct_Class(ManagedObject *jlc)
{
assert(!hythread_is_suspend_enabled());
assert(jlc != NULL);
assert(jlc->vt());
//assert(jlc->vt()->clss == VM_Global_State::loader_env->JavaLangClass_Class);
assert(VM_Global_State::loader_env->vm_class_offset != 0);
Class** vm_class_ptr = (Class**)(((U_8*)jlc) + VM_Global_State::loader_env->vm_class_offset);
assert(vm_class_ptr != NULL);
Class* clss = *vm_class_ptr;
assert(clss != NULL);
assert(clss->get_class_handle());
assert(*(clss->get_class_handle()) == jlc);
assert(clss != (Class*) jlc); // else the two structures still overlap!
return clss;
} //java_lang_Class_to_struct_Class
String* Class::get_simple_name()
{
Global_Env* env = VM_Global_State::loader_env;
if(m_simple_name == NULL)
{
if (is_array())
{
String* simple_base_name = m_array_base_class->get_simple_name();
unsigned len = simple_base_name->len;
unsigned dims = m_num_dimensions;
char * buf = (char*)STD_ALLOCA(dims * 2 + len);
strcpy(buf, simple_base_name->bytes);
while (dims-- > 0) {
buf[len++] = '[';
buf[len++] = ']';
}
m_simple_name = env->string_pool.lookup(buf, len);
}
else
{
const char* fn = m_name->bytes;
const char* start;
if(m_enclosing_class_index)
{
const char* enclosing_name =
class_cp_get_class_name(this, m_enclosing_class_index);
start = fn + strlen(enclosing_name);
while (*start == '$' || isdigit(*start)) start++;
}
else
{
start = strrchr(fn, '/');
}
if(start) {
m_simple_name = env->string_pool.lookup(start + 1);
} else {
m_simple_name = const_cast<String*>(m_name);
}
}
}
return m_simple_name;
}
String* class_name_get_java_name(const String* class_name) {
unsigned len = class_name->len + 1;
char* name = (char*)STD_ALLOCA(len);
memcpy(name, class_name->bytes, len);
for(char *p = name; *p; ++p) {
if (*p=='/') *p='.';
}
String* str = VM_Global_State::loader_env->string_pool.lookup(name);
return str;
}
// end pointers between struct Class and java.lang.Class
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// begin Support for compressed and raw reference pointers
#ifndef REFS_USE_UNCOMPRESSED
bool is_compressed_reference(COMPRESSED_REFERENCE compressed_ref)
{
// A compressed reference is an offset into the heap.
uint64 heap_max_size = (VM_Global_State::loader_env->heap_end
- VM_Global_State::loader_env->heap_base);
return ((uint64) compressed_ref) < heap_max_size;
} // is_compressed_reference
COMPRESSED_REFERENCE compress_reference(ManagedObject *obj) {
#ifdef REFS_USE_RUNTIME_SWITCH
assert(VM_Global_State::loader_env->compress_references);
#endif // REFS_USE_RUNTIME_SWITCH
COMPRESSED_REFERENCE compressed_ref;
if(obj == NULL)
compressed_ref = 0;
else
compressed_ref = (COMPRESSED_REFERENCE)((POINTER_SIZE_INT)obj
- (POINTER_SIZE_INT)VM_Global_State::loader_env->heap_base);
assert(is_compressed_reference(compressed_ref));
return compressed_ref;
} //compress_reference
ManagedObject *uncompress_compressed_reference(COMPRESSED_REFERENCE compressed_ref) {
#ifdef REFS_USE_RUNTIME_SWITCH
assert(VM_Global_State::loader_env->compress_references);
#endif // REFS_USE_RUNTIME_SWITCH
assert(is_compressed_reference(compressed_ref));
if (compressed_ref == 0) {
return NULL;
} else {
return (ManagedObject *)(VM_Global_State::loader_env->heap_base + compressed_ref);
}
} //uncompress_compressed_reference
#endif // REFS_USE_UNCOMPRESSED
// end Support for compressed and raw reference pointers
////////////////////////////////////////////////////////////////////
// Function registers a number of native methods to a given class.
bool
class_register_methods(Class_Handle klass,
const JNINativeMethod* methods,
int num_methods)
{
// get class and string pool
String_Pool &pool = VM_Global_State::loader_env->string_pool;
for( int index = 0; index < num_methods; index++ ) {
// look up strings in string pool
const String *name = pool.lookup(methods[index].name);
const String *desc = pool.lookup(methods[index].signature);
// find method from class
Method *class_method = NULL;
bool found = false;
for(int count = 0; count < klass->get_number_of_methods(); count++ ) {
class_method = klass->get_method(count);
if( class_method->get_name() == name &&
class_method->get_descriptor() == desc ) {
// found method
found = true;
break;
}
}
if (found) {
TRACE2("class.native", "Register native method: "
<< klass->get_name()->bytes
<< "." << name->bytes << desc->bytes);
// Calling callback for NativeMethodBind event
NativeCodePtr native_addr = methods[index].fnPtr;
jvmti_process_native_method_bind_event( (jmethodID) class_method, native_addr, &native_addr);
if (! interpreter_enabled()) {
NativeCodePtr stub = compile_create_lil_jni_stub(class_method, native_addr, NULL);
if (!stub)
return true;
class_method->lock();
class_method->set_code_addr(stub);
class_method->unlock();
// the following lines were copy-pasted from compile_do_compilation() function
// it is not obvious that they should be here.
compile_flush_generated_code();
//class_method->set_state(Method::ST_Compiled);
//class_method->do_jit_recompiled_method_callbacks();
class_method->apply_vtable_patches();
}
class_method->set_registered_native_func(native_addr);
} else {
// create error string "<class_name>.<method_name><method_descriptor>
int clen = klass->get_name()->len;
int mlen = name->len;
int dlen = desc->len;
int len = clen + 1 + mlen + dlen;
char *error = (char*)STD_ALLOCA(len + 1);
memcpy(error, klass->get_name()->bytes, clen);
error[clen] = '.';
memcpy(error + clen + 1, name->bytes, mlen);
memcpy(error + clen + 1 + mlen, desc->bytes, dlen);
error[len] = '\0';
TRACE2("class.native", "Native could not be registered: "
<< klass->get_name()->bytes << "." << name->bytes << desc->bytes);
// raise an exception
jthrowable exc_object = exn_create("java/lang/NoSuchMethodError", error);
exn_raise_object(exc_object);
return true;
}
}
return false;
} // class_register_methods
// Function unregisters registered native methods of a given class.
bool
class_unregister_methods(Class_Handle klass)
{
// lock class
klass->lock();
for(int count = 0; count < klass->get_number_of_methods(); count++ ) {
Method* method = klass->get_method(count);
if (NULL != method->get_registered_native_func()) {
// trace
TRACE2("class.native", "Unregister native method: "
<< klass->get_name() << "." << method->get_name()->bytes
<< method->get_descriptor()->bytes);
// reset registered_native_func
method->set_registered_native_func(NULL);
}
}
// unlock class
klass->unlock();
return false;
} // class_unregister_methods
////////////////////////////////////////////////////////////////////
// begin support for JIT notification when classes are extended
struct Class_Extended_Notification_Record {
Class *class_of_interest;
JIT *jit;
void *callback_data;
Class_Extended_Notification_Record *next;
bool equals(Class *class_of_interest_, JIT *jit_, void *callback_data_) {
if ((class_of_interest == class_of_interest_) &&
(jit == jit_) &&
(callback_data == callback_data_)) {
return true;
}
return false;
}
};
void Class::lock()
{
m_lock->_lock();
}
void Class::unlock()
{
m_lock->_unlock();
}
unsigned Class::calculate_size()
{
unsigned size = 0;
size += sizeof(Class);
size += m_num_innerclasses*sizeof(InnerClass);
size += sizeof(ConstantPool)
+ m_const_pool.get_size()*sizeof(ConstPoolEntry);
for(unsigned i = 0; i < m_num_fields; i++) {
size += m_fields[i].calculate_size();
}
for(unsigned i = 0; i < m_num_methods; i++) {
size += m_methods[i].calculate_size();
}
size += m_num_superinterfaces*sizeof(Class_Super);
size += m_static_data_size;
if(!is_interface())
size += sizeof(VTable);
size += sizeof(Lock_Manager);
return size;
}
void* Class::code_alloc(size_t size, size_t alignment, Code_Allocation_Action action)
{
assert (m_class_loader);
return m_class_loader->CodeAlloc(size, alignment, action);
}