vm/vmcore/include/Class.h (743 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.
*/
/**
* @author Pavel Pervov
*/
#ifndef _CLASS_H_
#define _CLASS_H_
/**
* @file
* Interfaces to class functionality.
*/
#include <assert.h>
#include "open/gc.h"
#include "open/rt_types.h"
#include "port_malloc.h"
#include "String_Pool.h"
#include "jit_intf.h"
#include <vector>
//
// magic number, and major/minor version numbers of class file
//
#define CLASSFILE_MAGIC 0xCAFEBABE
#define CLASSFILE_MAJOR_MIN 45
// Supported class files up to this version
#define CLASSFILE_MAJOR_MAX 50
#define CLASSFILE_MINOR_MAX 0
// forward declarations
struct Class;
// external declarations
class Class_Member;
struct Field;
struct Method;
struct Class_Extended_Notification_Record;
class CodeChunkInfo;
class Lock_Manager;
class ByteReader;
struct ClassLoader;
class JIT;
struct Global_Env;
class Package;
struct VM_thread;
struct AnnotationTable;
struct VTable;
struct Intfc_Table;
/** The constant pool entry descriptor.
* For each constant pool entry, the descriptor content varies depending
* on the constant pool tag that corresponds to this constant pool entry.
* Content of each entry is described in
* <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/ClassFileFormat-Java5.pdf">
* The Java Virtual Machine Specification, Chapter 4</a>, <i>The Constant
* Pool</i> section, with the following exceptions:<ol>
* <li>A zero entry of the constant pool contains an array of tags
* corresponding to entries in the constant pool entries array.</li>
* <li>As required by
* <a href=http://java.sun.com/docs/books/vmspec/2nd-edition/ConstantPool.pdf>
* The Java Virtual Machine Specification, Chapter 5</a>
* <i>Linking/Resolution</i> section, errors are cached for entries that have
* not been resolved earlier for some reason.</li></ol>
*/
union ConstPoolEntry {
/** Zero entry of constant pool only: array of tags for constant pool.*/
unsigned char* tags;
/** CONSTANT_Class.*/
struct {
union {
/** Resolved class*/
Class* klass;
/** Resolution error, if any.*/
struct {
/** Next resolution error in this constant pool.*/
ConstPoolEntry* next;
/** Exception object describing an error.*/
ManagedObject* cause;
} error;
};
/** Index to class name in this constant pool.*/
uint16 name_index;
} CONSTANT_Class;
/** CONSTANT_String.*/
struct {
/** Resolved class.*/
String* string;
/** Index of CONSTANT_Utf8 for this string.*/
uint16 string_index;
} CONSTANT_String;
/** CONSTANT_{Field|Method|InterfaceMethod}ref.*/
struct {
union {
/** Generic class member for CONSTANT_*ref.
* Only valid for resolved refs.*/
Class_Member* member;
/** Resolved entry for CONSTANT_Fieldref.*/
Field* field;
/** resolved entry for CONSTANT_[Interface]Methodref.*/
Method* method;
/** Resolution error, if any.*/
struct {
/** Next resolution error in this constant pool.*/
ConstPoolEntry* next;
/** Exception object describing error.*/
ManagedObject* cause;
} error;
};
/** Index of CONSTANT_Class for this CONSTANT_*ref.*/
uint16 class_index;
/** Index of CONSTANT_NameAndType for CONSTANT_*ref.*/
uint16 name_and_type_index;
} CONSTANT_ref;
/** Shortcut to resolution error in CONSTANT_Class and CONSTANT_ref.*/
struct {
/** Next resolution error in this constant pool.*/
ConstPoolEntry* next;
/** Exception object describing error.*/
ManagedObject* cause;
} error;
/** CONSTANT_Integer.*/
U_32 int_value;
/** CONSTANT_Float.*/
float float_value;
/** CONSTANT_Long and CONSTANT_Double.
* @note In this case we pack all 8 bytes of long/double in one
* ConstPoolEntry and leave the second ConstPoolEntry of the long/double
* unused.*/
struct {
U_32 low_bytes;
U_32 high_bytes;
} CONSTANT_8byte;
/** CONSTANT_NameAndType.*/
struct {
/** Resolved name.*/
String* name;
/** Resolved descriptor.*/
String* descriptor;
/** Name index in this constant pool.*/
uint16 name_index;
/** Descriptor index in this constant pool.*/
uint16 descriptor_index;
} CONSTANT_NameAndType;
/** CONSTANT_Utf8.*/
struct {
/** Content of CONSTANT_Utf8 entry.*/
String* string;
} CONSTANT_Utf8;
};
/** Types of constant pool entries. These entry types are defined by a seperate
* byte array that the first constant pool entry points at.*/
enum ConstPoolTags {
/** pointer to the tags array.*/
CONSTANT_Tags = 0,
/** The next 11 tag values are taken from
* <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/ClassFileFormat-Java5.pdf">
* The Java Virtual Machine Specification, Chapter 4</a>, <i>The Constant
* Pool</i> section.*/
CONSTANT_Utf8 = 1,
CONSTANT_Integer = 3,
CONSTANT_Float = 4,
CONSTANT_Long = 5,
CONSTANT_Double = 6,
CONSTANT_Class = 7,
CONSTANT_String = 8,
CONSTANT_Fieldref = 9,
CONSTANT_Methodref = 10,
CONSTANT_InterfaceMethodref = 11,
CONSTANT_NameAndType = 12,
CONSTANT_Last = CONSTANT_NameAndType,
/** used to mark second entry of Long and Double*/
CONSTANT_UnusedEntry = CONSTANT_Last + 1,
};
/** The constant pool of a class and related operations.
* The structure covers all operations that may be required to run
* on the constant pool, such as parsing and processing queries.*/
struct ConstantPool {
private:
// tag mask; 4 bits are sufficient for tag
static const unsigned char TAG_MASK = 0x0F;
// this entry contains resolution error information
static const unsigned char ERROR_MASK = 0x40;
// "entry is resolved" flag; msb
static const unsigned char RESOLVED_MASK = 0x80;
// constant pool size
uint16 m_size;
// constant pool entries; 0-th entry contains array of constant pool tags
// for all entries
ConstPoolEntry* m_entries;
// List of constant pool entries, which resolution had failed
// Required for fast enumeration of error objects
ConstPoolEntry* m_failedResolution;
public:
/** Initializes the constant pool to its initial values.*/
ConstantPool() {
init();
}
/** Clears constant pool content (if there are any).*/
~ConstantPool() {
clear();
}
/** Checks whether the constant pool is not empty.
* @return <code>true</code> if the constant pool contains
* certain entries; otherwise <code>false</code>.*/
bool available() const { return m_size != 0; }
/** Gets the size of the given constant pool.
* @return The number of entries in the constant pool.*/
uint16 get_size() const { return m_size; }
/** Checks whether the index is a valid one in the constant pool.
* @param[in] index - an index in the constant pool
* @return <code>true</code> if the index is a valid one in the constant
* pool; otherwise <code>false</code>.*/
bool is_valid_index(uint16 index) const {
// index is valid if it's greater than zero and less than m_size
// See specification 4.2 about constant_pool_count
return index != 0 && index < m_size;
}
/** Checks whether the constant-pool entry is resolved.
* @param[in] index - an index in the constant pool
* @return <code>true</code> if the entry is resolved;
* otherwise <code>false</code>.*/
bool is_entry_resolved(uint16 index) const {
assert(is_valid_index(index));
return (m_entries[0].tags[index] & RESOLVED_MASK) != 0;
}
/** Checks whether the resolution of the constant-pool entry has failed.
* @param[in] index - an index in the constant pool
* @return <code>true</code> if the resolution error is recorded
* for the entry.*/
bool is_entry_in_error(uint16 index) const {
assert(is_valid_index(index));
return (m_entries[0].tags[index] & ERROR_MASK) != 0;
}
/** Checks whether the constant-pool entry represents the string of
* the #CONSTANT_Utf8 type.
* @param[in] index - an index in the constant pool
* @return <code>true</code> if the given entry is the <code>utf8</code>
* string; otherwise <code>false</code>.*/
bool is_utf8(uint16 index) const {
return get_tag(index) == CONSTANT_Utf8;
}
/** Checks whether the constant-pool entry refers to a #CONSTANT_Class.
* @param[in] index - an index in the constant pool
* @return <code>true</code> if the given entry is a class;
* otherwise <code>false</code>.*/
bool is_class(uint16 index) const {
return get_tag(index) == CONSTANT_Class;
}
/** Checks whether the constant-pool entry contains a constant.
* @param[in] index - an index in the constant pool
* @return <code>true</code> if the given entry contains a constant;
* otherwise <code>false</code>.*/
bool is_constant(uint16 index) const {
return get_tag(index) == CONSTANT_Integer
|| get_tag(index) == CONSTANT_Float
|| get_tag(index) == CONSTANT_Long
|| get_tag(index) == CONSTANT_Double
|| get_tag(index) == CONSTANT_String
|| get_tag(index) == CONSTANT_Class;
}
/** Checks whether the constant-pool entry is a literal constant.
* @param[in] index - an index in the constant pool
* @return <code>true</code> if the given entry contains a string;
* otherwise <code>false</code>.*/
bool is_string(uint16 index) const {
return get_tag(index) == CONSTANT_String;
}
/** Checks whether the constant-pool entry is #CONSTANT_NameAndType.
* @param[in] index - an index in the constant pool
* @return <code>true</code> if the given entry contains name-and-type;
* otherwise <code>false</code>.*/
bool is_name_and_type(uint16 index) const {
return get_tag(index) == CONSTANT_NameAndType;
}
/** Checks whether the constant-pool entry contains a field reference,
* #CONSTANT_Fieldref.
* @param[in] index - an index in the constant pool
* @return <code>true</code> if the given entry contains a field reference;
* otherwise <code>false</code>.*/
bool is_fieldref(uint16 index) const {
return get_tag(index) == CONSTANT_Fieldref;
}
/** Checks whether the constant-pool entry contains a method reference,
* #CONSTANT_Methodref.
* @param[in] index - an index in the constant pool
* @return <code>true</code> if the given entry contains a method reference;
* otherwise <code>false</code>.*/
bool is_methodref(uint16 index) const {
return get_tag(index) == CONSTANT_Methodref;
}
/** Checks whether the constant-pool entry constains an interface-method
* reference, #CONSTANT_InterfaceMethodref.
* @param[in] index - an index in the constant pool
* @return <code>true</code> if the given entry contains an interface-method
* reference; otherwise <code>false</code>.*/
bool is_interfacemethodref(uint16 index) const {
return get_tag(index) == CONSTANT_InterfaceMethodref;
}
/** Gets a tag of the referenced constant-pool entry.
* @param[in] index - an index in the constant pool
* @return A constant-pool entry tag for a given index.*/
unsigned char get_tag(uint16 index) const {
assert(is_valid_index(index));
return m_entries[0].tags[index] & TAG_MASK;
}
/** Gets characters from the <code>utf8</code> string stored in the
* constant pool.
* @param[in] index - an index in the constant pool
* @return Characters from the <code>utf8</code> string stored in
* the constant pool.*/
const char* get_utf8_chars(uint16 index) const {
return get_utf8_string(index)->bytes;
}
/** Gets the <code>utf8</code> string stored in the constant pool.
* @param[in] index - an index in the constant pool
* @return The <code>utf8</code> string.*/
String* get_utf8_string(uint16 index) const {
assert(is_utf8(index));
return m_entries[index].CONSTANT_Utf8.string;
}
/** Gets characters stored in the <code>utf8</code> string for
* the #CONSTANT_String entry.
* @param[in] index - an index in the constant pool
* @return The <code>utf8</code> string characters for the given
* constant-pool entry.*/
const char* get_string_chars(uint16 index) const {
return get_string(index)->bytes;
}
/** Gets the <code>utf8</code> string stored for the #CONSTANT_String
* entry.
* @param[in] index - an index in the constant pool
* @return The <code>utf8</code> string stored in the constant-pool entry.*/
String* get_string(uint16 index) const {
assert(is_string(index));
return m_entries[index].CONSTANT_String.string;
}
/** Gets the <code>utf8</code> string representing the name part of the
* name-and-type constant-pool entry.
* @param[in] index - an index in the constant pool
* @return The <code>utf8</code> string with the name part.*/
String* get_name_and_type_name(uint16 index) const {
assert(is_name_and_type(index));
assert(is_entry_resolved(index));
return m_entries[index].CONSTANT_NameAndType.name;
}
/** Gets the <code>utf8</code> string representing the descriptor part of
* the name-and-type constant-pool entry.
* @param[in] index - an index in the constant pool
* @return The <code>utf8</code> string with the descriptor part.*/
String* get_name_and_type_descriptor(uint16 index) const {
assert(is_name_and_type(index));
assert(is_entry_resolved(index));
return m_entries[index].CONSTANT_NameAndType.descriptor;
}
/** Gets the generic class member for the <code>CONSTANT_*ref</code>
* constant-pool entry.
* @param[in] index - an index in the constant pool
* @return The generic-class member for the given constant-pool entry.*/
Class_Member* get_ref_class_member(uint16 index) const {
assert(is_fieldref(index)
|| is_methodref(index)
|| is_interfacemethodref(index));
return m_entries[index].CONSTANT_ref.member;
}
/** Gets the method from the #CONSTANT_Methodref or
* the #CONSTANT_InterfaceMethodref constant-pool entry
* @param[in] index - an index in the constant pool
* @return The method from the given constant-pool entry.*/
Method* get_ref_method(uint16 index) const {
assert(is_methodref(index)
|| is_interfacemethodref(index));
assert(is_entry_resolved(index));
return m_entries[index].CONSTANT_ref.method;
}
/** Gets the field from the #CONSTANT_Fieldref
* constant-pool entry.
* @param[in] index - an index in the constant pool
* @return The field from the given constant-pool entry.*/
Field* get_ref_field(uint16 index) const {
assert(is_fieldref(index));
assert(is_entry_resolved(index));
return m_entries[index].CONSTANT_ref.field;
}
/** Gets the class for the #CONSTANT_Class
* constant-pool entry.
* @param[in] index - an index in the constant pool
* @return The class for the given constant-pool entry.*/
Class* get_class_class(uint16 index) const {
assert(is_class(index));
assert(is_entry_resolved(index));
return m_entries[index].CONSTANT_Class.klass;
}
/** Gets a 32-bit value (either interger or float) for a constant stored
* in the constant pool.
* @param[in] index - an index in the constant pool
* @return The value of a 32-bit constant stored in the constant pool.*/
U_32 get_4byte(uint16 index) const {
assert(get_tag(index) == CONSTANT_Integer
|| get_tag(index) == CONSTANT_Float);
return m_entries[index].int_value;
}
/** Gets an integer value for a constant stored in the constant pool.
* @param[in] index - an index in the constant pool
* @return The value of integer constant stored in the constant pool.*/
U_32 get_int(uint16 index) const {
assert(get_tag(index) == CONSTANT_Integer);
return m_entries[index].int_value;
}
/** Gets a float value for a constant stored in the constant pool.
* @param[in] index - an index in the constant pool
* @return A value of a float constant stored in the constant pool.*/
float get_float(uint16 index) const {
assert(get_tag(index) == CONSTANT_Float);
return m_entries[index].float_value;
}
/** Gets a low word of the 64-bit constant (either long or double)
* stored in the constant pool.
* @param[in] index - an index in the constant pool
* @return A value of low 32-bits of 64-bit constant.*/
U_32 get_8byte_low_word(uint16 index) const {
assert(get_tag(index) == CONSTANT_Long
|| get_tag(index) == CONSTANT_Double);
return m_entries[index].CONSTANT_8byte.low_bytes;
}
/** Gets a high word of the 64-bit constant (either long or double)
* stored in the constant pool.
* @param[in] index - an index in the constant pool
* @return A value of high 32-bits of 64-bit constant.*/
U_32 get_8byte_high_word(uint16 index) const {
assert(get_tag(index) == CONSTANT_Long
|| get_tag(index) == CONSTANT_Double);
return m_entries[index].CONSTANT_8byte.high_bytes;
}
/** Gets an address of a constant stored in the constant pool.
* @param[in] index - an index in the constant pool
* @return An address of a constant.*/
void* get_address_of_constant(uint16 index) const {
assert(is_constant(index));
assert(!is_string(index));
return (void*)(m_entries + index);
}
/** Gets an exception, which has caused failure of the referred
* constant-pool entry.
* @param[in] index - an index in the constant pool
* @return An exception object, which is the cause of the
* resolution failure.*/
jthrowable get_error_cause(uint16 index) const {
assert(is_entry_in_error(index));
return (jthrowable)(&(m_entries[index].error.cause));
}
/** Gets a head of a single-linked list containing resolution errors
* in the given constant pool.
* @return A head of a signle-linked list of constant-pool entries,
* which resolution had failed.*/
ConstPoolEntry* get_error_chain() const {
return m_failedResolution;
}
/** Gets an an index in the constant pool where the <code>utf8</code>
* representation for #CONSTANT_String is stored.
* @param[in] index - an index in the constant pool for the
* #CONSTANT_String entry
* @return An an index in the constant pool with the <code>utf8</code>
* representation of the given string.*/
uint16 get_string_index(uint16 index) const {
assert(is_string(index));
return m_entries[index].CONSTANT_String.string_index;
}
/** Gets an index of the constant-pool entry containing the
* <code>utf8</code> string with the name part.
* @param[in] index - an index in the constant pool
* @return An an index in the constant pool with the <code>utf8</code>
* name string.*/
uint16 get_name_and_type_name_index(uint16 index) const {
assert(is_name_and_type(index));
return m_entries[index].CONSTANT_NameAndType.name_index;
}
/** Gets an index of the constant-pool entry containing the
* <code>utf8</code> string with the descriptor part.
* @param[in] index - an index in the constant pool
* @return An an index in the constant pool with the <code>utf8</code>
* string for the descriptor.*/
uint16 get_name_and_type_descriptor_index(uint16 index) const {
assert(is_name_and_type(index));
return m_entries[index].CONSTANT_NameAndType.descriptor_index;
}
/** Gets an index of the constant-pool entry containing a class for
* the given <code>CONSTANT_*ref</code> entry.
* @param[in] index - an index in the constant pool
* @return An index of a class entry for the given constant-pool entry.*/
uint16 get_ref_class_index(uint16 index) const {
assert(is_fieldref(index)
|| is_methodref(index)
|| is_interfacemethodref(index));
return m_entries[index].CONSTANT_ref.class_index;
}
/** Gets an index of <code>CONSTANT_NameAndType</code> for the given
* constant-pool entry.
* @param[in] index - an index in the constant pool
* @return An index of #CONSTANT_NameAndType for the given
* constant-pool entry.*/
uint16 get_ref_name_and_type_index(uint16 index) const {
assert(is_fieldref(index)
|| is_methodref(index)
|| is_interfacemethodref(index));
return m_entries[index].CONSTANT_ref.name_and_type_index;
}
/** Gets a class-name an index in the constant pool for the
* #CONSTANT_Class entry.
* @param[in] index - an index in the constant pool
* @return An index of the <code>utf8</code> name of the given class.*/
uint16 get_class_name_index(uint16 index) const {
assert(is_class(index));
return m_entries[index].CONSTANT_Class.name_index;
}
/** Resolves an entry to the class.
* @param[in] index - an index in the constant pool
* @param[in] clss - a class to resolve the given entry to*/
void resolve_entry(uint16 index, Class* clss) {
// we do not want to resolve entry of a different type
assert(is_class(index));
set_entry_resolved(index);
m_entries[index].CONSTANT_Class.klass = clss;
}
/** Resolves an entry to the field.
* @param[in] index - an index in the constant pool
* @param[in] field - a field to resolve the given entry to*/
void resolve_entry(uint16 index, Field* field) {
// we do not want to resolve entry of different type
assert(is_fieldref(index));
set_entry_resolved(index);
m_entries[index].CONSTANT_ref.field = field;
}
/** Resolves an entry to the method.
* @param[in] index - an index in the constant pool
* @param[in] method - a method to resolve the given entry to*/
void resolve_entry(uint16 index, Method* method) {
// we do not want to resolve entry of a different type
assert(is_methodref(index) || is_interfacemethodref(index));
set_entry_resolved(index);
m_entries[index].CONSTANT_ref.method = method;
}
/** Records a resolution error into a constant-pool entry.
* @param[in] index - an index in the constant pool
* @param[in] exn - a cause of resolution failure
* @note Disable suspension during this operation.*/
void resolve_as_error(uint16 index, jthrowable exn) {
assert(is_class(index)
|| is_fieldref(index)
|| is_methodref(index)
|| is_interfacemethodref(index));
set_entry_error_state(index);
m_entries[index].error.cause = *((ManagedObject**)exn);
m_entries[index].error.next = m_failedResolution;
assert(&(m_entries[index]) != m_failedResolution);
m_failedResolution = &(m_entries[index]);
}
/** Parses in a constant pool for a class.
* @param[in] clss - a class containing the given constant pool
* @param[in] string_pool - a reference to the string pool to intern strings in
* @param[in] cfs - a byte stream to parse the constant pool from
* @return <code>true</code> if the constant pool was parsed successfully;
* <code>false</code> if some error was discovered during the parsing.*/
bool parse(Class* clss, String_Pool& string_pool, ByteReader& cfs);
/** Checks constant pool consistency. <ul>
* <li>Makes sure that all indices to other constant pool entries are in range
* and that contents of the entries are of the right type.
* <li>Sets #CONSTANT_Class entries to point directly
* to <code>String</code> representing the internal form of a fully qualified
* form of a fully qualified name of <code>%Class</code>.
* <li>Sets #CONSTANT_String entries to point directly to the
* <code>String</code> representation.
* <li>Preresolves #CONSTANT_NameAndType entries to signatures. </ul>
* @param[in] env - VM environment
* @param[in] clss - the class that the given constant pool belongs to
* @param[in] is_trusted_cl - defines whether class was loaded by
* trusted classloader. User defined classloaders are not trusted.
* @return <code>true</code> if the constant pool of clss is valid;
* otherwise <code>false</code>.*/
bool check(Global_Env * env, Class* clss, bool is_trusted_cl);
/** Clears the constant-pool content: tags and entries arrays.*/
void clear() {
if(m_size != 0) {
delete[] m_entries[0].tags;
delete[] m_entries;
}
init();
}
/** Initializes the constant pool to initial values.*/
void init() {
m_size = 0;
m_entries = NULL;
m_failedResolution = NULL;
}
private:
/** Sets a resolved flag in the constant-pool entry.
* @param[in] index - an index in the constant pool*/
void set_entry_resolved(uint16 index) {
assert(is_valid_index(index));
//// we do not want to resolve one entry twice
// ppervov: FIXME: there is possible positive/negative race condition
// in class resolution
//assert(!is_entry_resolved(index));
// we should not resolve failed entries
// see comment above
//assert(!is_entry_in_error(index));
m_entries[0].tags[index] |= RESOLVED_MASK;
}
/** Sets an error flag in the constant-pool entry to mark it as failed.
* @param[in] index - an index in the constant pool*/
void set_entry_error_state(uint16 index) {
assert(is_valid_index(index));
//// we do not want to reset the resolved error
// ppervov: FIXME: there is possible positive/negative race condition
// in class resolution
//assert(!is_entry_resolved(index));
// we do not want to reset the reason of the failure
// see comment above
//assert(!is_entry_in_error(index));
m_entries[0].tags[index] |= ERROR_MASK;
}
/** Resolves the #CONSTANT_NameAndType constant-pool entry
* to actual string values.
* @param[in] index - an index in the constant pool
* @param[in] name - name-and-type name
* @param[in] descriptor - name-and-type type (descriptor)*/
void resolve_entry(uint16 index, String* name, String* descriptor) {
// we do not want to resolve entry of different type
assert(is_name_and_type(index));
set_entry_resolved(index);
m_entries[index].CONSTANT_NameAndType.name = name;
m_entries[index].CONSTANT_NameAndType.descriptor = descriptor;
}
/** Resolves the <code>CONSTANT_String</code> constant-pool entry to
* actual string values.
* @param[in] index - an index in the constant pool
* @param[in] str - an actual string*/
void resolve_entry(uint16 index, String* str) {
assert(is_string(index));
set_entry_resolved(index);
m_entries[index].CONSTANT_String.string = str;
}
};
/** Converts a class name from an internal (VM) form to the Java form.
* @param[in] class_name - the class name in an internal form
* @return The class name in the Java form.*/
VMEXPORT String* class_name_get_java_name(const String* class_name);
// A Java class
extern "C" {
/** The state of the Java class*/
enum Class_State {
ST_Start, /// the initial state
ST_LoadingAncestors, /// the loading super class and super interfaces
ST_Loaded, /// successfully loaded
ST_BytecodesVerified, /// bytecodes for methods verified for the class
ST_InstanceSizeComputed, /// preparing the class; instance size known
ST_Prepared, /// successfully prepared
ST_ConstraintsVerified, /// constraints verified for the class
ST_Initializing, /// initializing the class
ST_Initialized, /// the class initialized
ST_Error /// bad class or the class initializer failed
};
/** Access and properties flags for Class, Field and Method.*/
enum AccessAndPropertiesFlags {
/** Public access modifier. Valid for Class, Field, Method. */
ACC_PUBLIC = 0x0001,
/** Private access modifier. Valid for Field, Method.*/
ACC_PRIVATE = 0x0002,
/** Protected access modifier. Valid for Field, Method.*/
ACC_PROTECTED = 0x0004,
/** Static modifier. Valid for Field, Method.*/
ACC_STATIC = 0x0008,
/** Final modifier. Valid for Class, Field, Method.*/
ACC_FINAL = 0x0010,
/** Super modifier. Valid for Class.*/
ACC_SUPER = 0x0020,
/** Synchronized modifier. Valid for Method.*/
ACC_SYNCHRONIZED = 0x0020,
/** Bridge modifier. Valid for Method (since J2SE 5.0).*/
ACC_BRIDGE = 0x0040,
/** Volatile modifier. Valid for Field.*/
ACC_VOLATILE = 0x0040,
/** Varargs modifier. Valid for Method (since J2SE 5.0).*/
ACC_VARARGS = 0x0080,
/** Transient modifier. Valid for Field.*/
ACC_TRANSIENT = 0x0080,
/** Native modifier. Valid for Method.*/
ACC_NATIVE = 0x0100,
/** Interface modifier. Valid for Class.*/
ACC_INTERFACE = 0x0200,
/** Abstract modifier. Valid for Class, Method.*/
ACC_ABSTRACT = 0x0400,
/** Strict modifier. Valid for Method.*/
ACC_STRICT = 0x0800,
/** Synthetic modifier. Valid for Class, Field, Method (since J2SE 5.0).*/
ACC_SYNTHETIC = 0x1000,
/** Annotation modifier. Valid for Class (since J2SE 5.0).*/
ACC_ANNOTATION = 0x2000,
/** Enum modifier. Valid for Class, Field (since J2SE 5.0).*/
ACC_ENUM = 0x4000
};
/** VM representation of Java class.
* This class contains methods for parsing classes, querying class properties,
* setting external properties of a class (source file name, class file name),
* calling the verifier, preparing, resolving and initializing the class.*/
struct Class {
private:
typedef struct {
union {
const String* name;
Class* clss;
};
unsigned cp_index;
} Class_Super;
//
// super class of this class; initially, it is the string name of super
// class; after super class is loaded, it becomes a pointer to class
// structure of the super class.
//
Class_Super m_super_class;
// class name in internal (VM, class-file) format
const String* m_name;
// class canonical (Java) name
String* m_java_name;
// generic type information (since Java 1.5.0)
String* m_signature;
// simple name of the class as given in the source code; empty string if anonymous
String* m_simple_name;
// package to which this class belongs
Package* m_package;
// Distance in the hierarchy from java/lang/Object
U_32 m_depth;
// The field m_is_suitable_for_fast_instanceof should be 0
// if depth==0 or depth>=vm_max_fast_instanceof_depth()
// or is_array or access_flags&ACC_INTERFACE
// It should be 1 otherwise
int m_is_suitable_for_fast_instanceof;
// string name of file from which this class has been loaded
const char* m_class_file_name;
// string name of source java file from which this class has been compiled
const String* m_src_file_name;
// unique class id
// FIXME: current implementation of id is not thread safe
// so, class id may not be unique
unsigned m_id;
// The class loader used to load this class.
ClassLoader* m_class_loader;
// This points to the location where java.lang.Class associated
// with the current class resides. Similarly, java.lang.Class has a field
// that points to the corresponding Class data structure.
ManagedObject** m_class_handle;
// class file major version
uint16 m_version;
// Access and properties flags of a class
uint16 m_access_flags;
// state of this class
Class_State m_state;
// Is this class marked as deprecated
bool m_deprecated;
// Does this class represent a primitive type?
unsigned m_is_primitive : 1;
// Does this class represent an array?
unsigned m_is_array : 1;
// Does base class of this array is primitive
unsigned m_is_array_of_primitives : 1;
// Does the class have a finalizer that is not inherited from
// java.lang.Object?
unsigned m_has_finalizer : 1;
// Should access from this class be checked
// (needed for certain special classes)
unsigned m_can_access_all : 1;
// Can instances of this class be allocated using a fast inline sequence
// containing no calls to other routines
unsigned char m_is_fast_allocation_possible;
// Offset from the top by CLASS_ALLOCATED_SIZE_OFFSET
// The number of bytes allocated for this object. It is the same as
// instance_data_size with the constraint bit cleared. This includes
// the OBJECT_HEADER_SIZE as well as the OBJECT_VTABLE_POINTER_SIZE
unsigned int m_allocated_size;
// This is the size of an instance without any alignment padding.
// It can be used while calculating the field offsets of subclasses.
// It does not include the OBJECT_HEADER_SIZE but does include the
// OBJECT_VTABLE_POINTER_SIZE.
// The m_allocated_size field will be this field properly aligned.
unsigned m_unpadded_instance_data_size;
// How should objects of this class be aligned by GC.
int m_alignment;
// Try to keep instance_data_size near vtable since they are used at the same time
// by the allocation routines and sharing a cache line seem to help.
// The next to high bit is set if allocation needs to consider class_properties.
// (mumble->instance_data_size & NEXT_TO_HIGH_BIT_CLEAR_MASK) will always return the
// actual size of and instance of class mumble.
// Use get_instance_data_size() to get the actual size of an instance.
// Use set_instance_data_size_constraint_bit() to set this bit.
// For most classes the size of a class instance's data block.
// This is what is passed to the GC. See above for details.
unsigned m_instance_data_size;
// ppervov: FIXME: the next two can be joined into a union;
// vtable compression should be dropped in that case
// virtual method table; <code>NULL</code> for interfaces
VTable* m_vtable;
// "Compressed VTable" - offset from the base of VTable allocation area
Allocation_Handle m_allocation_handle;
// number of virtual methods in vtable
unsigned m_num_virtual_method_entries;
// number of interface methods in vtable
unsigned m_num_intfc_method_entries;
// An array of pointers to Method descriptors, one descriptor
// for each corresponding entry in m_vtable.methods[].
Method** m_vtable_descriptors;
// number of dimensions in array; current VM limitation is 255
// Note, that you can derive the base component type of the array
// by looking at m_name->bytes[m_num_dimensions].
unsigned char m_num_dimensions;
// for non-primitive arrays only, array_base_class is the base class
// of an array
Class* m_array_base_class;
// class of the element of an array
Class* m_array_element_class;
// size of element of array; equals zero, if this class is not an array
unsigned int m_array_element_size;
// shift corresponding to size of element of array, undefined for non-arrays
unsigned int m_array_element_shift;
// Number of superinterfaces
uint16 m_num_superinterfaces;
// array of interfaces this class implements; size is m_num_superinterfaces
// initially, it is an array of string names of interfaces and then,
// after superinterfaces are loaded, this becomes an array pointers
// to superinterface class structures
Class_Super* m_superinterfaces;
// constant pool of class
ConstantPool m_const_pool;
// number of fields in this class
uint16 m_num_fields;
// number of static fields in this class
uint16 m_num_static_fields;
// number of instance fields that are references
unsigned m_num_instance_refs;
// array of fields; size is m_num_fields
Field* m_fields;
// size of this class' static data block
unsigned m_static_data_size;
// block containing array of static data fields
void* m_static_data_block;
// number of methods in this class
uint16 m_num_methods;
// array of methods; size is m_num_methods
Method* m_methods;
// pointer to finalize method, NULL if none exists
Method* m_finalize_method;
// pointer to <clinit> method, NULL if none exists
Method* m_static_initializer;
// pointer to init()V method, cached for performance
Method* m_default_constructor;
// index of declaring class in constant pool of this class
uint16 m_declaring_class_index;
// index of CONSTANT_Class of outer class
uint16 m_enclosing_class_index;
// index of CONSTANT_MethodRef of outer method
uint16 m_enclosing_method_index;
// number of inner classes
uint16 m_num_innerclasses;
struct InnerClass {
uint16 index;
uint16 access_flags;
};
// indexes of inner classes descriptors in constant pool
InnerClass* m_innerclasses;
// annotations for this class
AnnotationTable* m_annotations;
//invisible annotations for this class
AnnotationTable* m_invisible_annotations;
// thread, which currently executes <clinit>
VM_thread* m_initializing_thread;
// These fields store information for
// Class Hierarchy Analysis JIT optimizations
// first class extending this class
Class* m_cha_first_child;
// next class which extends the same superclass
Class* m_cha_next_sibling;
// SourceDebugExtension class attribute support
String* m_sourceDebugExtension;
// verifier private data pointer
void* m_verify_data;
// class operations lock
Lock_Manager* m_lock;
// Per-class statistics
// Number of times an instance of the class has been created
// using new, newarray, etc
uint64 m_num_allocations;
// Number of bytes allocated for instances of the class
uint64 m_num_bytes_allocated;
// Number of instanceof/checkcast calls both from the user code
// and the VM that were not subsumed by the fast version of instanceof
uint64 m_num_instanceof_slow;
// For subclasses of java.lang.Throwable only
uint64 m_num_throws;
// Number of times class is checked for initialization
uint64 m_num_class_init_checks;
// Number of "padding" bytes added per class instance to its fields to
// make each field at least 32 bits
U_32 m_num_field_padding_bytes;
public:
/** Initializes class-member variables to their initial values.
* @param[in] env - VM environment
* @param[in] name - a class name to assign to the given class
* @param[in] cl - a class loader for the given class*/
void init_internals(const Global_Env* env, const String* name, ClassLoader* cl);
/** Clears member variables within a class.*/
void clear_internals();
void notify_unloading();
/** Determines whether the given class has a super class.
* @return <code>true</code> if the current class has a super class;
* otherwise <code>false</code>.*/
bool has_super_class() const {
return m_super_class.clss != NULL;
}
/** Gets the name of the super class.
*
* @return The super class name or <code>NULL</code>, if the given class
* is <code>java/lang/Object</code>.
* @note It is valid until the super class is loaded; after that, use
* <code>get_super_class()->get_name()</code> to retrieve the
* super class name.*/
const String* get_super_class_name() const {
return m_super_class.name;
}
/** Gets the super class of the given class.
* @return The super class of the given class or <code>NULL</code>,
* if the given class is <code>java/lang/Object</code>.*/
Class* get_super_class() const {
return m_super_class.clss;
}
/** Gets the class loader of the given class.
* @return the class loader of the given class.*/
ClassLoader* get_class_loader() const {
return m_class_loader;
}
/** Gets the class handle of <code>java.lang.Class</code> for the given class.
* @return The <code>java.lang.Class</code> handle for the given class.*/
ManagedObject** get_class_handle() const { return m_class_handle; }
/** Gets the natively interned class name for the given class.
* @return The class name in the VM format.*/
const String* get_name() const { return m_name; }
/** Gets a natively interned class name for the given class.
* @return A class name in the Java format.*/
String* get_java_name() {
if(!m_java_name) {
m_java_name = class_name_get_java_name(m_name);
}
return m_java_name;
}
/** Gets a class signature.
* @return A class signature.*/
String* get_signature() const { return m_signature; }
/** Gets a simple name of the class.
* @return A simple name of the class.*/
String* get_simple_name();
/** Gets a package containing the given class.
* @return A package to which the given class belongs.*/
Package* get_package() const { return m_package; }
/** Gets depth in the hierarchy of the given class.
* @return A number of classes in the super-class hierarchy.*/
U_32 get_depth() const { return m_depth; }
bool get_fast_instanceof_flag() const { return m_is_suitable_for_fast_instanceof; }
/** Gets the vtable for the given class.
* @return The vtable for the given class or <code>NULL</code>, if the given
* class is an interface.*/
VTable* get_vtable() const { return m_vtable; }
/** Gets an allocation handle for the given class.*/
Allocation_Handle get_allocation_handle() const { return m_allocation_handle; }
/** Gets the length of the source-file name.
* @return The length in bytes of the source-file name.*/
size_t get_source_file_name_length() {
assert(has_source_information());
return m_src_file_name->len;
}
/** Gets a source-file name.
* @return A source-file name for the given class.*/
const char* get_source_file_name() {
assert(has_source_information());
return m_src_file_name->bytes;
}
/** Gets a method localed at <code>method_idx</code> in
* the <code>m_vtable_descriptors</code> table.
* @param method_idx - index of method in vtable descriptors table
* @return A method from the vtable descriptors table.*/
Method* get_method_from_vtable(unsigned method_idx) const {
return m_vtable_descriptors[method_idx];
}
/// Returns the number of virtual methods in vtable
unsigned get_number_of_virtual_method_entries() const {
return m_num_virtual_method_entries;
}
/** Gets the first subclass for Class Hierarchy Analysis.
* @return The first subclass.*/
Class* get_first_child() const { return m_cha_first_child; }
/** Return the next sibling for Class Hierarchy Analysis.
* @return The next sibling.*/
Class* get_next_sibling() const { return m_cha_next_sibling; }
/** Gets offset of m_depth field in struct Class.
* @note Instanceof helpers use returned offset.*/
static size_t get_offset_of_depth() {
Class* dummy=NULL;
return (size_t)((char*)(&dummy->m_depth));
}
/** Gets offset of m_is_suitable_for_fast_instanceof field in struct Class.
* @note Instanceof helper uses returned offset.*/
static size_t get_offset_of_fast_instanceof_flag() {
Class* dummy=NULL;
return (size_t)((char*)(&dummy->m_is_suitable_for_fast_instanceof));
}
/** Gets an offset of <code>m_is_fast_allocation_possible</code> in
* the class.
* @note Allocation helpers use returned offset.*/
size_t get_offset_of_fast_allocation_flag() {
// else one byte ld in helpers will fail
assert(sizeof(m_is_fast_allocation_possible) == 1);
Class* dummy=NULL;
return (size_t)((char*)(&dummy->m_is_fast_allocation_possible));
}
/** Gets an offset of <code>m_allocation_handle</code> in the class.
* @note Allocation helpers use returned offset.*/
size_t get_offset_of_allocation_handle() {
assert(sizeof(m_allocation_handle) == sizeof(void*));
Class* dummy=NULL;
return (size_t)((char*)(&dummy->m_allocation_handle));
}
/** Gets an offset of <code>m_instance_data_size</code> in the class.
* @note Allocation helpers use returned offset.*/
size_t get_offset_of_instance_data_size() {
assert(sizeof(m_instance_data_size) == 4);
Class* dummy=NULL;
return (size_t)((char*)(&dummy->m_instance_data_size));
}
/** Gets an offset of <code>m_num_class_init_checks</code> in the class.
* @note Class initialization helper on IPF uses returned offset.*/
static size_t get_offset_of_class_init_checks() {
Class* dummy = NULL;
return (size_t)((char*)(&dummy->m_num_class_init_checks) - (char*)dummy);
}
/** Gets an offset of <code>m_array_element_class</code> in the class.
* @note Class initialization helper on IPF uses returned offset.*/
static size_t get_offset_of_array_element_class() {
Class* dummy = NULL;
assert(sizeof(dummy->m_array_element_class) == sizeof(void*));
return (size_t)((char*)(&dummy->m_array_element_class) - (char*)dummy);
}
/** Gets an offset of <code>m_class_handle</code> in the class.
* @note It used by VMHelper class*/
static size_t get_offset_of_jlc_handle () {
Class* dummy=NULL;
return (size_t)((char*)(&dummy->m_class_handle) - (char*)dummy);
}
/** Gets the number of array dimensions.
* @return Number of dimentions in an array represented by this class.*/
unsigned char get_number_of_dimensions() const {
assert(is_array());
return m_num_dimensions;
}
/**
* Gets the base class of the array (for non-primitive arrays only).
* @return Class describing the base type of an array
* represented by this class.*/
Class* get_array_base_class() const {
assert(is_array());
return m_array_base_class;
}
/** Gets the class of the array element.
* @return Class describing the element of an array
* represented by this class.*/
Class* get_array_element_class() const {
assert(is_array());
return m_array_element_class;
}
/** Gets the class state.
* @return The class state.*/
Class_State get_state() const { return m_state; }
/** Gets a number of superinterfaces.
* @return A number of superinterfaces of the given class.*/
uint16 get_number_of_superinterfaces() const { return m_num_superinterfaces; }
/** Gets a super-interface name from the array of super-interfaces that
* the given class implements.
* @param[in] index - an index of super-interface to return the name for
* @return The requested super-interface name.*/
const String* get_superinterface_name(uint16 index) const {
assert(index < m_num_superinterfaces);
return m_superinterfaces[index].name;
}
/** Gets a superinterface from the array of superinterfaces the given class
* implements.
* @param[in] index - an index of a superinterface to return
* @return A requested superinterface.*/
Class* get_superinterface(uint16 index) const {
assert(index < m_num_superinterfaces);
return m_superinterfaces[index].clss;
}
/** Gets a constant pool of the given class.
* @return A constant pool of the given class.*/
ConstantPool& get_constant_pool() { return m_const_pool; }
/** Gets a number of fields in the given class.
* @return A number of fields in the given class.*/
uint16 get_number_of_fields() const { return m_num_fields; }
/** Gets a number of static fields in the given class.
* @return A number of static fields in the given class.*/
uint16 get_number_of_static_fields() const { return m_num_static_fields; }
/** Gets a field from the given class by its position in the class-fields
* array.
* @param[in] index - an index in the class-fields array of a field to
* retrieve
* @return The requested field.*/
Field* get_field(uint16 index) const;
/** Gets an address of the memory block containing static data of
* the given class.
* @return An address of a static data block.*/
void* get_static_data_address() const { return m_static_data_block; }
/** Gets a number of methods in the given class.
* @return A number of methods in the given class.*/
uint16 get_number_of_methods() const { return m_num_methods; }
/** Gets a method from the given class by its position in the
* class-method array.
* @param[in] index - an index in the class-method array of a
* method to retrieve
* @return A requested method.*/
Method* get_method(uint16 index) const;
/** Gets a constant-pool index of the declaring class.
* @return An index in the constant pool describing the requested
* declaring class.*/
uint16 get_declaring_class_index() const { return m_declaring_class_index; }
/** Gets a constant-pool index of the enclosing class.
* @return An index in the constant pool describing the requested
* enclosing class.*/
uint16 get_enclosing_class_index() const { return m_enclosing_class_index; }
/** Gets a constant-pool index of the enclosing method.
* @return An index in the constant pool describing the requested enclosing
* method.*/
uint16 get_enclosing_method_index() const { return m_enclosing_method_index; }
/** Gets a number of inner classes.
* @return A number of inner classes.*/
uint16 get_number_of_inner_classes() const { return m_num_innerclasses; }
/** Gets an index in the constant pool of the given class, which
* describes the inner class.
* @param[in] index - an index of the inner class in the array of
* inner classes in the given class
* @return An index in the constant pool describing the requested inner
* class.*/
uint16 get_inner_class_index(uint16 index) const {
assert(index < m_num_innerclasses);
return m_innerclasses[index].index;
}
/** Gets access flags for the inner class.
* @param[in] index - an index of the inner class in the array of inner
* classes in the given class
* @return Access flags of the requested inner class.*/
uint16 get_inner_class_access_flags(uint16 index) const {
assert(index < m_num_innerclasses);
return m_innerclasses[index].access_flags;
}
/** Gets a collection of annotations.
* @return A collection of annotations.*/
AnnotationTable* get_annotations() const { return m_annotations; }
/** Gets a collection of invisible annotations.
* @return A collection of invisible annotations.*/
AnnotationTable* get_invisible_annotations() const {
return m_invisible_annotations;
}
/** Gets a class instance size.
* @return A size of the allocated instance in bytes.*/
unsigned int get_allocated_size() const { return m_allocated_size; }
unsigned int get_instance_data_size() const {
return m_instance_data_size & NEXT_TO_HIGH_BIT_CLEAR_MASK;
}
/** Gets the array-alement size.
* @return A size of the array element.
* @note The given function assumes that the class is an array class.*/
unsigned int get_array_element_size() const {
assert(m_is_array == 1);
return m_array_element_size;
}
/** Gets the class ID.*/
unsigned get_id() const { return m_id; }
/** Gets major version of class file.
* @return Major version of class file.*/
uint16 get_version() const { return m_version; }
/** Gets access and properties flags of the given class.
* @return The 16-bit integer representing access and properties flags
* the given class.*/
uint16 get_access_flags() const { return m_access_flags; }
/** Checks whether the given class represents the primitive type.
* @return <code>true</code> if the class is primitive; otherwise
* <code>false</code>.*/
bool is_primitive() const { return m_is_primitive == 1; }
/** Checks whether the given class represents an array.
* @return <code>true</code> if the given class is an array, otherwise
* <code>false</code>.*/
bool is_array() const { return m_is_array == 1; }
/** Checks whether the base class of the given array is primitive.
* @return <code>true</code> if the base class is primitive, otherwise
* <code>false</code>.*/
bool is_array_of_primitives() const { return m_is_array_of_primitives == 1; }
/** Checks whether the class has the <code>ACC_PUBLIC</code> flag set.
* @return <code>true</code> if the class has the <code>ACC_PUBLIC</code>
* access flag set.*/
bool is_public() const { return (m_access_flags & ACC_PUBLIC) != 0; }
/** Checks whether the class has the <code>ACC_PUBLIC</code> flag set.
* @return <code>true</code> if the class has the <code>ACC_PUBLIC</code>
* access flag set.*/
bool is_private() const { return (m_access_flags & ACC_PRIVATE) != 0; }
/** Checks whether the class has the <code>ACC_PUBLIC</code> flag set.
* @return <code>true</code> if the class has the <code>ACC_PUBLIC</code>
* access flag set.*/
bool is_protected() const { return (m_access_flags & ACC_PROTECTED) != 0; }
/** Checks whether the class has the <code>ACC_FINAL</code> flag set.
* @return <code>true</code> if the class has the <code>ACC_FINAL</code>
* access flag set.*/
bool is_final() const { return (m_access_flags & ACC_FINAL) != 0; }
/** Checks whether the class has the <code>ACC_SUPER</code> flag set.
* @return <code>true</code> if the class has the <code>ACC_SUPER</code>
* access flag set.*/
bool is_super() const { return (m_access_flags & ACC_SUPER) != 0; }
/** Checks whether the class has the <code>ACC_INTERFACE</code> flag set.
* @return <code>true</code> if the class has the <code>ACC_INTERFACE</code>
* access flag set.*/
bool is_interface() const { return (m_access_flags & ACC_INTERFACE) != 0; }
/** Checks whether the class has the <code>ACC_ABSTRACT</code> flag set.
* @return <code>true</code> if the class has the <code>ACC_ABSTRACT</code>
* access flag set.*/
bool is_abstract() const { return (m_access_flags & ACC_ABSTRACT) != 0; }
/** Checks whether the class is enum, that is the <code>ACC_ENUM</code>
* flag is set.
* @return <code>true</code> if the class is enum.*/
bool is_enum() const { return (m_access_flags & ACC_ENUM) != 0; }
/** Checks whether the class has the <code>ACC_SYNTHETIC</code> flag set.
* @return <code>true</code> if the class has the <code>ACC_SYNTHETIC</code>
* access flag set.*/
bool is_synthetic() const { return (m_access_flags & ACC_SYNTHETIC) != 0; }
/** Checks whether the class is an annotation.
* @return <code>true</code> if the class is an annotation.*/
bool is_annotation() const { return (m_access_flags & ACC_ANNOTATION) != 0; }
/** Checks whether the given class has a finalizer.
* @return <code>true</code> if the given class (or its super class) has
* a finalize method; otherwise <code>false</code>.*/
bool has_finalizer() const { return m_has_finalizer == 1; }
/** Checks whether the given class is an inner class of some other class.
* @return <code>true</code> if the given class is an inner class of some
* other class, otherwise <code>false</code>.*/
bool is_inner_class() const { return m_declaring_class_index != 0; }
/** Checks whether the given class can access <code>inner_class</code>.
* @param[in] env - VM environment
* @param[in] inner_class - an inner class to check access to
* @return <code>true</code> if the given class has access to the inner
* class; otherwise <code>false</code>.*/
bool can_access_inner_class(Global_Env* env, Class* inner_class);
/** Checks whether the given class can access a member class.
* @param[in] member - a class member to check access to
* @return <code>true</code> if the given class can access a member class;
* otherwise <code>false</code>.*/
bool can_access_member(Class_Member* member);
/** Checks whether the given class has a source-file name available.
* @return <code>true</code> if source file name is available for the given class;
* otherwise <code>false</code>.*/
bool has_source_information() const { return m_src_file_name != NULL; }
/** Checks whether the given class is in the process of initialization.
* @return <code>true</code> if the class initialization method is executed;
* otherwise <code>false</code>.*/
bool is_initializing() const { return m_state == ST_Initializing; }
/** Checks whether the class is initialized.
* @return <code>true</code> if the class is initialized;
* otherwise <code>false</code>.*/
bool is_initialized() const { return m_state == ST_Initialized; }
/** Checks whether the class is in the error state.
* @return <code>true</code> if the class is in the error state;
* otherwise <code>false</code>.*/
bool in_error() const { return m_state == ST_Error; }
/** Checks whether the given class has a passed preparation stage.
* @return <code>true</code> if the class has a passed preparation stage;
* otherwise <code>false</code>.*/
bool is_at_least_prepared() const {
return m_state == ST_Prepared
|| m_state == ST_ConstraintsVerified
|| m_state == ST_Initializing
|| m_state == ST_Initialized;
}
/** Checks whether the given class represents a class that is a subtype of
* <code>clss</code>, according to the Java instance of rules.
* @param[in] clss - a class to check for being super relative
* @return <code>true</code> if the given class represents a class that is
* a subtype of <code>clss</code>, otherwise <code>false</code>.*/
bool is_instanceof(Class* clss);
/** FIXME: all setter functions must be rethought to become private
* or to be removed altogether, if possible.
* Sets the name of a file from which the given class has been loaded.
* @param[in] cf_name - a class-file name*/
void set_class_file_name(const char* cf_name) {
assert(cf_name);
m_class_file_name = cf_name;
}
/** Sets instance data size constraint bit to let the allocation know
* there are constraints on the way instance should be allocated.
* @note Constaints are recorded in the <code>class_properties</code>
* field of the class <code>VTable</code>.*/
void set_instance_data_size_constraint_bit() {
m_instance_data_size |= NEXT_TO_HIGH_BIT_SET_MASK;
}
/** Sets a class handle of <code>java.lang.Class</code> for the given class.
* @param[in] oh - a class handle of <code>java.lang.Class</code>*/
void set_class_handle(ManagedObject** oh) { m_class_handle = oh; }
/** Constructs internal representation of a class from the byte array
* (defines class).
* @param[in] env - VM environment
* @param[in] cfs - a class-file stream; byte array contaning class data*/
bool parse(Global_Env* env, ByteReader& cfs);
/** Loads a super class and super interfaces of the given class.
* The given class's class loader is used for it.
* @param[in] env - VM environment*/
bool load_ancestors(Global_Env* env);
/** Verifies bytecodes of the class.
* @param[in] env - VM environment
* @return <code>true</code> if bytecodes of a class were successfully verified;
* otherwise <code>false</code>.*/
bool verify(const Global_Env* env);
/** Verifies constraints for the given class collected during the bytecodes
* verification.
* @param[in] env - VM environment
* @return <code>true</code> if constraints successfully pass verification;
* otherwise <code>false</code>.*/
bool verify_constraints(const Global_Env* env);
/** Setups the given class as representing a primitive type.
* @param[in] cl - a class loader the given class belongs to
* @note FIXME: <code>cl</code> is always a bootstrap class loader
* for primitive types. Retrieve the bootstrap class loader
* from VM environment here, not one level up the calling stack.*/
void setup_as_primitive(ClassLoader* cl) {
m_is_primitive = 1;
m_class_loader = cl;
m_access_flags = ACC_ABSTRACT | ACC_FINAL | ACC_PUBLIC;
m_state = ST_Initialized;
}
/** Sets up the given class as representing an array.
* @param[in] env - VM environment
* @param[in] num_dimentions - a number of dimentions this array has
* @param[in] isArrayOfPrimitives - does this array is an array of primitives
* @param[in] baseClass - base class of this array; for example,
* for <code>[[[Ljava/lang/String;</code>
* base class is <code>java/lang/String</code>
* @param[in] elementClass - class representing element of this array;
* for example, for <code>[[I</code>, element
* the class is <code>[I</code>
* @note For single-dimentional arrays <code>baseClass<code> and
* <code>elementClass</code> are the same.*/
void setup_as_array(Global_Env* env, unsigned char num_dimensions,
bool isArrayOfPrimitives, Class* baseClass, Class* elementClass);
/** Prepares a class: <ol>
* <li> assigns offsets:
* - the offset of instance data fields
* - virtual methods in a vtable
* - static data fields in a static data block</li>
* <li> creates a class vtable</li>
* <li> creates a static field block</li>
* <li> creates a static method block </ol>
* @param[in] env - vm environment
* @return <code>true</code> if the class was successfully prepared;
* otherwise <code>false</code>.*/
bool prepare(Global_Env* env);
/** Resolves a constant-pool entry to a class. Loads a class if neccessary.
* @param[in] env - VM environment
* @param[in] cp_index - a constant-pool index of <code>CONSTANT_Class</code>
* to resolve
* @return A resolved class, if a resolution attempt succeeds;
* otherwise <code>NULL</code>.
* @note Should become private as soon as wrappers become members of the
* struct #Class.*/
Class* _resolve_class(Global_Env* env, unsigned cp_index);
/** Resolves a declaring class.
* @return A declaring class, if the given class is inner class of some
* other class and if the resolution was successful;
* otherwise <code>NULL</code>.*/
Class* resolve_declaring_class(Global_Env* env);
/** Resolves a field in the constant pool of the given class.
* @param[in] env - VM environment
* @param[in] cp_index - an index of an entry in the constant pool,
* which describes field to be resolved
* @return A resolved field, if a resolution attempt succeeds;
* otherwise <code>NULL</code>.
* @note Should become private as soon as wrappers
* become members of the struct #Class.*/
Field* _resolve_field(Global_Env* env, unsigned cp_index);
/** Resolves a method in the constant pool of the given class.
* @param[in] env - VM environment
* @param[in] cp_index - an index of an entry in the constant pool,
* which describes method to be resolved
* @return A resolved method, if a resolution attempt succeeds;
* otherwise <code>NULL</code>.
* @note Should become private as soon as wrappers become members of
* the struct #Class.*/
Method* _resolve_method(Global_Env* env, unsigned cp_index);
/** Initializes the class.
* @param[in] throw_exception - defines whether the exception should
* be thrown or raised
* @note The given method may raise exception, if an error occurs during
* the initialization of the class.*/
void initialize();
/** Looks up the field with specified name and descriptor in the given class only.
* @param[in] name - the field name to look up for
* @param[in] desc - the field descriptor to look up for
* @return The looked up field if found in the given class,
* otherwise <code>NULL</code>.*/
Field* lookup_field(const String* name, const String* descriptor);
/** Looks up the field with specified name and descriptor in the given class
* and also in the super class and super-interfaces recursively.
* @param[in] name - field name to look up for
* @param[in] desc - field descriptor to look up for
* @return The looked up field if found, <code>NULL</code> otherwise*/
Field* lookup_field_recursive(const String* name, const String* descriptor);
/** Looks up a method with a specified name and descriptor in the given
* class only.
* @param[in] name - a method name to look up for
* @param[in] desc - a method descriptor to look up for
* @return The looked-up method, if found in the given class;
* otherwise <code>NULL</code>.*/
Method* lookup_method(const String* name, const String* desc);
/** Allocates an instance of the given class and returns a pointer to it.
* @return A managed pointer to the allocated class instance;
* <code>NULL</code>, if no memory is available and
* <code>OutOfMemoryError</code> exception is raised on a
* caller thread.*/
ManagedObject* allocate_instance();
/**
* Calculates a size of the block allocated for the array, which is represented by
* the given class.
* @param[in] length the length of the array
* @return The size of the array of specified length in bytes, or 0 if the size is too big.
*/
unsigned calculate_array_size(int length) const {
if (length < 0) {
return 0;
}
assert(m_array_element_size);
assert(length >= 0);
assert(is_array());
unsigned first_elem_offset;
if(m_array_element_shift < 3) {
first_elem_offset = VM_VECTOR_FIRST_ELEM_OFFSET_1_2_4;
} else {
first_elem_offset = VM_VECTOR_FIRST_ELEM_OFFSET_8;
}
// check overflow, we need:
// first_elem_offset + (length << m_array_element_shift)
// + GC_OBJECT_ALIGNMENT < NEXT_TO_HIGH_BIT_SET_MASK
//
if (((NEXT_TO_HIGH_BIT_SET_MASK - GC_OBJECT_ALIGNMENT - first_elem_offset)
>> m_array_element_shift) <= (unsigned)length) {
// zero means overflow
return 0;
}
unsigned size = first_elem_offset + (length << m_array_element_shift);
size = (((size + (GC_OBJECT_ALIGNMENT - 1)) & (~(GC_OBJECT_ALIGNMENT - 1))));
assert((size % GC_OBJECT_ALIGNMENT) == 0);
assert((size & NEXT_TO_HIGH_BIT_SET_MASK) == 0);
return size;
}
/** Estimates the amount of memory allocated for C++ part of the given class.
* @return The size of memory allocated for the given class.*/
unsigned calculate_size();
/** Gets the interface vtable for interface <code>iid</code> within
* object <code>obj</code>.
* @param[in] obj - an object to retrieve an interface table entry from
* @param[in] iid - an interface class to retrieve vtable for
* @return An interface vtable from object; <code>NULL</code>, if no
* such interface exists for the object.*/
static void* helper_get_interface_vtable(ManagedObject* obj, Class* iid);
// SourceDebugExtension class attribute support
/** Checks whether the given class has the
* <code>SourceDebugExtension</code> attribute.
* @return <code>true</code> if the <code>SourceDebugExtension</code>
* attribute is available for the given class;
* otherwise <code>false</code>.*/
bool has_source_debug_extension() const {
return m_sourceDebugExtension != NULL;
}
/** Gets length of the <code>SourceDebugExtension</code> attribute.
* @return The <code>SourceDebugExtension</code> attribute length.*/
unsigned get_source_debug_extension_length() const {
return m_sourceDebugExtension->len;
}
/** Gets data from the <code>SourceDebugExtension</code> attribute.
* @return <code>SourceDebugExtension</code> attribute bytes.*/
const char* get_source_debug_extension() const {
return m_sourceDebugExtension->bytes;
}
/** Stores a verifier specific pointer into the given class.
* @param[in] data - a verifier specific data pointer*/
void set_verification_data(void* data) {
assert(m_verify_data == NULL);
m_verify_data = data;
}
/** Gets a pointer to verifier specific data, previously stored with
* the call to <code>set_verification_data</code>.
* @return A pointer to verifier specific data or <code>NULL</code>, if
* none was set.*/
void* get_verification_data() {
return m_verify_data;
}
/** Locks access to the given class.*/
void lock();
/** Unlocks access to the given class.*/
void unlock();
// Statistics update
/** Updates allocation statistics.
* @param[in] size - a size of an allocated instance*/
void instance_allocated(unsigned size) {
m_num_allocations++;
m_num_bytes_allocated += size;
}
/** Updates an instance of slow path statistics.*/
void instanceof_slow_path_taken() { m_num_instanceof_slow++; }
/** Updates throwing statistics for <code>java/lang/Throwable</code> decendants.*/
void class_thrown() { m_num_throws++; }
/** Allocates memory for code from pool of defining classloader for the class.*/
void* code_alloc(size_t size, size_t alignment, Code_Allocation_Action action);
/** Updates initialization check statistics.*/
void initialization_checked() { m_num_class_init_checks++; }
/** Gets the number of times instance of the given class was allocated.
* @return The number of allocations of the given class.*/
uint64 get_times_allocated() const { return m_num_allocations; }
/** Gets the total number of bytes allocated for instances of the given class.
* @return The number of bytes allocated for all instances of the given class.*/
uint64 get_total_bytes_allocated() const { return m_num_bytes_allocated; }
/** Gets the number of times the slow path of the check instance was taken.
* @return The number of times the slow path was taken.*/
uint64 get_times_instanceof_slow_path_taken() const { return m_num_instanceof_slow; }
/** Gets the number of times the given class was thrown.
* @return The number of times the given class was thrown.*/
uint64 get_times_thrown() const { return m_num_throws; }
/** Gets the number of times the initialization of the given class
* was checked by run-time helpers.
* @return The number of times initialization of the given class was checked.*/
uint64 get_times_init_checked() const { return m_num_class_init_checks; }
/** Gets the number of excessive bytes used for aligning class fields.
* @return A number of excessive bytes used for aligning class fields.*/
uint64 get_total_padding_bytes() const { return m_num_field_padding_bytes; }
private:
/** Parses super-interfaces information from a class-file stream.
* @param[in] cfs - a class-file stream to parse superinterfaces information from
* @return <code>true</code> if information was succesfully parsed;
* otherwise <code>false</code>.*/
bool parse_interfaces(ByteReader &cfs);
/** Parses class fields from a class-file stream.
* @param[in] env - VM enviroment
* @param[in] cfs - a class-file stream
* @param[in] is_trusted_cl - defines whether class was loaded by
* trusted classloader. User defined classloaders are not trusted.
* @return <code>true</code> if successfully parses fields; <code>false</code>
* if any parse error occurs.*/
bool parse_fields(Global_Env* env, ByteReader &cfs, bool is_trusted_cl);
/** Parses class methods from a class-file stream.
* @param[in] env - VM enviroment
* @param[in] cfs - a class file stream
* @param[in] is_trusted_cl - defines whether class was loaded by
* trusted classloader. User defined classloaders are not trusted.
* @return <code>true</code> if successfully parses methods; <code>false</code>
* if any parse error occurs.*/
bool parse_methods(Global_Env* env, ByteReader &cfs, bool is_trusted_cl);
/** Calculates and assigns offsets to class fields during preparation.*/
void assign_offsets_to_fields();
/** Assign offsets to class-instance fields.
* @param[in] field_ptrs - an array of class fields to assign
* offsets to
* @param[in] do_field_compaction - defines whether the class fields should
* be compacted*/
void assign_offsets_to_instance_fields(Field** field_ptrs, bool do_field_compaction);
/** Assigns an offset to an instance field.
* @param[in] field - a field to calculate offset for
* @param[in] do_field_compaction - defines whether the class fields should
* be compacted*/
void assign_offset_to_instance_field(Field* field, bool do_field_compaction);
/** Assigns offsets to static fields of a class.
* @param[in] field_ptrs - an array of fields
* @param[in] do_field_compaction - defines whether the class fields should
* be compacted*/
void assign_offsets_to_static_fields(Field** field_ptrs, bool do_field_compaction);
/** Initializes an interface class.
* @return <code>true</code> if the interface was successfully initialized;
* otherwise <code>false</code>.*/
bool initialize_static_fields_for_interface();
/** Assigns offsets (from the base of the vtable) and the <code>VTable</code> index to
* class methods.
* @param[in] env - VM environment*/
void assign_offsets_to_methods(Global_Env* env);
/** Creates the vtable for the given class.
* @param[in] n_vtable_entries - a number of entries for the vtable*/
void create_vtable(unsigned n_vtable_entries);
/** Populates the vtable descriptors table with methods overriding as necessary.
* @param[in] intfc_table_entries - must contain all interfaces of the given class
*/
void populate_vtable_descriptors_table_and_override_methods(const std::vector<Class*>& intfc_table_entries);
/** Creates and populates an interface table for a class.
* @param[in] intfc_table_entries - must contain all interfaces of the given class
* @return The created interface table.*/
Intfc_Table* create_and_populate_interface_table(const std::vector<Class*>& intfc_table_entries);
/** Sets vtable entries to methods addresses.*/
void point_vtable_entries_to_stubs();
/** Adds any required "fake" methods to a class. These are interface methods
* inherited by an abstract class that are not implemented by that class
* or any superclass. Such methods will never be called, but they are added
* so they have the correct offset in the virtual method part of the vtable
* (that is the offset of the "real" method in the vtable for a concrete class).*/
void add_any_fake_methods();
}; // struct Class
} // extern "C"
/** Gets instance of java/lang/Class associated with this class.
* @param[in] clss - class to retrieve java/lang/Class instance for.
* @return Instance of java/lang/Class associated with class.*/
ManagedObject* struct_Class_to_java_lang_Class(Class* clss);
/** Gets handle of java/lang/Class instance associated with this class.
* @param[in] clss - class to retrieve handle with java/lang/Class instance for.
* @return Handle with instance of java/lang/Class associated with class.
* @note This function allocates local handle and stores reference to
* java/lang/Class into it.*/
jclass struct_Class_to_jclass(Class* clss);
/** Gets native class from the java/lang/Class handle.
* @param[in] jc - handle to retrieve struct Class from.
* @return Class for the given handle.*/
Class* jclass_to_struct_Class(jclass jc);
/** Gets native class for any given object handle.
* @param[in] jobj - object to retrieve class for.
* @return Class for the given object handle.*/
Class* jobject_to_struct_Class(jobject jobj);
/** Gets pointer to instance of java/lang/Class associated with the class.
* @param[in] clss - class to retrieve pointer to instance of java/lang/Class for.
* @return Pointer to instance of java/lang/Class associated with the class.
* @note This is NOT real handle, so, when using this function, make sure the
* returned value will never be passed to ANY user code including JVMTI
* agent callbacks.*/
jobject struct_Class_to_java_lang_Class_Handle(Class* clss);
/** Gets native class from instance of java/lang/Class.
* @param[in] jlc - instance of java/lang/Class to retrieve class from.
* @return Native class from instance of java/lang/Class.*/
Class* java_lang_Class_to_struct_Class(ManagedObject* jlc);
/** Looks up field in class and its superclasses.
* @param[in] clss - class to lookup field in.
* @param[in] name - name of the field.
* @param[in] desc - descriptor of the field.
* @return Requested field, if the field exists, <code>NULL</code> otherwise.*/
Field* class_lookup_field_recursive(Class* clss, const char* name, const char* desc);
/** Looks up method in class and its superclasses.
* @param[in] clss - class to lookup method in.
* @param[in] name - name of the method as VM String.
* @param[in] desc - descriptor of the method as VM String.
* @return Requested method, if the method exists,
* <code>NULL</code> otherwise.
* @note VMEXPORT specifier is solely for interpreter.*/
VMEXPORT
Method* class_lookup_method_recursive(Class* clss, const String* name, const String* desc);
/** Looks up method in class and its superclasses.
* @param[in] clss - class to lookup method in.
* @param[in] name - name of the method.
* @param[in] desc - descriptor of the method.
* @return Requested method, if the method exists,
* <code>NULL</code> otherwise.*/
Method* class_lookup_method_recursive(Class* clss, const char* name, const char* desc);
/** Looks up method in the given class only.
* @param[in] clss - class to lookup method in.
* @param[in] name - name of the method.
* @param[in] desc - descriptor of the method.
* @return Requested method, if the method exists,
* <code>NULL</code> otherwise.*/
Method* class_lookup_method(Class* clss, const char* name, const char* desc);
/** Gets method given its offset in the vtable.
* @param[in] vt - vtable containing method.
* @param[in] offset - offset of the method in the vtable.
* @return Method at the specified offset.*/
Method* class_get_method_from_vt_offset(VTable* vt, unsigned offset);
/** Loads a class and performs the first two parts of the link process:
* verify and prepare.
* @param[in] env - VM environment.
* @param[in] classname - name of a class to load.
* @param[in] cl - class loader to load class with.
* @return Loaded class, if loading and linking succeeded,
* <code>NULL</code> otherwise.*/
Class* class_load_verify_prepare_by_loader_jni(Global_Env* env,
const String* classname,
ClassLoader* cl);
/** Loads a class with bootstrap class loader and performs the first two parts
* of the link process: verify and prepare.
* @param[in] env - VM environment.
* @param[in] classname - name of a class to load.
* @param[in] cl - class loader to load class with.
* @return Loaded class, if loading and linking succeeded,
* <code>NULL</code> otherwise.
* @note The class is loaded .*/
Class* class_load_verify_prepare_from_jni(Global_Env* env,
const String* classname);
/** Executes static initializer of class.
* @param[in] clss - class to initialize.*/
void class_initialize_from_jni(Class *clss);
/** Registers a number of native methods to a given class.
* @param[in] klass - a specified class
* @param[in] methods - an array of methods
* @param[in] num_methods - a number of methods
* @return <code>false</code>, if methods resistration is successful;
* otherwise <code>true</code>.
* @note Function raises <code>NoSuchMethodError</code> with the method name in
* exception message, if one of the methods in the <code>JNINativeMethod*</code>
* array is not present in a specified class.*/
bool
class_register_methods(Class_Handle klass, const JNINativeMethod* methods, int num_methods);
/** Unregisters a native methods off a given class.
* @param[in] klass - specified class
* @return <code>false</code>, if methods unresistration is successful;
* otherwise <code>true</code>.*/
bool
class_unregister_methods(Class_Handle klass);
//method is defined in Resolve.cpp
Class* resolve_class_new_env(Global_Env* env, Class* clss, unsigned cp_index, bool raise_exn);
Method* resolve_special_method_env(Global_Env *env, Class_Handle curr_clss, unsigned index, bool raise_exn);
Method* resolve_static_method_env(Global_Env *env, Class *clss, unsigned cp_index, bool raise_exn);
Method* resolve_virtual_method_env(Global_Env *env, Class *clss, unsigned cp_index, bool raise_exn);
Method* resolve_interface_method_env(Global_Env *env, Class *clss, unsigned cp_index, bool raise_exn);
Field* resolve_static_field_env(Global_Env *env, Class *clss, unsigned cp_index, bool putfield, bool is_runtume);
Field* resolve_nonstatic_field_env(Global_Env* env, Class* clss, unsigned cp_index, unsigned putfield, bool raise_exn);
#endif // _CLASS_H_