duke@435: /* acorn@4497: * Copyright (c) 2003, 2013, 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 | jiangli@4302: // | method_idnum | max_stack | jiangli@4338: // | max_locals | size_of_parameters | 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) | jiangli@4302: // | (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) | jiangli@4302: // | (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) | jiangli@4302: // | (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) | jiangli@4302: // | (indexed from end of ConstMethod*) | jiangli@4302: // |------------------------------------------------------| coleenp@4398: // | method parameters elements + length (length last) | coleenp@4398: // | (length is u2, elements are u2, u4 structures) | coleenp@4398: // | (see class MethodParametersElement) | coleenp@4398: // | (access flags bit tells whether table is present) | coleenp@4398: // | (indexed from end of ConstMethod*) | coleenp@4398: // |------------------------------------------------------| jiangli@4302: // | generic signature index (u2) | jiangli@4302: // | (indexed from start of constMethodOop) | duke@435: // |------------------------------------------------------| coleenp@4572: // | annotations arrays - method, parameter, type, default| coleenp@4572: // | pointer to Array if annotation is present | coleenp@4572: // |------------------------------------------------------| coleenp@4398: // coleenp@4398: // IMPORTANT: If anything gets added here, there need to be changes to coleenp@4398: // ensure that ServicabilityAgent doesn't get broken as a result! duke@435: duke@435: coleenp@4572: // Utility class describing 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@4572: // Utility class describing 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: coleenp@4572: // Utility 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@4398: // Utility class describing elements in method parameters coleenp@4398: class MethodParametersElement VALUE_OBJ_CLASS_SPEC { coleenp@4398: public: coleenp@4398: u2 name_cp_index; emc@4524: u2 flags; coleenp@4398: }; coleenp@4398: acorn@4497: class KlassSizeStats; coleenp@4037: coleenp@4572: // Class to collect the sizes of ConstMethod inline tables coleenp@4572: #define INLINE_TABLES_DO(do_element) \ coleenp@4572: do_element(localvariable_table_length) \ coleenp@4572: do_element(compressed_linenumber_size) \ coleenp@4572: do_element(exception_table_length) \ coleenp@4572: do_element(checked_exceptions_length) \ coleenp@4572: do_element(method_parameters_length) \ coleenp@4572: do_element(generic_signature_index) \ coleenp@4572: do_element(method_annotations_length) \ coleenp@4572: do_element(parameter_annotations_length) \ coleenp@4572: do_element(type_annotations_length) \ coleenp@4572: do_element(default_annotations_length) coleenp@4572: coleenp@4572: #define INLINE_TABLE_DECLARE(sym) int _##sym; coleenp@4572: #define INLINE_TABLE_PARAM(sym) int sym, coleenp@4572: #define INLINE_TABLE_INIT(sym) _##sym(sym), coleenp@4572: #define INLINE_TABLE_NULL(sym) _##sym(0), coleenp@4572: #define INLINE_TABLE_ACCESSOR(sym) int sym() const { return _##sym; } coleenp@4572: coleenp@4572: class InlineTableSizes : StackObj { coleenp@4572: // declarations coleenp@4572: INLINE_TABLES_DO(INLINE_TABLE_DECLARE) coleenp@4572: int _end; coleenp@4572: public: coleenp@4572: InlineTableSizes( coleenp@4572: INLINE_TABLES_DO(INLINE_TABLE_PARAM) coleenp@4572: int end) : coleenp@4572: INLINE_TABLES_DO(INLINE_TABLE_INIT) coleenp@4572: _end(end) {} coleenp@4572: coleenp@4572: // Default constructor for no inlined tables coleenp@4572: InlineTableSizes() : coleenp@4572: INLINE_TABLES_DO(INLINE_TABLE_NULL) coleenp@4572: _end(0) {} coleenp@4572: coleenp@4572: // Accessors coleenp@4572: INLINE_TABLES_DO(INLINE_TABLE_ACCESSOR) coleenp@4572: }; coleenp@4572: #undef INLINE_TABLE_ACCESSOR coleenp@4572: #undef INLINE_TABLE_NULL coleenp@4572: #undef INLINE_TABLE_INIT coleenp@4572: #undef INLINE_TABLE_PARAM coleenp@4572: #undef INLINE_TABLE_DECLARE coleenp@4572: coleenp@4572: 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 { coleenp@4572: _has_linenumber_table = 0x0001, coleenp@4572: _has_checked_exceptions = 0x0002, coleenp@4572: _has_localvariable_table = 0x0004, coleenp@4572: _has_exception_table = 0x0008, coleenp@4572: _has_generic_signature = 0x0010, coleenp@4572: _has_method_parameters = 0x0020, coleenp@4572: _is_overpass = 0x0040, coleenp@4572: _has_method_annotations = 0x0080, coleenp@4572: _has_parameter_annotations = 0x0100, coleenp@4572: _has_type_annotations = 0x0200, coleenp@4572: _has_default_annotations = 0x0400 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; coleenp@4572: u2 _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 jiangli@4302: u2 _max_stack; // Maximum number of entries on the expression stack jiangli@4338: u2 _max_locals; // Number of local variables used by this method jiangli@4338: u2 _size_of_parameters; // size of the parameter block (receiver + arguments) in words coleenp@4037: coleenp@4037: // Constructor coleenp@4037: ConstMethod(int byte_code_size, coleenp@4572: InlineTableSizes* sizes, 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, coleenp@4572: InlineTableSizes* sizes, kamg@4245: MethodType mt, kamg@4245: TRAPS); coleenp@4037: coleenp@4037: bool is_constMethod() const { return true; } coleenp@4037: duke@435: // Inlined tables coleenp@4572: void set_inlined_tables_length(InlineTableSizes* sizes); duke@435: jiangli@4302: bool has_generic_signature() const jiangli@4302: { return (_flags & _has_generic_signature) != 0; } jiangli@4302: 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: coleenp@4398: bool has_method_parameters() const coleenp@4398: { return (_flags & _has_method_parameters) != 0; } coleenp@4398: 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: 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; } coleenp@4719: void copy_stackmap_data(ClassLoaderData* loader_data, u1* sd, int length, TRAPS); 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 jiangli@4302: int generic_signature_index() const { jiangli@4302: if (has_generic_signature()) { jiangli@4302: return *generic_signature_index_addr(); jiangli@4302: } else { jiangli@4302: return 0; jiangli@4302: } jiangli@4302: } jiangli@4302: void set_generic_signature_index(u2 index) { jiangli@4302: assert(has_generic_signature(), ""); jiangli@4302: u2* addr = generic_signature_index_addr(); jiangli@4302: *addr = index; jiangli@4302: } 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@4572: static int size(int code_size, InlineTableSizes* sizes); duke@435: coleenp@4037: int size() const { return _constMethod_size;} duke@435: void set_constMethod_size(int size) { _constMethod_size = size; } acorn@4497: #if INCLUDE_SERVICES acorn@4497: void collect_statistics(KlassSizeStats *sz) const; acorn@4497: #endif 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 jiangli@4302: u2* generic_signature_index_addr() const; duke@435: u2* checked_exceptions_length_addr() const; duke@435: u2* localvariable_table_length_addr() const; jiangli@3917: u2* exception_table_length_addr() const; coleenp@4398: u2* method_parameters_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: coleenp@4398: // method parameters table coleenp@4398: int method_parameters_length() const; coleenp@4398: MethodParametersElement* method_parameters_start() const; coleenp@4398: coleenp@4572: // method annotations coleenp@4572: bool has_method_annotations() const coleenp@4572: { return (_flags & _has_method_annotations) != 0; } coleenp@4572: coleenp@4572: bool has_parameter_annotations() const coleenp@4572: { return (_flags & _has_parameter_annotations) != 0; } coleenp@4572: coleenp@4572: bool has_type_annotations() const coleenp@4572: { return (_flags & _has_type_annotations) != 0; } coleenp@4572: coleenp@4572: bool has_default_annotations() const coleenp@4572: { return (_flags & _has_default_annotations) != 0; } coleenp@4572: coleenp@4572: coleenp@4572: AnnotationArray** method_annotations_addr() const; coleenp@4572: AnnotationArray* method_annotations() const { coleenp@4572: return has_method_annotations() ? *(method_annotations_addr()) : NULL; coleenp@4572: } coleenp@4572: void set_method_annotations(AnnotationArray* anno) { coleenp@4572: *(method_annotations_addr()) = anno; coleenp@4572: } coleenp@4572: coleenp@4572: AnnotationArray** parameter_annotations_addr() const; coleenp@4572: AnnotationArray* parameter_annotations() const { coleenp@4572: return has_parameter_annotations() ? *(parameter_annotations_addr()) : NULL; coleenp@4572: } coleenp@4572: void set_parameter_annotations(AnnotationArray* anno) { coleenp@4572: *(parameter_annotations_addr()) = anno; coleenp@4572: } coleenp@4572: coleenp@4572: AnnotationArray** type_annotations_addr() const; coleenp@4572: AnnotationArray* type_annotations() const { coleenp@4572: return has_type_annotations() ? *(type_annotations_addr()) : NULL; coleenp@4572: } coleenp@4572: void set_type_annotations(AnnotationArray* anno) { coleenp@4572: *(type_annotations_addr()) = anno; coleenp@4572: } coleenp@4572: coleenp@4572: AnnotationArray** default_annotations_addr() const; coleenp@4572: AnnotationArray* default_annotations() const { coleenp@4572: return has_default_annotations() ? *(default_annotations_addr()) : NULL; coleenp@4572: } coleenp@4572: void set_default_annotations(AnnotationArray* anno) { coleenp@4572: *(default_annotations_addr()) = anno; coleenp@4572: } coleenp@4572: coleenp@4572: int method_annotations_length() const { coleenp@4572: return has_method_annotations() ? method_annotations()->length() : 0; coleenp@4572: } coleenp@4572: int parameter_annotations_length() const { coleenp@4572: return has_parameter_annotations() ? parameter_annotations()->length() : 0; coleenp@4572: } coleenp@4572: int type_annotations_length() const { coleenp@4572: return has_type_annotations() ? type_annotations()->length() : 0; coleenp@4572: } coleenp@4572: int default_annotations_length() const { coleenp@4572: return has_default_annotations() ? default_annotations()->length() : 0; coleenp@4572: } coleenp@4572: coleenp@4837: // Copy annotations from other ConstMethod coleenp@4837: void copy_annotations_from(ConstMethod* cm); coleenp@4837: 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: jiangli@4302: static ByteSize max_stack_offset() jiangli@4302: { return byte_offset_of(ConstMethod, _max_stack); } jiangli@4338: static ByteSize size_of_locals_offset() jiangli@4338: { return byte_offset_of(ConstMethod, _max_locals); } jiangli@4338: static ByteSize size_of_parameters_offset() jiangli@4338: { return byte_offset_of(ConstMethod, _size_of_parameters); } jiangli@4338: jiangli@4302: 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: jiangli@4302: // max stack jiangli@4302: int max_stack() const { return _max_stack; } jiangli@4302: void set_max_stack(int size) { _max_stack = size; } jiangli@4302: jiangli@4338: // max locals jiangli@4338: int max_locals() const { return _max_locals; } jiangli@4338: void set_max_locals(int size) { _max_locals = size; } jiangli@4338: jiangli@4338: // size of parameters jiangli@4338: int size_of_parameters() const { return _size_of_parameters; } jiangli@4338: void set_size_of_parameters(int size) { _size_of_parameters = size; } jiangli@4338: 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 coleenp@4572: { return (address)((intptr_t*)this + _constMethod_size); } duke@435: coleenp@4037: // Last short in ConstMethod* coleenp@4572: u2* last_u2_element() const; 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