/*
* 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/classFileStream.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/stackMapTable.hpp"
#include "classfile/stackMapFrame.hpp"
#include "classfile/stackMapTableFormat.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verifier.hpp"
#include "classfile/vmSymbols.hpp"
#include "interpreter/bytecodes.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/oop.inline.hpp"
#include "oops/typeArrayOop.hpp"
#include "runtime/fieldDescriptor.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/orderAccess.hpp"
#ifdef TARGET_ARCH_x86
# include "bytes_x86.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "bytes_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "bytes_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "bytes_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "bytes_ppc.hpp"
#endif
// Access to external entry for VerifyClassCodes - old byte code verifier
extern "C" {
}
static void* verify_byte_codes_fn() {
if (_verify_byte_codes_fn == NULL) {
}
}
return (void*)_verify_byte_codes_fn;
}
// Methods in Verifier
}
bool need_verify =
// verifyAll
// verifyRemote
return !need_verify;
}
bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool should_verify_class, TRAPS) {
// If the class should be verified, first see if we can use the split
// verifier. If not, or if verification fails and FailOverToOldVerifier
// is set, then call the inference verifier.
if (TraceClassInitialization) {
}
if (UseSplitVerifier &&
if (can_failover && !HAS_PENDING_EXCEPTION &&
if (TraceClassInitialization || VerboseVerification) {
"Fail over class verification to old verifier for: %s", klassName);
}
}
if (exception_name != NULL) {
}
} else {
}
if (TraceClassInitialization || VerboseVerification) {
if (HAS_PENDING_EXCEPTION) {
} else if (exception_name != NULL) {
}
}
}
if (HAS_PENDING_EXCEPTION) {
return false; // use the existing exception
} else if (exception_name == NULL) {
return true; // verifcation succeeded
} else { // VerifyError or ClassFormatError to be created and thrown
// If the class being verified is the exception we're creating
// or one of it's superclasses, we're in trouble and are going
// to infinitely recurse when we try to initialize the exception.
// So bail out here by throwing the preallocated VM error.
}
}
}
}
// return if the class is a bootstrapping class
// or defineClass specified not to verify by default (flags override passed arg)
// We need to skip the following four for bootstraping
// Can not verify the bytecodes for shared classes because they have
// already been rewritten to contain constant pool cache indices,
// which the verifier can't understand.
// Shared classes shouldn't have stackmaps either.
// As of the fix for 4486457 we disable verification for all of the
// dynamically-generated bytecodes associated with the 1.4
// reflection implementation, not just those associated with
// NOTE: this is called too early in the bootstrapping process to be
// guarded by Universe::is_gte_jdk14x_version()/UseNewReflection.
(refl_magic_klass == NULL ||
);
}
void* verify_func = verify_byte_codes_fn();
if (verify_func == NULL) {
return vmSymbols::java_lang_VerifyError();
}
if (VerboseVerification) {
}
{
// ThreadToNativeFromVM takes care of changing thread_state, so safepoint
// code knows that we have left the VM
if (_is_new_verify_byte_codes_fn) {
klass->major_version());
} else {
}
}
// These numbers are chosen so that VerifyClassCodes interface doesn't need
// to be changed (still return jboolean (unsigned char)), and result is
// 1 when verification is passed.
if (result == 0) {
return vmSymbols::java_lang_VerifyError();
} else if (result == 1) {
return NULL; // verified.
} else if (result == 2) {
} else if (result == 3) {
return vmSymbols::java_lang_ClassFormatError();
} else {
return NULL;
}
}
return TypeOrigin();
}
}
}
}
}
}
}
}
}
}
void TypeOrigin::reset_frame() {
}
}
switch (_origin) {
case CF_LOCALS:
break;
case CF_STACK:
break;
case SM_LOCALS:
break;
case SM_STACK:
break;
case CONST_POOL:
break;
case SIG:
break;
case IMPLICIT:
case FRAME_ONLY:
case NONE:
default:
;
}
}
#ifdef ASSERT
} else {
}
}
#endif
if (is_valid()) {
}
}
switch (_fault) {
case INVALID_BYTECODE:
break;
case WRONG_TYPE:
} else {
}
break;
case FLAGS_MISMATCH:
"to stack map frame's.");
} else {
}
break;
case BAD_CP_INDEX:
break;
case BAD_LOCAL_INDEX:
break;
case LOCALS_SIZE_MISMATCH:
break;
case STACK_SIZE_MISMATCH:
break;
case STACK_OVERFLOW:
break;
case STACK_UNDERFLOW:
break;
case MISSING_STACKMAP:
break;
case BAD_STACKMAP:
break;
case UNKNOWN:
default:
}
}
const char* bytecode_name = "<invalid>";
} else {
bytecode_name = "<illegal>";
}
}
}
}
}
}
}
}
}
}
}
}
}
int current_offset = -1;
}
}
}
// Methods in ClassVerifier
// Create list to hold symbols in reference area.
}
ClassVerifier::~ClassVerifier() {
// Decrement the reference count for any symbols created.
s->decrement_refcount();
}
}
}
}
if (VerboseVerification) {
_klass->external_name());
}
// Check for recursive re-verification before each method.
if (was_recursively_verified()) return;
if (m->is_native() || m->is_abstract()) {
// If m is native or abstract, skip it. It is checked in class file
// parser that methods do not override a final method.
continue;
}
}
if (VerboseVerification || TraceClassInitialization) {
if (was_recursively_verified())
_klass->external_name());
}
}
_method = m; // initialize _method
if (VerboseVerification) {
}
const char* bad_type_msg = "Bad type on operand stack in %s";
class_format_error("Invalid method signature");
return;
}
// Initial stack map frame: offset is 0, stack is initially empty.
// Set initial locals
m, current_type(), CHECK_VERIFY(this));
// Scan the bytecode and map each instruction's start offset to a number.
int ex_min = code_length;
int ex_max = -1;
// Look through each item on the exception table. Each of the fields must refer
// to a legal instruction.
// Look through each entry on the local variable table and make sure
// its range of code array offsets is valid. (4169817)
if (m->has_localvariable_table()) {
}
if (VerboseVerification) {
}
RawBytecodeStream bcs(m);
// Scan the byte code linearly from the start to the end
bool no_control_flow = false; // Set to true when there is no direct control
// flow from current instruction to the next
// instruction in sequence
while (!bcs.is_last_bytecode()) {
// Check for recursive re-verification before each bytecode.
if (was_recursively_verified()) return;
// Set current frame's offset to bci
// Make sure every offset in stackmap table point to the beginning to
// an instruction. Match current_frame to stackmap_table entry with
// the same offset if exists.
no_control_flow, CHECK_VERIFY(this));
bool this_uninit = false; // Set to true when invokespecial <init> initialized 'this'
// Merge with the next instruction
{
int target;
#ifndef PRODUCT
if (VerboseVerification) {
}
#endif
// Make sure wide instruction is in correct format
/* Unreachable? RawBytecodeStream's raw_next() returns 'illegal'
* if we encounter a wide instruction that modifies an invalid
* opcode (not one of the ones listed above) */
return;
}
}
switch (opcode) {
no_control_flow = false; break;
case Bytecodes::_aconst_null :
no_control_flow = false; break;
case Bytecodes::_iconst_m1 :
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
if (!atype.is_int_array()) {
bad_type_msg, "iaload");
return;
}
no_control_flow = false; break;
bad_type_msg, "baload");
return;
}
no_control_flow = false; break;
if (!atype.is_char_array()) {
bad_type_msg, "caload");
return;
}
no_control_flow = false; break;
if (!atype.is_short_array()) {
bad_type_msg, "saload");
return;
}
no_control_flow = false; break;
if (!atype.is_long_array()) {
bad_type_msg, "laload");
return;
}
no_control_flow = false; break;
if (!atype.is_float_array()) {
bad_type_msg, "faload");
return;
}
no_control_flow = false; break;
if (!atype.is_double_array()) {
bad_type_msg, "daload");
return;
}
no_control_flow = false; break;
if (!atype.is_reference_array()) {
bad_type_msg, "aaload");
return;
}
} else {
}
no_control_flow = false; break;
}
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
if (!atype.is_int_array()) {
bad_type_msg, "iastore");
return;
}
no_control_flow = false; break;
bad_type_msg, "bastore");
return;
}
no_control_flow = false; break;
if (!atype.is_char_array()) {
bad_type_msg, "castore");
return;
}
no_control_flow = false; break;
if (!atype.is_short_array()) {
bad_type_msg, "sastore");
return;
}
no_control_flow = false; break;
if (!atype.is_long_array()) {
bad_type_msg, "lastore");
return;
}
no_control_flow = false; break;
if (!atype.is_float_array()) {
bad_type_msg, "fastore");
return;
}
no_control_flow = false; break;
if (!atype.is_double_array()) {
bad_type_msg, "dastore");
return;
}
no_control_flow = false; break;
// more type-checking is done at runtime
if (!atype.is_reference_array()) {
bad_type_msg, "aastore");
return;
}
// 4938384: relaxed constraint in JVMS 3nd edition.
no_control_flow = false; break;
no_control_flow = false; break;
if (type.is_category1()) {
} else if (type.is_category2_2nd()) {
} else {
/* Unreachable? Would need a category2_1st on TOS
* which does not appear possible. */
bad_type_msg, "pop2");
return;
}
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
{
if (type2.is_category1()) {
} else if (type2.is_category2_2nd()) {
} else {
/* Unreachable? Would need a category2_1st at stack depth 2 with
* a category1 on TOS which does not appear possible. */
return;
}
no_control_flow = false; break;
}
if (type.is_category1()) {
} else if (type.is_category2_2nd()) {
} else {
/* Unreachable? Would need a category2_1st on TOS which does not
* appear possible. */
bad_type_msg, "dup2");
return;
}
no_control_flow = false; break;
{
if (type.is_category1()) {
} else if (type.is_category2_2nd()) {
} else {
/* Unreachable? Would need a category2_1st on TOS which does
* not appear possible. */
bad_type_msg, "dup2_x1");
return;
}
no_control_flow = false; break;
}
{
if (type.is_category1()) {
} else if (type.is_category2_2nd()) {
} else {
/* Unreachable? Would need a category2_1st on TOS which does
* not appear possible. */
bad_type_msg, "dup2_x2");
return;
}
if (type3.is_category1()) {
} else if (type3.is_category2_2nd()) {
} else {
/* Unreachable? Would need a category2_1st on TOS after popping
* appear possible. */
bad_type_msg, "dup2_x2");
return;
}
no_control_flow = false; break;
}
no_control_flow = false; break;
// fall through
no_control_flow = false; break;
// fall through
no_control_flow = false; break;
no_control_flow = false; break;
// fall through
no_control_flow = false; break;
// fall through
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
no_control_flow = false; break;
case Bytecodes::_if_icmpeq:
case Bytecodes::_if_icmpne:
case Bytecodes::_if_icmplt:
case Bytecodes::_if_icmpge:
case Bytecodes::_if_icmpgt:
case Bytecodes::_if_icmple:
// fall through
no_control_flow = false; break;
case Bytecodes::_if_acmpeq :
case Bytecodes::_if_acmpne :
// fall through
case Bytecodes::_ifnonnull :
no_control_flow = false; break;
no_control_flow = true; break;
no_control_flow = true; break;
case Bytecodes::_tableswitch :
case Bytecodes::_lookupswitch :
&stackmap_table, CHECK_VERIFY(this));
no_control_flow = true; break;
¤t_frame, CHECK_VERIFY(this));
no_control_flow = true; break;
¤t_frame, CHECK_VERIFY(this));
no_control_flow = true; break;
¤t_frame, CHECK_VERIFY(this));
no_control_flow = true; break;
¤t_frame, CHECK_VERIFY(this));
no_control_flow = true; break;
¤t_frame, CHECK_VERIFY(this));
no_control_flow = true; break;
"Method expects a return value");
return;
}
// Make sure "this" has been initialized if current method is an
// <init>
"Constructor must call super() or this() "
"before return");
return;
}
no_control_flow = true; break;
case Bytecodes::_getstatic :
case Bytecodes::_putstatic :
no_control_flow = false; break;
case Bytecodes::_invokevirtual :
case Bytecodes::_invokespecial :
case Bytecodes::_invokestatic :
no_control_flow = false; break;
case Bytecodes::_invokeinterface :
case Bytecodes::_invokedynamic :
no_control_flow = false; break;
{
if (!new_class_type.is_object()) {
"Illegal new instruction");
return;
}
no_control_flow = false; break;
}
no_control_flow = false; break;
case Bytecodes::_anewarray :
no_control_flow = false; break;
case Bytecodes::_arraylength :
bad_type_msg, "arraylength");
}
no_control_flow = false; break;
case Bytecodes::_checkcast :
{
no_control_flow = false; break;
}
case Bytecodes::_instanceof : {
no_control_flow = false; break;
}
case Bytecodes::_monitorenter :
case Bytecodes::_monitorexit :
no_control_flow = false; break;
case Bytecodes::_multianewarray :
{
if (!new_array_type.is_array()) {
"Illegal constant pool index in multianewarray instruction");
return;
}
"Illegal dimension in multianewarray instruction: %d", dim);
return;
}
for (int i = 0; i < dim; i++) {
}
no_control_flow = false; break;
}
no_control_flow = true; break;
default:
// We only need to check the valid bytecodes in class file.
// And jsr and ret are not in the new class file format in JDK1.5.
"Bad instruction: %02x", opcode);
no_control_flow = false;
return;
} // end switch
} // end Merge with the next instruction
// Look for possible jump target in exception handlers and see if it
// matches current_frame
}
} // end while
// Make sure that control flow does not fall through end of the method
if (!no_control_flow) {
"Control flow falls through code end");
return;
}
}
RawBytecodeStream bcs(m);
while (!bcs.is_last_bytecode()) {
} else {
}
} else {
return NULL;
}
}
return code_data;
}
void ClassVerifier::verify_exception_handler_table(u4 code_length, char* code_data, int& min, int& max, TRAPS) {
for(int i = 0; i < exlength; i++) {
//reacquire the table in case a GC happened
return;
}
return;
}
}
return;
}
if (catch_type_index != 0) {
catch_type, this, CHECK_VERIFY(this));
if (!is_subclass) {
// 4286534: should throw VerifyError according to recent spec change
"Catch type is not a subclass "
"of Throwable in exception handler %d", handler_pc);
return;
}
}
}
}
if (localvariable_table_length > 0) {
for (int i = 0; i < localvariable_table_length; i++) {
"Illegal local variable table start_pc %d", start_bci);
return;
}
if (end_bci != code_length) {
return;
}
}
}
}
}
bool no_control_flow, TRAPS) {
"Expecting a stack map frame");
return 0;
}
if (this_offset == bci) {
// See if current stack map can be assigned to the frame in table.
// current_frame is the stackmap frame got from the last instruction.
// If matched, current_frame will be updated by this method.
if (!matches) {
// report type error
return 0;
}
} else if (this_offset < bci) {
// current_offset should have met this_offset.
return 0;
}
} else if (no_control_flow) {
return 0;
}
return stackmap_index;
}
void ClassVerifier::verify_exception_handler_targets(u2 bci, bool this_uninit, StackMapFrame* current_frame,
for(int i = 0; i < exlength; i++) {
//reacquire the table in case a GC happened
if (catch_type_index != 0) {
// We know that this index refers to a subclass of Throwable
} else {
}
if (!matches) {
"exception handler %d", handler_pc);
return;
}
}
}
}
void ClassVerifier::verify_cp_index(
"Illegal constant pool index %d in class %s",
return;
}
}
void ClassVerifier::verify_cp_type(
// In some situations, bytecode rewriting may occur while we're verifying.
// In this case, a constant pool cache exists and some indices refer to that
// instead. Be sure we don't pick up such indices by accident.
// We must check was_recursively_verified() before we get here.
"Illegal type at constant pool entry %d in class %s",
return;
}
}
"Illegal type at constant pool entry %d in class %s",
return;
}
}
ctx.reset_frames();
#ifdef ASSERT
#endif // ndef ASSERT
}
}
}
// Get current loader and protection domain first.
return SystemDictionary::resolve_or_fail(
true, CHECK_NULL);
}
bool is_method) {
// If target class isn't a super class of this class, we don't worry about this case
return false;
}
// Check if the specified method or field is protected
if (is_method) {
if (m != NULL && m->is_protected()) {
return true;
}
}
} else {
return true;
}
}
}
return false;
}
void ClassVerifier::verify_ldc(
unsigned int types;
// Note: The class file parser already verified the legality of
// MethodHandle and MethodType constants.
}
} else {
}
} else if (tag.is_method_handle()) {
} else if (tag.is_method_type()) {
} else {
/* Unreachable? verify_cp_type has already validated the cp type. */
return;
}
}
void ClassVerifier::verify_switch(
// 4639449 & 4647081: padding bytes must be 0
if(*(bcp + padding_offset) != 0) {
"Nonzero padding byte in lookswitch or tableswitch");
return;
}
}
"low must be less than or equal to high in tableswitch");
return;
}
if (keys < 0) {
return;
}
delta = 1;
} else {
if (keys < 0) {
"number of keys in lookupswitch less than 0");
return;
}
delta = 2;
// Make sure that the lookupswitch items are sorted
for (int i = 0; i < (keys - 1); i++) {
"Bad lookupswitch instruction");
return;
}
}
}
for (int i = 0; i < keys; i++) {
// Because check_jump_target() may safepoint, the bytecode could have
// moved, which means 'aligned_bcp' is no good and needs to be recalculated.
}
}
bool ClassVerifier::name_in_supers(
return true;
}
}
return false;
}
TRAPS) {
// Get field name and signature
"Invalid signature for field in class %s referenced "
return;
}
// Get referenced class type
if (!ref_class_type.is_object()) {
/* Unreachable? Class file parser verifies Fieldref contents */
"Expecting reference to class in class %s at constant pool index %d",
return;
}
"buffer type must match VerificationType size");
// If we make a VerificationType[2] array directly, the compiler calls
// to the c-runtime library to do the allocation instead of just
// stack allocating it. Plus it would run constructors. This shows up
// in performance profiles.
int n = change_sig_to_verificationType(
bool is_assignable;
case Bytecodes::_getstatic: {
for (int i = 0; i < n; i++) {
}
break;
}
case Bytecodes::_putstatic: {
for (int i = n - 1; i >= 0; i--) {
}
break;
}
target_class_type, CHECK_VERIFY(this));
for (int i = 0; i < n; i++) {
}
goto check_protected;
}
for (int i = n - 1; i >= 0; i--) {
}
// The JVMS 2nd edition allows field initialization before the superclass
// initializer, if the field is defined within the current class.
}
stack_object_type, this, CHECK_VERIFY(this));
if (!is_assignable) {
"Bad type on operand stack in putfield");
return;
}
}
if (_this_type == stack_object_type)
break; // stack_object_type must be assignable to _current_class_type
// stack_object_type must be assignable to _current_class_type since:
// 1. stack_object_type must be assignable to ref_class.
// 2. ref_class must be _current_class or a subclass of it. It can't
// be a superclass of it. See revised JVMS 5.4.4.
break;
field_sig, false)) {
// It's protected access, check if stack object is assignable to
// current class.
stack_object_type, this, CHECK_VERIFY(this));
if (!is_assignable) {
"Bad access to protected data in getfield");
return;
}
}
break;
}
default: ShouldNotReachHere();
}
}
void ClassVerifier::verify_invoke_init(
// The method must be an <init> method of this class or its superclass
"Bad <init> method call");
return;
}
*this_uninit = true;
} else if (type.is_uninitialized()) {
/* Unreachable? Stack map parsing ensures valid type and new
* instructions have a valid BCI. */
"Expecting new instruction");
return;
}
// The method must be an <init> method of the indicated class
"Call to wrong <init> method");
return;
}
// According to the VM spec, if the referent class is a superclass of the
// current class, and is in a different runtime package, and the method is
// protected, then the objectref must be the current class or a subclass
// of the current class.
objectref_type, this, CHECK_VERIFY(this));
if (!assignable) {
"Bad access to protected <init> method");
return;
}
}
}
} else {
"Bad operand type when invoking <init>");
return;
}
}
// Make sure the constant pool item is the right type
? 1 << JVM_CONSTANT_InvokeDynamic
: 1 << JVM_CONSTANT_Methodref);
// Get method name and signature
"Invalid method signature in class %s referenced "
return;
}
// Get referenced class type
if (!EnableInvokeDynamic ||
"invokedynamic instructions not enabled in this JVM" :
"invokedynamic instructions not supported by this class file version"),
_klass->external_name());
return;
}
} else {
}
// For a small signature length, we just allocate 128 bytes instead
// of parsing the signature once to find its size.
// -3 is for '(', ')' and return descriptor; multiply by 2 is for
"buffer type must match VerificationType size");
// If we make a VerificationType[128] array directly, the compiler calls
// to the c-runtime library to do the allocation instead of just
// stack allocating it. Plus it would run constructors. This shows up
// in performance profiles.
if (size > 128) {
// Long and double occupies two slots here.
} else{
}
int sig_i = 0;
while (!sig_stream.at_return_type()) {
sig_stream.next();
}
#ifdef ASSERT
{
assert(nargs <= (method_sig->utf8_length() - 3) * 2, "estimate of max size isn't conservative enough");
}
#endif
// Check instruction operands
// 4905268: count operand in invokeinterface should be nargs+1, not nargs.
// JSR202 spec: The count operand of an invokeinterface instruction is valid if it is
// the difference between the size of the operand stack before and after the instruction
// executes.
"Inconsistent args count operand in invokeinterface");
return;
}
if (*(bcp+4) != 0) {
"Fourth operand byte of invokeinterface must be zero");
return;
}
}
"Third and fourth operand bytes of invokedynamic must be zero");
return;
}
}
// Make sure <init> can only be invoked by invokespecial
"Illegal call to internal method");
return;
}
current_type(), this, CHECK_VERIFY(this));
if (!subtype) {
"Bad invokespecial instruction: "
"current class isn't assignable to reference class.");
return;
}
}
// Match method descriptor with operand stack
}
// Check objectref on operand stack
} else { // other methods
// Ensures that target class is assignable to method class.
if (current_type() != stack_object_type) {
// See the comments in verify_field_instructions() for
// the rationale behind this.
if (is_protected_access(
// It's protected access, check if stack object is
// assignable to current class.
stack_object_type, this, CHECK_VERIFY(this));
if (!is_assignable) {
// Special case: arrays pretend to implement public Object
// clone().
} else {
"Bad access to protected data in invokevirtual");
return;
}
}
}
}
}
} else {
}
}
}
// Push the result type.
// <init> method must have a void return type
/* Unreachable? Class file parser verifies that methods with '<' have
* void return */
"Return type must be void in <init> method");
return;
}
int n = change_sig_to_verificationType(
for (int i = 0; i < n; i++) {
}
}
}
const char* from_bt[] = {
};
return VerificationType::bogus_type();
}
// from_bt[index] contains the array signature which has a length of 2
}
void ClassVerifier::verify_anewarray(
int length;
char* arr_sig_str;
// add one dimension to component
arr_sig_str[0] = '[';
} else { // it's an object or interface
// add one dimension to component with 'L' prepended and ';' postpended.
arr_sig_str[0] = '[';
}
}
}
}
}
}
}
}
}
}
}
}
}
void ClassVerifier::verify_return_value(
"Method expects a return value");
return;
}
if (!match) {
"Bad return type");
return;
}
}
// The verifier creates symbols which are substrings of Symbols.
// These are stored in the verifier until the end of verification so that
// they can be reference counted.
return sym;
}
return sym;
}