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_