Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

ProxyFactory.java 31KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. Alternatively, the contents of this file may be used under
  8. * the terms of the GNU Lesser General Public License Version 2.1 or later.
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist.util.proxy;
  16. import java.lang.reflect.Field;
  17. import java.lang.reflect.InvocationTargetException;
  18. import java.lang.reflect.Method;
  19. import java.lang.reflect.Constructor;
  20. import java.lang.reflect.Member;
  21. import java.lang.reflect.Modifier;
  22. import java.security.ProtectionDomain;
  23. import java.util.HashMap;
  24. import java.util.WeakHashMap;
  25. import java.util.Iterator;
  26. import java.util.Map;
  27. import java.util.Set;
  28. import java.lang.ref.WeakReference;
  29. import javassist.CannotCompileException;
  30. import javassist.bytecode.*;
  31. /**
  32. * Factory of dynamic proxy classes.
  33. *
  34. * <p>This factory generates a class that extends the given super class and implements
  35. * the given interfaces. The calls of the methods inherited from the super class are
  36. * forwarded and then <code>invoke()</code> is called on the method handler
  37. * associated with the generated class. The calls of the methods from the interfaces
  38. * are also forwarded to the method handler.
  39. *
  40. * <p>For example, if the following code is executed,
  41. *
  42. * <ul><pre>
  43. * ProxyFactory f = new ProxyFactory();
  44. * f.setSuperclass(Foo.class);
  45. * MethodHandler mi = new MethodHandler() {
  46. * public Object invoke(Object self, Method m, Method proceed,
  47. * Object[] args) throws Throwable {
  48. * System.out.println("Name: " + m.getName());
  49. * return proceed.invoke(self, args); // execute the original method.
  50. * }
  51. * };
  52. * f.setHandler(mi);
  53. * f.setFilter(new MethodFilter() {
  54. * public boolean isHandled(Method m) {
  55. * // ignore finalize()
  56. * return !m.getName().equals("finalize");
  57. * }
  58. * });
  59. * Class c = f.createClass();
  60. * Foo foo = (Foo)c.newInstance();
  61. * </pre></ul>
  62. *
  63. * <p>Then, the following method call will be forwarded to MethodHandler
  64. * <code>mi</code> and prints a message before executing the originally called method
  65. * <code>bar()</code> in <code>Foo</code>.
  66. *
  67. * <ul><pre>
  68. * foo.bar();
  69. * </pre></ul>
  70. *
  71. * <p>To change the method handler during runtime,
  72. * execute the following code:
  73. *
  74. * <ul><pre>
  75. * MethodHandler mi2 = ... ; // another handler
  76. * ((ProxyObject)foo).setHandler(mi2);
  77. * </pre></ul>
  78. *
  79. * <p>Here is an example of method handler. It does not execute
  80. * anything except invoking the original method:
  81. *
  82. * <ul><pre>
  83. * class SimpleHandler implements MethodHandler {
  84. * public Object invoke(Object self, Method m,
  85. * Method proceed, Object[] args) throws Exception {
  86. * return proceed.invoke(self, args);
  87. * }
  88. * }
  89. * </pre></ul>
  90. *
  91. * @see MethodHandler
  92. * @since 3.1
  93. */
  94. public class ProxyFactory {
  95. private Class superClass;
  96. private Class[] interfaces;
  97. private MethodFilter methodFilter;
  98. private MethodHandler handler;
  99. private Class thisClass;
  100. /**
  101. * If the value of this variable is not null, the class file of
  102. * the generated proxy class is written under the directory specified
  103. * by this variable. For example, if the value is
  104. * <code>"."</code>, then the class file is written under the current
  105. * directory. This method is for debugging.
  106. *
  107. * <p>The default value is null.
  108. */
  109. public String writeDirectory;
  110. private static final Class OBJECT_TYPE = Object.class;
  111. private static final String HOLDER = "_methods_";
  112. private static final String HOLDER_TYPE = "[Ljava/lang/reflect/Method;";
  113. private static final String HANDLER = "handler";
  114. private static final String NULL_INTERCEPTOR_HOLDER = "javassist.util.proxy.RuntimeSupport";
  115. private static final String DEFAULT_INTERCEPTOR = "default_interceptor";
  116. private static final String HANDLER_TYPE
  117. = 'L' + MethodHandler.class.getName().replace('.', '/') + ';';
  118. private static final String HANDLER_SETTER = "setHandler";
  119. private static final String HANDLER_SETTER_TYPE = "(" + HANDLER_TYPE + ")V";
  120. /**
  121. * If true, a generated proxy class is cached and it will be reused
  122. * when generating the proxy class with the same properties is requested.
  123. * The default value is true.
  124. *
  125. * @since 3.4
  126. */
  127. public static boolean useCache = true;
  128. private static WeakHashMap proxyCache = new WeakHashMap();
  129. static class CacheKey {
  130. private String classes;
  131. private MethodFilter filter;
  132. private int hash;
  133. WeakReference proxyClass;
  134. public CacheKey(Class superClass, Class[] interfaces, MethodFilter f) {
  135. classes = getKey(superClass, interfaces);
  136. hash = classes.hashCode();
  137. filter = f;
  138. proxyClass = null;
  139. }
  140. public int hashCode() { return hash; }
  141. public boolean equals(Object obj) {
  142. if (obj instanceof CacheKey) {
  143. CacheKey target = (CacheKey)obj;
  144. return target.filter == filter && target.classes.equals(classes);
  145. }
  146. else
  147. return false;
  148. }
  149. static String getKey(Class superClass, Class[] interfaces) {
  150. StringBuffer sbuf = new StringBuffer();
  151. if (superClass != null)
  152. sbuf.append(superClass.getName());
  153. sbuf.append(':');
  154. if (interfaces != null) {
  155. int len = interfaces.length;
  156. for (int i = 0; i < len; i++)
  157. sbuf.append(interfaces[i].getName()).append(',');
  158. }
  159. return sbuf.toString();
  160. }
  161. }
  162. /**
  163. * Constructs a factory of proxy class.
  164. */
  165. public ProxyFactory() {
  166. superClass = null;
  167. interfaces = null;
  168. methodFilter = null;
  169. handler = null;
  170. thisClass = null;
  171. writeDirectory = null;
  172. }
  173. /**
  174. * Sets the super class of a proxy class.
  175. */
  176. public void setSuperclass(Class clazz) {
  177. superClass = clazz;
  178. }
  179. /**
  180. * Obtains the super class set by <code>setSuperclass()</code>.
  181. *
  182. * @since 3.4
  183. */
  184. public Class getSuperclass() { return superClass; }
  185. /**
  186. * Sets the interfaces of a proxy class.
  187. */
  188. public void setInterfaces(Class[] ifs) {
  189. interfaces = ifs;
  190. }
  191. /**
  192. * Obtains the interfaces set by <code>setInterfaces</code>.
  193. *
  194. * @since 3.4
  195. */
  196. public Class[] getInterfaces() { return interfaces; }
  197. /**
  198. * Sets a filter that selects the methods that will be controlled by a handler.
  199. */
  200. public void setFilter(MethodFilter mf) {
  201. methodFilter = mf;
  202. }
  203. /**
  204. * Generates a proxy class.
  205. */
  206. public Class createClass() {
  207. if (thisClass == null) {
  208. ClassLoader cl = getClassLoader();
  209. if (useCache)
  210. createClass2(cl);
  211. else
  212. createClass3(cl);
  213. }
  214. return thisClass;
  215. }
  216. private void createClass2(ClassLoader cl) {
  217. CacheKey key = new CacheKey(superClass, interfaces, methodFilter);
  218. synchronized (proxyCache) {
  219. HashMap cacheForTheLoader = (HashMap)proxyCache.get(cl);
  220. if (cacheForTheLoader == null) {
  221. cacheForTheLoader = new HashMap();
  222. proxyCache.put(cl, cacheForTheLoader);
  223. cacheForTheLoader.put(key, key);
  224. }
  225. else {
  226. CacheKey found = (CacheKey)cacheForTheLoader.get(key);
  227. if (found == null)
  228. cacheForTheLoader.put(key, key);
  229. else {
  230. key = found;
  231. Class c = isValidEntry(key); // no need to synchronize
  232. if (c != null) {
  233. thisClass = c;
  234. return;
  235. }
  236. }
  237. }
  238. }
  239. synchronized (key) {
  240. Class c = isValidEntry(key);
  241. if (c == null) {
  242. createClass3(cl);
  243. key.proxyClass = new WeakReference(thisClass);
  244. }
  245. else
  246. thisClass = c;
  247. }
  248. }
  249. private Class isValidEntry(CacheKey key) {
  250. WeakReference ref = key.proxyClass;
  251. if (ref != null) {
  252. Class c = (Class)ref.get();
  253. if(c != null && getHandler(c) == handler)
  254. return c;
  255. }
  256. return null;
  257. }
  258. private void createClass3(ClassLoader cl) {
  259. try {
  260. ClassFile cf = make();
  261. if (writeDirectory != null)
  262. FactoryHelper.writeFile(cf, writeDirectory);
  263. thisClass = FactoryHelper.toClass(cf, cl, getDomain());
  264. setHandler();
  265. }
  266. catch (CannotCompileException e) {
  267. throw new RuntimeException(e.getMessage(), e);
  268. }
  269. }
  270. /**
  271. * A provider of class loaders.
  272. *
  273. * @see #classLoaderProvider
  274. * @since 3.4
  275. */
  276. public static interface ClassLoaderProvider {
  277. /**
  278. * Returns a class loader.
  279. *
  280. * @param pf a proxy factory that is going to obtain a class loader.
  281. */
  282. public ClassLoader get(ProxyFactory pf);
  283. }
  284. /**
  285. * A provider used by <code>createClass()</code> for obtaining
  286. * a class loader.
  287. * <code>get()</code> on this <code>ClassLoaderProvider</code> object
  288. * is called to obtain a class loader.
  289. *
  290. * <p>The value of this field can be updated for changing the default
  291. * implementation.
  292. *
  293. * <p>Example:
  294. * <ul><pre>
  295. * ProxyFactory.classLoaderProvider = new ProxyFactory.ClassLoaderProvider() {
  296. * public ClassLoader get(ProxyFactory pf) {
  297. * return Thread.currentThread().getContextClassLoader();
  298. * }
  299. * };
  300. * </pre></ul>
  301. *
  302. * @since 3.4
  303. */
  304. public static ClassLoaderProvider classLoaderProvider
  305. = new ClassLoaderProvider() {
  306. public ClassLoader get(ProxyFactory pf) {
  307. return pf.getClassLoader0();
  308. }
  309. };
  310. protected ClassLoader getClassLoader() {
  311. return classLoaderProvider.get(this);
  312. }
  313. protected ClassLoader getClassLoader0() {
  314. ClassLoader loader = null;
  315. if (superClass != null && !superClass.getName().equals("java.lang.Object"))
  316. loader = superClass.getClassLoader();
  317. else if (interfaces != null && interfaces.length > 0)
  318. loader = interfaces[0].getClassLoader();
  319. if (loader == null) {
  320. loader = getClass().getClassLoader();
  321. // In case javassist is in the endorsed dir
  322. if (loader == null) {
  323. loader = Thread.currentThread().getContextClassLoader();
  324. if (loader == null)
  325. loader = ClassLoader.getSystemClassLoader();
  326. }
  327. }
  328. return loader;
  329. }
  330. protected ProtectionDomain getDomain() {
  331. Class clazz;
  332. if (superClass != null && !superClass.getName().equals("java.lang.Object"))
  333. clazz = superClass;
  334. else if (interfaces != null && interfaces.length > 0)
  335. clazz = interfaces[0];
  336. else
  337. clazz = this.getClass();
  338. return clazz.getProtectionDomain();
  339. }
  340. /**
  341. * Creates a proxy class and returns an instance of that class.
  342. *
  343. * @param paramTypes parameter types for a constructor.
  344. * @param args arguments passed to a constructor.
  345. */
  346. public Object create(Class[] paramTypes, Object[] args)
  347. throws NoSuchMethodException, IllegalArgumentException,
  348. InstantiationException, IllegalAccessException, InvocationTargetException
  349. {
  350. Class c = createClass();
  351. Constructor cons = c.getConstructor(paramTypes);
  352. return cons.newInstance(args);
  353. }
  354. /**
  355. * Sets the default invocation handler. This invocation handler is shared
  356. * among all the instances of a proxy class unless another is explicitly
  357. * specified.
  358. */
  359. public void setHandler(MethodHandler mi) {
  360. handler = mi;
  361. setHandler();
  362. }
  363. private void setHandler() {
  364. if (thisClass != null && handler != null)
  365. try {
  366. Field f = thisClass.getField(DEFAULT_INTERCEPTOR);
  367. f.setAccessible(true);
  368. f.set(null, handler);
  369. f.setAccessible(false);
  370. }
  371. catch (Exception e) {
  372. throw new RuntimeException(e);
  373. }
  374. }
  375. static MethodHandler getHandler(Class clazz) {
  376. try {
  377. Field f = clazz.getField(DEFAULT_INTERCEPTOR);
  378. f.setAccessible(true);
  379. MethodHandler h = (MethodHandler)f.get(null);
  380. f.setAccessible(false);
  381. return h;
  382. }
  383. catch (Exception e) {
  384. throw new RuntimeException(e);
  385. }
  386. }
  387. private static int counter = 0;
  388. private static synchronized String makeProxyName(String classname) {
  389. return classname + "_$$_javassist_" + counter++;
  390. }
  391. private ClassFile make() throws CannotCompileException {
  392. String superName, classname;
  393. if (interfaces == null)
  394. interfaces = new Class[0];
  395. if (superClass == null) {
  396. superClass = OBJECT_TYPE;
  397. superName = superClass.getName();
  398. classname = interfaces.length == 0 ? superName
  399. : interfaces[0].getName();
  400. }
  401. else {
  402. superName = superClass.getName();
  403. classname = superName;
  404. }
  405. if (Modifier.isFinal(superClass.getModifiers()))
  406. throw new CannotCompileException(superName + " is final");
  407. classname = makeProxyName(classname);
  408. if (classname.startsWith("java."))
  409. classname = "org.javassist.tmp." + classname;
  410. ClassFile cf = new ClassFile(false, classname, superName);
  411. cf.setAccessFlags(AccessFlag.PUBLIC);
  412. setInterfaces(cf, interfaces);
  413. ConstPool pool = cf.getConstPool();
  414. FieldInfo finfo = new FieldInfo(pool, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
  415. finfo.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
  416. cf.addField(finfo);
  417. FieldInfo finfo2 = new FieldInfo(pool, HANDLER, HANDLER_TYPE);
  418. finfo2.setAccessFlags(AccessFlag.PRIVATE);
  419. cf.addField(finfo2);
  420. HashMap allMethods = getMethods(superClass, interfaces);
  421. int size = allMethods.size();
  422. makeConstructors(classname, cf, pool, classname);
  423. int s = overrideMethods(cf, pool, classname, allMethods);
  424. addMethodsHolder(cf, pool, classname, s);
  425. addSetter(classname, cf, pool);
  426. thisClass = null;
  427. return cf;
  428. }
  429. private static void setInterfaces(ClassFile cf, Class[] interfaces) {
  430. String setterIntf = ProxyObject.class.getName();
  431. String[] list;
  432. if (interfaces == null || interfaces.length == 0)
  433. list = new String[] { setterIntf };
  434. else {
  435. list = new String[interfaces.length + 1];
  436. for (int i = 0; i < interfaces.length; i++)
  437. list[i] = interfaces[i].getName();
  438. list[interfaces.length] = setterIntf;
  439. }
  440. cf.setInterfaces(list);
  441. }
  442. private static void addMethodsHolder(ClassFile cf, ConstPool cp,
  443. String classname, int size)
  444. throws CannotCompileException
  445. {
  446. FieldInfo finfo = new FieldInfo(cp, HOLDER, HOLDER_TYPE);
  447. finfo.setAccessFlags(AccessFlag.PRIVATE | AccessFlag.STATIC);
  448. cf.addField(finfo);
  449. MethodInfo minfo = new MethodInfo(cp, "<clinit>", "()V");
  450. Bytecode code = new Bytecode(cp, 0, 0);
  451. code.addIconst(size * 2);
  452. code.addAnewarray("java.lang.reflect.Method");
  453. code.addPutstatic(classname, HOLDER, HOLDER_TYPE);
  454. code.addOpcode(Bytecode.RETURN);
  455. minfo.setCodeAttribute(code.toCodeAttribute());
  456. cf.addMethod(minfo);
  457. }
  458. private static void addSetter(String classname, ClassFile cf, ConstPool cp)
  459. throws CannotCompileException
  460. {
  461. MethodInfo minfo = new MethodInfo(cp, HANDLER_SETTER,
  462. HANDLER_SETTER_TYPE);
  463. minfo.setAccessFlags(AccessFlag.PUBLIC);
  464. Bytecode code = new Bytecode(cp, 2, 2);
  465. code.addAload(0);
  466. code.addAload(1);
  467. code.addPutfield(classname, HANDLER, HANDLER_TYPE);
  468. code.addOpcode(Bytecode.RETURN);
  469. minfo.setCodeAttribute(code.toCodeAttribute());
  470. cf.addMethod(minfo);
  471. }
  472. private int overrideMethods(ClassFile cf, ConstPool cp, String className,
  473. HashMap allMethods)
  474. throws CannotCompileException
  475. {
  476. String prefix = makeUniqueName("_d", allMethods);
  477. Set entries = allMethods.entrySet();
  478. Iterator it = entries.iterator();
  479. int index = 0;
  480. while (it.hasNext()) {
  481. Map.Entry e = (Map.Entry)it.next();
  482. String key = (String)e.getKey();
  483. Method meth = (Method)e.getValue();
  484. int mod = meth.getModifiers();
  485. if (!Modifier.isFinal(mod) && !Modifier.isStatic(mod)
  486. && isVisible(mod, className, meth))
  487. if (methodFilter == null || methodFilter.isHandled(meth))
  488. override(className, meth, prefix, index++,
  489. keyToDesc(key), cf, cp);
  490. }
  491. return index;
  492. }
  493. private void override(String thisClassname, Method meth, String prefix,
  494. int index, String desc, ClassFile cf, ConstPool cp)
  495. throws CannotCompileException
  496. {
  497. Class declClass = meth.getDeclaringClass();
  498. String delegatorName = prefix + index + meth.getName();
  499. if (Modifier.isAbstract(meth.getModifiers()))
  500. delegatorName = null;
  501. else {
  502. MethodInfo delegator
  503. = makeDelegator(meth, desc, cp, declClass, delegatorName);
  504. // delegator is not a bridge method. See Sec. 15.12.4.5 of JLS 3rd Ed.
  505. delegator.setAccessFlags(delegator.getAccessFlags() & ~AccessFlag.BRIDGE);
  506. cf.addMethod(delegator);
  507. }
  508. MethodInfo forwarder
  509. = makeForwarder(thisClassname, meth, desc, cp, declClass,
  510. delegatorName, index);
  511. cf.addMethod(forwarder);
  512. }
  513. private void makeConstructors(String thisClassName, ClassFile cf,
  514. ConstPool cp, String classname) throws CannotCompileException
  515. {
  516. Constructor[] cons = superClass.getDeclaredConstructors();
  517. for (int i = 0; i < cons.length; i++) {
  518. Constructor c = cons[i];
  519. int mod = c.getModifiers();
  520. if (!Modifier.isFinal(mod) && !Modifier.isPrivate(mod)
  521. && isVisible(mod, classname, c)) {
  522. MethodInfo m = makeConstructor(thisClassName, c, cp, superClass);
  523. cf.addMethod(m);
  524. }
  525. }
  526. }
  527. private static String makeUniqueName(String name, HashMap hash) {
  528. Set keys = hash.keySet();
  529. if (makeUniqueName0(name, keys.iterator()))
  530. return name;
  531. for (int i = 100; i < 999; i++) {
  532. String s = name + i;
  533. if (makeUniqueName0(s, keys.iterator()))
  534. return s;
  535. }
  536. throw new RuntimeException("cannot make a unique method name");
  537. }
  538. private static boolean makeUniqueName0(String name, Iterator it) {
  539. while (it.hasNext()) {
  540. String key = (String)it.next();
  541. if (key.startsWith(name))
  542. return false;
  543. }
  544. return true;
  545. }
  546. /**
  547. * Returns true if the method is visible from the class.
  548. *
  549. * @param mod the modifiers of the method.
  550. */
  551. private static boolean isVisible(int mod, String from, Member meth) {
  552. if ((mod & Modifier.PRIVATE) != 0)
  553. return false;
  554. else if ((mod & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0)
  555. return true;
  556. else {
  557. String p = getPackageName(from);
  558. String q = getPackageName(meth.getDeclaringClass().getName());
  559. if (p == null)
  560. return q == null;
  561. else
  562. return p.equals(q);
  563. }
  564. }
  565. private static String getPackageName(String name) {
  566. int i = name.lastIndexOf('.');
  567. if (i < 0)
  568. return null;
  569. else
  570. return name.substring(0, i);
  571. }
  572. private static HashMap getMethods(Class superClass, Class[] interfaceTypes) {
  573. HashMap hash = new HashMap();
  574. for (int i = 0; i < interfaceTypes.length; i++)
  575. getMethods(hash, interfaceTypes[i]);
  576. getMethods(hash, superClass);
  577. return hash;
  578. }
  579. private static void getMethods(HashMap hash, Class clazz) {
  580. Class[] ifs = clazz.getInterfaces();
  581. for (int i = 0; i < ifs.length; i++)
  582. getMethods(hash, ifs[i]);
  583. Class parent = clazz.getSuperclass();
  584. if (parent != null)
  585. getMethods(hash, parent);
  586. Method[] methods = clazz.getDeclaredMethods();
  587. for (int i = 0; i < methods.length; i++)
  588. if (!Modifier.isPrivate(methods[i].getModifiers())) {
  589. Method m = methods[i];
  590. String key = m.getName() + ':' + RuntimeSupport.makeDescriptor(m);
  591. hash.put(key, methods[i]);
  592. }
  593. }
  594. private static String keyToDesc(String key) {
  595. return key.substring(key.indexOf(':') + 1);
  596. }
  597. private static MethodInfo makeConstructor(String thisClassName, Constructor cons,
  598. ConstPool cp, Class superClass) {
  599. String desc = RuntimeSupport.makeDescriptor(cons.getParameterTypes(),
  600. Void.TYPE);
  601. MethodInfo minfo = new MethodInfo(cp, "<init>", desc);
  602. minfo.setAccessFlags(Modifier.PUBLIC); // cons.getModifiers() & ~Modifier.NATIVE
  603. setThrows(minfo, cp, cons.getExceptionTypes());
  604. Bytecode code = new Bytecode(cp, 0, 0);
  605. code.addAload(0);
  606. code.addGetstatic(thisClassName, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
  607. code.addOpcode(Opcode.DUP);
  608. code.addOpcode(Opcode.IFNONNULL);
  609. code.addIndex(7);
  610. code.addOpcode(Opcode.POP);
  611. code.addGetstatic(NULL_INTERCEPTOR_HOLDER, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
  612. code.addPutfield(thisClassName, HANDLER, HANDLER_TYPE);
  613. code.addAload(0);
  614. int s = addLoadParameters(code, cons.getParameterTypes(), 1);
  615. code.addInvokespecial(superClass.getName(), "<init>", desc);
  616. code.addOpcode(Opcode.RETURN);
  617. code.setMaxLocals(s + 1);
  618. minfo.setCodeAttribute(code.toCodeAttribute());
  619. return minfo;
  620. }
  621. private static MethodInfo makeDelegator(Method meth, String desc,
  622. ConstPool cp, Class declClass, String delegatorName) {
  623. MethodInfo delegator = new MethodInfo(cp, delegatorName, desc);
  624. delegator.setAccessFlags(Modifier.FINAL | Modifier.PUBLIC
  625. | (meth.getModifiers() & ~(Modifier.PRIVATE
  626. | Modifier.PROTECTED
  627. | Modifier.ABSTRACT
  628. | Modifier.NATIVE
  629. | Modifier.SYNCHRONIZED)));
  630. setThrows(delegator, cp, meth);
  631. Bytecode code = new Bytecode(cp, 0, 0);
  632. code.addAload(0);
  633. int s = addLoadParameters(code, meth.getParameterTypes(), 1);
  634. code.addInvokespecial(declClass.getName(), meth.getName(), desc);
  635. addReturn(code, meth.getReturnType());
  636. code.setMaxLocals(++s);
  637. delegator.setCodeAttribute(code.toCodeAttribute());
  638. return delegator;
  639. }
  640. /**
  641. * @param delegatorName null if the original method is abstract.
  642. */
  643. private static MethodInfo makeForwarder(String thisClassName,
  644. Method meth, String desc, ConstPool cp,
  645. Class declClass, String delegatorName, int index) {
  646. MethodInfo forwarder = new MethodInfo(cp, meth.getName(), desc);
  647. forwarder.setAccessFlags(Modifier.FINAL
  648. | (meth.getModifiers() & ~(Modifier.ABSTRACT
  649. | Modifier.NATIVE
  650. | Modifier.SYNCHRONIZED)));
  651. setThrows(forwarder, cp, meth);
  652. int args = Descriptor.paramSize(desc);
  653. Bytecode code = new Bytecode(cp, 0, args + 2);
  654. /*
  655. * if (methods[index * 2] == null) {
  656. * methods[index * 2]
  657. * = RuntimeSupport.findMethod(this, <overridden name>, <desc>);
  658. * methods[index * 2 + 1]
  659. * = RuntimeSupport.findMethod(this, <delegator name>, <desc>);
  660. * or = null // the original method is abstract.
  661. * }
  662. * return ($r)handler.invoke(this, methods[index * 2],
  663. * methods[index * 2 + 1], $args);
  664. */
  665. int origIndex = index * 2;
  666. int delIndex = index * 2 + 1;
  667. int arrayVar = args + 1;
  668. code.addGetstatic(thisClassName, HOLDER, HOLDER_TYPE);
  669. code.addAstore(arrayVar);
  670. code.addAload(arrayVar);
  671. code.addIconst(origIndex);
  672. code.addOpcode(Opcode.AALOAD);
  673. code.addOpcode(Opcode.IFNONNULL);
  674. int pc = code.currentPc();
  675. code.addIndex(0);
  676. callFindMethod(code, "findSuperMethod", arrayVar, origIndex, meth.getName(), desc);
  677. callFindMethod(code, "findMethod", arrayVar, delIndex, delegatorName, desc);
  678. code.write16bit(pc, code.currentPc() - pc + 1);
  679. code.addAload(0);
  680. code.addGetfield(thisClassName, HANDLER, HANDLER_TYPE);
  681. code.addAload(0);
  682. code.addAload(arrayVar);
  683. code.addIconst(origIndex);
  684. code.addOpcode(Opcode.AALOAD);
  685. code.addAload(arrayVar);
  686. code.addIconst(delIndex);
  687. code.addOpcode(Opcode.AALOAD);
  688. makeParameterList(code, meth.getParameterTypes());
  689. code.addInvokeinterface(MethodHandler.class.getName(), "invoke",
  690. "(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;",
  691. 5);
  692. Class retType = meth.getReturnType();
  693. addUnwrapper(code, retType);
  694. addReturn(code, retType);
  695. forwarder.setCodeAttribute(code.toCodeAttribute());
  696. return forwarder;
  697. }
  698. private static void setThrows(MethodInfo minfo, ConstPool cp, Method orig) {
  699. Class[] exceptions = orig.getExceptionTypes();
  700. setThrows(minfo, cp, exceptions);
  701. }
  702. private static void setThrows(MethodInfo minfo, ConstPool cp,
  703. Class[] exceptions) {
  704. if (exceptions.length == 0)
  705. return;
  706. String[] list = new String[exceptions.length];
  707. for (int i = 0; i < exceptions.length; i++)
  708. list[i] = exceptions[i].getName();
  709. ExceptionsAttribute ea = new ExceptionsAttribute(cp);
  710. ea.setExceptions(list);
  711. minfo.setExceptionsAttribute(ea);
  712. }
  713. private static int addLoadParameters(Bytecode code, Class[] params,
  714. int offset) {
  715. int stacksize = 0;
  716. int n = params.length;
  717. for (int i = 0; i < n; ++i)
  718. stacksize += addLoad(code, stacksize + offset, params[i]);
  719. return stacksize;
  720. }
  721. private static int addLoad(Bytecode code, int n, Class type) {
  722. if (type.isPrimitive()) {
  723. if (type == Long.TYPE) {
  724. code.addLload(n);
  725. return 2;
  726. }
  727. else if (type == Float.TYPE)
  728. code.addFload(n);
  729. else if (type == Double.TYPE) {
  730. code.addDload(n);
  731. return 2;
  732. }
  733. else
  734. code.addIload(n);
  735. }
  736. else
  737. code.addAload(n);
  738. return 1;
  739. }
  740. private static int addReturn(Bytecode code, Class type) {
  741. if (type.isPrimitive()) {
  742. if (type == Long.TYPE) {
  743. code.addOpcode(Opcode.LRETURN);
  744. return 2;
  745. }
  746. else if (type == Float.TYPE)
  747. code.addOpcode(Opcode.FRETURN);
  748. else if (type == Double.TYPE) {
  749. code.addOpcode(Opcode.DRETURN);
  750. return 2;
  751. }
  752. else if (type == Void.TYPE) {
  753. code.addOpcode(Opcode.RETURN);
  754. return 0;
  755. }
  756. else
  757. code.addOpcode(Opcode.IRETURN);
  758. }
  759. else
  760. code.addOpcode(Opcode.ARETURN);
  761. return 1;
  762. }
  763. private static void makeParameterList(Bytecode code, Class[] params) {
  764. int regno = 1;
  765. int n = params.length;
  766. code.addIconst(n);
  767. code.addAnewarray("java/lang/Object");
  768. for (int i = 0; i < n; i++) {
  769. code.addOpcode(Opcode.DUP);
  770. code.addIconst(i);
  771. Class type = params[i];
  772. if (type.isPrimitive())
  773. regno = makeWrapper(code, type, regno);
  774. else {
  775. code.addAload(regno);
  776. regno++;
  777. }
  778. code.addOpcode(Opcode.AASTORE);
  779. }
  780. }
  781. private static int makeWrapper(Bytecode code, Class type, int regno) {
  782. int index = FactoryHelper.typeIndex(type);
  783. String wrapper = FactoryHelper.wrapperTypes[index];
  784. code.addNew(wrapper);
  785. code.addOpcode(Opcode.DUP);
  786. addLoad(code, regno, type);
  787. code.addInvokespecial(wrapper, "<init>",
  788. FactoryHelper.wrapperDesc[index]);
  789. return regno + FactoryHelper.dataSize[index];
  790. }
  791. /**
  792. * @param methodName might be null.
  793. */
  794. private static void callFindMethod(Bytecode code, String findMethod,
  795. int arrayVar, int index, String methodName, String desc) {
  796. String findClass = RuntimeSupport.class.getName();
  797. String findDesc
  798. = "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/reflect/Method;";
  799. code.addAload(arrayVar);
  800. code.addIconst(index);
  801. if (methodName == null)
  802. code.addOpcode(Opcode.ACONST_NULL);
  803. else {
  804. code.addAload(0);
  805. code.addLdc(methodName);
  806. code.addLdc(desc);
  807. code.addInvokestatic(findClass, findMethod, findDesc);
  808. }
  809. code.addOpcode(Opcode.AASTORE);
  810. }
  811. private static void addUnwrapper(Bytecode code, Class type) {
  812. if (type.isPrimitive()) {
  813. if (type == Void.TYPE)
  814. code.addOpcode(Opcode.POP);
  815. else {
  816. int index = FactoryHelper.typeIndex(type);
  817. String wrapper = FactoryHelper.wrapperTypes[index];
  818. code.addCheckcast(wrapper);
  819. code.addInvokevirtual(wrapper,
  820. FactoryHelper.unwarpMethods[index],
  821. FactoryHelper.unwrapDesc[index]);
  822. }
  823. }
  824. else
  825. code.addCheckcast(type.getName());
  826. }
  827. }