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

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