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.Vector;
0009:
0010: /**
0011: * Class used to implement Scheme lambda expressions.
0012: * @author Per Bothner
0013: */
0014:
0015: public class LambdaExp extends ScopeExp {
0016: public String name;
0017: public Expression body;
0018: public int min_args;
0019: // Maximum number of actual arguments; -1 if variable.
0020: public int max_args;
0021:
0022: /** Set of visible top-level LambdaExps that need apply methods. */
0023: Vector applyMethods;
0024:
0025: // public int plainArgs;
0026: Variable argsArray;
0027: // First argument that goes into argsArray.
0028: private Declaration firstArgsArrayArg;
0029:
0030: public Keyword[] keywords;
0031: public Expression[] defaultArgs;
0032:
0033: public java.util.Stack[] parameterCopies;
0034:
0035: static int counter;
0036: /** Unique id number, to ease print-outs and debugging. */
0037: int id = ++counter;
0038:
0039: /** A list of Declarations, chained using Declaration's nextCapturedVar.
0040: * All the Declarations are allocated in the current heapFrame. */
0041: Declaration capturedVars;
0042:
0043: /** A local variable that points to the heap-allocated part of the frame.
0044: * Each captured variable is a field in the heapFrame. A procedure has
0045: * a heapFrame iff it has a parameter or local variable that is
0046: * referenced ("captured") by a non-inline inferior procedure.
0047: * (I.e there is a least one non-inline procedure that encloses the
0048: * reference but not the definition.) Note that an inline procedure may
0049: * have a heapFrame if it encloses a non-inline procedure. This is
0050: * necessary because we represent loops as tail-recursive inline procedures.
0051: */
0052: Variable heapFrame;
0053:
0054: public LambdaExp firstChild;
0055: public LambdaExp nextSibling;
0056:
0057: /** A magic value to indicate there is no unique return continuation. */
0058: final static ApplyExp unknownContinuation = new ApplyExp(
0059: (Expression) null, null);
0060:
0061: /** The unique caller that calls this lambda.
0062: The value is null, if no callers have been seen.
0063: A value of unknownContinuation means there are multiple call sites.
0064: Tail-recursive calls do not count as multiple call sites. (With a
0065: little more analysis, we could also allow multiple non-self tail-calls
0066: as long as they all are ultimately called from the same place.)
0067: This is used to see if we can inline the function at its unique
0068: call site. */
0069: public ApplyExp returnContinuation;
0070:
0071: public void forceGeneration() {
0072: returnContinuation = unknownContinuation;
0073: }
0074:
0075: /** If non-null, a Declaration whose value is (only) this LambdaExp. */
0076: public Declaration nameDecl;
0077:
0078: /** If non-null, this is a Field that is used for implementing lexical closures.
0079: * If getName() is "closureEnv", it is our parent's heapFrame,
0080: * which is an instance of one of our siblings.
0081: * (Otherwise, we use "this" as the implicit "closureEnv" field.) */
0082: public Field closureEnvField;
0083:
0084: /** Field in heapFrame.getType() that contains the static link.
0085: * It is used by child functions to get to outer environments.
0086: * Its value is this function's closureEnv value. */
0087: public Field staticLinkField;
0088:
0089: /** A variable that points to the closure environment passed in.
0090: * It can be any one of:
0091: * null, if no closure environment is needed;
0092: * this, if this object is its parent's heapFrame;
0093: * a local variable initialized from this.closureEnv;
0094: * a parameter (only if !getCanRead()); or
0095: * a copy of our caller's closureEnv or heapFrame (only if getInlineOnly()).
0096: * See declareClosureEnv and closureEnvField. */
0097: Variable closureEnv;
0098:
0099: static final int INLINE_ONLY = 1;
0100: static final int CAN_READ = 2;
0101: static final int CAN_CALL = 4;
0102: static final int IMPORTS_LEX_VARS = 8;
0103: static final int NEEDS_STATIC_LINK = 16;
0104: /* Used (future) by FindTailCalls. */
0105: static final int CANNOT_INLINE = 32;
0106: static final int CLASS_METHOD = 64;
0107: static final int METHODS_COMPILED = 128;
0108: static final int NO_FIELD = 256;
0109: static final int DEFAULT_CAPTURES_ARG = 512;
0110: public static final int SEQUENCE_RESULT = 1024;
0111: protected static final int NEXT_AVAIL_FLAG = 2048;
0112:
0113: /** True iff this lambda is only "called" inline. */
0114: public final boolean getInlineOnly() {
0115: return (flags & INLINE_ONLY) != 0;
0116: }
0117:
0118: public final void setInlineOnly(boolean inlineOnly) {
0119: setFlag(inlineOnly, INLINE_ONLY);
0120: }
0121:
0122: public final boolean getNeedsClosureEnv() {
0123: return (flags & (NEEDS_STATIC_LINK | IMPORTS_LEX_VARS)) != 0;
0124: }
0125:
0126: /** True if a child lambda uses lexical variables from outside.
0127: Hence, a child heapFrame needs a staticLink to outer frames. */
0128: public final boolean getNeedsStaticLink() {
0129: return (flags & NEEDS_STATIC_LINK) != 0;
0130: }
0131:
0132: public final void setNeedsStaticLink(boolean needsStaticLink) {
0133: if (needsStaticLink)
0134: flags |= NEEDS_STATIC_LINK;
0135: else
0136: flags &= ~NEEDS_STATIC_LINK;
0137: }
0138:
0139: /** True iff this lambda "captures" (uses) lexical variables from outside. */
0140: public final boolean getImportsLexVars() {
0141: return (flags & IMPORTS_LEX_VARS) != 0;
0142: }
0143:
0144: public final void setImportsLexVars(boolean importsLexVars) {
0145: if (importsLexVars)
0146: flags |= IMPORTS_LEX_VARS;
0147: else
0148: flags &= ~IMPORTS_LEX_VARS;
0149: }
0150:
0151: public final void setImportsLexVars() {
0152: int old = flags;
0153: flags |= IMPORTS_LEX_VARS;
0154:
0155: // If this needs an environment (closure), then its callers do too.
0156: if ((old & IMPORTS_LEX_VARS) == 0 && nameDecl != null)
0157: setCallersNeedStaticLink();
0158: }
0159:
0160: public final void setNeedsStaticLink() {
0161: int old = flags;
0162: flags |= NEEDS_STATIC_LINK;
0163:
0164: // If this needs an environment (closure), then its callers do too.
0165: if ((old & NEEDS_STATIC_LINK) == 0 && nameDecl != null)
0166: setCallersNeedStaticLink();
0167: }
0168:
0169: void setCallersNeedStaticLink() {
0170: LambdaExp outer = outerLambda();
0171: for (ApplyExp app = nameDecl.firstCall; app != null; app = app.nextCall) {
0172: LambdaExp caller = app.context;
0173: for (; caller != outer; caller = caller.outerLambda())
0174: caller.setNeedsStaticLink();
0175: }
0176: }
0177:
0178: public final boolean getCanRead() {
0179: return (flags & CAN_READ) != 0;
0180: }
0181:
0182: public final void setCanRead(boolean read) {
0183: if (read)
0184: flags |= CAN_READ;
0185: else
0186: flags &= ~CAN_READ;
0187: }
0188:
0189: public final boolean getCanCall() {
0190: return (flags & CAN_CALL) != 0;
0191: }
0192:
0193: public final void setCanCall(boolean called) {
0194: if (called)
0195: flags |= CAN_CALL;
0196: else
0197: flags &= ~CAN_CALL;
0198: }
0199:
0200: /** True if this is a method in an ClassExp. */
0201: public final boolean isClassMethod() {
0202: return (flags & CLASS_METHOD) != 0;
0203: }
0204:
0205: public final void setClassMethod(boolean isMethod) {
0206: if (isMethod)
0207: flags |= CLASS_METHOD;
0208: else
0209: flags &= ~CLASS_METHOD;
0210: }
0211:
0212: /** The name to give to a dummy implicit function that surrounds a file. */
0213: public static String fileFunctionName = "atFileLevel";
0214:
0215: /** True iff this is the dummy top-level function of a module body. */
0216: public final boolean isModuleBody() {
0217: return this instanceof ModuleExp;
0218: }
0219:
0220: /** True if a class is generated for this procedure.
0221: * We don't need a class if this is only called inline.
0222: * We also don't need a class if all callers are known, and we can
0223: * invoke a method for this procedure.
0224: * However, the last optimization is not available when using tail calls.
0225: */
0226: public final boolean isClassGenerated() {
0227: return (!getInlineOnly() && (isModuleBody() || this instanceof ClassExp));
0228: }
0229:
0230: public final boolean isHandlingTailCalls() {
0231: return (isModuleBody() && !((ModuleExp) this ).isStatic())
0232: || (Compilation.usingTailCalls && !isModuleBody() && !isClassMethod());
0233: }
0234:
0235: public final boolean variable_args() {
0236: return max_args < 0;
0237: }
0238:
0239: ClassType type = Compilation.typeProcedure;
0240:
0241: /** Return the ClassType of the Procedure this is being compiled into. */
0242: public ClassType getCompiledClassType(Compilation comp) {
0243: if (type == Compilation.typeProcedure)
0244: throw new Error("internal error: getCompiledClassType");
0245: return type;
0246: }
0247:
0248: public Type getType() {
0249: return type;
0250: }
0251:
0252: public Type[] getArgTypes() {
0253: Type[] res = new Type[max_args];
0254: int n = 0;
0255: for (Declaration d = firstDecl(); d != null; d = d.nextDecl())
0256: res[n++] = d.getType();
0257: return res;
0258: }
0259:
0260: /** Number of argument variable actually passed by the caller.
0261: * For functions that accept more than 4 argument, or take a variable number,
0262: * this is 1, since in that all arguments are passed in a single array. */
0263: public int incomingArgs() {
0264: // The max_args > 0 is a hack to handle LambdaProecdure, which
0265: // currently always uses a single array argument.
0266: return min_args == max_args && max_args <= 4 && max_args > 0 ? max_args
0267: : 1;
0268: }
0269:
0270: /** If non-zero, the selector field of the ModuleMethod for this. */
0271: int selectorValue;
0272:
0273: int getSelectorValue(Compilation comp) {
0274: if (selectorValue == 0)
0275: selectorValue = ++comp.maxSelectorValue;
0276: return selectorValue;
0277: }
0278:
0279: /** Methods used to implement this functions.
0280: * primMethods[0] is used if the argument count is min_args;
0281: * primMethods[1] is used if the argument count is min_args+1;
0282: * primMethods[primMethods.length-1] is used otherwise.
0283: */
0284: Method[] primMethods;
0285:
0286: /** Select the method used given an argument count. */
0287: public final Method getMethod(int argCount) {
0288: if (primMethods == null
0289: || (max_args >= 0 && argCount > max_args))
0290: return null;
0291: int index = argCount - min_args;
0292: if (index < 0)
0293: return null; // Too few arguments.
0294: int length = primMethods.length;
0295: return primMethods[index < length ? index : length - 1];
0296: }
0297:
0298: /** Get the method that contains the actual body of the procedure.
0299: * (The other methods are just stubs that call that method.) */
0300: public Method getMainMethod() {
0301: Method[] methods = primMethods;
0302: return methods == null ? null : methods[methods.length - 1];
0303: }
0304:
0305: /** Return the parameter type of the "keyword/rest" parameters. */
0306: public final Type restArgType() {
0307: if (min_args == max_args)
0308: return null;
0309: if (primMethods == null)
0310: throw new Error("internal error - restArgType");
0311: Method[] methods = primMethods;
0312: if (max_args >= 0 && methods.length > max_args - min_args)
0313: return null;
0314: Type[] types = methods[methods.length - 1].getParameterTypes();
0315: return types[types.length - 1];
0316: }
0317:
0318: public void setName(String name) {
0319: this .name = name;
0320: }
0321:
0322: public String getName() {
0323: return name;
0324: }
0325:
0326: public LambdaExp outerLambda() {
0327: return outer == null ? null : outer.currentLambda();
0328: }
0329:
0330: /** Return the closest outer non-inlined LambdaExp. */
0331:
0332: public LambdaExp outerLambdaNotInline() {
0333: for (ScopeExp exp = this ; (exp = exp.outer) != null;) {
0334: if (exp instanceof LambdaExp) {
0335: LambdaExp result = (LambdaExp) exp;
0336: if (!result.getInlineOnly())
0337: return result;
0338: }
0339: }
0340: return null;
0341: }
0342:
0343: /** Return the englobing ClassExp or null. */
0344:
0345: public ClassExp outerClass() {
0346: for (ScopeExp exp = this ; exp != null; exp = exp.outer) {
0347: if (exp instanceof ClassExp)
0348: return (ClassExp) exp;
0349: }
0350: return null;
0351: }
0352:
0353: /** For an INLINE_ONLY function, return the function it gets inlined in. */
0354: public LambdaExp getCaller() {
0355: return returnContinuation.context;
0356: }
0357:
0358: Variable this Variable;
0359:
0360: public Variable declareThis(ClassType clas) {
0361: if (this Variable == null) {
0362: this Variable = new Variable("this");
0363: scope.addVariableAfter(null, this Variable);
0364: this Variable.setParameter(true);
0365: this Variable.setArtificial(true);
0366: }
0367: if (this Variable.getType() == null)
0368: this Variable.setType(clas);
0369: return this Variable;
0370: }
0371:
0372: public Variable declareClosureEnv() {
0373: if (closureEnv == null && getNeedsClosureEnv()) {
0374: LambdaExp parent = outerLambda();
0375: if (parent instanceof ClassExp)
0376: parent = parent.outerLambda();
0377: Variable parentFrame = parent.heapFrame != null ? parent.heapFrame
0378: : parent.closureEnv;
0379: if (isClassMethod())
0380: /*closureEnv =*/declareThis(type);
0381: else if (parent.heapFrame == null
0382: && !parent.getNeedsStaticLink()
0383: && !(parent instanceof ModuleExp))
0384: closureEnv = null;
0385: else if (!isClassGenerated() && !getInlineOnly()) {
0386: Method primMethod = getMainMethod();
0387: if (!primMethod.getStaticFlag())
0388: /*closureEnv =*/declareThis(primMethod
0389: .getDeclaringClass());
0390: else {
0391: Type envType = primMethod.getParameterTypes()[0];
0392: closureEnv = new Variable("closureEnv", envType);
0393: scope.addVariableAfter(null, closureEnv);
0394: closureEnv.setArtificial(true);
0395: closureEnv.setParameter(true);
0396: }
0397: } else {
0398: LambdaExp caller = getInlineOnly() ? getCaller() : null;
0399: if (parent == caller)
0400: closureEnv = parentFrame;
0401: else if (caller != null
0402: && parent == caller.outerLambdaNotInline())
0403: closureEnv = caller.closureEnv;
0404: else {
0405: closureEnv = new Variable("closureEnv", parentFrame
0406: .getType());
0407: scope.addVariable(closureEnv);
0408: closureEnv.setArtificial(true);
0409: }
0410: }
0411: }
0412: return closureEnv;
0413: }
0414:
0415: public LambdaExp() {
0416: }
0417:
0418: public LambdaExp(int args) {
0419: min_args = args;
0420: max_args = args;
0421: }
0422:
0423: public LambdaExp(Expression body) {
0424: this .body = body;
0425: }
0426:
0427: /** Generate code to load heapFrame on the JVM stack. */
0428: public void loadHeapFrame(Compilation comp) {
0429: gnu.bytecode.CodeAttr code = comp.getCode();
0430: LambdaExp curLambda = comp.curLambda;
0431: while (curLambda != this && curLambda.getInlineOnly())
0432: curLambda = curLambda.returnContinuation.context;
0433: if (this == curLambda) {
0434: if (this .heapFrame == null)
0435: code.emitPushThis();
0436: else
0437: code.emitLoad(this .heapFrame);
0438: } else {
0439: if (curLambda.closureEnv == null)
0440: code.emitPushThis();
0441: else
0442: code.emitLoad(curLambda.closureEnv);
0443: LambdaExp parent = curLambda.outerLambda();
0444: while (parent != this ) {
0445: if (parent.staticLinkField != null)
0446: code.emitGetField(parent.staticLinkField);
0447: //curLambda = parent;
0448: parent = parent.outerLambda();
0449: }
0450: }
0451: }
0452:
0453: /** Get the i'the formal parameter. */
0454: Declaration getArg(int i) {
0455: for (Declaration var = firstDecl();; var = var.nextDecl()) {
0456: if (var == null)
0457: throw new Error("internal error - getArg");
0458: if (i == 0)
0459: return var;
0460: --i;
0461: }
0462: }
0463:
0464: public void compileEnd(Compilation comp) {
0465: gnu.bytecode.CodeAttr code = comp.getCode();
0466: if (!getInlineOnly()) {
0467: if (comp.method.reachableHere()
0468: /* Work-around since reachableHere is not computed properly:
0469: Only return if the method is void or if there is a value
0470: on the stack.
0471: */
0472: && (code.SP > 0 || comp.method.getReturnType()
0473: .isVoid())
0474: && (!Compilation.usingTailCalls || isModuleBody()
0475: || isClassMethod() || isHandlingTailCalls())) {
0476: // The line of a method is by convention it's last one,
0477: // specifically to make this feature possible.
0478: if (getLine() > 0)
0479: code.putLineNumber(getFile(), getLine());
0480:
0481: code.emitReturn();
0482: }
0483: code.popScope(); // Undoes enterScope in allocParameters
0484: }
0485: if (!Compilation.fewerClasses) // FIXME
0486: code.popScope(); // Undoes pushScope in method.initCode.
0487:
0488: if (applyMethods != null && applyMethods.size() > 0) {
0489: Method save_method = comp.method;
0490: ClassType save_class = comp.curClass;
0491: comp.curClass = getHeapFrameType();
0492: comp.generateApplyMethods(this );
0493: comp.method = save_method;
0494: comp.curClass = save_class;
0495: }
0496: if (heapFrame != null)
0497: comp.generateConstructor((ClassType) heapFrame.getType(),
0498: this );
0499: }
0500:
0501: Field allocFieldFor(Compilation comp) {
0502: if (nameDecl != null && nameDecl.field != null)
0503: return nameDecl.field;
0504: String name = getName();
0505: String fname = name == null ? "lambda" : Compilation
0506: .mangleName(name);
0507: int fflags = Access.FINAL;
0508: if (nameDecl != null && nameDecl.context instanceof ModuleExp) {
0509: if (nameDecl.getFlag(Declaration.STATIC_SPECIFIED)) {
0510: fflags |= Access.STATIC;
0511: // If there is no instanceField, then the field gets initialized in
0512: // <init>, not <clinit>, which is bad for a "static final" field.
0513: if (!((ModuleExp) nameDecl.context).isStatic())
0514: fflags &= ~Access.FINAL;
0515: }
0516: if (!nameDecl.isPrivate())
0517: fflags |= Access.PUBLIC;
0518: } else {
0519: fname = fname + "$Fn" + ++comp.localFieldIndex;
0520: if (!getNeedsClosureEnv())
0521: fflags = (fflags | Access.STATIC) & ~Access.FINAL;
0522: }
0523: ClassType frameType = getHeapLambda().getHeapFrameType();
0524: Type rtype = Compilation.getMethodProcType(frameType);
0525: Field field = frameType.addField(fname, rtype, fflags);
0526: if (nameDecl != null)
0527: nameDecl.field = field;
0528: return field;
0529: }
0530:
0531: final void addApplyMethod(LambdaExp lexp) {
0532: if (applyMethods == null) {
0533: applyMethods = new Vector();
0534: if (heapFrame != null)
0535: ((ClassType) heapFrame.getType())
0536: .setSuper(Compilation.typeModuleBody);
0537: else
0538: type.setSuper(Compilation.typeModuleBody);
0539: }
0540: applyMethods.addElement(lexp);
0541: }
0542:
0543: public Field compileSetField(Compilation comp) {
0544: if (comp.usingCPStyle())
0545: compile(comp, Type.pointer_type);
0546: else {
0547: compileAsMethod(comp);
0548: getHeapLambda().addApplyMethod(this );
0549: }
0550:
0551: return (new ProcInitializer(this , comp)).field;
0552: }
0553:
0554: public void compile(Compilation comp, Target target) {
0555: if (target instanceof IgnoreTarget) {
0556: if (getInlineOnly())
0557: return;
0558: // else Causes failures. Better to remove unneeded LambdaExp earlier. FIXME
0559: }
0560: Type rtype;
0561: CodeAttr code = comp.getCode();
0562:
0563: if (comp.usingCPStyle()) {
0564: // Label func_start = new Label(code);
0565: Label func_end = new Label(code);
0566: LambdaExp saveLambda = comp.curLambda;
0567: comp.curLambda = this ;
0568: type = saveLambda.type;
0569: closureEnv = saveLambda.closureEnv;
0570: /*
0571: if (comp.usingCPStyle())
0572: {
0573: heapFrame = comp.thisDecl;
0574: for (Declaration var = firstDecl();
0575: var != null; var = var.nextDecl())
0576: var.assignField(comp);
0577: }
0578: */
0579: gnu.bytecode.SwitchState fswitch = comp.fswitch;
0580: int pc = comp.fswitch.getMaxValue() + 1;
0581: code.emitGoto(func_end);
0582: Type[] stackTypes = code.saveStackTypeState(true);
0583:
0584: fswitch.addCase(pc, code);
0585: /*
0586: code.emitPushThis();
0587: code.emitGetField(comp.argsCallContextField);
0588: code.emitStore(comp.argsArray);
0589: */
0590: allocParameters(comp);
0591: enterFunction(comp);
0592:
0593: compileBody(comp);
0594: compileEnd(comp);
0595: comp.curLambda = saveLambda;
0596: func_end.define(code);
0597: code.restoreStackTypeState(stackTypes);
0598: ClassType ctype = comp.curClass;
0599: rtype = ctype;
0600: /*
0601: code.emitNew(ctype);
0602: code.emitDup(ctype);
0603: code.emitInvokeSpecial(ctype.constructor);
0604: code.emitDup(ctype);
0605: code.emitPushInt(pc);
0606: code.emitPutField(comp.saved_pcCallFrameField);
0607: if (isHandlingTailCalls())
0608: {
0609: // Set name field.
0610: if (name != null)
0611: {
0612: code.emitDup(ctype);
0613: code.emitPushString(name);
0614: code.emitInvokeVirtual(comp.setNameMethod);
0615: }
0616: // Set numArgs field.
0617: code.emitDup(ctype);
0618: code.emitPushInt(min_args | (max_args << 12));
0619: code.emitPutField(comp.numArgsCallFrameField);
0620: // Set static link field to this CallFrame.
0621: code.emitDup(ctype);
0622: code.emitPushThis();
0623: code.emitPutField(comp.callerCallFrameField);
0624: }
0625: */
0626: } else {
0627: LambdaExp outer = outerLambda();
0628: rtype = comp.typeModuleMethod;
0629: if ((flags & NO_FIELD) != 0) {
0630: compileAsMethod(comp);
0631: ProcInitializer.emitLoadModuleMethod(this , comp);
0632: } else {
0633: Field field = compileSetField(comp);
0634: if (field.getStaticFlag())
0635: code.emitGetStatic(field);
0636: else {
0637: LambdaExp parent = comp.curLambda;
0638: Variable frame = parent.heapFrame != null ? parent.heapFrame
0639: : parent.closureEnv;
0640: code.emitLoad(frame);
0641: code.emitGetField(field);
0642: }
0643: }
0644: }
0645: target.compileFromStack(comp, rtype);
0646: }
0647:
0648: public ClassType getHeapFrameType() {
0649: if (this instanceof ModuleExp || this instanceof ClassExp)
0650: return (ClassType) getType();
0651: else
0652: return (ClassType) heapFrame.getType();
0653: }
0654:
0655: public LambdaExp getHeapLambda() {
0656: ScopeExp exp = outer;
0657:
0658: if (getNeedsClosureEnv())
0659: for (;; exp = exp.outer) {
0660: if (exp == null)
0661: return null;
0662: if (exp instanceof ModuleExp
0663: || (exp instanceof ClassExp && ((ClassExp) exp).needsConstructor)
0664: || (exp instanceof LambdaExp && ((LambdaExp) exp).heapFrame != null))
0665: return (LambdaExp) exp;
0666: }
0667:
0668: // No need for heap, return the englobing class
0669: ClassExp res = currentClass();
0670:
0671: /*
0672: For user classes, needsConstructor is false, but their outer
0673: class (lambda) is the package class.
0674: */
0675: if (res.needsConstructor)
0676: return res;
0677: else
0678: return res.outerLambda();
0679:
0680: }
0681:
0682: void addMethodFor(Compilation comp, ObjectType closureEnvType) {
0683: LambdaExp heapLambda = getHeapLambda();
0684: ClassType ctype = heapLambda.getHeapFrameType();
0685: addMethodFor(ctype, comp, closureEnvType);
0686: }
0687:
0688: void addMethodFor(ClassType ctype, Compilation comp,
0689: ObjectType closureEnvType) {
0690: // generate_unique_name (new_class, child.getName());
0691: String name = getName();
0692: LambdaExp outer = outerLambda();
0693:
0694: int key_args = keywords == null ? 0 : keywords.length;
0695: int opt_args = defaultArgs == null ? 0 : defaultArgs.length
0696: - key_args;
0697: int numStubs = ((flags & DEFAULT_CAPTURES_ARG) != 0)
0698: || Compilation.usingTailCalls ? 0 : opt_args;
0699: boolean varArgs = max_args < 0
0700: || min_args + numStubs < max_args;
0701: primMethods = new Method[numStubs + 1];
0702:
0703: boolean isStatic;
0704: boolean isInitMethod = false;
0705: if (isClassMethod()) {
0706: if (outer instanceof ClassExp) {
0707: ClassExp cl = (ClassExp) outer;
0708: isStatic = cl.isMakingClassPair()
0709: && closureEnvType != null;
0710: if (this == cl.initMethod)
0711: isInitMethod = true;
0712: } else
0713: isStatic = false;
0714: } else if (this Variable != null || closureEnvType == ctype)
0715: isStatic = false;
0716: else if (nameDecl == null)
0717: isStatic = true;
0718: else if (nameDecl.getFlag(Declaration.NONSTATIC_SPECIFIED))
0719: isStatic = false;
0720: else if (nameDecl.getFlag(Declaration.STATIC_SPECIFIED))
0721: isStatic = true;
0722: else if (nameDecl.context instanceof ModuleExp) {
0723: ModuleExp mexp = (ModuleExp) nameDecl.context;
0724: isStatic = mexp.getSuperType() == null
0725: && mexp.getInterfaces() == null;
0726: } else
0727: isStatic = true;
0728:
0729: StringBuffer nameBuf = new StringBuffer(60);
0730: if (!(outer.isModuleBody() || outer instanceof ClassExp)
0731: || name == null) {
0732: nameBuf.append("lambda");
0733: nameBuf.append(+(++comp.method_counter));
0734: }
0735: if (name != null)
0736: nameBuf.append(Compilation.mangleName(name));
0737: if (getFlag(SEQUENCE_RESULT))
0738: nameBuf.append("$C");
0739: if (Compilation.usingTailCalls && !isInitMethod
0740: && !isClassMethod())
0741: nameBuf.append("$T");
0742:
0743: int mflags = (isStatic ? Access.STATIC : 0);
0744: if (nameDecl != null)
0745: if (nameDecl.isSpecifiedPrivate())
0746: mflags |= Access.PRIVATE;
0747: else if (!nameDecl.isPrivate())
0748: mflags |= Access.PUBLIC;
0749:
0750: if (isInitMethod) {
0751: // Make it provide to prevent inherited $finit$ from overriding
0752: // the current one - and thus preventing its execution.
0753: mflags = (mflags & ~(Access.PUBLIC | Access.PROTECTED))
0754: + Access.PRIVATE;
0755: }
0756: if (ctype.isInterface())
0757: mflags |= Access.ABSTRACT;
0758: if (!isStatic)
0759: if (isClassMethod())
0760: declareThis(ctype);
0761: else
0762: closureEnv = declareThis(ctype);
0763:
0764: Type rtype = (getFlag(SEQUENCE_RESULT) || (Compilation.usingTailCalls && !isClassMethod())) ? Type.void_type
0765: : getReturnType().getImplementationType();
0766: int extraArg = (closureEnvType != null && closureEnvType != ctype) ? 1
0767: : 0;
0768: if (Compilation.usingTailCalls && !isInitMethod
0769: && !isClassMethod()) {
0770: Type[] atypes = new Type[1 + extraArg];
0771: if (extraArg > 0)
0772: atypes[0] = closureEnvType;
0773: atypes[extraArg] = Compilation.typeCallContext;
0774: primMethods[0] = ctype.addMethod(nameBuf.toString(),
0775: atypes, rtype, mflags);
0776: argsArray = new Variable("argsArray",
0777: Compilation.objArrayType);
0778: return;
0779: }
0780: for (int i = 0; i <= numStubs; i++) {
0781: int plainArgs = min_args + i;
0782: int numArgs = plainArgs;
0783: if (i == numStubs && varArgs)
0784: numArgs++;
0785: Type[] atypes = new Type[extraArg + numArgs];
0786: if (extraArg > 0)
0787: atypes[0] = closureEnvType;
0788: Declaration var = firstDecl();
0789: for (int itype = 0; itype < plainArgs; var = var.nextDecl())
0790: atypes[extraArg + itype++] = var.getType()
0791: .getImplementationType();
0792: if (plainArgs < numArgs) {
0793: nameBuf.append("$V");
0794: name = nameBuf.toString();
0795: Type lastType = var.getType();
0796: String lastTypeName = lastType.getName();
0797: if (key_args > 0
0798: || numStubs < opt_args
0799: || !("gnu.lists.LList".equals(lastTypeName) || "java.lang.Object[]"
0800: .equals(lastTypeName))) {
0801: lastType = Compilation.objArrayType;
0802: argsArray = new Variable("argsArray",
0803: Compilation.objArrayType);
0804: }
0805: firstArgsArrayArg = var;
0806: atypes[atypes.length - 1] = lastType;
0807: }
0808:
0809: boolean classSpecified = (outer instanceof ClassExp || (outer instanceof ModuleExp && (((ModuleExp) outer)
0810: .getFlag(ModuleExp.SUPERTYPE_SPECIFIED))));
0811: name = nameBuf.toString();
0812: {
0813: // If the base class or interfaces were not explicitly
0814: // specified, then any existing matching method (such as "run"
0815: // or "apply") is a conflict. So rename the method.
0816: int renameCount = 0;
0817: int len = nameBuf.length();
0818: retry: for (;;) {
0819: for (ClassType t = ctype; t != null; t = t
0820: .getSuperclass()) {
0821: if (t.getDeclaredMethod(name, atypes) != null) {
0822: nameBuf.setLength(len);
0823: nameBuf.append('$');
0824: nameBuf.append(++renameCount);
0825: name = nameBuf.toString();
0826: continue retry;
0827: }
0828: if (classSpecified)
0829: break;
0830: }
0831: break;
0832: }
0833: }
0834: primMethods[i] = ctype.addMethod(name, atypes, rtype,
0835: mflags);
0836: }
0837:
0838: addAttributes(getMainMethod());
0839: }
0840:
0841: // Can we merge this with allocParameters?
0842: public void allocChildClasses(Compilation comp) {
0843: if (this instanceof ModuleExp)
0844: ((ModuleExp) this ).allocFields(comp);
0845: else {
0846: Method main = getMainMethod();
0847:
0848: Declaration decl = firstDecl();
0849: if (isHandlingTailCalls()) {
0850: firstArgsArrayArg = decl;
0851: if (!Compilation.usingTailCalls) // FIXME
0852: scope.addVariable(null, comp.typeCallContext,
0853: "$ctx");
0854: }
0855: for (;;) {
0856: if (decl == firstArgsArrayArg && argsArray != null) {
0857: scope.addVariable(argsArray);
0858: argsArray.setParameter(true);
0859: argsArray.setArtificial(true);
0860: }
0861: if (decl == null)
0862: break;
0863: Variable var = decl.var;
0864: // i is the register to use for the current parameter
0865: if (decl.isSimple() && !decl.isIndirectBinding()) {
0866: // For a simple parameter not captured by an inferior lambda,
0867: // just allocate it in the incoming register.
0868: var = decl.allocateVariable(null);
0869: //var.allocateLocal(code);
0870: } else {
0871: // This variable was captured by an inner lambda.
0872: // Its home location is in the heapFrame.
0873: // Later, we copy it from its incoming register
0874: // to its home location heapFrame. Here we just create and
0875: // assign a Variable for the incoming (register) value.
0876: String vname = Compilation.mangleName(
0877: decl.getName()).intern();
0878: var = decl.var = scope.addVariable(null, decl
0879: .getType(), vname);
0880: //scope.addVariableAfter(var, decl);
0881: var.setArtificial(true);
0882: var.setParameter(true);
0883: //var.allocateLocal(code);
0884: }
0885: decl = decl.nextDecl();
0886: }
0887: }
0888:
0889: declareClosureEnv();
0890:
0891: if (comp.usingCPStyle() && comp.curClass == comp.mainClass)
0892: return;
0893:
0894: allocFrame(comp);
0895:
0896: for (LambdaExp child = firstChild; child != null; child = child.nextSibling) {
0897: if (child.isClassGenerated()) {
0898: if (child.min_args != child.max_args
0899: || child.min_args > 4
0900: || child.isHandlingTailCalls()) {
0901: child.argsArray = new Variable("argsArray",
0902: comp.objArrayType);
0903: child.firstArgsArrayArg = child.firstDecl();
0904: }
0905: } else if (!child.getInlineOnly()) {
0906: boolean method_static;
0907: ObjectType closureEnvType;
0908: if (!child.getNeedsClosureEnv())
0909: closureEnvType = null;
0910: else if (this instanceof ClassExp)
0911: closureEnvType = getCompiledClassType(comp);
0912: else if ("$finit$".equals(getName()))
0913: closureEnvType = outerLambda()
0914: .getCompiledClassType(comp);
0915: else {
0916: LambdaExp owner = this ;
0917: while (owner.heapFrame == null)
0918: owner = owner.outerLambda();
0919: closureEnvType = (ClassType) owner.heapFrame
0920: .getType();
0921: }
0922: child.addMethodFor(comp, closureEnvType);
0923: }
0924: }
0925: }
0926:
0927: public void allocFrame(Compilation comp) {
0928: if (heapFrame != null) {
0929: ClassType frameType;
0930: if (this instanceof ModuleExp || this instanceof ClassExp)
0931: frameType = getCompiledClassType(comp);
0932: else {
0933: ClassExp outerClass = outerClass();
0934: if (outerClass != null) {
0935: String name = getName();
0936: if (name == null)
0937: name = "lambda";
0938: // At least for constructors ("<init>") we need to make sure
0939: // that the name is valid.
0940: name = Compilation.mangleName(name);
0941: // Use the outer class as a prefix name.
0942: name = outerClass.getName() + "$" + name;
0943: // Make sure the name is unique.
0944: name = comp.generateUniqueName(name);
0945: frameType = new ClassType(name);
0946: if (outerClass.getFile() != null)
0947: frameType.setSourceFile(outerClass.getFile());
0948: } else
0949: frameType = new ClassType(comp
0950: .generateClassName("frame"));
0951: if (Compilation.usingTailCalls) // FIXME
0952: frameType.setSuper(Type.pointer_type);
0953: else
0954: frameType.setSuper(Compilation.typeModuleBody);
0955: comp.addClass(frameType);
0956: }
0957: heapFrame.setType(frameType);
0958: }
0959: }
0960:
0961: void allocParameters(Compilation comp) {
0962: CodeAttr code = comp.getCode();
0963:
0964: int i = 0;
0965: int j = 0;
0966:
0967: if (isHandlingTailCalls() && !isModuleBody()
0968: && !comp.usingCPStyle()) {
0969: comp.callStackContext = new Variable("$ctx",
0970: comp.typeCallContext);
0971: // Variable thisVar = isStaic? = null : declareThis(comp.curClass);
0972: scope.addVariableAfter(this Variable, comp.callStackContext);
0973: comp.callStackContext.setParameter(true);
0974: comp.callStackContext.setArtificial(true);
0975: }
0976:
0977: code.locals.enterScope(scope);
0978:
0979: if (argsArray != null && isHandlingTailCalls()) {
0980: code.emitLoad(comp.callStackContext);
0981: code.emitInvoke(comp.typeCallContext.getDeclaredMethod(
0982: "getArgs", 0));
0983: code.emitStore(argsArray);
0984: }
0985:
0986: for (Declaration decl = firstDecl(); decl != null;) {
0987: Variable var = decl.var;
0988: // If the only reason we are using an argsArray is because there
0989: // are more than 4 arguments, copy the arguments in local register.
0990: // Then forget about the args array. We do this first, before
0991: // the label that tail-recursion branches back to.
0992: // This way, a self-tail-call knows where to leave the argumnents.
0993: if (argsArray != null && min_args == max_args
0994: && primMethods == null && !isHandlingTailCalls()) {
0995: code.emitLoad(argsArray);
0996: code.emitPushInt(j);
0997: code.emitArrayLoad(Type.pointer_type);
0998: decl.getType().emitCoerceFromObject(code);
0999: code.emitStore(decl.getVariable());
1000: }
1001: j++;
1002: i++;
1003: decl = decl.nextDecl();
1004: }
1005: if (heapFrame != null)
1006: heapFrame.allocateLocal(code);
1007: }
1008:
1009: static Method searchForKeywordMethod3;
1010: static Method searchForKeywordMethod4;
1011:
1012: /** Rembembers stuff to do in <init> of this class. */
1013: Initializer initChain;
1014: /** Rembembers stuff to do in <clinit> of this class. */
1015: Initializer clinitChain;
1016:
1017: void addInitializer(Initializer elem) {
1018: elem.next = this .initChain;
1019: this .initChain = elem;
1020: }
1021:
1022: void addClassInitializer(Initializer elem) {
1023: elem.next = this .clinitChain;
1024: this .clinitChain = elem;
1025: }
1026:
1027: private Field instanceField;
1028:
1029: Field getInstanceField() {
1030: if (instanceField == null) {
1031: instanceField = type.addField("$instance", type,
1032: Access.STATIC | Access.FINAL | Access.PUBLIC);
1033: }
1034: return instanceField;
1035: }
1036:
1037: /** Rembembers literals to initialize (in <clinit>). */
1038: Literal literalsChain;
1039: java.util.Hashtable literalTable;
1040:
1041: void generateClassInit(Compilation comp) {
1042: if (instanceField == null && clinitChain == null
1043: && literalsChain == null)
1044: return;
1045:
1046: Method method = type.addMethod("<clinit>", Type.typeArray0,
1047: Type.void_type, Access.PUBLIC | Access.STATIC);
1048: method.init_param_slots();
1049:
1050: CodeAttr code = method.getCode();
1051:
1052: // These gotos are losing. Should instead do a pre-pass (using
1053: // an ExpWalker) before compilation that collects all needed
1054: // constants. Then we generate code to init the literals *first*,
1055: // before compiling anything else. FIXME.
1056: Label lab0 = new Label(code);
1057: Label lab1 = new Label(code);
1058: Label lab2 = new Label(code);
1059:
1060: code.emitGoto(lab2);
1061:
1062: lab0.define(code);
1063:
1064: if (clinitChain != null) {
1065: Label lastClinit = new Label(code);
1066: code.emitGoto(lastClinit);
1067: Label previous = null;
1068:
1069: /* Dumping initializers can add new initializers,
1070: so we loop until none is added.
1071: The order of execution is reversed, the last ones being required
1072: by the first ones.
1073: */
1074: while (clinitChain != null) {
1075: Label current = new Label(code);
1076: current.define(code);
1077:
1078: Initializer chain = clinitChain;
1079: clinitChain = null;
1080: comp.dumpInitializers(chain, method);
1081:
1082: if (previous != null)
1083: code.emitGoto(previous);
1084: else
1085: method.getCode().emitReturn();
1086:
1087: if (clinitChain == null) {
1088: lastClinit.define(code);
1089: code.emitGoto(current);
1090: } else
1091: previous = current;
1092: }
1093: } else
1094: method.getCode().emitReturn();
1095:
1096: lab1.define(code);
1097: comp.literalsChain = literalsChain;
1098: // reset the litTable to force emission of the literals
1099: // litTable should not be a field in compilation
1100: comp.litTable = null;
1101: comp.method = method;
1102: Literal.emit(comp);
1103: code.emitGoto(lab0);
1104:
1105: lab2.define(code);
1106: if (instanceField != null) {
1107: comp.generateConstructor(this );
1108: //ClassType type = getHeapFrameType(); // Is this more correct?
1109: if (type.constructor != null) {
1110: code.emitNew(type);
1111: code.emitDup(type);
1112: code.emitInvokeSpecial(type.constructor);
1113: code.emitPutStatic(instanceField);
1114: }
1115: } else if (this instanceof ClassExp)
1116: // generateConstructor might have been called earlier, but we call it
1117: // again because the super-class (gnu.expr.ModuleBody)
1118: // seems to be found late.
1119: comp.generateConstructor(this );
1120: code.emitGoto(lab1);
1121: }
1122:
1123: void enterFunction(Compilation comp) {
1124: CodeAttr code = comp.getCode();
1125:
1126: // Tail-calls loop back to here!
1127: scope.setStartPC(code.getPC());
1128:
1129: if (closureEnv != null && !closureEnv.isParameter()
1130: && !comp.usingCPStyle()) {
1131: if (getInlineOnly())
1132: outerLambda().loadHeapFrame(comp);
1133: else {
1134: code.emitPushThis();
1135: Field field = closureEnvField;
1136: if (field == null)
1137: field = outerLambda().closureEnvField;
1138: code.emitGetField(field);
1139: }
1140: code.emitStore(closureEnv);
1141: }
1142: if (heapFrame != null && !comp.usingCPStyle()) {
1143: ClassType frameType = (ClassType) heapFrame.getType();
1144: for (Declaration decl = capturedVars; decl != null; decl = decl.nextCapturedVar) {
1145: if (decl.field != null)
1146: continue;
1147: String dname = comp.mangleName(decl.getName());
1148: String mname = dname;
1149: // Check for existing field with same name.
1150: for (int i = 0;;) {
1151: Field fld = frameType.getField(mname);
1152: if (fld == null)
1153: break;
1154: mname = dname + '_' + ++i;
1155: }
1156: Type dtype = decl.getType();
1157: decl.field = frameType.addField(mname, decl.getType());
1158: }
1159: if (closureEnv != null && heapFrame != null)
1160: staticLinkField = frameType.addField("staticLink",
1161: closureEnv.getType());
1162: if (!(this instanceof ModuleExp)
1163: && !(this instanceof ClassExp)) {
1164: code.emitNew(frameType);
1165: code.emitDup(frameType);
1166: Method constructor = comp.getConstructor(frameType,
1167: this );
1168: code.emitInvokeSpecial(constructor);
1169:
1170: // In a constructor, the closure (this) is not valid until the
1171: // end, so it shouldn't be used (presumably it is not used
1172: // anyway).
1173: // There might be a deeper change that would make this test
1174: // unnecessary.
1175: if (staticLinkField != null
1176: && !(this instanceof ConstructorExp)) {
1177: code.emitDup(heapFrame.getType());
1178: code.emitLoad(closureEnv);
1179: code.emitPutField(staticLinkField);
1180: }
1181: code.emitStore(heapFrame);
1182: }
1183: }
1184:
1185: Variable argsArray = this .argsArray;
1186: if (min_args == max_args && !comp.fewerClasses
1187: && primMethods == null && !isHandlingTailCalls())
1188: argsArray = null;
1189:
1190: // For each non-artificial parameter, copy it from its incoming
1191: // location (a local variable register, or the argsArray) into
1192: // its home location, if they are different.
1193: int i = 0;
1194: int opt_i = 0;
1195: int key_i = 0;
1196: int key_args = keywords == null ? 0 : keywords.length;
1197: int opt_args = defaultArgs == null ? 0 : defaultArgs.length
1198: - key_args;
1199: if (this instanceof ModuleExp)
1200: return;
1201: // If plainArgs>=0, it is the number of arguments *not* in argsArray.
1202: int plainArgs = -1;
1203: int defaultStart = 0;
1204: Method mainMethod = getMainMethod();
1205:
1206: for (Declaration param = firstDecl(); param != null; param = param
1207: .nextDecl()) {
1208: if (param == firstArgsArrayArg && argsArray != null) {
1209: if (primMethods != null && !Compilation.usingTailCalls) {
1210: plainArgs = i;
1211: defaultStart = plainArgs - min_args;
1212: } else {
1213: plainArgs = 0;
1214: defaultStart = 0;
1215: }
1216: }
1217: if (plainArgs >= 0 || !param.isSimple()
1218: || param.isIndirectBinding()) {
1219: Type paramType = param.getType();
1220: Type stackType = (mainMethod == null || plainArgs >= 0 ? Type.pointer_type
1221: : paramType);
1222: // If the parameter is captured by an inferior lambda,
1223: // then the incoming parameter needs to be copied into its
1224: // slot in the heapFrame. Thus we emit an aaload instruction.
1225: // Unfortunately, it expects the new value *last*,
1226: // so first push the heapFrame array and the array index.
1227: if (!param.isSimple())
1228: param.loadOwningObject(comp);
1229: // This part of the code pushes the incoming argument.
1230: if (plainArgs < 0) {
1231: // Simple case: Use Incoming register.
1232: code.emitLoad(param.getVariable());
1233: } else if (i < min_args) { // This is a required parameter, in argsArray[i].
1234: code.emitLoad(argsArray);
1235: code.emitPushInt(i);
1236: code.emitArrayLoad(Type.pointer_type);
1237: } else if (i < min_args + opt_args) { // An optional parameter
1238: code.emitPushInt(i - plainArgs);
1239: code.emitLoad(argsArray);
1240: code.emitArrayLength();
1241: code.emitIfIntLt();
1242: code.emitLoad(argsArray);
1243: code.emitPushInt(i - plainArgs);
1244: code.emitArrayLoad(Type.pointer_type);
1245: code.emitElse();
1246: defaultArgs[defaultStart + opt_i++].compile(comp,
1247: paramType);
1248: code.emitFi();
1249: } else if (max_args < 0 && i == min_args + opt_args) {
1250: // This is the "rest" parameter (i.e. following a "."):
1251: // Convert argsArray[i .. ] to a list.
1252: code.emitLoad(argsArray);
1253: code.emitPushInt(i - plainArgs);
1254: code.emitInvokeStatic(Compilation.makeListMethod);
1255: stackType = comp.scmListType;
1256: } else { // Keyword argument.
1257: code.emitLoad(argsArray);
1258: code.emitPushInt(min_args + opt_args - plainArgs);
1259: comp.compileConstant(keywords[key_i++]);
1260: Expression defaultArg = defaultArgs[defaultStart
1261: + opt_i++];
1262: // We can generate better code if the defaultArg expression
1263: // has no side effects. For simplicity and safety, we just
1264: // special case literals, which handles most cases.
1265: if (defaultArg instanceof QuoteExp) {
1266: if (searchForKeywordMethod4 == null) {
1267: Type[] argts = new Type[4];
1268: argts[0] = Compilation.objArrayType;
1269: argts[1] = Type.int_type;
1270: argts[2] = Type.pointer_type;
1271: argts[3] = Type.pointer_type;
1272: searchForKeywordMethod4 = Compilation.scmKeywordType
1273: .addMethod("searchForKeyword",
1274: argts, Type.pointer_type,
1275: Access.PUBLIC
1276: | Access.STATIC);
1277: }
1278: defaultArg.compile(comp, paramType);
1279: code.emitInvokeStatic(searchForKeywordMethod4);
1280: } else {
1281: if (searchForKeywordMethod3 == null) {
1282: Type[] argts = new Type[3];
1283: argts[0] = Compilation.objArrayType;
1284: argts[1] = Type.int_type;
1285: argts[2] = Type.pointer_type;
1286: searchForKeywordMethod3 = Compilation.scmKeywordType
1287: .addMethod("searchForKeyword",
1288: argts, Type.pointer_type,
1289: Access.PUBLIC
1290: | Access.STATIC);
1291: }
1292: code.emitInvokeStatic(searchForKeywordMethod3);
1293: code.emitDup(1);
1294: comp.compileConstant(Special.dfault);
1295: code.emitIfEq();
1296: code.emitPop(1);
1297: defaultArg.compile(comp, paramType);
1298: code.emitFi();
1299: }
1300: }
1301: // Now finish copying the incoming argument into its
1302: // home location.
1303: if (paramType != stackType)
1304: CheckedTarget.emitCheckedCoerce(comp, this , i,
1305: paramType);
1306: if (param.isIndirectBinding())
1307: param.pushIndirectBinding(comp);
1308: if (param.isSimple())
1309: code.emitStore(param.getVariable());
1310: else
1311: code.emitPutField(param.field);
1312: }
1313: i++;
1314: }
1315: }
1316:
1317: void compileChildMethods(Compilation comp) {
1318: for (LambdaExp child = firstChild; child != null;) {
1319: if (!child.getCanRead() && !child.getInlineOnly()
1320: && !child.isHandlingTailCalls()) {
1321: child.compileAsMethod(comp);
1322: }
1323: child = child.nextSibling;
1324: }
1325: }
1326:
1327: void compileAsMethod(Compilation comp) {
1328: if ((flags & METHODS_COMPILED) != 0)
1329: return;
1330: flags |= METHODS_COMPILED;
1331: Method save_method = comp.method;
1332: LambdaExp save_lambda = comp.curLambda;
1333: Variable saveStackContext = comp.callStackContext;
1334: comp.curLambda = this ;
1335:
1336: if (primMethods == null) {
1337: // This happens for lambdas that are not toplevel nor contained
1338: // in a toplevel lambda (eg: global variables values).
1339: outer = (ClassExp) comp.topLambda;
1340: addMethodFor(comp.topClass, comp, null);
1341: compileAsMethod(comp);
1342: }
1343:
1344: Method method = primMethods[0];
1345: boolean isStatic = method.getStaticFlag();
1346: int numStubs = primMethods.length - 1;
1347: Type restArgType = restArgType();
1348:
1349: int[] saveDeclFlags = null;
1350: if (numStubs > 0) {
1351: saveDeclFlags = new int[min_args + numStubs];
1352: int k = 0;
1353: for (Declaration decl = firstDecl(); k < min_args
1354: + numStubs; decl = decl.nextDecl())
1355: saveDeclFlags[k++] = decl.flags;
1356: }
1357:
1358: for (int i = 0; i <= numStubs; i++) {
1359: comp.method = primMethods[i];
1360: if (i < numStubs) {
1361: comp.method.init_param_slots();
1362: CodeAttr code = comp.getCode();
1363: int toCall = i + 1;
1364: while (toCall < numStubs
1365: && defaultArgs[toCall] instanceof QuoteExp)
1366: toCall++;
1367: int this Arg = isStatic ? 0 : 1;
1368: boolean varArgs = toCall == numStubs
1369: && restArgType != null;
1370: Declaration decl;
1371: Variable var = code.getArg(0);
1372: if (!isStatic) {
1373: code.emitPushThis();
1374: if (getNeedsClosureEnv())
1375: closureEnv = var;
1376: var = code.getArg(1);
1377: }
1378: decl = firstDecl();
1379: for (int j = 0; j < min_args + i; j++, decl = decl
1380: .nextDecl()) {
1381: decl.flags |= Declaration.IS_SIMPLE;
1382: decl.var = var;
1383: code.emitLoad(var);
1384: var = var.nextVar();
1385: }
1386: for (int j = i; j < toCall; j++, decl = decl.nextDecl()) {
1387: Target paramTarget = StackTarget.getInstance(decl
1388: .getType());
1389: defaultArgs[j].compile(comp, paramTarget);
1390: }
1391: if (varArgs) {
1392: Expression arg;
1393: String lastTypeName = restArgType.getName();
1394: if ("gnu.lists.LList".equals(lastTypeName))
1395: arg = new QuoteExp(gnu.lists.LList.Empty);
1396: else if ("java.lang.Object[]".equals(lastTypeName))
1397: arg = new QuoteExp(Values.noArgs);
1398: else
1399: // FIXME
1400: throw new Error("unimplemented #!rest type");
1401: arg.compile(comp, restArgType);
1402: }
1403: if (isStatic)
1404: code.emitInvokeStatic(primMethods[toCall]);
1405: else
1406: code.emitInvokeVirtual(primMethods[toCall]);
1407: code.emitReturn();
1408: closureEnv = null;
1409: } else {
1410: if (saveDeclFlags != null) {
1411: int k = 0;
1412: for (Declaration decl = firstDecl(); k < min_args
1413: + numStubs; decl = decl.nextDecl()) {
1414: decl.flags = saveDeclFlags[k++];
1415: decl.var = null;
1416: }
1417: }
1418: if (comp.curClass.isInterface()
1419: && comp.method.isAbstract()) {
1420: // Interface method. Skip code generation.
1421: } else {
1422: comp.method.initCode();
1423: allocChildClasses(comp);
1424: allocParameters(comp);
1425: enterFunction(comp);
1426:
1427: compileBody(comp);
1428: compileEnd(comp);
1429: }
1430: }
1431: }
1432:
1433: compileChildMethods(comp);
1434: comp.method = save_method;
1435: comp.curLambda = save_lambda;
1436: comp.callStackContext = saveStackContext;
1437: }
1438:
1439: public void compileBody(Compilation comp) {
1440: Target target;
1441: if (isHandlingTailCalls()) {
1442: CodeAttr code = comp.getCode();
1443: Variable ctxVar = comp.callStackContext;
1444: code.emitLoad(ctxVar);
1445: code.emitGetField(comp.typeCallContext
1446: .getDeclaredField("consumer"));
1447: Scope scope = code.getCurrentScope();
1448: Variable result = scope.addVariable(code,
1449: Compilation.typeConsumer, "$result");
1450: code.emitStore(result);
1451: target = new ConsumerTarget(result);
1452: } else
1453: target = Target.pushValue(comp.method.getReturnType());
1454: body.compileWithPosition(comp, target);
1455: }
1456:
1457: /** A cache if this has already been evaluated. */
1458: Procedure this Value;
1459:
1460: protected Expression walk(ExpWalker walker) {
1461: return walker.walkLambdaExp(this );
1462: }
1463:
1464: protected void walkChildren(ExpWalker walker) {
1465: walkChildrenOnly(walker);
1466: walkProperties(walker);
1467: }
1468:
1469: protected final void walkChildrenOnly(ExpWalker walker) {
1470: LambdaExp save = walker.currentLambda;
1471: walker.currentLambda = this ;
1472: try {
1473: walker.walkDefaultArgs(this );
1474: if (walker.exitValue == null && body != null)
1475: body = body.walk(walker);
1476: } finally {
1477: walker.currentLambda = save;
1478: }
1479: }
1480:
1481: protected final void walkProperties(ExpWalker walker) {
1482: if (properties != null) {
1483: int len = properties.length;
1484: for (int i = 1; i < len; i += 2) {
1485: Object val = properties[i];
1486: if (val instanceof Expression) {
1487: properties[i] = ((Expression) properties[i])
1488: .walk(walker);
1489: }
1490: }
1491: }
1492: }
1493:
1494: public void print(OutPort out) {
1495: out.startLogicalBlock("(Lambda/", ")", 2);
1496: if (name != null) {
1497: out.print(name);
1498: out.print('/');
1499: }
1500: out.print(id);
1501: out.print('/');
1502: out.writeSpaceFill();
1503: printLineColumn(out);
1504: out.print('(');
1505: Special prevMode = null;
1506: int i = 0;
1507: int opt_i = 0;
1508: int key_args = keywords == null ? 0 : keywords.length;
1509: int opt_args = defaultArgs == null ? 0 : defaultArgs.length
1510: - key_args;
1511: for (Declaration decl = firstDecl(); decl != null; decl = decl
1512: .nextDecl()) {
1513: Special mode;
1514: if (i < min_args)
1515: mode = null;
1516: else if (i < min_args + opt_args)
1517: mode = Special.optional;
1518: else if (max_args < 0 && i == min_args + opt_args)
1519: mode = Special.rest;
1520: else
1521: mode = Special.key;
1522: if (i > 0)
1523: out.writeSpaceFill();
1524: if (mode != prevMode) {
1525: out.print(mode);
1526: out.writeSpaceFill();
1527: }
1528: Expression defaultArg = null;
1529: if ((mode == Special.optional || mode == Special.key)
1530: && defaultArgs != null)
1531: defaultArg = defaultArgs[opt_i++];
1532: if (defaultArg != null)
1533: out.print('(');
1534: out.print(decl.getName());
1535: if (defaultArg != null && defaultArg != QuoteExp.falseExp) {
1536: out.print(' ');
1537: defaultArg.print(out);
1538: out.print(')');
1539: }
1540: i++;
1541: prevMode = mode;
1542: }
1543: out.print(')');
1544: out.writeSpaceLinear();
1545: if (body == null)
1546: out.print("<null body>");
1547: else
1548: body.print(out);
1549: out.endLogicalBlock(")");
1550: }
1551:
1552: protected final String getExpClassName() {
1553: String cname = getClass().getName();
1554: int index = cname.lastIndexOf('.');
1555: if (index >= 0)
1556: cname = cname.substring(index + 1);
1557: return cname;
1558: }
1559:
1560: public String toString() {
1561: String str = getExpClassName() + ':' + name + '/' + id + '/';
1562:
1563: int l = getLine();
1564: if (l <= 0 && body != null)
1565: l = body.getLine();
1566: if (l > 0)
1567: str = str + "l:" + l;
1568:
1569: return str;
1570: }
1571:
1572: /** If non-null, a sequence of (key, value)-pairs.
1573: * These will be used to call setProperty at run-time. */
1574: Object[] properties;
1575:
1576: public Object getProperty(Object key, Object defaultValue) {
1577: if (properties != null) {
1578: for (int i = properties.length; (i -= 2) >= 0;) {
1579: if (properties[i] == key)
1580: return properties[i + 1];
1581: }
1582: }
1583: return defaultValue;
1584: }
1585:
1586: public synchronized void setProperty(Object key, Object value) {
1587: properties = Procedure.setProperty(properties, key, value);
1588: }
1589:
1590: /** If non-null, the type of values returned by this function.
1591: * If null, the return type has not been set or calculated yet. */
1592: protected Type returnType;
1593:
1594: /** The return type of this function, i.e the type of its returned values. */
1595: public final Type getReturnType() {
1596: if (returnType == null) {
1597: returnType = Type.pointer_type; // To guards against cycles.
1598: returnType = body.getType();
1599: }
1600: return returnType;
1601: }
1602:
1603: /* Set teh return type of this function. */
1604: public final void setReturnType(Type returnType) {
1605: this .returnType = returnType;
1606: }
1607:
1608: /**
1609: List attributes that should be added to the main primitive method
1610: generated for this lambdaExp.
1611: */
1612: public void addBytecodeAttribute(Attribute a) {
1613: a.setNext(attributes);
1614: attributes = a;
1615: }
1616:
1617: private gnu.bytecode.Attribute attributes;
1618:
1619: void addAttributes(AttrContainer bytecode) {
1620: for (Attribute a = attributes; a != null;) {
1621: Attribute next = a.getNext();
1622: a.addToFrontOf(bytecode);
1623: a = next;
1624: }
1625: }
1626: }
|