@@ -66,16 +66,18 @@ public static String hash(byte[] classData, int offset, int length) {
66
66
private final ReentrantLock lock = new ReentrantLock ();
67
67
68
68
/** Predefined classes by hash. */
69
- private final EconomicMap <String , Class <?>> predefinedClassesByName = ImageHeapMap .create ();
69
+ private final EconomicMap <String , Class <?>> predefinedClassesByHash = ImageHeapMap .create ();
70
70
71
71
/** Predefined classes which have already been loaded, by name. */
72
72
private final EconomicMap <String , Class <?>> loadedClassesByName = EconomicMap .create ();
73
73
74
74
@ Platforms (Platform .HOSTED_ONLY .class )
75
75
public static void registerClass (String hash , Class <?> clazz ) {
76
- Class <?> existing = singleton ().predefinedClassesByName .putIfAbsent (hash , clazz );
77
- VMError .guarantee (existing == null , "Can define only one class per hash" );
78
- singleton ().predefinedClasses .add (clazz );
76
+ Class <?> existing = singleton ().predefinedClassesByHash .putIfAbsent (hash , clazz );
77
+ if (existing != clazz ) {
78
+ VMError .guarantee (existing == null , "Can define only one class per hash" );
79
+ singleton ().predefinedClasses .add (clazz );
80
+ }
79
81
}
80
82
81
83
@ Platforms (Platform .HOSTED_ONLY .class )
@@ -85,7 +87,7 @@ public static boolean isPredefined(Class<?> clazz) {
85
87
86
88
public static Class <?> loadClass (ClassLoader classLoader , String expectedName , byte [] data , int offset , int length , ProtectionDomain protectionDomain ) {
87
89
String hash = hash (data , offset , length );
88
- Class <?> clazz = singleton ().predefinedClassesByName .get (hash );
90
+ Class <?> clazz = singleton ().predefinedClassesByHash .get (hash );
89
91
if (clazz == null ) {
90
92
String name = (expectedName != null ) ? expectedName : "(name not specified)" ;
91
93
throw VMError .unsupportedFeature ("Defining a class from new bytecodes at run time is not supported. Class " + name +
@@ -97,7 +99,7 @@ public static Class<?> loadClass(ClassLoader classLoader, String expectedName, b
97
99
private Class <?> load (ClassLoader classLoader , ProtectionDomain protectionDomain , Class <?> clazz ) {
98
100
lock .lock ();
99
101
try {
100
- boolean alreadyLoaded = singleton (). loadedClassesByName .putIfAbsent (clazz .getName (), clazz ) != null ;
102
+ boolean alreadyLoaded = ( loadedClassesByName .get (clazz .getName ()) == clazz ) ;
101
103
if (alreadyLoaded ) {
102
104
if (classLoader == clazz .getClassLoader ()) {
103
105
throw new LinkageError ("loader " + classLoader + " attempted duplicate class definition for " + clazz .getName () + " defined by " + clazz .getClassLoader ());
@@ -107,6 +109,12 @@ private Class<?> load(ClassLoader classLoader, ProtectionDomain protectionDomain
107
109
"been loaded by class loader: " + clazz .getClassLoader ());
108
110
}
109
111
}
112
+
113
+ throwIfUnresolvable (clazz .getSuperclass (), classLoader );
114
+ for (Class <?> intf : clazz .getInterfaces ()) {
115
+ throwIfUnresolvable (intf , classLoader );
116
+ }
117
+
110
118
/*
111
119
* The following is part of the locked block so that other threads can observe only the
112
120
* initialized values once the class can be found.
@@ -116,12 +124,33 @@ private Class<?> load(ClassLoader classLoader, ProtectionDomain protectionDomain
116
124
if (protectionDomain != null ) {
117
125
hub .setProtectionDomainAtRuntime (protectionDomain );
118
126
}
127
+ loadedClassesByName .put (clazz .getName (), clazz );
119
128
return clazz ;
120
129
} finally {
121
130
lock .unlock ();
122
131
}
123
132
}
124
133
134
+ public static void throwIfUnresolvable (Class <?> clazz , ClassLoader classLoader ) {
135
+ if (clazz == null ) {
136
+ return ;
137
+ }
138
+ DynamicHub hub = DynamicHub .fromClass (clazz );
139
+ if (!hub .hasClassLoader ()) {
140
+ throwResolutionError (clazz .getName ());
141
+ }
142
+ if (!isSameOrParent (clazz .getClassLoader (), classLoader )) { // common case: same loader
143
+ throwResolutionError (clazz .getName ());
144
+ }
145
+ }
146
+
147
+ private static void throwResolutionError (String name ) {
148
+ // NoClassDefFoundError with ClassNotFoundException required by Java VM specification, 5.3
149
+ NoClassDefFoundError error = new NoClassDefFoundError (name .replace ('.' , '/' ));
150
+ error .initCause (new ClassNotFoundException (name ));
151
+ throw error ;
152
+ }
153
+
125
154
static Class <?> getLoadedForNameOrNull (String name , ClassLoader classLoader ) {
126
155
Class <?> clazz = singleton ().getLoaded (name );
127
156
if (clazz == null || !isSameOrParent (clazz .getClassLoader (), classLoader )) {
@@ -145,7 +174,7 @@ private static boolean isSameOrParent(ClassLoader parent, ClassLoader child) {
145
174
}
146
175
ClassLoader c = child ;
147
176
do {
148
- if (c == parent ) {
177
+ if (c == parent ) { // common case
149
178
return true ;
150
179
}
151
180
c = c .getParent ();
@@ -155,7 +184,7 @@ private static boolean isSameOrParent(ClassLoader parent, ClassLoader child) {
155
184
156
185
public static class TestingBackdoor {
157
186
public static UnmodifiableEconomicMap <String , Class <?>> getPredefinedClasses () {
158
- return singleton ().predefinedClassesByName ;
187
+ return singleton ().predefinedClassesByHash ;
159
188
}
160
189
}
161
190
}
0 commit comments