001: package gnu.expr;
002:
003: import gnu.bytecode.*;
004: import gnu.mapping.*;
005: import java.util.Vector;
006:
007: public class ClassExp extends LambdaExp {
008: public boolean needsConstructor;
009:
010: boolean simple;
011:
012: public boolean isSimple() {
013: return simple;
014: }
015:
016: public void setSimple(boolean value) {
017: simple = value;
018: }
019:
020: int accessFlags;
021:
022: public void setAccessFlags(int value) {
023: accessFlags = value;
024: }
025:
026: public boolean isInterface() {
027: return (accessFlags & Access.INTERFACE) != 0;
028: }
029:
030: /** The class of instances of this class.
031: * Same as super.type unless isMakingClassPair(), in which case super.type
032: * is an interface, and instanceType is a class implementing the interface.
033: * Using an interface plus a class gives us true multiple inheritance. */
034: ClassType instanceType;
035:
036: boolean makeClassPair;
037:
038: public void setMakingClassPair(boolean val) {
039: makeClassPair = val;
040: }
041:
042: /** True if we should make a pair of an interface and a class. */
043: public boolean isMakingClassPair() {
044: return makeClassPair;
045: }
046:
047: /** List of base classes and implemented interfaces. */
048: public Expression[] super s;
049:
050: public LambdaExp initMethod;
051:
052: public ClassExp() {
053: type = null;
054: // Make sure we actually generate a class.
055: setCanRead(true);
056: }
057:
058: /**
059: Create a ClassExp object to represent an existing class.
060: This ClassExp will not be compiled to a new class.
061: */
062: public ClassExp(ClassType type) {
063: this ();
064: this .type = this .instanceType = type;
065: setName(type.getName());
066: }
067:
068: public Declaration addField(String name, Type type) {
069: Declaration res = addDeclaration(name, type);
070: res.setSimple(false);
071: res.setFlag(Declaration.NONSTATIC_SPECIFIED);
072: res.setCanRead(true);
073: res.setCanWrite(true);
074: res.noteValue(null);
075:
076: // If the class already exists, find the corresponding field there.
077: if (instanceType != null)
078: res.field = instanceType.getDeclaredField(name);
079:
080: return res;
081: }
082:
083: /**
084: Add a method to this class.
085: @return the expression that should be used to call that method.
086: */
087: public ReferenceExp addMethod(LambdaExp method, boolean isPrivate) {
088: Declaration decl = new Declaration(method.getName());
089: decl.noteValue(method);
090: decl.setFlag(Declaration.IS_CONSTANT
091: | Declaration.STATIC_SPECIFIED);
092: decl.setProcedureDecl(true);
093: if (isPrivate)
094: decl.setSpecifiedPrivate(true);
095: method.nameDecl.context = this ;
096:
097: method.nextSibling = this .firstChild;
098: this .firstChild = method;
099:
100: if (instanceType != null) {
101: Method m = instanceType.getDeclaredMethod(method.getName(),
102: method.getArgTypes());
103: if (m != null && !m.isConstructor()) {
104: m.eraseCode();
105: method.declareThis(instanceType);
106: method.primMethods = new Method[] { m };
107: }
108: }
109:
110: return new ReferenceExp(decl);
111: }
112:
113: /**
114: Add a method to this class.
115: @return the expression that should be used to call that method.
116: */
117: public ReferenceExp addMethod(LambdaExp method) {
118: return addMethod(method, false);
119: }
120:
121: /*
122: public Object eval (Environment env)
123: {
124: System.err.println("eval ClassExp");
125: Class clas = evalToClass();
126: return Type.make(clas);
127: }
128: */
129:
130: public void compile(Compilation comp, Target target) {
131: if (target instanceof IgnoreTarget)
132: return;
133: ClassType new_class = compile(comp);
134: String className = new_class.getName();
135: // Type.make(Class.forname)
136:
137: ClassType typeClass = ClassType.make("java.lang.Class");
138: Method forNameClassMethod = typeClass.addMethod("forName",
139: comp.string1Arg, typeClass, Access.STATIC
140: | Access.PUBLIC);
141: gnu.bytecode.CodeAttr code = comp.getCode();
142: code.emitPushString(className);
143: code.emitInvokeStatic(forNameClassMethod);
144: ClassType typeType;
145: int nargs;
146: boolean needsLink = getNeedsClosureEnv();
147: if (isMakingClassPair() || needsLink) {
148: code.emitPushString(instanceType.getName());
149: code.emitInvokeStatic(forNameClassMethod);
150: typeType = ClassType.make("gnu.expr.PairClassType");
151: nargs = needsLink ? 3 : 2;
152: } else {
153: typeType = ClassType.make("gnu.bytecode.Type");
154: nargs = 1;
155: }
156: Type[] argsClass = new Type[nargs];
157: if (needsLink) {
158: comp.curLambda.loadHeapFrame(comp);
159: argsClass[--nargs] = Type.pointer_type;
160: }
161: while (--nargs >= 0)
162: argsClass[nargs] = typeClass;
163: Method makeMethod = typeType.addMethod("make", argsClass,
164: typeType, Access.STATIC | Access.PUBLIC);
165: code.emitInvokeStatic(makeMethod);
166:
167: target.compileFromStack(comp, typeType);
168: }
169:
170: public String getJavaName() {
171: return name == null ? "object" : Compilation
172: .mangleNameIfNeeded(name);
173: }
174:
175: public ClassType getCompiledClassType(Compilation comp) {
176: if (!partsDeclared) {
177: getType();
178: declareParts(comp);
179: }
180: if (type.getName() == null) {
181: String name = getName();
182: if (name == null)
183: name = "object";
184: else {
185: int nlen = name.length();
186: if (nlen > 2 && name.charAt(0) == '<'
187: && name.charAt(nlen - 1) == '>')
188: name = name.substring(1, nlen - 1);
189: }
190: if (!isSimple() || this instanceof ObjectExp)
191: name = comp.generateClassName(name);
192: else
193: // Keep the name if it is fully qualified, mangle it instead
194: if (name.indexOf('.') == -1)
195: name = comp.mangleNameIfNeeded(name);
196: type.setName(name);
197: }
198: if (filename != null)
199: type.setSourceFile(filename);
200: if (!isInterface())
201: comp.generateConstructor(getClassType(), this );
202: return type;
203: }
204:
205: public void recomputeInterfaces() {
206: setTypes();
207: }
208:
209: private void setTypes() {
210: int len = super s == null ? 0 : super s.length;
211: ClassType[] super Types = new ClassType[len];
212: ClassType super Type = null;
213: int j = 0;
214: for (int i = 0; i < len; i++) {
215: Type st = Interpreter.getInterpreter()
216: .getTypeFor(super s[i]);
217: if (st == null || !(st instanceof ClassType))
218: throw new Error("invalid super type");
219: ClassType t = (ClassType) st;
220: if ((t.getModifiers() & Access.INTERFACE) == 0) {
221: if (j < i)
222: throw new Error("duplicate superclass");
223: super Type = t;
224: } else
225: super Types[j++] = t;
226: }
227:
228: // If type is null, we simply want to recompute interfaces
229: if (type == null) {
230: if (super Type == null) {
231: if (!isSimple()) {
232: PairClassType ptype = new PairClassType();
233: type = ptype;
234: setMakingClassPair(true);
235: instanceType = new ClassType();
236: type.setInterface(true);
237: ClassType[] interfaces = { type };
238: // Can we better. FIXME.
239: instanceType.setSuper(Type.pointer_type);
240: instanceType.setInterfaces(interfaces);
241: ptype.instanceType = instanceType;
242: } else
243: instanceType = type = new ClassType(getName());
244: type.setSuper(Type.pointer_type);
245: } else {
246: instanceType = type = new ClassType(getName());
247: type.setSuper(super Type);
248: }
249:
250: instanceType.collectable = true;
251: // Access.SUPER mut be set on all non-interface classes
252: if (!isInterface())
253: accessFlags |= Access.SUPER;
254: instanceType.setModifiers(accessFlags);
255: }
256:
257: if (j > 0) {
258: ClassType[] interfaces;
259: if (j == len)
260: interfaces = super Types;
261: else {
262: interfaces = new ClassType[j];
263: System.arraycopy(super Types, 0, interfaces, 0, j);
264: }
265: type.setInterfaces(interfaces);
266: }
267: }
268:
269: public Type getType() {
270: if (type == null)
271: setTypes();
272: return type;
273: }
274:
275: public ClassType getClassType() {
276: return (ClassType) getType();
277: }
278:
279: boolean partsDeclared;
280:
281: public void declareParts(Compilation comp) {
282: if (partsDeclared)
283: return;
284: partsDeclared = true;
285: comp.topLambda = this ;
286: comp.topClass = this .type;
287: for (Declaration decl = firstDecl(); decl != null; decl = decl
288: .nextDecl()) {
289: // If the declaration derives from a method, don't create field.
290: // Also, field can already exist if the class is imported from a
291: // compiled package.
292: if (decl.getCanRead() && decl.field == null) {
293: int flags = 0;
294: if (decl.isSpecifiedPrivate())
295: flags |= Access.PRIVATE;
296: else
297: flags |= Access.PUBLIC;
298: if (decl.getFlag(Declaration.STATIC_SPECIFIED))
299: flags |= Access.STATIC;
300: if (isMakingClassPair()) {
301: flags |= Access.ABSTRACT;
302: Type ftype = decl.getType().getImplementationType();
303: type.addMethod(slotToMethodName("get", decl
304: .getName()), flags, Type.typeArray0, ftype);
305: Type[] stypes = { ftype };
306: type.addMethod(slotToMethodName("set", decl
307: .getName()), flags, stypes, Type.void_type);
308: } else
309: // This handles class fields.
310: {
311: if (decl.getFlag(Declaration.TRANSIENT))
312: flags |= Access.TRANSIENT;
313: if (decl.getFlag(Declaration.VOLATILE))
314: flags |= Access.VOLATILE;
315: if (decl.getFlag(Declaration.IS_CONSTANT))
316: flags |= Access.FINAL;
317: String fname = Compilation.mangleNameIfNeeded(decl
318: .getName());
319: decl.field = instanceType.addField(fname, decl
320: .getType(), flags);
321: decl.setSimple(false);
322: }
323: }
324: }
325:
326: for (LambdaExp child = firstChild; child != null; child = child.nextSibling) {
327: // When we recompile an existing method in an existing class,
328: // we keep the same Method objects.
329: if (child.primMethods != null)
330: continue;
331:
332: if (child != initMethod || !isMakingClassPair())
333: child.addMethodFor(type, null, null);
334: if (isMakingClassPair())
335: child.addMethodFor(instanceType, null, type);
336: }
337:
338: addAttributes(instanceType);
339: }
340:
341: /** Return implementation method matching name and param types.
342: * Used when compiling a pair class and generating a concrete method
343: * implementing an interface method, to find static implementation method
344: * in this or super implementation class we need to call.
345: * @param interfaceType search the implementation classes corresponding
346: * to this interface type and its super-interfaces.
347: * @param mname method name to look for.
348: * @param paramTypes method types to look for.
349: * @param vec where to place found methods
350: * If a method is found, don't search super-interfaces, as the found method
351: * is more specific and overrides any that might in super-interfaces.
352: */
353: static void getImplMethods(ClassType interfaceType, String mname,
354: Type[] paramTypes, Vector vec) {
355: ClassType implType;
356: if (interfaceType instanceof PairClassType)
357: implType = ((PairClassType) interfaceType).instanceType;
358: else if (!interfaceType.isInterface())
359: return;
360: else {
361: String implTypeName = interfaceType.getName() + "$class";
362: implType = ClassType.make(implTypeName);
363: }
364: Type[] itypes = new Type[paramTypes.length + 1];
365: itypes[0] = interfaceType;
366: System.arraycopy(paramTypes, 0, itypes, 1, paramTypes.length);
367: Method implMethod = implType.getDeclaredMethod(mname, itypes);
368: if (implMethod != null) {
369: int count = vec.size();
370: if (count == 0
371: || !vec.elementAt(count - 1).equals(implMethod))
372: vec.addElement(implMethod);
373: } else {
374: ClassType[] super Interfaces = interfaceType.getInterfaces();
375: for (int i = 0; i < super Interfaces.length; i++)
376: getImplMethods(super Interfaces[i], mname, paramTypes,
377: vec);
378: }
379: }
380:
381: public ClassType compile(Compilation comp) {
382: ClassType saveClass = comp.curClass;
383: Method saveMethod = comp.method;
384: try {
385: ClassType new_class = getCompiledClassType(comp);
386: comp.curClass = new_class;
387:
388: String filename = getFile();
389: if (filename != null)
390: new_class.setSourceFile(filename);
391:
392: LambdaExp saveLambda = comp.curLambda;
393: comp.curLambda = this ;
394:
395: allocFrame(comp);
396: if (getNeedsStaticLink()) {
397: Variable parentFrame = saveLambda.heapFrame != null ? saveLambda.heapFrame
398: : saveLambda.closureEnv;
399: if (parentFrame != null)
400: closureEnvField = staticLinkField = instanceType
401: .addField("this$0", parentFrame.getType());
402: }
403: comp.generateConstructor(instanceType, this );
404: CodeAttr code;
405:
406: for (LambdaExp child = firstChild; child != null;) {
407: Method save_method = comp.method;
408: LambdaExp save_lambda = comp.curLambda;
409: comp.method = child.getMainMethod();
410: //comp.curClass = comp.method.getDeclaringClass();
411: child.declareThis(comp.curClass);
412: comp.curClass = instanceType;
413: comp.curLambda = child;
414: comp.method.initCode();
415: child.allocChildClasses(comp);
416: child.allocParameters(comp);
417: child.enterFunction(comp);
418: child.compileBody(comp);
419: child.compileEnd(comp);
420: child.compileChildMethods(comp);
421: comp.method = save_method;
422: comp.curClass = new_class;
423: comp.curLambda = save_lambda;
424: child = child.nextSibling;
425: }
426:
427: Method[] methods = type.getMethods(
428: AbstractMethodFilter.instance, 2);
429: for (int i = 0; i < methods.length; i++) {
430: Method meth = methods[i];
431: String mname = meth.getName();
432: Type[] ptypes = meth.getParameterTypes();
433: Type rtype = meth.getReturnType();
434:
435: Method mimpl = instanceType.getMethod(mname, ptypes);
436: if (mimpl != null && !mimpl.isAbstract())
437: continue;
438:
439: char ch;
440: if (mname.length() > 3 && mname.charAt(2) == 't'
441: && mname.charAt(1) == 'e'
442: && ((ch = mname.charAt(0)) == 'g' || ch == 's')) {
443: Type ftype;
444: if (ch == 's' && rtype.isVoid()
445: && ptypes.length == 1)
446: ftype = ptypes[0];
447: else if (ch == 'g' && ptypes.length == 0)
448: ftype = rtype;
449: else
450: continue;
451: String fname = Character.toLowerCase(mname
452: .charAt(3))
453: + mname.substring(4);
454: Field fld = instanceType.getField(fname);
455: if (fld == null)
456: fld = instanceType.addField(fname, ftype,
457: Access.PUBLIC);
458: Method impl = instanceType.addMethod(mname,
459: Access.PUBLIC, ptypes, rtype);
460: impl.init_param_slots();
461: code = impl.getCode();
462: code.emitPushThis();
463: if (ch == 'g') {
464: code.emitGetField(fld);
465: } else {
466: code.emitLoad(code.getArg(1));
467: code.emitPutField(fld);
468: }
469: code.emitReturn();
470: } else {
471: Vector vec = new Vector();
472: getImplMethods(type, mname, ptypes, vec);
473: if (vec.size() != 1) {
474: // FIXME - need better error message!
475: String msg = vec.size() == 0 ? "missing implementation for "
476: : "ambiguous implementation for ";
477: comp.error('e', msg + meth);
478: } else {
479: Method impl = instanceType.addMethod(mname,
480: Access.PUBLIC, ptypes, rtype);
481: impl.init_param_slots();
482: code = impl.getCode();
483: for (Variable var = code.getCurrentScope()
484: .firstVar(); var != null; var = var
485: .nextVar())
486: code.emitLoad(var);
487: Method imethod = (Method) vec.elementAt(0);
488: code.emitInvokeStatic(imethod);
489: code.emitReturn();
490: }
491: }
492: }
493:
494: comp.curLambda = saveLambda;
495:
496: return new_class;
497: } finally {
498: comp.curClass = saveClass;
499: comp.method = saveMethod;
500: }
501: }
502:
503: /**
504: Return code to create an instance of this class.
505: The instance is initialized by calling the default constructor.
506: */
507: public final Expression instantiate() {
508: return new QuoteExp(new PrimProcedure(getDefaultConstructor()));
509: }
510:
511: private Method getDefaultConstructor() {
512: ClassType clas = getClassType();
513: return Compilation.getConstructor(clas, this );
514: }
515:
516: void compileChildMethods(Compilation comp) {
517: // We set comp.curClass, so that literals are emited in the right class.
518: ClassType save_class = comp.curClass;
519: comp.curClass = this .type;
520:
521: super .compileChildMethods(comp);
522: setFieldValues(comp);
523:
524: comp.curClass = save_class;
525: }
526:
527: private void setFieldValues(Compilation comp) {
528: for (Declaration decl = firstDecl(); decl != null; decl = decl
529: .nextDecl()) {
530: if (decl.field != null) {
531: decl.setFieldValue(comp);
532: }
533: }
534: }
535:
536: protected Expression walk(ExpWalker walker) {
537: return walker.walkClassExp(this );
538: }
539:
540: protected void walkChildren(ExpWalker walker) {
541: LambdaExp save = walker.currentLambda;
542: walker.currentLambda = this ;
543: try {
544: for (LambdaExp child = firstChild; child != null
545: && walker.exitValue == null; child = child.nextSibling)
546: walker.walkLambdaExp(child);
547:
548: // Walk static fields. This is particularly important for
549: // those initialized to some value, since that value might
550: // include closures that need to be walked.
551: for (Declaration decl = firstDecl(); decl != null; decl = decl
552: .nextDecl())
553: if (decl.isStatic() && decl.value != null)
554: decl.value.walk(walker);
555: } finally {
556: walker.currentLambda = save;
557: }
558: }
559:
560: public void print(OutPort out) {
561: out.startLogicalBlock("(" + getExpClassName() + "/", ")", 2);
562: if (name != null) {
563: out.print(name);
564: out.print('/');
565: }
566: out.print(id);
567: out.print("/ (");
568: Special prevMode = null;
569: int i = 0;
570: int opt_i = 0;
571: int key_args = keywords == null ? 0 : keywords.length;
572: int opt_args = defaultArgs == null ? 0 : defaultArgs.length
573: - key_args;
574: for (Declaration decl = firstDecl(); decl != null; decl = decl
575: .nextDecl()) {
576: if (i > 0)
577: out.print(' ');
578: out.print(decl);
579: i++;
580: }
581: out.print(") ");
582: for (LambdaExp child = firstChild; child != null; child = child.nextSibling) {
583: out.writeSpaceLinear();
584: out.print(" method: ");
585: child.print(out);
586: }
587: out.writeSpaceLinear();
588: if (body == null)
589: out.print("<null body>");
590: else
591: body.print(out);
592: out.endLogicalBlock(")");
593: }
594:
595: public Field compileSetField(Compilation comp) {
596: return (new ClassInitializer(this , comp)).field;
597: }
598:
599: /** Mangle a "slot" name to a get- or set- method name. */
600: public static String slotToMethodName(String prefix, String sname) {
601: StringBuffer sbuf = new StringBuffer(sname.length() + 3);
602: sbuf.append(prefix);
603: sbuf.append(Character.toTitleCase(sname.charAt(0)));
604: sbuf.append(sname.substring(1));
605: return sbuf.toString();
606: }
607:
608: /****************************************************************
609: * Assertions
610: ****************************************************************/
611:
612: private Field assertionEnabledField;
613:
614: public Field getAssertionEnabledField() {
615: if (assertionEnabledField == null) {
616: ClassType classe = (ClassType) getType();
617:
618: // Get the field if it already exists.
619: // This is the case for already compiled classes.
620: assertionEnabledField = classe
621: .getField("$assertionsEnabled");
622: if (assertionEnabledField != null)
623: return assertionEnabledField;
624:
625: assertionEnabledField = classe.addField(
626: "$assertionsEnabled", Type.boolean_type,
627: Access.STATIC | Access.FINAL);
628:
629: addClassInitializer(new Initializer() {
630: {
631: field = assertionEnabledField;
632: }
633:
634: public void emit(Compilation comp) {
635: CodeAttr code = comp.getCode();
636:
637: // Try to get the assertion status, if in JDK 1.4 or later.
638: code.emitTryStart(false, Type.boolean_type);
639: code.emitPushString(getName());
640: code.emitInvokeStatic(forName);
641: code.emitInvokeVirtual(desiredAssertionStatus);
642: code.emitTryEnd();
643:
644: // If the method does not exist, get global assertion status.
645: Variable catchVar = new Variable("e", noSuchMethod);
646: catchVar.allocateLocal(code);
647: code.emitCatchStart(catchVar);
648: code.emitPushString("assertions");
649: code.emitInvokeStatic(getProperty);
650: code.emitIfNull();
651: code.emitPushBoolean(false);
652: code.emitElse();
653: code.emitPushBoolean(true);
654: code.emitFi();
655: code.emitCatchEnd();
656: code.emitTryCatchEnd();
657:
658: code.emitPutStatic(field);
659: }
660: });
661: }
662:
663: return assertionEnabledField;
664: }
665:
666: static final ClassType javaClass = ClassType
667: .make("java.lang.Class"), noSuchMethod = ClassType
668: .make("java.lang.NoSuchMethodError");
669:
670: static final Method forName = javaClass.getDeclaredMethod(
671: "forName", 1), desiredAssertionStatus = javaClass
672: .addMethod("desiredAssertionStatus", Access.PUBLIC,
673: new Type[] {}, Type.boolean_type),
674: getProperty = ClassType.make("java.lang.System")
675: .getDeclaredMethod("getProperty", 1);
676:
677: }
678:
679: class AbstractMethodFilter implements gnu.bytecode.Filter {
680: public static AbstractMethodFilter instance = new AbstractMethodFilter();
681:
682: public boolean select(Object value) {
683: gnu.bytecode.Method method = (gnu.bytecode.Method) value;
684: return method.isAbstract();
685: }
686: }
|