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