duke@435: /* coleenp@4572: * Copyright (c) 1997, 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_CLASSFILE_CLASSFILEPARSER_HPP stefank@2314: #define SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP stefank@2314: stefank@2314: #include "classfile/classFileStream.hpp" stefank@2314: #include "memory/resourceArea.hpp" stefank@2314: #include "oops/oop.inline.hpp" stefank@2314: #include "oops/typeArrayOop.hpp" stefank@2314: #include "runtime/handles.inline.hpp" stefank@2314: #include "utilities/accessFlags.hpp" jrose@3926: #include "classfile/symbolTable.hpp" stefank@2314: never@3137: class FieldAllocationCount; coleenp@4719: class FieldLayoutInfo; never@3137: never@3137: duke@435: // Parser for for .class files duke@435: // duke@435: // The bytes describing the class file structure is read from a Stream object duke@435: duke@435: class ClassFileParser VALUE_OBJ_CLASS_SPEC { duke@435: private: duke@435: bool _need_verify; duke@435: bool _relax_verify; duke@435: u2 _major_version; duke@435: u2 _minor_version; coleenp@2497: Symbol* _class_name; coleenp@4719: ClassLoaderData* _loader_data; jrose@1145: KlassHandle _host_klass; jrose@866: GrowableArray* _cp_patches; // overrides for CP entries duke@435: jrose@3926: // precomputed flags duke@435: bool _has_finalizer; duke@435: bool _has_empty_finalizer; duke@435: bool _has_vanilla_constructor; jrose@3926: int _max_bootstrap_specifier_index; // detects BSS values duke@435: jrose@3926: // class attributes parsed before the instance klass is created: jrose@3926: bool _synthetic_flag; coleenp@4719: int _sde_length; coleenp@4719: char* _sde_buffer; jrose@3926: Symbol* _sourcefile; jrose@3926: Symbol* _generic_signature; coleenp@4719: coleenp@4719: // Metadata created before the instance klass is created. Must be deallocated coleenp@4719: // if not transferred to the InstanceKlass upon successful class loading coleenp@4719: // in which case these pointers have been set to NULL. coleenp@4719: instanceKlassHandle _super_klass; coleenp@4719: ConstantPool* _cp; coleenp@4719: Array* _fields; coleenp@4719: Array* _methods; coleenp@4719: Array* _inner_classes; coleenp@4719: Array* _local_interfaces; coleenp@4719: Array* _transitive_interfaces; coleenp@4037: AnnotationArray* _annotations; stefank@4393: AnnotationArray* _type_annotations; coleenp@4719: Array* _fields_annotations; coleenp@4719: Array* _fields_type_annotations; coleenp@4719: InstanceKlass* _klass; // InstanceKlass once created. jrose@3926: jrose@3926: void set_class_synthetic_flag(bool x) { _synthetic_flag = x; } jrose@3926: void set_class_sourcefile(Symbol* x) { _sourcefile = x; } jrose@3926: void set_class_generic_signature(Symbol* x) { _generic_signature = x; } kvn@3930: void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; } coleenp@4719: coleenp@4719: void init_parsed_class_attributes(ClassLoaderData* loader_data) { coleenp@4719: _loader_data = loader_data; jrose@3926: _synthetic_flag = false; jrose@3926: _sourcefile = NULL; jrose@3926: _generic_signature = NULL; kvn@3930: _sde_buffer = NULL; kvn@3930: _sde_length = 0; jrose@3926: // initialize the other flags too: jrose@3926: _has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false; jrose@3926: _max_bootstrap_specifier_index = -1; coleenp@4719: clear_class_metadata(); coleenp@4719: _klass = NULL; jrose@3926: } jrose@3926: void apply_parsed_class_attributes(instanceKlassHandle k); // update k coleenp@4719: void apply_parsed_class_metadata(instanceKlassHandle k, int fields_count, TRAPS); coleenp@4719: void clear_class_metadata() { coleenp@4719: // metadata created before the instance klass is created. Must be coleenp@4719: // deallocated if classfile parsing returns an error. coleenp@4719: _cp = NULL; coleenp@4719: _fields = NULL; coleenp@4719: _methods = NULL; coleenp@4719: _inner_classes = NULL; coleenp@4719: _local_interfaces = NULL; coleenp@4719: _transitive_interfaces = NULL; coleenp@4719: _annotations = _type_annotations = NULL; coleenp@4719: _fields_annotations = _fields_type_annotations = NULL; coleenp@4719: } jrose@3926: jrose@3926: class AnnotationCollector { jrose@3926: public: jrose@3926: enum Location { _in_field, _in_method, _in_class }; jrose@3926: enum ID { jrose@3926: _unknown = 0, twisti@4866: _method_CallerSensitive, jrose@3926: _method_ForceInline, twisti@3969: _method_DontInline, twisti@3969: _method_LambdaForm_Compiled, twisti@3969: _method_LambdaForm_Hidden, jwilhelm@4430: _sun_misc_Contended, jrose@3926: _annotation_LIMIT jrose@3926: }; jrose@3926: const Location _location; jrose@3926: int _annotations_present; jwilhelm@4430: u2 _contended_group; jwilhelm@4430: jrose@3926: AnnotationCollector(Location location) jrose@3926: : _location(location), _annotations_present(0) jrose@3926: { jrose@3926: assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, ""); jrose@3926: } jrose@3926: // If this annotation name has an ID, report it (or _none). jwilhelm@4430: ID annotation_index(ClassLoaderData* loader_data, Symbol* name); jrose@3926: // Set the annotation name: jrose@3926: void set_annotation(ID id) { jrose@3926: assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob"); jrose@3926: _annotations_present |= nth_bit((int)id); jrose@3926: } jrose@3926: // Report if the annotation is present. jrose@3926: bool has_any_annotations() { return _annotations_present != 0; } jrose@3926: bool has_annotation(ID id) { return (nth_bit((int)id) & _annotations_present) != 0; } jwilhelm@4430: jwilhelm@4430: void set_contended_group(u2 group) { _contended_group = group; } jwilhelm@4430: u2 contended_group() { return _contended_group; } jwilhelm@4430: jwilhelm@4430: void set_contended(bool contended) { set_annotation(_sun_misc_Contended); } jwilhelm@4430: bool is_contended() { return has_annotation(_sun_misc_Contended); } jrose@3926: }; coleenp@4719: coleenp@4719: // This class also doubles as a holder for metadata cleanup. jrose@3926: class FieldAnnotationCollector: public AnnotationCollector { coleenp@4719: ClassLoaderData* _loader_data; coleenp@4719: AnnotationArray* _field_annotations; coleenp@4719: AnnotationArray* _field_type_annotations; jrose@3926: public: coleenp@4719: FieldAnnotationCollector(ClassLoaderData* loader_data) : coleenp@4719: AnnotationCollector(_in_field), coleenp@4719: _loader_data(loader_data), coleenp@4719: _field_annotations(NULL), coleenp@4719: _field_type_annotations(NULL) {} jrose@3926: void apply_to(FieldInfo* f); coleenp@4719: ~FieldAnnotationCollector(); coleenp@4719: AnnotationArray* field_annotations() { return _field_annotations; } coleenp@4719: AnnotationArray* field_type_annotations() { return _field_type_annotations; } coleenp@4719: coleenp@4719: void set_field_annotations(AnnotationArray* a) { _field_annotations = a; } coleenp@4719: void set_field_type_annotations(AnnotationArray* a) { _field_type_annotations = a; } jrose@3926: }; coleenp@4719: jrose@3926: class MethodAnnotationCollector: public AnnotationCollector { jrose@3926: public: jrose@3926: MethodAnnotationCollector() : AnnotationCollector(_in_method) { } jrose@3926: void apply_to(methodHandle m); jrose@3926: }; jrose@3926: class ClassAnnotationCollector: public AnnotationCollector { jrose@3926: public: jrose@3926: ClassAnnotationCollector() : AnnotationCollector(_in_class) { } jrose@3926: void apply_to(instanceKlassHandle k); jrose@3926: }; jrose@2353: duke@435: enum { fixed_buffer_size = 128 }; duke@435: u_char linenumbertable_buffer[fixed_buffer_size]; duke@435: duke@435: ClassFileStream* _stream; // Actual input stream duke@435: duke@435: enum { LegalClass, LegalField, LegalMethod }; // used to verify unqualified names duke@435: duke@435: // Accessors duke@435: ClassFileStream* stream() { return _stream; } duke@435: void set_stream(ClassFileStream* st) { _stream = st; } duke@435: duke@435: // Constant pool parsing coleenp@4719: void parse_constant_pool_entries(int length, TRAPS); duke@435: coleenp@4719: constantPoolHandle parse_constant_pool(TRAPS); duke@435: duke@435: // Interface parsing coleenp@4719: Array* parse_interfaces(int length, duke@435: Handle protection_domain, coleenp@2497: Symbol* class_name, kamg@4245: bool* has_default_methods, duke@435: TRAPS); coleenp@4037: void record_defined_class_dependencies(instanceKlassHandle defined_klass, TRAPS); duke@435: coleenp@4719: instanceKlassHandle parse_super_class(int super_class_index, TRAPS); duke@435: // Field parsing coleenp@4719: void parse_field_attributes(u2 attributes_count, duke@435: bool is_static, u2 signature_index, duke@435: u2* constantvalue_index_addr, duke@435: bool* is_synthetic_addr, duke@435: u2* generic_signature_index_addr, jrose@3926: FieldAnnotationCollector* parsed_annotations, jrose@3926: TRAPS); coleenp@4719: Array* parse_fields(Symbol* class_name, coleenp@4719: bool is_interface, coleenp@4142: FieldAllocationCount *fac, coleenp@4142: u2* java_fields_count_ptr, TRAPS); duke@435: jwilhelm@4430: void print_field_layout(Symbol* name, jwilhelm@4430: Array* fields, jwilhelm@4430: constantPoolHandle cp, jwilhelm@4430: int instance_size, jwilhelm@4430: int instance_fields_start, jwilhelm@4430: int instance_fields_end, jwilhelm@4430: int static_fields_end); jwilhelm@4430: duke@435: // Method parsing coleenp@4719: methodHandle parse_method(bool is_interface, duke@435: AccessFlags* promoted_flags, duke@435: TRAPS); coleenp@4719: Array* parse_methods(bool is_interface, duke@435: AccessFlags* promoted_flags, duke@435: bool* has_final_method, kamg@4245: bool* has_default_method, duke@435: TRAPS); coleenp@4719: intArray* sort_methods(Array* methods); coleenp@4719: coleenp@4719: u2* parse_exception_table(u4 code_length, u4 exception_table_length, coleenp@4719: TRAPS); duke@435: void parse_linenumber_table( duke@435: u4 code_attribute_length, u4 code_length, duke@435: CompressedLineNumberWriteStream** write_stream, TRAPS); duke@435: u2* parse_localvariable_table(u4 code_length, u2 max_locals, u4 code_attribute_length, coleenp@4719: u2* localvariable_table_length, duke@435: bool isLVTT, TRAPS); duke@435: u2* parse_checked_exceptions(u2* checked_exceptions_length, u4 method_attribute_length, coleenp@4719: TRAPS); duke@435: void parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index, coleenp@4719: u1* u1_array, u2* u2_array, TRAPS); coleenp@4719: u1* parse_stackmap_table(u4 code_attribute_length, TRAPS); duke@435: duke@435: // Classfile attribute parsing coleenp@4719: void parse_classfile_sourcefile_attribute(TRAPS); coleenp@4719: void parse_classfile_source_debug_extension_attribute(int length, TRAPS); coleenp@4719: u2 parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, jiangli@3670: bool parsed_enclosingmethod_attribute, jiangli@3670: u2 enclosing_method_class_index, jiangli@3670: u2 enclosing_method_method_index, jrose@3926: TRAPS); coleenp@4719: void parse_classfile_attributes(ClassAnnotationCollector* parsed_annotations, jrose@3926: TRAPS); coleenp@4719: void parse_classfile_synthetic_attribute(TRAPS); coleenp@4719: void parse_classfile_signature_attribute(TRAPS); coleenp@4719: void parse_classfile_bootstrap_methods_attribute(u4 attribute_length, TRAPS); duke@435: duke@435: // Annotations handling coleenp@4719: AnnotationArray* assemble_annotations(u1* runtime_visible_annotations, coleenp@4142: int runtime_visible_annotations_length, coleenp@4142: u1* runtime_invisible_annotations, coleenp@4142: int runtime_invisible_annotations_length, TRAPS); jrose@3926: int skip_annotation(u1* buffer, int limit, int index); jrose@3926: int skip_annotation_value(u1* buffer, int limit, int index); coleenp@4719: void parse_annotations(u1* buffer, int limit, jrose@3926: /* Results (currently, only one result is supported): */ jrose@3926: AnnotationCollector* result, jrose@3926: TRAPS); duke@435: duke@435: // Final setup jcoomes@1374: unsigned int compute_oop_map_count(instanceKlassHandle super, jcoomes@1374: unsigned int nonstatic_oop_count, jcoomes@1374: int first_nonstatic_oop_offset); jcoomes@1374: void fill_oop_maps(instanceKlassHandle k, jcoomes@1374: unsigned int nonstatic_oop_map_count, jcoomes@1374: int* nonstatic_oop_offsets, jcoomes@1374: unsigned int* nonstatic_oop_counts); duke@435: void set_precomputed_flags(instanceKlassHandle k); coleenp@4719: Array* compute_transitive_interfaces(instanceKlassHandle super, coleenp@4142: Array* local_ifs, TRAPS); duke@435: duke@435: // Format checker methods duke@435: void classfile_parse_error(const char* msg, TRAPS); duke@435: void classfile_parse_error(const char* msg, int index, TRAPS); duke@435: void classfile_parse_error(const char* msg, const char *name, TRAPS); duke@435: void classfile_parse_error(const char* msg, int index, const char *name, TRAPS); duke@435: inline void guarantee_property(bool b, const char* msg, TRAPS) { duke@435: if (!b) { classfile_parse_error(msg, CHECK); } duke@435: } duke@435: duke@435: inline void assert_property(bool b, const char* msg, TRAPS) { duke@435: #ifdef ASSERT duke@435: if (!b) { fatal(msg); } duke@435: #endif duke@435: } duke@435: duke@435: inline void check_property(bool property, const char* msg, int index, TRAPS) { duke@435: if (_need_verify) { duke@435: guarantee_property(property, msg, index, CHECK); duke@435: } else { duke@435: assert_property(property, msg, CHECK); duke@435: } duke@435: } duke@435: duke@435: inline void check_property(bool property, const char* msg, TRAPS) { duke@435: if (_need_verify) { duke@435: guarantee_property(property, msg, CHECK); duke@435: } else { duke@435: assert_property(property, msg, CHECK); duke@435: } duke@435: } duke@435: duke@435: inline void guarantee_property(bool b, const char* msg, int index, TRAPS) { duke@435: if (!b) { classfile_parse_error(msg, index, CHECK); } duke@435: } duke@435: inline void guarantee_property(bool b, const char* msg, const char *name, TRAPS) { duke@435: if (!b) { classfile_parse_error(msg, name, CHECK); } duke@435: } duke@435: inline void guarantee_property(bool b, const char* msg, int index, const char *name, TRAPS) { duke@435: if (!b) { classfile_parse_error(msg, index, name, CHECK); } duke@435: } duke@435: kamg@1941: void throwIllegalSignature( coleenp@2497: const char* type, Symbol* name, Symbol* sig, TRAPS); kamg@1941: duke@435: bool is_supported_version(u2 major, u2 minor); duke@435: bool has_illegal_visibility(jint flags); duke@435: coleenp@4719: void verify_constantvalue(int constantvalue_index, int signature_index, TRAPS); duke@435: void verify_legal_utf8(const unsigned char* buffer, int length, TRAPS); coleenp@2497: void verify_legal_class_name(Symbol* name, TRAPS); coleenp@2497: void verify_legal_field_name(Symbol* name, TRAPS); coleenp@2497: void verify_legal_method_name(Symbol* name, TRAPS); coleenp@2497: void verify_legal_field_signature(Symbol* fieldname, Symbol* signature, TRAPS); coleenp@2497: int verify_legal_method_signature(Symbol* methodname, Symbol* signature, TRAPS); duke@435: void verify_legal_class_modifiers(jint flags, TRAPS); duke@435: void verify_legal_field_modifiers(jint flags, bool is_interface, TRAPS); coleenp@2497: void verify_legal_method_modifiers(jint flags, bool is_interface, Symbol* name, TRAPS); duke@435: bool verify_unqualified_name(char* name, unsigned int length, int type); duke@435: char* skip_over_field_name(char* name, bool slash_ok, unsigned int length); duke@435: char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS); duke@435: jrose@1145: bool is_anonymous() { twisti@2698: assert(EnableInvokeDynamic || _host_klass.is_null(), ""); jrose@1145: return _host_klass.not_null(); jrose@1145: } jrose@866: bool has_cp_patch_at(int index) { twisti@2698: assert(EnableInvokeDynamic, ""); jrose@866: assert(index >= 0, "oob"); jrose@866: return (_cp_patches != NULL jrose@866: && index < _cp_patches->length() jrose@866: && _cp_patches->adr_at(index)->not_null()); jrose@866: } jrose@866: Handle cp_patch_at(int index) { jrose@866: assert(has_cp_patch_at(index), "oob"); jrose@866: return _cp_patches->at(index); jrose@866: } jrose@866: Handle clear_cp_patch_at(int index) { jrose@866: Handle patch = cp_patch_at(index); jrose@866: _cp_patches->at_put(index, Handle()); jrose@866: assert(!has_cp_patch_at(index), ""); jrose@866: return patch; jrose@866: } jrose@866: void patch_constant_pool(constantPoolHandle cp, int index, Handle patch, TRAPS); jrose@866: jrose@866: // Wrapper for constantTag.is_klass_[or_]reference. coleenp@4037: // In older versions of the VM, Klass*s cannot sneak into early phases of jrose@866: // constant pool construction, but in later versions they can. jrose@866: // %%% Let's phase out the old is_klass_reference. coleenp@4719: bool valid_klass_reference_at(int index) { coleenp@4719: return _cp->is_within_bounds(index) && coleenp@4719: (EnableInvokeDynamic coleenp@4719: ? _cp->tag_at(index).is_klass_or_reference() coleenp@4719: : _cp->tag_at(index).is_klass_reference()); coleenp@4719: } coleenp@4719: coleenp@4719: // Checks that the cpool index is in range and is a utf8 coleenp@4719: bool valid_symbol_at(int cpool_index) { coleenp@4719: return (_cp->is_within_bounds(cpool_index) && coleenp@4719: _cp->tag_at(cpool_index).is_utf8()); jrose@866: } jrose@866: coleenp@4572: void copy_localvariable_table(ConstMethod* cm, int lvt_cnt, coleenp@4572: u2* localvariable_table_length, coleenp@4572: u2** localvariable_table_start, coleenp@4572: int lvtt_cnt, coleenp@4572: u2* localvariable_type_table_length, coleenp@4572: u2** localvariable_type_table_start, coleenp@4572: TRAPS); coleenp@4572: coleenp@4719: void copy_method_annotations(ConstMethod* cm, coleenp@4572: u1* runtime_visible_annotations, coleenp@4572: int runtime_visible_annotations_length, coleenp@4572: u1* runtime_invisible_annotations, coleenp@4572: int runtime_invisible_annotations_length, coleenp@4572: u1* runtime_visible_parameter_annotations, coleenp@4572: int runtime_visible_parameter_annotations_length, coleenp@4572: u1* runtime_invisible_parameter_annotations, coleenp@4572: int runtime_invisible_parameter_annotations_length, coleenp@4572: u1* runtime_visible_type_annotations, coleenp@4572: int runtime_visible_type_annotations_length, coleenp@4572: u1* runtime_invisible_type_annotations, coleenp@4572: int runtime_invisible_type_annotations_length, coleenp@4572: u1* annotation_default, coleenp@4572: int annotation_default_length, coleenp@4572: TRAPS); coleenp@4572: coleenp@4719: // lays out fields in class and returns the total oopmap count coleenp@4719: void layout_fields(Handle class_loader, FieldAllocationCount* fac, coleenp@4719: ClassAnnotationCollector* parsed_annotations, coleenp@4719: FieldLayoutInfo* info, TRAPS); coleenp@4719: duke@435: public: duke@435: // Constructor duke@435: ClassFileParser(ClassFileStream* st) { set_stream(st); } coleenp@4719: ~ClassFileParser(); duke@435: coleenp@4037: // Parse .class file and return new Klass*. The Klass* is not hooked up duke@435: // to the system dictionary or any other structures, so a .class file can duke@435: // be loaded several times if desired. duke@435: // The system dictionary hookup is done by the caller. duke@435: // duke@435: // "parsed_name" is updated by this method, and is the name found duke@435: // while parsing the stream. coleenp@2497: instanceKlassHandle parseClassFile(Symbol* name, coleenp@4304: ClassLoaderData* loader_data, duke@435: Handle protection_domain, coleenp@2497: TempNewSymbol& parsed_name, acorn@1408: bool verify, jrose@866: TRAPS) { jrose@1145: KlassHandle no_host_klass; coleenp@4304: return parseClassFile(name, loader_data, protection_domain, no_host_klass, NULL, parsed_name, verify, THREAD); jrose@866: } coleenp@2497: instanceKlassHandle parseClassFile(Symbol* name, coleenp@4304: ClassLoaderData* loader_data, jrose@866: Handle protection_domain, jrose@1145: KlassHandle host_klass, jrose@866: GrowableArray* cp_patches, coleenp@2497: TempNewSymbol& parsed_name, acorn@1408: bool verify, duke@435: TRAPS); duke@435: duke@435: // Verifier checks duke@435: static void check_super_class_access(instanceKlassHandle this_klass, TRAPS); duke@435: static void check_super_interface_access(instanceKlassHandle this_klass, TRAPS); duke@435: static void check_final_method_override(instanceKlassHandle this_klass, TRAPS); duke@435: static void check_illegal_static_method(instanceKlassHandle this_klass, TRAPS); duke@435: }; stefank@2314: stefank@2314: #endif // SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP