duke@435: /* jiangli@3826: * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #ifndef SHARE_VM_OOPS_CONSTMETHODOOP_HPP stefank@2314: #define SHARE_VM_OOPS_CONSTMETHODOOP_HPP stefank@2314: stefank@2314: #include "oops/oop.hpp" stefank@2314: coleenp@4037: // An ConstMethod* represents portions of a Java method which duke@435: // do not vary. duke@435: // duke@435: // Memory layout (each line represents a word). Note that most duke@435: // applications load thousands of methods, so keeping the size of this duke@435: // structure small has a big impact on footprint. duke@435: // duke@435: // |------------------------------------------------------| duke@435: // | header | duke@435: // | klass | duke@435: // |------------------------------------------------------| duke@435: // | fingerprint 1 | duke@435: // | fingerprint 2 | jiangli@3826: // | constants (oop) | duke@435: // | stackmap_data (oop) | duke@435: // | constMethod_size | duke@435: // | interp_kind | flags | code_size | duke@435: // | name index | signature index | duke@435: // | method_idnum | generic_signature_index | duke@435: // |------------------------------------------------------| duke@435: // | | duke@435: // | byte codes | duke@435: // | | duke@435: // |------------------------------------------------------| duke@435: // | compressed linenumber table | duke@435: // | (see class CompressedLineNumberReadStream) | duke@435: // | (note that length is unknown until decompressed) | duke@435: // | (access flags bit tells whether table is present) | coleenp@4037: // | (indexed from start of ConstMethod*) | duke@435: // | (elements not necessarily sorted!) | duke@435: // |------------------------------------------------------| duke@435: // | localvariable table elements + length (length last) | duke@435: // | (length is u2, elements are 6-tuples of u2) | duke@435: // | (see class LocalVariableTableElement) | duke@435: // | (access flags bit tells whether table is present) | coleenp@4037: // | (indexed from end of ConstMethod*) | jiangli@3917: // |------------------------------------------------------| jiangli@3917: // | exception table + length (length last) | jiangli@3917: // | (length is u2, elements are 4-tuples of u2) | jiangli@3917: // | (see class ExceptionTableElement) | jiangli@3917: // | (access flags bit tells whether table is present) | coleenp@4037: // | (indexed from end of ConstMethod*) | duke@435: // |------------------------------------------------------| duke@435: // | checked exceptions elements + length (length last) | duke@435: // | (length is u2, elements are u2) | duke@435: // | (see class CheckedExceptionElement) | duke@435: // | (access flags bit tells whether table is present) | coleenp@4037: // | (indexed from end of ConstMethod*) | duke@435: // |------------------------------------------------------| duke@435: duke@435: coleenp@4037: // Utitily class decribing elements in checked exceptions table inlined in Method*. duke@435: class CheckedExceptionElement VALUE_OBJ_CLASS_SPEC { duke@435: public: duke@435: u2 class_cp_index; duke@435: }; duke@435: duke@435: coleenp@4037: // Utitily class decribing elements in local variable table inlined in Method*. duke@435: class LocalVariableTableElement VALUE_OBJ_CLASS_SPEC { duke@435: public: duke@435: u2 start_bci; duke@435: u2 length; duke@435: u2 name_cp_index; duke@435: u2 descriptor_cp_index; duke@435: u2 signature_cp_index; duke@435: u2 slot; duke@435: }; duke@435: jiangli@3917: // Utitily class describing elements in exception table jiangli@3917: class ExceptionTableElement VALUE_OBJ_CLASS_SPEC { jiangli@3917: public: jiangli@3917: u2 start_pc; jiangli@3917: u2 end_pc; jiangli@3917: u2 handler_pc; jiangli@3917: u2 catch_type_index; jiangli@3917: }; jiangli@3917: coleenp@4037: coleenp@4037: class ConstMethod : public MetaspaceObj { duke@435: friend class VMStructs; kamg@4245: kamg@4245: public: kamg@4245: typedef enum { NORMAL, OVERPASS } MethodType; kamg@4245: duke@435: private: duke@435: enum { duke@435: _has_linenumber_table = 1, duke@435: _has_checked_exceptions = 2, jiangli@3917: _has_localvariable_table = 4, kamg@4245: _has_exception_table = 8, kamg@4245: _is_overpass = 16 duke@435: }; duke@435: duke@435: // Bit vector of signature duke@435: // Callers interpret 0=not initialized yet and duke@435: // -1=too many args to fix, must parse the slow way. duke@435: // The real initial value is special to account for nonatomicity of 64 bit duke@435: // loads and stores. This value may updated and read without a lock by duke@435: // multiple threads, so is volatile. duke@435: volatile uint64_t _fingerprint; duke@435: coleenp@4037: ConstantPool* _constants; // Constant pool duke@435: duke@435: // Raw stackmap data for the method coleenp@4037: Array* _stackmap_data; duke@435: duke@435: int _constMethod_size; duke@435: jbyte _interpreter_kind; duke@435: jbyte _flags; duke@435: coleenp@4037: // Size of Java bytecodes allocated immediately after Method*. duke@435: u2 _code_size; duke@435: u2 _name_index; // Method name (index in constant pool) duke@435: u2 _signature_index; // Method signature (index in constant pool) duke@435: u2 _method_idnum; // unique identification number for the method within the class duke@435: // initially corresponds to the index into the methods array. duke@435: // but this may change with redefinition duke@435: u2 _generic_signature_index; // Generic signature (index in constant pool, 0 if absent) duke@435: coleenp@4037: coleenp@4037: // Constructor coleenp@4037: ConstMethod(int byte_code_size, kamg@4245: int compressed_line_number_size, kamg@4245: int localvariable_table_length, kamg@4245: int exception_table_length, kamg@4245: int checked_exceptions_length, kamg@4245: MethodType is_overpass, kamg@4245: int size); duke@435: public: kamg@4245: coleenp@4037: static ConstMethod* allocate(ClassLoaderData* loader_data, kamg@4245: int byte_code_size, kamg@4245: int compressed_line_number_size, kamg@4245: int localvariable_table_length, kamg@4245: int exception_table_length, kamg@4245: int checked_exceptions_length, kamg@4245: MethodType mt, kamg@4245: TRAPS); coleenp@4037: coleenp@4037: bool is_constMethod() const { return true; } coleenp@4037: duke@435: // Inlined tables duke@435: void set_inlined_tables_length(int checked_exceptions_len, duke@435: int compressed_line_number_size, jiangli@3917: int localvariable_table_len, jiangli@3917: int exception_table_len); duke@435: duke@435: bool has_linenumber_table() const duke@435: { return (_flags & _has_linenumber_table) != 0; } duke@435: duke@435: bool has_checked_exceptions() const duke@435: { return (_flags & _has_checked_exceptions) != 0; } duke@435: duke@435: bool has_localvariable_table() const duke@435: { return (_flags & _has_localvariable_table) != 0; } duke@435: jiangli@3917: bool has_exception_handler() const jiangli@3917: { return (_flags & _has_exception_table) != 0; } jiangli@3917: kamg@4245: MethodType method_type() const { kamg@4245: return ((_flags & _is_overpass) == 0) ? NORMAL : OVERPASS; kamg@4245: } kamg@4245: kamg@4245: void set_method_type(MethodType mt) { kamg@4245: if (mt == NORMAL) { kamg@4245: _flags &= ~(_is_overpass); kamg@4245: } else { kamg@4245: _flags |= _is_overpass; kamg@4245: } kamg@4245: } kamg@4245: kamg@4245: duke@435: void set_interpreter_kind(int kind) { _interpreter_kind = kind; } duke@435: int interpreter_kind(void) const { return _interpreter_kind; } duke@435: jiangli@3826: // constant pool coleenp@4037: ConstantPool* constants() const { return _constants; } coleenp@4037: void set_constants(ConstantPool* c) { _constants = c; } duke@435: coleenp@4037: Method* method() const; duke@435: duke@435: // stackmap table data coleenp@4037: Array* stackmap_data() const { return _stackmap_data; } coleenp@4037: void set_stackmap_data(Array* sd) { _stackmap_data = sd; } duke@435: bool has_stackmap_table() const { return _stackmap_data != NULL; } duke@435: duke@435: void init_fingerprint() { duke@435: const uint64_t initval = CONST64(0x8000000000000000); duke@435: _fingerprint = initval; duke@435: } duke@435: duke@435: uint64_t fingerprint() const { duke@435: // Since reads aren't atomic for 64 bits, if any of the high or low order duke@435: // word is the initial value, return 0. See init_fingerprint for initval. duke@435: uint high_fp = (uint)(_fingerprint >> 32); duke@435: if ((int) _fingerprint == 0 || high_fp == 0x80000000) { duke@435: return 0L; duke@435: } else { duke@435: return _fingerprint; duke@435: } duke@435: } duke@435: duke@435: uint64_t set_fingerprint(uint64_t new_fingerprint) { duke@435: #ifdef ASSERT duke@435: // Assert only valid if complete/valid 64 bit _fingerprint value is read. duke@435: uint64_t oldfp = fingerprint(); duke@435: #endif // ASSERT duke@435: _fingerprint = new_fingerprint; duke@435: assert(oldfp == 0L || new_fingerprint == oldfp, duke@435: "fingerprint cannot change"); duke@435: assert(((new_fingerprint >> 32) != 0x80000000) && (int)new_fingerprint !=0, duke@435: "fingerprint should call init to set initial value"); duke@435: return new_fingerprint; duke@435: } duke@435: duke@435: // name duke@435: int name_index() const { return _name_index; } duke@435: void set_name_index(int index) { _name_index = index; } duke@435: duke@435: // signature duke@435: int signature_index() const { return _signature_index; } duke@435: void set_signature_index(int index) { _signature_index = index; } duke@435: duke@435: // generics support duke@435: int generic_signature_index() const { return _generic_signature_index; } duke@435: void set_generic_signature_index(int index) { _generic_signature_index = index; } duke@435: duke@435: // Sizing duke@435: static int header_size() { coleenp@4037: return sizeof(ConstMethod)/HeapWordSize; duke@435: } duke@435: coleenp@4037: // Size needed coleenp@4037: static int size(int code_size, int compressed_line_number_size, duke@435: int local_variable_table_length, jiangli@3917: int exception_table_length, duke@435: int checked_exceptions_length); duke@435: coleenp@4037: int size() const { return _constMethod_size;} duke@435: void set_constMethod_size(int size) { _constMethod_size = size; } duke@435: duke@435: // code size duke@435: int code_size() const { return _code_size; } duke@435: void set_code_size(int size) { duke@435: assert(max_method_code_size < (1 << 16), duke@435: "u2 is too small to hold method code size in general"); duke@435: assert(0 <= size && size <= max_method_code_size, "invalid code size"); duke@435: _code_size = size; duke@435: } duke@435: duke@435: // linenumber table - note that length is unknown until decompression, duke@435: // see class CompressedLineNumberReadStream. duke@435: u_char* compressed_linenumber_table() const; // not preserved by gc duke@435: u2* checked_exceptions_length_addr() const; duke@435: u2* localvariable_table_length_addr() const; jiangli@3917: u2* exception_table_length_addr() const; duke@435: duke@435: // checked exceptions duke@435: int checked_exceptions_length() const; duke@435: CheckedExceptionElement* checked_exceptions_start() const; duke@435: duke@435: // localvariable table duke@435: int localvariable_table_length() const; duke@435: LocalVariableTableElement* localvariable_table_start() const; duke@435: jiangli@3917: // exception table jiangli@3917: int exception_table_length() const; jiangli@3917: ExceptionTableElement* exception_table_start() const; jiangli@3917: duke@435: // byte codes twisti@1573: void set_code(address code) { twisti@1573: if (code_size() > 0) { twisti@1573: memcpy(code_base(), code, code_size()); twisti@1573: } twisti@1573: } duke@435: address code_base() const { return (address) (this+1); } duke@435: address code_end() const { return code_base() + code_size(); } duke@435: bool contains(address bcp) const { return code_base() <= bcp duke@435: && bcp < code_end(); } duke@435: // Offset to bytecodes duke@435: static ByteSize codes_offset() coleenp@4037: { return in_ByteSize(sizeof(ConstMethod)); } duke@435: jiangli@3826: static ByteSize constants_offset() coleenp@4037: { return byte_offset_of(ConstMethod, _constants); } duke@435: duke@435: // Unique id for the method duke@435: static const u2 MAX_IDNUM; duke@435: static const u2 UNSET_IDNUM; duke@435: u2 method_idnum() const { return _method_idnum; } duke@435: void set_method_idnum(u2 idnum) { _method_idnum = idnum; } duke@435: coleenp@4037: // Deallocation for RedefineClasses coleenp@4037: void deallocate_contents(ClassLoaderData* loader_data); coleenp@4037: bool is_klass() const { return false; } coleenp@4037: DEBUG_ONLY(bool on_stack() { return false; }) coleenp@4037: duke@435: private: duke@435: // Since the size of the compressed line number table is unknown, the duke@435: // offsets of the other variable sized sections are computed backwards coleenp@4037: // from the end of the ConstMethod*. duke@435: coleenp@4037: // First byte after ConstMethod* duke@435: address constMethod_end() const duke@435: { return (address)((oop*)this + _constMethod_size); } duke@435: coleenp@4037: // Last short in ConstMethod* duke@435: u2* last_u2_element() const duke@435: { return (u2*)constMethod_end() - 1; } coleenp@4037: coleenp@4037: public: coleenp@4037: // Printing coleenp@4037: void print_on (outputStream* st) const; coleenp@4037: void print_value_on(outputStream* st) const; coleenp@4037: coleenp@4037: const char* internal_name() const { return "{constMethod}"; } coleenp@4037: coleenp@4037: // Verify coleenp@4037: void verify_on(outputStream* st); duke@435: }; stefank@2314: stefank@2314: #endif // SHARE_VM_OOPS_CONSTMETHODOOP_HPP