Proxy.java 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546
  1. /* Proxy.java -- build a proxy class that implements reflected interfaces
  2. Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. 02110-1301 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package java.lang.reflect;
  32. import gnu.java.lang.CPStringBuilder;
  33. import gnu.java.lang.reflect.TypeSignature;
  34. import java.io.Serializable;
  35. import java.security.ProtectionDomain;
  36. import java.util.Arrays;
  37. import java.util.HashMap;
  38. import java.util.HashSet;
  39. import java.util.Iterator;
  40. import java.util.Map;
  41. import java.util.Set;
  42. /**
  43. * This class allows you to dynamically create an instance of any (or
  44. * even multiple) interfaces by reflection, and decide at runtime
  45. * how that instance will behave by giving it an appropriate
  46. * {@link InvocationHandler}. Proxy classes serialize specially, so
  47. * that the proxy object can be reused between VMs, without requiring
  48. * a persistent copy of the generated class code.
  49. *
  50. * <h3>Creation</h3>
  51. * To create a proxy for some interface Foo:
  52. *
  53. * <pre>
  54. * InvocationHandler handler = new MyInvocationHandler(...);
  55. * Class proxyClass = Proxy.getProxyClass(
  56. * Foo.class.getClassLoader(), new Class[] { Foo.class });
  57. * Foo f = (Foo) proxyClass
  58. * .getConstructor(new Class[] { InvocationHandler.class })
  59. * .newInstance(new Object[] { handler });
  60. * </pre>
  61. * or more simply:
  62. * <pre>
  63. * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
  64. * new Class[] { Foo.class },
  65. * handler);
  66. * </pre>
  67. *
  68. * <h3>Dynamic Proxy Classes</h3>
  69. * A dynamic proxy class is created at runtime, and has the following
  70. * properties:
  71. * <ul>
  72. * <li>The class is <code>public</code> and <code>final</code>,
  73. * and is neither <code>abstract</code> nor an inner class.</li>
  74. * <li>The class has no canonical name (there is no formula you can use
  75. * to determine or generate its name), but begins with the
  76. * sequence "$Proxy". Abuse this knowledge at your own peril.
  77. * (For now, '$' in user identifiers is legal, but it may not
  78. * be that way forever. You weren't using '$' in your
  79. * identifiers, were you?)</li>
  80. * <li>The class extends Proxy, and explicitly implements all the
  81. * interfaces specified at creation, in order (this is important
  82. * for determining how method invocation is resolved). Note that
  83. * a proxy class implements {@link Serializable}, at least
  84. * implicitly, since Proxy does, but true serial behavior
  85. * depends on using a serializable invocation handler as well.</li>
  86. * <li>If at least one interface is non-public, the proxy class
  87. * will be in the same package. Otherwise, the package is
  88. * unspecified. This will work even if the package is sealed
  89. * from user-generated classes, because Proxy classes are
  90. * generated by a trusted source. Meanwhile, the proxy class
  91. * belongs to the classloader you designated.</li>
  92. * <li>Reflection works as expected: {@link Class#getInterfaces()} and
  93. * {@link Class#getMethods()} work as they do on normal classes.</li>
  94. * <li>The method {@link #isProxyClass(Class)} will distinguish between
  95. * true proxy classes and user extensions of this class. It only
  96. * returns true for classes created by {@link #getProxyClass}.</li>
  97. * <li>The {@link ProtectionDomain} of a proxy class is the same as for
  98. * bootstrap classes, such as Object or Proxy, since it is created by
  99. * a trusted source. This protection domain will typically be granted
  100. * {@link java.security.AllPermission}. But this is not a security
  101. * risk, since there are adequate permissions on reflection, which is
  102. * the only way to create an instance of the proxy class.</li>
  103. * <li>The proxy class contains a single constructor, which takes as
  104. * its only argument an {@link InvocationHandler}. The method
  105. * {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)}
  106. * is shorthand to do the necessary reflection.</li>
  107. * </ul>
  108. *
  109. * <h3>Proxy Instances</h3>
  110. * A proxy instance is an instance of a proxy class. It has the
  111. * following properties, many of which follow from the properties of a
  112. * proxy class listed above:
  113. * <ul>
  114. * <li>For a proxy class with Foo listed as one of its interfaces, the
  115. * expression <code>proxy instanceof Foo</code> will return true,
  116. * and the expression <code>(Foo) proxy</code> will succeed without
  117. * a {@link ClassCastException}.</li>
  118. * <li>Each proxy instance has an invocation handler, which can be
  119. * accessed by {@link #getInvocationHandler(Object)}. Any call
  120. * to an interface method, including {@link Object#hashCode()},
  121. * {@link Object#equals(Object)}, or {@link Object#toString()},
  122. * but excluding the public final methods of Object, will be
  123. * encoded and passed to the {@link InvocationHandler#invoke}
  124. * method of this handler.</li>
  125. * </ul>
  126. *
  127. * <h3>Inheritance Issues</h3>
  128. * A proxy class may inherit a method from more than one interface.
  129. * The order in which interfaces are listed matters, because it determines
  130. * which reflected {@link Method} object will be passed to the invocation
  131. * handler. This means that the dynamically generated class cannot
  132. * determine through which interface a method is being invoked.<p>
  133. *
  134. * In short, if a method is declared in Object (namely, hashCode,
  135. * equals, or toString), then Object will be used; otherwise, the
  136. * leftmost interface that inherits or declares a method will be used,
  137. * even if it has a more permissive throws clause than what the proxy
  138. * class is allowed. Thus, in the invocation handler, it is not always
  139. * safe to assume that every class listed in the throws clause of the
  140. * passed Method object can safely be thrown; fortunately, the Proxy
  141. * instance is robust enough to wrap all illegal checked exceptions in
  142. * {@link UndeclaredThrowableException}.
  143. *
  144. * @see InvocationHandler
  145. * @see UndeclaredThrowableException
  146. * @see Class
  147. * @author Eric Blake (ebb9@email.byu.edu)
  148. * @since 1.3
  149. * @status updated to 1.5, except for the use of ProtectionDomain
  150. */
  151. public class Proxy implements Serializable
  152. {
  153. /**
  154. * Compatible with JDK 1.3+.
  155. */
  156. private static final long serialVersionUID = -2222568056686623797L;
  157. /**
  158. * Map of ProxyType to proxy class.
  159. *
  160. * @XXX This prevents proxy classes from being garbage collected.
  161. * java.util.WeakHashSet is not appropriate, because that collects the
  162. * keys, but we are interested in collecting the elements.
  163. */
  164. private static final Map proxyClasses = new HashMap();
  165. /**
  166. * The invocation handler for this proxy instance. For Proxy, this
  167. * field is unused, but it appears here in order to be serialized in all
  168. * proxy classes.
  169. *
  170. * <em>NOTE</em>: This implementation is more secure for proxy classes
  171. * than what Sun specifies. Sun does not require h to be immutable, but
  172. * this means you could change h after the fact by reflection. However,
  173. * by making h immutable, we may break non-proxy classes which extend
  174. * Proxy.
  175. * @serial invocation handler associated with this proxy instance
  176. */
  177. protected InvocationHandler h;
  178. /**
  179. * Constructs a new Proxy from a subclass (usually a proxy class),
  180. * with the specified invocation handler.
  181. *
  182. * <em>NOTE</em>: This throws a NullPointerException if you attempt
  183. * to create a proxy instance with a null handler using reflection.
  184. * This behavior is not yet specified by Sun; see Sun Bug 4487672.
  185. *
  186. * @param handler the invocation handler, may be null if the subclass
  187. * is not a proxy class
  188. * @throws NullPointerException if handler is null and this is a proxy
  189. * instance
  190. */
  191. protected Proxy(InvocationHandler handler)
  192. {
  193. if (handler == null && isProxyClass(getClass()))
  194. throw new NullPointerException("invalid handler");
  195. h = handler;
  196. }
  197. /**
  198. * Returns the proxy {@link Class} for the given ClassLoader and array
  199. * of interfaces, dynamically generating it if necessary.
  200. *
  201. * <p>There are several restrictions on this method, the violation of
  202. * which will result in an IllegalArgumentException or
  203. * NullPointerException:</p>
  204. *
  205. * <ul>
  206. * <li>All objects in `interfaces' must represent distinct interfaces.
  207. * Classes, primitive types, null, and duplicates are forbidden.</li>
  208. * <li>The interfaces must be visible in the specified ClassLoader.
  209. * In other words, for each interface i:
  210. * <code>Class.forName(i.getName(), false, loader) == i</code>
  211. * must be true.</li>
  212. * <li>All non-public interfaces (if any) must reside in the same
  213. * package, or the proxy class would be non-instantiable. If
  214. * there are no non-public interfaces, the package of the proxy
  215. * class is unspecified.</li>
  216. * <li>All interfaces must be compatible - if two declare a method
  217. * with the same name and parameters, the return type must be
  218. * the same and the throws clause of the proxy class will be
  219. * the maximal subset of subclasses of the throws clauses for
  220. * each method that is overridden.</li>
  221. * <li>VM constraints limit the number of interfaces a proxy class
  222. * may directly implement (however, the indirect inheritance
  223. * of {@link Serializable} does not count against this limit).
  224. * Even though most VMs can theoretically have 65535
  225. * superinterfaces for a class, the actual limit is smaller
  226. * because a class's constant pool is limited to 65535 entries,
  227. * and not all entries can be interfaces.</li>
  228. * </ul>
  229. *
  230. * <p>Note that different orders of interfaces produce distinct classes.</p>
  231. *
  232. * @param loader the class loader to define the proxy class in; null
  233. * implies the bootstrap class loader
  234. * @param interfaces the array of interfaces the proxy class implements,
  235. * may be empty, but not null
  236. * @return the Class object of the proxy class
  237. * @throws IllegalArgumentException if the constraints above were
  238. * violated, except for problems with null
  239. * @throws NullPointerException if `interfaces' is null or contains
  240. * a null entry
  241. */
  242. // synchronized so that we aren't trying to build the same class
  243. // simultaneously in two threads
  244. public static synchronized Class<?> getProxyClass(ClassLoader loader,
  245. Class<?>... interfaces)
  246. {
  247. interfaces = (Class[]) interfaces.clone();
  248. ProxyType pt = new ProxyType(loader, interfaces);
  249. Class clazz = (Class) proxyClasses.get(pt);
  250. if (clazz == null)
  251. {
  252. if (VMProxy.HAVE_NATIVE_GET_PROXY_CLASS)
  253. clazz = VMProxy.getProxyClass(loader, interfaces);
  254. else
  255. {
  256. ProxyData data = (VMProxy.HAVE_NATIVE_GET_PROXY_DATA
  257. ? VMProxy.getProxyData(loader, interfaces)
  258. : ProxyData.getProxyData(pt));
  259. clazz = (VMProxy.HAVE_NATIVE_GENERATE_PROXY_CLASS
  260. ? VMProxy.generateProxyClass(loader, data)
  261. : new ClassFactory(data).generate(loader));
  262. }
  263. Object check = proxyClasses.put(pt, clazz);
  264. // assert check == null && clazz != null;
  265. if (check != null || clazz == null)
  266. throw new InternalError(/*"Fatal flaw in getProxyClass"*/);
  267. }
  268. return clazz;
  269. }
  270. /**
  271. * Combines several methods into one. This is equivalent to:
  272. * <pre>
  273. * Proxy.getProxyClass(loader, interfaces)
  274. * .getConstructor(new Class[] {InvocationHandler.class})
  275. * .newInstance(new Object[] {handler});
  276. * </pre>
  277. * except that it will not fail with the normal problems caused
  278. * by reflection. It can still fail for the same reasons documented
  279. * in getProxyClass, or if handler is null.
  280. *
  281. * @param loader the class loader to define the proxy class in; null
  282. * implies the bootstrap class loader
  283. * @param interfaces the array of interfaces the proxy class implements,
  284. * may be empty, but not null
  285. * @param handler the invocation handler, may not be null
  286. * @return a proxy instance implementing the specified interfaces
  287. * @throws IllegalArgumentException if the constraints for getProxyClass
  288. * were violated, except for problems with null
  289. * @throws NullPointerException if `interfaces' is null or contains
  290. * a null entry, or if handler is null
  291. * @see #getProxyClass(ClassLoader, Class[])
  292. * @see Class#getConstructor(Class[])
  293. * @see Constructor#newInstance(Object[])
  294. */
  295. public static Object newProxyInstance(ClassLoader loader,
  296. Class<?>[] interfaces,
  297. InvocationHandler handler)
  298. {
  299. try
  300. {
  301. // getProxyClass() and Proxy() throw the necessary exceptions
  302. return getProxyClass(loader, interfaces)
  303. .getConstructor(new Class[] {InvocationHandler.class})
  304. .newInstance(new Object[] {handler});
  305. }
  306. catch (RuntimeException e)
  307. {
  308. // Let IllegalArgumentException, NullPointerException escape.
  309. // assert e instanceof IllegalArgumentException
  310. // || e instanceof NullPointerException;
  311. throw e;
  312. }
  313. catch (InvocationTargetException e)
  314. {
  315. // Let wrapped NullPointerException escape.
  316. // assert e.getTargetException() instanceof NullPointerException
  317. throw (NullPointerException) e.getCause();
  318. }
  319. catch (Exception e)
  320. {
  321. // Covers InstantiationException, IllegalAccessException,
  322. // NoSuchMethodException, none of which should be generated
  323. // if the proxy class was generated correctly.
  324. // assert false;
  325. throw (Error) new InternalError("Unexpected: " + e).initCause(e);
  326. }
  327. }
  328. /**
  329. * Returns true if and only if the Class object is a dynamically created
  330. * proxy class (created by <code>getProxyClass</code> or by the
  331. * syntactic sugar of <code>newProxyInstance</code>).
  332. *
  333. * <p>This check is secure (in other words, it is not simply
  334. * <code>clazz.getSuperclass() == Proxy.class</code>), it will not
  335. * be spoofed by non-proxy classes that extend Proxy.
  336. *
  337. * @param clazz the class to check, must not be null
  338. * @return true if the class represents a proxy class
  339. * @throws NullPointerException if clazz is null
  340. */
  341. // This is synchronized on the off chance that another thread is
  342. // trying to add a class to the map at the same time we read it.
  343. public static synchronized boolean isProxyClass(Class<?> clazz)
  344. {
  345. if (! Proxy.class.isAssignableFrom(clazz))
  346. return false;
  347. // This is a linear search, even though we could do an O(1) search
  348. // using new ProxyType(clazz.getClassLoader(), clazz.getInterfaces()).
  349. return proxyClasses.containsValue(clazz);
  350. }
  351. /**
  352. * Returns the invocation handler for the given proxy instance.<p>
  353. *
  354. * <em>NOTE</em>: We guarantee a non-null result if successful,
  355. * but Sun allows the creation of a proxy instance with a null
  356. * handler. See the comments for {@link #Proxy(InvocationHandler)}.
  357. *
  358. * @param proxy the proxy instance, must not be null
  359. * @return the invocation handler, guaranteed non-null.
  360. * @throws IllegalArgumentException if
  361. * <code>Proxy.isProxyClass(proxy.getClass())</code> returns false.
  362. * @throws NullPointerException if proxy is null
  363. */
  364. public static InvocationHandler getInvocationHandler(Object proxy)
  365. {
  366. if (! isProxyClass(proxy.getClass()))
  367. throw new IllegalArgumentException("not a proxy instance");
  368. return ((Proxy) proxy).h;
  369. }
  370. /**
  371. * Helper class for mapping unique ClassLoader and interface combinations
  372. * to proxy classes.
  373. *
  374. * @author Eric Blake (ebb9@email.byu.edu)
  375. */
  376. private static final class ProxyType
  377. {
  378. /**
  379. * Store the class loader (may be null)
  380. */
  381. final ClassLoader loader;
  382. /**
  383. * Store the interfaces (never null, all elements are interfaces)
  384. */
  385. final Class[] interfaces;
  386. /**
  387. * Construct the helper object.
  388. *
  389. * @param loader the class loader to define the proxy class in; null
  390. * implies the bootstrap class loader
  391. * @param interfaces an array of interfaces
  392. */
  393. ProxyType(ClassLoader loader, Class[] interfaces)
  394. {
  395. this.loader = loader;
  396. this.interfaces = interfaces;
  397. }
  398. /**
  399. * Calculates the hash code.
  400. *
  401. * @return a combination of the classloader and interfaces hashcodes.
  402. */
  403. public int hashCode()
  404. {
  405. int hash = loader == null ? 0 : loader.hashCode();
  406. for (int i = 0; i < interfaces.length; i++)
  407. hash = hash * 31 + interfaces[i].hashCode();
  408. return hash;
  409. }
  410. /**
  411. * Calculates equality.
  412. *
  413. * @param other object to compare to
  414. * @return true if it is a ProxyType with same data
  415. */
  416. public boolean equals(Object other)
  417. {
  418. ProxyType pt = (ProxyType) other;
  419. if (loader != pt.loader || interfaces.length != pt.interfaces.length)
  420. return false;
  421. for (int i = 0; i < interfaces.length; i++)
  422. if (interfaces[i] != pt.interfaces[i])
  423. return false;
  424. return true;
  425. }
  426. } // class ProxyType
  427. /**
  428. * Helper class which allows hashing of a method name and signature
  429. * without worrying about return type, declaring class, or throws clause,
  430. * and which reduces the maximally common throws clause between two methods
  431. *
  432. * @author Eric Blake (ebb9@email.byu.edu)
  433. */
  434. private static final class ProxySignature
  435. {
  436. /**
  437. * The core signatures which all Proxy instances handle.
  438. */
  439. static final HashMap coreMethods = new HashMap();
  440. static
  441. {
  442. try
  443. {
  444. ProxySignature sig
  445. = new ProxySignature(Object.class
  446. .getMethod("equals",
  447. new Class[] {Object.class}));
  448. coreMethods.put(sig, sig);
  449. sig = new ProxySignature(Object.class.getMethod("hashCode"));
  450. coreMethods.put(sig, sig);
  451. sig = new ProxySignature(Object.class.getMethod("toString"));
  452. coreMethods.put(sig, sig);
  453. }
  454. catch (Exception e)
  455. {
  456. // assert false;
  457. throw (Error) new InternalError("Unexpected: " + e).initCause(e);
  458. }
  459. }
  460. /**
  461. * The underlying Method object, never null
  462. */
  463. final Method method;
  464. /**
  465. * The set of compatible thrown exceptions, may be empty
  466. */
  467. final Set exceptions = new HashSet();
  468. /**
  469. * Construct a signature
  470. *
  471. * @param method the Method this signature is based on, never null
  472. */
  473. ProxySignature(Method method)
  474. {
  475. this.method = method;
  476. Class[] exc = method.getExceptionTypes();
  477. int i = exc.length;
  478. while (--i >= 0)
  479. {
  480. // discard unchecked exceptions
  481. if (Error.class.isAssignableFrom(exc[i])
  482. || RuntimeException.class.isAssignableFrom(exc[i]))
  483. continue;
  484. exceptions.add(exc[i]);
  485. }
  486. }
  487. /**
  488. * Given a method, make sure it's return type is identical
  489. * to this, and adjust this signature's throws clause appropriately
  490. *
  491. * @param other the signature to merge in
  492. * @throws IllegalArgumentException if the return types conflict
  493. */
  494. void checkCompatibility(ProxySignature other)
  495. {
  496. if (method.getReturnType() != other.method.getReturnType())
  497. throw new IllegalArgumentException("incompatible return types: "
  498. + method + ", " + other.method);
  499. // if you can think of a more efficient way than this O(n^2) search,
  500. // implement it!
  501. int size1 = exceptions.size();
  502. int size2 = other.exceptions.size();
  503. boolean[] valid1 = new boolean[size1];
  504. boolean[] valid2 = new boolean[size2];
  505. Iterator itr = exceptions.iterator();
  506. int pos = size1;
  507. while (--pos >= 0)
  508. {
  509. Class c1 = (Class) itr.next();
  510. Iterator itr2 = other.exceptions.iterator();
  511. int pos2 = size2;
  512. while (--pos2 >= 0)
  513. {
  514. Class c2 = (Class) itr2.next();
  515. if (c2.isAssignableFrom(c1))
  516. valid1[pos] = true;
  517. if (c1.isAssignableFrom(c2))
  518. valid2[pos2] = true;
  519. }
  520. }
  521. pos = size1;
  522. itr = exceptions.iterator();
  523. while (--pos >= 0)
  524. {
  525. itr.next();
  526. if (! valid1[pos])
  527. itr.remove();
  528. }
  529. pos = size2;
  530. itr = other.exceptions.iterator();
  531. while (--pos >= 0)
  532. {
  533. itr.next();
  534. if (! valid2[pos])
  535. itr.remove();
  536. }
  537. exceptions.addAll(other.exceptions);
  538. }
  539. /**
  540. * Calculates the hash code.
  541. *
  542. * @return a combination of name and parameter types
  543. */
  544. public int hashCode()
  545. {
  546. int hash = method.getName().hashCode();
  547. Class[] types = method.getParameterTypes();
  548. for (int i = 0; i < types.length; i++)
  549. hash = hash * 31 + types[i].hashCode();
  550. return hash;
  551. }
  552. /**
  553. * Calculates equality.
  554. *
  555. * @param other object to compare to
  556. * @return true if it is a ProxySignature with same data
  557. */
  558. public boolean equals(Object other)
  559. {
  560. ProxySignature ps = (ProxySignature) other;
  561. Class[] types1 = method.getParameterTypes();
  562. Class[] types2 = ps.method.getParameterTypes();
  563. if (! method.getName().equals(ps.method.getName())
  564. || types1.length != types2.length)
  565. return false;
  566. int i = types1.length;
  567. while (--i >= 0)
  568. if (types1[i] != types2[i])
  569. return false;
  570. return true;
  571. }
  572. } // class ProxySignature
  573. /**
  574. * A flat representation of all data needed to generate bytecode/instantiate
  575. * a proxy class. This is basically a struct.
  576. *
  577. * @author Eric Blake (ebb9@email.byu.edu)
  578. */
  579. static final class ProxyData
  580. {
  581. /**
  582. * The package this class is in <b>including the trailing dot</b>
  583. * or an empty string for the unnamed (aka default) package.
  584. */
  585. String pack = "";
  586. /**
  587. * The interfaces this class implements. Non-null, but possibly empty.
  588. */
  589. Class[] interfaces;
  590. /**
  591. * The Method objects this class must pass as the second argument to
  592. * invoke (also useful for determining what methods this class has).
  593. * Non-null, non-empty (includes at least Object.hashCode, Object.equals,
  594. * and Object.toString).
  595. */
  596. Method[] methods;
  597. /**
  598. * The exceptions that do not need to be wrapped in
  599. * UndeclaredThrowableException. exceptions[i] is the same as, or a
  600. * subset of subclasses, of methods[i].getExceptionTypes(), depending on
  601. * compatible throws clauses with multiple inheritance. It is unspecified
  602. * if these lists include or exclude subclasses of Error and
  603. * RuntimeException, but excluding them is harmless and generates a
  604. * smaller class.
  605. */
  606. Class[][] exceptions;
  607. /**
  608. * For unique id's
  609. */
  610. private static int count;
  611. /**
  612. * The id of this proxy class
  613. */
  614. final int id = count++;
  615. /**
  616. * Construct a ProxyData with uninitialized data members.
  617. */
  618. ProxyData()
  619. {
  620. }
  621. /**
  622. * Return the name of a package (including the trailing dot)
  623. * given the name of a class.
  624. * Returns an empty string if no package. We use this in preference to
  625. * using Class.getPackage() to avoid problems with ClassLoaders
  626. * that don't set the package.
  627. */
  628. private static String getPackage(Class k)
  629. {
  630. String name = k.getName();
  631. int idx = name.lastIndexOf('.');
  632. return name.substring(0, idx + 1);
  633. }
  634. /**
  635. * Verifies that the arguments are legal, and sets up remaining data
  636. * This should only be called when a class must be generated, as
  637. * it is expensive.
  638. *
  639. * @param pt the ProxyType to convert to ProxyData
  640. * @return the flattened, verified ProxyData structure for use in
  641. * class generation
  642. * @throws IllegalArgumentException if `interfaces' contains
  643. * non-interfaces or incompatible combinations, and verify is true
  644. * @throws NullPointerException if interfaces is null or contains null
  645. */
  646. static ProxyData getProxyData(ProxyType pt)
  647. {
  648. Map method_set = (Map) ProxySignature.coreMethods.clone();
  649. boolean in_package = false; // true if we encounter non-public interface
  650. ProxyData data = new ProxyData();
  651. data.interfaces = pt.interfaces;
  652. // if interfaces is too large, we croak later on when the constant
  653. // pool overflows
  654. int i = data.interfaces.length;
  655. while (--i >= 0)
  656. {
  657. Class inter = data.interfaces[i];
  658. if (! inter.isInterface())
  659. throw new IllegalArgumentException("not an interface: " + inter);
  660. try
  661. {
  662. if (Class.forName(inter.getName(), false, pt.loader) != inter)
  663. throw new IllegalArgumentException("not accessible in "
  664. + "classloader: " + inter);
  665. }
  666. catch (ClassNotFoundException e)
  667. {
  668. throw new IllegalArgumentException("not accessible in "
  669. + "classloader: " + inter);
  670. }
  671. if (! Modifier.isPublic(inter.getModifiers()))
  672. if (in_package)
  673. {
  674. String p = getPackage(inter);
  675. if (! data.pack.equals(p))
  676. throw new IllegalArgumentException("non-public interfaces "
  677. + "from different "
  678. + "packages");
  679. }
  680. else
  681. {
  682. in_package = true;
  683. data.pack = getPackage(inter);
  684. }
  685. for (int j = i-1; j >= 0; j--)
  686. if (data.interfaces[j] == inter)
  687. throw new IllegalArgumentException("duplicate interface: "
  688. + inter);
  689. Method[] methods = inter.getMethods();
  690. int j = methods.length;
  691. while (--j >= 0)
  692. {
  693. if (isCoreObjectMethod(methods[j]))
  694. {
  695. // In the case of an attempt to redefine a public non-final
  696. // method of Object, we must skip it
  697. continue;
  698. }
  699. ProxySignature sig = new ProxySignature(methods[j]);
  700. ProxySignature old = (ProxySignature) method_set.put(sig, sig);
  701. if (old != null)
  702. sig.checkCompatibility(old);
  703. }
  704. }
  705. i = method_set.size();
  706. data.methods = new Method[i];
  707. data.exceptions = new Class[i][];
  708. Iterator itr = method_set.values().iterator();
  709. while (--i >= 0)
  710. {
  711. ProxySignature sig = (ProxySignature) itr.next();
  712. data.methods[i] = sig.method;
  713. data.exceptions[i] = (Class[]) sig.exceptions
  714. .toArray(new Class[sig.exceptions.size()]);
  715. }
  716. return data;
  717. }
  718. /**
  719. * Checks whether the method is similar to a public non-final method of
  720. * Object or not (i.e. with the same name and parameter types). Note that we
  721. * can't rely, directly or indirectly (via Collection.contains) on
  722. * Method.equals as it would also check the declaring class, what we do not
  723. * want. We only want to check that the given method have the same signature
  724. * as a core method (same name and parameter types)
  725. *
  726. * @param method the method to check
  727. * @return whether the method has the same name and parameter types as
  728. * Object.equals, Object.hashCode or Object.toString
  729. * @see java.lang.Object#equals(Object)
  730. * @see java.lang.Object#hashCode()
  731. * @see java.lang.Object#toString()
  732. */
  733. private static boolean isCoreObjectMethod(Method method)
  734. {
  735. String methodName = method.getName();
  736. if (methodName.equals("equals"))
  737. {
  738. return Arrays.equals(method.getParameterTypes(),
  739. new Class[] { Object.class });
  740. }
  741. if (methodName.equals("hashCode"))
  742. {
  743. return method.getParameterTypes().length == 0;
  744. }
  745. if (methodName.equals("toString"))
  746. {
  747. return method.getParameterTypes().length == 0;
  748. }
  749. return false;
  750. }
  751. } // class ProxyData
  752. /**
  753. * Does all the work of building a class. By making this a nested class,
  754. * this code is not loaded in memory if the VM has a native
  755. * implementation instead.
  756. *
  757. * @author Eric Blake (ebb9@email.byu.edu)
  758. */
  759. private static final class ClassFactory
  760. {
  761. /** Constants for assisting the compilation */
  762. private static final byte FIELD = 1;
  763. private static final byte METHOD = 2;
  764. private static final byte INTERFACE = 3;
  765. private static final String CTOR_SIG
  766. = "(Ljava/lang/reflect/InvocationHandler;)V";
  767. private static final String INVOKE_SIG = "(Ljava/lang/Object;"
  768. + "Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;";
  769. /** Bytecodes for insertion in the class definition byte[] */
  770. private static final char ACONST_NULL = 1;
  771. private static final char ICONST_0 = 3;
  772. private static final char BIPUSH = 16;
  773. private static final char SIPUSH = 17;
  774. private static final char ILOAD = 21;
  775. private static final char ILOAD_0 = 26;
  776. private static final char ALOAD_0 = 42;
  777. private static final char ALOAD_1 = 43;
  778. private static final char AALOAD = 50;
  779. private static final char AASTORE = 83;
  780. private static final char DUP = 89;
  781. private static final char DUP_X1 = 90;
  782. private static final char SWAP = 95;
  783. private static final char IRETURN = 172;
  784. private static final char LRETURN = 173;
  785. private static final char FRETURN = 174;
  786. private static final char DRETURN = 175;
  787. private static final char ARETURN = 176;
  788. private static final char RETURN = 177;
  789. private static final char GETSTATIC = 178;
  790. private static final char GETFIELD = 180;
  791. private static final char INVOKEVIRTUAL = 182;
  792. private static final char INVOKESPECIAL = 183;
  793. private static final char INVOKEINTERFACE = 185;
  794. private static final char NEW = 187;
  795. private static final char ANEWARRAY = 189;
  796. private static final char ATHROW = 191;
  797. private static final char CHECKCAST = 192;
  798. // Implementation note: we use StringBuffers to hold the byte data, since
  799. // they automatically grow. However, we only use the low 8 bits of
  800. // every char in the array, so we are using twice the necessary memory
  801. // for the ease StringBuffer provides.
  802. /** The constant pool. */
  803. private final StringBuffer pool = new StringBuffer();
  804. /** The rest of the class data. */
  805. private final StringBuffer stream = new StringBuffer();
  806. /** Map of strings to byte sequences, to minimize size of pool. */
  807. private final Map poolEntries = new HashMap();
  808. /** The VM name of this proxy class. */
  809. private final String qualName;
  810. /**
  811. * The Method objects the proxy class refers to when calling the
  812. * invocation handler.
  813. */
  814. private final Method[] methods;
  815. /**
  816. * Initializes the buffers with the bytecode contents for a proxy class.
  817. *
  818. * @param data the remainder of the class data
  819. * @throws IllegalArgumentException if anything else goes wrong this
  820. * late in the game; as far as I can tell, this will only happen
  821. * if the constant pool overflows, which is possible even when
  822. * the user doesn't exceed the 65535 interface limit
  823. */
  824. ClassFactory(ProxyData data)
  825. {
  826. methods = data.methods;
  827. // magic = 0xcafebabe
  828. // minor_version = 0
  829. // major_version = 46
  830. // constant_pool_count: place-holder for now
  831. pool.append("\u00ca\u00fe\u00ba\u00be\0\0\0\56\0\0");
  832. // constant_pool[], filled in as we go
  833. // access_flags
  834. putU2(Modifier.SUPER | Modifier.FINAL | Modifier.PUBLIC);
  835. // this_class
  836. qualName = (data.pack + "$Proxy" + data.id);
  837. putU2(classInfo(TypeSignature.getEncodingOfClass(qualName, false)));
  838. // super_class
  839. putU2(classInfo("java/lang/reflect/Proxy"));
  840. // interfaces_count
  841. putU2(data.interfaces.length);
  842. // interfaces[]
  843. for (int i = 0; i < data.interfaces.length; i++)
  844. putU2(classInfo(data.interfaces[i]));
  845. // Recall that Proxy classes serialize specially, so we do not need
  846. // to worry about a <clinit> method for this field. Instead, we
  847. // just assign it by reflection after the class is successfully loaded.
  848. // fields_count - private static Method[] m;
  849. putU2(1);
  850. // fields[]
  851. // m.access_flags
  852. putU2(Modifier.PRIVATE | Modifier.STATIC);
  853. // m.name_index
  854. putU2(utf8Info("m"));
  855. // m.descriptor_index
  856. putU2(utf8Info("[Ljava/lang/reflect/Method;"));
  857. // m.attributes_count
  858. putU2(0);
  859. // m.attributes[]
  860. // methods_count - # handler methods, plus <init>
  861. putU2(methods.length + 1);
  862. // methods[]
  863. // <init>.access_flags
  864. putU2(Modifier.PUBLIC);
  865. // <init>.name_index
  866. putU2(utf8Info("<init>"));
  867. // <init>.descriptor_index
  868. putU2(utf8Info(CTOR_SIG));
  869. // <init>.attributes_count - only Code is needed
  870. putU2(1);
  871. // <init>.Code.attribute_name_index
  872. putU2(utf8Info("Code"));
  873. // <init>.Code.attribute_length = 18
  874. // <init>.Code.info:
  875. // $Proxynn(InvocationHandler h) { super(h); }
  876. // <init>.Code.max_stack = 2
  877. // <init>.Code.max_locals = 2
  878. // <init>.Code.code_length = 6
  879. // <init>.Code.code[]
  880. stream.append("\0\0\0\22\0\2\0\2\0\0\0\6" + ALOAD_0 + ALOAD_1
  881. + INVOKESPECIAL);
  882. putU2(refInfo(METHOD, "java/lang/reflect/Proxy", "<init>", CTOR_SIG));
  883. // <init>.Code.exception_table_length = 0
  884. // <init>.Code.exception_table[]
  885. // <init>.Code.attributes_count = 0
  886. // <init>.Code.attributes[]
  887. stream.append(RETURN + "\0\0\0\0");
  888. for (int i = methods.length - 1; i >= 0; i--)
  889. emitMethod(i, data.exceptions[i]);
  890. // attributes_count
  891. putU2(0);
  892. // attributes[] - empty; omit SourceFile attribute
  893. // XXX should we mark this with a Synthetic attribute?
  894. }
  895. /**
  896. * Produce the bytecode for a single method.
  897. *
  898. * @param i the index of the method we are building
  899. * @param e the exceptions possible for the method
  900. */
  901. private void emitMethod(int i, Class[] e)
  902. {
  903. // First, we precalculate the method length and other information.
  904. Method m = methods[i];
  905. Class[] paramtypes = m.getParameterTypes();
  906. int wrap_overhead = 0; // max words taken by wrapped primitive
  907. int param_count = 1; // 1 for this
  908. int code_length = 16; // aload_0, getfield, aload_0, getstatic, const,
  909. // aaload, const/aconst_null, invokeinterface
  910. if (i > 5)
  911. {
  912. if (i > Byte.MAX_VALUE)
  913. code_length += 2; // sipush
  914. else
  915. code_length++; // bipush
  916. }
  917. if (paramtypes.length > 0)
  918. {
  919. code_length += 3; // anewarray
  920. if (paramtypes.length > Byte.MAX_VALUE)
  921. code_length += 2; // sipush
  922. else if (paramtypes.length > 5)
  923. code_length++; // bipush
  924. for (int j = 0; j < paramtypes.length; j++)
  925. {
  926. code_length += 4; // dup, const, load, store
  927. Class type = paramtypes[j];
  928. if (j > 5)
  929. {
  930. if (j > Byte.MAX_VALUE)
  931. code_length += 2; // sipush
  932. else
  933. code_length++; // bipush
  934. }
  935. if (param_count >= 4)
  936. code_length++; // 2-byte load
  937. param_count++;
  938. if (type.isPrimitive())
  939. {
  940. code_length += 7; // new, dup, invokespecial
  941. if (type == long.class || type == double.class)
  942. {
  943. wrap_overhead = 3;
  944. param_count++;
  945. }
  946. else if (wrap_overhead < 2)
  947. wrap_overhead = 2;
  948. }
  949. }
  950. }
  951. int end_pc = code_length;
  952. Class ret_type = m.getReturnType();
  953. if (ret_type == void.class)
  954. code_length++; // return
  955. else if (ret_type.isPrimitive())
  956. code_length += 7; // cast, invokevirtual, return
  957. else
  958. code_length += 4; // cast, return
  959. int exception_count = 0;
  960. boolean throws_throwable = false;
  961. for (int j = 0; j < e.length; j++)
  962. if (e[j] == Throwable.class)
  963. {
  964. throws_throwable = true;
  965. break;
  966. }
  967. if (! throws_throwable)
  968. {
  969. exception_count = e.length + 3; // Throwable, Error, RuntimeException
  970. code_length += 9; // new, dup_x1, swap, invokespecial, athrow
  971. }
  972. int handler_pc = code_length - 1;
  973. CPStringBuilder signature = new CPStringBuilder("(");
  974. for (int j = 0; j < paramtypes.length; j++)
  975. signature.append(TypeSignature.getEncodingOfClass(paramtypes[j]));
  976. signature.append(")").append(TypeSignature.getEncodingOfClass(ret_type));
  977. // Now we have enough information to emit the method.
  978. // handler.access_flags
  979. putU2(Modifier.PUBLIC | Modifier.FINAL);
  980. // handler.name_index
  981. putU2(utf8Info(m.getName()));
  982. // handler.descriptor_index
  983. putU2(utf8Info(signature.toString()));
  984. // handler.attributes_count - Code is necessary, Exceptions possible
  985. putU2(e.length > 0 ? 2 : 1);
  986. // handler.Code.info:
  987. // type name(args) {
  988. // try {
  989. // return (type) h.invoke(this, methods[i], new Object[] {args});
  990. // } catch (<declared Exceptions> e) {
  991. // throw e;
  992. // } catch (Throwable t) {
  993. // throw new UndeclaredThrowableException(t);
  994. // }
  995. // }
  996. // Special cases:
  997. // if arg_n is primitive, wrap it
  998. // if method throws Throwable, try-catch is not needed
  999. // if method returns void, return statement not needed
  1000. // if method returns primitive, unwrap it
  1001. // save space by sharing code for all the declared handlers
  1002. // handler.Code.attribute_name_index
  1003. putU2(utf8Info("Code"));
  1004. // handler.Code.attribute_length
  1005. putU4(12 + code_length + 8 * exception_count);
  1006. // handler.Code.max_stack
  1007. putU2(param_count == 1 ? 4 : 7 + wrap_overhead);
  1008. // handler.Code.max_locals
  1009. putU2(param_count);
  1010. // handler.Code.code_length
  1011. putU4(code_length);
  1012. // handler.Code.code[]
  1013. putU1(ALOAD_0);
  1014. putU1(GETFIELD);
  1015. putU2(refInfo(FIELD, "java/lang/reflect/Proxy", "h",
  1016. "Ljava/lang/reflect/InvocationHandler;"));
  1017. putU1(ALOAD_0);
  1018. putU1(GETSTATIC);
  1019. putU2(refInfo(FIELD, TypeSignature.getEncodingOfClass(qualName, false),
  1020. "m", "[Ljava/lang/reflect/Method;"));
  1021. putConst(i);
  1022. putU1(AALOAD);
  1023. if (paramtypes.length > 0)
  1024. {
  1025. putConst(paramtypes.length);
  1026. putU1(ANEWARRAY);
  1027. putU2(classInfo("java/lang/Object"));
  1028. param_count = 1;
  1029. for (int j = 0; j < paramtypes.length; j++, param_count++)
  1030. {
  1031. putU1(DUP);
  1032. putConst(j);
  1033. if (paramtypes[j].isPrimitive())
  1034. {
  1035. putU1(NEW);
  1036. putU2(classInfo(wrapper(paramtypes[j])));
  1037. putU1(DUP);
  1038. }
  1039. putLoad(param_count, paramtypes[j]);
  1040. if (paramtypes[j].isPrimitive())
  1041. {
  1042. putU1(INVOKESPECIAL);
  1043. putU2(refInfo(METHOD, wrapper(paramtypes[j]), "<init>",
  1044. '(' + (TypeSignature
  1045. .getEncodingOfClass(paramtypes[j])
  1046. + ")V")));
  1047. if (paramtypes[j] == long.class
  1048. || paramtypes[j] == double.class)
  1049. param_count++;
  1050. }
  1051. putU1(AASTORE);
  1052. }
  1053. }
  1054. else
  1055. putU1(ACONST_NULL);
  1056. putU1(INVOKEINTERFACE);
  1057. putU2(refInfo(INTERFACE, "java/lang/reflect/InvocationHandler",
  1058. "invoke", INVOKE_SIG));
  1059. putU1(4); // InvocationHandler, this, Method, Object[]
  1060. putU1(0);
  1061. if (ret_type == void.class)
  1062. putU1(RETURN);
  1063. else if (ret_type.isPrimitive())
  1064. {
  1065. putU1(CHECKCAST);
  1066. putU2(classInfo(wrapper(ret_type)));
  1067. putU1(INVOKEVIRTUAL);
  1068. putU2(refInfo(METHOD, wrapper(ret_type),
  1069. ret_type.getName() + "Value",
  1070. "()" + TypeSignature.getEncodingOfClass(ret_type)));
  1071. if (ret_type == long.class)
  1072. putU1(LRETURN);
  1073. else if (ret_type == float.class)
  1074. putU1(FRETURN);
  1075. else if (ret_type == double.class)
  1076. putU1(DRETURN);
  1077. else
  1078. putU1(IRETURN);
  1079. }
  1080. else
  1081. {
  1082. putU1(CHECKCAST);
  1083. putU2(classInfo(ret_type));
  1084. putU1(ARETURN);
  1085. }
  1086. if (! throws_throwable)
  1087. {
  1088. putU1(NEW);
  1089. putU2(classInfo("java/lang/reflect/UndeclaredThrowableException"));
  1090. putU1(DUP_X1);
  1091. putU1(SWAP);
  1092. putU1(INVOKESPECIAL);
  1093. putU2(refInfo(METHOD,
  1094. "java/lang/reflect/UndeclaredThrowableException",
  1095. "<init>", "(Ljava/lang/Throwable;)V"));
  1096. putU1(ATHROW);
  1097. }
  1098. // handler.Code.exception_table_length
  1099. putU2(exception_count);
  1100. // handler.Code.exception_table[]
  1101. if (! throws_throwable)
  1102. {
  1103. // handler.Code.exception_table.start_pc
  1104. putU2(0);
  1105. // handler.Code.exception_table.end_pc
  1106. putU2(end_pc);
  1107. // handler.Code.exception_table.handler_pc
  1108. putU2(handler_pc);
  1109. // handler.Code.exception_table.catch_type
  1110. putU2(classInfo("java/lang/Error"));
  1111. // handler.Code.exception_table.start_pc
  1112. putU2(0);
  1113. // handler.Code.exception_table.end_pc
  1114. putU2(end_pc);
  1115. // handler.Code.exception_table.handler_pc
  1116. putU2(handler_pc);
  1117. // handler.Code.exception_table.catch_type
  1118. putU2(classInfo("java/lang/RuntimeException"));
  1119. for (int j = 0; j < e.length; j++)
  1120. {
  1121. // handler.Code.exception_table.start_pc
  1122. putU2(0);
  1123. // handler.Code.exception_table.end_pc
  1124. putU2(end_pc);
  1125. // handler.Code.exception_table.handler_pc
  1126. putU2(handler_pc);
  1127. // handler.Code.exception_table.catch_type
  1128. putU2(classInfo(e[j]));
  1129. }
  1130. // handler.Code.exception_table.start_pc
  1131. putU2(0);
  1132. // handler.Code.exception_table.end_pc
  1133. putU2(end_pc);
  1134. // handler.Code.exception_table.handler_pc -
  1135. // -8 for undeclared handler, which falls thru to normal one
  1136. putU2(handler_pc - 8);
  1137. // handler.Code.exception_table.catch_type
  1138. putU2(0);
  1139. }
  1140. // handler.Code.attributes_count
  1141. putU2(0);
  1142. // handler.Code.attributes[]
  1143. if (e.length > 0)
  1144. {
  1145. // handler.Exceptions.attribute_name_index
  1146. putU2(utf8Info("Exceptions"));
  1147. // handler.Exceptions.attribute_length
  1148. putU4(2 * e.length + 2);
  1149. // handler.Exceptions.number_of_exceptions
  1150. putU2(e.length);
  1151. // handler.Exceptions.exception_index_table[]
  1152. for (int j = 0; j < e.length; j++)
  1153. putU2(classInfo(e[j]));
  1154. }
  1155. }
  1156. /**
  1157. * Creates the Class object that corresponds to the bytecode buffers
  1158. * built when this object was constructed.
  1159. *
  1160. * @param loader the class loader to define the proxy class in; null
  1161. * implies the bootstrap class loader
  1162. * @return the proxy class Class object
  1163. */
  1164. Class generate(ClassLoader loader)
  1165. {
  1166. byte[] bytecode = new byte[pool.length() + stream.length()];
  1167. // More efficient to bypass calling charAt() repetitively.
  1168. char[] c = pool.toString().toCharArray();
  1169. int i = c.length;
  1170. while (--i >= 0)
  1171. bytecode[i] = (byte) c[i];
  1172. c = stream.toString().toCharArray();
  1173. i = c.length;
  1174. int j = bytecode.length;
  1175. while (i > 0)
  1176. bytecode[--j] = (byte) c[--i];
  1177. // Patch the constant pool size, which we left at 0 earlier.
  1178. int count = poolEntries.size() + 1;
  1179. bytecode[8] = (byte) (count >> 8);
  1180. bytecode[9] = (byte) count;
  1181. try
  1182. {
  1183. Class vmClassLoader = Class.forName("java.lang.VMClassLoader");
  1184. Class[] types = {ClassLoader.class, String.class,
  1185. byte[].class, int.class, int.class,
  1186. ProtectionDomain.class };
  1187. Method m = vmClassLoader.getDeclaredMethod("defineClass", types);
  1188. // We can bypass the security check of setAccessible(true), since
  1189. // we're in the same package.
  1190. m.flag = true;
  1191. Object[] args = {loader, qualName, bytecode, Integer.valueOf(0),
  1192. Integer.valueOf(bytecode.length),
  1193. Object.class.getProtectionDomain() };
  1194. Class clazz = (Class) m.invoke(null, args);
  1195. // Finally, initialize the m field of the proxy class, before
  1196. // returning it.
  1197. Field f = clazz.getDeclaredField("m");
  1198. f.flag = true;
  1199. // we can share the array, because it is not publicized
  1200. f.set(null, methods);
  1201. return clazz;
  1202. }
  1203. catch (Exception e)
  1204. {
  1205. // assert false;
  1206. throw (Error) new InternalError("Unexpected: " + e).initCause(e);
  1207. }
  1208. }
  1209. /**
  1210. * Put a single byte on the stream.
  1211. *
  1212. * @param i the information to add (only lowest 8 bits are used)
  1213. */
  1214. private void putU1(int i)
  1215. {
  1216. stream.append((char) i);
  1217. }
  1218. /**
  1219. * Put two bytes on the stream.
  1220. *
  1221. * @param i the information to add (only lowest 16 bits are used)
  1222. */
  1223. private void putU2(int i)
  1224. {
  1225. stream.append((char) (i >> 8)).append((char) i);
  1226. }
  1227. /**
  1228. * Put four bytes on the stream.
  1229. *
  1230. * @param i the information to add (treated as unsigned)
  1231. */
  1232. private void putU4(int i)
  1233. {
  1234. stream.append((char) (i >> 24)).append((char) (i >> 16));
  1235. stream.append((char) (i >> 8)).append((char) i);
  1236. }
  1237. /**
  1238. * Put bytecode to load a constant integer on the stream. This only
  1239. * needs to work for values less than Short.MAX_VALUE.
  1240. *
  1241. * @param i the int to add
  1242. */
  1243. private void putConst(int i)
  1244. {
  1245. if (i >= -1 && i <= 5)
  1246. putU1(ICONST_0 + i);
  1247. else if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE)
  1248. {
  1249. putU1(BIPUSH);
  1250. putU1(i);
  1251. }
  1252. else
  1253. {
  1254. putU1(SIPUSH);
  1255. putU2(i);
  1256. }
  1257. }
  1258. /**
  1259. * Put bytecode to load a given local variable on the stream.
  1260. *
  1261. * @param i the slot to load
  1262. * @param type the base type of the load
  1263. */
  1264. private void putLoad(int i, Class type)
  1265. {
  1266. int offset = 0;
  1267. if (type == long.class)
  1268. offset = 1;
  1269. else if (type == float.class)
  1270. offset = 2;
  1271. else if (type == double.class)
  1272. offset = 3;
  1273. else if (! type.isPrimitive())
  1274. offset = 4;
  1275. if (i < 4)
  1276. putU1(ILOAD_0 + 4 * offset + i);
  1277. else
  1278. {
  1279. putU1(ILOAD + offset);
  1280. putU1(i);
  1281. }
  1282. }
  1283. /**
  1284. * Given a primitive type, return its wrapper class name.
  1285. *
  1286. * @param clazz the primitive type (but not void.class)
  1287. * @return the internal form of the wrapper class name
  1288. */
  1289. private String wrapper(Class clazz)
  1290. {
  1291. if (clazz == boolean.class)
  1292. return "java/lang/Boolean";
  1293. if (clazz == byte.class)
  1294. return "java/lang/Byte";
  1295. if (clazz == short.class)
  1296. return "java/lang/Short";
  1297. if (clazz == char.class)
  1298. return "java/lang/Character";
  1299. if (clazz == int.class)
  1300. return "java/lang/Integer";
  1301. if (clazz == long.class)
  1302. return "java/lang/Long";
  1303. if (clazz == float.class)
  1304. return "java/lang/Float";
  1305. if (clazz == double.class)
  1306. return "java/lang/Double";
  1307. // assert false;
  1308. return null;
  1309. }
  1310. /**
  1311. * Returns the entry of this String in the Constant pool, adding it
  1312. * if necessary.
  1313. *
  1314. * @param str the String to resolve
  1315. * @return the index of the String in the constant pool
  1316. */
  1317. private char utf8Info(String str)
  1318. {
  1319. String utf8 = toUtf8(str);
  1320. int len = utf8.length();
  1321. return poolIndex("\1" + (char) (len >> 8) + (char) (len & 0xff) + utf8);
  1322. }
  1323. /**
  1324. * Returns the entry of the appropriate class info structure in the
  1325. * Constant pool, adding it if necessary.
  1326. *
  1327. * @param name the class name, in internal form
  1328. * @return the index of the ClassInfo in the constant pool
  1329. */
  1330. private char classInfo(String name)
  1331. {
  1332. char index = utf8Info(name);
  1333. char[] c = {7, (char) (index >> 8), (char) (index & 0xff)};
  1334. return poolIndex(new String(c));
  1335. }
  1336. /**
  1337. * Returns the entry of the appropriate class info structure in the
  1338. * Constant pool, adding it if necessary.
  1339. *
  1340. * @param clazz the class type
  1341. * @return the index of the ClassInfo in the constant pool
  1342. */
  1343. private char classInfo(Class clazz)
  1344. {
  1345. return classInfo(TypeSignature.getEncodingOfClass(clazz.getName(),
  1346. false));
  1347. }
  1348. /**
  1349. * Returns the entry of the appropriate fieldref, methodref, or
  1350. * interfacemethodref info structure in the Constant pool, adding it
  1351. * if necessary.
  1352. *
  1353. * @param structure FIELD, METHOD, or INTERFACE
  1354. * @param clazz the class name, in internal form
  1355. * @param name the simple reference name
  1356. * @param type the type of the reference
  1357. * @return the index of the appropriate Info structure in the constant pool
  1358. */
  1359. private char refInfo(byte structure, String clazz, String name,
  1360. String type)
  1361. {
  1362. char cindex = classInfo(clazz);
  1363. char ntindex = nameAndTypeInfo(name, type);
  1364. // relies on FIELD == 1, METHOD == 2, INTERFACE == 3
  1365. char[] c = {(char) (structure + 8),
  1366. (char) (cindex >> 8), (char) (cindex & 0xff),
  1367. (char) (ntindex >> 8), (char) (ntindex & 0xff)};
  1368. return poolIndex(new String(c));
  1369. }
  1370. /**
  1371. * Returns the entry of the appropriate nameAndTyperef info structure
  1372. * in the Constant pool, adding it if necessary.
  1373. *
  1374. * @param name the simple name
  1375. * @param type the reference type
  1376. * @return the index of the NameAndTypeInfo structure in the constant pool
  1377. */
  1378. private char nameAndTypeInfo(String name, String type)
  1379. {
  1380. char nindex = utf8Info(name);
  1381. char tindex = utf8Info(type);
  1382. char[] c = {12, (char) (nindex >> 8), (char) (nindex & 0xff),
  1383. (char) (tindex >> 8), (char) (tindex & 0xff)};
  1384. return poolIndex(new String(c));
  1385. }
  1386. /**
  1387. * Converts a regular string to a UTF8 string, where the upper byte
  1388. * of every char is 0, and '\\u0000' is not in the string. This is
  1389. * basically to use a String as a fancy byte[], and while it is less
  1390. * efficient in memory use, it is easier for hashing.
  1391. *
  1392. * @param str the original, in straight unicode
  1393. * @return a modified string, in UTF8 format in the low bytes
  1394. */
  1395. private String toUtf8(String str)
  1396. {
  1397. final char[] ca = str.toCharArray();
  1398. final int len = ca.length;
  1399. // Avoid object creation, if str is already fits UTF8.
  1400. int i;
  1401. for (i = 0; i < len; i++)
  1402. if (ca[i] == 0 || ca[i] > '\u007f')
  1403. break;
  1404. if (i == len)
  1405. return str;
  1406. final CPStringBuilder sb = new CPStringBuilder(str);
  1407. sb.setLength(i);
  1408. for ( ; i < len; i++)
  1409. {
  1410. final char c = ca[i];
  1411. if (c > 0 && c <= '\u007f')
  1412. sb.append(c);
  1413. else if (c <= '\u07ff') // includes '\0'
  1414. {
  1415. sb.append((char) (0xc0 | (c >> 6)));
  1416. sb.append((char) (0x80 | (c & 0x6f)));
  1417. }
  1418. else
  1419. {
  1420. sb.append((char) (0xe0 | (c >> 12)));
  1421. sb.append((char) (0x80 | ((c >> 6) & 0x6f)));
  1422. sb.append((char) (0x80 | (c & 0x6f)));
  1423. }
  1424. }
  1425. return sb.toString();
  1426. }
  1427. /**
  1428. * Returns the location of a byte sequence (conveniently wrapped in
  1429. * a String with all characters between \u0001 and \u00ff inclusive)
  1430. * in the constant pool, adding it if necessary.
  1431. *
  1432. * @param sequence the byte sequence to look for
  1433. * @return the index of the sequence
  1434. * @throws IllegalArgumentException if this would make the constant
  1435. * pool overflow
  1436. */
  1437. private char poolIndex(String sequence)
  1438. {
  1439. Integer i = (Integer) poolEntries.get(sequence);
  1440. if (i == null)
  1441. {
  1442. // pool starts at index 1
  1443. int size = poolEntries.size() + 1;
  1444. if (size >= 65535)
  1445. throw new IllegalArgumentException("exceeds VM limitations");
  1446. i = Integer.valueOf(size);
  1447. poolEntries.put(sequence, i);
  1448. pool.append(sequence);
  1449. }
  1450. return (char) i.intValue();
  1451. }
  1452. } // class ClassFactory
  1453. }