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