0001: // Copyright (c) 1999, 2000, 2001 Per M.A. Bothner.
0002: // This is free software; for terms and warranty disclaimer see ./COPYING.
0003:
0004: package gnu.expr;
0005:
0006: import gnu.bytecode.*;
0007: import gnu.mapping.*;
0008: import java.util.*;
0009: import java.io.*;
0010:
0011: public class Compilation {
0012: /** Used by LambdaExp.getSelectorValue if need to allocate new selector. */
0013: int maxSelectorValue;
0014:
0015: public ClassType curClass;
0016: public ClassType mainClass;
0017:
0018: public LambdaExp curLambda;
0019: public ModuleExp mainLambda;
0020: public Variable this Decl;
0021:
0022: /** Contains "$instance" if the module is static; otherwise null. */
0023: Field instanceField;
0024:
0025: /** If true, minimize the number of classes generated.
0026: * Do this even if it makes things a little slower. */
0027: public static boolean fewerClasses;
0028:
0029: /** If true, print out final expressions after optimizations etc. */
0030: public static boolean debugPrintFinalExpr;
0031:
0032: public static boolean usingCPStyle;
0033: public static boolean usingTailCalls = false;
0034:
0035: /** If moduleStatic > 0, (module-static #t) is implied by default.
0036: * If moduleStatic < 0, (module-static #f) is implied by default. */
0037: public static int moduleStatic = 0;
0038:
0039: ClassType[] classes;
0040: int numClasses;
0041:
0042: /** True if the compiled result will be immediately loaded. */
0043: boolean immediate;
0044:
0045: /** The current method. */
0046: public Method method;
0047:
0048: public final CodeAttr getCode() {
0049: return method.getCode();
0050: }
0051:
0052: int method_counter;
0053:
0054: /* When multiple procedures are compiled into a single method,
0055: we use a switch to jump to the correct part of the method. */
0056: SwitchState fswitch;
0057:
0058: Field fswitchIndex;
0059: /** The actual parameter of the current CallFrame.step(CallContext) method. */
0060: Variable callStackContext;
0061:
0062: // Various standard classes
0063: static public ClassType typeObject = Type.pointer_type;
0064: static public ClassType scmBooleanType = ClassType
0065: .make("java.lang.Boolean");
0066: static public ClassType typeString = ClassType
0067: .make("java.lang.String");
0068: static public ClassType javaStringType = typeString;
0069: static public ClassType scmSymbolType = typeString;
0070: static public ClassType scmKeywordType = ClassType
0071: .make("gnu.expr.Keyword");
0072: static public ClassType scmSequenceType = ClassType
0073: .make("gnu.lists.Sequence");
0074: static public ClassType javaIntegerType = ClassType
0075: .make("java.lang.Integer");
0076: static public ClassType scmListType = ClassType
0077: .make("gnu.lists.LList");
0078: static public ClassType typePair = ClassType.make("gnu.lists.Pair");
0079: static public ClassType scmPairType = typePair;
0080: static public ClassType scmUndefinedType = ClassType
0081: .make("gnu.expr.Undefined");
0082: public static final ArrayType objArrayType = ArrayType
0083: .make(typeObject);
0084: public static final ArrayType symbolArrayType = ArrayType
0085: .make(scmSymbolType);
0086: static public ClassType scmNamedType = ClassType
0087: .make("gnu.mapping.Named");
0088: static public ClassType typeRunnable = ClassType
0089: .make("java.lang.Runnable");
0090: static public ClassType typeObjectType = ClassType
0091: .make("gnu.bytecode.ObjectType");
0092: static public ClassType typeClassType = ClassType.make(
0093: "gnu.bytecode.ClassType", typeObjectType);
0094: static public ClassType typeProcedure = ClassType
0095: .make("gnu.mapping.Procedure");
0096: static public ClassType typeInterpreter = ClassType
0097: .make("gnu.expr.Interpreter");
0098: static public ClassType typeMacro = ClassType
0099: .make("kawa.lang.Macro");
0100: static public ClassType typeEnvironment = ClassType
0101: .make("gnu.mapping.Environment");
0102: static public ClassType typeLocation = ClassType
0103: .make("gnu.mapping.Location");
0104: static public ClassType typeBinding = ClassType.make(
0105: "gnu.mapping.Binding", typeLocation);
0106: static public final Method getLocationMethod = typeLocation
0107: .addMethod("get", Type.typeArray0, Type.pointer_type,
0108: Access.PUBLIC);
0109: static public final Method getProcedureBindingMethod = typeBinding
0110: .addMethod("getProcedure", Type.typeArray0, typeProcedure,
0111: Access.PUBLIC);
0112: static public final Field trueConstant = scmBooleanType.addField(
0113: "TRUE", scmBooleanType, Access.PUBLIC | Access.STATIC);
0114: static public final Field falseConstant = scmBooleanType.addField(
0115: "FALSE", scmBooleanType, Access.PUBLIC | Access.STATIC);
0116: static final Field voidConstant = typeInterpreter.addField(
0117: "voidObject", typeObject, Access.PUBLIC | Access.STATIC);
0118: static final Field undefinedConstant = typeInterpreter.addField(
0119: "undefinedObject", scmUndefinedType, Access.PUBLIC
0120: | Access.STATIC);
0121: static final Field emptyConstant = scmListType.addField("Empty",
0122: scmListType, Access.PUBLIC | Access.STATIC);
0123: static final Field eofConstant = scmSequenceType.addField(
0124: "eofValue", typeObject, Access.PUBLIC | Access.STATIC);
0125: static final Method setNameMethod = typeProcedure
0126: .getDeclaredMethod("setName", 1);
0127: static Method initIntegerMethod;
0128: static Method lookupGlobalMethod;
0129: static Method defineGlobalMethod;
0130: static Method defineFunctionMethod;
0131: static Method putGlobalMethod;
0132: static Method makeListMethod;
0133:
0134: public static final Type[] int1Args = { Type.int_type };
0135: public static final Type[] string1Arg = { javaStringType };
0136: public static final Type[] sym1Arg = string1Arg;
0137:
0138: static public final Method getBindingEnvironmentMethod = typeEnvironment
0139: .addMethod("getBinding", string1Arg, typeBinding,
0140: Access.PUBLIC);
0141:
0142: static {
0143: Type[] makeListArgs = { objArrayType, Type.int_type };
0144: makeListMethod = scmListType.addMethod("makeList",
0145: makeListArgs, scmListType, Access.PUBLIC
0146: | Access.STATIC);
0147: initIntegerMethod = javaIntegerType.addMethod("<init>",
0148: int1Args, Type.void_type, Access.PUBLIC);
0149:
0150: lookupGlobalMethod = typeEnvironment.addMethod("lookup_global",
0151: sym1Arg, typeObject, Access.PUBLIC | Access.STATIC);
0152: Type[] symObjArgs = { scmSymbolType, typeObject };
0153: defineGlobalMethod = typeEnvironment.addMethod("define_global",
0154: symObjArgs, Type.void_type, Access.PUBLIC
0155: | Access.STATIC);
0156: defineFunctionMethod = typeEnvironment.addMethod(
0157: "defineFunction", symObjArgs, Type.void_type,
0158: Access.PUBLIC | Access.STATIC);
0159: putGlobalMethod = typeEnvironment.addMethod("put_global",
0160: symObjArgs, Type.void_type, Access.PUBLIC
0161: | Access.STATIC);
0162: }
0163:
0164: public static Method getCurrentEnvironmentMethod = typeEnvironment
0165: .addMethod("getCurrent", Type.typeArray0, typeEnvironment,
0166: Access.PUBLIC | Access.STATIC);
0167:
0168: public static Type[] apply0args = Type.typeArray0;
0169: public static Type[] apply1args = { typeObject };
0170: public static Type[] apply2args = { typeObject, typeObject };
0171: public static Type[] applyNargs = { objArrayType };
0172:
0173: static Method checkArgCountMethod;
0174:
0175: public static Method apply0method = typeProcedure.addMethod(
0176: "apply0", apply0args, typeObject, Access.PUBLIC
0177: | Access.FINAL);
0178:
0179: public static Method apply1method;
0180: public static Method apply2method;
0181: public static Method apply3method;
0182: public static Method apply4method;
0183: public static Method applyNmethod;
0184:
0185: static {
0186: apply1method = typeProcedure.addMethod("apply1", apply1args,
0187: typeObject, Access.PUBLIC);
0188: apply2method = typeProcedure.addMethod("apply2", apply2args,
0189: typeObject, Access.PUBLIC);
0190: Type[] apply3args = { typeObject, typeObject, typeObject };
0191: apply3method = typeProcedure.addMethod("apply3", apply3args,
0192: typeObject, Access.PUBLIC);
0193: Type[] apply4args = { typeObject, typeObject, typeObject,
0194: typeObject };
0195: apply4method = typeProcedure.addMethod("apply4", apply4args,
0196: typeObject, Access.PUBLIC);
0197: applyNmethod = typeProcedure.addMethod("applyN", applyNargs,
0198: typeObject, Access.PUBLIC);
0199: Type[] args = new Type[2];
0200: args[0] = typeProcedure;
0201: args[1] = Type.int_type;
0202: checkArgCountMethod = typeProcedure.addMethod("checkArgCount",
0203: args, Type.void_type, Access.PUBLIC | Access.STATIC);
0204: }
0205:
0206: public static Method[] applymethods = { apply0method, apply1method,
0207: apply2method, apply3method, apply4method, applyNmethod };
0208:
0209: public static ClassType typeProcedure0 = ClassType.make(
0210: "gnu.mapping.Procedure0", typeProcedure);
0211: public static ClassType typeProcedure1 = ClassType.make(
0212: "gnu.mapping.Procedure1", typeProcedure);
0213: public static ClassType typeProcedure2 = ClassType.make(
0214: "gnu.mapping.Procedure2", typeProcedure);
0215: public static ClassType typeProcedure3 = ClassType.make(
0216: "gnu.mapping.Procedure3", typeProcedure);
0217: public static ClassType typeProcedure4 = ClassType.make(
0218: "gnu.mapping.Procedure4", typeProcedure);
0219: public static ClassType typeProcedureN = ClassType.make(
0220: "gnu.mapping.ProcedureN", typeProcedure);
0221: public static ClassType typeModuleBody = ClassType.make(
0222: "gnu.expr.ModuleBody", typeProcedure0);
0223: public static ClassType typeApplet = ClassType
0224: .make("java.applet.Applet");
0225: public static ClassType typeServlet = ClassType
0226: .make("gnu.kawa.servlet.KawaServlet");
0227:
0228: public static ClassType typeModuleMethod = ClassType.make(
0229: "gnu.expr.ModuleMethod", typeProcedureN);
0230: public static ClassType typeApplyMethodProc = ClassType.make(
0231: "gnu.mapping.ApplyMethodProc", typeProcedureN);
0232: public static ClassType typeApplyMethodContainer = ClassType
0233: .make("gnu.mapping.ApplyMethodContainer");
0234:
0235: /* Classes, fields, and methods used wgen usingCPStyle". */
0236: public static ClassType typeCallContext = ClassType
0237: .make("gnu.mapping.CallContext");
0238: public static final ClassType typeConsumer = ClassType
0239: .make("gnu.lists.Consumer");
0240: public static Method popCallContextMethod = typeCallContext
0241: .addMethod("pop", apply0args, Type.void_type, Access.PUBLIC);
0242: public static ClassType typeValues = ClassType
0243: .make("gnu.mapping.Values");
0244: public static Field noArgsField = typeValues.addField("noArgs",
0245: objArrayType, Access.PUBLIC | Access.STATIC);
0246: public static Field pcCallContextField = typeCallContext.addField(
0247: "pc", Type.int_type, Access.PROTECTED);
0248: public static ClassType typeCpsProcedure = ClassType
0249: .make("gnu.mapping.CpsProcedure");
0250: public static ClassType typeCallFrame = ClassType
0251: .make("gnu.mapping.CallFrame");
0252: public static ClassType typeCpsMethodProc = ClassType.make(
0253: "gnu.mapping.CpsMethodProc", typeCpsProcedure);
0254: public static ClassType typeCpsMethodContainer = ClassType
0255: .make("gnu.mapping.CpsMethodContainer");
0256: public static Field numArgsCallFrameField = typeCallFrame.addField(
0257: "numArgs", Type.int_type, Access.PROTECTED);
0258: public static Field argsCallContextField = typeCallContext
0259: .addField("values", objArrayType, Access.PROTECTED);
0260: public static Field procCallContextField = typeCallContext
0261: .addField("proc", typeProcedure, Access.PROTECTED);
0262: public static Field callerCallFrameField = typeCallFrame.addField(
0263: "caller", typeCallFrame, Access.PROTECTED);
0264: public static Field saved_pcCallFrameField = typeCallFrame
0265: .addField("saved_pc", Type.int_type, Access.PROTECTED);
0266: private static Type[] applyCpsArgs = { typeCallContext };
0267: public static Method applyCpsMethod = typeProcedure.addMethod(
0268: "apply", applyCpsArgs, Type.void_type, Access.PUBLIC);
0269:
0270: public static ClassType[] typeProcedureArray = { typeProcedure0,
0271: typeProcedure1, typeProcedure2, typeProcedure3,
0272: typeProcedure4 };
0273:
0274: Hashtable literalTable;
0275: int literalsCount;
0276:
0277: /** Rembembers stuff to do in <clinit> of main class. */
0278: Initializer clinitChain;
0279:
0280: /** Rembembers literals to initialize (in <clinit>). */
0281: Literal literalsChain;
0282:
0283: public static boolean generateMainDefault = false;
0284: /** True if we should generate a main(String[]) method. */
0285: public boolean generateMain = generateMainDefault;
0286:
0287: LitTable litTable;
0288:
0289: public static boolean generateAppletDefault = false;
0290: /** True if we should generate an Applet. */
0291: public boolean generateApplet = generateAppletDefault;
0292:
0293: public static boolean generateServletDefault = false;
0294: /** True if we should generate an Servlet. */
0295: public boolean generateServlet = generateServletDefault;
0296:
0297: public static final ClassType getMethodProcType(ClassType modClass) {
0298: return usingTailCalls ? typeCpsMethodProc
0299: : true || modClass.getSuperclass().isSubtype(
0300: typeProcedure) ? typeModuleMethod
0301: : typeApplyMethodProc;
0302: }
0303:
0304: public final ClassType getModuleSuperType(ModuleExp module) {
0305: ClassType sup = module.getSuperType();
0306: return (sup != null ? sup : usingCPStyle() ? typeCallFrame
0307: : generateApplet ? typeApplet
0308: : generateServlet ? typeServlet
0309: : typeModuleBody);
0310: }
0311:
0312: public Interpreter getInterpreter() {
0313: return Interpreter.defaultInterpreter; // For now. FIXME.
0314: }
0315:
0316: public Literal findLiteral(Object value) {
0317: if (value == null)
0318: return Literal.nullLiteral;
0319: Literal literal = (Literal) literalTable.get(value);
0320: if (literal == null) {
0321: if (value instanceof Boolean) {
0322: boolean val = ((Boolean) value).booleanValue();
0323: literal = new Literal(value, val ? trueConstant
0324: : falseConstant, this );
0325: } else if (value == Values.empty)
0326: literal = new Literal(value, voidConstant, this );
0327: else if (value == gnu.lists.LList.Empty)
0328: literal = new Literal(value, emptyConstant, this );
0329: else if (value == gnu.lists.Sequence.eofValue)
0330: literal = new Literal(value, eofConstant, this );
0331: else if (value instanceof Undefined)
0332: literal = new Literal(value, undefinedConstant, this );
0333: else if (immediate) {
0334: literal = new Literal(value, this );
0335: } else {
0336: Type literalType = Type.make(value.getClass());
0337: if (literalType == Type.byte_ctype
0338: || literalType == Type.short_ctype)
0339: literalType = Type.int_ctype;
0340: literal = new Literal(value, literalType, this );
0341: }
0342: }
0343: return literal;
0344: }
0345:
0346: /** Emit code to "evaluate" a compile-time constant.
0347: * This is the normal external interface.
0348: * @param value the value to be compiled
0349: */
0350: public void compileConstant(Object value) {
0351: gnu.bytecode.CodeAttr code = getCode();
0352: if (value == null)
0353: code.emitPushNull();
0354: else if (value instanceof String && !immediate)
0355: code.emitPushString((String) value);
0356: else {
0357: Literal literal = findLiteral(value);
0358: if (literal.field == null)
0359: literal.assign(this );
0360: code.emitGetStatic(literal.field);
0361: }
0362: }
0363:
0364: public void compileConstant(Object value, Target target) {
0365: if (target instanceof IgnoreTarget)
0366: return;
0367: if (target instanceof ConsumerTarget) {
0368: if (value == Values.empty)
0369: return;
0370: // else FIXME
0371: }
0372: if (target instanceof ConditionalTarget) {
0373: ConditionalTarget ctarg = (ConditionalTarget) target;
0374: getCode().emitGoto(
0375: getInterpreter().isTrue(value) ? ctarg.ifTrue
0376: : ctarg.ifFalse);
0377: return;
0378: }
0379: if (target instanceof StackTarget) {
0380: if (value == null) {
0381: getCode().emitPushNull();
0382: return;
0383: }
0384:
0385: Type type = ((StackTarget) target).getType();
0386: if (type instanceof PrimType) {
0387: try {
0388: String signature = type.getSignature();
0389: CodeAttr code = getCode();
0390: char sig1 = (signature == null || signature
0391: .length() != 1) ? ' ' : signature.charAt(0);
0392: if (value instanceof Number) {
0393: Number num = (Number) value;
0394: switch (sig1) {
0395: case 'I':
0396: case 'C':
0397: code.emitPushInt(num.intValue());
0398: return;
0399: case 'S':
0400: code.emitPushInt(num.shortValue());
0401: return;
0402: case 'B':
0403: code.emitPushInt(num.byteValue());
0404: return;
0405: case 'J':
0406: code.emitPushLong(num.longValue());
0407: return;
0408: case 'F':
0409: code.emitPushFloat(num.floatValue());
0410: return;
0411: case 'D':
0412: code.emitPushDouble(num.doubleValue());
0413: return;
0414: }
0415: } else if (value instanceof Character) {
0416: if (sig1 == 'C' || sig1 == 'I' || sig1 == 'J') {
0417: code.emitPushInt(((Character) value)
0418: .charValue());
0419: return;
0420: } else if (sig1 == 'F') {
0421: code.emitPushFloat(((Character) value)
0422: .charValue());
0423: return;
0424: } else if (sig1 == 'D') {
0425: code.emitPushDouble(((Character) value)
0426: .charValue());
0427: return;
0428: }
0429: }
0430: if (sig1 == 'C') {
0431: code.emitPushInt((int) ((PrimType) type)
0432: .charValue(value));
0433: return;
0434: }
0435: if (sig1 == 'Z') {
0436: boolean val = ((PrimType) type)
0437: .booleanValue(value);
0438: code.emitPushBoolean(val);
0439: return;
0440: }
0441: if (sig1 == 'V' && value == Values.empty)
0442: return;
0443: } catch (ClassCastException ex) {
0444: // should print an ERROR.
0445: }
0446: }
0447: try {
0448: value = type.coerceFromObject(value);
0449: } catch (Exception ex) {
0450: if (value != Values.empty)
0451: error('w', "cannot convert literal (of type "
0452: + value.getClass().getName() + ") to "
0453: + type.getName());
0454: }
0455: }
0456: compileConstant(value);
0457: target.compileFromStack(this , value == null ? target.getType()
0458: : Type.make(value.getClass()));
0459: }
0460:
0461: void dumpInitializers(Initializer inits, Method initMethod) {
0462: Method save = method;
0463: method = initMethod;
0464: dumpInitializers(inits);
0465: method = save;
0466: }
0467:
0468: private void dumpInitializers(Initializer inits) {
0469: for (Initializer init = Initializer.reverse(inits); init != null; init = init.next)
0470: init.emit(this );
0471: }
0472:
0473: /** Search this Compilation for a ClassType with a given name.
0474: * @param name the name of the class desired
0475: * @return the matching ClassType, or null if none is found */
0476: public ClassType findNamedClass(String name) {
0477: for (int i = 0; i < numClasses; i++) {
0478: if (name.equals(classes[i].getName()))
0479: return classes[i];
0480: }
0481: return null;
0482: }
0483:
0484: /** If non-null: a prefix for generateClassName to prepend to names. */
0485: public String classPrefix;
0486:
0487: public static String mangleName(String name) {
0488: return mangleName(name, false);
0489: }
0490:
0491: public static String mangleNameIfNeeded(String name) {
0492: if (isValidJavaName(name))
0493: return name;
0494: else
0495: return mangleName(name, true);
0496: }
0497:
0498: public static boolean isValidJavaName(String name) {
0499: int len = name.length();
0500: if (len == 0
0501: || !Character.isJavaIdentifierStart(name.charAt(0)))
0502: return false;
0503: for (int i = len; --i > 0;)
0504: if (!Character.isJavaIdentifierPart(name.charAt(i)))
0505: return false;
0506: return true;
0507: }
0508:
0509: /** Convert a string to a safe Java identifier.
0510: * @param reversible if we should use an invertible mapping. */
0511: public static String mangleName(String name, boolean reversible) {
0512: int len = name.length();
0513: StringBuffer mangled = new StringBuffer(len);
0514: boolean upcaseNext = false;
0515: for (int i = 0; i < len; i++) {
0516: char ch = name.charAt(i);
0517: if (upcaseNext) {
0518: ch = Character.toTitleCase(ch);
0519: upcaseNext = false;
0520: }
0521: if (Character.isDigit(ch)) {
0522: if (i == 0)
0523: mangled.append("$N");
0524: mangled.append(ch);
0525: } else if (Character.isLetter(ch) || ch == '_')
0526: mangled.append(ch);
0527: else if (ch == '$')
0528: mangled.append(reversible ? "$$" : "$");
0529: else {
0530: switch (ch) {
0531: case '+':
0532: mangled.append("$Pl");
0533: break;
0534: case '-':
0535: if (reversible)
0536: mangled.append("$Mn");
0537: else {
0538: char next = i + 1 < len ? name.charAt(i + 1)
0539: : '\0';
0540: if (next == '>') {
0541: mangled.append("$To$");
0542: i++;
0543: } else if (!Character.isLowerCase(next))
0544: mangled.append("$Mn");
0545: }
0546: break;
0547: case '*':
0548: mangled.append("$St");
0549: break;
0550: case '/':
0551: mangled.append("$Sl");
0552: break;
0553: case '=':
0554: mangled.append("$Eq");
0555: break;
0556: case '<':
0557: mangled.append("$Ls");
0558: break;
0559: case '>':
0560: mangled.append("$Gr");
0561: break;
0562: case '@':
0563: mangled.append("$At");
0564: break;
0565: case '~':
0566: mangled.append("$Tl");
0567: break;
0568: case '%':
0569: mangled.append("$Pc");
0570: break;
0571: case '.':
0572: mangled.append("$Dt");
0573: break;
0574: case ',':
0575: mangled.append("$Cm");
0576: break;
0577: case '(':
0578: mangled.append("$LP");
0579: break;
0580: case ')':
0581: mangled.append("$RP");
0582: break;
0583: case '[':
0584: mangled.append("$LB");
0585: break;
0586: case ']':
0587: mangled.append("$RB");
0588: break;
0589: case '{':
0590: mangled.append("$LC");
0591: break;
0592: case '}':
0593: mangled.append("$RC");
0594: break;
0595: case '\'':
0596: mangled.append("$Sq");
0597: break;
0598: case '"':
0599: mangled.append("$Dq");
0600: break;
0601: case '&':
0602: mangled.append("$Am");
0603: break;
0604: case '#':
0605: mangled.append("$Nm");
0606: break;
0607: case '?':
0608: char first = mangled.length() > 0 ? mangled
0609: .charAt(0) : '\0';
0610: if (!reversible && i + 1 == len
0611: && Character.isLowerCase(first)) {
0612: mangled.setCharAt(0, Character
0613: .toTitleCase(first));
0614: mangled.insert(0, "is");
0615: } else
0616: mangled.append("$Qu");
0617: break;
0618: case '!':
0619: mangled.append("$Ex");
0620: break;
0621: case ':':
0622: mangled.append("$Cl");
0623: break;
0624: case ';':
0625: mangled.append("$SC");
0626: break;
0627: case '^':
0628: mangled.append("$Up");
0629: break;
0630: case '|':
0631: mangled.append("$VB");
0632: break;
0633: default:
0634: mangled.append('$');
0635: mangled.append(Character.forDigit((ch >> 12) & 15,
0636: 16));
0637: mangled.append(Character.forDigit((ch >> 8) & 15,
0638: 16));
0639: mangled.append(Character.forDigit((ch >> 4) & 15,
0640: 16));
0641: mangled.append(Character.forDigit((ch) & 15, 16));
0642: }
0643: if (!reversible)
0644: upcaseNext = true;
0645: }
0646: }
0647: String mname = mangled.toString();
0648: return mname.equals(name) ? name : mname;
0649: }
0650:
0651: /** Demangle a three-character mangling starting with '$'.
0652: * UNFINISHED!
0653: */
0654: public static char demangle2(char char1, char char2) {
0655: switch (char1 << 16 | char2) {
0656: case 'A' << 16 | 'm':
0657: return '&';
0658: case 'A' << 16 | 't':
0659: return '@';
0660: case 'C' << 16 | 'l':
0661: return ':';
0662: case 'C' << 16 | 'm':
0663: return ',';
0664: case 'D' << 16 | 'q':
0665: return '\"';
0666: case 'D' << 16 | 't':
0667: return '.';
0668: case 'E' << 16 | 'q':
0669: return '=';
0670: case 'E' << 16 | 'x':
0671: return '!';
0672: case 'G' << 16 | 'r':
0673: return '>';
0674: case 'L' << 16 | 'B':
0675: return '[';
0676: case 'L' << 16 | 'C':
0677: return '{';
0678: case 'L' << 16 | 'P':
0679: return '(';
0680: case 'L' << 16 | 's':
0681: return '<';
0682: case 'M' << 16 | 'c':
0683: return '%';
0684: case 'M' << 16 | 'n':
0685: return '-';
0686: case 'N' << 16 | 'm':
0687: return '#';
0688: case 'P' << 16 | 'c':
0689: return '%';
0690: case 'P' << 16 | 'l':
0691: return '+';
0692: case 'Q' << 16 | 'u':
0693: return '?';
0694: case 'R' << 16 | 'B':
0695: return ']';
0696: case 'R' << 16 | 'C':
0697: return '}';
0698: case 'R' << 16 | 'P':
0699: return ')';
0700: case 'S' << 16 | 'C':
0701: return ';';
0702: case 'S' << 16 | 'l':
0703: return '/';
0704: case 'S' << 16 | 'q':
0705: return '\\';
0706: case 'S' << 16 | 't':
0707: return '*';
0708: case 'T' << 16 | 'l':
0709: return '~';
0710: case 'U' << 16 | 'p':
0711: return '^';
0712: case 'V' << 16 | 'B':
0713: return '|';
0714: }
0715: return (char) (-1);
0716: }
0717:
0718: public static String demangleName(String name) {
0719: return demangleName(name, false);
0720: }
0721:
0722: public static String demangleName(String name, boolean reversible) {
0723: StringBuffer sbuf = new StringBuffer();
0724: int len = name.length();
0725: boolean mangled = false;
0726: boolean predicate = false;
0727: boolean downCaseNext = false;
0728: for (int i = 0; i < len; i++) {
0729: char ch = name.charAt(i);
0730: if (downCaseNext && !reversible) {
0731: ch = Character.toLowerCase(ch);
0732: downCaseNext = false;
0733: }
0734: char d;
0735: if (!reversible && ch == 'i' && i == 0 && len > 2
0736: && name.charAt(i + 1) == 's'
0737: && !Character.isLowerCase(d = name.charAt(i + 2))) {
0738: mangled = true;
0739: predicate = true;
0740: i++;
0741: if (Character.isUpperCase(d)
0742: || Character.isTitleCase(d)) {
0743: sbuf.append(Character.toLowerCase(d));
0744: i++;
0745: continue;
0746: }
0747: continue;
0748: } else if (ch == '$' && i + 2 < len) {
0749: char c1 = name.charAt(i + 1);
0750: char c2 = name.charAt(i + 2);
0751: d = Compilation.demangle2(c1, c2);
0752: if (d != (char) (-1)) {
0753: sbuf.append(d);
0754: i += 2;
0755: mangled = true;
0756: downCaseNext = true;
0757: continue;
0758: } else if (c1 == 'T' && c2 == 'o' && i + 3 < len
0759: && name.charAt(i + 3) == '$') {
0760: sbuf.append("->");
0761: i += 3;
0762: mangled = true;
0763: downCaseNext = true;
0764: continue;
0765: }
0766: } else if (!reversible
0767: && i > 1
0768: && (Character.isUpperCase(ch) || Character
0769: .isTitleCase(ch))
0770: && (Character.isLowerCase(name.charAt(i - 1)))) {
0771: sbuf.append('-');
0772: mangled = true;
0773: ch = Character.toLowerCase(ch);
0774: }
0775: sbuf.append(ch);
0776: }
0777: if (predicate)
0778: sbuf.append('?');
0779: return mangled ? sbuf.toString() : name;
0780: }
0781:
0782: /** Generate an unused class name.
0783: * @param hint the requested name (or prefix)
0784: * @return a unique class name.
0785: */
0786: public String generateClassName(String hint) {
0787: hint = mangleName(hint, true);
0788: if (mainClass != null)
0789: hint = mainClass.getName() + '$' + hint;
0790: else if (classPrefix != null)
0791: hint = classPrefix + hint;
0792: if (findNamedClass(hint) == null)
0793: return hint;
0794: for (int i = 0;; i++) {
0795: String new_hint = hint + i;
0796: if (findNamedClass(new_hint) == null)
0797: return new_hint;
0798: }
0799: }
0800:
0801: /** Generate an unused name.
0802: * @param hint the requested name (or prefix)
0803: * @return a unique class name.
0804: */
0805: public String generateUniqueName(String hint) {
0806: if (currentPackage.findNamedClass(hint) == null)
0807: return hint;
0808: for (int i = 0;; i++) {
0809: String new_hint = hint + i;
0810: if (currentPackage.findNamedClass(new_hint) == null)
0811: return new_hint;
0812: }
0813: }
0814:
0815: String source_filename;
0816:
0817: /** Create a new Compilation environment.
0818: * @param lexp top-level function
0819: * @param classname name of top-level class to generate
0820: * @param prefix prefix to pre-pend to the names of other (non-top) classes
0821: * @param immediate true if the classes will be immediately loaded
0822: */
0823: public Compilation(ModuleExp lexp, String classname, String prefix,
0824: boolean immediate) {
0825: source_filename = lexp.filename;
0826: classPrefix = prefix;
0827: this .immediate = immediate;
0828: mainClass = new ClassType(classname);
0829: mainLambda = lexp;
0830:
0831: // Do various code re-writes and optimization.
0832: PushApply.pushApply(lexp);
0833: InlineCalls.inlineCalls(lexp);
0834: ChainLambdas.chainLambdas(lexp, this );
0835: FindTailCalls.findTailCalls(lexp);
0836: lexp.setCanRead(true);
0837: FindCapturedVars.findCapturedVars(lexp);
0838:
0839: if (debugPrintFinalExpr) {
0840: OutPort dout = OutPort.outDefault();
0841: dout.println("[Compiling final " + lexp.getName()
0842: + " class=" + classname + ':');
0843: lexp.print(dout);
0844: dout.println(']');
0845: dout.flush();
0846: }
0847:
0848: mainClass = addClass(lexp, mainClass);
0849: literalTable = new Hashtable(100);
0850: try {
0851: addClass(lexp);
0852: } catch (RuntimeException ex) {
0853: // Try to produce a localized error message.
0854: error('f', "Internal compiler exception: " + ex);
0855: throw ex;
0856: }
0857: }
0858:
0859: /*
0860: public void addClass (ClassType new_class)
0861: {
0862: if (source_filename != null)
0863: new_class.setSourceFile (source_filename);
0864: if (classes == null)
0865: classes = new ClassType[20];
0866: else if (numClasses >= classes.length)
0867: {
0868: ClassType[] new_classes = new ClassType[2 * classes.length];
0869: System.arraycopy (classes, 0, new_classes, 0, numClasses);
0870: classes = new_classes;
0871: }
0872: classes[numClasses++] = new_class;
0873: new_class.access_flags |= Access.PUBLIC|Access.SUPER;
0874: }
0875: */
0876:
0877: ClassType allocClass(ModuleExp module) {
0878: String name = module.getJavaName();
0879: name = generateClassName(name);
0880: return addClass(module, new ClassType(name));
0881: }
0882:
0883: ClassType addClass(LambdaExp lexp, ClassType type) {
0884: ClassType super Type;
0885: if (lexp.isModuleBody()) {
0886: ModuleExp module = (ModuleExp) lexp;
0887: super Type = getModuleSuperType(module);
0888: ClassType[] interfaces = module.getInterfaces();
0889: if (interfaces != null)
0890: type.setInterfaces(interfaces);
0891: } else
0892: super Type = (usingCPStyle ? typeCallFrame
0893: : lexp.isHandlingTailCalls() ? typeCpsProcedure
0894: : (lexp.min_args != lexp.max_args || lexp.min_args > 4) ? typeProcedureN
0895: : typeProcedureArray[lexp.min_args]);
0896: type.setSuper(super Type);
0897:
0898: lexp.type = type;
0899: addClass(type);
0900: return type;
0901: }
0902:
0903: public final Method getConstructor(LambdaExp lexp) {
0904: return getConstructor(lexp.getHeapFrameType(), lexp);
0905: }
0906:
0907: public static final Method getConstructor(ClassType clas,
0908: LambdaExp lexp) {
0909: Type[] args;
0910: if (lexp instanceof ClassExp && lexp.staticLinkField != null) {
0911: args = new Type[1];
0912: args[0] = lexp.staticLinkField.getType();
0913: } else
0914: args = apply0args;
0915: return clas.addMethod("<init>", Access.PUBLIC, args,
0916: Type.void_type);
0917: }
0918:
0919: public final void generateConstructor(LambdaExp lexp) {
0920: generateConstructor(lexp.getHeapFrameType(), lexp);
0921: }
0922:
0923: public final void generateConstructor(ClassType clas, LambdaExp lexp) {
0924: if (lexp instanceof ClassExp
0925: && !((ClassExp) lexp).needsConstructor)
0926: return;
0927:
0928: Method save_method = method;
0929: ClassType save_class = curClass;
0930: curClass = clas;
0931: Method constructor_method = getConstructor(clas, lexp);
0932: clas.constructor = constructor_method;
0933: constructor_method.eraseCode();
0934:
0935: Method super Constructor = clas.getSuperclass().addMethod(
0936: "<init>", Access.PUBLIC, apply0args, Type.void_type);
0937: method = constructor_method;
0938: constructor_method.init_param_slots();
0939: CodeAttr code = getCode();
0940: code.emitPushThis();
0941: code.emitInvokeSpecial(super Constructor);
0942:
0943: if (lexp instanceof ClassExp && lexp.staticLinkField != null) {
0944: code.emitPushThis();
0945: code.emitLoad(code.getCurrentScope().getVariable(1));
0946: code.emitPutField(lexp.staticLinkField);
0947: }
0948:
0949: Initializer init;
0950: lexp.initChain = Initializer.reverse(lexp.initChain);
0951: while ((init = lexp.initChain) != null) {
0952: lexp.initChain = init.next;
0953: init.emit(this );
0954: }
0955:
0956: if (lexp instanceof ClassExp) {
0957: ClassExp cexp = (ClassExp) lexp;
0958: LambdaExp initMethod = cexp.initMethod;
0959: if (initMethod != null) {
0960: code.emitPushThis();
0961: code.emitInvoke(initMethod.getMainMethod());
0962: }
0963: }
0964:
0965: code.emitReturn();
0966: method = save_method;
0967: curClass = save_class;
0968: }
0969:
0970: /** Generate ModuleBody's apply0 .. applyN methods.
0971: * Use the applyMethods vector, which contains methods that implement
0972: * the (public, readable) methods of the current module. */
0973: public void generateApplyMethods(LambdaExp lexp) {
0974: int numApplyMethods = lexp.applyMethods == null ? 0
0975: : lexp.applyMethods.size();
0976: if (numApplyMethods == 0)
0977: return;
0978: boolean generateApplyMethodContainer = !(curClass
0979: .getSuperclass().isSubtype(typeProcedure));
0980: ClassType procType = getMethodProcType(curClass);
0981: if (Compilation.usingTailCalls)
0982: curClass.addInterface(typeCpsMethodContainer);
0983: else if (generateApplyMethodContainer)
0984: curClass.addInterface(typeApplyMethodContainer);
0985: Method save_method = method;
0986: CodeAttr code = null;
0987: for (int i = Compilation.usingTailCalls ? 5 : 0; i < 6; i++) {
0988: // If i < 5, generate the method named ("apply"+i);
0989: // else generate "applyN".
0990: boolean needThisApply = false;
0991: SwitchState aswitch = null;
0992: String mname = null;
0993: Type[] applyArgs = null;
0994:
0995: for (int j = numApplyMethods; --j >= 0;) {
0996: LambdaExp source = (LambdaExp) lexp.applyMethods
0997: .elementAt(j);
0998: int min_args = source.min_args;
0999: if (source.isClassMethod())
1000: min_args++;
1001: // Select the subset of source.primMethods[*] that are suitable
1002: // for the current apply method.
1003: Method[] primMethods = source.primMethods;
1004: int numMethods = primMethods.length;
1005: boolean varArgs = source.max_args < 0
1006: || Compilation.usingTailCalls
1007: || source.max_args >= min_args + numMethods;
1008: int methodIndex;
1009: boolean skipThisProc = false;
1010: if (i < 5) // Handling apply0 .. apply4
1011: {
1012: methodIndex = i - min_args;
1013: if (methodIndex < 0
1014: || methodIndex >= numMethods
1015: || (methodIndex == numMethods - 1 && varArgs))
1016: skipThisProc = true;
1017: numMethods = 1;
1018: varArgs = false;
1019: } else // Handling applyN
1020: {
1021: methodIndex = 5 - min_args;
1022: if (methodIndex > 0 && numMethods <= methodIndex
1023: && !varArgs)
1024: skipThisProc = true;
1025: methodIndex = numMethods - 1;
1026: }
1027: if (skipThisProc && !generateApplyMethodContainer)
1028: continue;
1029: if (!needThisApply) {
1030: // First LambdaExp we seen suitable for this i.
1031: if (i < 5) {
1032: mname = "apply" + i;
1033: applyArgs = new Type[i + 1];
1034: for (int k = i; k > 0; k--)
1035: applyArgs[k] = typeObject;
1036: } else if (Compilation.usingTailCalls) {
1037: mname = "apply";
1038: applyArgs = new Type[2];
1039: applyArgs[1] = typeCallContext;
1040: } else {
1041: mname = "applyN";
1042: applyArgs = new Type[2];
1043: applyArgs[1] = objArrayType;
1044: }
1045: applyArgs[0] = procType;
1046: method = curClass
1047: .addMethod(
1048: mname,
1049: applyArgs,
1050: Compilation.usingTailCalls ? (Type) Type.void_type
1051: : (Type) Type.pointer_type,
1052: Access.PUBLIC);
1053: method.init_param_slots();
1054: code = getCode();
1055:
1056: code.emitLoad(code.getArg(1)); // method
1057: code.emitGetField(procType
1058: .getDeclaredField("selector"));
1059: aswitch = new SwitchState(code);
1060:
1061: needThisApply = true;
1062: }
1063: if (skipThisProc && generateApplyMethodContainer)
1064: continue;
1065:
1066: aswitch.addCase(source.getSelectorValue(this ), code);
1067:
1068: Method primMethod = primMethods[methodIndex];
1069: Type[] primArgTypes = primMethod.getParameterTypes();
1070: int nargs = primArgTypes.length;
1071: int singleArgs = varArgs ? (nargs - 1) : nargs;
1072: Variable counter = null;
1073: int pendingIfEnds = 0;
1074:
1075: if (i > 4 && numMethods > 1) {
1076: counter = code.addLocal(Type.int_type);
1077: code.emitLoad(code.getArg(2));
1078: code.emitArrayLength();
1079: if (min_args != 0) {
1080: code.emitPushInt(min_args);
1081: code.emitSub(Type.int_type);
1082: }
1083: code.emitStore(counter);
1084: }
1085:
1086: int argumentStart = 2;
1087:
1088: if (source.getNeedsClosureEnv())
1089: code.emitPushThis();
1090:
1091: if (source.isClassMethod()) {
1092: code.emitLoad(code.getArg(argumentStart++));
1093: Type ptype = primMethod.getDeclaringClass();
1094: ptype.emitCoerceFromObject(code);
1095: }
1096:
1097: Declaration var = source.firstDecl();
1098: for (int k = 0; k < singleArgs; k++) {
1099: if (counter != null && k >= min_args) {
1100: code.emitLoad(counter);
1101: code.emitIfIntLEqZero();
1102: code.emitInvoke(primMethods[k - min_args]);
1103: code.emitElse();
1104: pendingIfEnds++;
1105: code.emitInc(counter, (short) (-1));
1106: }
1107:
1108: if (i > 4) // applyN method
1109: {
1110: // Load Object[]args value:
1111: code.emitLoad(code.getArg(2));
1112: code.emitPushInt(k);
1113: code.emitArrayLoad(Type.pointer_type);
1114: } else
1115: // apply'i method
1116: code.emitLoad(code.getArg(k + argumentStart));
1117: Type ptype = var.getType();
1118: if (ptype != Type.pointer_type)
1119: StackTarget.convert(this , Type.pointer_type,
1120: ptype);
1121: var = var.nextDecl();
1122: }
1123:
1124: if (varArgs) {
1125: Type lastArgType = primArgTypes[singleArgs];
1126: if (lastArgType instanceof ArrayType) {
1127: Type elType = ((ArrayType) lastArgType)
1128: .getComponentType();
1129: boolean mustConvert = !"java.lang.Object"
1130: .equals(elType.getName());
1131: if (singleArgs == 0 && !mustConvert)
1132: code.emitLoad(code.getArg(2)); // load args array.
1133: else {
1134: code.pushScope();
1135: if (counter == null) {
1136: counter = code.addLocal(Type.int_type);
1137: code.emitLoad(code.getArg(2));
1138: code.emitArrayLength();
1139: if (singleArgs != 0) {
1140: code.emitPushInt(singleArgs);
1141: code.emitSub(Type.int_type);
1142: }
1143: code.emitStore(counter);
1144: }
1145: code.emitLoad(counter);
1146: code.emitNewArray(elType);
1147: Label testLabel = new Label(code);
1148: code.emitGoto(testLabel);
1149: Label loopTopLabel = new Label(code);
1150: loopTopLabel.define(code);
1151:
1152: code.emitDup(1); // new array
1153: code.emitLoad(counter);
1154: code.emitLoad(code.getArg(2));
1155: code.emitLoad(counter);
1156: if (singleArgs != 0) {
1157: code.emitPushInt(singleArgs);
1158: code.emitAdd(Type.int_type);
1159: }
1160: code.emitArrayLoad(Type.pointer_type);
1161: if (mustConvert) {
1162: CheckedTarget.emitCheckedCoerce(this ,
1163: source, source.getName(), -1,
1164: elType);
1165: }
1166: code.emitArrayStore(elType);
1167: testLabel.define(code);
1168: code.emitInc(counter, (short) (-1));
1169: code.emitLoad(counter);
1170: code.emitGotoIfIntGeZero(loopTopLabel);
1171: code.popScope();
1172: }
1173: } else if ("gnu.lists.LList".equals(lastArgType
1174: .getName())) {
1175: code.emitLoad(code.getArg(2)); // load args array.
1176: code.emitPushInt(singleArgs);
1177: code
1178: .emitInvokeStatic(Compilation.makeListMethod);
1179: } else if (lastArgType == typeCallContext)
1180: code.emitLoad(code.getArg(2));
1181: else
1182: throw new RuntimeException(
1183: "unsupported #!rest type:"
1184: + lastArgType);
1185: }
1186:
1187: code.emitInvoke(primMethod);
1188: while (--pendingIfEnds >= 0)
1189: code.emitFi();
1190: if (!usingTailCalls)
1191: Target.pushObject.compileFromStack(this , source
1192: .getReturnType());
1193: code.emitReturn();
1194: }
1195: if (false && needThisApply) {
1196: aswitch.addDefault(code);
1197: if (usingTailCalls) {
1198: code.emitLoad(code.getArg(1));
1199: Method errMethod = typeCpsMethodProc
1200: .getDeclaredMethod("applyError", 0);
1201: code.emitInvokeVirtual(errMethod);
1202: } else {
1203: int nargs = i > 4 ? 2 : i + 1;
1204: nargs++;
1205: for (int k = generateApplyMethodContainer ? 1 : 0; k < nargs; k++)
1206: code.emitLoad(code.getArg(k));
1207: if (generateApplyMethodContainer) {
1208: mname = mname + "Default";
1209: Method defMethod = typeApplyMethodProc
1210: .getDeclaredMethod(mname, applyArgs);
1211: code.emitInvokeStatic(defMethod);
1212: } else {
1213: code.emitInvokeSpecial(curClass.getSuperclass()
1214: .getDeclaredMethod(mname, applyArgs));
1215: }
1216: }
1217: code.emitReturn();
1218: aswitch.finish(code);
1219: } else if (needThisApply) {
1220: aswitch.finish(code);
1221: }
1222: }
1223: lexp.applyMethods = null;
1224: method = save_method;
1225: }
1226:
1227: private Method startClassInit() {
1228: method = curClass.addMethod("<clinit>", apply0args,
1229: Type.void_type, Access.PUBLIC | Access.STATIC);
1230: method.init_param_slots();
1231:
1232: CodeAttr code = getCode();
1233:
1234: if (generateMain || generateApplet || generateServlet) {
1235: ClassType interpreterType = (ClassType) Type
1236: .make(getInterpreter().getClass());
1237: Method registerMethod = interpreterType.getDeclaredMethod(
1238: "registerEnvironment", 0);
1239: if (registerMethod != null)
1240: code.emitInvokeStatic(registerMethod);
1241: }
1242: return method;
1243: }
1244:
1245: /** Compiles a module to a class. */
1246: public final ClassType addClass(ModuleExp module) {
1247: String name;
1248: ClassType new_class = module.type;
1249: if (new_class == typeProcedure)
1250: new_class = allocClass(module);
1251: curClass = new_class;
1252:
1253: String filename = module.getFile();
1254: module.type = new_class;
1255: if (filename != null)
1256: new_class.setSourceFile(filename);
1257:
1258: int arg_count;
1259: char arg_letter;
1260: LambdaExp saveLambda = curLambda;
1261: curLambda = module;
1262: Type[] arg_types;
1263: if (module.isHandlingTailCalls() || usingCPStyle()) {
1264: arg_count = 1;
1265: arg_letter = '?';
1266: arg_types = new Type[1];
1267: arg_types[0] = typeCallContext;
1268: } else if (module.min_args != module.max_args
1269: || module.min_args > 4
1270: || (fewerClasses && curClass == mainClass)) {
1271: arg_count = 1;
1272: arg_letter = 'N';
1273: arg_types = new Type[1];
1274: arg_types[0] = new ArrayType(typeObject);
1275: } else {
1276: arg_count = module.min_args;
1277: arg_letter = Character.forDigit(arg_count, 10);
1278: arg_types = new Type[arg_count];
1279: for (int i = arg_count; --i >= 0;)
1280: arg_types[i] = typeObject;
1281: }
1282:
1283: CodeAttr code;
1284: if (arg_letter == 'N' || arg_letter == '?') {
1285: method = curClass.addMethod("numArgs", apply0args,
1286: Type.int_type, Access.PUBLIC);
1287: method.init_param_slots();
1288: code = getCode();
1289: code.emitPushInt(module.min_args | (module.max_args << 12));
1290: code.emitReturn();
1291: }
1292:
1293: Expression body = module.body;
1294: Variable heapFrame = module.heapFrame;
1295:
1296: Method apply_method;
1297: boolean staticModule = false;
1298: Label classInitLabel = null;
1299: Label classBodyLabel = null;
1300:
1301: if (usingCPStyle()) {
1302: apply_method = curClass.addMethod("step", arg_types,
1303: Type.void_type, Access.PUBLIC | Access.FINAL);
1304: } else if (module.isHandlingTailCalls()) {
1305: apply_method = curClass.addMethod("apply", arg_types,
1306: Type.void_type, Access.PUBLIC | Access.FINAL);
1307: } else {
1308: staticModule = true;
1309: generateConstructor(module);
1310: instanceField = curClass.addField("$instance", curClass,
1311: Access.STATIC | Access.FINAL);
1312: apply_method = startClassInit();
1313: code = getCode();
1314: code.emitNew(curClass);
1315: code.emitDup(curClass);
1316: code.emitInvokeSpecial(curClass.constructor);
1317: code.emitPutStatic(instanceField);
1318:
1319: classInitLabel = new Label(code);
1320: classBodyLabel = new Label(code);
1321: code.emitGoto(classInitLabel);
1322: classBodyLabel.define(code);
1323: }
1324: method = apply_method;
1325:
1326: // For each parameter, assign it to its proper slot.
1327: // If a parameter !isSimple(), we cannot assign it to a local slot,
1328: // so instead create an artificial Variable for the incoming argument.
1329: // Below, we assign the value to the slot.
1330: method.initCode();
1331: code = getCode();
1332: // if (usingCPStyle()) code.addParamLocals();
1333:
1334: this Decl = method.getStaticFlag() ? null : module
1335: .declareThis(new_class);
1336: module.closureEnv = module.this Variable;
1337: module.heapFrame = module.this Variable;
1338: module.allocChildClasses(this );
1339:
1340: if (module.isHandlingTailCalls() || usingCPStyle()) {
1341: callStackContext = new Variable("$ctx", typeCallContext);
1342: Scope scope = module.scope;
1343: scope.addVariableAfter(this Decl, callStackContext);
1344: callStackContext.setParameter(true);
1345: callStackContext.setArtificial(true);
1346: }
1347:
1348: int line = module.getLine();
1349: if (line > 0)
1350: code.putLineNumber(module.getFile(), line);
1351:
1352: /*
1353: if (arg_letter == 'N')
1354: {
1355: argsArray.reserveLocal(1, code); // FIXME
1356:
1357: if (true) // If generating code to check number of arguments
1358: {
1359: code.emitPushThis();
1360: code.emitLoad(argsArray);
1361: code.emitArrayLength();
1362: code.emitInvokeStatic(checkArgCountMethod);
1363: }
1364: }
1365: */
1366:
1367: module.allocParameters(this );
1368: module.enterFunction(this );
1369: if (usingCPStyle()) {
1370: //code.emitLoad(code.getArg(1));
1371: code.emitLoad(callStackContext);
1372: code.emitGetField(pcCallContextField);
1373: fswitch = new SwitchState(code);
1374: Label l = new Label(code);
1375: l.define(code);
1376: fswitch.addCase(0, l, code);
1377: }
1378:
1379: try {
1380: module.compileBody(this );
1381: } catch (Exception ex) {
1382: error('f', "internal error while compiling - caught: " + ex);
1383: ex.printStackTrace(System.err);
1384: System.exit(-1);
1385: }
1386: module.compileEnd(this );
1387:
1388: if (Compilation.fewerClasses) // FIXME
1389: method.popScope(); // Undoes pushScope in method.initCode.
1390:
1391: module.heapFrame = heapFrame; // Restore heapFrame.
1392: module.compileChildMethods(this );
1393: if (usingCPStyle() || (fewerClasses && curClass == mainClass)) {
1394: code = getCode();
1395: fswitch.finish(code);
1396: }
1397:
1398: if (Compilation.usingTailCalls && !staticModule)
1399: generateConstructor(module);
1400:
1401: if (curClass == mainClass // && ! immediate
1402: && (staticModule || clinitChain != null
1403: || literalsChain != null || generateMain
1404: || generateApplet || generateServlet)) {
1405: Method save_method = method;
1406:
1407: if (staticModule)
1408: classInitLabel.define(code);
1409: else
1410: startClassInit();
1411: code = getCode();
1412: if (clinitChain != null) {
1413: Label lab0 = new Label(code);
1414: Label lab1 = new Label(code);
1415: Label lab2 = new Label(code);
1416: // These gotos are losing. Should instead do a pre-pass (using
1417: // an ExpWalker) before compilation that collects all needed
1418: // constants. Then we generate code to init the literals *first*,
1419: // before compiling anything else. FIXME.
1420: code.emitGoto(lab1);
1421: lab0.define(code);
1422: dumpInitializers(clinitChain);
1423: code.emitGoto(lab2);
1424: lab1.define(code);
1425: Literal.emit(this );
1426: code.emitGoto(lab0);
1427: lab2.define(code);
1428: } else
1429: Literal.emit(this );
1430:
1431: if (staticModule)
1432: code.emitGoto(classBodyLabel);
1433: else
1434: code.emitReturn();
1435: method = save_method;
1436: }
1437:
1438: curLambda = saveLambda;
1439:
1440: if (generateMain && curClass == mainClass) {
1441: Type[] args = { new ArrayType(javaStringType) };
1442: method = curClass.addMethod("main", Access.PUBLIC
1443: | Access.STATIC, args, Type.void_type);
1444:
1445: method.init_param_slots();
1446: code = getCode();
1447: code.emitNew(curClass);
1448: code.emitDup(curClass);
1449: code.emitInvokeSpecial(curClass.constructor);
1450: code.emitLoad(code.getArg(0));
1451: Method moduleMain = typeModuleBody.addMethod("runAsMain",
1452: Access.PUBLIC, args, Type.void_type);
1453: code.emitInvokeVirtual(moduleMain);
1454: code.emitReturn();
1455: }
1456:
1457: return new_class;
1458: }
1459:
1460: public static boolean usingCPStyle() {
1461: return usingCPStyle;
1462: }
1463:
1464: public boolean usingTailCalls() {
1465: return usingTailCalls;
1466: }
1467:
1468: int localFieldIndex;
1469:
1470: public Field allocLocalField(Type type, String name) {
1471: if (name == null)
1472: name = "tmp_" + (++localFieldIndex);
1473: Field field = curClass.addField(name, type, 0);
1474: return field;
1475: }
1476:
1477: /** Generate code to push the current CallContext on the JVM stack.
1478: * Assumes that callStackContext has been set for the current function.
1479: * (Later we should call a routine to get it via the current thread.) */
1480: public final void loadCallContext() {
1481: getCode().emitLoad(callStackContext);
1482: }
1483:
1484: public void freeLocalField(Field field) {
1485: // FIXME
1486: }
1487:
1488: String filename;
1489: int position;
1490:
1491: public void error(char severity, String message) {
1492: error(severity, filename, position >> 12, position
1493: & ((1 << 12) - 1), message);
1494: }
1495:
1496: public void error(char severity, String filename, int line,
1497: int column, String message) {
1498: error(new gnu.text.SourceError(severity, filename, line,
1499: column, message));
1500: }
1501:
1502: public void error(gnu.text.SourceError err) {
1503: // FIXME - use SourceMessages framework!
1504: System.err.println(err);
1505: }
1506:
1507: /****************************************************************
1508: * Compilation of Packages
1509: ****************************************************************/
1510:
1511: public Compilation() {
1512: this .immediate = false;
1513: }
1514:
1515: Package currentPackage;
1516:
1517: public void compile(Package root) {
1518: for (Package pkg = root; pkg != null; pkg = pkg.next)
1519: allocate(pkg);
1520:
1521: for (Package pkg = root; pkg != null; pkg = pkg.next)
1522: generate(pkg);
1523: }
1524:
1525: public void allocate(Package pkg) {
1526: currentPackage = pkg;
1527:
1528: classPrefix = pkg.name == null ? "" : pkg.name + ".";
1529:
1530: // Do various code re-writes and optimization.
1531: //PushApply.pushApply(pkg);
1532: //InlineCalls.inlineCalls(pkg);
1533: ChainLambdas.chainLambdas(pkg, this );
1534: FindTailCalls.findTailCalls(pkg);
1535: FindCapturedVars.findCapturedVars(pkg);
1536:
1537: for (LambdaExp c = pkg.firstClass; c != null; c = c.nextSibling)
1538: ((ClassExp) c).declareParts(this );
1539: }
1540:
1541: /** Create a new Compilation environment.
1542: * @param pkg the package to compile
1543: */
1544: public void generate(Package pkg) {
1545: currentPackage = pkg;
1546:
1547: source_filename = pkg.directory.getPath();
1548: classPrefix = pkg.name + ".";
1549:
1550: try {
1551: compileAll(pkg);
1552: } catch (RuntimeException ex) {
1553: // Rethrow the error, since it is better handled at the Nice level.
1554: if (true)
1555: throw ex;
1556:
1557: // Try to produce a localized error message.
1558: error('f', "Internal compiler exception: " + ex);
1559: throw ex;
1560: }
1561: }
1562:
1563: /** Compiles a module to a class. */
1564: private final void compileAll(Package pkg) {
1565: for (LambdaExp c = pkg.firstClass; c != null; c = c.nextSibling) {
1566: literalTable = new Hashtable(100);
1567: c.literalTable = literalTable;
1568: topLambda = c;
1569: // If the class has outer set, use that as the toplevel class.
1570: if (c.outer != null)
1571: topLambda = (LambdaExp) c.outer;
1572: topClass = (ClassType) topLambda.getType();
1573: c.compileChildMethods(this );
1574: }
1575:
1576: for (LambdaExp c = pkg.firstClass; c != null; c = c.nextSibling) {
1577: topLambda = c;
1578: // If the class has outer set, use that as the toplevel class.
1579: if (c.outer != null)
1580: topLambda = (LambdaExp) c.outer;
1581: literalTable = c.literalTable;
1582: topClass = (ClassType) topLambda.getType();
1583:
1584: curClass = topClass;
1585: c.generateClassInit(this );
1586: generateApplyMethods(c);
1587: }
1588: }
1589:
1590: public LambdaExp topLambda;
1591: ClassType topClass;
1592:
1593: public void addClass(ClassType new_class) {
1594: currentPackage.addClass(new_class);
1595: new_class.access_flags |= Access.PUBLIC;
1596: }
1597: }
|