001: /*
002: * ClassGenerator.java
003: *
004: * Copyright (c) 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * See the file "LICENSE.txt" for information on usage and redistribution
007: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
008: */
009: package pnuts.compiler;
010:
011: import java.lang.reflect.Constructor;
012: import java.lang.reflect.Method;
013: import java.lang.reflect.Modifier;
014: import java.util.ArrayList;
015: import java.util.HashSet;
016: import java.util.Iterator;
017: import java.util.List;
018: import java.util.Set;
019: import org.pnuts.lang.ObjectDescFactory;
020: import org.pnuts.lang.PropertyHandler;
021: import org.pnuts.lang.ReflectionUtil;
022: import org.pnuts.lang.Signature;
023: import pnuts.lang.AbstractData;
024: import pnuts.lang.Context;
025: import pnuts.lang.PnutsParserTreeConstants;
026: import pnuts.lang.SimpleNode;
027: import pnuts.lang.Runtime;
028:
029: public class ClassGenerator {
030: public final static int THIS_BIT = 0x0001;
031: public final static int SUPER_BIT = 0x0002;
032: final static String SUPER_PROXY_NAME = "pnuts.compiler.ClassGenerator$SuperCallProxy";
033:
034: public static ClassFile createClassFile(String className,
035: Class super Class, Class[] interfaceTypes,
036: Set super MethodNames) {
037: ClassSpec[] interfaces = new ClassSpec[interfaceTypes.length];
038: for (int i = 0; i < interfaces.length; i++) {
039: interfaces[i] = ClassSpec.create(interfaceTypes[i]);
040: }
041: return createClassFile(className, ClassSpec.create(super Class),
042: interfaces, super MethodNames);
043: }
044:
045: public static ClassFile createClassFile(String className,
046: ClassSpec super classSpec, ClassSpec[] interfaces,
047: Set super MethodNames) {
048: Class super Class = super classSpec.compileTimeClass;
049: if (super Class == null) {
050: super Class = Object.class;
051: }
052: ClassFile cf = new ClassFile(className,
053: super classSpec.className, null, Constants.ACC_PUBLIC);
054: if (interfaces != null) {
055: for (int i = 0; i < interfaces.length; i++) {
056: cf.addInterface(interfaces[i].className);
057: }
058: }
059: cf.addField("_context", "Lpnuts/lang/Context;",
060: (short) (Constants.ACC_PRIVATE | Constants.ACC_STATIC));
061:
062: super Call(cf, super Class, super MethodNames);
063:
064: return cf;
065:
066: }
067:
068: public static void constructor(ClassFile cf,
069: ClassSpec super classSpec, Compiler compiler,
070: CompileContext cc, List/*<Signature>*/signatures) {
071: String super className = super classSpec.className;
072: Class super Class = super classSpec.compileTimeClass;
073: Set/*<Constructor>*/protected_constructors = new HashSet();
074: if (super Class == null) {
075: super Class = Object.class;
076: }
077:
078: getProtectedConstructors(super Class, new HashSet(),
079: protected_constructors);
080: Constructor[] public_constructors = super Class
081: .getConstructors();
082:
083: Set/*<Signature>*/generated_constructors = new HashSet();
084: int num_constructors = 0;
085: ;
086:
087: for (int i = 0, n = signatures.size(); i < n; i++) {
088: Signature sig = (Signature) signatures.get(i);
089: // SimpleNode fnode = (SimpleNode)sig.nodeInfo;
090:
091: int modifiers = sig.getModifiers();
092: Class[] parameterTypes;
093: Class[] exceptionTypes;
094:
095: List constructors = new ArrayList();
096: if (sig.resolveAsConstructor(super Class, constructors)) {
097: for (int j = 0, n2 = constructors.size(); j < n2; j++) {
098: Constructor cons = (Constructor) constructors
099: .get(j);
100: parameterTypes = cons.getParameterTypes();
101: exceptionTypes = cons.getExceptionTypes();
102: constructor(cf, cc, compiler, super classSpec,
103: parameterTypes, exceptionTypes,
104: Constants.ACC_PUBLIC);
105: generated_constructors
106: .add(new Signature(null, void.class,
107: parameterTypes, exceptionTypes));
108: num_constructors++;
109: }
110: } else {
111: parameterTypes = sig.getParameterTypes();
112: exceptionTypes = sig.getExceptionTypes();
113: constructor(cf, cc, compiler, super classSpec,
114: parameterTypes, exceptionTypes,
115: Constants.ACC_PUBLIC);
116: generated_constructors.add(new Signature(null,
117: void.class, parameterTypes, exceptionTypes));
118: num_constructors++;
119:
120: }
121: }
122: for (int i = 0; i < public_constructors.length; i++) {
123: Constructor cons = public_constructors[i];
124: Class[] parameterTypes = cons.getParameterTypes();
125: Class[] exceptionTypes = cons.getExceptionTypes();
126: Signature sig = new Signature(null, void.class,
127: parameterTypes, exceptionTypes);
128: if (!generated_constructors.contains(sig)) {
129: derivedConstructors(cf, cc, compiler, super Class,
130: super className, parameterTypes, exceptionTypes,
131: Constants.ACC_PUBLIC);
132: num_constructors++;
133: }
134: }
135: if (num_constructors == 0) {
136: cf.openMethod("<init>", "()V", Constants.ACC_PUBLIC);
137: cf.add(Opcode.ALOAD_0);
138: cf.add(Opcode.INVOKESPECIAL, super className, "<init>",
139: "()", "V");
140: cf.add(Opcode.ALOAD_0);
141: cf.add(Opcode.INVOKEVIRTUAL, cf.getClassName(),
142: "__initialize", "()", "V");
143:
144: cf.add(Opcode.RETURN);
145: cf.closeMethod();
146: generated_constructors.add(new Signature(null, void.class,
147: new Class[0], new Class[0]));
148: }
149: for (Iterator it = protected_constructors.iterator(); it
150: .hasNext();) {
151: Constructor cons = (Constructor) it.next();
152: Class[] parameterTypes = cons.getParameterTypes();
153: Class[] exceptionTypes = cons.getExceptionTypes();
154: Signature sig = new Signature(null, void.class,
155: parameterTypes, exceptionTypes);
156: if (!generated_constructors.contains(sig)) {
157: derivedConstructors(cf, cc, compiler, super Class,
158: super className, parameterTypes, exceptionTypes,
159: Constants.ACC_PROTECTED);
160: }
161: }
162: }
163:
164: /*
165: * derived constructors that just calls super(...)
166: */
167: static void derivedConstructors(ClassFile cf, CompileContext cc,
168: Compiler compiler, Class super Class, String super className,
169: Class[] parameterTypes, Class[] exceptionTypes,
170: short modifier) {
171: String sig = ClassFile.signature(parameterTypes);
172:
173: String[] exceptionTypeInfo = null;
174: if (exceptionTypes != null && exceptionTypes.length > 0) {
175: exceptionTypeInfo = new String[exceptionTypes.length];
176: for (int j = 0; j < exceptionTypes.length; j++) {
177: exceptionTypeInfo[j] = exceptionTypes[j].getName();
178: }
179: }
180: cf.openMethod("<init>", sig + "V", modifier, exceptionTypeInfo);
181: cf.add(Opcode.ALOAD_0);
182: int pos = 1;
183: for (int i = 0; i < parameterTypes.length; i++) {
184: Class type = parameterTypes[i];
185: if (type.isPrimitive()) {
186: if (type == long.class) {
187: cf.lloadLocal(pos);
188: pos += 2;
189: } else if (type == double.class) {
190: cf.dloadLocal(pos);
191: pos += 2;
192: } else if (type == float.class) {
193: cf.floadLocal(pos++);
194: } else if (type == int.class || type == byte.class
195: || type == short.class || type == char.class
196: || type == boolean.class) {
197: cf.iloadLocal(pos++);
198: }
199: } else {
200: cf.loadLocal(pos++);
201: }
202: }
203: cf
204: .add(Opcode.INVOKESPECIAL, super className, "<init>",
205: sig, "V");
206:
207: /*
208: * __initialize(this);
209: */
210: cf.add(Opcode.ALOAD_0);
211: cf.add(Opcode.INVOKEVIRTUAL, cf.getClassName(), "__initialize",
212: "()", "V");
213:
214: cf.add(Opcode.RETURN);
215: cf.closeMethod();
216: }
217:
218: /*
219: * user defined constructors
220: */
221: static void constructor(ClassFile cf, Context cc,
222: Compiler compiler, ClassSpec super classSpec,
223: Class[] parameterTypes, Class[] exceptionTypes,
224: short modifier) {
225: String className = cf.getClassName();
226: for (int i = 0; i < parameterTypes.length; i++) {
227: if (parameterTypes[i] == null) {
228: parameterTypes[i] = Object.class;
229: }
230: }
231: String sig = ClassFile.signature(parameterTypes);
232: String methodID = Signature.toJavaIdentifier(sig);
233:
234: String[] exceptionTypeInfo = null;
235: if (exceptionTypes != null && exceptionTypes.length > 0) {
236: exceptionTypeInfo = new String[exceptionTypes.length];
237: for (int j = 0; j < exceptionTypes.length; j++) {
238: exceptionTypeInfo[j] = exceptionTypes[j].getName();
239: }
240: }
241:
242: cf.openMethod("<init>", sig + "V", modifier, exceptionTypeInfo);
243:
244: cf.add(Opcode.ALOAD_0);
245: cf.add(Opcode.INVOKESPECIAL, super classSpec.className,
246: "<init>", "()", "V");
247:
248: cf.add(Opcode.ALOAD_0);
249: cf.add(Opcode.INVOKEVIRTUAL, cf.getClassName(), "__initialize",
250: "()", "V");
251:
252: cf.add(Opcode.ALOAD_0);
253: cf.add(Opcode.GETFIELD, className, methodID,
254: "Lpnuts/lang/PnutsFunction;");
255: int f = cf.getLocal();
256:
257: cf.storeLocal(f);
258: cf.loadLocal(f);
259: Label nonnull = cf.getLabel();
260: cf.add(Opcode.IFNONNULL, nonnull);
261: cf.add(Opcode.RETURN);
262:
263: nonnull.fix();
264: cf.loadLocal(f);
265: cf.add(Opcode.CHECKCAST, "pnuts.lang.PnutsFunction");
266:
267: int nargs = parameterTypes.length;
268: if (nargs <= -0x8000 || nargs >= 0x8000) {
269: throw new RuntimeException("too many parameters");
270: }
271:
272: Label catchStart = cf.getLabel(true);
273:
274: int k = 0;
275:
276: cf.pushInteger(nargs);
277: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
278:
279: for (int j = 0; j < nargs; j++) {
280: cf.add(Opcode.DUP);
281: cf.pushInteger(j + k);
282: Class paramType = parameterTypes[j];
283: if (paramType != null && paramType.isPrimitive()) {
284: loadPrimitive(cf, paramType, j + 1);
285: if (paramType.equals(long.class)
286: || paramType.equals(double.class)) {
287: j++;
288: }
289: } else {
290: cf.loadLocal(j + 1);
291: }
292: cf.add(Opcode.AASTORE);
293: }
294: k = 0;
295:
296: cf.add(Opcode.GETSTATIC, className, "_context",
297: "Lpnuts/lang/Context;");
298: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.PnutsFunction",
299: "call", "([Ljava/lang/Object;Lpnuts/lang/Context;)",
300: "Ljava/lang/Object;");
301:
302: cf.add(Opcode.POP);
303: cf.add(Opcode.RETURN);
304:
305: Label catchEnd = cf.getLabel(true);
306: Label catchTarget = cf.getLabel(true);
307: cf.reserveStack(1);
308: int pex = cf.getLocal();
309: cf.storeLocal(pex);
310:
311: cf.loadLocal(pex);
312: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.PnutsException",
313: "getThrowable", "()", "Ljava/lang/Throwable;");
314: int ex = cf.getLocal();
315: cf.storeLocal(ex);
316: Label next;
317: if (exceptionTypeInfo != null) {
318: for (int i = 0; i < exceptionTypeInfo.length; i++) {
319: next = cf.getLabel();
320: cf.loadLocal(ex);
321: cf.add(Opcode.INSTANCEOF, exceptionTypeInfo[i]);
322: cf.add(Opcode.IFEQ, next);
323: cf.loadLocal(ex);
324: cf.add(Opcode.ATHROW);
325: next.fix();
326: }
327: }
328:
329: cf.loadLocal(pex);
330: cf.add(Opcode.ATHROW);
331: cf.addExceptionHandler(catchStart, catchEnd, catchTarget,
332: "pnuts.lang.PnutsException");
333: cf.closeMethod();
334: }
335:
336: /*
337: * this._superCallProxy = new SuperCallProxy(this);
338: */
339: static void assignSuperCallProxy(ClassFile cf, String className) {
340: cf.add(Opcode.ALOAD_0);
341: cf.add(Opcode.NEW, SUPER_PROXY_NAME);
342: cf.add(Opcode.DUP);
343: cf.add(Opcode.ALOAD_0);
344: cf.add(Opcode.INVOKESPECIAL, SUPER_PROXY_NAME, "<init>",
345: "(Ljava/lang/Object;)", "V");
346: cf.add(Opcode.PUTFIELD, className, "_superCallProxy",
347: "Lpnuts/lang/AbstractData;");
348: }
349:
350: /*
351: * private AbstractData _superCallProxy;
352: *
353: * public <Type> $super$<MethodName>(...){ super. <MethodName>(...); } ...
354: */
355: private static void super Call(ClassFile cf, Class super Class,
356: Set super MethodNames) {
357: Method[] methods = ReflectionUtil
358: .getInheritableMethods(super Class);
359: for (int i = 0; i < methods.length; i++) {
360: Method m = methods[i];
361:
362: int modifiers = m.getModifiers();
363: if (!Modifier.isStatic(modifiers)
364: && !Modifier.isFinal(modifiers)
365: && (Modifier.isPublic(modifiers) || Modifier
366: .isProtected(modifiers))) {
367: String methodName = m.getName();
368: if (super MethodNames != null
369: && !super MethodNames.contains(methodName)) {
370: continue;
371: }
372: Class[] parameterTypes = m.getParameterTypes();
373: Class returnType = m.getReturnType();
374:
375: cf.openMethod("$super$" + methodName, ClassFile
376: .signature(parameterTypes)
377: + ClassFile.signature(returnType),
378: Constants.ACC_PUBLIC);
379: cf.add(Opcode.ALOAD_0);
380: int nparams = parameterTypes.length;
381: for (int j = 0, k = 0; j < nparams; j++) {
382: Class type = parameterTypes[j];
383: if (type.isPrimitive()) {
384: if (type == int.class || type == byte.class
385: || type == short.class
386: || type == boolean.class
387: || type == char.class) {
388: cf.iloadLocal(j + k + 1);
389: } else if (type == long.class) {
390: cf.lloadLocal(j + k + 1);
391: k++;
392: } else if (type == float.class) {
393: cf.floadLocal(j + k + 1);
394: } else if (type == double.class) {
395: cf.dloadLocal(j + k + 1);
396: k++;
397: }
398: } else {
399: cf.loadLocal(j + k + 1);
400: }
401: }
402:
403: cf.add(Opcode.INVOKESPECIAL, m.getDeclaringClass()
404: .getName(), methodName, ClassFile
405: .signature(parameterTypes), ClassFile
406: .signature(returnType));
407: if (returnType.isPrimitive()) {
408: if (returnType == int.class
409: || returnType == byte.class
410: || returnType == short.class
411: || returnType == boolean.class
412: || returnType == char.class) {
413: cf.add(Opcode.IRETURN);
414: } else if (returnType == long.class) {
415: cf.add(Opcode.LRETURN);
416: } else if (returnType == float.class) {
417: cf.add(Opcode.FRETURN);
418: } else if (returnType == double.class) {
419: cf.add(Opcode.DRETURN);
420: } else if (returnType == Void.TYPE) {
421: cf.add(Opcode.RETURN);
422: }
423: } else {
424: cf.add(Opcode.ARETURN);
425: }
426: cf.closeMethod();
427: }
428: }
429: }
430:
431: private static void getImplicitInterfaces(Class cls, List list) {
432: Class[] interfaces = cls.getInterfaces();
433: for (int i = 0; i < interfaces.length; i++) {
434: list.add(interfaces[i]);
435: }
436: }
437:
438: static Constructor[] getProtectedConstructors(Class cls) {
439: Set/*<Signature>*/s = new HashSet(); // signatures
440: Set/*<Constructor>*/cons = new HashSet(); // constructors
441: Class c = cls;
442: while (c != null) {
443: getProtectedConstructors(c, s, cons);
444: c = c.getSuperclass();
445: }
446: return (Constructor[]) cons
447: .toArray(new Constructor[cons.size()]);
448: }
449:
450: static void getProtectedConstructors(Class cls, Set signatures,
451: Set constructors) {
452: Constructor _constructors[] = cls.getDeclaredConstructors();
453: for (int j = 0; j < _constructors.length; j++) {
454: Constructor c = _constructors[j];
455: int modifiers = c.getModifiers();
456: if (!Modifier.isProtected(modifiers)
457: || Modifier.isFinal(modifiers)) {
458: continue;
459: }
460: String sig = ClassFile.signature(c.getParameterTypes());
461: if (signatures.add(sig)) {
462: constructors.add(c);
463: }
464: }
465: }
466:
467: public static void defineMethod(ClassFile cf,
468: Class[] parameterTypes, Class returnType,
469: Class[] exceptionTypes, int modifiers, String methodName,
470: String sig, int mode) {
471: String className = cf.getClassName();
472: String[] exceptionTypeInfo = null;
473: if (exceptionTypes != null && exceptionTypes.length > 0) {
474: exceptionTypeInfo = new String[exceptionTypes.length];
475: for (int i = 0; i < exceptionTypes.length; i++) {
476: exceptionTypeInfo[i] = exceptionTypes[i].getName();
477: }
478: }
479: cf
480: .openMethod(
481: methodName,
482: ClassFile.signature(parameterTypes)
483: + ClassFile.signature(returnType),
484: (short) (modifiers & (Constants.ACC_PUBLIC | Constants.ACC_PROTECTED)),
485: exceptionTypeInfo);
486:
487: cf.add(Opcode.GETSTATIC, className, "_package",
488: "Lpnuts/lang/Package;");
489: cf.add(Opcode.LDC, cf.addConstant(sig));
490: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.String", "intern",
491: "()", "Ljava/lang/String;");
492: cf.add(Opcode.GETSTATIC, className, "_context",
493: "Lpnuts/lang/Context;");
494: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Package", "get",
495: "(Ljava/lang/String;Lpnuts/lang/Context;)",
496: "Ljava/lang/Object;");
497: // int f = cf.getLocal();
498: cf.add(Opcode.CHECKCAST, "pnuts.lang.PnutsFunction");
499:
500: int nargs = parameterTypes.length;
501: if (nargs <= -0x8000 || nargs >= 0x8000) {
502: throw new RuntimeException("too many parameters");
503: }
504: boolean hasThis = ((mode & THIS_BIT) == THIS_BIT);
505: boolean hasSuper = ((mode & SUPER_BIT) == SUPER_BIT);
506: int i = 0;
507:
508: Label catchStart = cf.getLabel(true);
509:
510: int nargs2 = nargs;
511: if (hasThis) {
512: nargs2++;
513: i++;
514: }
515: if (hasSuper) {
516: nargs2++;
517: i++;
518: }
519:
520: cf.pushInteger(nargs2);
521: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
522:
523: int k = 0;
524: for (int j = 0; k < nargs; j++, k++) {
525: cf.add(Opcode.DUP);
526: cf.pushInteger(k/* + i*/);
527: Class paramType = parameterTypes[k];
528: if (paramType.isPrimitive()) {
529: loadPrimitive(cf, paramType, j + 1);
530: if (paramType.equals(long.class)
531: || paramType.equals(double.class)) {
532: j++;
533: }
534: } else {
535: cf.loadLocal(j + 1);
536: }
537: cf.add(Opcode.AASTORE);
538: }
539: i = 0;
540: if (hasThis) {
541: cf.add(Opcode.DUP);
542: cf.pushInteger(i++);
543: cf.loadLocal(0);
544: cf.add(Opcode.AASTORE);
545: }
546: if (hasSuper) {
547: cf.add(Opcode.DUP);
548: cf.pushInteger(i++);
549: cf.loadLocal(0);
550: cf.add(Opcode.GETFIELD, className, "_superCallProxy",
551: "Lpnuts/lang/AbstractData;");
552: cf.add(Opcode.AASTORE);
553: }
554:
555: cf.add(Opcode.GETSTATIC, className, "_context",
556: "Lpnuts/lang/Context;");
557: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.PnutsFunction",
558: "call", "([Ljava/lang/Object;Lpnuts/lang/Context;)",
559: "Ljava/lang/Object;");
560:
561: if (returnType == void.class) {
562: cf.add(Opcode.POP);
563: cf.add(Opcode.RETURN);
564: } else if (returnType.isPrimitive()) {
565: returnPrimitive(cf, returnType);
566: } else {
567: if (returnType != Object.class) {
568: // TODO: transform array <-> list?
569: cf.add(Opcode.CHECKCAST, returnType.getName());
570: }
571: cf.add(Opcode.ARETURN);
572: }
573:
574: Label catchEnd = cf.getLabel(true);
575: Label catchTarget = cf.getLabel(true);
576: cf.reserveStack(1);
577: int pex = cf.getLocal();
578: cf.storeLocal(pex);
579:
580: cf.loadLocal(pex);
581: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.PnutsException",
582: "getThrowable", "()", "Ljava/lang/Throwable;");
583: int ex = cf.getLocal();
584: cf.storeLocal(ex);
585: Label next;
586: if (exceptionTypeInfo != null) {
587: for (i = 0; i < exceptionTypeInfo.length; i++) {
588: next = cf.getLabel();
589: cf.loadLocal(ex);
590: cf.add(Opcode.INSTANCEOF, exceptionTypeInfo[i]);
591: cf.add(Opcode.IFEQ, next);
592: cf.loadLocal(ex);
593: cf.add(Opcode.ATHROW);
594: next.fix();
595: }
596: }
597:
598: cf.loadLocal(pex);
599: cf.add(Opcode.ATHROW);
600: cf.addExceptionHandler(catchStart, catchEnd, catchTarget,
601: "pnuts.lang.PnutsException");
602:
603: cf.closeMethod();
604: }
605:
606: public static void defineMethod(ClassFile cf,
607: Class[] parameterTypes, Class returnType,
608: Class[] exceptionTypes, int modifiers, String methodName,
609: String sig, String functionFieldName) {
610: String className = cf.getClassName();
611: String[] exceptionTypeInfo = null;
612: if (exceptionTypes != null && exceptionTypes.length > 0) {
613: exceptionTypeInfo = new String[exceptionTypes.length];
614: for (int i = 0; i < exceptionTypes.length; i++) {
615: exceptionTypeInfo[i] = exceptionTypes[i].getName();
616: }
617: }
618: cf
619: .openMethod(
620: methodName,
621: ClassFile.signature(parameterTypes)
622: + ClassFile.signature(returnType),
623: (short) (modifiers & (Constants.ACC_PUBLIC | Constants.ACC_PROTECTED)),
624: exceptionTypeInfo);
625: cf.add(Opcode.ALOAD_0);
626: cf.add(Opcode.GETFIELD, className, functionFieldName,
627: "Lpnuts/lang/PnutsFunction;");
628:
629: int nargs = parameterTypes.length;
630: if (nargs <= -0x8000 || nargs >= 0x8000) {
631: throw new RuntimeException("too many parameters");
632: }
633:
634: Label catchStart = cf.getLabel(true);
635:
636: cf.pushInteger(nargs);
637: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
638:
639: int k = 0;
640: for (int j = 0; k < nargs; j++, k++) {
641: cf.add(Opcode.DUP);
642: cf.pushInteger(k/* + i*/);
643: Class paramType = parameterTypes[k];
644: if (paramType.isPrimitive()) {
645: loadPrimitive(cf, paramType, j + 1);
646: if (paramType.equals(long.class)
647: || paramType.equals(double.class)) {
648: j++;
649: }
650: } else {
651: cf.loadLocal(j + 1);
652: }
653: cf.add(Opcode.AASTORE);
654: }
655:
656: cf.add(Opcode.GETSTATIC, className, "_context",
657: "Lpnuts/lang/Context;");
658: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.PnutsFunction",
659: "call", "([Ljava/lang/Object;Lpnuts/lang/Context;)",
660: "Ljava/lang/Object;");
661:
662: if (returnType == void.class) {
663: cf.add(Opcode.POP);
664: cf.add(Opcode.RETURN);
665: } else if (returnType.isPrimitive()) {
666: returnPrimitive(cf, returnType);
667: } else {
668: if (returnType != Object.class) {
669: // TODO: transform array <-> list?
670: cf.add(Opcode.CHECKCAST, returnType.getName());
671: }
672: cf.add(Opcode.ARETURN);
673: }
674:
675: Label catchEnd = cf.getLabel(true);
676: Label catchTarget = cf.getLabel(true);
677: cf.reserveStack(1);
678: int pex = cf.getLocal();
679: cf.storeLocal(pex);
680:
681: cf.loadLocal(pex);
682: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.PnutsException",
683: "getThrowable", "()", "Ljava/lang/Throwable;");
684: int ex = cf.getLocal();
685: cf.storeLocal(ex);
686: Label next;
687: if (exceptionTypeInfo != null) {
688: for (int i = 0; i < exceptionTypeInfo.length; i++) {
689: next = cf.getLabel();
690: cf.loadLocal(ex);
691: cf.add(Opcode.INSTANCEOF, exceptionTypeInfo[i]);
692: cf.add(Opcode.IFEQ, next);
693: cf.loadLocal(ex);
694: cf.add(Opcode.ATHROW);
695: next.fix();
696: }
697: }
698:
699: cf.loadLocal(pex);
700: cf.add(Opcode.ATHROW);
701: cf.addExceptionHandler(catchStart, catchEnd, catchTarget,
702: "pnuts.lang.PnutsException");
703:
704: cf.closeMethod();
705: }
706:
707: private static void loadPrimitive(ClassFile cf, Class primitive,
708: int index) {
709: if (primitive == int.class) {
710: cf.add(Opcode.NEW, "java.lang.Integer");
711: cf.add(Opcode.DUP);
712: cf.iloadLocal(index);
713: cf.add(Opcode.INVOKESPECIAL, "java.lang.Integer", "<init>",
714: "(I)", "V");
715: } else if (primitive == byte.class) {
716: cf.add(Opcode.NEW, "java.lang.Byte");
717: cf.add(Opcode.DUP);
718: cf.iloadLocal(index);
719: cf.add(Opcode.INVOKESPECIAL, "java.lang.Byte", "<init>",
720: "(B)", "V");
721: } else if (primitive == short.class) {
722: cf.add(Opcode.NEW, "java.lang.Short");
723: cf.add(Opcode.DUP);
724: cf.iloadLocal(index);
725: cf.add(Opcode.INVOKESPECIAL, "java.lang.Short", "<init>",
726: "(S)", "V");
727: } else if (primitive == char.class) {
728: cf.add(Opcode.NEW, "java.lang.Character");
729: cf.add(Opcode.DUP);
730: cf.iloadLocal(index);
731: cf.add(Opcode.INVOKESPECIAL, "java.lang.Character",
732: "<init>", "(C)", "V");
733: } else if (primitive == long.class) {
734: cf.add(Opcode.NEW, "java.lang.Long");
735: cf.add(Opcode.DUP);
736: cf.lloadLocal(index);
737: cf.add(Opcode.INVOKESPECIAL, "java.lang.Long", "<init>",
738: "(J)", "V");
739: } else if (primitive == float.class) {
740: cf.add(Opcode.NEW, "java.lang.Float");
741: cf.add(Opcode.DUP);
742: cf.floadLocal(index);
743: cf.add(Opcode.INVOKESPECIAL, "java.lang.Float", "<init>",
744: "(F)", "V");
745: } else if (primitive == double.class) {
746: cf.add(Opcode.NEW, "java.lang.Double");
747: cf.add(Opcode.DUP);
748: cf.dloadLocal(index);
749: cf.add(Opcode.INVOKESPECIAL, "java.lang.Double", "<init>",
750: "(D)", "V");
751: } else if (primitive == boolean.class) {
752: cf.add(Opcode.NEW, "java.lang.Boolean");
753: cf.add(Opcode.DUP);
754: cf.iloadLocal(index);
755: cf.add(Opcode.INVOKESPECIAL, "java.lang.Boolean", "<init>",
756: "(Z)", "V");
757: }
758: }
759:
760: private static void returnPrimitive(ClassFile cf, Class type) {
761: if (type == int.class) {
762: cf.add(Opcode.CHECKCAST, "java.lang.Integer");
763: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Integer",
764: "intValue", "()", "I");
765: cf.add(Opcode.IRETURN);
766: } else if (type == byte.class) {
767: cf.add(Opcode.CHECKCAST, "java.lang.Byte");
768: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Byte", "byteValue",
769: "()", "B");
770: cf.add(Opcode.IRETURN);
771: } else if (type == short.class) {
772: cf.add(Opcode.CHECKCAST, "java.lang.Short");
773: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Short",
774: "shortValue", "()", "S");
775: cf.add(Opcode.IRETURN);
776: } else if (type == char.class) {
777: cf.add(Opcode.CHECKCAST, "java.lang.Character");
778: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Character",
779: "charValue", "()", "C");
780: cf.add(Opcode.IRETURN);
781: } else if (type == long.class) {
782: cf.add(Opcode.CHECKCAST, "java.lang.Long");
783: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Long", "longValue",
784: "()", "L");
785: cf.add(Opcode.LRETURN);
786: } else if (type == float.class) {
787: cf.add(Opcode.CHECKCAST, "java.lang.Float");
788: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Float",
789: "floatValue", "()", "F");
790: cf.add(Opcode.FRETURN);
791: } else if (type == double.class) {
792: cf.add(Opcode.CHECKCAST, "java.lang.Double");
793: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Double",
794: "doubleValue", "()", "D");
795: cf.add(Opcode.DRETURN);
796: } else if (type == boolean.class) {
797: cf.add(Opcode.CHECKCAST, "java.lang.Boolean");
798: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Boolean",
799: "booleanValue", "()", "Z");
800: cf.add(Opcode.IRETURN);
801: } else {
802: throw new InternalError();
803: }
804: }
805:
806: static class MethodArity {
807: String name;
808: int nargs;
809:
810: MethodArity(String name, int nargs) {
811: this .name = name;
812: this .nargs = nargs;
813: }
814:
815: public int hashCode() {
816: return name.hashCode() * nargs;
817: }
818:
819: public boolean equals(Object obj) {
820: if (obj instanceof MethodArity) {
821: MethodArity a = (MethodArity) obj;
822: return a.nargs == nargs && a.name.equals(name);
823: }
824: return false;
825: }
826: }
827:
828: private static class ThisTransformer extends ScopeAnalyzer {
829:
830: private Set methods;
831: private Set fields;
832: private Set nodesNeedTransformation;
833:
834: ThisTransformer(Set methods, Set fields,
835: Set nodesNeedTransformation) {
836: this .methods = methods;
837: this .fields = fields;
838: this .nodesNeedTransformation = nodesNeedTransformation;
839: }
840:
841: protected void handleFreeVariable(SimpleNode node,
842: Context context) {
843: SimpleNode parent = node.jjtGetParent();
844: if (parent != null
845: && parent.id == PnutsParserTreeConstants.JJTAPPLICATIONNODE) {
846: String symbol = node.str;
847: SimpleNode argNode = parent.jjtGetChild(1);
848: int n = argNode.jjtGetNumChildren();
849:
850: MethodArity arity = new MethodArity(symbol, n);
851: if (methods.contains(arity)) {
852: nodesNeedTransformation.add(parent);
853: }
854: } else if (parent != null
855: && parent.id != PnutsParserTreeConstants.JJTMEMBERNODE) {
856: if (fields.contains(node.str)) {
857: nodesNeedTransformation.add(node);
858: }
859: }
860: }
861:
862: protected void declared(SimpleNode node, Context context,
863: String symbol) {
864: if (fields.contains(node.str)) {
865: nodesNeedTransformation.add(node);
866: }
867: }
868: }
869:
870: private static void populateMembers(SimpleNode classDefBody,
871: Set methods, Set fields) {
872: for (int i = 0, n = classDefBody.jjtGetNumChildren(); i < n; i++) {
873: SimpleNode c = classDefBody.jjtGetChild(i);
874: String name;
875: int arity;
876: if (c.id == PnutsParserTreeConstants.JJTMETHODDEF) {
877: name = c.str;
878: int num = c.jjtGetNumChildren();
879: if (num == 2) {
880: SimpleNode typedParamList = c.jjtGetChild(0);
881: arity = typedParamList.jjtGetNumChildren();
882: } else if (num == 3) {
883: SimpleNode typedParamList = c.jjtGetChild(1);
884: arity = typedParamList.jjtGetNumChildren();
885: } else {
886: throw new InternalError();
887: }
888: methods.add(new MethodArity(name, arity));
889: } else if (c.id == PnutsParserTreeConstants.JJTFIELDDEF) {
890: fields.add(c.str);
891: }
892: }
893: }
894:
895: private static void populateMethodArities(Class cls, Set methods) {
896: Method m[] = cls.getMethods();
897: for (int i = 0; i < m.length; i++) {
898: MethodArity a = new MethodArity(m[i].getName(), m[i]
899: .getParameterTypes().length);
900: methods.add(a);
901: }
902: }
903:
904: private static void populateFieldNames(Class cls, final Set fields) {
905: ObjectDescFactory.getDefault().create(cls).handleProperties(
906: new PropertyHandler() {
907: public void handle(String propertyName, Class type,
908: Method readMethod, Method writeMethod) {
909: fields.add(propertyName);
910: }
911: });
912: }
913:
914: private static void transformApplicationNode(SimpleNode node) {
915: node.id = PnutsParserTreeConstants.JJTMETHODNODE;
916: SimpleNode n0 = node.jjtGetChild(0);
917: node.str = n0.str;
918: n0.str = Compiler.THIS;
919: }
920:
921: private static void transformApplicationNode(SimpleNode node,
922: Set methods, Set fields) {
923: Set nodes = new HashSet();
924: new ThisTransformer(methods, fields, nodes).analyze(node);
925: for (Iterator it = nodes.iterator(); it.hasNext();) {
926: SimpleNode n = (SimpleNode) it.next();
927: if (n.id == PnutsParserTreeConstants.JJTAPPLICATIONNODE) {
928: transformApplicationNode(n);
929: }
930: }
931: }
932:
933: public static void transformClassDefBody(SimpleNode classDefBody,
934: Class super class) {
935: Set methods = new HashSet();
936: Set fields = new HashSet();
937: populateMethodArities(super class, methods);
938: populateFieldNames(super class, fields);
939: populateMembers(classDefBody, methods, fields);
940: transformApplicationNode(classDefBody, methods, fields);
941: }
942:
943: public static class SuperCallProxy implements AbstractData {
944: private Object target;
945:
946: public SuperCallProxy(Object target) {
947: this .target = target;
948: }
949:
950: public Object get(String name, Context context) {
951: throw new UnsupportedOperationException();
952: }
953:
954: public void set(String name, Object value, Context context) {
955: throw new UnsupportedOperationException();
956: }
957:
958: public Object invoke(String name, Object[] args, Context context) {
959: return Runtime.callMethod(context, target.getClass(),
960: "$super$" + name, args, null, target);
961: }
962: }
963: }
|