You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ProxyFactory.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2005 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.Method;
  18. import java.lang.reflect.Constructor;
  19. import java.lang.reflect.Member;
  20. import java.lang.reflect.Modifier;
  21. import java.util.HashMap;
  22. import java.util.Iterator;
  23. import java.util.Map;
  24. import java.util.Set;
  25. import javassist.CannotCompileException;
  26. import javassist.bytecode.*;
  27. /**
  28. * Factory of dynamic proxy classes.
  29. *
  30. * <p>This factory generates a class that extends the given super class and implements
  31. * the given interfaces. The calls of the methods inherited from the super class are
  32. * forwarded and then <code>invoke()</code> is called on the method handler
  33. * associated with the generated class. The calls of the methods from the interfaces
  34. * are also forwarded to the method handler.
  35. *
  36. * <p>For example, if the following code is executed,
  37. *
  38. * <ul><pre>
  39. * ProxyFactory f = new ProxyFactory();
  40. * f.setSuperclass(Foo.class);
  41. * MethodHandler mi = new MethodHandler() {
  42. * public Object invoke(Object self, Method m, Method proceed,
  43. * Object[] args) throws Exception {
  44. * System.out.println("Name: " + m.getName());
  45. * proceed.invoke(self, args); // execute the original method.
  46. * }
  47. * };
  48. * f.setHandler(mi);
  49. * Class c = f.createClass();
  50. * Foo foo = (Foo)c.newInstance();
  51. * </pre></ul>
  52. *
  53. * <p>Then, the following method call will be forwarded to MethodHandler
  54. * <code>mi</code> and prints a message before executing the originally called method
  55. * <code>bar()</code> in <code>Foo</code>.
  56. *
  57. * <ul><pre>
  58. * foo.bar();
  59. * </pre></ul>
  60. *
  61. * <p>To change the method handler during runtime,
  62. * execute the following code:
  63. *
  64. * <ul><pre>
  65. * MethodHandler mi2 = ... ; // another handler
  66. * ((ProxyObject)foo).setHandler(mi2);
  67. * </pre></ul>
  68. *
  69. * <p>Here is an example of method handler. It does not execute
  70. * anything except invoking the original method:
  71. *
  72. * <ul><pre>
  73. * class SimpleHandler implements MethodHandler {
  74. * public Object invoke(Object self, Method m,
  75. * Method proceed, Object[] args) throws Exception {
  76. * return proceed.invoke(self, args);
  77. * }
  78. * }
  79. * </pre></ul>
  80. *
  81. * @see MethodHandler
  82. * @since 3.1
  83. */
  84. public class ProxyFactory {
  85. private Class superClass;
  86. private Class[] interfaces;
  87. private MethodFilter methodFilter;
  88. private MethodHandler handler;
  89. private Class thisClass;
  90. /**
  91. * If the value of this variable is not null, the class file of
  92. * the generated proxy class is written under the directory specified
  93. * by this variable. For example, if the value is
  94. * <code>"."</code>, then the class file is written under the current
  95. * directory. This method is for debugging.
  96. *
  97. * <p>The default value is null.
  98. */
  99. public String writeDirectory;
  100. private static final Class OBJECT_TYPE = Object.class;
  101. private static final String HOLDER = "_methods_";
  102. private static final String HOLDER_TYPE = "[Ljava/lang/reflect/Method;";
  103. private static final String HANDLER = "handler";
  104. private static final String DEFAULT_INTERCEPTOR = "default_interceptor";
  105. private static final String HANDLER_TYPE
  106. = 'L' + MethodHandler.class.getName().replace('.', '/') + ';';
  107. private static final String HANDLER_SETTER = "setHandler";
  108. private static final String HANDLER_SETTER_TYPE = "(" + HANDLER_TYPE + ")V";
  109. /**
  110. * Constructs a factory of proxy class.
  111. */
  112. public ProxyFactory() {
  113. superClass = null;
  114. interfaces = null;
  115. methodFilter = null;
  116. handler = new MethodHandler() {
  117. public Object invoke(Object self, Method m,
  118. Method proceed, Object[] args)
  119. throws Exception
  120. {
  121. return proceed.invoke(self, args);
  122. }
  123. };
  124. thisClass = null;
  125. writeDirectory = null;
  126. }
  127. /**
  128. * Sets the super class of a proxy class.
  129. */
  130. public void setSuperclass(Class clazz) {
  131. superClass = clazz;
  132. }
  133. /**
  134. * Sets the interfaces of a proxy class.
  135. */
  136. public void setInterfaces(Class[] ifs) {
  137. interfaces = ifs;
  138. }
  139. /**
  140. * Sets a filter that selects the methods that will be controlled by a handler.
  141. */
  142. public void setFilter(MethodFilter mf) {
  143. methodFilter = mf;
  144. }
  145. /**
  146. * Generates a proxy class.
  147. */
  148. public Class createClass() {
  149. if (thisClass == null)
  150. try {
  151. ClassFile cf = make();
  152. ClassLoader cl = getClassLoader();
  153. if (writeDirectory != null)
  154. FactoryHelper.writeFile(cf, writeDirectory);
  155. thisClass = FactoryHelper.toClass(cf, cl);
  156. setHandler();
  157. }
  158. catch (CannotCompileException e) {
  159. throw new RuntimeException(e.getMessage(), e);
  160. }
  161. return thisClass;
  162. }
  163. protected ClassLoader getClassLoader() {
  164. if (superClass != null && !superClass.getName().equals("java.lang.Object"))
  165. return superClass.getClassLoader();
  166. else if (interfaces != null && interfaces.length > 0)
  167. return interfaces[0].getClassLoader();
  168. else
  169. return this.getClass().getClassLoader();
  170. // return Thread.currentThread().getContextClassLoader();
  171. }
  172. /**
  173. * Sets the default invocation handler. This invocation handler is shared
  174. * among all the instances of a proxy class unless another is explicitly
  175. * specified.
  176. */
  177. public void setHandler(MethodHandler mi) {
  178. handler = mi;
  179. setHandler();
  180. }
  181. private void setHandler() {
  182. if (thisClass != null && handler != null)
  183. try {
  184. Field f = thisClass.getField(DEFAULT_INTERCEPTOR);
  185. f.setAccessible(true);
  186. f.set(null, handler);
  187. f.setAccessible(false);
  188. }
  189. catch (Exception e) {
  190. throw new RuntimeException(e);
  191. }
  192. }
  193. private static int counter = 0;
  194. private ClassFile make() throws CannotCompileException {
  195. String superName, classname;
  196. if (interfaces == null)
  197. interfaces = new Class[0];
  198. if (superClass == null) {
  199. superClass = OBJECT_TYPE;
  200. superName = superClass.getName();
  201. classname = interfaces.length == 0 ? superName
  202. : interfaces[0].getName();
  203. }
  204. else {
  205. superName = superClass.getName();
  206. classname = superName;
  207. }
  208. if (Modifier.isFinal(superClass.getModifiers()))
  209. throw new CannotCompileException(superName + " is final");
  210. // generate a proxy name.
  211. classname = classname + "_$$_javassist_" + counter++;
  212. if (classname.startsWith("java."))
  213. classname = "org.javassist.tmp." + classname;
  214. ClassFile cf = new ClassFile(false, classname, superName);
  215. cf.setAccessFlags(AccessFlag.PUBLIC);
  216. setInterfaces(cf, interfaces);
  217. ConstPool pool = cf.getConstPool();
  218. FieldInfo finfo = new FieldInfo(pool, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
  219. finfo.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
  220. cf.addField(finfo);
  221. FieldInfo finfo2 = new FieldInfo(pool, HANDLER, HANDLER_TYPE);
  222. finfo2.setAccessFlags(AccessFlag.PRIVATE);
  223. cf.addField(finfo2);
  224. HashMap allMethods = getMethods(superClass, interfaces);
  225. int size = allMethods.size();
  226. makeConstructors(classname, cf, pool, classname);
  227. int s = overrideMethods(cf, pool, classname, allMethods);
  228. addMethodsHolder(cf, pool, classname, s);
  229. addSetter(classname, cf, pool);
  230. thisClass = null;
  231. return cf;
  232. }
  233. private static void setInterfaces(ClassFile cf, Class[] interfaces) {
  234. String setterIntf = ProxyObject.class.getName();
  235. String[] list;
  236. if (interfaces == null || interfaces.length == 0)
  237. list = new String[] { setterIntf };
  238. else {
  239. list = new String[interfaces.length + 1];
  240. for (int i = 0; i < interfaces.length; i++)
  241. list[i] = interfaces[i].getName();
  242. list[interfaces.length] = setterIntf;
  243. }
  244. cf.setInterfaces(list);
  245. }
  246. private static void addMethodsHolder(ClassFile cf, ConstPool cp,
  247. String classname, int size)
  248. throws CannotCompileException
  249. {
  250. FieldInfo finfo = new FieldInfo(cp, HOLDER, HOLDER_TYPE);
  251. finfo.setAccessFlags(AccessFlag.PRIVATE | AccessFlag.STATIC);
  252. cf.addField(finfo);
  253. MethodInfo minfo = new MethodInfo(cp, "<clinit>", "()V");
  254. Bytecode code = new Bytecode(cp, 0, 0);
  255. code.addIconst(size * 2);
  256. code.addAnewarray("java.lang.reflect.Method");
  257. code.addPutstatic(classname, HOLDER, HOLDER_TYPE);
  258. code.addOpcode(Bytecode.RETURN);
  259. minfo.setCodeAttribute(code.toCodeAttribute());
  260. cf.addMethod(minfo);
  261. }
  262. private static void addSetter(String classname, ClassFile cf, ConstPool cp)
  263. throws CannotCompileException
  264. {
  265. MethodInfo minfo = new MethodInfo(cp, HANDLER_SETTER,
  266. HANDLER_SETTER_TYPE);
  267. minfo.setAccessFlags(AccessFlag.PUBLIC);
  268. Bytecode code = new Bytecode(cp, 2, 2);
  269. code.addAload(0);
  270. code.addAload(1);
  271. code.addPutfield(classname, HANDLER, HANDLER_TYPE);
  272. code.addOpcode(Bytecode.RETURN);
  273. minfo.setCodeAttribute(code.toCodeAttribute());
  274. cf.addMethod(minfo);
  275. }
  276. private int overrideMethods(ClassFile cf, ConstPool cp, String className,
  277. HashMap allMethods)
  278. throws CannotCompileException
  279. {
  280. String prefix = makeUniqueName("_d", allMethods);
  281. Set entries = allMethods.entrySet();
  282. Iterator it = entries.iterator();
  283. int index = 0;
  284. while (it.hasNext()) {
  285. Map.Entry e = (Map.Entry)it.next();
  286. String key = (String)e.getKey();
  287. Method meth = (Method)e.getValue();
  288. int mod = meth.getModifiers();
  289. if (!Modifier.isFinal(mod) && !Modifier.isStatic(mod)
  290. && isVisible(mod, className, meth))
  291. if (methodFilter == null || methodFilter.isHandled(meth))
  292. override(className, meth, prefix, index++,
  293. keyToDesc(key), cf, cp);
  294. }
  295. return index;
  296. }
  297. private void override(String thisClassname, Method meth, String prefix,
  298. int index, String desc, ClassFile cf, ConstPool cp)
  299. throws CannotCompileException
  300. {
  301. Class declClass = meth.getDeclaringClass();
  302. String delegatorName = prefix + index + meth.getName();
  303. if (Modifier.isAbstract(meth.getModifiers()))
  304. delegatorName = null;
  305. else {
  306. MethodInfo delegator
  307. = makeDelegator(meth, desc, cp, declClass, delegatorName);
  308. cf.addMethod(delegator);
  309. }
  310. MethodInfo forwarder
  311. = makeForwarder(thisClassname, meth, desc, cp, declClass,
  312. delegatorName, index);
  313. cf.addMethod(forwarder);
  314. }
  315. private void makeConstructors(String thisClassName, ClassFile cf,
  316. ConstPool cp, String classname) throws CannotCompileException
  317. {
  318. Constructor[] cons = superClass.getDeclaredConstructors();
  319. for (int i = 0; i < cons.length; i++) {
  320. Constructor c = cons[i];
  321. int mod = c.getModifiers();
  322. if (!Modifier.isFinal(mod) && !Modifier.isPrivate(mod)
  323. && isVisible(mod, classname, c)) {
  324. MethodInfo m = makeConstructor(thisClassName, c, cp, superClass);
  325. cf.addMethod(m);
  326. }
  327. }
  328. }
  329. private static String makeUniqueName(String name, HashMap hash) {
  330. Set keys = hash.keySet();
  331. if (makeUniqueName0(name, keys.iterator()))
  332. return name;
  333. for (int i = 100; i < 999; i++) {
  334. String s = name + i;
  335. if (makeUniqueName0(s, keys.iterator()))
  336. return s;
  337. }
  338. throw new RuntimeException("cannot make a unique method name");
  339. }
  340. private static boolean makeUniqueName0(String name, Iterator it) {
  341. while (it.hasNext()) {
  342. String key = (String)it.next();
  343. if (key.startsWith(name))
  344. return false;
  345. }
  346. return true;
  347. }
  348. /**
  349. * Returns true if the method is visible from the class.
  350. *
  351. * @param mod the modifiers of the method.
  352. */
  353. private static boolean isVisible(int mod, String from, Member meth) {
  354. if ((mod & Modifier.PRIVATE) != 0)
  355. return false;
  356. else if ((mod & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0)
  357. return true;
  358. else {
  359. String p = getPackageName(from);
  360. String q = getPackageName(meth.getDeclaringClass().getName());
  361. if (p == null)
  362. return q == null;
  363. else
  364. return p.equals(q);
  365. }
  366. }
  367. private static String getPackageName(String name) {
  368. int i = name.lastIndexOf('.');
  369. if (i < 0)
  370. return null;
  371. else
  372. return name.substring(0, i);
  373. }
  374. private static HashMap getMethods(Class superClass, Class[] interfaceTypes) {
  375. HashMap hash = new HashMap();
  376. for (int i = 0; i < interfaceTypes.length; i++)
  377. getMethods(hash, interfaceTypes[i]);
  378. getMethods(hash, superClass);
  379. return hash;
  380. }
  381. private static void getMethods(HashMap hash, Class clazz) {
  382. Class[] ifs = clazz.getInterfaces();
  383. for (int i = 0; i < ifs.length; i++)
  384. getMethods(hash, ifs[i]);
  385. Class parent = clazz.getSuperclass();
  386. if (parent != null)
  387. getMethods(hash, parent);
  388. Method[] methods = clazz.getDeclaredMethods();
  389. for (int i = 0; i < methods.length; i++)
  390. if (!Modifier.isPrivate(methods[i].getModifiers())) {
  391. Method m = methods[i];
  392. String key = m.getName() + ':' + RuntimeSupport.makeDescriptor(m);
  393. hash.put(key, methods[i]);
  394. }
  395. }
  396. private static String keyToDesc(String key) {
  397. return key.substring(key.indexOf(':') + 1);
  398. }
  399. private static MethodInfo makeConstructor(String thisClassName, Constructor cons,
  400. ConstPool cp, Class superClass) {
  401. String desc = RuntimeSupport.makeDescriptor(cons.getParameterTypes(),
  402. Void.TYPE);
  403. MethodInfo minfo = new MethodInfo(cp, "<init>", desc);
  404. minfo.setAccessFlags(Modifier.PUBLIC); // cons.getModifiers() & ~Modifier.NATIVE
  405. setThrows(minfo, cp, cons.getExceptionTypes());
  406. Bytecode code = new Bytecode(cp, 0, 0);
  407. code.addAload(0);
  408. code.addGetstatic(thisClassName, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
  409. code.addPutfield(thisClassName, HANDLER, HANDLER_TYPE);
  410. code.addAload(0);
  411. int s = addLoadParameters(code, cons.getParameterTypes(), 1);
  412. code.addInvokespecial(superClass.getName(), "<init>", desc);
  413. code.addOpcode(Opcode.RETURN);
  414. code.setMaxLocals(++s);
  415. minfo.setCodeAttribute(code.toCodeAttribute());
  416. return minfo;
  417. }
  418. private static MethodInfo makeDelegator(Method meth, String desc,
  419. ConstPool cp, Class declClass, String delegatorName) {
  420. MethodInfo delegator = new MethodInfo(cp, delegatorName, desc);
  421. delegator.setAccessFlags(Modifier.FINAL | Modifier.PUBLIC
  422. | (meth.getModifiers() & ~(Modifier.PRIVATE
  423. | Modifier.PROTECTED
  424. | Modifier.ABSTRACT
  425. | Modifier.NATIVE
  426. | Modifier.SYNCHRONIZED)));
  427. setThrows(delegator, cp, meth);
  428. Bytecode code = new Bytecode(cp, 0, 0);
  429. code.addAload(0);
  430. int s = addLoadParameters(code, meth.getParameterTypes(), 1);
  431. code.addInvokespecial(declClass.getName(), meth.getName(), desc);
  432. addReturn(code, meth.getReturnType());
  433. code.setMaxLocals(++s);
  434. delegator.setCodeAttribute(code.toCodeAttribute());
  435. return delegator;
  436. }
  437. /**
  438. * @param delegatorName null if the original method is abstract.
  439. */
  440. private static MethodInfo makeForwarder(String thisClassName,
  441. Method meth, String desc, ConstPool cp,
  442. Class declClass, String delegatorName, int index) {
  443. MethodInfo forwarder = new MethodInfo(cp, meth.getName(), desc);
  444. forwarder.setAccessFlags(Modifier.FINAL
  445. | (meth.getModifiers() & ~(Modifier.ABSTRACT
  446. | Modifier.NATIVE
  447. | Modifier.SYNCHRONIZED)));
  448. setThrows(forwarder, cp, meth);
  449. int args = Descriptor.paramSize(desc);
  450. Bytecode code = new Bytecode(cp, 0, args + 2);
  451. /*
  452. * if (methods[index * 2] == null) {
  453. * methods[index * 2]
  454. * = RuntimeSupport.findMethod(this, <overridden name>, <desc>);
  455. * methods[index * 2 + 1]
  456. * = RuntimeSupport.findMethod(this, <delegator name>, <desc>);
  457. * or = null // the original method is abstract.
  458. * }
  459. * return ($r)handler.invoke(this, methods[index * 2],
  460. * methods[index * 2 + 1], $args);
  461. */
  462. int origIndex = index * 2;
  463. int delIndex = index * 2 + 1;
  464. int arrayVar = args + 1;
  465. code.addGetstatic(thisClassName, HOLDER, HOLDER_TYPE);
  466. code.addAstore(arrayVar);
  467. code.addAload(arrayVar);
  468. code.addIconst(origIndex);
  469. code.addOpcode(Opcode.AALOAD);
  470. code.addOpcode(Opcode.IFNONNULL);
  471. int pc = code.currentPc();
  472. code.addIndex(0);
  473. callFindMethod(code, "findSuperMethod", arrayVar, origIndex, meth.getName(), desc);
  474. callFindMethod(code, "findMethod", arrayVar, delIndex, delegatorName, desc);
  475. code.write16bit(pc, code.currentPc() - pc + 1);
  476. code.addAload(0);
  477. code.addGetfield(thisClassName, HANDLER, HANDLER_TYPE);
  478. code.addAload(0);
  479. code.addAload(arrayVar);
  480. code.addIconst(origIndex);
  481. code.addOpcode(Opcode.AALOAD);
  482. code.addAload(arrayVar);
  483. code.addIconst(delIndex);
  484. code.addOpcode(Opcode.AALOAD);
  485. makeParameterList(code, meth.getParameterTypes());
  486. code.addInvokeinterface(MethodHandler.class.getName(), "invoke",
  487. "(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;",
  488. 5);
  489. Class retType = meth.getReturnType();
  490. addUnwrapper(code, retType);
  491. addReturn(code, retType);
  492. forwarder.setCodeAttribute(code.toCodeAttribute());
  493. return forwarder;
  494. }
  495. private static void setThrows(MethodInfo minfo, ConstPool cp, Method orig) {
  496. Class[] exceptions = orig.getExceptionTypes();
  497. setThrows(minfo, cp, exceptions);
  498. }
  499. private static void setThrows(MethodInfo minfo, ConstPool cp,
  500. Class[] exceptions) {
  501. if (exceptions.length == 0)
  502. return;
  503. String[] list = new String[exceptions.length];
  504. for (int i = 0; i < exceptions.length; i++)
  505. list[i] = exceptions[i].getName();
  506. ExceptionsAttribute ea = new ExceptionsAttribute(cp);
  507. ea.setExceptions(list);
  508. minfo.setExceptionsAttribute(ea);
  509. }
  510. private static int addLoadParameters(Bytecode code, Class[] params,
  511. int offset) {
  512. int stacksize = 0;
  513. int n = params.length;
  514. for (int i = 0; i < n; ++i)
  515. stacksize += addLoad(code, stacksize + offset, params[i]);
  516. return stacksize;
  517. }
  518. private static int addLoad(Bytecode code, int n, Class type) {
  519. if (type.isPrimitive()) {
  520. if (type == Long.TYPE) {
  521. code.addLload(n);
  522. return 2;
  523. }
  524. else if (type == Float.TYPE)
  525. code.addFload(n);
  526. else if (type == Double.TYPE) {
  527. code.addDload(n);
  528. return 2;
  529. }
  530. else
  531. code.addIload(n);
  532. }
  533. else
  534. code.addAload(n);
  535. return 1;
  536. }
  537. private static int addReturn(Bytecode code, Class type) {
  538. if (type.isPrimitive()) {
  539. if (type == Long.TYPE) {
  540. code.addOpcode(Opcode.LRETURN);
  541. return 2;
  542. }
  543. else if (type == Float.TYPE)
  544. code.addOpcode(Opcode.FRETURN);
  545. else if (type == Double.TYPE) {
  546. code.addOpcode(Opcode.DRETURN);
  547. return 2;
  548. }
  549. else if (type == Void.TYPE) {
  550. code.addOpcode(Opcode.RETURN);
  551. return 0;
  552. }
  553. else
  554. code.addOpcode(Opcode.IRETURN);
  555. }
  556. else
  557. code.addOpcode(Opcode.ARETURN);
  558. return 1;
  559. }
  560. private static void makeParameterList(Bytecode code, Class[] params) {
  561. int regno = 1;
  562. int n = params.length;
  563. code.addIconst(n);
  564. code.addAnewarray("java/lang/Object");
  565. for (int i = 0; i < n; i++) {
  566. code.addOpcode(Opcode.DUP);
  567. code.addIconst(i);
  568. Class type = params[i];
  569. if (type.isPrimitive())
  570. regno = makeWrapper(code, type, regno);
  571. else {
  572. code.addAload(regno);
  573. regno++;
  574. }
  575. code.addOpcode(Opcode.AASTORE);
  576. }
  577. }
  578. private static int makeWrapper(Bytecode code, Class type, int regno) {
  579. int index = FactoryHelper.typeIndex(type);
  580. String wrapper = FactoryHelper.wrapperTypes[index];
  581. code.addNew(wrapper);
  582. code.addOpcode(Opcode.DUP);
  583. addLoad(code, regno, type);
  584. code.addInvokespecial(wrapper, "<init>",
  585. FactoryHelper.wrapperDesc[index]);
  586. return regno + FactoryHelper.dataSize[index];
  587. }
  588. /**
  589. * @param methodName might be null.
  590. */
  591. private static void callFindMethod(Bytecode code, String findMethod,
  592. int arrayVar, int index, String methodName, String desc) {
  593. String findClass = RuntimeSupport.class.getName();
  594. String findDesc
  595. = "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/reflect/Method;";
  596. code.addAload(arrayVar);
  597. code.addIconst(index);
  598. if (methodName == null)
  599. code.addOpcode(Opcode.ACONST_NULL);
  600. else {
  601. code.addAload(0);
  602. code.addLdc(methodName);
  603. code.addLdc(desc);
  604. code.addInvokestatic(findClass, findMethod, findDesc);
  605. }
  606. code.addOpcode(Opcode.AASTORE);
  607. }
  608. private static void addUnwrapper(Bytecode code, Class type) {
  609. if (type.isPrimitive()) {
  610. if (type == Void.TYPE)
  611. code.addOpcode(Opcode.POP);
  612. else {
  613. int index = FactoryHelper.typeIndex(type);
  614. String wrapper = FactoryHelper.wrapperTypes[index];
  615. code.addCheckcast(wrapper);
  616. code.addInvokevirtual(wrapper,
  617. FactoryHelper.unwarpMethods[index],
  618. FactoryHelper.unwrapDesc[index]);
  619. }
  620. }
  621. else
  622. code.addCheckcast(type.getName());
  623. }
  624. }