8327624: Remove VM implementation that bypass verification for core reflection
Reviewed-by: liach, dholmes, jrose, alanb, mli
This commit is contained in:
parent
28147dab07
commit
d6eddcdaf9
src
hotspot/share
classfile
classFileParser.cppclassLoaderData.cppjavaClasses.cppjavaClasses.hppmodules.cppsystemDictionary.cppsystemDictionaryShared.cppverifier.cppvmClassMacros.hppvmSymbols.hpp
interpreter
prims
runtime
java.base/share/classes/jdk/internal/reflect
AccessorGenerator.javaByteVector.javaByteVectorFactory.javaByteVectorImpl.javaClassDefiner.javaClassFileAssembler.javaClassFileConstants.javaConstructorAccessorImpl.javaFieldAccessorImpl.javaLabel.javaMagicAccessorImpl.javaMethodAccessorImpl.javaReflectionFactory.javaSerializationConstructorAccessorGenerator.javaSerializationConstructorAccessorImpl.java
@ -4076,26 +4076,6 @@ void ClassFileParser::check_super_class_access(const InstanceKlass* this_klass,
|
||||
return;
|
||||
}
|
||||
|
||||
// If the loader is not the boot loader then throw an exception if its
|
||||
// superclass is in package jdk.internal.reflect and its loader is not a
|
||||
// special reflection class loader
|
||||
if (!this_klass->class_loader_data()->is_the_null_class_loader_data()) {
|
||||
PackageEntry* super_package = super->package();
|
||||
if (super_package != nullptr &&
|
||||
super_package->name()->fast_compare(vmSymbols::jdk_internal_reflect()) == 0 &&
|
||||
!java_lang_ClassLoader::is_reflection_class_loader(this_klass->class_loader())) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
vmSymbols::java_lang_IllegalAccessError(),
|
||||
"class %s loaded by %s cannot access jdk/internal/reflect superclass %s",
|
||||
this_klass->external_name(),
|
||||
this_klass->class_loader_data()->loader_name_and_id(),
|
||||
super->external_name());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Reflection::VerifyClassAccessResults vca_result =
|
||||
Reflection::verify_class_access(this_klass, InstanceKlass::cast(super), false);
|
||||
if (vca_result != Reflection::ACCESS_OK) {
|
||||
@ -5106,7 +5086,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
|
||||
|
||||
// Set PackageEntry for this_klass
|
||||
oop cl = ik->class_loader();
|
||||
Handle clh = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(cl));
|
||||
Handle clh = Handle(THREAD, cl);
|
||||
ClassLoaderData* cld = ClassLoaderData::class_loader_data_or_null(clh());
|
||||
ik->set_package(cld, nullptr, CHECK);
|
||||
|
||||
|
@ -644,8 +644,6 @@ Dictionary* ClassLoaderData::create_dictionary() {
|
||||
int size;
|
||||
if (_the_null_class_loader_data == nullptr) {
|
||||
size = _boot_loader_dictionary_size;
|
||||
} else if (class_loader()->is_a(vmClasses::reflect_DelegatingClassLoader_klass())) {
|
||||
size = 1; // there's only one class in relection class loader and no initiated classes
|
||||
} else if (is_system_class_loader_data()) {
|
||||
size = _boot_loader_dictionary_size;
|
||||
} else {
|
||||
@ -815,8 +813,6 @@ ClassLoaderMetaspace* ClassLoaderData::metaspace_non_null() {
|
||||
metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::BootMetaspaceType);
|
||||
} else if (has_class_mirror_holder()) {
|
||||
metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::ClassMirrorHolderMetaspaceType);
|
||||
} else if (class_loader()->is_a(vmClasses::reflect_DelegatingClassLoader_klass())) {
|
||||
metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType);
|
||||
} else {
|
||||
metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::StandardMetaspaceType);
|
||||
}
|
||||
|
@ -4763,9 +4763,6 @@ bool java_lang_ClassLoader::parallelCapable(oop class_loader) {
|
||||
}
|
||||
|
||||
bool java_lang_ClassLoader::is_trusted_loader(oop loader) {
|
||||
// Fix for 4474172; see evaluation for more details
|
||||
loader = non_reflection_class_loader(loader);
|
||||
|
||||
oop cl = SystemDictionary::java_system_loader();
|
||||
while(cl != nullptr) {
|
||||
if (cl == loader) return true;
|
||||
@ -4774,29 +4771,6 @@ bool java_lang_ClassLoader::is_trusted_loader(oop loader) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if this is one of the class loaders associated with
|
||||
// the generated bytecodes for serialization constructor returned
|
||||
// by sun.reflect.ReflectionFactory::newConstructorForSerialization
|
||||
bool java_lang_ClassLoader::is_reflection_class_loader(oop loader) {
|
||||
if (loader != nullptr) {
|
||||
Klass* delegating_cl_class = vmClasses::reflect_DelegatingClassLoader_klass();
|
||||
// This might be null in non-1.4 JDKs
|
||||
return (delegating_cl_class != nullptr && loader->is_a(delegating_cl_class));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) {
|
||||
// See whether this is one of the class loaders associated with
|
||||
// the generated bytecodes for reflection, and if so, "magically"
|
||||
// delegate to its parent to prevent class loading from occurring
|
||||
// in places where applications using reflection didn't expect it.
|
||||
if (is_reflection_class_loader(loader)) {
|
||||
return parent(loader);
|
||||
}
|
||||
return loader;
|
||||
}
|
||||
|
||||
oop java_lang_ClassLoader::unnamedModule(oop loader) {
|
||||
assert(is_instance(loader), "loader must be oop");
|
||||
return loader->obj_field(_unnamedModule_offset);
|
||||
|
@ -1502,14 +1502,6 @@ class java_lang_ClassLoader : AllStatic {
|
||||
|
||||
static bool is_trusted_loader(oop loader);
|
||||
|
||||
// Return true if this is one of the class loaders associated with
|
||||
// the generated bytecodes for serialization constructor returned
|
||||
// by sun.reflect.ReflectionFactory::newConstructorForSerialization
|
||||
static bool is_reflection_class_loader(oop loader);
|
||||
|
||||
// Fix for 4474172
|
||||
static oop non_reflection_class_loader(oop loader);
|
||||
|
||||
// Testers
|
||||
static bool is_subclass(Klass* klass) {
|
||||
return klass->is_subclass_of(vmClasses::ClassLoader_klass());
|
||||
|
@ -309,11 +309,6 @@ void Modules::define_module(Handle module, jboolean is_open, jstring version,
|
||||
}
|
||||
|
||||
oop loader = java_lang_Module::loader(module());
|
||||
// Make sure loader is not the jdk.internal.reflect.DelegatingClassLoader.
|
||||
if (loader != java_lang_ClassLoader::non_reflection_class_loader(loader)) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
"Class loader is an invalid delegating class loader");
|
||||
}
|
||||
Handle h_loader = Handle(THREAD, loader);
|
||||
// define_module can be called during start-up, before the class loader's ClassLoaderData
|
||||
// has been created. SystemDictionary::register_loader ensures creation, if needed.
|
||||
|
@ -598,8 +598,6 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
|
||||
|
||||
HandleMark hm(THREAD);
|
||||
|
||||
// Fix for 4474172; see evaluation for more details
|
||||
class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
|
||||
ClassLoaderData* loader_data = register_loader(class_loader);
|
||||
Dictionary* dictionary = loader_data->dictionary();
|
||||
|
||||
@ -765,12 +763,7 @@ InstanceKlass* SystemDictionary::find_instance_klass(Thread* current,
|
||||
Handle class_loader,
|
||||
Handle protection_domain) {
|
||||
|
||||
// The result of this call should be consistent with the result
|
||||
// of the call to resolve_instance_class_or_null().
|
||||
// See evaluation 6790209 and 4474172 for more details.
|
||||
oop class_loader_oop = java_lang_ClassLoader::non_reflection_class_loader(class_loader());
|
||||
ClassLoaderData* loader_data = ClassLoaderData::class_loader_data_or_null(class_loader_oop);
|
||||
|
||||
ClassLoaderData* loader_data = ClassLoaderData::class_loader_data_or_null(class_loader());
|
||||
if (loader_data == nullptr) {
|
||||
// If the ClassLoaderData has not been setup,
|
||||
// then the class loader has no entries in the dictionary.
|
||||
|
@ -403,9 +403,6 @@ InstanceKlass* SystemDictionaryShared::find_or_load_shared_class(
|
||||
|
||||
if (SystemDictionary::is_system_class_loader(class_loader()) ||
|
||||
SystemDictionary::is_platform_class_loader(class_loader())) {
|
||||
// Fix for 4474172; see evaluation for more details
|
||||
class_loader = Handle(
|
||||
THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
|
||||
ClassLoaderData *loader_data = register_loader(class_loader);
|
||||
Dictionary* dictionary = loader_data->dictionary();
|
||||
|
||||
|
@ -275,10 +275,6 @@ bool Verifier::verify(InstanceKlass* klass, bool should_verify_class, TRAPS) {
|
||||
|
||||
bool Verifier::is_eligible_for_verification(InstanceKlass* klass, bool should_verify_class) {
|
||||
Symbol* name = klass->name();
|
||||
Klass* refl_serialization_ctor_klass = vmClasses::reflect_SerializationConstructorAccessorImpl_klass();
|
||||
|
||||
bool is_reflect_accessor = refl_serialization_ctor_klass != nullptr &&
|
||||
klass->is_subtype_of(refl_serialization_ctor_klass);
|
||||
|
||||
return (should_verify_for(klass->class_loader(), should_verify_class) &&
|
||||
// return if the class is a bootstrapping class
|
||||
@ -295,12 +291,7 @@ bool Verifier::is_eligible_for_verification(InstanceKlass* klass, bool should_ve
|
||||
// Shared classes shouldn't have stackmaps either.
|
||||
// However, bytecodes for shared old classes can be verified because
|
||||
// they have not been rewritten.
|
||||
!(klass->is_shared() && klass->is_rewritten()) &&
|
||||
|
||||
// As of the fix for 4486457 we disable verification for all of the
|
||||
// dynamically-generated bytecodes associated with
|
||||
// jdk/internal/reflect/SerializationConstructorAccessor.
|
||||
(!is_reflect_accessor));
|
||||
!(klass->is_shared() && klass->is_rewritten()));
|
||||
}
|
||||
|
||||
Symbol* Verifier::inference_verify(
|
||||
|
@ -107,11 +107,9 @@
|
||||
do_klass(StackChunk_klass, jdk_internal_vm_StackChunk ) \
|
||||
\
|
||||
do_klass(reflect_MethodAccessorImpl_klass, reflect_MethodAccessorImpl ) \
|
||||
do_klass(reflect_DelegatingClassLoader_klass, reflect_DelegatingClassLoader ) \
|
||||
do_klass(reflect_ConstantPool_klass, reflect_ConstantPool ) \
|
||||
do_klass(reflect_CallerSensitive_klass, reflect_CallerSensitive ) \
|
||||
do_klass(reflect_DirectConstructorHandleAccessor_NativeAccessor_klass, reflect_DirectConstructorHandleAccessor_NativeAccessor) \
|
||||
do_klass(reflect_SerializationConstructorAccessorImpl_klass, reflect_SerializationConstructorAccessorImpl ) \
|
||||
\
|
||||
/* support for dynamic typing */ \
|
||||
do_klass(DirectMethodHandle_klass, java_lang_invoke_DirectMethodHandle ) \
|
||||
|
@ -262,12 +262,10 @@ class SerializeClosure;
|
||||
\
|
||||
template(jdk_internal_reflect, "jdk/internal/reflect") \
|
||||
template(reflect_MethodAccessorImpl, "jdk/internal/reflect/MethodAccessorImpl") \
|
||||
template(reflect_DelegatingClassLoader, "jdk/internal/reflect/DelegatingClassLoader") \
|
||||
template(reflect_Reflection, "jdk/internal/reflect/Reflection") \
|
||||
template(reflect_CallerSensitive, "jdk/internal/reflect/CallerSensitive") \
|
||||
template(reflect_CallerSensitive_signature, "Ljdk/internal/reflect/CallerSensitive;") \
|
||||
template(reflect_DirectConstructorHandleAccessor_NativeAccessor, "jdk/internal/reflect/DirectConstructorHandleAccessor$NativeAccessor") \
|
||||
template(reflect_SerializationConstructorAccessorImpl, "jdk/internal/reflect/SerializationConstructorAccessorImpl") \
|
||||
template(clazz_name, "clazz") \
|
||||
template(exceptionTypes_name, "exceptionTypes") \
|
||||
template(modifiers_name, "modifiers") \
|
||||
|
@ -1200,13 +1200,7 @@ Method* LinkResolver::linktime_resolve_special_method(const LinkInfo& link_info,
|
||||
Klass* current_klass = link_info.current_klass();
|
||||
if (current_klass != nullptr && resolved_klass->is_interface()) {
|
||||
InstanceKlass* klass_to_check = InstanceKlass::cast(current_klass);
|
||||
// Disable verification for the dynamically-generated reflection bytecodes
|
||||
// for serialization constructor accessor.
|
||||
bool is_reflect = klass_to_check->is_subclass_of(
|
||||
vmClasses::reflect_SerializationConstructorAccessorImpl_klass());
|
||||
|
||||
if (!is_reflect &&
|
||||
!klass_to_check->is_same_or_direct_interface(resolved_klass)) {
|
||||
if (!klass_to_check->is_same_or_direct_interface(resolved_klass)) {
|
||||
ResourceMark rm(THREAD);
|
||||
stringStream ss;
|
||||
ss.print("Interface method reference: '");
|
||||
|
@ -3278,10 +3278,7 @@ JVM_ENTRY(jobject, JVM_LatestUserDefinedLoader(JNIEnv *env))
|
||||
InstanceKlass* ik = vfst.method()->method_holder();
|
||||
oop loader = ik->class_loader();
|
||||
if (loader != nullptr && !SystemDictionary::is_platform_class_loader(loader)) {
|
||||
// Skip reflection related frames
|
||||
if (!ik->is_subclass_of(vmClasses::reflect_SerializationConstructorAccessorImpl_klass())) {
|
||||
return JNIHandles::make_local(THREAD, loader);
|
||||
}
|
||||
return JNIHandles::make_local(THREAD, loader);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -448,12 +448,6 @@ Reflection::VerifyClassAccessResults Reflection::verify_class_access(
|
||||
is_same_class_package(current_class, new_class)) {
|
||||
return ACCESS_OK;
|
||||
}
|
||||
// Allow all accesses from jdk/internal/reflect/SerializationConstructorAccessorImpl subclasses to
|
||||
// succeed trivially.
|
||||
if (vmClasses::reflect_SerializationConstructorAccessorImpl_klass_is_loaded() &&
|
||||
current_class->is_subclass_of(vmClasses::reflect_SerializationConstructorAccessorImpl_klass())) {
|
||||
return ACCESS_OK;
|
||||
}
|
||||
|
||||
// module boundaries
|
||||
if (new_class->is_public()) {
|
||||
@ -658,12 +652,6 @@ bool Reflection::verify_member_access(const Klass* current_class,
|
||||
}
|
||||
}
|
||||
|
||||
// Allow all accesses from jdk/internal/reflect/SerializationConstructorAccessorImpl subclasses to
|
||||
// succeed trivially.
|
||||
if (current_class->is_subclass_of(vmClasses::reflect_SerializationConstructorAccessorImpl_klass())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for special relaxations
|
||||
return can_relax_access_check_for(current_class, member_class, classloader_only);
|
||||
}
|
||||
|
@ -1,722 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.internal.reflect;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/** Shared functionality for all accessor generators */
|
||||
|
||||
class AccessorGenerator implements ClassFileConstants {
|
||||
static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
|
||||
// Constants because there's no way to say "short integer constant",
|
||||
// i.e., "1S"
|
||||
protected static final short S0 = (short) 0;
|
||||
protected static final short S1 = (short) 1;
|
||||
protected static final short S2 = (short) 2;
|
||||
protected static final short S3 = (short) 3;
|
||||
protected static final short S4 = (short) 4;
|
||||
protected static final short S5 = (short) 5;
|
||||
protected static final short S6 = (short) 6;
|
||||
|
||||
// Instance variables for shared functionality
|
||||
protected ClassFileAssembler asm;
|
||||
protected int modifiers;
|
||||
protected short thisClass;
|
||||
protected short superClass;
|
||||
protected short targetClass;
|
||||
// Common constant pool entries to FieldAccessor and MethodAccessor
|
||||
protected short throwableClass;
|
||||
protected short classCastClass;
|
||||
protected short nullPointerClass;
|
||||
protected short illegalArgumentClass;
|
||||
protected short invocationTargetClass;
|
||||
protected short initIdx;
|
||||
protected short initNameAndTypeIdx;
|
||||
protected short initStringNameAndTypeIdx;
|
||||
protected short nullPointerCtorIdx;
|
||||
protected short illegalArgumentCtorIdx;
|
||||
protected short illegalArgumentStringCtorIdx;
|
||||
protected short invocationTargetCtorIdx;
|
||||
protected short superCtorIdx;
|
||||
protected short objectClass;
|
||||
protected short toStringIdx;
|
||||
protected short codeIdx;
|
||||
protected short exceptionsIdx;
|
||||
// Boxing
|
||||
protected short valueOfIdx;
|
||||
protected short booleanIdx;
|
||||
protected short booleanBoxIdx;
|
||||
protected short booleanUnboxIdx;
|
||||
protected short byteIdx;
|
||||
protected short byteBoxIdx;
|
||||
protected short byteUnboxIdx;
|
||||
protected short characterIdx;
|
||||
protected short characterBoxIdx;
|
||||
protected short characterUnboxIdx;
|
||||
protected short doubleIdx;
|
||||
protected short doubleBoxIdx;
|
||||
protected short doubleUnboxIdx;
|
||||
protected short floatIdx;
|
||||
protected short floatBoxIdx;
|
||||
protected short floatUnboxIdx;
|
||||
protected short integerIdx;
|
||||
protected short integerBoxIdx;
|
||||
protected short integerUnboxIdx;
|
||||
protected short longIdx;
|
||||
protected short longBoxIdx;
|
||||
protected short longUnboxIdx;
|
||||
protected short shortIdx;
|
||||
protected short shortBoxIdx;
|
||||
protected short shortUnboxIdx;
|
||||
|
||||
protected final short NUM_COMMON_CPOOL_ENTRIES = (short) 30;
|
||||
protected final short NUM_BOXING_CPOOL_ENTRIES = (short) 73;
|
||||
|
||||
// Requires that superClass has been set up
|
||||
protected void emitCommonConstantPoolEntries() {
|
||||
// + [UTF-8] "java/lang/Throwable"
|
||||
// + [CONSTANT_Class_info] for above
|
||||
// + [UTF-8] "java/lang/ClassCastException"
|
||||
// + [CONSTANT_Class_info] for above
|
||||
// + [UTF-8] "java/lang/NullPointerException"
|
||||
// + [CONSTANT_Class_info] for above
|
||||
// + [UTF-8] "java/lang/IllegalArgumentException"
|
||||
// + [CONSTANT_Class_info] for above
|
||||
// + [UTF-8] "java/lang/InvocationTargetException"
|
||||
// + [CONSTANT_Class_info] for above
|
||||
// + [UTF-8] "<init>"
|
||||
// + [UTF-8] "()V"
|
||||
// + [CONSTANT_NameAndType_info] for above
|
||||
// + [CONSTANT_Methodref_info] for NullPointerException's constructor
|
||||
// + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor
|
||||
// + [UTF-8] "(Ljava/lang/String;)V"
|
||||
// + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/String;)V"
|
||||
// + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String
|
||||
// + [UTF-8] "(Ljava/lang/Throwable;)V"
|
||||
// + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/Throwable;)V"
|
||||
// + [CONSTANT_Methodref_info] for InvocationTargetException's constructor
|
||||
// + [CONSTANT_Methodref_info] for "super()"
|
||||
// + [UTF-8] "java/lang/Object"
|
||||
// + [CONSTANT_Class_info] for above
|
||||
// + [UTF-8] "toString"
|
||||
// + [UTF-8] "()Ljava/lang/String;"
|
||||
// + [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;"
|
||||
// + [CONSTANT_Methodref_info] for Object's toString method
|
||||
// + [UTF-8] "Code"
|
||||
// + [UTF-8] "Exceptions"
|
||||
asm.emitConstantPoolUTF8("java/lang/Throwable");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
throwableClass = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("java/lang/ClassCastException");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
classCastClass = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("java/lang/NullPointerException");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
nullPointerClass = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("java/lang/IllegalArgumentException");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
illegalArgumentClass = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("java/lang/reflect/InvocationTargetException");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
invocationTargetClass = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("<init>");
|
||||
initIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("()V");
|
||||
asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
|
||||
initNameAndTypeIdx = asm.cpi();
|
||||
asm.emitConstantPoolMethodref(nullPointerClass, initNameAndTypeIdx);
|
||||
nullPointerCtorIdx = asm.cpi();
|
||||
asm.emitConstantPoolMethodref(illegalArgumentClass, initNameAndTypeIdx);
|
||||
illegalArgumentCtorIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("(Ljava/lang/String;)V");
|
||||
asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
|
||||
initStringNameAndTypeIdx = asm.cpi();
|
||||
asm.emitConstantPoolMethodref(illegalArgumentClass, initStringNameAndTypeIdx);
|
||||
illegalArgumentStringCtorIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("(Ljava/lang/Throwable;)V");
|
||||
asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
|
||||
asm.emitConstantPoolMethodref(invocationTargetClass, asm.cpi());
|
||||
invocationTargetCtorIdx = asm.cpi();
|
||||
asm.emitConstantPoolMethodref(superClass, initNameAndTypeIdx);
|
||||
superCtorIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("java/lang/Object");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
objectClass = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("toString");
|
||||
asm.emitConstantPoolUTF8("()Ljava/lang/String;");
|
||||
asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
|
||||
asm.emitConstantPoolMethodref(objectClass, asm.cpi());
|
||||
toStringIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("Code");
|
||||
codeIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("Exceptions");
|
||||
exceptionsIdx = asm.cpi();
|
||||
}
|
||||
|
||||
/** Constant pool entries required to be able to box/unbox primitive
|
||||
types. Note that we don't emit these if we don't need them. */
|
||||
protected void emitBoxingContantPoolEntries() {
|
||||
// * [UTF-8] "valueOf"
|
||||
// * [UTF-8] "java/lang/Boolean"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(Z)Ljava/lang/Boolean;"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "booleanValue"
|
||||
// * [UTF-8] "()Z"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Byte"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(B)Ljava/lang/Byte;"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "byteValue"
|
||||
// * [UTF-8] "()B"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Character"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(C)Ljava/lang/Character;"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "charValue"
|
||||
// * [UTF-8] "()C"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Double"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(D)Ljava/lang/Double;"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "doubleValue"
|
||||
// * [UTF-8] "()D"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Float"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(F)Ljava/lang/Float;"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "floatValue"
|
||||
// * [UTF-8] "()F"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Integer"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(I)Ljava/lang/Integer;"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "intValue"
|
||||
// * [UTF-8] "()I"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Long"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(J)Ljava/lang/Long;"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "longValue"
|
||||
// * [UTF-8] "()J"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Short"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(S)Ljava/lang/Short;"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "shortValue"
|
||||
// * [UTF-8] "()S"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
|
||||
// valueOf-method name
|
||||
asm.emitConstantPoolUTF8("valueOf");
|
||||
valueOfIdx = asm.cpi();
|
||||
|
||||
// Boolean
|
||||
asm.emitConstantPoolUTF8("java/lang/Boolean");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
booleanIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("(Z)Ljava/lang/Boolean;");
|
||||
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
|
||||
booleanBoxIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("booleanValue");
|
||||
asm.emitConstantPoolUTF8("()Z");
|
||||
asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
|
||||
booleanUnboxIdx = asm.cpi();
|
||||
|
||||
// Byte
|
||||
asm.emitConstantPoolUTF8("java/lang/Byte");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
byteIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("(B)Ljava/lang/Byte;");
|
||||
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
|
||||
byteBoxIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("byteValue");
|
||||
asm.emitConstantPoolUTF8("()B");
|
||||
asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
|
||||
byteUnboxIdx = asm.cpi();
|
||||
|
||||
// Character
|
||||
asm.emitConstantPoolUTF8("java/lang/Character");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
characterIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("(C)Ljava/lang/Character;");
|
||||
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
|
||||
characterBoxIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("charValue");
|
||||
asm.emitConstantPoolUTF8("()C");
|
||||
asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
|
||||
characterUnboxIdx = asm.cpi();
|
||||
|
||||
// Double
|
||||
asm.emitConstantPoolUTF8("java/lang/Double");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
doubleIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("(D)Ljava/lang/Double;");
|
||||
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
|
||||
doubleBoxIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("doubleValue");
|
||||
asm.emitConstantPoolUTF8("()D");
|
||||
asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
|
||||
doubleUnboxIdx = asm.cpi();
|
||||
|
||||
// Float
|
||||
asm.emitConstantPoolUTF8("java/lang/Float");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
floatIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("(F)Ljava/lang/Float;");
|
||||
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
|
||||
floatBoxIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("floatValue");
|
||||
asm.emitConstantPoolUTF8("()F");
|
||||
asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
|
||||
floatUnboxIdx = asm.cpi();
|
||||
|
||||
// Integer
|
||||
asm.emitConstantPoolUTF8("java/lang/Integer");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
integerIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("(I)Ljava/lang/Integer;");
|
||||
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
|
||||
integerBoxIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("intValue");
|
||||
asm.emitConstantPoolUTF8("()I");
|
||||
asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
|
||||
integerUnboxIdx = asm.cpi();
|
||||
|
||||
// Long
|
||||
asm.emitConstantPoolUTF8("java/lang/Long");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
longIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("(J)Ljava/lang/Long;");
|
||||
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
|
||||
longBoxIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("longValue");
|
||||
asm.emitConstantPoolUTF8("()J");
|
||||
asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
|
||||
longUnboxIdx = asm.cpi();
|
||||
|
||||
// Short
|
||||
asm.emitConstantPoolUTF8("java/lang/Short");
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
shortIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("(S)Ljava/lang/Short;");
|
||||
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
|
||||
shortBoxIdx = asm.cpi();
|
||||
asm.emitConstantPoolUTF8("shortValue");
|
||||
asm.emitConstantPoolUTF8("()S");
|
||||
asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
|
||||
asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
|
||||
shortUnboxIdx = asm.cpi();
|
||||
}
|
||||
|
||||
// Necessary because of Java's annoying promotion rules
|
||||
protected static short add(short s1, short s2) {
|
||||
return (short) (s1 + s2);
|
||||
}
|
||||
|
||||
protected static short sub(short s1, short s2) {
|
||||
return (short) (s1 - s2);
|
||||
}
|
||||
|
||||
protected boolean isStatic() {
|
||||
return Modifier.isStatic(modifiers);
|
||||
}
|
||||
|
||||
protected boolean isPrivate() {
|
||||
return Modifier.isPrivate(modifiers);
|
||||
}
|
||||
|
||||
/** Returns class name in "internal" form (i.e., '/' separators
|
||||
instead of '.') */
|
||||
protected static String getClassName
|
||||
(Class<?> c, boolean addPrefixAndSuffixForNonPrimitiveTypes)
|
||||
{
|
||||
if (c.isPrimitive()) {
|
||||
if (c == Boolean.TYPE) {
|
||||
return "Z";
|
||||
} else if (c == Byte.TYPE) {
|
||||
return "B";
|
||||
} else if (c == Character.TYPE) {
|
||||
return "C";
|
||||
} else if (c == Double.TYPE) {
|
||||
return "D";
|
||||
} else if (c == Float.TYPE) {
|
||||
return "F";
|
||||
} else if (c == Integer.TYPE) {
|
||||
return "I";
|
||||
} else if (c == Long.TYPE) {
|
||||
return "J";
|
||||
} else if (c == Short.TYPE) {
|
||||
return "S";
|
||||
} else if (c == Void.TYPE) {
|
||||
return "V";
|
||||
}
|
||||
throw new InternalError("Should have found primitive type");
|
||||
} else if (c.isArray()) {
|
||||
return "[" + getClassName(c.getComponentType(), true);
|
||||
} else {
|
||||
if (addPrefixAndSuffixForNonPrimitiveTypes) {
|
||||
return internalize("L" + c.getName() + ";");
|
||||
} else {
|
||||
return internalize(c.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String internalize(String className) {
|
||||
return className.replace('.', '/');
|
||||
}
|
||||
|
||||
protected void emitConstructor() {
|
||||
// Generate code into fresh code buffer
|
||||
ClassFileAssembler cb = new ClassFileAssembler();
|
||||
// 0 incoming arguments
|
||||
cb.setMaxLocals(1);
|
||||
cb.opc_aload_0();
|
||||
cb.opc_invokespecial(superCtorIdx, 0, 0);
|
||||
cb.opc_return();
|
||||
|
||||
// Emit method
|
||||
emitMethod(initIdx, cb.getMaxLocals(), cb, null, null);
|
||||
}
|
||||
|
||||
// The descriptor's index in the constant pool must be (1 +
|
||||
// nameIdx). "numArgs" must indicate ALL arguments, including the
|
||||
// implicit "this" argument; double and long arguments each count
|
||||
// as 2 in this count. The code buffer must NOT contain the code
|
||||
// length. The exception table may be null, but if non-null must
|
||||
// NOT contain the exception table's length. The checked exception
|
||||
// indices may be null.
|
||||
protected void emitMethod(short nameIdx,
|
||||
int numArgs,
|
||||
ClassFileAssembler code,
|
||||
ClassFileAssembler exceptionTable,
|
||||
short[] checkedExceptionIndices)
|
||||
{
|
||||
int codeLen = code.getLength();
|
||||
int excLen = 0;
|
||||
if (exceptionTable != null) {
|
||||
excLen = exceptionTable.getLength();
|
||||
if ((excLen % 8) != 0) {
|
||||
throw new IllegalArgumentException("Illegal exception table");
|
||||
}
|
||||
}
|
||||
int attrLen = 12 + codeLen + excLen;
|
||||
excLen = excLen / 8; // No-op if no exception table
|
||||
|
||||
asm.emitShort(ACC_PUBLIC);
|
||||
asm.emitShort(nameIdx);
|
||||
asm.emitShort(add(nameIdx, S1));
|
||||
if (checkedExceptionIndices == null) {
|
||||
// Code attribute only
|
||||
asm.emitShort(S1);
|
||||
} else {
|
||||
// Code and Exceptions attributes
|
||||
asm.emitShort(S2);
|
||||
}
|
||||
// Code attribute
|
||||
asm.emitShort(codeIdx);
|
||||
asm.emitInt(attrLen);
|
||||
asm.emitShort(code.getMaxStack());
|
||||
asm.emitShort((short) Math.max(numArgs, code.getMaxLocals()));
|
||||
asm.emitInt(codeLen);
|
||||
asm.append(code);
|
||||
asm.emitShort((short) excLen);
|
||||
if (exceptionTable != null) {
|
||||
asm.append(exceptionTable);
|
||||
}
|
||||
asm.emitShort(S0); // No additional attributes for Code attribute
|
||||
if (checkedExceptionIndices != null) {
|
||||
// Exceptions attribute
|
||||
asm.emitShort(exceptionsIdx);
|
||||
asm.emitInt(2 + 2 * checkedExceptionIndices.length);
|
||||
asm.emitShort((short) checkedExceptionIndices.length);
|
||||
for (int i = 0; i < checkedExceptionIndices.length; i++) {
|
||||
asm.emitShort(checkedExceptionIndices[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected short indexForPrimitiveType(Class<?> type) {
|
||||
if (type == Boolean.TYPE) {
|
||||
return booleanIdx;
|
||||
} else if (type == Byte.TYPE) {
|
||||
return byteIdx;
|
||||
} else if (type == Character.TYPE) {
|
||||
return characterIdx;
|
||||
} else if (type == Double.TYPE) {
|
||||
return doubleIdx;
|
||||
} else if (type == Float.TYPE) {
|
||||
return floatIdx;
|
||||
} else if (type == Integer.TYPE) {
|
||||
return integerIdx;
|
||||
} else if (type == Long.TYPE) {
|
||||
return longIdx;
|
||||
} else if (type == Short.TYPE) {
|
||||
return shortIdx;
|
||||
}
|
||||
throw new InternalError("Should have found primitive type");
|
||||
}
|
||||
|
||||
protected short boxingMethodForPrimitiveType(Class<?> type) {
|
||||
if (type == Boolean.TYPE) {
|
||||
return booleanBoxIdx;
|
||||
} else if (type == Byte.TYPE) {
|
||||
return byteBoxIdx;
|
||||
} else if (type == Character.TYPE) {
|
||||
return characterBoxIdx;
|
||||
} else if (type == Double.TYPE) {
|
||||
return doubleBoxIdx;
|
||||
} else if (type == Float.TYPE) {
|
||||
return floatBoxIdx;
|
||||
} else if (type == Integer.TYPE) {
|
||||
return integerBoxIdx;
|
||||
} else if (type == Long.TYPE) {
|
||||
return longBoxIdx;
|
||||
} else if (type == Short.TYPE) {
|
||||
return shortBoxIdx;
|
||||
}
|
||||
throw new InternalError("Should have found primitive type");
|
||||
}
|
||||
|
||||
/** Returns true for widening or identity conversions for primitive
|
||||
types only */
|
||||
protected static boolean canWidenTo(Class<?> type, Class<?> otherType) {
|
||||
if (!type.isPrimitive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Widening conversions (from JVM spec):
|
||||
// byte to short, int, long, float, or double
|
||||
// short to int, long, float, or double
|
||||
// char to int, long, float, or double
|
||||
// int to long, float, or double
|
||||
// long to float or double
|
||||
// float to double
|
||||
|
||||
if (type == Boolean.TYPE) {
|
||||
if (otherType == Boolean.TYPE) {
|
||||
return true;
|
||||
}
|
||||
} else if (type == Byte.TYPE) {
|
||||
if ( otherType == Byte.TYPE
|
||||
|| otherType == Short.TYPE
|
||||
|| otherType == Integer.TYPE
|
||||
|| otherType == Long.TYPE
|
||||
|| otherType == Float.TYPE
|
||||
|| otherType == Double.TYPE) {
|
||||
return true;
|
||||
}
|
||||
} else if (type == Short.TYPE) {
|
||||
if ( otherType == Short.TYPE
|
||||
|| otherType == Integer.TYPE
|
||||
|| otherType == Long.TYPE
|
||||
|| otherType == Float.TYPE
|
||||
|| otherType == Double.TYPE) {
|
||||
return true;
|
||||
}
|
||||
} else if (type == Character.TYPE) {
|
||||
if ( otherType == Character.TYPE
|
||||
|| otherType == Integer.TYPE
|
||||
|| otherType == Long.TYPE
|
||||
|| otherType == Float.TYPE
|
||||
|| otherType == Double.TYPE) {
|
||||
return true;
|
||||
}
|
||||
} else if (type == Integer.TYPE) {
|
||||
if ( otherType == Integer.TYPE
|
||||
|| otherType == Long.TYPE
|
||||
|| otherType == Float.TYPE
|
||||
|| otherType == Double.TYPE) {
|
||||
return true;
|
||||
}
|
||||
} else if (type == Long.TYPE) {
|
||||
if ( otherType == Long.TYPE
|
||||
|| otherType == Float.TYPE
|
||||
|| otherType == Double.TYPE) {
|
||||
return true;
|
||||
}
|
||||
} else if (type == Float.TYPE) {
|
||||
if ( otherType == Float.TYPE
|
||||
|| otherType == Double.TYPE) {
|
||||
return true;
|
||||
}
|
||||
} else if (type == Double.TYPE) {
|
||||
if (otherType == Double.TYPE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Emits the widening bytecode for the given primitive conversion
|
||||
(or none if the identity conversion). Requires that a primitive
|
||||
conversion exists; i.e., canWidenTo must have already been
|
||||
called and returned true. */
|
||||
protected static void emitWideningBytecodeForPrimitiveConversion
|
||||
(ClassFileAssembler cb,
|
||||
Class<?> fromType,
|
||||
Class<?> toType)
|
||||
{
|
||||
// Note that widening conversions for integral types (i.e., "b2s",
|
||||
// "s2i") are no-ops since values on the Java stack are
|
||||
// sign-extended.
|
||||
|
||||
// Widening conversions (from JVM spec):
|
||||
// byte to short, int, long, float, or double
|
||||
// short to int, long, float, or double
|
||||
// char to int, long, float, or double
|
||||
// int to long, float, or double
|
||||
// long to float or double
|
||||
// float to double
|
||||
|
||||
if ( fromType == Byte.TYPE
|
||||
|| fromType == Short.TYPE
|
||||
|| fromType == Character.TYPE
|
||||
|| fromType == Integer.TYPE) {
|
||||
if (toType == Long.TYPE) {
|
||||
cb.opc_i2l();
|
||||
} else if (toType == Float.TYPE) {
|
||||
cb.opc_i2f();
|
||||
} else if (toType == Double.TYPE) {
|
||||
cb.opc_i2d();
|
||||
}
|
||||
} else if (fromType == Long.TYPE) {
|
||||
if (toType == Float.TYPE) {
|
||||
cb.opc_l2f();
|
||||
} else if (toType == Double.TYPE) {
|
||||
cb.opc_l2d();
|
||||
}
|
||||
} else if (fromType == Float.TYPE) {
|
||||
if (toType == Double.TYPE) {
|
||||
cb.opc_f2d();
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, was identity or no-op conversion. Fall through.
|
||||
}
|
||||
|
||||
protected short unboxingMethodForPrimitiveType(Class<?> primType) {
|
||||
if (primType == Boolean.TYPE) {
|
||||
return booleanUnboxIdx;
|
||||
} else if (primType == Byte.TYPE) {
|
||||
return byteUnboxIdx;
|
||||
} else if (primType == Character.TYPE) {
|
||||
return characterUnboxIdx;
|
||||
} else if (primType == Short.TYPE) {
|
||||
return shortUnboxIdx;
|
||||
} else if (primType == Integer.TYPE) {
|
||||
return integerUnboxIdx;
|
||||
} else if (primType == Long.TYPE) {
|
||||
return longUnboxIdx;
|
||||
} else if (primType == Float.TYPE) {
|
||||
return floatUnboxIdx;
|
||||
} else if (primType == Double.TYPE) {
|
||||
return doubleUnboxIdx;
|
||||
}
|
||||
throw new InternalError("Illegal primitive type " + primType.getName());
|
||||
}
|
||||
|
||||
protected static final Class<?>[] primitiveTypes = new Class<?>[] {
|
||||
Boolean.TYPE,
|
||||
Byte.TYPE,
|
||||
Character.TYPE,
|
||||
Short.TYPE,
|
||||
Integer.TYPE,
|
||||
Long.TYPE,
|
||||
Float.TYPE,
|
||||
Double.TYPE
|
||||
};
|
||||
|
||||
/** We don't consider "Void" to be a primitive type */
|
||||
protected static boolean isPrimitive(Class<?> c) {
|
||||
return (c.isPrimitive() && c != Void.TYPE);
|
||||
}
|
||||
|
||||
protected int typeSizeInStackSlots(Class<?> c) {
|
||||
if (c == Void.TYPE) {
|
||||
return 0;
|
||||
}
|
||||
if (c == Long.TYPE || c == Double.TYPE) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private ClassFileAssembler illegalArgumentCodeBuffer;
|
||||
protected ClassFileAssembler illegalArgumentCodeBuffer() {
|
||||
if (illegalArgumentCodeBuffer == null) {
|
||||
illegalArgumentCodeBuffer = new ClassFileAssembler();
|
||||
illegalArgumentCodeBuffer.opc_new(illegalArgumentClass);
|
||||
illegalArgumentCodeBuffer.opc_dup();
|
||||
illegalArgumentCodeBuffer.opc_invokespecial(illegalArgumentCtorIdx, 0, 0);
|
||||
illegalArgumentCodeBuffer.opc_athrow();
|
||||
}
|
||||
|
||||
return illegalArgumentCodeBuffer;
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.internal.reflect;
|
||||
|
||||
/** A growable array of bytes. */
|
||||
|
||||
interface ByteVector {
|
||||
public int getLength();
|
||||
public byte get(int index);
|
||||
public void put(int index, byte value);
|
||||
public void add(byte value);
|
||||
public void trim();
|
||||
public byte[] getData();
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.internal.reflect;
|
||||
|
||||
class ByteVectorFactory {
|
||||
static ByteVector create() {
|
||||
return new ByteVectorImpl();
|
||||
}
|
||||
|
||||
static ByteVector create(int sz) {
|
||||
return new ByteVectorImpl(sz);
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.internal.reflect;
|
||||
|
||||
class ByteVectorImpl implements ByteVector {
|
||||
private byte[] data;
|
||||
private int pos;
|
||||
|
||||
public ByteVectorImpl() {
|
||||
this(100);
|
||||
}
|
||||
|
||||
public ByteVectorImpl(int sz) {
|
||||
data = new byte[sz];
|
||||
pos = -1;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return pos + 1;
|
||||
}
|
||||
|
||||
public byte get(int index) {
|
||||
if (index >= data.length) {
|
||||
resize(index);
|
||||
pos = index;
|
||||
}
|
||||
return data[index];
|
||||
}
|
||||
|
||||
public void put(int index, byte value) {
|
||||
if (index >= data.length) {
|
||||
resize(index);
|
||||
pos = index;
|
||||
}
|
||||
data[index] = value;
|
||||
}
|
||||
|
||||
public void add(byte value) {
|
||||
if (++pos >= data.length) {
|
||||
resize(pos);
|
||||
}
|
||||
data[pos] = value;
|
||||
}
|
||||
|
||||
public void trim() {
|
||||
if (pos != data.length - 1) {
|
||||
byte[] newData = new byte[pos + 1];
|
||||
System.arraycopy(data, 0, newData, 0, pos + 1);
|
||||
data = newData;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
private void resize(int minSize) {
|
||||
if (minSize <= 2 * data.length) {
|
||||
minSize = 2 * data.length;
|
||||
}
|
||||
byte[] newData = new byte[minSize];
|
||||
System.arraycopy(data, 0, newData, 0, data.length);
|
||||
data = newData;
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.internal.reflect;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import jdk.internal.access.JavaLangAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
|
||||
/** Utility class which assists in calling defineClass() by
|
||||
* creating a new class loader which delegates to the one needed in
|
||||
* order for proper resolution of the given bytecodes to occur.
|
||||
*
|
||||
* This is only used to define SerializationConstructorAccessor.
|
||||
*/
|
||||
|
||||
class ClassDefiner {
|
||||
static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
|
||||
|
||||
/** <P> We define generated code into a new class loader which
|
||||
delegates to the defining loader of the target class. It is
|
||||
necessary for the VM to be able to resolve references to the
|
||||
target class from the generated bytecodes, which could not occur
|
||||
if the generated code was loaded into the bootstrap class
|
||||
loader. </P>
|
||||
|
||||
<P> There are two primary reasons for creating a new loader
|
||||
instead of defining these bytecodes directly into the defining
|
||||
loader of the target class: first, it avoids any possible
|
||||
security risk of having these bytecodes in the same loader.
|
||||
Second, it allows the generated bytecodes to be unloaded earlier
|
||||
than would otherwise be possible, decreasing run-time
|
||||
footprint. </P>
|
||||
*/
|
||||
static Class<?> defineClass(String name, byte[] bytes, int off, int len,
|
||||
final ClassLoader parentClassLoader)
|
||||
{
|
||||
@SuppressWarnings("removal")
|
||||
ClassLoader newLoader = AccessController.doPrivileged(
|
||||
new PrivilegedAction<ClassLoader>() {
|
||||
public ClassLoader run() {
|
||||
return new DelegatingClassLoader(parentClassLoader);
|
||||
}
|
||||
});
|
||||
return JLA.defineClass(newLoader, name, bytes, null, "__ClassDefiner__");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NOTE: this class's name and presence are known to the virtual
|
||||
// machine as of the fix for 4474172.
|
||||
class DelegatingClassLoader extends ClassLoader {
|
||||
DelegatingClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
}
|
@ -1,671 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.internal.reflect;
|
||||
|
||||
import sun.nio.cs.UTF_8;
|
||||
|
||||
class ClassFileAssembler implements ClassFileConstants {
|
||||
private ByteVector vec;
|
||||
private short cpIdx = 0;
|
||||
|
||||
public ClassFileAssembler() {
|
||||
this(ByteVectorFactory.create());
|
||||
}
|
||||
|
||||
public ClassFileAssembler(ByteVector vec) {
|
||||
this.vec = vec;
|
||||
}
|
||||
|
||||
public ByteVector getData() {
|
||||
return vec;
|
||||
}
|
||||
|
||||
/** Length in bytes */
|
||||
public short getLength() {
|
||||
return (short) vec.getLength();
|
||||
}
|
||||
|
||||
public void emitMagicAndVersion() {
|
||||
emitInt(0xCAFEBABE);
|
||||
emitShort((short) 0);
|
||||
emitShort((short) 49);
|
||||
}
|
||||
|
||||
public void emitInt(int val) {
|
||||
emitByte((byte) (val >> 24));
|
||||
emitByte((byte) ((val >> 16) & 0xFF));
|
||||
emitByte((byte) ((val >> 8) & 0xFF));
|
||||
emitByte((byte) (val & 0xFF));
|
||||
}
|
||||
|
||||
public void emitShort(short val) {
|
||||
emitByte((byte) ((val >> 8) & 0xFF));
|
||||
emitByte((byte) (val & 0xFF));
|
||||
}
|
||||
|
||||
// Support for labels; package-private
|
||||
void emitShort(short bci, short val) {
|
||||
vec.put(bci, (byte) ((val >> 8) & 0xFF));
|
||||
vec.put(bci + 1, (byte) (val & 0xFF));
|
||||
}
|
||||
|
||||
public void emitByte(byte val) {
|
||||
vec.add(val);
|
||||
}
|
||||
|
||||
public void append(ClassFileAssembler asm) {
|
||||
append(asm.vec);
|
||||
}
|
||||
|
||||
public void append(ByteVector vec) {
|
||||
for (int i = 0; i < vec.getLength(); i++) {
|
||||
emitByte(vec.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
/** Keeps track of the current (one-based) constant pool index;
|
||||
incremented after emitting one of the following constant pool
|
||||
entries. Can fetch the current constant pool index for use in
|
||||
later entries. Index points at the last valid constant pool
|
||||
entry; initially invalid. It is illegal to fetch the constant
|
||||
pool index before emitting at least one constant pool entry. */
|
||||
public short cpi() {
|
||||
if (cpIdx == 0) {
|
||||
throw new RuntimeException("Illegal use of ClassFileAssembler");
|
||||
}
|
||||
return cpIdx;
|
||||
}
|
||||
|
||||
public void emitConstantPoolUTF8(String str) {
|
||||
byte[] bytes = str.getBytes(UTF_8.INSTANCE);
|
||||
emitByte(CONSTANT_Utf8);
|
||||
emitShort((short) bytes.length);
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
emitByte(bytes[i]);
|
||||
}
|
||||
cpIdx++;
|
||||
}
|
||||
|
||||
public void emitConstantPoolClass(short index) {
|
||||
emitByte(CONSTANT_Class);
|
||||
emitShort(index);
|
||||
cpIdx++;
|
||||
}
|
||||
|
||||
public void emitConstantPoolNameAndType(short nameIndex, short typeIndex) {
|
||||
emitByte(CONSTANT_NameAndType);
|
||||
emitShort(nameIndex);
|
||||
emitShort(typeIndex);
|
||||
cpIdx++;
|
||||
}
|
||||
|
||||
public void emitConstantPoolFieldref
|
||||
(short classIndex, short nameAndTypeIndex)
|
||||
{
|
||||
emitByte(CONSTANT_Fieldref);
|
||||
emitShort(classIndex);
|
||||
emitShort(nameAndTypeIndex);
|
||||
cpIdx++;
|
||||
}
|
||||
|
||||
public void emitConstantPoolMethodref
|
||||
(short classIndex, short nameAndTypeIndex)
|
||||
{
|
||||
emitByte(CONSTANT_Methodref);
|
||||
emitShort(classIndex);
|
||||
emitShort(nameAndTypeIndex);
|
||||
cpIdx++;
|
||||
}
|
||||
|
||||
public void emitConstantPoolInterfaceMethodref
|
||||
(short classIndex, short nameAndTypeIndex)
|
||||
{
|
||||
emitByte(CONSTANT_InterfaceMethodref);
|
||||
emitShort(classIndex);
|
||||
emitShort(nameAndTypeIndex);
|
||||
cpIdx++;
|
||||
}
|
||||
|
||||
public void emitConstantPoolString(short utf8Index) {
|
||||
emitByte(CONSTANT_String);
|
||||
emitShort(utf8Index);
|
||||
cpIdx++;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Opcodes. Keeps track of maximum stack and locals. Make a new
|
||||
// assembler for each piece of assembled code, then append the
|
||||
// result to the previous assembler's class file.
|
||||
//
|
||||
|
||||
private int stack = 0;
|
||||
private int maxStack = 0;
|
||||
private int maxLocals = 0;
|
||||
|
||||
private void incStack() {
|
||||
setStack(stack + 1);
|
||||
}
|
||||
|
||||
private void decStack() {
|
||||
--stack;
|
||||
}
|
||||
|
||||
public short getMaxStack() {
|
||||
return (short) maxStack;
|
||||
}
|
||||
|
||||
public short getMaxLocals() {
|
||||
return (short) maxLocals;
|
||||
}
|
||||
|
||||
/** It's necessary to be able to specify the number of arguments at
|
||||
the beginning of the method (which translates to the initial
|
||||
value of max locals) */
|
||||
public void setMaxLocals(int maxLocals) {
|
||||
this.maxLocals = maxLocals;
|
||||
}
|
||||
|
||||
/** Needed to do flow control. Returns current stack depth. */
|
||||
public int getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
||||
/** Needed to do flow control. */
|
||||
public void setStack(int value) {
|
||||
stack = value;
|
||||
if (stack > maxStack) {
|
||||
maxStack = stack;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------//
|
||||
// Constants //
|
||||
//-----------//
|
||||
|
||||
public void opc_aconst_null() {
|
||||
emitByte(opc_aconst_null);
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_sipush(short constant) {
|
||||
emitByte(opc_sipush);
|
||||
emitShort(constant);
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_ldc(byte cpIdx) {
|
||||
emitByte(opc_ldc);
|
||||
emitByte(cpIdx);
|
||||
incStack();
|
||||
}
|
||||
|
||||
//---------------------------------//
|
||||
// Local variable loads and stores //
|
||||
//---------------------------------//
|
||||
|
||||
public void opc_iload_0() {
|
||||
emitByte(opc_iload_0);
|
||||
if (maxLocals < 1) maxLocals = 1;
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_iload_1() {
|
||||
emitByte(opc_iload_1);
|
||||
if (maxLocals < 2) maxLocals = 2;
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_iload_2() {
|
||||
emitByte(opc_iload_2);
|
||||
if (maxLocals < 3) maxLocals = 3;
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_iload_3() {
|
||||
emitByte(opc_iload_3);
|
||||
if (maxLocals < 4) maxLocals = 4;
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_lload_0() {
|
||||
emitByte(opc_lload_0);
|
||||
if (maxLocals < 2) maxLocals = 2;
|
||||
incStack();
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_lload_1() {
|
||||
emitByte(opc_lload_1);
|
||||
if (maxLocals < 3) maxLocals = 3;
|
||||
incStack();
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_lload_2() {
|
||||
emitByte(opc_lload_2);
|
||||
if (maxLocals < 4) maxLocals = 4;
|
||||
incStack();
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_lload_3() {
|
||||
emitByte(opc_lload_3);
|
||||
if (maxLocals < 5) maxLocals = 5;
|
||||
incStack();
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_fload_0() {
|
||||
emitByte(opc_fload_0);
|
||||
if (maxLocals < 1) maxLocals = 1;
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_fload_1() {
|
||||
emitByte(opc_fload_1);
|
||||
if (maxLocals < 2) maxLocals = 2;
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_fload_2() {
|
||||
emitByte(opc_fload_2);
|
||||
if (maxLocals < 3) maxLocals = 3;
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_fload_3() {
|
||||
emitByte(opc_fload_3);
|
||||
if (maxLocals < 4) maxLocals = 4;
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_dload_0() {
|
||||
emitByte(opc_dload_0);
|
||||
if (maxLocals < 2) maxLocals = 2;
|
||||
incStack();
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_dload_1() {
|
||||
emitByte(opc_dload_1);
|
||||
if (maxLocals < 3) maxLocals = 3;
|
||||
incStack();
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_dload_2() {
|
||||
emitByte(opc_dload_2);
|
||||
if (maxLocals < 4) maxLocals = 4;
|
||||
incStack();
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_dload_3() {
|
||||
emitByte(opc_dload_3);
|
||||
if (maxLocals < 5) maxLocals = 5;
|
||||
incStack();
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_aload_0() {
|
||||
emitByte(opc_aload_0);
|
||||
if (maxLocals < 1) maxLocals = 1;
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_aload_1() {
|
||||
emitByte(opc_aload_1);
|
||||
if (maxLocals < 2) maxLocals = 2;
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_aload_2() {
|
||||
emitByte(opc_aload_2);
|
||||
if (maxLocals < 3) maxLocals = 3;
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_aload_3() {
|
||||
emitByte(opc_aload_3);
|
||||
if (maxLocals < 4) maxLocals = 4;
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_aaload() {
|
||||
emitByte(opc_aaload);
|
||||
decStack();
|
||||
}
|
||||
|
||||
public void opc_astore_0() {
|
||||
emitByte(opc_astore_0);
|
||||
if (maxLocals < 1) maxLocals = 1;
|
||||
decStack();
|
||||
}
|
||||
|
||||
public void opc_astore_1() {
|
||||
emitByte(opc_astore_1);
|
||||
if (maxLocals < 2) maxLocals = 2;
|
||||
decStack();
|
||||
}
|
||||
|
||||
public void opc_astore_2() {
|
||||
emitByte(opc_astore_2);
|
||||
if (maxLocals < 3) maxLocals = 3;
|
||||
decStack();
|
||||
}
|
||||
|
||||
public void opc_astore_3() {
|
||||
emitByte(opc_astore_3);
|
||||
if (maxLocals < 4) maxLocals = 4;
|
||||
decStack();
|
||||
}
|
||||
|
||||
//--------------------//
|
||||
// Stack manipulation //
|
||||
//--------------------//
|
||||
|
||||
public void opc_pop() {
|
||||
emitByte(opc_pop);
|
||||
decStack();
|
||||
}
|
||||
|
||||
public void opc_dup() {
|
||||
emitByte(opc_dup);
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_dup_x1() {
|
||||
emitByte(opc_dup_x1);
|
||||
incStack();
|
||||
}
|
||||
|
||||
public void opc_swap() {
|
||||
emitByte(opc_swap);
|
||||
}
|
||||
|
||||
//---------------------------//
|
||||
// Widening conversions only //
|
||||
//---------------------------//
|
||||
|
||||
public void opc_i2l() {
|
||||
emitByte(opc_i2l);
|
||||
}
|
||||
|
||||
public void opc_i2f() {
|
||||
emitByte(opc_i2f);
|
||||
}
|
||||
|
||||
public void opc_i2d() {
|
||||
emitByte(opc_i2d);
|
||||
}
|
||||
|
||||
public void opc_l2f() {
|
||||
emitByte(opc_l2f);
|
||||
}
|
||||
|
||||
public void opc_l2d() {
|
||||
emitByte(opc_l2d);
|
||||
}
|
||||
|
||||
public void opc_f2d() {
|
||||
emitByte(opc_f2d);
|
||||
}
|
||||
|
||||
//--------------//
|
||||
// Control flow //
|
||||
//--------------//
|
||||
|
||||
public void opc_ifeq(short bciOffset) {
|
||||
emitByte(opc_ifeq);
|
||||
emitShort(bciOffset);
|
||||
decStack();
|
||||
}
|
||||
|
||||
/** Control flow with forward-reference BCI. Stack assumes
|
||||
straight-through control flow. */
|
||||
public void opc_ifeq(Label l) {
|
||||
short instrBCI = getLength();
|
||||
emitByte(opc_ifeq);
|
||||
l.add(this, instrBCI, getLength(), getStack() - 1);
|
||||
emitShort((short) -1); // Must be patched later
|
||||
}
|
||||
|
||||
public void opc_if_icmpeq(short bciOffset) {
|
||||
emitByte(opc_if_icmpeq);
|
||||
emitShort(bciOffset);
|
||||
setStack(getStack() - 2);
|
||||
}
|
||||
|
||||
/** Control flow with forward-reference BCI. Stack assumes straight
|
||||
control flow. */
|
||||
public void opc_if_icmpeq(Label l) {
|
||||
short instrBCI = getLength();
|
||||
emitByte(opc_if_icmpeq);
|
||||
l.add(this, instrBCI, getLength(), getStack() - 2);
|
||||
emitShort((short) -1); // Must be patched later
|
||||
}
|
||||
|
||||
public void opc_goto(short bciOffset) {
|
||||
emitByte(opc_goto);
|
||||
emitShort(bciOffset);
|
||||
}
|
||||
|
||||
/** Control flow with forward-reference BCI. Stack assumes straight
|
||||
control flow. */
|
||||
public void opc_goto(Label l) {
|
||||
short instrBCI = getLength();
|
||||
emitByte(opc_goto);
|
||||
l.add(this, instrBCI, getLength(), getStack());
|
||||
emitShort((short) -1); // Must be patched later
|
||||
}
|
||||
|
||||
public void opc_ifnull(short bciOffset) {
|
||||
emitByte(opc_ifnull);
|
||||
emitShort(bciOffset);
|
||||
decStack();
|
||||
}
|
||||
|
||||
/** Control flow with forward-reference BCI. Stack assumes straight
|
||||
control flow. */
|
||||
public void opc_ifnull(Label l) {
|
||||
short instrBCI = getLength();
|
||||
emitByte(opc_ifnull);
|
||||
l.add(this, instrBCI, getLength(), getStack() - 1);
|
||||
emitShort((short) -1); // Must be patched later
|
||||
decStack();
|
||||
}
|
||||
|
||||
public void opc_ifnonnull(short bciOffset) {
|
||||
emitByte(opc_ifnonnull);
|
||||
emitShort(bciOffset);
|
||||
decStack();
|
||||
}
|
||||
|
||||
/** Control flow with forward-reference BCI. Stack assumes straight
|
||||
control flow. */
|
||||
public void opc_ifnonnull(Label l) {
|
||||
short instrBCI = getLength();
|
||||
emitByte(opc_ifnonnull);
|
||||
l.add(this, instrBCI, getLength(), getStack() - 1);
|
||||
emitShort((short) -1); // Must be patched later
|
||||
decStack();
|
||||
}
|
||||
|
||||
//---------------------//
|
||||
// Return instructions //
|
||||
//---------------------//
|
||||
|
||||
public void opc_ireturn() {
|
||||
emitByte(opc_ireturn);
|
||||
setStack(0);
|
||||
}
|
||||
|
||||
public void opc_lreturn() {
|
||||
emitByte(opc_lreturn);
|
||||
setStack(0);
|
||||
}
|
||||
|
||||
public void opc_freturn() {
|
||||
emitByte(opc_freturn);
|
||||
setStack(0);
|
||||
}
|
||||
|
||||
public void opc_dreturn() {
|
||||
emitByte(opc_dreturn);
|
||||
setStack(0);
|
||||
}
|
||||
|
||||
public void opc_areturn() {
|
||||
emitByte(opc_areturn);
|
||||
setStack(0);
|
||||
}
|
||||
|
||||
public void opc_return() {
|
||||
emitByte(opc_return);
|
||||
setStack(0);
|
||||
}
|
||||
|
||||
//------------------//
|
||||
// Field operations //
|
||||
//------------------//
|
||||
|
||||
public void opc_getstatic(short fieldIndex, int fieldSizeInStackSlots) {
|
||||
emitByte(opc_getstatic);
|
||||
emitShort(fieldIndex);
|
||||
setStack(getStack() + fieldSizeInStackSlots);
|
||||
}
|
||||
|
||||
public void opc_putstatic(short fieldIndex, int fieldSizeInStackSlots) {
|
||||
emitByte(opc_putstatic);
|
||||
emitShort(fieldIndex);
|
||||
setStack(getStack() - fieldSizeInStackSlots);
|
||||
}
|
||||
|
||||
public void opc_getfield(short fieldIndex, int fieldSizeInStackSlots) {
|
||||
emitByte(opc_getfield);
|
||||
emitShort(fieldIndex);
|
||||
setStack(getStack() + fieldSizeInStackSlots - 1);
|
||||
}
|
||||
|
||||
public void opc_putfield(short fieldIndex, int fieldSizeInStackSlots) {
|
||||
emitByte(opc_putfield);
|
||||
emitShort(fieldIndex);
|
||||
setStack(getStack() - fieldSizeInStackSlots - 1);
|
||||
}
|
||||
|
||||
//--------------------//
|
||||
// Method invocations //
|
||||
//--------------------//
|
||||
|
||||
/** Long and double arguments and return types count as 2 arguments;
|
||||
other values count as 1. */
|
||||
public void opc_invokevirtual(short methodIndex,
|
||||
int numArgs,
|
||||
int numReturnValues)
|
||||
{
|
||||
emitByte(opc_invokevirtual);
|
||||
emitShort(methodIndex);
|
||||
setStack(getStack() - numArgs - 1 + numReturnValues);
|
||||
}
|
||||
|
||||
/** Long and double arguments and return types count as 2 arguments;
|
||||
other values count as 1. */
|
||||
public void opc_invokespecial(short methodIndex,
|
||||
int numArgs,
|
||||
int numReturnValues)
|
||||
{
|
||||
emitByte(opc_invokespecial);
|
||||
emitShort(methodIndex);
|
||||
setStack(getStack() - numArgs - 1 + numReturnValues);
|
||||
}
|
||||
|
||||
/** Long and double arguments and return types count as 2 arguments;
|
||||
other values count as 1. */
|
||||
public void opc_invokestatic(short methodIndex,
|
||||
int numArgs,
|
||||
int numReturnValues)
|
||||
{
|
||||
emitByte(opc_invokestatic);
|
||||
emitShort(methodIndex);
|
||||
setStack(getStack() - numArgs + numReturnValues);
|
||||
}
|
||||
|
||||
/** Long and double arguments and return types count as 2 arguments;
|
||||
other values count as 1. */
|
||||
public void opc_invokeinterface(short methodIndex,
|
||||
int numArgs,
|
||||
byte count,
|
||||
int numReturnValues)
|
||||
{
|
||||
emitByte(opc_invokeinterface);
|
||||
emitShort(methodIndex);
|
||||
emitByte(count);
|
||||
emitByte((byte) 0);
|
||||
setStack(getStack() - numArgs - 1 + numReturnValues);
|
||||
}
|
||||
|
||||
//--------------//
|
||||
// Array length //
|
||||
//--------------//
|
||||
|
||||
public void opc_arraylength() {
|
||||
emitByte(opc_arraylength);
|
||||
}
|
||||
|
||||
//-----//
|
||||
// New //
|
||||
//-----//
|
||||
|
||||
public void opc_new(short classIndex) {
|
||||
emitByte(opc_new);
|
||||
emitShort(classIndex);
|
||||
incStack();
|
||||
}
|
||||
|
||||
//--------//
|
||||
// Athrow //
|
||||
//--------//
|
||||
|
||||
public void opc_athrow() {
|
||||
emitByte(opc_athrow);
|
||||
setStack(1);
|
||||
}
|
||||
|
||||
//--------------------------//
|
||||
// Checkcast and instanceof //
|
||||
//--------------------------//
|
||||
|
||||
/** Assumes the checkcast succeeds */
|
||||
public void opc_checkcast(short classIndex) {
|
||||
emitByte(opc_checkcast);
|
||||
emitShort(classIndex);
|
||||
}
|
||||
|
||||
public void opc_instanceof(short classIndex) {
|
||||
emitByte(opc_instanceof);
|
||||
emitShort(classIndex);
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.internal.reflect;
|
||||
|
||||
/** Minimal set of class file constants for assembly of field and
|
||||
method accessors. */
|
||||
|
||||
interface ClassFileConstants {
|
||||
// Constants
|
||||
public static final byte opc_aconst_null = (byte) 0x1;
|
||||
public static final byte opc_sipush = (byte) 0x11;
|
||||
public static final byte opc_ldc = (byte) 0x12;
|
||||
|
||||
// Local variable loads and stores
|
||||
public static final byte opc_iload_0 = (byte) 0x1a;
|
||||
public static final byte opc_iload_1 = (byte) 0x1b;
|
||||
public static final byte opc_iload_2 = (byte) 0x1c;
|
||||
public static final byte opc_iload_3 = (byte) 0x1d;
|
||||
public static final byte opc_lload_0 = (byte) 0x1e;
|
||||
public static final byte opc_lload_1 = (byte) 0x1f;
|
||||
public static final byte opc_lload_2 = (byte) 0x20;
|
||||
public static final byte opc_lload_3 = (byte) 0x21;
|
||||
public static final byte opc_fload_0 = (byte) 0x22;
|
||||
public static final byte opc_fload_1 = (byte) 0x23;
|
||||
public static final byte opc_fload_2 = (byte) 0x24;
|
||||
public static final byte opc_fload_3 = (byte) 0x25;
|
||||
public static final byte opc_dload_0 = (byte) 0x26;
|
||||
public static final byte opc_dload_1 = (byte) 0x27;
|
||||
public static final byte opc_dload_2 = (byte) 0x28;
|
||||
public static final byte opc_dload_3 = (byte) 0x29;
|
||||
public static final byte opc_aload_0 = (byte) 0x2a;
|
||||
public static final byte opc_aload_1 = (byte) 0x2b;
|
||||
public static final byte opc_aload_2 = (byte) 0x2c;
|
||||
public static final byte opc_aload_3 = (byte) 0x2d;
|
||||
public static final byte opc_aaload = (byte) 0x32;
|
||||
public static final byte opc_astore_0 = (byte) 0x4b;
|
||||
public static final byte opc_astore_1 = (byte) 0x4c;
|
||||
public static final byte opc_astore_2 = (byte) 0x4d;
|
||||
public static final byte opc_astore_3 = (byte) 0x4e;
|
||||
|
||||
// Stack manipulation
|
||||
public static final byte opc_pop = (byte) 0x57;
|
||||
public static final byte opc_dup = (byte) 0x59;
|
||||
public static final byte opc_dup_x1 = (byte) 0x5a;
|
||||
public static final byte opc_swap = (byte) 0x5f;
|
||||
|
||||
// Conversions
|
||||
public static final byte opc_i2l = (byte) 0x85;
|
||||
public static final byte opc_i2f = (byte) 0x86;
|
||||
public static final byte opc_i2d = (byte) 0x87;
|
||||
public static final byte opc_l2i = (byte) 0x88;
|
||||
public static final byte opc_l2f = (byte) 0x89;
|
||||
public static final byte opc_l2d = (byte) 0x8a;
|
||||
public static final byte opc_f2i = (byte) 0x8b;
|
||||
public static final byte opc_f2l = (byte) 0x8c;
|
||||
public static final byte opc_f2d = (byte) 0x8d;
|
||||
public static final byte opc_d2i = (byte) 0x8e;
|
||||
public static final byte opc_d2l = (byte) 0x8f;
|
||||
public static final byte opc_d2f = (byte) 0x90;
|
||||
public static final byte opc_i2b = (byte) 0x91;
|
||||
public static final byte opc_i2c = (byte) 0x92;
|
||||
public static final byte opc_i2s = (byte) 0x93;
|
||||
|
||||
// Control flow
|
||||
public static final byte opc_ifeq = (byte) 0x99;
|
||||
public static final byte opc_if_icmpeq = (byte) 0x9f;
|
||||
public static final byte opc_goto = (byte) 0xa7;
|
||||
|
||||
// Return instructions
|
||||
public static final byte opc_ireturn = (byte) 0xac;
|
||||
public static final byte opc_lreturn = (byte) 0xad;
|
||||
public static final byte opc_freturn = (byte) 0xae;
|
||||
public static final byte opc_dreturn = (byte) 0xaf;
|
||||
public static final byte opc_areturn = (byte) 0xb0;
|
||||
public static final byte opc_return = (byte) 0xb1;
|
||||
|
||||
// Field operations
|
||||
public static final byte opc_getstatic = (byte) 0xb2;
|
||||
public static final byte opc_putstatic = (byte) 0xb3;
|
||||
public static final byte opc_getfield = (byte) 0xb4;
|
||||
public static final byte opc_putfield = (byte) 0xb5;
|
||||
|
||||
// Method invocations
|
||||
public static final byte opc_invokevirtual = (byte) 0xb6;
|
||||
public static final byte opc_invokespecial = (byte) 0xb7;
|
||||
public static final byte opc_invokestatic = (byte) 0xb8;
|
||||
public static final byte opc_invokeinterface = (byte) 0xb9;
|
||||
|
||||
// Array length
|
||||
public static final byte opc_arraylength = (byte) 0xbe;
|
||||
|
||||
// New
|
||||
public static final byte opc_new = (byte) 0xbb;
|
||||
|
||||
// Athrow
|
||||
public static final byte opc_athrow = (byte) 0xbf;
|
||||
|
||||
// Checkcast and instanceof
|
||||
public static final byte opc_checkcast = (byte) 0xc0;
|
||||
public static final byte opc_instanceof = (byte) 0xc1;
|
||||
|
||||
// Ifnull and ifnonnull
|
||||
public static final byte opc_ifnull = (byte) 0xc6;
|
||||
public static final byte opc_ifnonnull = (byte) 0xc7;
|
||||
|
||||
// Constant pool tags
|
||||
public static final byte CONSTANT_Class = (byte) 7;
|
||||
public static final byte CONSTANT_Fieldref = (byte) 9;
|
||||
public static final byte CONSTANT_Methodref = (byte) 10;
|
||||
public static final byte CONSTANT_InterfaceMethodref = (byte) 11;
|
||||
public static final byte CONSTANT_NameAndType = (byte) 12;
|
||||
public static final byte CONSTANT_String = (byte) 8;
|
||||
public static final byte CONSTANT_Utf8 = (byte) 1;
|
||||
|
||||
// Access flags
|
||||
public static final short ACC_PUBLIC = (short) 0x0001;
|
||||
}
|
@ -27,12 +27,7 @@ package jdk.internal.reflect;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/** Package-private implementation of the ConstructorAccessor
|
||||
interface which has access to all classes and all fields,
|
||||
regardless of language restrictions. See MagicAccessorImpl. */
|
||||
|
||||
abstract class ConstructorAccessorImpl extends MagicAccessorImpl
|
||||
implements ConstructorAccessor {
|
||||
abstract class ConstructorAccessorImpl implements ConstructorAccessor {
|
||||
/** Matches specification in {@link java.lang.reflect.Constructor} */
|
||||
public abstract Object newInstance(Object[] args)
|
||||
throws InstantiationException,
|
||||
|
@ -28,12 +28,7 @@ package jdk.internal.reflect;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
/** Package-private implementation of the FieldAccessor interface
|
||||
which has access to all classes and all fields, regardless of
|
||||
language restrictions. See MagicAccessorImpl. */
|
||||
|
||||
abstract class FieldAccessorImpl extends MagicAccessorImpl
|
||||
implements FieldAccessor {
|
||||
abstract class FieldAccessorImpl implements FieldAccessor {
|
||||
protected final Field field;
|
||||
|
||||
FieldAccessorImpl(Field field) {
|
||||
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.internal.reflect;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/** Allows forward references in bytecode streams emitted by
|
||||
ClassFileAssembler. Assumes that the start of the method body is
|
||||
the first byte in the assembler's buffer. May be used at more than
|
||||
one branch site. */
|
||||
|
||||
class Label {
|
||||
static class PatchInfo {
|
||||
PatchInfo(ClassFileAssembler asm,
|
||||
short instrBCI,
|
||||
short patchBCI,
|
||||
int stackDepth)
|
||||
{
|
||||
this.asm = asm;
|
||||
this.instrBCI = instrBCI;
|
||||
this.patchBCI = patchBCI;
|
||||
this.stackDepth = stackDepth;
|
||||
}
|
||||
// This won't work for more than one assembler anyway, so this is
|
||||
// unnecessary
|
||||
final ClassFileAssembler asm;
|
||||
final short instrBCI;
|
||||
final short patchBCI;
|
||||
final int stackDepth;
|
||||
}
|
||||
private final List<PatchInfo> patches = new ArrayList<>();
|
||||
|
||||
public Label() {
|
||||
}
|
||||
|
||||
void add(ClassFileAssembler asm,
|
||||
short instrBCI,
|
||||
short patchBCI,
|
||||
int stackDepth)
|
||||
{
|
||||
patches.add(new PatchInfo(asm, instrBCI, patchBCI, stackDepth));
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
for (PatchInfo patch : patches){
|
||||
short curBCI = patch.asm.getLength();
|
||||
short offset = (short) (curBCI - patch.instrBCI);
|
||||
patch.asm.emitShort(patch.patchBCI, offset);
|
||||
patch.asm.setStack(patch.stackDepth);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.internal.reflect;
|
||||
|
||||
/** <P> MagicAccessorImpl (named for parity with FieldAccessorImpl and
|
||||
others, not because it actually implements an interface) is a
|
||||
marker class in the hierarchy. All subclasses of this class are
|
||||
"magically" granted access by the VM to otherwise inaccessible
|
||||
fields and methods of other classes. It is used to hold the code
|
||||
for dynamically-generated FieldAccessorImpl and MethodAccessorImpl
|
||||
subclasses. (Use of the word "unsafe" was avoided in this class's
|
||||
name to avoid confusion with {@link jdk.internal.misc.Unsafe}.) </P>
|
||||
|
||||
<P> The bug fix for 4486457 also necessitated disabling
|
||||
verification for this class and all subclasses, as opposed to just
|
||||
SerializationConstructorAccessorImpl and subclasses, to avoid
|
||||
having to indicate to the VM which of these dynamically-generated
|
||||
stub classes were known to be able to pass the verifier. </P>
|
||||
|
||||
<P> Do not change the name of this class without also changing the
|
||||
VM's code. </P> */
|
||||
|
||||
class MagicAccessorImpl {
|
||||
}
|
@ -27,11 +27,7 @@ package jdk.internal.reflect;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/** <P> Package-private implementation of the MethodAccessor interface
|
||||
which has access to all classes and all fields, regardless of
|
||||
language restrictions. See MagicAccessor. </P>
|
||||
|
||||
<P> This class is known to the VM; do not change its name without
|
||||
/** <P> This class is known to the VM; do not change its name without
|
||||
also changing the VM's code. </P>
|
||||
|
||||
<P> NOTE: ALL methods of subclasses are skipped during security
|
||||
@ -40,8 +36,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||
methods for java.lang.reflect.Method.invoke(). </P>
|
||||
*/
|
||||
|
||||
abstract class MethodAccessorImpl extends MagicAccessorImpl
|
||||
implements MethodAccessor {
|
||||
abstract class MethodAccessorImpl implements MethodAccessor {
|
||||
/** Matches specification in {@link java.lang.reflect.Method} */
|
||||
public abstract Object invoke(Object obj, Object[] args)
|
||||
throws IllegalArgumentException, InvocationTargetException;
|
||||
|
@ -334,16 +334,8 @@ public class ReflectionFactory {
|
||||
|
||||
private final Constructor<?> generateConstructor(Class<?> cl,
|
||||
Constructor<?> constructorToCall) {
|
||||
ConstructorAccessor acc;
|
||||
if (useOldSerializableConstructor()) {
|
||||
acc = new SerializationConstructorAccessorGenerator().
|
||||
generateSerializationConstructor(cl,
|
||||
constructorToCall.getParameterTypes(),
|
||||
constructorToCall.getModifiers(),
|
||||
constructorToCall.getDeclaringClass());
|
||||
} else {
|
||||
acc = MethodHandleAccessorFactory.newSerializableConstructorAccessor(cl, constructorToCall);
|
||||
}
|
||||
ConstructorAccessor acc = MethodHandleAccessorFactory
|
||||
.newSerializableConstructorAccessor(cl, constructorToCall);
|
||||
// Unlike other root constructors, this constructor is not copied for mutation
|
||||
// but directly mutated, as it is not cached. To cache this constructor,
|
||||
// setAccessible call must be done on a copy and return that copy instead.
|
||||
@ -507,10 +499,6 @@ public class ReflectionFactory {
|
||||
return config().useNativeAccessorOnly;
|
||||
}
|
||||
|
||||
static boolean useOldSerializableConstructor() {
|
||||
return config().useOldSerializableConstructor;
|
||||
}
|
||||
|
||||
private static boolean disableSerialConstructorChecks() {
|
||||
return config().disableSerialConstructorChecks;
|
||||
}
|
||||
@ -527,7 +515,6 @@ public class ReflectionFactory {
|
||||
private static @Stable Config config;
|
||||
|
||||
private static final Config DEFAULT_CONFIG = new Config(false, // useNativeAccessorOnly
|
||||
false, // useOldSerializeableConstructor
|
||||
false); // disableSerialConstructorChecks
|
||||
|
||||
/**
|
||||
@ -542,7 +529,6 @@ public class ReflectionFactory {
|
||||
* is to override them.
|
||||
*/
|
||||
private record Config(boolean useNativeAccessorOnly,
|
||||
boolean useOldSerializableConstructor,
|
||||
boolean disableSerialConstructorChecks) {
|
||||
}
|
||||
|
||||
@ -566,12 +552,10 @@ public class ReflectionFactory {
|
||||
Properties props = GetPropertyAction.privilegedGetProperties();
|
||||
boolean useNativeAccessorOnly =
|
||||
"true".equals(props.getProperty("jdk.reflect.useNativeAccessorOnly"));
|
||||
boolean useOldSerializableConstructor =
|
||||
"true".equals(props.getProperty("jdk.reflect.useOldSerializableConstructor"));
|
||||
boolean disableSerialConstructorChecks =
|
||||
"true".equals(props.getProperty("jdk.disableSerialConstructorChecks"));
|
||||
|
||||
return new Config(useNativeAccessorOnly, useOldSerializableConstructor, disableSerialConstructorChecks);
|
||||
return new Config(useNativeAccessorOnly, disableSerialConstructorChecks);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,725 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.internal.reflect;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
|
||||
/** Generator for jdk.internal.reflect.SerializationConstructorAccessorImpl
|
||||
objects using bytecodes to implement a constructor for serialization
|
||||
returned by ReflectionFactory::newConstructorForSerialization. */
|
||||
|
||||
class SerializationConstructorAccessorGenerator extends AccessorGenerator {
|
||||
|
||||
private static final short NUM_BASE_CPOOL_ENTRIES = (short) 12;
|
||||
// One for invoke() plus one for constructor
|
||||
private static final short NUM_METHODS = (short) 2;
|
||||
// Only used if forSerialization is true
|
||||
private static final short NUM_SERIALIZATION_CPOOL_ENTRIES = (short) 2;
|
||||
|
||||
private static volatile int methodSymnum;
|
||||
private static volatile int constructorSymnum;
|
||||
private static volatile int serializationConstructorSymnum;
|
||||
|
||||
private Class<?> declaringClass;
|
||||
private Class<?>[] parameterTypes;
|
||||
private Class<?> returnType;
|
||||
private boolean isConstructor;
|
||||
private boolean forSerialization;
|
||||
|
||||
private short targetMethodRef;
|
||||
private short invokeIdx;
|
||||
private short invokeDescriptorIdx;
|
||||
// Constant pool index of CONSTANT_Class_info for first
|
||||
// non-primitive parameter type. Should be incremented by 2.
|
||||
private short nonPrimitiveParametersBaseIdx;
|
||||
|
||||
SerializationConstructorAccessorGenerator() {
|
||||
}
|
||||
|
||||
/** This routine is not thread-safe */
|
||||
public SerializationConstructorAccessorImpl
|
||||
generateSerializationConstructor(Class<?> declaringClass,
|
||||
Class<?>[] parameterTypes,
|
||||
int modifiers,
|
||||
Class<?> targetConstructorClass)
|
||||
{
|
||||
return (SerializationConstructorAccessorImpl)
|
||||
generate(declaringClass,
|
||||
"<init>",
|
||||
parameterTypes,
|
||||
Void.TYPE,
|
||||
modifiers,
|
||||
true,
|
||||
true,
|
||||
targetConstructorClass);
|
||||
}
|
||||
|
||||
/** This routine is not thread-safe */
|
||||
@SuppressWarnings("removal")
|
||||
private MagicAccessorImpl generate(final Class<?> declaringClass,
|
||||
String name,
|
||||
Class<?>[] parameterTypes,
|
||||
Class<?> returnType,
|
||||
int modifiers,
|
||||
boolean isConstructor,
|
||||
boolean forSerialization,
|
||||
Class<?> serializationTargetClass)
|
||||
{
|
||||
ByteVector vec = ByteVectorFactory.create();
|
||||
asm = new ClassFileAssembler(vec);
|
||||
this.declaringClass = declaringClass;
|
||||
this.parameterTypes = parameterTypes;
|
||||
this.returnType = returnType;
|
||||
this.modifiers = modifiers;
|
||||
this.isConstructor = isConstructor;
|
||||
this.forSerialization = forSerialization;
|
||||
|
||||
asm.emitMagicAndVersion();
|
||||
|
||||
// Constant pool entries:
|
||||
// ( * = Boxing information: optional)
|
||||
// (+ = Shared entries provided by AccessorGenerator)
|
||||
// (^ = Only present if generating SerializationConstructorAccessor)
|
||||
// [UTF-8] [This class's name]
|
||||
// [CONSTANT_Class_info] for above
|
||||
// [UTF-8] "jdk/internal/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}"
|
||||
// [CONSTANT_Class_info] for above
|
||||
// [UTF-8] [Target class's name]
|
||||
// [CONSTANT_Class_info] for above
|
||||
// ^ [UTF-8] [Serialization: Class's name in which to invoke constructor]
|
||||
// ^ [CONSTANT_Class_info] for above
|
||||
// [UTF-8] target method or constructor name
|
||||
// [UTF-8] target method or constructor signature
|
||||
// [CONSTANT_NameAndType_info] for above
|
||||
// [CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info] for target method
|
||||
// [UTF-8] "invoke" or "newInstance"
|
||||
// [UTF-8] invoke or newInstance descriptor
|
||||
// [UTF-8] descriptor for type of non-primitive parameter 1
|
||||
// [CONSTANT_Class_info] for type of non-primitive parameter 1
|
||||
// ...
|
||||
// [UTF-8] descriptor for type of non-primitive parameter n
|
||||
// [CONSTANT_Class_info] for type of non-primitive parameter n
|
||||
// + [UTF-8] "java/lang/Exception"
|
||||
// + [CONSTANT_Class_info] for above
|
||||
// + [UTF-8] "java/lang/ClassCastException"
|
||||
// + [CONSTANT_Class_info] for above
|
||||
// + [UTF-8] "java/lang/NullPointerException"
|
||||
// + [CONSTANT_Class_info] for above
|
||||
// + [UTF-8] "java/lang/IllegalArgumentException"
|
||||
// + [CONSTANT_Class_info] for above
|
||||
// + [UTF-8] "java/lang/InvocationTargetException"
|
||||
// + [CONSTANT_Class_info] for above
|
||||
// + [UTF-8] "<init>"
|
||||
// + [UTF-8] "()V"
|
||||
// + [CONSTANT_NameAndType_info] for above
|
||||
// + [CONSTANT_Methodref_info] for NullPointerException's constructor
|
||||
// + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor
|
||||
// + [UTF-8] "(Ljava/lang/String;)V"
|
||||
// + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/String;)V"
|
||||
// + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String
|
||||
// + [UTF-8] "(Ljava/lang/Throwable;)V"
|
||||
// + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/Throwable;)V"
|
||||
// + [CONSTANT_Methodref_info] for InvocationTargetException's constructor
|
||||
// + [CONSTANT_Methodref_info] for "super()"
|
||||
// + [UTF-8] "java/lang/Object"
|
||||
// + [CONSTANT_Class_info] for above
|
||||
// + [UTF-8] "toString"
|
||||
// + [UTF-8] "()Ljava/lang/String;"
|
||||
// + [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;"
|
||||
// + [CONSTANT_Methodref_info] for Object's toString method
|
||||
// + [UTF-8] "Code"
|
||||
// + [UTF-8] "Exceptions"
|
||||
// * [UTF-8] "java/lang/Boolean"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(Z)V"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "booleanValue"
|
||||
// * [UTF-8] "()Z"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Byte"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(B)V"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "byteValue"
|
||||
// * [UTF-8] "()B"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Character"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(C)V"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "charValue"
|
||||
// * [UTF-8] "()C"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Double"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(D)V"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "doubleValue"
|
||||
// * [UTF-8] "()D"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Float"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(F)V"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "floatValue"
|
||||
// * [UTF-8] "()F"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Integer"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(I)V"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "intValue"
|
||||
// * [UTF-8] "()I"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Long"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(J)V"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "longValue"
|
||||
// * [UTF-8] "()J"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "java/lang/Short"
|
||||
// * [CONSTANT_Class_info] for above
|
||||
// * [UTF-8] "(S)V"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
// * [UTF-8] "shortValue"
|
||||
// * [UTF-8] "()S"
|
||||
// * [CONSTANT_NameAndType_info] for above
|
||||
// * [CONSTANT_Methodref_info] for above
|
||||
|
||||
short numCPEntries = NUM_BASE_CPOOL_ENTRIES + NUM_COMMON_CPOOL_ENTRIES;
|
||||
boolean usesPrimitives = usesPrimitiveTypes();
|
||||
if (usesPrimitives) {
|
||||
numCPEntries += NUM_BOXING_CPOOL_ENTRIES;
|
||||
}
|
||||
if (forSerialization) {
|
||||
numCPEntries += NUM_SERIALIZATION_CPOOL_ENTRIES;
|
||||
}
|
||||
|
||||
// Add in variable-length number of entries to be able to describe
|
||||
// non-primitive parameter types and checked exceptions.
|
||||
numCPEntries += (short) (2 * numNonPrimitiveParameterTypes());
|
||||
|
||||
asm.emitShort(add(numCPEntries, S1));
|
||||
|
||||
final String generatedName = generateName(isConstructor, forSerialization);
|
||||
asm.emitConstantPoolUTF8(generatedName);
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
thisClass = asm.cpi();
|
||||
if (isConstructor) {
|
||||
if (forSerialization) {
|
||||
asm.emitConstantPoolUTF8
|
||||
("jdk/internal/reflect/SerializationConstructorAccessorImpl");
|
||||
} else {
|
||||
asm.emitConstantPoolUTF8("jdk/internal/reflect/ConstructorAccessorImpl");
|
||||
}
|
||||
} else {
|
||||
asm.emitConstantPoolUTF8("jdk/internal/reflect/MethodAccessorImpl");
|
||||
}
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
superClass = asm.cpi();
|
||||
asm.emitConstantPoolUTF8(getClassName(declaringClass, false));
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
targetClass = asm.cpi();
|
||||
short serializationTargetClassIdx = (short) 0;
|
||||
if (forSerialization) {
|
||||
asm.emitConstantPoolUTF8(getClassName(serializationTargetClass, false));
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
serializationTargetClassIdx = asm.cpi();
|
||||
}
|
||||
asm.emitConstantPoolUTF8(name);
|
||||
asm.emitConstantPoolUTF8(buildInternalSignature());
|
||||
asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
|
||||
if (isInterface()) {
|
||||
asm.emitConstantPoolInterfaceMethodref(targetClass, asm.cpi());
|
||||
} else {
|
||||
if (forSerialization) {
|
||||
asm.emitConstantPoolMethodref(serializationTargetClassIdx, asm.cpi());
|
||||
} else {
|
||||
asm.emitConstantPoolMethodref(targetClass, asm.cpi());
|
||||
}
|
||||
}
|
||||
targetMethodRef = asm.cpi();
|
||||
if (isConstructor) {
|
||||
asm.emitConstantPoolUTF8("newInstance");
|
||||
} else {
|
||||
asm.emitConstantPoolUTF8("invoke");
|
||||
}
|
||||
invokeIdx = asm.cpi();
|
||||
if (isConstructor) {
|
||||
asm.emitConstantPoolUTF8("([Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
} else {
|
||||
asm.emitConstantPoolUTF8
|
||||
("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
}
|
||||
invokeDescriptorIdx = asm.cpi();
|
||||
|
||||
// Output class information for non-primitive parameter types
|
||||
nonPrimitiveParametersBaseIdx = add(asm.cpi(), S2);
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
Class<?> c = parameterTypes[i];
|
||||
if (!isPrimitive(c)) {
|
||||
asm.emitConstantPoolUTF8(getClassName(c, false));
|
||||
asm.emitConstantPoolClass(asm.cpi());
|
||||
}
|
||||
}
|
||||
|
||||
// Entries common to FieldAccessor, MethodAccessor and ConstructorAccessor
|
||||
emitCommonConstantPoolEntries();
|
||||
|
||||
// Boxing entries
|
||||
if (usesPrimitives) {
|
||||
emitBoxingContantPoolEntries();
|
||||
}
|
||||
|
||||
if (asm.cpi() != numCPEntries) {
|
||||
throw new InternalError("Adjust this code (cpi = " + asm.cpi() +
|
||||
", numCPEntries = " + numCPEntries + ")");
|
||||
}
|
||||
|
||||
// Access flags
|
||||
asm.emitShort(ACC_PUBLIC);
|
||||
|
||||
// This class
|
||||
asm.emitShort(thisClass);
|
||||
|
||||
// Superclass
|
||||
asm.emitShort(superClass);
|
||||
|
||||
// Interfaces count and interfaces
|
||||
asm.emitShort(S0);
|
||||
|
||||
// Fields count and fields
|
||||
asm.emitShort(S0);
|
||||
|
||||
// Methods count and methods
|
||||
asm.emitShort(NUM_METHODS);
|
||||
|
||||
emitConstructor();
|
||||
emitInvoke();
|
||||
|
||||
// Additional attributes (none)
|
||||
asm.emitShort(S0);
|
||||
|
||||
// Load class
|
||||
vec.trim();
|
||||
final byte[] bytes = vec.getData();
|
||||
// Note: the class loader is the only thing that really matters
|
||||
// here -- it's important to get the generated code into the
|
||||
// same namespace as the target class. Since the generated code
|
||||
// is privileged anyway, the protection domain probably doesn't
|
||||
// matter.
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<MagicAccessorImpl>() {
|
||||
@SuppressWarnings("deprecation") // Class.newInstance
|
||||
public MagicAccessorImpl run() {
|
||||
try {
|
||||
return (MagicAccessorImpl)
|
||||
ClassDefiner.defineClass
|
||||
(generatedName,
|
||||
bytes,
|
||||
0,
|
||||
bytes.length,
|
||||
declaringClass.getClassLoader()).newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** This emits the code for either invoke() or newInstance() */
|
||||
private void emitInvoke() {
|
||||
// NOTE that this code will only handle 65535 parameters since we
|
||||
// use the sipush instruction to get the array index on the
|
||||
// operand stack.
|
||||
if (parameterTypes.length > 65535) {
|
||||
throw new InternalError("Can't handle more than 65535 parameters");
|
||||
}
|
||||
|
||||
// Generate code into fresh code buffer
|
||||
ClassFileAssembler cb = new ClassFileAssembler();
|
||||
if (isConstructor) {
|
||||
// 1 incoming argument
|
||||
cb.setMaxLocals(2);
|
||||
} else {
|
||||
// 2 incoming arguments
|
||||
cb.setMaxLocals(3);
|
||||
}
|
||||
|
||||
short illegalArgStartPC = 0;
|
||||
|
||||
if (isConstructor) {
|
||||
// Instantiate target class before continuing
|
||||
// new <target class type>
|
||||
// dup
|
||||
cb.opc_new(targetClass);
|
||||
cb.opc_dup();
|
||||
} else {
|
||||
// Get target object on operand stack if necessary.
|
||||
|
||||
// We need to do an explicit null check here; we won't see
|
||||
// NullPointerExceptions from the invoke bytecode, since it's
|
||||
// covered by an exception handler.
|
||||
if (!isStatic()) {
|
||||
// aload_1
|
||||
// ifnonnull <checkcast label>
|
||||
// new <NullPointerException>
|
||||
// dup
|
||||
// invokespecial <NullPointerException ctor>
|
||||
// athrow
|
||||
// <checkcast label:>
|
||||
// aload_1
|
||||
// checkcast <target class's type>
|
||||
cb.opc_aload_1();
|
||||
Label l = new Label();
|
||||
cb.opc_ifnonnull(l);
|
||||
cb.opc_new(nullPointerClass);
|
||||
cb.opc_dup();
|
||||
cb.opc_invokespecial(nullPointerCtorIdx, 0, 0);
|
||||
cb.opc_athrow();
|
||||
l.bind();
|
||||
illegalArgStartPC = cb.getLength();
|
||||
cb.opc_aload_1();
|
||||
cb.opc_checkcast(targetClass);
|
||||
}
|
||||
}
|
||||
|
||||
// Have to check length of incoming array and throw
|
||||
// IllegalArgumentException if not correct. A concession to the
|
||||
// JCK (isn't clearly specified in the spec): we allow null in the
|
||||
// case where the argument list is zero length.
|
||||
// if no-arg:
|
||||
// aload_2 | aload_1 (Method | Constructor)
|
||||
// ifnull <success label>
|
||||
// aload_2 | aload_1
|
||||
// arraylength
|
||||
// sipush <num parameter types>
|
||||
// if_icmpeq <success label>
|
||||
// new <IllegalArgumentException>
|
||||
// dup
|
||||
// invokespecial <IllegalArgumentException ctor>
|
||||
// athrow
|
||||
// <success label:>
|
||||
Label successLabel = new Label();
|
||||
if (parameterTypes.length == 0) {
|
||||
if (isConstructor) {
|
||||
cb.opc_aload_1();
|
||||
} else {
|
||||
cb.opc_aload_2();
|
||||
}
|
||||
cb.opc_ifnull(successLabel);
|
||||
}
|
||||
if (isConstructor) {
|
||||
cb.opc_aload_1();
|
||||
} else {
|
||||
cb.opc_aload_2();
|
||||
}
|
||||
cb.opc_arraylength();
|
||||
cb.opc_sipush((short) parameterTypes.length);
|
||||
cb.opc_if_icmpeq(successLabel);
|
||||
cb.opc_new(illegalArgumentClass);
|
||||
cb.opc_dup();
|
||||
cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0);
|
||||
cb.opc_athrow();
|
||||
successLabel.bind();
|
||||
|
||||
// Iterate through incoming actual parameters, ensuring that each
|
||||
// is compatible with the formal parameter type, and pushing the
|
||||
// actual on the operand stack (unboxing and widening if necessary).
|
||||
|
||||
short paramTypeCPIdx = nonPrimitiveParametersBaseIdx;
|
||||
Label nextParamLabel = null;
|
||||
byte count = 1; // both invokeinterface opcode's "count" as well as
|
||||
// num args of other invoke bytecodes
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
Class<?> paramType = parameterTypes[i];
|
||||
count += (byte) typeSizeInStackSlots(paramType);
|
||||
if (nextParamLabel != null) {
|
||||
nextParamLabel.bind();
|
||||
nextParamLabel = null;
|
||||
}
|
||||
// aload_2 | aload_1
|
||||
// sipush <index>
|
||||
// aaload
|
||||
if (isConstructor) {
|
||||
cb.opc_aload_1();
|
||||
} else {
|
||||
cb.opc_aload_2();
|
||||
}
|
||||
cb.opc_sipush((short) i);
|
||||
cb.opc_aaload();
|
||||
if (isPrimitive(paramType)) {
|
||||
// Unboxing code.
|
||||
// Put parameter into temporary local variable
|
||||
// astore_3 | astore_2
|
||||
if (isConstructor) {
|
||||
cb.opc_astore_2();
|
||||
} else {
|
||||
cb.opc_astore_3();
|
||||
}
|
||||
|
||||
// repeat for all possible widening conversions:
|
||||
// aload_3 | aload_2
|
||||
// instanceof <primitive boxing type>
|
||||
// ifeq <next unboxing label>
|
||||
// aload_3 | aload_2
|
||||
// checkcast <primitive boxing type> // Note: this is "redundant",
|
||||
// // but necessary for the verifier
|
||||
// invokevirtual <unboxing method>
|
||||
// <widening conversion bytecode, if necessary>
|
||||
// goto <next parameter label>
|
||||
// <next unboxing label:> ...
|
||||
// last unboxing label:
|
||||
// new <IllegalArgumentException>
|
||||
// dup
|
||||
// invokespecial <IllegalArgumentException ctor>
|
||||
// athrow
|
||||
|
||||
Label l = null; // unboxing label
|
||||
nextParamLabel = new Label();
|
||||
|
||||
for (int j = 0; j < primitiveTypes.length; j++) {
|
||||
Class<?> c = primitiveTypes[j];
|
||||
if (canWidenTo(c, paramType)) {
|
||||
if (l != null) {
|
||||
l.bind();
|
||||
}
|
||||
// Emit checking and unboxing code for this type
|
||||
if (isConstructor) {
|
||||
cb.opc_aload_2();
|
||||
} else {
|
||||
cb.opc_aload_3();
|
||||
}
|
||||
cb.opc_instanceof(indexForPrimitiveType(c));
|
||||
l = new Label();
|
||||
cb.opc_ifeq(l);
|
||||
if (isConstructor) {
|
||||
cb.opc_aload_2();
|
||||
} else {
|
||||
cb.opc_aload_3();
|
||||
}
|
||||
cb.opc_checkcast(indexForPrimitiveType(c));
|
||||
cb.opc_invokevirtual(unboxingMethodForPrimitiveType(c),
|
||||
0,
|
||||
typeSizeInStackSlots(c));
|
||||
emitWideningBytecodeForPrimitiveConversion(cb,
|
||||
c,
|
||||
paramType);
|
||||
cb.opc_goto(nextParamLabel);
|
||||
}
|
||||
}
|
||||
|
||||
if (l == null) {
|
||||
throw new InternalError
|
||||
("Must have found at least identity conversion");
|
||||
}
|
||||
|
||||
// Fell through; given object is null or invalid. According to
|
||||
// the spec, we can throw IllegalArgumentException for both of
|
||||
// these cases.
|
||||
|
||||
l.bind();
|
||||
cb.opc_new(illegalArgumentClass);
|
||||
cb.opc_dup();
|
||||
cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0);
|
||||
cb.opc_athrow();
|
||||
} else {
|
||||
// Emit appropriate checkcast
|
||||
cb.opc_checkcast(paramTypeCPIdx);
|
||||
paramTypeCPIdx = add(paramTypeCPIdx, S2);
|
||||
// Fall through to next argument
|
||||
}
|
||||
}
|
||||
// Bind last goto if present
|
||||
if (nextParamLabel != null) {
|
||||
nextParamLabel.bind();
|
||||
}
|
||||
|
||||
short invokeStartPC = cb.getLength();
|
||||
|
||||
// OK, ready to perform the invocation.
|
||||
if (isConstructor) {
|
||||
cb.opc_invokespecial(targetMethodRef, count, 0);
|
||||
} else {
|
||||
if (isStatic()) {
|
||||
cb.opc_invokestatic(targetMethodRef,
|
||||
count,
|
||||
typeSizeInStackSlots(returnType));
|
||||
} else {
|
||||
if (isInterface()) {
|
||||
cb.opc_invokeinterface(targetMethodRef,
|
||||
count,
|
||||
count,
|
||||
typeSizeInStackSlots(returnType));
|
||||
} else {
|
||||
cb.opc_invokevirtual(targetMethodRef,
|
||||
count,
|
||||
typeSizeInStackSlots(returnType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
short invokeEndPC = cb.getLength();
|
||||
|
||||
if (!isConstructor) {
|
||||
// Box return value if necessary
|
||||
if (isPrimitive(returnType)) {
|
||||
cb.opc_invokestatic(boxingMethodForPrimitiveType(returnType),
|
||||
typeSizeInStackSlots(returnType),
|
||||
0);
|
||||
} else if (returnType == Void.TYPE) {
|
||||
cb.opc_aconst_null();
|
||||
}
|
||||
}
|
||||
cb.opc_areturn();
|
||||
|
||||
// We generate two exception handlers; one which is responsible
|
||||
// for catching ClassCastException and NullPointerException and
|
||||
// throwing IllegalArgumentException, and the other which catches
|
||||
// all java/lang/Throwable objects thrown from the target method
|
||||
// and wraps them in InvocationTargetExceptions.
|
||||
|
||||
short classCastHandler = cb.getLength();
|
||||
|
||||
// ClassCast, etc. exception handler
|
||||
cb.setStack(1);
|
||||
cb.opc_invokespecial(toStringIdx, 0, 1);
|
||||
cb.opc_new(illegalArgumentClass);
|
||||
cb.opc_dup_x1();
|
||||
cb.opc_swap();
|
||||
cb.opc_invokespecial(illegalArgumentStringCtorIdx, 1, 0);
|
||||
cb.opc_athrow();
|
||||
|
||||
short invocationTargetHandler = cb.getLength();
|
||||
|
||||
// InvocationTargetException exception handler
|
||||
cb.setStack(1);
|
||||
cb.opc_new(invocationTargetClass);
|
||||
cb.opc_dup_x1();
|
||||
cb.opc_swap();
|
||||
cb.opc_invokespecial(invocationTargetCtorIdx, 1, 0);
|
||||
cb.opc_athrow();
|
||||
|
||||
// Generate exception table. We cover the entire code sequence
|
||||
// with an exception handler which catches ClassCastException and
|
||||
// converts it into an IllegalArgumentException.
|
||||
|
||||
ClassFileAssembler exc = new ClassFileAssembler();
|
||||
|
||||
exc.emitShort(illegalArgStartPC); // start PC
|
||||
exc.emitShort(invokeStartPC); // end PC
|
||||
exc.emitShort(classCastHandler); // handler PC
|
||||
exc.emitShort(classCastClass); // catch type
|
||||
|
||||
exc.emitShort(illegalArgStartPC); // start PC
|
||||
exc.emitShort(invokeStartPC); // end PC
|
||||
exc.emitShort(classCastHandler); // handler PC
|
||||
exc.emitShort(nullPointerClass); // catch type
|
||||
|
||||
exc.emitShort(invokeStartPC); // start PC
|
||||
exc.emitShort(invokeEndPC); // end PC
|
||||
exc.emitShort(invocationTargetHandler); // handler PC
|
||||
exc.emitShort(throwableClass); // catch type
|
||||
|
||||
emitMethod(invokeIdx, cb.getMaxLocals(), cb, exc,
|
||||
new short[] { invocationTargetClass });
|
||||
}
|
||||
|
||||
private boolean usesPrimitiveTypes() {
|
||||
// We need to emit boxing/unboxing constant pool information if
|
||||
// the method takes a primitive type for any of its parameters or
|
||||
// returns a primitive value (except void)
|
||||
if (returnType.isPrimitive()) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
if (parameterTypes[i].isPrimitive()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int numNonPrimitiveParameterTypes() {
|
||||
int num = 0;
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
if (!parameterTypes[i].isPrimitive()) {
|
||||
++num;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
private boolean isInterface() {
|
||||
return declaringClass.isInterface();
|
||||
}
|
||||
|
||||
private String buildInternalSignature() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
sb.append(getClassName(parameterTypes[i], true));
|
||||
}
|
||||
sb.append(")");
|
||||
sb.append(getClassName(returnType, true));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static synchronized String generateName(boolean isConstructor,
|
||||
boolean forSerialization)
|
||||
{
|
||||
if (isConstructor) {
|
||||
if (forSerialization) {
|
||||
int num = ++serializationConstructorSymnum;
|
||||
return "jdk/internal/reflect/GeneratedSerializationConstructorAccessor" + num;
|
||||
} else {
|
||||
int num = ++constructorSymnum;
|
||||
return "jdk/internal/reflect/GeneratedConstructorAccessor" + num;
|
||||
}
|
||||
} else {
|
||||
int num = ++methodSymnum;
|
||||
return "jdk/internal/reflect/GeneratedMethodAccessor" + num;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.internal.reflect;
|
||||
|
||||
/** <P> Java serialization (in java.io) expects to be able to
|
||||
instantiate a class and invoke a no-arg constructor of that
|
||||
class's first non-Serializable superclass. This is not a valid
|
||||
operation according to the VM specification; one can not (for
|
||||
classes A and B, where B is a subclass of A) write "new B;
|
||||
invokespecial A()" without getting a verification error. </P>
|
||||
|
||||
<P> In all other respects, the bytecode-based reflection framework
|
||||
can be reused for this purpose. This marker class was originally
|
||||
known to the VM and verification disabled for it and all
|
||||
subclasses, but the bug fix for 4486457 necessitated disabling
|
||||
verification for all of the dynamically-generated bytecodes
|
||||
associated with reflection. This class has been left in place to
|
||||
make future debugging easier. </P> */
|
||||
|
||||
abstract class SerializationConstructorAccessorImpl
|
||||
extends ConstructorAccessorImpl {
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user