001: /***** BEGIN LICENSE BLOCK *****
002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
003: *
004: * The contents of this file are subject to the Common Public
005: * License Version 1.0 (the "License"); you may not use this file
006: * except in compliance with the License. You may obtain a copy of
007: * the License at http://www.eclipse.org/legal/cpl-v10.html
008: *
009: * Software distributed under the License is distributed on an "AS
010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * rights and limitations under the License.
013: *
014: * Copyright (C) 2006 Ola Bini <ola@ologix.com>
015: *
016: * Alternatively, the contents of this file may be used under the terms of
017: * either of the GNU General Public License Version 2 or later (the "GPL"),
018: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
019: * in which case the provisions of the GPL or the LGPL are applicable instead
020: * of those above. If you wish to allow use of your version of this file only
021: * under the terms of either the GPL or the LGPL, and not to allow others to
022: * use your version of this file under the terms of the CPL, indicate your
023: * decision by deleting the provisions above and replace them with the notice
024: * and other provisions required by the GPL or the LGPL. If you do not delete
025: * the provisions above, a recipient may use your version of this file under
026: * the terms of any one of the CPL, the GPL or the LGPL.
027: ***** END LICENSE BLOCK *****/package org.jruby.runtime.callback;
028:
029: import org.jruby.Ruby;
030: import org.jruby.RubyKernel;
031: import org.objectweb.asm.ClassWriter;
032: import org.objectweb.asm.MethodVisitor;
033: import org.objectweb.asm.Opcodes;
034: import org.jruby.runtime.Arity;
035: import org.jruby.runtime.Block;
036: import org.jruby.runtime.CallbackFactory;
037: import org.jruby.runtime.CompiledBlockCallback;
038: import org.jruby.runtime.ThreadContext;
039: import org.jruby.runtime.builtin.IRubyObject;
040: import org.jruby.util.CodegenUtils;
041: import org.jruby.util.JRubyClassLoader;
042:
043: public class InvocationCallbackFactory extends CallbackFactory
044: implements Opcodes {
045: private final static CodegenUtils cg = CodegenUtils.cg;
046:
047: private final Class type;
048: private final JRubyClassLoader classLoader;
049: private final String typePath;
050: private final Ruby runtime;
051:
052: private final static String SUPER_CLASS = cg
053: .p(InvocationCallback.class);
054: private final static String FAST_SUPER_CLASS = cg
055: .p(FastInvocationCallback.class);
056: private final static String BLOCK_ID = cg.ci(Block.class);
057: private final static String CALL_SIG = cg.sig(
058: RubyKernel.IRUBY_OBJECT, cg.params(Object.class,
059: Object[].class, Block.class));
060: private final static String FAST_CALL_SIG = cg.sig(
061: RubyKernel.IRUBY_OBJECT, cg.params(Object.class,
062: Object[].class));
063: private final static String BLOCK_CALL_SIG = cg.sig(
064: RubyKernel.IRUBY_OBJECT, cg.params(ThreadContext.class,
065: RubyKernel.IRUBY_OBJECT, IRubyObject[].class));
066: private final static String IRUB = cg.p(RubyKernel.IRUBY_OBJECT);
067: private final static String IRUB_ID = cg
068: .ci(RubyKernel.IRUBY_OBJECT);
069:
070: public InvocationCallbackFactory(Ruby runtime, Class type,
071: JRubyClassLoader classLoader) {
072: this .type = type;
073: this .classLoader = classLoader;
074: this .typePath = cg.p(type);
075: this .runtime = runtime;
076: }
077:
078: private String getReturnName(String method, Class[] args)
079: throws Exception {
080: String t = type.getMethod(method, args).getReturnType()
081: .getName().replace('.', '/');
082: if ("void".equalsIgnoreCase(t)) {
083: throw new IllegalArgumentException(
084: "Method "
085: + method
086: + " has a void return type. This is not allowed in JRuby.");
087: }
088: return t;
089: }
090:
091: private ClassWriter createCtor(String namePath) throws Exception {
092: ClassWriter cw = new ClassWriter(true);
093: cw.visit(V1_4, ACC_PUBLIC + ACC_SUPER, namePath, null,
094: SUPER_CLASS, null);
095: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V",
096: null, null);
097: mv.visitCode();
098: mv.visitVarInsn(ALOAD, 0);
099: mv.visitMethodInsn(INVOKESPECIAL, SUPER_CLASS, "<init>", "()V");
100: mv.visitInsn(RETURN);
101: mv.visitMaxs(1, 1);
102: mv.visitEnd();
103: return cw;
104: }
105:
106: private ClassWriter createCtorFast(String namePath)
107: throws Exception {
108: ClassWriter cw = new ClassWriter(true);
109: cw.visit(V1_4, ACC_PUBLIC + ACC_SUPER, namePath, null,
110: FAST_SUPER_CLASS, null);
111: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V",
112: null, null);
113: mv.visitCode();
114: mv.visitVarInsn(ALOAD, 0);
115: mv.visitMethodInsn(INVOKESPECIAL, FAST_SUPER_CLASS, "<init>",
116: "()V");
117: mv.visitInsn(RETURN);
118: mv.visitMaxs(1, 1);
119: mv.visitEnd();
120: return cw;
121: }
122:
123: private ClassWriter createBlockCtor(String namePath)
124: throws Exception {
125: ClassWriter cw = new ClassWriter(true);
126: cw.visit(V1_4, ACC_PUBLIC + ACC_SUPER, namePath, null, cg
127: .p(Object.class), new String[] { cg
128: .p(CompiledBlockCallback.class) });
129: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V",
130: null, null);
131: mv.visitCode();
132: mv.visitVarInsn(ALOAD, 0);
133: mv.visitMethodInsn(INVOKESPECIAL, cg.p(Object.class), "<init>",
134: "()V");
135: mv.visitInsn(RETURN);
136: mv.visitMaxs(1, 1);
137: mv.visitEnd();
138: return cw;
139: }
140:
141: private Class tryClass(String name) {
142: try {
143: return classLoader.loadClass(name);
144: } catch (Exception e) {
145: return null;
146: }
147: }
148:
149: private MethodVisitor startCall(ClassWriter cw) {
150: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "call", CALL_SIG,
151: null, null);
152: ;
153: mv.visitCode();
154: mv.visitVarInsn(ALOAD, 1);
155: mv.visitTypeInsn(CHECKCAST, typePath);
156: return mv;
157: }
158:
159: private MethodVisitor startCallS(ClassWriter cw) {
160: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "call", CALL_SIG,
161: null, null);
162: ;
163: mv.visitCode();
164: mv.visitVarInsn(ALOAD, 1);
165: mv.visitTypeInsn(CHECKCAST, IRUB);
166: return mv;
167: }
168:
169: private MethodVisitor startCallFast(ClassWriter cw) {
170: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "call",
171: FAST_CALL_SIG, null, null);
172: ;
173: mv.visitCode();
174: mv.visitVarInsn(ALOAD, 1);
175: mv.visitTypeInsn(CHECKCAST, typePath);
176: return mv;
177: }
178:
179: private MethodVisitor startCallSFast(ClassWriter cw) {
180: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "call",
181: FAST_CALL_SIG, null, null);
182: ;
183: mv.visitCode();
184: mv.visitVarInsn(ALOAD, 1);
185: mv.visitTypeInsn(CHECKCAST, IRUB);
186: return mv;
187: }
188:
189: private MethodVisitor startBlockCall(ClassWriter cw) {
190: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "call",
191: BLOCK_CALL_SIG, null, null);
192: ;
193: mv.visitCode();
194: return mv;
195: }
196:
197: private Class endCall(ClassWriter cw, MethodVisitor mv, String name) {
198: mv.visitEnd();
199: cw.visitEnd();
200: byte[] code = cw.toByteArray();
201: return classLoader.defineClass(name, code);
202: }
203:
204: public Callback getMethod(String method) {
205: String mname = type.getName() + "Invoker" + method + "0";
206: String mnamePath = typePath + "Invoker" + method + "0";
207: synchronized (runtime.getJRubyClassLoader()) {
208: Class c = tryClass(mname);
209: try {
210: if (c == null) {
211: String ret = getReturnName(method,
212: new Class[] { Block.class });
213: ClassWriter cw = createCtor(mnamePath);
214: MethodVisitor mv = startCall(cw);
215: mv.visitVarInsn(ALOAD, 3);
216: mv.visitMethodInsn(INVOKEVIRTUAL, typePath, method,
217: "(" + BLOCK_ID + ")L" + ret + ";");
218: mv.visitInsn(ARETURN);
219: mv.visitMaxs(1, 3);
220: c = endCall(cw, mv, mname);
221: }
222: InvocationCallback ic = (InvocationCallback) c
223: .newInstance();
224: ic.setArity(Arity.noArguments());
225: return ic;
226: } catch (IllegalArgumentException e) {
227: throw e;
228: } catch (Exception e) {
229: throw new IllegalArgumentException(e.getMessage());
230: }
231: }
232: }
233:
234: public Callback getMethod(String method, Class arg1) {
235: String mname = type.getName() + "Invoker" + method + "1";
236: String mnamePath = typePath + "Invoker" + method + "1";
237: synchronized (runtime.getJRubyClassLoader()) {
238: Class c = tryClass(mname);
239: try {
240: if (c == null) {
241: String ret = getReturnName(method, new Class[] {
242: arg1, Block.class });
243: ClassWriter cw = createCtor(mnamePath);
244: MethodVisitor mv = startCall(cw);
245: mv.visitVarInsn(ALOAD, 2);
246: mv.visitInsn(ICONST_0);
247: mv.visitInsn(AALOAD);
248: mv.visitTypeInsn(CHECKCAST, cg.p(arg1));
249: mv.visitVarInsn(ALOAD, 3);
250: mv.visitMethodInsn(INVOKEVIRTUAL, typePath, method,
251: "(" + cg.ci(arg1) + BLOCK_ID + ")L" + ret
252: + ";");
253: mv.visitInsn(ARETURN);
254: mv.visitMaxs(3, 3);
255: c = endCall(cw, mv, mname);
256: }
257: InvocationCallback ic = (InvocationCallback) c
258: .newInstance();
259: ic.setArity(Arity.singleArgument());
260: return ic;
261: } catch (IllegalArgumentException e) {
262: throw e;
263: } catch (Exception e) {
264: throw new IllegalArgumentException(e.getMessage());
265: }
266: }
267: }
268:
269: public Callback getMethod(String method, Class arg1, Class arg2) {
270: String mname = type.getName() + "Invoker" + method + "2";
271: String mnamePath = typePath + "Invoker" + method + "2";
272: synchronized (runtime.getJRubyClassLoader()) {
273: Class c = tryClass(mname);
274: try {
275: if (c == null) {
276: String ret = getReturnName(method, new Class[] {
277: arg1, arg2, Block.class });
278: ClassWriter cw = createCtor(mnamePath);
279: MethodVisitor mv = startCall(cw);
280: mv.visitVarInsn(ALOAD, 2);
281: mv.visitInsn(ICONST_0);
282: mv.visitInsn(AALOAD);
283: mv.visitTypeInsn(CHECKCAST, cg.p(arg1));
284: mv.visitVarInsn(ALOAD, 2);
285: mv.visitInsn(ICONST_1);
286: mv.visitInsn(AALOAD);
287: mv.visitTypeInsn(CHECKCAST, cg.p(arg2));
288: mv.visitVarInsn(ALOAD, 3);
289: mv.visitMethodInsn(INVOKEVIRTUAL, typePath, method,
290: "(" + cg.ci(arg1) + cg.ci(arg2) + BLOCK_ID
291: + ")L" + ret + ";");
292: mv.visitInsn(ARETURN);
293: mv.visitMaxs(4, 3);
294: c = endCall(cw, mv, mname);
295: }
296: InvocationCallback ic = (InvocationCallback) c
297: .newInstance();
298: ic.setArity(Arity.twoArguments());
299: return ic;
300: } catch (IllegalArgumentException e) {
301: throw e;
302: } catch (Exception e) {
303: throw new IllegalArgumentException(e.getMessage());
304: }
305: }
306: }
307:
308: public Callback getMethod(String method, Class arg1, Class arg2,
309: Class arg3) {
310: String mname = type.getName() + "Invoker" + method + "3";
311: String mnamePath = typePath + "Invoker" + method + "3";
312: synchronized (runtime.getJRubyClassLoader()) {
313: Class c = tryClass(mname);
314: try {
315: if (c == null) {
316: String ret = getReturnName(method, new Class[] {
317: arg1, arg2, arg3, Block.class });
318: ClassWriter cw = createCtor(mnamePath);
319: MethodVisitor mv = startCall(cw);
320: mv.visitVarInsn(ALOAD, 2);
321: mv.visitInsn(ICONST_0);
322: mv.visitInsn(AALOAD);
323: mv.visitTypeInsn(CHECKCAST, cg.p(arg1));
324: mv.visitVarInsn(ALOAD, 2);
325: mv.visitInsn(ICONST_1);
326: mv.visitInsn(AALOAD);
327: mv.visitTypeInsn(CHECKCAST, cg.p(arg2));
328: mv.visitVarInsn(ALOAD, 2);
329: mv.visitInsn(ICONST_2);
330: mv.visitInsn(AALOAD);
331: mv.visitTypeInsn(CHECKCAST, cg.p(arg3));
332: mv.visitVarInsn(ALOAD, 3);
333: mv.visitMethodInsn(INVOKEVIRTUAL, typePath, method,
334: "(" + cg.ci(arg1) + cg.ci(arg2)
335: + cg.ci(arg3) + BLOCK_ID + ")L"
336: + ret + ";");
337: mv.visitInsn(ARETURN);
338: mv.visitMaxs(5, 3);
339: c = endCall(cw, mv, mname);
340: }
341: InvocationCallback ic = (InvocationCallback) c
342: .newInstance();
343: ic.setArity(Arity.fixed(3));
344: return ic;
345: } catch (IllegalArgumentException e) {
346: throw e;
347: } catch (Exception e) {
348: throw new IllegalArgumentException(e.getMessage());
349: }
350: }
351: }
352:
353: public Callback getSingletonMethod(String method) {
354: String mname = type.getName() + "InvokerS" + method + "0";
355: String mnamePath = typePath + "InvokerS" + method + "0";
356: synchronized (runtime.getJRubyClassLoader()) {
357: Class c = tryClass(mname);
358: try {
359: if (c == null) {
360: String ret = getReturnName(method, new Class[] {
361: RubyKernel.IRUBY_OBJECT, Block.class });
362: ClassWriter cw = createCtor(mnamePath);
363: MethodVisitor mv = startCallS(cw);
364: mv.visitVarInsn(ALOAD, 3);
365: mv
366: .visitMethodInsn(INVOKESTATIC, typePath,
367: method, "(" + IRUB_ID + BLOCK_ID
368: + ")L" + ret + ";");
369: mv.visitInsn(ARETURN);
370: mv.visitMaxs(1, 3);
371: c = endCall(cw, mv, mname);
372: }
373: InvocationCallback ic = (InvocationCallback) c
374: .newInstance();
375: ic.setArity(Arity.noArguments());
376: return ic;
377: } catch (IllegalArgumentException e) {
378: throw e;
379: } catch (Exception e) {
380: throw new IllegalArgumentException(e.getMessage());
381: }
382: }
383: }
384:
385: public Callback getSingletonMethod(String method, Class arg1) {
386: String mname = type.getName() + "InvokerS" + method + "1";
387: String mnamePath = typePath + "InvokerS" + method + "1";
388: synchronized (runtime.getJRubyClassLoader()) {
389: Class c = tryClass(mname);
390: try {
391: if (c == null) {
392: String ret = getReturnName(method,
393: new Class[] { RubyKernel.IRUBY_OBJECT,
394: arg1, Block.class });
395: ClassWriter cw = createCtor(mnamePath);
396: MethodVisitor mv = startCallS(cw);
397: mv.visitVarInsn(ALOAD, 2);
398: mv.visitInsn(ICONST_0);
399: mv.visitInsn(AALOAD);
400: mv.visitTypeInsn(CHECKCAST, cg.p(arg1));
401: mv.visitVarInsn(ALOAD, 3);
402: mv.visitMethodInsn(INVOKESTATIC, typePath, method,
403: "(" + IRUB_ID + cg.ci(arg1) + BLOCK_ID
404: + ")L" + ret + ";");
405: mv.visitInsn(ARETURN);
406: mv.visitMaxs(3, 3);
407: c = endCall(cw, mv, mname);
408: }
409: InvocationCallback ic = (InvocationCallback) c
410: .newInstance();
411: ic.setArity(Arity.singleArgument());
412: return ic;
413: } catch (IllegalArgumentException e) {
414: throw e;
415: } catch (Exception e) {
416: throw new IllegalArgumentException(e.getMessage());
417: }
418: }
419: }
420:
421: public Callback getSingletonMethod(String method, Class arg1,
422: Class arg2) {
423: String mname = type.getName() + "InvokerS" + method + "2";
424: String mnamePath = typePath + "InvokerS" + method + "2";
425: synchronized (runtime.getJRubyClassLoader()) {
426: Class c = tryClass(mname);
427: try {
428: if (c == null) {
429: String ret = getReturnName(method, new Class[] {
430: RubyKernel.IRUBY_OBJECT, arg1, arg2,
431: Block.class });
432: ClassWriter cw = createCtor(mnamePath);
433: MethodVisitor mv = startCallS(cw);
434: mv.visitVarInsn(ALOAD, 2);
435: mv.visitInsn(ICONST_0);
436: mv.visitInsn(AALOAD);
437: mv.visitTypeInsn(CHECKCAST, cg.p(arg1));
438: mv.visitVarInsn(ALOAD, 2);
439: mv.visitInsn(ICONST_1);
440: mv.visitInsn(AALOAD);
441: mv.visitTypeInsn(CHECKCAST, cg.p(arg2));
442: mv.visitVarInsn(ALOAD, 3);
443: mv.visitMethodInsn(INVOKESTATIC, typePath, method,
444: "(" + IRUB_ID + cg.ci(arg1) + cg.ci(arg2)
445: + BLOCK_ID + ")L" + ret + ";");
446: mv.visitInsn(ARETURN);
447: mv.visitMaxs(4, 4);
448: c = endCall(cw, mv, mname);
449: }
450: InvocationCallback ic = (InvocationCallback) c
451: .newInstance();
452: ic.setArity(Arity.twoArguments());
453: return ic;
454: } catch (IllegalArgumentException e) {
455: throw e;
456: } catch (Exception e) {
457: throw new IllegalArgumentException(e.getMessage());
458: }
459: }
460: }
461:
462: public Callback getSingletonMethod(String method, Class arg1,
463: Class arg2, Class arg3) {
464: String mname = type.getName() + "InvokerS" + method + "3";
465: String mnamePath = typePath + "InvokerS" + method + "3";
466: synchronized (runtime.getJRubyClassLoader()) {
467: Class c = tryClass(mname);
468: try {
469: if (c == null) {
470: String ret = getReturnName(method, new Class[] {
471: RubyKernel.IRUBY_OBJECT, arg1, arg2, arg3,
472: Block.class });
473: ClassWriter cw = createCtor(mnamePath);
474: MethodVisitor mv = startCallS(cw);
475: mv.visitVarInsn(ALOAD, 2);
476: mv.visitInsn(ICONST_0);
477: mv.visitInsn(AALOAD);
478: mv.visitTypeInsn(CHECKCAST, cg.p(arg1));
479: mv.visitVarInsn(ALOAD, 2);
480: mv.visitInsn(ICONST_1);
481: mv.visitInsn(AALOAD);
482: mv.visitTypeInsn(CHECKCAST, cg.p(arg2));
483: mv.visitVarInsn(ALOAD, 2);
484: mv.visitInsn(ICONST_2);
485: mv.visitInsn(AALOAD);
486: mv.visitTypeInsn(CHECKCAST, cg.p(arg3));
487: mv.visitVarInsn(ALOAD, 3);
488: mv.visitMethodInsn(INVOKESTATIC, typePath, method,
489: "(" + IRUB_ID + cg.ci(arg1) + cg.ci(arg2)
490: + cg.ci(arg3) + BLOCK_ID + ")L"
491: + ret + ";");
492: mv.visitInsn(ARETURN);
493: mv.visitMaxs(5, 3);
494: c = endCall(cw, mv, mname);
495: }
496: InvocationCallback ic = (InvocationCallback) c
497: .newInstance();
498: ic.setArity(Arity.fixed(3));
499: return ic;
500: } catch (IllegalArgumentException e) {
501: throw e;
502: } catch (Exception e) {
503: throw new IllegalArgumentException(e.getMessage());
504: }
505: }
506: }
507:
508: public Callback getBlockMethod(String method) {
509: // TODO: This is probably BAD...
510: return new ReflectionCallback(type, method, new Class[] {
511: RubyKernel.IRUBY_OBJECT, RubyKernel.IRUBY_OBJECT },
512: false, true, Arity.fixed(2), false);
513: }
514:
515: public CompiledBlockCallback getBlockCallback(String method) {
516: String mname = type.getName() + "Block" + method + "xx1";
517: String mnamePath = typePath + "Block" + method + "xx1";
518: synchronized (classLoader) {
519: Class c = tryClass(mname);
520: try {
521: if (c == null) {
522: ClassWriter cw = createBlockCtor(mnamePath);
523: MethodVisitor mv = startBlockCall(cw);
524: mv.visitVarInsn(ALOAD, 1);
525: mv.visitVarInsn(ALOAD, 2);
526: mv.visitVarInsn(ALOAD, 3);
527: mv.visitMethodInsn(INVOKESTATIC, typePath, method,
528: cg.sig(RubyKernel.IRUBY_OBJECT, cg.params(
529: ThreadContext.class,
530: RubyKernel.IRUBY_OBJECT,
531: IRubyObject[].class)));
532: mv.visitInsn(ARETURN);
533: mv.visitMaxs(2, 3);
534: c = endCall(cw, mv, mname);
535: }
536: CompiledBlockCallback ic = (CompiledBlockCallback) c
537: .newInstance();
538: return ic;
539: } catch (IllegalArgumentException e) {
540: throw e;
541: } catch (Exception e) {
542: throw new IllegalArgumentException(e.getMessage());
543: }
544: }
545: }
546:
547: public Callback getOptSingletonMethod(String method) {
548: String mname = type.getName() + "InvokerS" + method + "xx1";
549: String mnamePath = typePath + "InvokerS" + method + "xx1";
550: synchronized (runtime.getJRubyClassLoader()) {
551: Class c = tryClass(mname);
552: try {
553: if (c == null) {
554: String ret = getReturnName(method, new Class[] {
555: RubyKernel.IRUBY_OBJECT,
556: IRubyObject[].class, Block.class });
557: ClassWriter cw = createCtor(mnamePath);
558: MethodVisitor mv = startCallS(cw);
559: mv.visitVarInsn(ALOAD, 2);
560: mv.visitTypeInsn(CHECKCAST, "[" + IRUB_ID);
561: mv.visitTypeInsn(CHECKCAST, "[" + IRUB_ID);
562: mv.visitVarInsn(ALOAD, 3);
563: mv.visitMethodInsn(INVOKESTATIC, typePath, method,
564: "(" + IRUB_ID + "[" + IRUB_ID + BLOCK_ID
565: + ")L" + ret + ";");
566: mv.visitInsn(ARETURN);
567: mv.visitMaxs(2, 3);
568: c = endCall(cw, mv, mname);
569: }
570: InvocationCallback ic = (InvocationCallback) c
571: .newInstance();
572: ic.setArity(Arity.optional());
573: return ic;
574: } catch (IllegalArgumentException e) {
575: throw e;
576: } catch (Exception e) {
577: throw new IllegalArgumentException(e.getMessage());
578: }
579: }
580: }
581:
582: public Callback getOptMethod(String method) {
583: String mname = type.getName() + "Invoker" + method + "xx1";
584: String mnamePath = typePath + "Invoker" + method + "xx1";
585: synchronized (runtime.getJRubyClassLoader()) {
586: Class c = tryClass(mname);
587: try {
588: if (c == null) {
589: String ret = getReturnName(method, new Class[] {
590: IRubyObject[].class, Block.class });
591: ClassWriter cw = createCtor(mnamePath);
592: MethodVisitor mv = startCall(cw);
593: mv.visitVarInsn(ALOAD, 2);
594: mv.visitTypeInsn(CHECKCAST, "[" + IRUB_ID);
595: mv.visitTypeInsn(CHECKCAST, "[" + IRUB_ID);
596: mv.visitVarInsn(ALOAD, 3);
597: mv.visitMethodInsn(INVOKEVIRTUAL, typePath, method,
598: "([" + IRUB_ID + BLOCK_ID + ")L" + ret
599: + ";");
600: mv.visitInsn(ARETURN);
601: mv.visitMaxs(2, 3);
602: c = endCall(cw, mv, mname);
603: }
604: InvocationCallback ic = (InvocationCallback) c
605: .newInstance();
606: ic.setArity(Arity.optional());
607: return ic;
608: } catch (IllegalArgumentException e) {
609: throw e;
610: } catch (Exception e) {
611: throw new IllegalArgumentException(e.getMessage());
612: }
613: }
614: }
615:
616: public Callback getFastMethod(String method) {
617: String mname = type.getName() + "Invoker" + method + "0";
618: String mnamePath = typePath + "Invoker" + method + "0";
619: synchronized (runtime.getJRubyClassLoader()) {
620: Class c = tryClass(mname);
621: try {
622: if (c == null) {
623: String ret = getReturnName(method, null);
624: ClassWriter cw = createCtorFast(mnamePath);
625: MethodVisitor mv = startCallFast(cw);
626: mv.visitMethodInsn(INVOKEVIRTUAL, typePath, method,
627: "()L" + ret + ";");
628: mv.visitInsn(ARETURN);
629: mv.visitMaxs(1, 3);
630: c = endCall(cw, mv, mname);
631: }
632: FastInvocationCallback ic = (FastInvocationCallback) c
633: .newInstance();
634: ic.setArity(Arity.noArguments());
635: return ic;
636: } catch (IllegalArgumentException e) {
637: throw e;
638: } catch (Exception e) {
639: throw new IllegalArgumentException(e.getMessage());
640: }
641: }
642: }
643:
644: public Callback getFastMethod(String method, Class arg1) {
645: String mname = type.getName() + "Invoker" + method + "1";
646: String mnamePath = typePath + "Invoker" + method + "1";
647: synchronized (runtime.getJRubyClassLoader()) {
648: Class c = tryClass(mname);
649: try {
650: if (c == null) {
651: String ret = getReturnName(method,
652: new Class[] { arg1 });
653: ClassWriter cw = createCtorFast(mnamePath);
654: MethodVisitor mv = startCallFast(cw);
655: mv.visitVarInsn(ALOAD, 2);
656: mv.visitInsn(ICONST_0);
657: mv.visitInsn(AALOAD);
658: mv.visitTypeInsn(CHECKCAST, cg.p(arg1));
659: mv.visitMethodInsn(INVOKEVIRTUAL, typePath, method,
660: "(" + cg.ci(arg1) + ")L" + ret + ";");
661: mv.visitInsn(ARETURN);
662: mv.visitMaxs(3, 3);
663: c = endCall(cw, mv, mname);
664: }
665: FastInvocationCallback ic = (FastInvocationCallback) c
666: .newInstance();
667: ic.setArity(Arity.singleArgument());
668: return ic;
669: } catch (IllegalArgumentException e) {
670: throw e;
671: } catch (Exception e) {
672: throw new IllegalArgumentException(e.getMessage());
673: }
674: }
675: }
676:
677: public Callback getFastMethod(String method, Class arg1, Class arg2) {
678: String mname = type.getName() + "Invoker" + method + "2";
679: String mnamePath = typePath + "Invoker" + method + "2";
680: synchronized (runtime.getJRubyClassLoader()) {
681: Class c = tryClass(mname);
682: try {
683: if (c == null) {
684: String ret = getReturnName(method, new Class[] {
685: arg1, arg2 });
686: ClassWriter cw = createCtorFast(mnamePath);
687: MethodVisitor mv = startCallFast(cw);
688: mv.visitVarInsn(ALOAD, 2);
689: mv.visitInsn(ICONST_0);
690: mv.visitInsn(AALOAD);
691: mv.visitTypeInsn(CHECKCAST, cg.p(arg1));
692: mv.visitVarInsn(ALOAD, 2);
693: mv.visitInsn(ICONST_1);
694: mv.visitInsn(AALOAD);
695: mv.visitTypeInsn(CHECKCAST, cg.p(arg2));
696: mv.visitMethodInsn(INVOKEVIRTUAL, typePath, method,
697: "(" + cg.ci(arg1) + cg.ci(arg2) + ")L"
698: + ret + ";");
699: mv.visitInsn(ARETURN);
700: mv.visitMaxs(4, 3);
701: c = endCall(cw, mv, mname);
702: }
703: FastInvocationCallback ic = (FastInvocationCallback) c
704: .newInstance();
705: ic.setArity(Arity.twoArguments());
706: return ic;
707: } catch (IllegalArgumentException e) {
708: throw e;
709: } catch (Exception e) {
710: throw new IllegalArgumentException(e.getMessage());
711: }
712: }
713: }
714:
715: public Callback getFastMethod(String method, Class arg1,
716: Class arg2, Class arg3) {
717: String mname = type.getName() + "Invoker" + method + "3";
718: String mnamePath = typePath + "Invoker" + method + "3";
719: synchronized (runtime.getJRubyClassLoader()) {
720: Class c = tryClass(mname);
721: try {
722: if (c == null) {
723: String ret = getReturnName(method, new Class[] {
724: arg1, arg2, arg3 });
725: ClassWriter cw = createCtorFast(mnamePath);
726: MethodVisitor mv = startCallFast(cw);
727: mv.visitVarInsn(ALOAD, 2);
728: mv.visitInsn(ICONST_0);
729: mv.visitInsn(AALOAD);
730: mv.visitTypeInsn(CHECKCAST, cg.p(arg1));
731: mv.visitVarInsn(ALOAD, 2);
732: mv.visitInsn(ICONST_1);
733: mv.visitInsn(AALOAD);
734: mv.visitTypeInsn(CHECKCAST, cg.p(arg2));
735: mv.visitVarInsn(ALOAD, 2);
736: mv.visitInsn(ICONST_2);
737: mv.visitInsn(AALOAD);
738: mv.visitTypeInsn(CHECKCAST, cg.p(arg3));
739: mv.visitMethodInsn(INVOKEVIRTUAL, typePath, method,
740: "(" + cg.ci(arg1) + cg.ci(arg2)
741: + cg.ci(arg3) + ")L" + ret + ";");
742: mv.visitInsn(ARETURN);
743: mv.visitMaxs(5, 3);
744: c = endCall(cw, mv, mname);
745: }
746: FastInvocationCallback ic = (FastInvocationCallback) c
747: .newInstance();
748: ic.setArity(Arity.fixed(3));
749: return ic;
750: } catch (IllegalArgumentException e) {
751: throw e;
752: } catch (Exception e) {
753: throw new IllegalArgumentException(e.getMessage());
754: }
755: }
756: }
757:
758: public Callback getFastSingletonMethod(String method) {
759: String mname = type.getName() + "InvokerS" + method + "0";
760: String mnamePath = typePath + "InvokerS" + method + "0";
761: synchronized (runtime.getJRubyClassLoader()) {
762: Class c = tryClass(mname);
763: try {
764: if (c == null) {
765: String ret = getReturnName(method,
766: new Class[] { RubyKernel.IRUBY_OBJECT });
767: ClassWriter cw = createCtorFast(mnamePath);
768: MethodVisitor mv = startCallSFast(cw);
769: mv.visitMethodInsn(INVOKESTATIC, typePath, method,
770: "(" + IRUB_ID + ")L" + ret + ";");
771: mv.visitInsn(ARETURN);
772: mv.visitMaxs(1, 3);
773: c = endCall(cw, mv, mname);
774: }
775: FastInvocationCallback ic = (FastInvocationCallback) c
776: .newInstance();
777: ic.setArity(Arity.noArguments());
778: return ic;
779: } catch (IllegalArgumentException e) {
780: throw e;
781: } catch (Exception e) {
782: throw new IllegalArgumentException(e.getMessage());
783: }
784: }
785: }
786:
787: public Callback getFastSingletonMethod(String method, Class arg1) {
788: String mname = type.getName() + "InvokerS" + method + "1";
789: String mnamePath = typePath + "InvokerS" + method + "1";
790: synchronized (runtime.getJRubyClassLoader()) {
791: Class c = tryClass(mname);
792: try {
793: if (c == null) {
794: String ret = getReturnName(method, new Class[] {
795: RubyKernel.IRUBY_OBJECT, arg1 });
796: ClassWriter cw = createCtorFast(mnamePath);
797: MethodVisitor mv = startCallSFast(cw);
798: mv.visitVarInsn(ALOAD, 2);
799: mv.visitInsn(ICONST_0);
800: mv.visitInsn(AALOAD);
801: mv.visitTypeInsn(CHECKCAST, cg.p(arg1));
802: mv.visitMethodInsn(INVOKESTATIC, typePath, method,
803: "(" + IRUB_ID + cg.ci(arg1) + ")L" + ret
804: + ";");
805: mv.visitInsn(ARETURN);
806: mv.visitMaxs(3, 3);
807: c = endCall(cw, mv, mname);
808: }
809: FastInvocationCallback ic = (FastInvocationCallback) c
810: .newInstance();
811: ic.setArity(Arity.singleArgument());
812: return ic;
813: } catch (IllegalArgumentException e) {
814: throw e;
815: } catch (Exception e) {
816: throw new IllegalArgumentException(e.getMessage());
817: }
818: }
819: }
820:
821: public Callback getFastSingletonMethod(String method, Class arg1,
822: Class arg2) {
823: String mname = type.getName() + "InvokerS" + method + "2";
824: String mnamePath = typePath + "InvokerS" + method + "2";
825: synchronized (runtime.getJRubyClassLoader()) {
826: Class c = tryClass(mname);
827: try {
828: if (c == null) {
829: String ret = getReturnName(method, new Class[] {
830: RubyKernel.IRUBY_OBJECT, arg1, arg2 });
831: ClassWriter cw = createCtorFast(mnamePath);
832: MethodVisitor mv = startCallSFast(cw);
833: mv.visitVarInsn(ALOAD, 2);
834: mv.visitInsn(ICONST_0);
835: mv.visitInsn(AALOAD);
836: mv.visitTypeInsn(CHECKCAST, cg.p(arg1));
837: mv.visitVarInsn(ALOAD, 2);
838: mv.visitInsn(ICONST_1);
839: mv.visitInsn(AALOAD);
840: mv.visitTypeInsn(CHECKCAST, cg.p(arg2));
841: mv.visitMethodInsn(INVOKESTATIC, typePath, method,
842: "(" + IRUB_ID + cg.ci(arg1) + cg.ci(arg2)
843: + ")L" + ret + ";");
844: mv.visitInsn(ARETURN);
845: mv.visitMaxs(4, 4);
846: c = endCall(cw, mv, mname);
847: }
848: FastInvocationCallback ic = (FastInvocationCallback) c
849: .newInstance();
850: ic.setArity(Arity.twoArguments());
851: return ic;
852: } catch (IllegalArgumentException e) {
853: throw e;
854: } catch (Exception e) {
855: throw new IllegalArgumentException(e.getMessage());
856: }
857: }
858: }
859:
860: public Callback getFastSingletonMethod(String method, Class arg1,
861: Class arg2, Class arg3) {
862: String mname = type.getName() + "InvokerS" + method + "3";
863: String mnamePath = typePath + "InvokerS" + method + "3";
864: synchronized (runtime.getJRubyClassLoader()) {
865: Class c = tryClass(mname);
866: try {
867: if (c == null) {
868: String ret = getReturnName(method, new Class[] {
869: RubyKernel.IRUBY_OBJECT, arg1, arg2, arg3 });
870: ClassWriter cw = createCtorFast(mnamePath);
871: MethodVisitor mv = startCallSFast(cw);
872: mv.visitVarInsn(ALOAD, 2);
873: mv.visitInsn(ICONST_0);
874: mv.visitInsn(AALOAD);
875: mv.visitTypeInsn(CHECKCAST, cg.p(arg1));
876: mv.visitVarInsn(ALOAD, 2);
877: mv.visitInsn(ICONST_1);
878: mv.visitInsn(AALOAD);
879: mv.visitTypeInsn(CHECKCAST, cg.p(arg2));
880: mv.visitVarInsn(ALOAD, 2);
881: mv.visitInsn(ICONST_2);
882: mv.visitInsn(AALOAD);
883: mv.visitTypeInsn(CHECKCAST, cg.p(arg3));
884: mv.visitMethodInsn(INVOKESTATIC, typePath, method,
885: "(" + IRUB_ID + cg.ci(arg1) + cg.ci(arg2)
886: + cg.ci(arg3) + ")L" + ret + ";");
887: mv.visitInsn(ARETURN);
888: mv.visitMaxs(5, 3);
889: c = endCall(cw, mv, mname);
890: }
891: FastInvocationCallback ic = (FastInvocationCallback) c
892: .newInstance();
893: ic.setArity(Arity.fixed(3));
894: return ic;
895: } catch (IllegalArgumentException e) {
896: throw e;
897: } catch (Exception e) {
898: throw new IllegalArgumentException(e.getMessage());
899: }
900: }
901: }
902:
903: public Callback getFastOptMethod(String method) {
904: String mname = type.getName() + "Invoker" + method + "xx1";
905: String mnamePath = typePath + "Invoker" + method + "xx1";
906: synchronized (runtime.getJRubyClassLoader()) {
907: Class c = tryClass(mname);
908: try {
909: if (c == null) {
910: String ret = getReturnName(method,
911: new Class[] { IRubyObject[].class });
912: ClassWriter cw = createCtorFast(mnamePath);
913: MethodVisitor mv = startCallFast(cw);
914: mv.visitVarInsn(ALOAD, 2);
915: mv.visitTypeInsn(CHECKCAST, "[" + IRUB_ID);
916: mv.visitTypeInsn(CHECKCAST, "[" + IRUB_ID);
917: mv.visitMethodInsn(INVOKEVIRTUAL, typePath, method,
918: "([" + IRUB_ID + ")L" + ret + ";");
919: mv.visitInsn(ARETURN);
920: mv.visitMaxs(2, 3);
921: c = endCall(cw, mv, mname);
922: }
923: FastInvocationCallback ic = (FastInvocationCallback) c
924: .newInstance();
925: ic.setArity(Arity.optional());
926: return ic;
927: } catch (IllegalArgumentException e) {
928: throw e;
929: } catch (Exception e) {
930: throw new IllegalArgumentException(e.getMessage());
931: }
932: }
933: }
934:
935: public Callback getFastOptSingletonMethod(String method) {
936: String mname = type.getName() + "InvokerS" + method + "xx1";
937: String mnamePath = typePath + "InvokerS" + method + "xx1";
938: synchronized (runtime.getJRubyClassLoader()) {
939: Class c = tryClass(mname);
940: try {
941: if (c == null) {
942: String ret = getReturnName(method, new Class[] {
943: RubyKernel.IRUBY_OBJECT,
944: IRubyObject[].class });
945: ClassWriter cw = createCtorFast(mnamePath);
946: MethodVisitor mv = startCallSFast(cw);
947: mv.visitVarInsn(ALOAD, 2);
948: mv.visitTypeInsn(CHECKCAST, "[" + IRUB_ID);
949: mv.visitTypeInsn(CHECKCAST, "[" + IRUB_ID);
950: mv.visitMethodInsn(INVOKESTATIC, typePath, method,
951: "(" + IRUB_ID + "[" + IRUB_ID + ")L" + ret
952: + ";");
953: mv.visitInsn(ARETURN);
954: mv.visitMaxs(2, 3);
955: c = endCall(cw, mv, mname);
956: }
957: FastInvocationCallback ic = (FastInvocationCallback) c
958: .newInstance();
959: ic.setArity(Arity.optional());
960: return ic;
961: } catch (IllegalArgumentException e) {
962: throw e;
963: } catch (Exception e) {
964: throw new IllegalArgumentException(e.getMessage());
965: }
966: }
967: }
968: } //InvocationCallbackFactory
|