/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "classfile/classFileParser.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verificationType.hpp"
#include "classfile/verifier.hpp"
#include "classfile/vmSymbols.hpp"
#include "memory/allocation.hpp"
#include "memory/gcLocker.hpp"
#include "memory/oopFactory.hpp"
#include "memory/referenceType.hpp"
#include "memory/universe.inline.hpp"
#include "oops/constantPoolOop.hpp"
#include "oops/fieldStreams.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/instanceMirrorKlass.hpp"
#include "oops/klass.inline.hpp"
#include "oops/klassOop.hpp"
#include "oops/klassVtable.hpp"
#include "oops/methodOop.hpp"
#include "oops/symbol.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/perfData.hpp"
#include "runtime/reflection.hpp"
#include "runtime/signature.hpp"
#include "services/classLoadingService.hpp"
#include "services/threadService.hpp"
// We generally try to create the oops directly when parsing, rather than
// allocating temporary data structures and copying the bytes twice. A
// temporary area is only needed when parsing utf8 entries in the constant
// pool and when parsing line number tables.
// We add assert in debug mode when class format is not checked.
#define JAVA_MAX_SUPPORTED_MINOR_VERSION 0
// Used for two backward compatibility reasons:
// - to check for new additions to the class file format in JDK1.5
// - to check for bug fixes in the format checker in JDK1.5
// Used for backward compatibility reasons:
// - to check for javac bug fixes that happened after 1.5
// - also used as the max version when running in jdk6
// Used for backward compatibility reasons:
// - to check NameAndType_info signatures more aggressively
void ClassFileParser::parse_constant_pool_entries(Handle class_loader, constantPoolHandle cp, int length, TRAPS) {
// Use a local copy of ClassFileStream. It helps the C++ compiler to optimize
// this function (_current can be allocated in a register, with scalar
// replacement of aggregates). The _current pointer is copied back to
// stream() when this function returns. DON'T call another method within
// this method that uses stream().
#ifdef ASSERT
#endif
// Used for batching symbol allocations.
int names_count = 0;
// parsing Index 0 is unused
// Each of the following case guarantees one more byte in the stream
// for the following tag or the access_flags following constant pool,
// so we don't need bounds-check for reading tag.
switch (tag) {
case JVM_CONSTANT_Class :
{
}
break;
case JVM_CONSTANT_Fieldref :
{
}
break;
case JVM_CONSTANT_Methodref :
{
}
break;
{
}
break;
case JVM_CONSTANT_String :
{
}
break;
case JVM_CONSTANT_MethodHandle :
case JVM_CONSTANT_MethodType :
"Class file version does not support constant tag %u in class file %s",
}
if (!EnableInvokeDynamic) {
"This JVM does not support constant tag %u in class file %s",
}
if (tag == JVM_CONSTANT_MethodHandle) {
} else if (tag == JVM_CONSTANT_MethodType) {
} else {
}
break;
case JVM_CONSTANT_InvokeDynamic :
{
"Class file version does not support constant tag %u in class file %s",
}
if (!EnableInvokeDynamic) {
"This JVM does not support constant tag %u in class file %s",
}
if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index)
}
break;
case JVM_CONSTANT_Integer :
{
}
break;
case JVM_CONSTANT_Float :
{
}
break;
case JVM_CONSTANT_Long :
// A mangled type might cause you to overrun allocated memory
"Invalid constant pool entry %u in class file %s",
{
}
index++; // Skip entry following eigth-byte constant, see JVM book p. 98
break;
case JVM_CONSTANT_Double :
// A mangled type might cause you to overrun allocated memory
"Invalid constant pool entry %u in class file %s",
{
}
index++; // Skip entry following eigth-byte constant, see JVM book p. 98
break;
case JVM_CONSTANT_NameAndType :
{
}
break;
case JVM_CONSTANT_Utf8 :
{
// Got utf8 string, guarantee utf8_length+1 bytes, set stream position forward.
// Before storing the symbol, make sure it's legal
if (_need_verify) {
}
"Illegal utf8 patch at %d in class file %s",
// (could use java_lang_String::as_symbol instead, but might as well batch them)
}
unsigned int hash;
SymbolTable::new_symbols(class_loader, cp, names_count, names, lengths, indices, hashValues, CHECK);
names_count = 0;
}
} else {
}
}
break;
default:
break;
}
}
// Allocate the remaining symbols
if (names_count > 0) {
SymbolTable::new_symbols(class_loader, cp, names_count, names, lengths, indices, hashValues, CHECK);
}
// Copy _current pointer of local copy back to stream().
#ifdef ASSERT
#endif
}
// This class unreferences constant pool symbols if an error has occurred
// while parsing the class before it is assigned into the class.
// If it gets an error after that it is unloaded and the constant pool will
// be cleaned up then.
bool _in_error;
public:
~ConstantPoolCleaner() {
}
}
};
else
return NULL;
}
CHECK_(nullHandle));
// parsing constant pool entries
// first verification pass - validate cross references and fixup class and string constants
switch (tag) {
case JVM_CONSTANT_Class :
ShouldNotReachHere(); // Only JVM_CONSTANT_ClassIndex should be present
break;
case JVM_CONSTANT_Fieldref :
// fall through
case JVM_CONSTANT_Methodref :
// fall through
case JVM_CONSTANT_InterfaceMethodref : {
if (!_need_verify) break;
"Invalid constant pool index %u in class file %s",
CHECK_(nullHandle));
"Invalid constant pool index %u in class file %s",
CHECK_(nullHandle));
break;
}
case JVM_CONSTANT_String :
ShouldNotReachHere(); // Only JVM_CONSTANT_StringIndex should be present
break;
case JVM_CONSTANT_Integer :
break;
case JVM_CONSTANT_Float :
break;
case JVM_CONSTANT_Long :
case JVM_CONSTANT_Double :
index++;
break;
case JVM_CONSTANT_NameAndType : {
if (!_need_verify) break;
"Invalid constant pool index %u in class file %s",
"Invalid constant pool index %u in class file %s",
break;
}
case JVM_CONSTANT_Utf8 :
break;
case JVM_CONSTANT_UnresolvedClass : // fall-through
ShouldNotReachHere(); // Only JVM_CONSTANT_ClassIndex should be present
break;
case JVM_CONSTANT_ClassIndex :
{
"Invalid constant pool index %u in class file %s",
}
break;
ShouldNotReachHere(); // Only JVM_CONSTANT_StringIndex should be present
break;
case JVM_CONSTANT_StringIndex :
{
"Invalid constant pool index %u in class file %s",
}
break;
case JVM_CONSTANT_MethodHandle :
{
"Invalid constant pool index %u in class file %s",
switch (ref_kind) {
case JVM_REF_getField:
case JVM_REF_getStatic:
case JVM_REF_putField:
case JVM_REF_putStatic:
"Invalid constant pool index %u in class file %s (not a field)",
break;
case JVM_REF_invokeVirtual:
case JVM_REF_invokeStatic:
case JVM_REF_invokeSpecial:
case JVM_REF_newInvokeSpecial:
"Invalid constant pool index %u in class file %s (not a method)",
break;
case JVM_REF_invokeInterface:
"Invalid constant pool index %u in class file %s (not an interface method)",
break;
default:
"Bad method handle kind at constant pool index %u in class file %s",
}
// Keep the ref_index unchanged. It will be indirected at link-time.
}
break;
case JVM_CONSTANT_MethodType :
{
"Invalid constant pool index %u in class file %s",
}
break;
case JVM_CONSTANT_InvokeDynamic :
{
"Invalid constant pool index %u in class file %s",
CHECK_(nullHandle));
// bootstrap specifier index must be checked later, when BootstrapMethods attr is available
break;
}
default:
break;
} // end of switch
} // end of for
if (_cp_patches != NULL) {
// need to treat this_class specially...
int this_class_index;
{
}
if (has_cp_patch_at(index)) {
"Illegal constant pool patch to self at %d in class file %s",
}
}
// Ensure that all the patches have been used.
"Unused constant pool patch at %d in class file %s",
}
}
if (!_need_verify) {
cp_in_error.set_in_error(false);
return cp;
}
// second verification pass - checks the strings are of the right format.
// but not yet to the other entries
switch (tag) {
case JVM_CONSTANT_UnresolvedClass: {
// check the name, even if _cp_patches will overwrite it
break;
}
case JVM_CONSTANT_NameAndType: {
} else {
}
}
break;
}
case JVM_CONSTANT_Fieldref:
case JVM_CONSTANT_Methodref:
case JVM_CONSTANT_InterfaceMethodref: {
// already verified to be utf8
// already verified to be utf8
if (tag == JVM_CONSTANT_Fieldref) {
// Signature is verified above, when iterating NameAndType_info.
// Need only to be sure it's the right type.
}
} else {
}
} else {
// Signature is verified above, when iterating NameAndType_info.
// Need only to be sure it's the right type.
}
} else {
}
if (tag == JVM_CONSTANT_Methodref) {
// 4509014: If a class method name begins with '<', it must be "<init>".
"Bad method name at constant pool index %u in class file %s",
}
}
}
}
break;
}
case JVM_CONSTANT_MethodHandle: {
switch (ref_kind) {
case JVM_REF_invokeVirtual:
case JVM_REF_invokeStatic:
case JVM_REF_invokeSpecial:
case JVM_REF_newInvokeSpecial:
{
if (ref_kind == JVM_REF_newInvokeSpecial) {
"Bad constructor name at constant pool index %u in class file %s",
}
} else {
"Bad method name at constant pool index %u in class file %s",
}
}
}
break;
// Other ref_kinds are already fully checked in previous pass.
}
break;
}
case JVM_CONSTANT_MethodType: {
break;
}
case JVM_CONSTANT_Utf8: {
}
} // end of switch
} // end of for
cp_in_error.set_in_error(false);
return cp;
}
case JVM_CONSTANT_UnresolvedClass :
// Patching a class means pre-resolving it.
// The name in the constant pool is ignored.
"Illegal class patch at %d in class file %s",
} else {
"Illegal class patch at %d in class file %s",
}
break;
// Patching a string means pre-resolving it.
// The spelling in the constant pool is ignored.
// The constant reference may be any object whatever.
// If it is not a real interned string, the constant is referred
// to as a "pseudo-string", and must be presented to the CP
// explicitly, because it may require scavenging.
break;
{
"Illegal primitive patch at %d in class file %s",
switch (value_type) {
default: assert(false, "");
}
}
break;
default:
// %%% TODO: put method handles into CONSTANT_InterfaceMethodref, etc.
"Illegal unexpected patch at %d in class file %s",
return;
}
// On fall-through, mark the patch as used.
}
public:
};
unsigned int raw_hash = 0;
}
}
// The old format checker uses heap sort to find duplicates.
// NOTE: caller should guarantee that GC doesn't happen during the life cycle
// of table since we don't expect Symbol*'s to move.
// First lookup for duplicates
return false;
}
}
// No duplicate is found, allocate a new entry and fill it.
entry = new NameSigHash();
// Insert into hash table
return true;
}
int length,
TRAPS) {
int index;
"Interface name has bad constant pool index %u in class file %s",
} else {
// Don't need to check legal name because it's checked when parsing constant pool.
// But need to make sure it's not an array type.
// Call resolve_super so classcircularity is checked
false, CHECK_(nullHandle));
}
}
}
return interfaces;
}
// Check if there's any duplicates in interfaces
bool dup = false;
{
// If no duplicates, add (name, NULL) in hashtable interface_names.
dup = true;
break;
}
}
}
if (dup) {
classfile_parse_error("Duplicate interface name in class file %s",
CHECK_(nullHandle));
}
return interfaces;
}
void ClassFileParser::verify_constantvalue(int constantvalue_index, int signature_index, constantPoolHandle cp, TRAPS) {
// Make sure the constant pool entry is of a type appropriate to this field
(constantvalue_index > 0 &&
"Bad initial value index %u in ConstantValue attribute in class file %s",
case T_LONG:
guarantee_property(value_type.is_long(), "Inconsistent constant value type in class file %s", CHECK);
break;
case T_FLOAT:
guarantee_property(value_type.is_float(), "Inconsistent constant value type in class file %s", CHECK);
break;
case T_DOUBLE:
guarantee_property(value_type.is_double(), "Inconsistent constant value type in class file %s", CHECK);
break;
guarantee_property(value_type.is_int(), "Inconsistent constant value type in class file %s", CHECK);
break;
case T_OBJECT:
"Bad string initial value in class file %s", CHECK);
break;
default:
"Unable to set initial value %u in class file %s",
}
}
// Parse attributes for a field.
bool* is_synthetic_addr,
TRAPS) {
bool is_synthetic = false;
int runtime_visible_annotations_length = 0;
int runtime_invisible_annotations_length = 0;
while (attributes_count--) {
"Invalid field attribute index %u in class file %s",
CHECK);
// ignore if non-static
if (constantvalue_index != 0) {
}
attribute_length == 2,
"Invalid ConstantValue field attribute length %u in class file %s",
if (_need_verify) {
}
if (attribute_length != 0) {
"Invalid Synthetic field attribute length %u in class file %s",
}
is_synthetic = true;
if (attribute_length != 0) {
"Invalid Deprecated field attribute length %u in class file %s",
}
} else if (_major_version >= JAVA_1_5_VERSION) {
if (attribute_length != 2) {
"Wrong size %u for field's Signature attribute in class file %s",
}
} else if (PreserveAllAnnotations && attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
} else {
}
} else {
}
}
CHECK);
return;
}
// Field allocation types. Used for computing field offsets.
enum FieldAllocationType {
};
BAD_ALLOCATION_TYPE, // 0
BAD_ALLOCATION_TYPE, // 1
BAD_ALLOCATION_TYPE, // 2
BAD_ALLOCATION_TYPE, // 3
NONSTATIC_BYTE , // T_BOOLEAN = 4,
NONSTATIC_SHORT, // T_CHAR = 5,
NONSTATIC_WORD, // T_FLOAT = 6,
NONSTATIC_DOUBLE, // T_DOUBLE = 7,
NONSTATIC_BYTE, // T_BYTE = 8,
NONSTATIC_SHORT, // T_SHORT = 9,
NONSTATIC_WORD, // T_INT = 10,
NONSTATIC_DOUBLE, // T_LONG = 11,
NONSTATIC_OOP, // T_OBJECT = 12,
NONSTATIC_OOP, // T_ARRAY = 13,
BAD_ALLOCATION_TYPE, // T_VOID = 14,
BAD_ALLOCATION_TYPE, // T_ADDRESS = 15,
BAD_ALLOCATION_TYPE, // T_NARROWOOP= 16,
BAD_ALLOCATION_TYPE, // T_CONFLICT = 17,
BAD_ALLOCATION_TYPE, // 0
BAD_ALLOCATION_TYPE, // 1
BAD_ALLOCATION_TYPE, // 2
BAD_ALLOCATION_TYPE, // 3
STATIC_BYTE , // T_BOOLEAN = 4,
STATIC_SHORT, // T_CHAR = 5,
STATIC_WORD, // T_FLOAT = 6,
STATIC_DOUBLE, // T_DOUBLE = 7,
STATIC_BYTE, // T_BYTE = 8,
STATIC_SHORT, // T_SHORT = 9,
STATIC_WORD, // T_INT = 10,
STATIC_DOUBLE, // T_LONG = 11,
STATIC_OOP, // T_OBJECT = 12,
STATIC_OOP, // T_ARRAY = 13,
BAD_ALLOCATION_TYPE, // T_VOID = 14,
BAD_ALLOCATION_TYPE, // T_ADDRESS = 15,
BAD_ALLOCATION_TYPE, // T_NARROWOOP= 16,
BAD_ALLOCATION_TYPE, // T_CONFLICT = 17,
};
return result;
}
public:
for (int i = 0; i < MAX_FIELD_ALLOCATION_TYPE; i++) {
count[i] = 0;
}
}
// Make sure there is no overflow with injected fields.
return atype;
}
};
int num_injected = 0;
// The field array starts with tuples of shorts
// [access, name index, sig index, initial value index, byte offset].
// A generic signature slot only exists for field with generic
// signature attribute. And the access flag is set with
// JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE for that field. The generic
// signature slots are at the end of the field array and after all
// other fields data.
//
// f1: [access, name index, sig index, initial value index, low_offset, high_offset]
// f2: [access, name index, sig index, initial value index, low_offset, high_offset]
// ...
// fn: [access, name index, sig index, initial value index, low_offset, high_offset]
// [generic signature index]
// [generic signature index]
// ...
//
// Allocate a temporary resource array for field data. For each field,
// a slot is reserved in the temporary array for the generic signature
// index. After parsing all fields, the data are copied to a permanent
// array and any unused slots will be discarded.
// The generic signature slots start after all other fields' data.
int num_generic_signature = 0;
for (int n = 0; n < length; n++) {
cfs->guarantee_more(8, CHECK_(nullHandle)); // access_flags, name_index, descriptor_index, attributes_count
"Invalid constant pool index %u for field name in class file %s",
"Invalid constant pool index %u for field signature in class file %s",
bool is_synthetic = false;
if (attributes_count > 0) {
CHECK_(nullHandle));
if (field_annotations.not_null()) {
if (fields_annotations->is_null()) {
}
}
if (is_synthetic) {
}
if (generic_signature_index != 0) {
}
}
0);
// Remember how many oops we encountered and compute allocation type
// The correct offset is computed later (all oop fields will be located together)
// We temporarily store the allocation type in the offset field
}
if (num_injected != 0) {
for (int n = 0; n < num_injected; n++) {
// Check for duplicates
if (injected[n].may_be_java) {
bool duplicate = false;
for (int i = 0; i < length; i++) {
// Symbol is desclared in Java so skip this one
duplicate = true;
break;
}
}
if (duplicate) {
// These will be removed from the field array at the end
continue;
}
}
// Injected field
injected[n].name_index,
0,
0);
// Remember how many oops we encountered and compute allocation type
// The correct offset is computed later (all oop fields will be located together)
// We temporarily store the allocation type in the offset field
index++;
}
}
// Now copy the fields' data from the temporary resource array.
// Sometimes injected fields already exist in the Java source so
// the fields array could be too long. In that case the
// fields array is trimed. Also unused slots that were reserved
// for generic signature indexes are discarded.
CHECK_(nullHandle));
{
int i = 0;
}
j < generic_signature_slot; j++) {
}
}
// Check duplicated fields
bool dup = false;
{
dup = true;
break;
}
}
}
if (dup) {
classfile_parse_error("Duplicate field name&signature in class file %s",
CHECK_(nullHandle));
}
}
return fields;
}
while (length-- > 0) {
}
}
TRAPS) {
cfs->guarantee_more(8 * exception_table_length, CHECK_NULL); // start_pc, end_pc, handler_pc, catch_type_index
// Will check legal target after parsing code array in verifier.
if (_need_verify) {
for (unsigned int i = 0; i < exception_table_length; i++) {
"Illegal exception table range in class file %s",
"Illegal exception table handler in class file %s",
if (catch_type_index != 0) {
"Catch type in exception table has bad constant type in class file %s", CHECK_NULL);
}
}
} else {
}
return exception_table_start;
}
// Each entry is a u2 start_pc, and a u2 line_number
// Verify line number attribute and table length
"LineNumberTable attribute has wrong length in class file %s", CHECK);
if ((*write_stream) == NULL) {
if (length_in_bytes > fixed_buffer_size) {
} else {
(*write_stream) = new CompressedLineNumberWriteStream(
}
}
while (num_entries-- > 0) {
"Invalid pc in LineNumberTable in class file %s", CHECK);
}
}
// Class file LocalVariableTable elements.
public:
};
public:
};
return raw_hash % HASH_ROW_SIZE;
}
for (int i = 0; i < HASH_ROW_SIZE; i++) {
}
}
for (int i = 0; i < HASH_ROW_SIZE; i++) {
delete(current);
}
}
}
/*
* so the following comparison seems to be redundant:
* && elem->name_cp_index == entry->_elem->name_cp_index
*/
) {
return entry;
}
}
return NULL;
}
// Return false if the local variable is found in table.
// Return true if no duplicate is found.
// And local variable is added as a new entry in table.
// First lookup for duplicates
return false;
}
// No duplicate is found, allocate a new entry and fill it.
return false;
}
// Insert into hash table
return true;
}
lvt->signature_cp_index = 0;
}
// Function is used to parse both attributes:
// LocalVariableTable (LVT) and LocalVariableTypeTable (LVTT)
bool isLVTT,
TRAPS) {
// Verify local variable table attribute has right length
if (_need_verify) {
guarantee_property(code_attribute_length == (sizeof(*localvariable_table_length) + size * sizeof(u2)),
}
if (!_need_verify) {
} else {
for(int i = 0; i < (*localvariable_table_length); i++) {
// Assign to a u4 to avoid overflow
if (start_pc >= code_length) {
"Invalid start_pc %u in %s in class file %s",
}
if (end_pc > code_length) {
"Invalid length %u in %s in class file %s",
}
"Name index %u in %s has bad constant type in class file %s",
"Signature index %u in %s has bad constant type in class file %s",
if (!isLVTT) {
// 4894874: check special cases for double and long local variables
extra_slot = 1;
}
}
"Invalid index %u in %s in class file %s",
}
}
return localvariable_table_start;
}
for(int i = 0; i < array_length; i++) {
index++;
index++;
} else if (tag == ITEM_Object) {
"Bad class index %u in StackMap in class file %s",
class_index, CHECK);
} else if (tag == ITEM_Uninitialized) {
"Bad uninitialized type offset %u in StackMap in class file %s",
} else {
"Unknown variable type %u in StackMap in class file %s",
}
}
}
if (code_attribute_length == 0)
return NULL;
// check code_attribute_length first
if (!_need_verify && !DumpSharedSpaces) {
return NULL;
}
(void*)stackmap_table_start, code_attribute_length);
return stackmap_data;
}
if (!_need_verify) {
} else {
// Verify each value in the checked exception table
for (int i = 0; i < len; i++) {
"Exception name has bad type at constant pool %u in class file %s",
}
}
// check exceptions attribute length
if (_need_verify) {
"Exceptions attribute has wrong length in class file %s", CHECK_NULL);
}
return checked_exceptions_start;
}
"%s \"%s\" in class %s has illegal signature \"%s\"", type,
}
// Skip an annotation. Return >=limit if there is any problem.
// annotation := atype:u2 do(nmem:u2) {member:u2 value}
// value := switch (tag:u1) { ... }
}
return index;
}
// Skip an annotation value. Return >=limit if there is any problem.
// value := switch (tag:u1) {
// case B, C, I, S, Z, D, F, J, c: con:u2;
// case e: e_class:u2 e_name:u2;
// case s: s_con:u2;
// case [: do(nval:u2) {value};
// case @: annotation;
// case s: s_con:u2;
// }
switch (tag) {
case 'B': case 'C': case 'I': case 'S': case 'Z':
case 'D': case 'F': case 'J': case 'c': case 's':
break;
case 'e':
break;
case '[':
{
}
}
break;
case '@':
break;
default:
assert(false, "annotation tag");
return limit; // bad tag byte
}
return index;
}
// Sift through annotations, looking for those significant to the VM:
TRAPS) {
// annotations := do(nann:u2) {annotation}
int index = 0;
enum { // initial annotation layout
};
if (count >= 1) {
}
// Here is where parsing particular annotations will take place.
// If there are no values, just set the bit and move on:
if (count == 0) continue;
// For the record, here is how annotation payloads can be collected.
// Suppose we want to capture @Retention.value. Here is how:
//if (id == AnnotationCollector::_class_Retention) {
// Symbol* payload = NULL;
// if (count == 1
// && e_size == (index0 - index) // match size
// && e_tag_val == *(abase + tag_off)
// && (check_symbol_at(cp, Bytes::get_Java_u2(abase + e_type_off))
// == vmSymbols::RetentionPolicy_signature())
// && member == vmSymbols::value_name()) {
// payload = check_symbol_at(cp, Bytes::get_Java_u2(abase + e_con_off));
// }
// check_property(payload != NULL,
// "Invalid @Retention annotation at offset %u in class file %s",
// index0, CHECK);
// if (payload != NULL) {
// payload->increment_refcount();
// coll->_class_RetentionPolicy = payload;
// }
//}
}
}
ClassFileParser::AnnotationCollector::ID ClassFileParser::AnnotationCollector::annotation_index(Symbol* name) {
switch (sid) {
return _method_ForceInline;
return _method_DontInline;
return _method_LambdaForm_Compiled;
return _method_LambdaForm_Hidden;
default: break;
}
return AnnotationCollector::_unknown;
}
fatal("no field annotations yet");
}
m->set_force_inline(true);
m->set_dont_inline(true);
m->set_hidden(true);
}
fatal("no class annotations yet");
}
// Note: the parse_method below is big and clunky because all parsing of the code and exceptions
// attribute is inlined. This is cumbersome to avoid since we inline most of the parts in the
// methodOop to save footprint, so we only know the size of the resulting methodOop when the
// entire method attribute is parsed.
//
// The promoted_flags parameter is used to pass relevant access_flags
// from the method back up to the containing klass. These flag values
// are added to klass's access_flags.
TRAPS) {
// Parse fixed parts
cfs->guarantee_more(8, CHECK_(nullHandle)); // access_flags, name_index, descriptor_index, attributes_count
"Illegal constant pool index %u for method name in class file %s",
"Illegal constant pool index %u for method signature in class file %s",
// We ignore the other access flags for a valid class initializer.
// (JVM Spec 2nd ed., chapter 4.6)
}
} else {
}
if (_need_verify) {
if (args_size > MAX_ARGS_SIZE) {
classfile_parse_error("Too many arguments in method signature in class file %s", CHECK_(nullHandle));
}
}
// Default values for code and exceptions attribute elements
int linenumber_table_length = 0;
int total_lvt_length = 0;
bool lvt_allocated = false;
bool parsed_code_attribute = false;
bool parsed_checked_exceptions_attribute = false;
bool parsed_stackmap_attribute = false;
// stackmap attribute - JDK1.5
int runtime_visible_annotations_length = 0;
int runtime_invisible_annotations_length = 0;
int annotation_default_length = 0;
// Parse code and exceptions attribute
while (method_attributes_count--) {
"Invalid method attribute name index %u in class file %s",
// Parse Code attribute
if (_need_verify) {
"Code attribute in native or abstract methods in class file %s",
CHECK_(nullHandle));
}
if (parsed_code_attribute) {
}
parsed_code_attribute = true;
// Stack size, locals size, and code size
} else {
}
if (_need_verify) {
"Invalid method Code length %u in class file %s",
}
// Code pointer
// Exception handler table
if (exception_table_length > 0) {
}
// Parse additional attributes in code attribute
unsigned int calculated_attribute_length = 0;
} else {
// max_stack, locals and length are smaller in pre-version 45.2 classes
}
sizeof(exception_table_length) +
sizeof(code_attributes_count) +
( sizeof(u2) + // start_pc
sizeof(u2) + // end_pc
sizeof(u2) + // handler_pc
sizeof(u2) ); // catch_type_index
while (code_attributes_count--) {
sizeof(code_attribute_name_index) +
sizeof(code_attribute_length);
"Invalid code attribute name index %u in class file %s",
CHECK_(nullHandle));
if (LoadLineNumberTables &&
// Parse and compress line number table
} else if (LoadLocalVariableTables &&
// Parse local variable table
if (!lvt_allocated) {
lvt_allocated = true;
}
if (lvt_cnt == max_lvt_cnt) {
max_lvt_cnt <<= 1;
}
cp,
false, // is not LVTT
CHECK_(nullHandle));
lvt_cnt++;
} else if (LoadLocalVariableTypeTables &&
if (!lvt_allocated) {
lvt_allocated = true;
}
// Parse local variable type table
if (lvtt_cnt == max_lvtt_cnt) {
max_lvtt_cnt <<= 1;
}
cp,
true, // is LVTT
CHECK_(nullHandle));
lvtt_cnt++;
} else if (UseSplitVerifier &&
// Stack map is only needed by the new verifier in JDK1.5.
if (parsed_stackmap_attribute) {
}
parsed_stackmap_attribute = true;
} else {
// Skip unknown attributes
}
}
// check method attribute length
if (_need_verify) {
}
// Parse Exceptions attribute
}
if (method_attribute_length != 0) {
"Invalid Synthetic method attribute length %u in class file %s",
}
// Should we check that there hasn't already been a synthetic attribute?
if (method_attribute_length != 0) {
"Invalid Deprecated method attribute length %u in class file %s",
}
} else if (_major_version >= JAVA_1_5_VERSION) {
if (method_attribute_length != 2) {
"Invalid Signature attribute length %u in class file %s",
}
parse_annotations(runtime_visible_annotations, runtime_visible_annotations_length, cp, &parsed_annotations, CHECK_(nullHandle));
} else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
} else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_parameter_annotations()) {
} else {
// Skip unknown attributes
}
} else {
// Skip unknown attributes
}
}
if (linenumber_table != NULL) {
}
// Make sure there's at least one Code attribute in non-native/non-abstract method
if (_need_verify) {
"Absent Code attribute in method that is not native or abstract in class file %s", CHECK_(nullHandle));
}
// All sizing information for a methodOop is finally available, now create it
CHECK_(nullHandle));
// Fill in information from fixed part (access_flags already set)
m->set_constants(cp());
m->set_name_index(name_index);
#ifdef CC_INTERP
// hmm is there a gc issue here??
#endif
if (args_size >= 0) {
} else {
}
#ifdef ASSERT
if (args_size >= 0) {
}
#endif
// Fill in code attribute information
m->set_max_stack(max_stack);
m->set_max_locals(max_locals);
/**
* The stackmap_data field is the flag used to indicate
* that the methodOop and it's associated constMethodOop are partially
* the field is set, the oops are considered fully initialized so make
* sure that the oops can pass verification when this field is set.
*/
// Copy byte codes
m->set_code(code_start);
// Copy line number table
if (linenumber_table != NULL) {
}
// Copy exception table
if (exception_table_length > 0) {
int size =
}
// Copy checked exceptions
if (checked_exceptions_length > 0) {
}
*
* Rules for LVT's and LVTT's are:
* - There can be any number of LVT's and LVTT's.
* - If there are n LVT's, it is the same as if there was just
* one LVT containing all the entries from the n LVT's.
* - There may be no more than one LVT entry per local variable.
* Two LVT entries are 'equal' if these fields are the same:
* start_pc, length, name, slot
* - There may be no more than one LVTT entry per each LVT entry.
* Each LVTT entry has to match some LVT entry.
* - HotSpot internal LVT keeps natural ordering of class file LVT entries.
*/
if (total_lvt_length > 0) {
// To fill LocalVariableTable in
// If no duplicates, add LVT elem in hashtable lvt_Hash.
&& _need_verify
&& _major_version >= JAVA_1_5_VERSION ) {
classfile_parse_error("Duplicated LocalVariableTable attribute "
"entry for '%s' in class file %s",
CHECK_(nullHandle));
}
}
}
// To merge LocalVariableTable and LocalVariableTypeTable
if (_need_verify) {
classfile_parse_error("LVTT entry for '%s' in class file %s "
"does not match any LVT entry",
CHECK_(nullHandle));
}
classfile_parse_error("Duplicated LocalVariableTypeTable attribute "
"entry for '%s' in class file %s",
CHECK_(nullHandle));
} else {
// to add generic signatures into LocalVariableTable
}
}
}
}
CHECK_(nullHandle));
CHECK_(nullHandle));
NULL,
0,
CHECK_(nullHandle));
if (m->is_empty_method()) {
_has_empty_finalizer = true;
} else {
_has_finalizer = true;
}
}
m->is_vanilla_constructor()) {
_has_vanilla_constructor = true;
}
return m;
}
// The promoted_flags parameter is used to pass relevant access_flags
// from the methods back up to the containing klass. These flag values
// are added to klass's access_flags.
bool* has_final_method,
TRAPS) {
if (length == 0) {
} else {
CHECK_(nullHandle));
*has_final_method = true;
}
if (method_annotations.not_null()) {
if (methods_annotations.is_null()) {
}
}
if (method_parameter_annotations.not_null()) {
if (methods_parameter_annotations.is_null()) {
}
}
if (method_default_annotations.not_null()) {
if (methods_default_annotations.is_null()) {
}
}
}
// Check duplicated methods
bool dup = false;
{
for (int i = 0; i < length; i++) {
dup = true;
break;
}
}
}
if (dup) {
classfile_parse_error("Duplicate method name&signature in class file %s",
CHECK_(nullHandle));
}
}
return methods;
}
}
TRAPS) {
// If JVMTI original method ordering or sharing is enabled we have to
// remember the original class file ordering.
// We temporarily use the vtable_index field in the methodOop to store the
// class file index, so we can read in after calling qsort.
// Put the method ordering in the shared archive.
m->set_vtable_index(index);
}
}
// Sort method array by ascending method name (for faster lookups & vtable construction)
// Note that the ordering is not alphabetical, see Symbol::fast_compare
// If JVMTI original method ordering or sharing is enabled construct int
// array remembering the original ordering
}
return method_ordering;
} else {
}
}
"Invalid SourceFile attribute at constant pool index %u in class file %s",
}
// Don't bother storing it if there is no way to retrieve it
if (JvmtiExport::can_get_source_debug_extension()) {
for (int i = 0; i < length; i++) {
sde[i] = sde_buffer[i];
}
}
// Got utf8 string, set stream position forward
}
// Inner classes can be static, private or protected (classic VM does this)
#define RECOGNIZED_INNER_CLASS_MODIFIERS (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED | JVM_ACC_STATIC)
// Return number of classes in the inner classes attribute table
TRAPS) {
if (inner_classes_attribute_start != NULL) {
}
// 4-tuples of shorts of inner classes data and 2 shorts of enclosing
// method data:
// [inner_class_info_index,
// outer_class_info_index,
// inner_name_index,
// inner_class_access_flags,
// ...
// enclosing_method_class_index,
// enclosing_method_method_index]
int index = 0;
for (int n = 0; n < length; n++) {
// Inner class index
inner_class_info_index == 0 ||
"inner_class_info_index %u has bad constant type in class file %s",
// Outer class index
outer_class_info_index == 0 ||
"outer_class_info_index %u has bad constant type in class file %s",
// Inner class name
"inner_name_index %u has bad constant type in class file %s",
if (_need_verify) {
"Class is both outer and inner class in class file %s", CHECK_0);
}
// Access flags
// Set abstract bit for old class files for backward compatibility
}
}
// 4347400: make sure there's no duplicate entry in the classes array
"Duplicate entry in InnerClasses in class file %s",
CHECK_0);
}
}
}
// Set EnclosingMethod class and method indexes.
}
// Update instanceKlass with inner class info.
// Restore buffer's current position.
return length;
}
set_class_synthetic_flag(true);
}
"Invalid constant pool index %u in Signature attribute in class file %s",
}
"Short length on BootstrapMethods in class file %s",
CHECK);
// The attribute contains a counted array of counted tuples of shorts,
// represending bootstrap specifiers:
// length*{bootstrap_method_index, argument_count*{argument_index}}
// operand_count = number of shorts in attr, except for leading length
// The attribute is copied into a short[] array.
// The array begins with a series of short[2] pairs, one for each tuple.
int operand_fill_index = index_size;
for (int n = 0; n < attribute_array_length; n++) {
// Store a 32-bit offset into the header of the operand array.
// Read a bootstrap specifier.
"bootstrap_method_index %u has bad constant type in class file %s",
CHECK);
for (int j = 0; j < argument_count; j++) {
"argument_index %u has bad constant type in class file %s",
CHECK);
}
}
assert(constantPoolOopDesc::operand_array_length(operands()) == attribute_array_length, "correct decode");
"Bad length on BootstrapMethods in class file %s",
CHECK);
}
TRAPS) {
// Set inner classes attribute to default sentinel
bool parsed_sourcefile_attribute = false;
bool parsed_innerclasses_attribute = false;
bool parsed_enclosingmethod_attribute = false;
bool parsed_bootstrap_methods_attribute = false;
int runtime_visible_annotations_length = 0;
int runtime_invisible_annotations_length = 0;
// Iterate over attributes
while (attributes_count--) {
"Attribute name has bad constant pool index %u in class file %s",
// Check for SourceFile tag
if (_need_verify) {
guarantee_property(attribute_length == 2, "Wrong SourceFile attribute length in class file %s", CHECK);
}
if (parsed_sourcefile_attribute) {
} else {
parsed_sourcefile_attribute = true;
}
// Check for SourceDebugExtension tag
// Check for InnerClasses tag
} else {
parsed_innerclasses_attribute = true;
}
// Check for Synthetic tag
// Shouldn't we check that the synthetic flags wasn't already set? - not required in spec
if (attribute_length != 0) {
"Invalid Synthetic classfile attribute length %u in class file %s",
}
// Check for Deprecatd tag - 4276120
if (attribute_length != 0) {
"Invalid Deprecated classfile attribute length %u in class file %s",
}
} else if (_major_version >= JAVA_1_5_VERSION) {
if (attribute_length != 2) {
"Wrong Signature attribute length %u in class file %s",
}
cp,
CHECK);
} else {
parsed_enclosingmethod_attribute = true;
}
if (enclosing_method_class_index == 0) {
}
// Validate the constant pool indices and types
classfile_parse_error("Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK);
}
if (enclosing_method_method_index != 0 &&
classfile_parse_error("Invalid or out-of-bounds method index in EnclosingMethod attribute in class file %s", CHECK);
}
} else {
// Unknown attribute
}
} else {
// Unknown attribute
}
}
CHECK);
"Wrong InnerClasses attribute length in class file %s", CHECK);
}
}
if (_max_bootstrap_specifier_index >= 0) {
"Missing BootstrapMethods attribute in class file %s", CHECK);
}
}
if (_synthetic_flag)
k->set_is_synthetic();
if (_sourcefile != NULL) {
}
if (_generic_signature != NULL) {
}
if (_sde_buffer != NULL) {
}
k->set_inner_classes(_inner_classes());
}
if (runtime_visible_annotations != NULL ||
if (runtime_visible_annotations != NULL) {
memcpy(annotations->byte_at_addr(0), runtime_visible_annotations, runtime_visible_annotations_length);
}
if (runtime_invisible_annotations != NULL) {
memcpy(annotations->byte_at_addr(runtime_visible_annotations_length), runtime_invisible_annotations, runtime_invisible_annotations_length);
}
}
return annotations;
}
bool verify,
TRAPS) {
// When a retransformable agent is attached, JVMTI caches the
// class bytes that existed before the first retransformation.
// If RedefineClasses() was used before the retransformable
// agent attached, then the cached class bytes may not be the
// original class bytes.
// Timing
NULL,
if (JvmtiExport::should_post_class_file_load_hook()) {
// Get the cached class file bytes (if any) from the class that
// is being redefined or retransformed. We use jvmti_thread_state()
// instead of JvmtiThreadState::state_for(jt) so we don't allocate
// a JvmtiThreadState any earlier than necessary. This will help
// avoid the bug described by 7126851.
if (h_class_being_redefined != NULL) {
}
}
// JVMTI agent has modified class file data.
// Set new class file stream using JVMTI agent modified
// class file data.
}
}
// Figure out whether we can skip format checking (matching classic VM behavior)
// Set the verify flag in stream
// Save the class file name for easier error message printing.
// Magic value
"Incompatible magic value %u in class file %s",
// Version numbers
// Check version numbers - we check this even with verifier off
"Unsupported major.minor version %u.%u",
} else {
"%s : Unsupported major.minor version %u.%u",
name->as_C_string(),
}
return nullHandle;
}
// Check if verification needs to be relaxed for this class file
// Do not restrict it to jdk1.0 or jdk1.1 to maintain backward compatibility (4982376)
// Constant pool
// Access flags
// Set abstract bit for old class files for backward compatibility
}
// This class and superclass
"Invalid this class index %u in constant pool in class file %s",
// It's important to set parsed_name *before* resolving the super class.
// (it's used for cleanup by the caller if parsing fails)
// parsed_name is returned and can be used if there's an error, so add to
// its reference count. Caller will decrement the refcount.
// Update _class_name which could be null previously to be class_name
// Don't need to check whether this class name is legal or not.
// It has been checked when constant pool is parsed.
// However, make sure it is not an array type.
if (_need_verify) {
"Bad class name in class file %s",
CHECK_(nullHandle));
}
// release all handles when parsing is done
// Checks if name in class file matches requested name
"%s (wrong name: %s)",
name->as_C_string(),
);
return nullHandle;
}
if (TraceClassLoadingPreorder) {
}
if (super_class_index == 0) {
"Invalid superclass index %u in class file %s",
CHECK_(nullHandle));
} else {
"Invalid superclass index %u in class file %s",
CHECK_(nullHandle));
// The class name should be legal because it is checked when parsing constant pool.
// However, make sure it is not an array type.
bool is_array = false;
if (_need_verify)
} else if (_need_verify) {
}
if (_need_verify) {
}
}
// Interfaces
if (itfs_len == 0) {
} else {
local_interfaces = parse_interfaces(cp, itfs_len, class_loader, protection_domain, _class_name, CHECK_(nullHandle));
}
// Fields (offsets are filled in later)
typeArrayHandle fields = parse_fields(class_name, cp, access_flags.is_interface(), &fac, &fields_annotations,
CHECK_(nullHandle));
// Methods
bool has_final_method = false;
// These need to be oop pointers because they are allocated lazily
// inside parse_methods inside a nested HandleMark
CHECK_(nullHandle));
// Additional attributes
// Make sure this is the end of class file stream
// We check super class after class file is parsed and format is checked
if (access_flags.is_interface()) {
// Before attempting to resolve the superclass, check for class format
// errors not checked yet.
"Interfaces must have java.lang.Object as superclass in class file %s",
CHECK_(nullHandle));
}
sk,
true,
CHECK_(nullHandle));
}
if (super_klass.not_null()) {
if (super_klass->is_interface()) {
"class %s has interface %s as super class",
);
return nullHandle;
}
// Make sure super class is not final
if (super_klass->is_final()) {
}
}
// Compute the transitive list of all unique interfaces implemented by this class
objArrayHandle transitive_interfaces = compute_transitive_interfaces(super_klass, local_interfaces, CHECK_(nullHandle));
// sort methods
CHECK_(nullHandle));
// promote flags from parse_methods() to the klass' flags
// Size of Java vtable (in words)
int vtable_size = 0;
int itable_size = 0;
int num_miranda_methods = 0;
super_klass(),
methods(),
CHECK_(nullHandle));
// Size of Java itable (in words)
itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces);
// Field size and offset computation
#ifndef PRODUCT
int orig_nonstatic_field_size = 0;
#endif
int static_field_size = 0;
// Calculate the starting byte offsets
}
bool super_has_nonstatic_fields =
nonstatic_oop_count) != 0);
// Prepare list of oops for oop map generation.
int* nonstatic_oop_offsets;
unsigned int* nonstatic_oop_counts;
unsigned int nonstatic_oop_map_count = 0;
first_nonstatic_oop_offset = 0; // will be set for first oop field
#ifndef PRODUCT
if( PrintCompactFieldsSavings ) {
if ( nonstatic_double_count > 0 ) {
}
}
#endif
assert(false, "0 <= FieldsAllocationStyle <= 2");
}
// The next classes have predefined hard-coded fields offsets
// (see in JavaClasses::compute_hard_coded_offsets()).
// Use default fields allocation order for them.
allocation_style = 0; // Allocate oops first
compact_fields = false; // Don't compact fields
}
if( allocation_style == 0 ) {
} else if( allocation_style == 1 ) {
} else if( allocation_style == 2 ) {
// Fields allocation: oops fields in super and sub classes are together.
super_klass->nonstatic_oop_map_size() > 0 ) {
if (next_offset == next_nonstatic_field_offset) {
allocation_style = 0; // allocate oops first
}
}
if( allocation_style == 2 ) {
}
} else {
}
int nonstatic_oop_space_count = 0;
int nonstatic_word_space_count = 0;
int nonstatic_short_space_count = 0;
int nonstatic_byte_space_count = 0;
if( nonstatic_double_count > 0 ) {
// Allocate available fields into the gap before double field.
if( nonstatic_word_count > 0 ) {
nonstatic_word_count -= 1;
length -= BytesPerInt;
offset += BytesPerInt;
}
nonstatic_short_count -= 1;
length -= BytesPerShort;
offset += BytesPerShort;
}
while( length > 0 && nonstatic_byte_count > 0 ) {
nonstatic_byte_count -= 1;
length -= 1;
}
// Allocate oop field in the gap if there are no other fields for that.
allocation_style != 0 ) { // when oop fields not first
nonstatic_oop_count -= 1;
length -= heapOopSize;
offset += heapOopSize;
}
}
}
int notaligned_offset;
if( allocation_style == 0 ) {
} else { // allocation_style == 1
if( nonstatic_oop_count > 0 ) {
}
}
// Iterate over fields again and compute correct offsets.
// The field allocation type was temporarily stored in the offset slot.
// oop fields are located before non-oop fields (static and non-static).
int real_offset;
switch (atype) {
case STATIC_OOP:
break;
case STATIC_BYTE:
next_static_byte_offset += 1;
break;
case STATIC_SHORT:
break;
case STATIC_WORD:
break;
case STATIC_DOUBLE:
break;
case NONSTATIC_OOP:
if( nonstatic_oop_space_count > 0 ) {
} else {
}
// Update oop maps
if( nonstatic_oop_map_count > 0 &&
heapOopSize ) {
// Extend current oop map
} else {
// Create new oop map
nonstatic_oop_map_count += 1;
if( first_nonstatic_oop_offset == 0 ) { // Undefined
}
}
break;
case NONSTATIC_BYTE:
if( nonstatic_byte_space_count > 0 ) {
} else {
}
break;
case NONSTATIC_SHORT:
if( nonstatic_short_space_count > 0 ) {
} else {
}
break;
case NONSTATIC_WORD:
if( nonstatic_word_space_count > 0 ) {
} else {
}
break;
case NONSTATIC_DOUBLE:
break;
default:
}
}
// Size of instances
int instance_size;
assert(instance_size == align_object_size(align_size_up((instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize), wordSize) / wordSize), "consistent layout helper value");
// Number of non-static oop map blocks allocated at end of klass.
const unsigned int total_oop_map_count =
// Compute reference type
if (super_klass() == NULL) {
} else {
}
// We can now create the basic klassOop for this klass
rt, host_klass,
CHECK_(nullHandle));
"sanity");
// Fill in information already parsed
// Not yet: supers are done below to support the new subtype-checking fields
//this_klass->set_super(super_klass());
if (has_final_method) {
}
// The instanceKlass::_methods_jmethod_ids cache and the
// instanceKlass::_methods_cached_itable_indices cache are
// both managed on the assumption that the initial cache
// size is equal to the number of methods in the class. If
// that changes, then instanceKlass::idnum_can_increment()
// has to be changed accordingly.
if (is_anonymous()) // I am well known to myself
// Set up methodOop::intrinsic_id as soon as we know the names of methods.
// (We used to do this lazily, but now we query it in Rewriter,
// which is eagerly done for every method, so we might as well do it now,
// when everything is fresh in memory.)
}
}
if (cached_class_file_bytes != NULL) {
// JVMTI: we have an instanceKlass now, tell it about the cached bytes
}
// Miranda methods
if ((num_miranda_methods > 0) ||
// if this class introduced new miranda methods or
// super class exists and this class inherited miranda methods
) {
}
// Fill in field values obtained by parse_classfile_attributes
// VerifyOops believes that once this has been set, the object is completely loaded.
// Compute transitive closure of interfaces this class implements
// Fill in information needed to compute superclasses.
// Initialize itable offset tables
// Do final class setup
// Fill in has_finalizer, has_vanilla_constructor, and layout_helper
// reinitialize modifiers, using the InnerClasses attribute
// check if this class can access its super class
// check if this class can access its superinterfaces
// check if this class overrides any final method
// check that if this class is an interface then it doesn't have static methods
if (this_klass->is_interface()) {
}
// Allocate mirror and initialize static fields
false /* not shared class */);
if (TraceClassLoading) {
// print in a single call to reduce interleaving of output
} else if (class_loader.is_null()) {
if (THREAD->is_Java_thread()) {
} else {
}
} else {
}
}
if (TraceClassResolution) {
// print out the superclass.
tty->print("RESOLVE %s %s (super)\n", from, instanceKlass::cast(this_klass->java_super())->external_name());
}
// print out each of the interface classes referred to by this class.
if (!local_interfaces.is_null()) {
for (int i = 0; i < length; i++) {
}
}
}
#ifndef PRODUCT
if( PrintCompactFieldsSavings ) {
this_klass->external_name());
} else if( nonstatic_field_size > orig_nonstatic_field_size ) {
this_klass->external_name());
}
}
#endif
// preserve result across HandleMark
}
// Create new handle outside HandleMark
return this_klass;
}
unsigned int
unsigned int nonstatic_oop_map_count,
int first_nonstatic_oop_offset) {
unsigned int map_count =
if (nonstatic_oop_map_count > 0) {
// We have oops to add to map
if (map_count == 0) {
} else {
// Check whether we should add a new map block or whether the last one can
// be extended
if (next_offset == first_nonstatic_oop_offset) {
// There is no gap bettwen superklass's last oop field and first
// local oop field, merge maps.
nonstatic_oop_map_count -= 1;
} else {
// Superklass didn't end with a oop field, add extra maps
}
}
}
return map_count;
}
unsigned int nonstatic_oop_map_count,
int* nonstatic_oop_offsets,
unsigned int* nonstatic_oop_counts) {
if (super_count > 0) {
// Copy maps from superklass
for (unsigned int i = 0; i < super_count; ++i) {
*this_oop_map++ = *super_oop_map++;
}
}
if (nonstatic_oop_map_count > 0) {
// The counts differ because there is no gap between superklass's last oop
// field and the first local oop field. Extend the last oop map copied
// from the superklass instead of creating new one.
this_oop_map--;
this_oop_map++;
}
// Add new map blocks, fill them
while (nonstatic_oop_map_count-- > 0) {
this_oop_map++;
}
this_oop_map, "sanity");
}
}
// Check if this klass has an empty finalize method (i.e. one with return bytecode only),
// in which case we don't have to register objects as finalizable
if (!_has_empty_finalizer) {
if (_has_finalizer ||
k->set_has_finalizer();
}
}
#ifdef ASSERT
bool f = false;
if (m != NULL && !m->is_empty_method()) {
f = true;
}
#endif
// Check if this klass supports the java.lang.Cloneable interface
if (SystemDictionary::Cloneable_klass_loaded()) {
k->set_is_cloneable();
}
}
// Check if this klass has a vanilla default constructor
// java.lang.Object has empty default constructor
} else {
}
#ifdef ASSERT
bool v = false;
), vmSymbols::void_method_signature());
v = true;
}
}
#endif
}
// If it cannot be fast-path allocated, set a bit in the layout helper.
// See documentation of instanceKlass::can_be_fastpath_allocated().
if ((!RegisterFinalizersAtInit && k->has_finalizer())
|| k->is_abstract() || k->is_interface()
&& k->class_loader() == NULL)
|| k->size_helper() >= FastAllocateSizeLimit) {
// Forbid fast-path allocation.
k->set_layout_helper(lh);
}
}
// utility method for appending and array with check for duplicates
// iterate over new interfaces
// check for duplicates
bool duplicate = false;
for (int j = 0; j < index; j++) {
duplicate = true;
break;
}
}
// add new interface
if (!duplicate) {
}
}
}
objArrayHandle ClassFileParser::compute_transitive_interfaces(instanceKlassHandle super, objArrayHandle local_ifs, TRAPS) {
// Compute maximum size for transitive interfaces
int max_transitive_size = 0;
int super_size = 0;
// Add superclass transitive interfaces size
}
// Add local interfaces' super interfaces
for (int i = 0; i < local_size; i++) {
}
// Finally add local interfaces
// Construct array
if (max_transitive_size == 0) {
// no interfaces, use canonicalized array
} else if (max_transitive_size == super_size) {
// no new local interfaces added, share superklass' transitive interface array
} else if (max_transitive_size == local_size) {
// only local interfaces added, share local interface array
} else {
objArrayOop new_objarray = oopFactory::new_system_objArray(max_transitive_size, CHECK_(nullHandle));
int index = 0;
// Copy down from superclass
}
// Copy down from local interfaces' superinterfaces
}
// Finally add local interfaces
// Check if duplicates were removed
if (index != max_transitive_size) {
for (int i = 0; i < index; i++) {
new_result->obj_at_put(i, e);
}
}
}
return result;
}
"class %s cannot access its superclass %s",
);
return;
}
}
for (int i = lng - 1; i >= 0; i--) {
"class %s cannot access its superinterface %s",
);
return;
}
}
}
// go thru each method and check if it overrides a final method
// skip private, static and <init> methods
if ((!m->is_private()) &&
(!m->is_static()) &&
while (k != NULL) {
// skip supers that don't have final methods.
if (k->klass_part()->has_final_method()) {
// lookup a matching method in the super class hierarchy
break; // didn't find any match; get out
}
// matching method in super is final
super_m->method_holder(),
super_m->method_holder(),
super_m->access_flags(), false))
// this class can access super final method and therefore override
) {
"class %s overrides final method %s.%s",
name->as_C_string(),
);
return;
}
// continue to look from super_m's holder's super.
continue;
}
k = k->klass_part()->super();
}
}
}
}
// assumes that this_klass is an interface
// if m is static and not the init method, throw a verify error
"Illegal static method %s in interface %s",
m->name()->as_C_string(),
);
return;
}
}
}
// utility methods for format checking
if (!_need_verify) { return; }
if ((is_abstract && is_final) ||
(is_interface && !is_abstract) ||
"Illegal class modifiers in class %s: 0x%X",
);
return;
}
}
return ((is_public && is_protected) ||
(is_public && is_private) ||
(is_protected && is_private));
}
return (major >= JAVA_MIN_SUPPORTED_VERSION) &&
(major <= max_version) &&
((major != max_version) ||
}
if (!_need_verify) { return; }
bool is_illegal = false;
if (is_interface) {
(major_gte_15 && is_enum)) {
is_illegal = true;
}
} else { // not interface
is_illegal = true;
}
}
if (is_illegal) {
"Illegal field modifiers in class %s: 0x%X",
return;
}
}
if (!_need_verify) { return; }
bool is_illegal = false;
if (is_interface) {
is_illegal = true;
}
} else { // not interface
if (is_initializer) {
is_illegal = true;
}
} else { // not initializer
if (is_abstract) {
is_illegal = true;
}
}
if (has_illegal_visibility(flags)) {
is_illegal = true;
}
}
}
if (is_illegal) {
"Method %s in class %s has illegal modifiers: 0x%X",
return;
}
}
int i = 0;
for (int k=0; k<count; k++) {
// For an unsigned char v,
// (v | v - 1) is < 128 (highest bit 0) for 0 < v < 128;
// (v | v - 1) is >= 128 (highest bit 1) for v == 0 or v >= 128.
if (res >= 128) break;
i += 4;
}
for(; i < length; i++) {
unsigned short c;
// no embedded zeros
guarantee_property((buffer[i] != 0), "Illegal UTF8 string in constant pool in class file %s", CHECK);
if(buffer[i] < 128) {
continue;
}
i += 5;
continue;
}
}
switch (buffer[i] >> 4) {
default: break;
case 0x8: case 0x9: case 0xA: case 0xB: case 0xF:
case 0xC: case 0xD: // 110xxxxx 10xxxxxx
i++;
c += buffer[i] & 0x3F;
// for classes with major > 47, c must a null or a character in its shortest form
break;
}
}
case 0xE: // 1110xxxx 10xxxxxx 10xxxxxx
i += 2;
// for classes with major > 47, c must be in its shortest form
break;
}
}
} // end of switch
} // end of for
}
// Checks if name is a legal class name.
if (!_need_verify || _relax_verify) { return; }
bool legal = false;
if (length > 0) {
char* p;
if (bytes[0] == JVM_SIGNATURE_ARRAY) {
} else if (_major_version < JAVA_1_5_VERSION) {
if (bytes[0] != '<') {
}
} else {
// 4900761: relax the constraints based on JSR202 spec
// Class names may be drawn from the entire Unicode character set.
// Identifiers between '/' must be unqualified names.
// The utf8 string has been verified when parsing cpool entries.
}
}
if (!legal) {
"Illegal class name \"%s\" in class file %s", bytes,
);
return;
}
}
// Checks if name is a legal field name.
if (!_need_verify || _relax_verify) { return; }
bool legal = false;
if (length > 0) {
if (_major_version < JAVA_1_5_VERSION) {
if (bytes[0] != '<') {
}
} else {
// 4881221: relax the constraints based on JSR202 spec
}
}
if (!legal) {
"Illegal field name \"%s\" in class %s", bytes,
);
return;
}
}
// Checks if name is a legal method name.
if (!_need_verify || _relax_verify) { return; }
bool legal = false;
if (length > 0) {
if (bytes[0] == '<') {
legal = true;
}
} else if (_major_version < JAVA_1_5_VERSION) {
char* p;
} else {
// 4881221: relax the constraints based on JSR202 spec
}
}
if (!legal) {
"Illegal method name \"%s\" in class %s", bytes,
);
return;
}
}
// Checks if signature is a legal field signature.
if (!_need_verify) { return; }
}
}
// Checks if signature is a legal method signature.
// Returns number of parameters
if (!_need_verify) {
// make sure caller's args_size will be less than 0 even for non-static
// method so it will be recomputed in compute_size_of_parameters().
return -2;
}
unsigned int args_size = 0;
char* nextp;
// The first character must be a '('
if ((length > 0) && (*p++ == JVM_SIGNATURE_FUNC)) {
length--;
// Skip over legal field signatures
args_size++;
if (p[0] == 'J' || p[0] == 'D') {
args_size++;
}
p = nextp;
}
// The first non-signature thing better be a ')'
if ((length > 0) && (*p++ == JVM_SIGNATURE_ENDFUNC)) {
length--;
// All internal methods must return void
return args_size;
}
} else {
// Now we better just have a return value
return args_size;
}
}
}
}
// Report error
return 0;
}
// Unqualified names may not contain the characters '.', ';', '[', or '/'.
// Method names also may not contain the characters '<' or '>', unless <init>
// or <clinit>. Note that method names may not be <init> or <clinit> in this
// method. Because these names have been checked as special cases before
// calling this method in verify_legal_method_name.
ch = *p;
if (ch < 128) {
p++;
return false; // do not permit '.', ';', or '['
}
return false; // do not permit '/' unless it's class name
}
return false; // do not permit '<' or '>' in method names
}
} else {
p = tmp_p;
}
}
return true;
}
// Take pointer to a string. Skip over the longest part of the string that could
// be taken as a fieldname. Allow '/' if slash_ok is true.
// Return a pointer to just past the fieldname.
// Return NULL if no fieldname at all was found, or in the case of slash_ok
// being true, we saw consecutive slashes (meaning we were looking for a
// qualified path but found something that was badly-formed).
char* p;
char* old_p = p;
ch = *p;
if (ch < 128) {
p++;
// quick check for ascii
last_is_slash = false;
continue;
}
if (last_is_slash) {
return NULL; // Don't permit consecutive slashes
}
last_is_slash = true;
continue;
}
} else {
p = tmp_p;
last_is_slash = false;
// Check if ch is Java identifier start or is Java identifier part
// 4672820: call java.lang.Character methods directly without generating separate tables.
// return value
// Set up the arguments to isJavaIdentifierStart and isJavaIdentifierPart
// public static boolean isJavaIdentifierStart(char ch);
&args,
THREAD);
if (HAS_PENDING_EXCEPTION) {
return 0;
}
if (result.get_jboolean()) {
continue;
}
if (not_first_ch) {
// public static boolean isJavaIdentifierPart(char ch);
&args,
THREAD);
if (HAS_PENDING_EXCEPTION) {
return 0;
}
if (result.get_jboolean()) {
continue;
}
}
}
}
return (not_first_ch) ? p : NULL;
}
// Take pointer to a string. Skip over the longest part of the string that could
// be taken as a field signature. Allow "void" if void_ok.
// Return a pointer to just past the signature.
// Return NULL if no legal signature is found.
bool void_ok,
unsigned int length,
TRAPS) {
unsigned int array_dim = 0;
while (length > 0) {
switch (signature[0]) {
case JVM_SIGNATURE_BOOLEAN:
case JVM_SIGNATURE_BYTE:
case JVM_SIGNATURE_CHAR:
case JVM_SIGNATURE_SHORT:
case JVM_SIGNATURE_INT:
case JVM_SIGNATURE_FLOAT:
case JVM_SIGNATURE_LONG:
case JVM_SIGNATURE_DOUBLE:
return signature + 1;
case JVM_SIGNATURE_CLASS: {
if (_major_version < JAVA_1_5_VERSION) {
// Skip over the class name if one is there
// The next character better be a semicolon
return p + 1;
}
} else {
// 4900761: For class version > 48, any unicode is allowed in class name.
length--;
signature++;
if (signature[0] == '.') {
classfile_parse_error("Class name contains illegal character '.' in descriptor in class file %s", CHECK_0);
}
length--;
signature++;
}
}
return NULL;
}
case JVM_SIGNATURE_ARRAY:
array_dim++;
if (array_dim > 255) {
// 4277370: array descriptor is valid only if it represents 255 or fewer dimensions.
classfile_parse_error("Array type descriptor has more than 255 dimensions in class file %s", CHECK_0);
}
// The rest of what's there better be a legal signature
signature++;
length--;
void_ok = false;
break;
default:
return NULL;
}
}
return NULL;
}