void StackMapFrame::set_local_2( int32_t index, VerificationType type1, VerificationType type2, TRAPS) { assert(type1.is_long() || type1.is_double(), "must be long/double"); assert(type2.is_long2() || type2.is_double2(), "must be long/double_2"); if (index >= _max_locals - 1) { verifier()->verify_error( ErrorContext::bad_local_index(_offset, index), "Local variable table overflow"); return; } // If type at index+1 is double or long, set the next location to be unusable if (_locals[index+1].is_double() || _locals[index+1].is_long()) { assert((index + 2) < _locals_size, "Local variable table overflow"); _locals[index + 2] = VerificationType::bogus_type(); } // If type at index is double_2 or long_2, set the previous location to be unusable if (_locals[index].is_double2() || _locals[index].is_long2()) { assert(index >= 1, "Local variable table underflow"); _locals[index - 1] = VerificationType::bogus_type(); } _locals[index] = type1; _locals[index+1] = type2; if (index >= _locals_size - 1) { #ifdef ASSERT for (int i=_locals_size; i<index; i++) { assert(_locals[i] == VerificationType::bogus_type(), "holes must be bogus type"); } #endif _locals_size = index + 2; } }
inline void push_stack_2( VerificationType type1, VerificationType type2, TRAPS) { assert(type1.is_long() || type1.is_double(), "must be long/double"); assert(type2.is_long2() || type2.is_double2(), "must be long/double_2"); if (_stack_size >= _max_stack - 1) { verifier()->verify_error( ErrorContext::stack_overflow(_offset, this), "Operand stack overflow"); return; } _stack[_stack_size++] = type1; _stack[_stack_size++] = type2; }
// Push type into stack type array. inline void push_stack(VerificationType type, TRAPS) { assert(!type.is_check(), "Must be a real type"); if (_stack_size >= _max_stack) { verifier()->verify_error( ErrorContext::stack_overflow(_offset, this), "Operand stack overflow"); return; } _stack[_stack_size++] = type; }
// Pop and return the top type on stack type array after verifying it // is assignable to type. inline VerificationType pop_stack(VerificationType type, TRAPS) { if (_stack_size != 0) { VerificationType top = _stack[_stack_size - 1]; bool subtype = type.is_assignable_from( top, verifier(), CHECK_(VerificationType::bogus_type())); if (subtype) { --_stack_size; return top; } } return pop_stack_ex(type, THREAD); }
void StackMapFrame::get_local_2( int32_t index, VerificationType type1, VerificationType type2, TRAPS) { assert(type1.is_long() || type1.is_double(), "must be long/double"); assert(type2.is_long2() || type2.is_double2(), "must be long/double_2"); if (index >= _locals_size - 1) { verifier()->verify_error( ErrorContext::bad_local_index(_offset, index), "get long/double overflows locals"); return; } bool subtype = type1.is_assignable_from(_locals[index], verifier(), CHECK); if (!subtype) { verifier()->verify_error( ErrorContext::bad_type(_offset, TypeOrigin::local(index, this), TypeOrigin::implicit(type1)), "Bad local variable type"); } else { subtype = type2.is_assignable_from(_locals[index + 1], verifier(), CHECK); if (!subtype) { /* Unreachable? All local store routines convert a split long or double * into a TOP during the store. So we should never end up seeing an * orphaned half. */ verifier()->verify_error( ErrorContext::bad_type(_offset, TypeOrigin::local(index + 1, this), TypeOrigin::implicit(type2)), "Bad local variable type"); } } }
VerificationType StackMapFrame::set_locals_from_arg( const methodHandle m, VerificationType thisKlass, TRAPS) { SignatureStream ss(m->signature()); int init_local_num = 0; if (!m->is_static()) { init_local_num++; // add one extra argument for instance method if (m->name() == vmSymbols::object_initializer_name() && thisKlass.name() != vmSymbols::java_lang_Object()) { _locals[0] = VerificationType::uninitialized_this_type(); _flags |= FLAG_THIS_UNINIT; } else { _locals[0] = thisKlass; } } // local num may be greater than size of parameters because long/double occupies two slots while(!ss.at_return_type()) { init_local_num += _verifier->change_sig_to_verificationType( &ss, &_locals[init_local_num], CHECK_VERIFY_(verifier(), VerificationType::bogus_type())); ss.next(); } _locals_size = init_local_num; switch (ss.type()) { case T_OBJECT: case T_ARRAY: { Symbol* sig = ss.as_symbol(CHECK_(VerificationType::bogus_type())); // Create another symbol to save as signature stream unreferences // this symbol. Symbol* sig_copy = verifier()->create_temporary_symbol(sig, 0, sig->utf8_length(), CHECK_(VerificationType::bogus_type())); assert(sig_copy == sig, "symbols don't match"); return VerificationType::reference_type(sig_copy); } case T_INT: return VerificationType::integer_type(); case T_BYTE: return VerificationType::byte_type(); case T_CHAR: return VerificationType::char_type(); case T_SHORT: return VerificationType::short_type(); case T_BOOLEAN: return VerificationType::boolean_type(); case T_FLOAT: return VerificationType::float_type(); case T_DOUBLE: return VerificationType::double_type(); case T_LONG: return VerificationType::long_type(); case T_VOID: return VerificationType::bogus_type(); default: ShouldNotReachHere(); } return VerificationType::bogus_type(); }
bool VerificationType::is_reference_assignable_from( const VerificationType& from, ClassVerifier* context, bool from_field_is_protected, TRAPS) const { instanceKlassHandle klass = context->current_class(); if (from.is_null()) { // null is assignable to any reference return true; } else if (is_null()) { return false; } else if (name() == from.name()) { return true; } else if (is_object()) { // We need check the class hierarchy to check assignability if (name() == vmSymbols::java_lang_Object()) { // any object or array is assignable to java.lang.Object return true; } if (DumpSharedSpaces && SystemDictionaryShared::add_verification_constraint(klass(), name(), from.name(), from_field_is_protected, from.is_array(), from.is_object())) { // If add_verification_constraint() returns true, the resolution/check should be // delayed until runtime. return true; } return resolve_and_check_assignability(klass(), name(), from.name(), from_field_is_protected, from.is_array(), from.is_object(), THREAD); } else if (is_array() && from.is_array()) { VerificationType comp_this = get_component(context, CHECK_false); VerificationType comp_from = from.get_component(context, CHECK_false); if (!comp_this.is_bogus() && !comp_from.is_bogus()) { return comp_this.is_component_assignable_from(comp_from, context, from_field_is_protected, CHECK_false); } } return false; }
VerificationType StackMapFrame::pop_stack_ex(VerificationType type, TRAPS) { if (_stack_size <= 0) { verifier()->verify_error(_offset, "Operand stack underflow"); return VerificationType::bogus_type(); } VerificationType top = _stack[--_stack_size]; bool subtype = type.is_assignable_from( top, verifier()->current_class(), CHECK_(VerificationType::bogus_type())); if (!subtype) { verifier()->verify_error(_offset, "Bad type on operand stack"); return VerificationType::bogus_type(); } NOT_PRODUCT( _stack[_stack_size] = VerificationType::bogus_type(); ) return top;
bool VerificationType::is_reference_assignable_from( const VerificationType& from, ClassVerifier* context, bool from_field_is_protected, TRAPS) const { instanceKlassHandle klass = context->current_class(); if (from.is_null()) { // null is assignable to any reference return true; } else if (is_null()) { return false; } else if (name() == from.name()) { return true; } else if (is_object()) { // We need check the class hierarchy to check assignability if (name() == vmSymbols::java_lang_Object()) { // any object or array is assignable to java.lang.Object return true; } Klass* obj = SystemDictionary::resolve_or_fail( name(), Handle(THREAD, klass->class_loader()), Handle(THREAD, klass->protection_domain()), true, CHECK_false); if (TraceClassResolution) { Verifier::trace_class_resolution(obj, klass()); } KlassHandle this_class(THREAD, obj); if (this_class->is_interface() && (!from_field_is_protected || from.name() != vmSymbols::java_lang_Object())) { // If we are not trying to access a protected field or method in // java.lang.Object then we treat interfaces as java.lang.Object, // including java.lang.Cloneable and java.io.Serializable. return true; } else if (from.is_object()) { Klass* from_class = SystemDictionary::resolve_or_fail( from.name(), Handle(THREAD, klass->class_loader()), Handle(THREAD, klass->protection_domain()), true, CHECK_false); if (TraceClassResolution) { Verifier::trace_class_resolution(from_class, klass()); } return InstanceKlass::cast(from_class)->is_subclass_of(this_class()); } } else if (is_array() && from.is_array()) { VerificationType comp_this = get_component(context, CHECK_false); VerificationType comp_from = from.get_component(context, CHECK_false); if (!comp_this.is_bogus() && !comp_from.is_bogus()) { return comp_this.is_component_assignable_from(comp_from, context, from_field_is_protected, CHECK_false); } } return false; }
VerificationType StackMapFrame::pop_stack_ex(VerificationType type, TRAPS) { if (_stack_size <= 0) { verifier()->verify_error( ErrorContext::stack_underflow(_offset, this), "Operand stack underflow"); return VerificationType::bogus_type(); } VerificationType top = _stack[--_stack_size]; bool subtype = type.is_assignable_from( top, verifier(), CHECK_(VerificationType::bogus_type())); if (!subtype) { verifier()->verify_error( ErrorContext::bad_type(_offset, stack_top_ctx(), TypeOrigin::implicit(type)), "Bad type on operand stack"); return VerificationType::bogus_type(); } return top; }
VerificationType StackMapFrame::get_local( int32_t index, VerificationType type, TRAPS) { if (index >= _max_locals) { verifier()->verify_error( ErrorContext::bad_local_index(_offset, index), "Local variable table overflow"); return VerificationType::bogus_type(); } bool subtype = type.is_assignable_from(_locals[index], verifier(), CHECK_(VerificationType::bogus_type())); if (!subtype) { verifier()->verify_error( ErrorContext::bad_type(_offset, TypeOrigin::local(index, this), TypeOrigin::implicit(type)), "Bad local variable type"); return VerificationType::bogus_type(); } if(index >= _locals_size) { _locals_size = index + 1; } return _locals[index]; }
inline void pop_stack_2( VerificationType type1, VerificationType type2, TRAPS) { assert(type1.is_long2() || type1.is_double2(), "must be long/double"); assert(type2.is_long() || type2.is_double(), "must be long/double_2"); if (_stack_size >= 2) { VerificationType top1 = _stack[_stack_size - 1]; bool subtype1 = type1.is_assignable_from(top1, verifier(), CHECK); VerificationType top2 = _stack[_stack_size - 2]; bool subtype2 = type2.is_assignable_from(top2, verifier(), CHECK); if (subtype1 && subtype2) { _stack_size -= 2; return; } } pop_stack_ex(type1, THREAD); pop_stack_ex(type2, THREAD); }