1 /*
2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.xml.internal.bind.v2.runtime.reflect.opt;
27
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.Method;
30 import java.lang.ref.WeakReference;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import java.util.concurrent.locks.Lock;
34 import java.util.concurrent.locks.ReentrantReadWriteLock;
35 import java.util.HashMap;
36 import java.util.Map;
37 import java.util.WeakHashMap;
38 import java.util.logging.Level;
39 import java.util.logging.Logger;
40
41 import com.sun.xml.internal.bind.Util;
42 import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor;
43
44 /**
45 * A {@link ClassLoader} used to "inject" optimized accessor classes
46 * into the VM.
47 *
48 * <p>
49 * Its parent class loader needs to be set to the one that can see the user
50 * class.
51 *
52 * @author Kohsuke Kawaguchi
53 */
54 final class Injector {
55
56 /**
57 * {@link Injector}s keyed by their parent {@link ClassLoader}.
58 *
59 * We only need one injector per one user class loader.
60 */
61 private static final ReentrantReadWriteLock irwl = new ReentrantReadWriteLock();
62 private static final Lock ir = irwl.readLock();
114 try {
115 wr = new WeakReference<Injector>(injector = new Injector(cl));
116 iw.lock();
117 try {
118 if (!injectors.containsKey(cl)) {
119 injectors.put(cl, wr);
120 }
121 } finally {
122 iw.unlock();
123 }
124 } catch (SecurityException e) {
125 logger.log(Level.FINE, "Unable to set up a back-door for the injector", e);
126 return null;
127 }
128 }
129 return injector;
130 }
131 /**
132 * Injected classes keyed by their names.
133 */
134 private final Map<String, Class> classes = new HashMap<String, Class>();
135 private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
136 private final Lock r = rwl.readLock();
137 private final Lock w = rwl.writeLock();
138 private final ClassLoader parent;
139 /**
140 * True if this injector is capable of injecting accessors.
141 * False otherwise, which happens if this classloader can't see {@link Accessor}.
142 */
143 private final boolean loadable;
144 private static final Method defineClass;
145 private static final Method resolveClass;
146 private static final Method findLoadedClass;
147
148 static {
149 Method[] m = AccessController.doPrivileged(
150 new PrivilegedAction<Method[]>() {
151 @Override
152 public Method[] run() {
153 return new Method[]{
154 getMethod(ClassLoader.class, "defineClass", String.class, byte[].class, Integer.TYPE, Integer.TYPE),
155 getMethod(ClassLoader.class, "resolveClass", Class.class),
156 getMethod(ClassLoader.class, "findLoadedClass", String.class)
157 };
158 }
159 }
160 );
161 defineClass = m[0];
162 resolveClass = m[1];
163 findLoadedClass = m[2];
164 }
165
166 private static Method getMethod(final Class<?> c, final String methodname, final Class<?>... params) {
167 try {
168 Method m = c.getDeclaredMethod(methodname, params);
169 m.setAccessible(true);
170 return m;
171 } catch (NoSuchMethodException e) {
172 throw new NoSuchMethodError(e.getMessage());
173 }
174 }
175
176 private Injector(ClassLoader parent) {
177 this.parent = parent;
178 assert parent != null;
179
180 boolean loadableCheck = false;
181
182 try {
183 loadableCheck = parent.loadClass(Accessor.class.getName()) == Accessor.class;
193 if (!loadable) // this injector cannot inject anything
194 {
195 return null;
196 }
197
198 boolean wlocked = false;
199 boolean rlocked = false;
200 try {
201
202 r.lock();
203 rlocked = true;
204
205 Class c = classes.get(className);
206
207 // Unlock now during the findLoadedClass process to avoid
208 // deadlocks
209 r.unlock();
210 rlocked = false;
211
212 //find loaded class from classloader
213 if (c == null) {
214
215 try {
216 c = (Class) findLoadedClass.invoke(parent, className.replace('/', '.'));
217 } catch (IllegalArgumentException e) {
218 logger.log(Level.FINE, "Unable to find " + className, e);
219 } catch (IllegalAccessException e) {
220 logger.log(Level.FINE, "Unable to find " + className, e);
221 } catch (InvocationTargetException e) {
222 Throwable t = e.getTargetException();
223 logger.log(Level.FINE, "Unable to find " + className, t);
224 }
225
226 if (c != null) {
227
228 w.lock();
229 wlocked = true;
230
231 classes.put(className, c);
232
233 w.unlock();
234 wlocked = false;
235
236 return c;
237 }
238 }
239
240 if (c == null) {
241
242 r.lock();
243 rlocked = true;
244
245 c = classes.get(className);
246
247 // Unlock now during the define/resolve process to avoid
248 // deadlocks
249 r.unlock();
250 rlocked = false;
251
252 if (c == null) {
253
254 // we need to inject a class into the
255 try {
256 c = (Class) defineClass.invoke(parent, className.replace('/', '.'), image, 0, image.length);
257 resolveClass.invoke(parent, c);
258 } catch (IllegalAccessException e) {
259 logger.log(Level.FINE, "Unable to inject " + className, e);
260 return null;
261 } catch (InvocationTargetException e) {
262 Throwable t = e.getTargetException();
263 if (t instanceof LinkageError) {
264 logger.log(Level.FINE, "duplicate class definition bug occured? Please report this : " + className, t);
265 } else {
266 logger.log(Level.FINE, "Unable to inject " + className, t);
267 }
268 return null;
269 } catch (SecurityException e) {
270 logger.log(Level.FINE, "Unable to inject " + className, e);
271 return null;
272 } catch (LinkageError e) {
273 logger.log(Level.FINE, "Unable to inject " + className, e);
274 return null;
275 }
276
277 w.lock();
|
1 /*
2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.xml.internal.bind.v2.runtime.reflect.opt;
27
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.Method;
30 import java.lang.ref.WeakReference;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import java.util.concurrent.locks.Lock;
34 import java.util.concurrent.locks.ReentrantReadWriteLock;
35 import java.util.HashMap;
36 import java.util.Map;
37 import java.util.WeakHashMap;
38 import java.util.logging.Level;
39 import java.util.logging.Logger;
40
41 import com.sun.xml.internal.bind.Util;
42 import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor;
43 import java.lang.reflect.Field;
44 import java.security.CodeSource;
45 import java.security.PrivilegedActionException;
46 import java.security.PrivilegedExceptionAction;
47 import java.security.ProtectionDomain;
48
49 /**
50 * A {@link ClassLoader} used to "inject" optimized accessor classes
51 * into the VM.
52 *
53 * <p>
54 * Its parent class loader needs to be set to the one that can see the user
55 * class.
56 *
57 * @author Kohsuke Kawaguchi
58 */
59 final class Injector {
60
61 /**
62 * {@link Injector}s keyed by their parent {@link ClassLoader}.
63 *
64 * We only need one injector per one user class loader.
65 */
66 private static final ReentrantReadWriteLock irwl = new ReentrantReadWriteLock();
67 private static final Lock ir = irwl.readLock();
119 try {
120 wr = new WeakReference<Injector>(injector = new Injector(cl));
121 iw.lock();
122 try {
123 if (!injectors.containsKey(cl)) {
124 injectors.put(cl, wr);
125 }
126 } finally {
127 iw.unlock();
128 }
129 } catch (SecurityException e) {
130 logger.log(Level.FINE, "Unable to set up a back-door for the injector", e);
131 return null;
132 }
133 }
134 return injector;
135 }
136 /**
137 * Injected classes keyed by their names.
138 */
139 private final Map<String, Class> classes = new HashMap<>();
140 private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
141 private final Lock r = rwl.readLock();
142 private final Lock w = rwl.writeLock();
143 private final ClassLoader parent;
144 /**
145 * True if this injector is capable of injecting accessors.
146 * False otherwise, which happens if this classloader can't see {@link Accessor}.
147 */
148 private final boolean loadable;
149 private static Method defineClass;
150 private static Method resolveClass;
151 private static Method findLoadedClass;
152 private static Object U;
153
154 static {
155 try {
156 Method[] m = AccessController.doPrivileged(
157 new PrivilegedAction<Method[]>() {
158 @Override
159 public Method[] run() {
160 return new Method[]{
161 getMethod(ClassLoader.class, "defineClass", String.class, byte[].class, Integer.TYPE, Integer.TYPE),
162 getMethod(ClassLoader.class, "resolveClass", Class.class),
163 getMethod(ClassLoader.class, "findLoadedClass", String.class)
164 };
165 }
166 }
167 );
168 defineClass = m[0];
169 resolveClass = m[1];
170 findLoadedClass = m[2];
171 } catch (Throwable t) {
172 try {
173 U = AccessController.doPrivileged(new PrivilegedExceptionAction() {
174 @Override
175 public Object run() throws Exception {
176 Class u = Class.forName("sun.misc.Unsafe");
177 Field theUnsafe = u.getDeclaredField("theUnsafe");
178 theUnsafe.setAccessible(true);
179 return theUnsafe.get(null);
180 }
181 });
182 defineClass = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
183 @Override
184 public Method run() throws Exception {
185 try {
186 return U.getClass().getMethod("defineClass",
187 new Class[]{String.class,
188 byte[].class,
189 Integer.TYPE,
190 Integer.TYPE,
191 ClassLoader.class,
192 ProtectionDomain.class});
193 } catch (NoSuchMethodException | SecurityException ex) {
194 throw ex;
195 }
196 }
197 });
198 } catch (SecurityException | PrivilegedActionException ex) {
199 Logger.getLogger(Injector.class.getName()).log(Level.SEVERE, null, ex);
200 }
201 }
202 }
203
204 private static Method getMethod(final Class<?> c, final String methodname, final Class<?>... params) {
205 try {
206 Method m = c.getDeclaredMethod(methodname, params);
207 m.setAccessible(true);
208 return m;
209 } catch (NoSuchMethodException e) {
210 throw new NoSuchMethodError(e.getMessage());
211 }
212 }
213
214 private Injector(ClassLoader parent) {
215 this.parent = parent;
216 assert parent != null;
217
218 boolean loadableCheck = false;
219
220 try {
221 loadableCheck = parent.loadClass(Accessor.class.getName()) == Accessor.class;
231 if (!loadable) // this injector cannot inject anything
232 {
233 return null;
234 }
235
236 boolean wlocked = false;
237 boolean rlocked = false;
238 try {
239
240 r.lock();
241 rlocked = true;
242
243 Class c = classes.get(className);
244
245 // Unlock now during the findLoadedClass process to avoid
246 // deadlocks
247 r.unlock();
248 rlocked = false;
249
250 //find loaded class from classloader
251 if (c == null && findLoadedClass != null) {
252
253 try {
254 c = (Class) findLoadedClass.invoke(parent, className.replace('/', '.'));
255 } catch (IllegalArgumentException | IllegalAccessException e) {
256 logger.log(Level.FINE, "Unable to find " + className, e);
257 } catch (InvocationTargetException e) {
258 Throwable t = e.getTargetException();
259 logger.log(Level.FINE, "Unable to find " + className, t);
260 }
261
262 if (c != null) {
263
264 w.lock();
265 wlocked = true;
266
267 classes.put(className, c);
268
269 w.unlock();
270 wlocked = false;
271
272 return c;
273 }
274 }
275
276 if (c == null) {
277
278 r.lock();
279 rlocked = true;
280
281 c = classes.get(className);
282
283 // Unlock now during the define/resolve process to avoid
284 // deadlocks
285 r.unlock();
286 rlocked = false;
287
288 if (c == null) {
289
290 // we need to inject a class into the
291 try {
292 if (resolveClass != null) {
293 c = (Class) defineClass.invoke(parent, className.replace('/', '.'), image, 0, image.length);
294 resolveClass.invoke(parent, c);
295 } else {
296 c = (Class) defineClass.invoke(U, className.replace('/', '.'), image, 0, image.length, parent, Injector.class.getProtectionDomain());
297 }
298 } catch (IllegalAccessException e) {
299 logger.log(Level.FINE, "Unable to inject " + className, e);
300 return null;
301 } catch (InvocationTargetException e) {
302 Throwable t = e.getTargetException();
303 if (t instanceof LinkageError) {
304 logger.log(Level.FINE, "duplicate class definition bug occured? Please report this : " + className, t);
305 } else {
306 logger.log(Level.FINE, "Unable to inject " + className, t);
307 }
308 return null;
309 } catch (SecurityException e) {
310 logger.log(Level.FINE, "Unable to inject " + className, e);
311 return null;
312 } catch (LinkageError e) {
313 logger.log(Level.FINE, "Unable to inject " + className, e);
314 return null;
315 }
316
317 w.lock();
|