1 // Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2007, 2008, 2009  Per M.A. Bothner.
2 // This is free software;  for terms and warranty disclaimer see ./COPYING.
3 
4 package gnu.expr;
5 import gnu.bytecode.*;
6 import gnu.mapping.*;
7 import gnu.lists.LList;
8 import gnu.kawa.functions.Convert;
9 import gnu.kawa.io.OutPort;
10 import gnu.kawa.lispexpr.LangObjType;
11 import java.util.*;
12 import java.lang.annotation.ElementType;
13 /* #ifdef use:java.lang.invoke */
14 import java.lang.invoke.*;
15 /* #else */
16 // import gnu.mapping.CallContext.MethodHandle;
17 /* #endif */
18 
19 /**
20  * Class used to implement Scheme lambda expressions.
21  * @author	Per Bothner
22  */
23 
24 public class LambdaExp extends ScopeExp {
25     public Expression body;
26 
27     /** Minimum number of actual arguments.
28      * Does not count implicit isThisParameter(). */
29     public int min_args;
30 
31     /** Maximum number of actual arguments;  -1 if variable.
32      * Does not count keyword arguments. */
33     public int max_args;
34 
35     /** Number of optional arguments, not counting keyword arguments. */
36     public int opt_args;
37 
38     /** Set of visible top-level LambdaExps that need apply methods. */
39     ArrayList<LambdaExp> applyMethods;
40 
41     public Keyword[] keywords;
42 
43     /** A list of Declarations, chained using Declaration's nextCapturedVar.
44      * All the Declarations are allocated in the current heapFrame. */
45     Declaration capturedVars;
46 
47     /** Linked link of references to sibling declarations.
48      * Chained using {@see ReferenceExp#siblingReferencesNext} links.
49      * I.e. References to declarations external to this LambdaExp,
50      * but local to the outer LambdaExp.
51      */
52     ReferenceExp siblingReferences;
53 
54     /** The location for function start, before arguments are stored. */
55     Label startForInlining;
56     /** Queue of deferred inline class.
57      * The items are (deferred-lambda, Target) pairs.
58      */
59     LinkedList<Object> pendingInlines;
60 
capture(Declaration decl)61     public void capture(Declaration decl) {
62         if (decl.isSimple()) {
63             if (capturedVars == null
64                 && ! decl.isStatic()
65                 && ! isClassGenerated()) {
66                 heapFrame = new gnu.bytecode.Variable("$heapFrame");
67             }
68             decl.setSimple(false);
69             if (! decl.isPublic()) {
70                 decl.nextCapturedVar = capturedVars;
71                 capturedVars = decl;
72             }
73         }
74     }
75 
addParameter(Object name)76     public Declaration addParameter(Object name) {
77         min_args++;
78         max_args++;
79         return super.addDeclaration(name);
80     }
81 
82     /** A local variable that points to the heap-allocated part of the frame.
83      * Each captured variable is a field in the heapFrame.  A procedure has
84      * a heapFrame iff if has a parameter or local variable that is
85      * referenced ("captured") by a non-inline inferior procedure.
86      * (I.e there is a least one non-inline procedure that encloses the
87      * reference but not the definition.)  Note that an inline procedure may
88      * have a heapFrame if it encloses a non-inline procedure.  This is
89      * necessary because we represent loops as tail-recursive inline procedures.
90      */
91     Variable heapFrame;
92 
93     public LambdaExp firstChild;
94     public LambdaExp nextSibling;
95 
96     /** A magic value to indicate there is no unique return continuation. */
97     final static ApplyExp unknownContinuation
98         = new ApplyExp ((Expression) null, (Expression[]) null);
99 
100     /** The unique call site that calls this lambda.
101      * The value is null if no callers have been seen.
102      * A value of unknownContinuation means there are multiple call sites.
103      * Tail-recursive calls do not count as multiple call sites.
104      * This is used to see if we can inline the function at its unique call site.
105      * Usually this is an ApplyExp, but it can also be the "tail position"
106      * for some outer expression, such as an IfExp.  This allows inlining f
107      * in the call 'if (cond) f(x) else f(y)' since both calls have the same
108      * return point.
109      */
110     public Expression returnContinuation;
111 
112     /** If non-null, set of functions that tail-call this function. */
113     java.util.Set<LambdaExp> tailCallers;
114 
115     /** If this lambda gets inlined this is the containing lambda.
116         Otherwise this is null. */
117     public LambdaExp inlineHome;
118 
119     /** Expressions that name classes that may be thrown. */
120     Expression[] throwsSpecification;
121 
setExceptions(Expression[] exceptions)122     public void setExceptions(Expression[] exceptions) {
123         throwsSpecification = exceptions;
124     }
125 
126     /** If non-null, a Declaration whose value is (only) this LambdaExp. */
127     public Declaration nameDecl;
128 
129     public static final String CLOSURE_ENV_NAME = "$closureEnv";
130 
131     /** If non-null, this is a Field that is used for implementing lexical closures.
132      * If getName() is CLOSURE_ENV_NAME, it is our parent's heapFrame,
133      * which is an instance of one of our siblings.
134      * (Otherwise, we use "this" as the implicit "closureEnv" field.) */
135     public Field closureEnvField;
136 
137     /** Field in heapFrame.getType() that contains the static link.
138      * It is used by child functions to get to outer environments.
139      * Its value is this function's closureEnv value. */
140     public Field staticLinkField;
141 
142     /** A variable that points to the closure environment passed in.
143      * It can be any one of:
144      * null, if no closure environment is needed;
145      * this, if this object is its parent's heapFrame;
146      * a local variable initialized from this.closureEnv;
147      * a parameter (only if !getCanRead()); or
148      * a copy of our caller's closureEnv or heapFrame (only if getInlineOnly()).
149      * See declareClosureEnv and closureEnvField. */
150     Variable closureEnv;
151 
152     static final int CAN_READ = Expression.NEXT_AVAIL_FLAG; // 2
153     static final int INLINE_ONLY = 4;
154     static final int IMPORTS_LEX_VARS = 8;
155     static final int NEEDS_STATIC_LINK = 16;
156     /* Used (future) by FindTailCalls. */
157     static final int CANNOT_INLINE = 32;
158     static final int CLASS_METHOD = 64;
159     static final int METHODS_COMPILED = 128;
160     public static final int NO_FIELD = 256;
161     /** True if any parameter default expression captures a parameter. */
162     static final int DEFAULT_CAPTURES_ARG = 512;
163     public static final int SEQUENCE_RESULT = 1024;
164     public static final int OVERLOADABLE_FIELD = 2048;
165     public static final int ATTEMPT_INLINE = 4096;
166     public static final int IN_EXPWALKER = 0x2000;
167     /** Treat as inlined in outer lambda when determining tailcalls. */
168     public static final int PASSES_TAILCALLS = 0x4000;
169 
170     /** True of emitted method should be public.
171      * Needed if PrimProcedure.getMethodFor shold be able to find it.
172      */
173     public static final int PUBLIC_METHOD = 0x4000;
174     public static final int ALLOW_OTHER_KEYWORDS = 0x8000;
175 
176     protected static final int HAS_NONTRIVIAL_PATTERN = 0x10000;
177     /** True if IS_SUPPLIED_PARAMETER is set on a parameter.
178      * In that case we generate an extra foo$P method for the actual body.
179      * (It might make sense to also do this whenever a default expression
180      * is non-literal, but we current don't do that.)
181      */
182     protected static final int HAS_NONTRIVIAL_DEFAULT = 0x20000;
183     protected static final int NEXT_AVAIL_FLAG = 0x40000;
184 
185     /** True iff this lambda is only "called" inline. */
getInlineOnly()186     public final boolean getInlineOnly() { return (flags & INLINE_ONLY) != 0; }
setInlineOnly(boolean inlineOnly)187     public final void setInlineOnly(boolean inlineOnly)
188     { setFlag(inlineOnly, INLINE_ONLY); }
189 
inlinedInCheckMethod()190     public final boolean inlinedInCheckMethod() {
191         return (flags & HAS_NONTRIVIAL_PATTERN) != 0;
192     }
193 
194     /** True if no primitive method is created for this procedure.
195         Specifically if {@code getInlineOnly() || inlinedInCheckMethod()} .*/
inlinedInCallerOrCheckMethodOnly()196     public boolean inlinedInCallerOrCheckMethodOnly() {
197         return (flags & (INLINE_ONLY|HAS_NONTRIVIAL_PATTERN)) != 0;
198     }
199 
200     /** Note this function is inlined in a give context.
201      * This is meant to be used during validate-apply processing,
202      * for procedures that will be inlined in a compile method.
203      */
setInlineOnly(Expression returnContinuation, LambdaExp caller)204     public final void setInlineOnly(Expression returnContinuation,
205                                     LambdaExp caller) {
206         setInlineOnly(true);
207         this.returnContinuation = returnContinuation;
208         this.inlineHome = caller;
209     }
210 
getNeedsClosureEnv()211     public final boolean getNeedsClosureEnv() {
212         return (flags & (NEEDS_STATIC_LINK|IMPORTS_LEX_VARS)) != 0;
213     }
214 
215     /** True if a child lambda uses lexical variables from outside.
216         Hence, a child heapFrame needs a staticLink to outer frames. */
getNeedsStaticLink()217     public final boolean getNeedsStaticLink()
218     { return (flags & NEEDS_STATIC_LINK) != 0; }
219 
setNeedsStaticLink(boolean needsStaticLink)220     public final void setNeedsStaticLink(boolean needsStaticLink) {
221         if (needsStaticLink) flags |= NEEDS_STATIC_LINK;
222         else flags &= ~NEEDS_STATIC_LINK;
223     }
224 
225     /** True iff this lambda "captures" (uses) lexical variables from outside. */
getImportsLexVars()226     public final boolean getImportsLexVars() {
227         return (flags & IMPORTS_LEX_VARS) != 0;
228     }
229 
setImportsLexVars(boolean importsLexVars)230     public final void setImportsLexVars(boolean importsLexVars) {
231         if (importsLexVars) flags |= IMPORTS_LEX_VARS;
232         else flags &= ~IMPORTS_LEX_VARS;
233     }
234 
setImportsLexVars()235     public final void setImportsLexVars() {
236         int old = flags;
237         flags |= IMPORTS_LEX_VARS;
238 
239         // If this needs an environment (closure), then its callers do too.
240         if ((old & IMPORTS_LEX_VARS) == 0 && nameDecl != null)
241             setCallersNeedStaticLink();
242     }
243 
setNeedsStaticLink()244     public final void setNeedsStaticLink() {
245         int old = flags;
246         flags |= NEEDS_STATIC_LINK;
247 
248         // If this needs an environment (closure), then its callers do too.
249         if ((old & NEEDS_STATIC_LINK) == 0 && nameDecl != null)
250             setCallersNeedStaticLink();
251     }
252 
setCallersNeedStaticLink()253     void setCallersNeedStaticLink() {
254         LambdaExp outer = nameDecl.getContext().currentLambda();
255         for (ApplyExp app = nameDecl.firstCall;  app != null;
256              app = app.nextCall) {
257             LambdaExp caller = app.context;
258             for (; caller != outer && !(caller instanceof ModuleExp);
259                  caller = caller.outerLambda())
260                 caller.setNeedsStaticLink();
261         }
262     }
263 
getCanRead()264     public final boolean getCanRead() {
265         return (flags & CAN_READ) != 0;
266     }
setCanRead(boolean read)267     public final void setCanRead(boolean read) {
268         if (read) flags |= CAN_READ;
269         else flags &= ~CAN_READ;
270     }
271 
272     /** True if this is a method in an ClassExp. */
isClassMethod()273     public final boolean isClassMethod() {
274         return (flags & CLASS_METHOD) != 0;
275     }
276 
setClassMethod(boolean isMethod)277     public final void setClassMethod(boolean isMethod) {
278         if (isMethod) flags |= CLASS_METHOD;
279         else flags &= ~CLASS_METHOD;
280     }
281 
282     /** True iff this is the dummy top-level function of a module body. */
isModuleBody()283     public final boolean isModuleBody() { return this instanceof ModuleExp; }
284 
isAbstract()285     public boolean isAbstract() {
286         return body == QuoteExp.abstractExp;
287     }
288 
isNative()289     public boolean isNative() {
290         return body == QuoteExp.nativeExp;
291     }
292 
293     int callConvention;
294     /** The calling convention used for this function.
295      * It is derived from Compilation's currentCallConvention.
296      * @return One of the CALL_WITH_xxx values in Compilation. */
getCallConvention()297     public int getCallConvention() { return callConvention; }
setCallConvention(Compilation comp)298     public void setCallConvention(Compilation comp) {
299         if (isClassMethod()
300             || (this instanceof ModuleExp
301                 && ((ModuleExp) this).staticInitRun()))
302             callConvention = Compilation.CALL_WITH_RETURN;
303         else {
304             int defaultConvention = comp.currentCallConvention();
305             callConvention =
306                 (defaultConvention < Compilation.CALL_WITH_CONSUMER
307                  && isModuleBody())
308                 ? Compilation.CALL_WITH_CONSUMER
309                 : defaultConvention == Compilation.CALL_WITH_UNSPECIFIED
310                 ? Compilation.CALL_WITH_RETURN
311                 : defaultConvention;
312         }
313     }
usingCallContext()314     public boolean usingCallContext()
315     { return getCallConvention() >= Compilation.CALL_WITH_CONSUMER; }
316 
317     /** This function can finish if specified functions can finish.
318      * I.e. calling this function can complete normally is there is a bit i
319      * such that for all LambdaExp l the mask canFinishCondition.get(l)
320      * bit a zero value for bit i.
321      * May be null if there is no dependency yet in the current execution
322      * path fork, in which case PushApply.canFinishDeps will realize it.
323      * This value is calculated during PushApply and used in InlineCalls.
324      */
325     CanFinishMap canFinishCondition;
326 
327     /** Set of functions whose canFinishCondition may depend on this. */
328     Set<LambdaExp> canFinishListeners;
329 
notifyCanFinish()330     void notifyCanFinish() {
331         Set<LambdaExp> listeners = canFinishListeners;
332         if (listeners != null) {
333             canFinishListeners = null;
334             for (LambdaExp f : listeners) {
335                 f.checkCanFinish();
336             }
337         }
338     }
339 
checkCanFinish()340     void checkCanFinish() {
341         CanFinishMap cond = canFinishCondition;
342         if (cond != null && ! getFlag(LambdaExp.IN_EXPWALKER)) {
343             // See if we can simplify exp.canFinishCondition.
344             // I.e. if any dependencies are now CAN_FINISH.
345             if (cond.canFinish()) {
346                 canFinishCondition = CanFinishMap.CAN_FINISH;
347                 notifyCanFinish();
348             }
349         }
350     }
351 
352 
353 
isHandlingTailCalls()354     public final boolean isHandlingTailCalls() {
355         return isModuleBody()
356             || (getCallConvention() >= Compilation.CALL_WITH_TAILCALLS
357                 && ! isClassMethod());
358     }
359 
variable_args()360     public final boolean variable_args () { return max_args < 0; }
361 
362     ClassType compiledType = Compilation.typeProcedure;
363 
364     /** Return the ClassType of the Procedure this is being compiled into. */
getCompiledClassType(Compilation comp)365     protected ClassType getCompiledClassType(Compilation comp) {
366         if (compiledType == Compilation.typeProcedure)
367             throw new Error("internal error: getCompiledClassType");
368         return compiledType;
369     }
370 
calculateType()371     protected Type calculateType() {
372         return compiledType;
373     }
374 
375     /** The ClassType generated for this class.
376      * Only used for ClassExp (which overrides this method) or ModuleExp.
377      */
getClassType()378     public ClassType getClassType() { return compiledType; }
379 
setType(ClassType type)380     public void setType (ClassType type) {
381         this.compiledType = type;
382         this.type = type;
383     }
384 
385     /** Number of argument variable actually passed by the caller.
386      * For functions that accept more than 4 argument, or take a variable number,
387      * this is 1, since in that all arguments are passed in a single array. */
incomingArgs()388     public int incomingArgs() {
389         // The max_args > 0 is a hack to handle LambdaProcedure, which
390         // currently always uses a single array argument.
391         return min_args == max_args && max_args <= 4 && max_args > 0 ? max_args : 1;
392     }
393 
394     /* * If non-zero, the selector field of the ModuleMethod for this. * /
395     //int selectorValue;
396 
397     int getSelectorValue(Compilation comp) {
398         int s = selectorValue;
399         if (s == 0) {
400             s = comp.maxSelectorValue;
401             comp.maxSelectorValue = s + primMethods.length;
402             selectorValue = ++s;
403         }
404         return s;
405     }
406     */
407 
408     Method checkMethod;
409     /*
410     public Method getCheckMethod() {
411         Method m = checkMethod;
412         if (m == null) {
413             m =
414             checkMethod = m;
415         }
416         return m;
417     }
418     */
419 
420     /** Methods used to implement this functions.
421      * primMethods[0] is used if the argument count is min_args;
422      * primMethods[1] is used if the argument count is min_args+1;
423      * primMethods[primMethods.length-1] is used otherwise.
424      * If HAS_NONTRIVIAL_DEFAULT there is one extra.
425      */
426     Method[] primMethods;
427     /** If in a ClassExp which isMakingClassPair, the static body methods.
428      * Otherwise, same as primMethods. */
429     Method[] primBodyMethods;
430 
431     /** Select the method used given an argument count. */
getMethod(int nonSpliceCount, int spliceCount)432     public final Method getMethod(int nonSpliceCount, int spliceCount) {
433         if (primMethods == null || (max_args >= 0 && nonSpliceCount > max_args))
434             return null;
435         if (keywords != null || (opt_args > 0 && primMethods.length == 1))
436             return null;
437         int index = nonSpliceCount - min_args;
438         if (index < 0)
439             return null; // Too few arguments.
440         int length = primMethods.length;
441         if (spliceCount > 0)
442             return length == 1 ? primMethods[0] : null;
443         if (getFlag(HAS_NONTRIVIAL_DEFAULT))
444             length--;
445         return primMethods[index < length ? index : length - 1];
446     }
447 
448     /** Get the method that contains the actual body of the procedure.
449      * (The other methods are just stubs that call that method.) */
getMainMethod()450     public final Method getMainMethod() {
451         Method[] methods = primBodyMethods;
452         return methods == null ? null
453             : methods[methods.length-(getFlag(HAS_NONTRIVIAL_DEFAULT)?2:1)];
454     }
455 
456     /** Return the parameter type of the "keyword/rest" parameters. */
restArgType()457     public final Type restArgType() {
458         if (min_args == max_args)
459             return null;
460         if (primMethods == null)
461             throw new Error("internal error - restArgType");
462         Method[] methods = primMethods;
463         if (max_args >= 0 && methods.length > max_args - min_args)
464             return null;
465         Method method = methods[methods.length-1];
466         Type[] types = method.getParameterTypes();
467         int ilast = types.length-1;
468         if (method.getName().endsWith("$X"))
469             ilast--;
470         return types[ilast];
471     }
472 
outerLambda()473     public LambdaExp outerLambda() {
474         return getOuter() == null ? null : getOuter().currentLambda ();
475     }
476 
outerLambdaOrCaller()477     public LambdaExp outerLambdaOrCaller() {
478         return getInlineOnly() ? inlineHome : outerLambda();
479     }
480 
481     /** Return the closest outer non-inlined LambdaExp. */
482 
outerLambdaNotInline()483     public LambdaExp outerLambdaNotInline() {
484         for (ScopeExp exp = this; (exp = exp.getOuter()) != null; ) {
485             if (exp instanceof LambdaExp) {
486                 LambdaExp result = (LambdaExp) exp;
487                 if (! result.getInlineOnly())
488                     return result;
489             }
490         }
491         return null;
492     }
493 
494     /** True if given LambdaExp is inlined in this function, perhaps indirectly.
495      * Is false if this is not inline-only or if getCaller() is not inlined is
496      * outer.  Usually the same as (this.outerLambdaNotInline()==outer),
497      * except in the case that outer.getInlineOnly(). */
inlinedIn(LambdaExp outer)498     boolean inlinedIn(LambdaExp outer) {
499         for (LambdaExp exp = this; ; exp = exp.getCaller()) {
500             if (exp == outer)
501                 return true;
502             if (! exp.getInlineOnly())
503                 return false;
504         }
505     }
506 
507     /** For an INLINE_ONLY function, return the function it gets inlined in. */
getCaller()508     public LambdaExp getCaller() {
509         return inlineHome;
510     }
511 
512     Variable thisVariable;
513 
declareThis(ClassType clas)514     public Variable declareThis(ClassType clas) {
515         if (thisVariable == null) {
516             thisVariable = new Variable("this");
517             getVarScope().addVariableAfter(null, thisVariable);
518             thisVariable.setParameter (true);
519         }
520         if (thisVariable.getType() == null)
521             thisVariable.setType(clas);
522         if (decls != null && decls.isThisParameter())
523             decls.var = thisVariable;
524         return thisVariable;
525     }
526 
declareClosureEnv()527     public Variable declareClosureEnv() {
528         if (closureEnv == null && getNeedsClosureEnv()) {
529             LambdaExp parent = outerLambdaOrCaller();
530             if (parent instanceof ClassExp)
531                 parent = parent.outerLambda();
532             if (isClassMethod() && ! "*init*".equals(getName()))
533                 closureEnv = declareThis(compiledType);
534             else if (parent.heapFrame == null && ! parent.getNeedsStaticLink()
535                      && ! (parent instanceof ModuleExp))
536                 closureEnv = null;
537             else if (! isClassGenerated() && ! getInlineOnly()) {
538                 Method primMethod = getMainMethod();
539                 boolean isInit = "*init*".equals(getName());
540                 if (primMethod != null && ! primMethod.getStaticFlag()
541                     && ! isInit)
542                     closureEnv = declareThis(primMethod.getDeclaringClass());
543                 else if (inlinedInCheckMethod()) {
544                     Type envType = getOwningLambda().getHeapFrameType();
545                     closureEnv = new Variable(CLOSURE_ENV_NAME, envType);
546                     getVarScope().addVariable(closureEnv);
547                 } else {
548                     Type envType = primMethod.getParameterTypes()[0];
549                     closureEnv = new Variable(CLOSURE_ENV_NAME, envType);
550                     Variable prev;
551                     if (isInit)
552                         prev = declareThis(primMethod.getDeclaringClass());
553                     else
554                         prev = null;
555                     getVarScope().addVariableAfter(prev, closureEnv);
556                     closureEnv.setParameter(true);
557                 }
558             } else {
559                 if (inlineHome != null)
560                     inlineHome.declareClosureEnv();
561                 closureEnv =
562                     parent.heapFrame != null && parent == outerLambda()
563                     ? parent.heapFrame
564                     : parent.closureEnv;
565             }
566         }
567         return closureEnv;
568     }
569 
LambdaExp()570     public LambdaExp() {
571     }
572 
LambdaExp(int args)573     public LambdaExp(int args) {
574         min_args = args;
575         max_args = args;
576     }
577 
578 
LambdaExp(Expression body)579     public LambdaExp(Expression body) {
580         this.body = body;
581     }
582 
583     /** Generate code to load heapFrame on the JVM stack. */
loadHeapFrame(Compilation comp)584     public void loadHeapFrame (Compilation comp) {
585         LambdaExp curLambda = comp.curLambda;
586         while (curLambda != this && curLambda.getInlineOnly())
587             curLambda = curLambda.getCaller();
588 
589         gnu.bytecode.CodeAttr code = comp.getCode();
590         if (curLambda.heapFrame != null && this == curLambda) {
591             code.emitLoad(curLambda.heapFrame);
592             return;
593         }
594         ClassType curType;
595         if (curLambda.closureEnv != null) {
596             code.emitLoad(curLambda.closureEnv);
597             curType = (ClassType) curLambda.closureEnv.getType();
598         } else {
599             code.emitPushThis();
600             curType = comp.curClass;
601         }
602         while (curLambda != this) {
603             Field link = curLambda.staticLinkField;
604             if (link != null && link.getDeclaringClass() == curType) {
605                 code.emitGetField(link);
606                 curType = (ClassType) link.getType();
607             }
608             curLambda = curLambda.outerLambdaOrCaller();
609         }
610     }
611 
612     /** Get the i'the formal parameter. */
getArg(int i)613     Declaration getArg(int i) {
614         for (Declaration var = firstDecl();  ; var = var.nextDecl()) {
615             if (var == null)
616                 throw new Error ("internal error - getArg");
617             if (i == 0)
618                 return var;
619             --i;
620         }
621     }
622 
compileEnd(Compilation comp)623     public void compileEnd (Compilation comp) {
624         gnu.bytecode.CodeAttr code = comp.getCode();
625         HashMap<String,Variable> varMap = new HashMap<String,Variable>();
626 
627         Label endLabel = new Label(code);
628         while (pendingInlines != null && ! pendingInlines.isEmpty()) {
629             LambdaExp child = (LambdaExp) pendingInlines.remove();
630             Target ctarget = (Target) pendingInlines.remove();
631             if (child.getInlineOnly()
632                 && ! child.getFlag(LambdaExp.METHODS_COMPILED)
633                 && child.startForInlining != null) {
634                 if (code.reachableHere())
635                     code.emitGoto(endLabel);
636                 child.compileAsInlined(comp, ctarget);
637             }
638         }
639         if (endLabel.isUsed())
640             endLabel.define(code);
641         code.getCurrentScope().fixParamNames(varMap);
642         popScope(code);        // Undoes enterScope in allocParameters
643 
644         if (! inlinedInCallerOrCheckMethodOnly()) {
645             if (comp.method.reachableHere()
646                 && (getCallConvention() < Compilation.CALL_WITH_TAILCALLS
647                     || isModuleBody() || isClassMethod() || isHandlingTailCalls())) {
648                 code.emitReturn();
649             }
650             code.getCurrentScope().fixParamNames(varMap);
651             code.popScope(); // Undoes pushScope in method.initCode.
652         }
653 
654         for (LambdaExp child = firstChild;  child != null; ) {
655             if (! child.getCanRead() && ! child.getInlineOnly()
656                 && child.getFlag(Expression.VALIDATED)) {
657                 child.compileAsMethod(comp);
658             }
659             else if (child instanceof ClassExp) {
660                 ((ClassExp) child).compileMembers(comp);
661             }
662             child = child.nextSibling;
663         }
664 
665         if (heapFrame != null)
666             comp.generateConstructor(this);
667         generateApplyMethods(comp);
668     }
669 
generateApplyMethods(Compilation comp)670     public void generateApplyMethods(Compilation comp) {
671         //comp.generateCheckMethods(this);
672     }
673 
allocFieldFor(Compilation comp)674     Field allocFieldFor(Compilation comp) {
675         if (nameDecl != null && nameDecl.getField() != null
676             && nameDecl.getValueRaw() == this)
677             return nameDecl.getField();
678         boolean needsClosure = getNeedsClosureEnv();
679         ClassType frameType = needsClosure ? getOwningLambda().getHeapFrameType()
680             : comp.mainClass;
681         String name = getName();
682         String fname
683             = name == null ? "lambda" : Mangling.mangleField(name);
684         int fflags = Access.FINAL;
685         if (nameDecl != null && nameDecl.context instanceof ModuleExp) {
686             boolean external_access = nameDecl.needsExternalAccess();
687             if (external_access)
688                 fname = Declaration.PRIVATE_PREFIX + fname;
689             if (nameDecl.getFlag(Declaration.STATIC_SPECIFIED)) {
690                 fflags |= Access.STATIC;
691                 // A static field in a non-static module is
692                 // initialized in <init>, not <clinit>,
693                 // which is bad for a "static final" field.
694                 if (! ((ModuleExp) nameDecl.context).isStatic())
695                     fflags &= ~Access.FINAL;
696             }
697             // In immediate mode we may need to access the field from a future
698             // command in a different "runtime package" (see JVM spec) because it
699             // gets loaded by a different class loader.  So make the field public.
700             if (! nameDecl.isPrivate() || external_access || comp.immediate)
701                 fflags |= Access.PUBLIC;
702             if ((flags & OVERLOADABLE_FIELD) != 0) {
703                 String fname0 = fname;
704                 int suffix = min_args == max_args ? min_args : 1;
705                 do { fname = fname0 + '$' + suffix++; }
706                 while (frameType.getDeclaredField(fname) != null);
707             }
708         } else {
709             fname = fname + "$Fn" + ++comp.localFieldIndex;
710             if (! needsClosure)
711                 fflags |= Access.STATIC;
712         }
713         Field field =
714             frameType.addField(fname, Compilation.typeCompiledProc, fflags);
715         if (nameDecl != null)
716             nameDecl.setField(field);
717         return field;
718     }
719 
addApplyMethod(Compilation comp, Field field)720     final void addApplyMethod(Compilation comp, Field field) {
721         LambdaExp owner = this;
722         if (field != null && field.getStaticFlag())
723             owner = comp.getModule();
724         else {
725             // Similar to getOwningLambda(), but we can't add apply methods
726             // to a ClassExp - at least not unless it extends ModuleBody.
727             for (;;) {
728                 owner = owner.outerLambda();
729                 if (owner instanceof ModuleExp
730                     || owner.heapFrame != null)
731                     break;
732             }
733             ClassType frameType = owner.getHeapFrameType();
734             if (! (frameType.getSuperclass().isSubtype(Compilation.typeCompiledProc)))
735                 owner = comp.getModule();
736         }
737         if (owner.applyMethods == null)
738             owner.applyMethods = new ArrayList<LambdaExp>();
739         owner.applyMethods.add(this);
740         checkMethod = comp.generateCheckMethod(this, owner);
741     }
742 
compileSetField(Compilation comp)743     public Field compileSetField(Compilation comp) {
744         if (primMethods == null
745             && ! inlinedInCheckMethod())
746             allocMethod(outerLambda(), comp);
747         Field field = allocFieldFor(comp);
748         if (comp.usingCPStyle())
749             compile(comp, Type.objectType);
750         else {
751             if (! inlinedInCheckMethod())
752                 compileAsMethod(comp);
753             addApplyMethod(comp, field);
754         }
755         if (nameDecl != null)
756             nameDecl.compileAnnotations(field, ElementType.FIELD);
757         return (new ProcInitializer(this, comp, field)).field;
758     }
759 
compile(Compilation comp, Target target)760     public void compile(Compilation comp, Target target) {
761         if (target instanceof IgnoreTarget)
762             return;
763         if (getInlineOnly()) {
764             // Normally this shouldn't happen.  One case where it does
765             // is when passing an inline-only lambda as a parameter to a function
766             // that doesn't get fully inlined.  Cleaner would be to elide
767             // the ignored parameter.
768             QuoteExp.nullExp.compile(comp, target);
769             return;
770         }
771         Type rtype;
772         CodeAttr code = comp.getCode();
773 
774         /*
775         if (comp.usingCPStyle()) {
776             //	Label func_start = new Label(code);
777             Label func_end = new Label(code);
778             LambdaExp saveLambda = comp.curLambda;
779             comp.curLambda = this;
780             type = saveLambda.type;
781             closureEnv = saveLambda.closureEnv;
782             // if (comp.usingCPStyle()) {
783             //     heapFrame = comp.thisDecl;
784             //     for (Declaration var = firstDecl();
785             // 	 var != null; var = var.nextDecl())
786             //       var.assignField(comp);
787             //   }
788             gnu.bytecode.SwitchState fswitch = comp.fswitch;
789             int pc = comp.fswitch.getMaxValue() + 1;
790             code.emitGoto(func_end);
791             Type[] stackTypes = code.saveStackTypeState(true);
792 
793             fswitch.addCase(pc, code);
794             // code.emitPushThis();
795             // code.emitGetField(comp.argsCallContextField);
796             // code.emitStore(comp.argsArray);
797             allocParameters(comp);
798             enterFunction(comp);
799 
800             compileBody(comp);
801             comp.curLambda = saveLambda;
802             func_end.define(code);
803             code.restoreStackTypeState(stackTypes);
804             ClassType ctype = comp.curClass;
805             rtype = ctype;
806             // code.emitNew(ctype);
807             // code.emitDup(ctype);
808             // code.emitInvokeSpecial(ctype.constructor);
809             // code.emitDup(ctype);
810             // code.emitPushInt(pc);
811             // code.emitPutField(comp.saved_pcCallFrameField);
812             // if (isHandlingTailCalls())
813             //   {
814             //     // Set name field.
815             //     if (name != null)
816             //       {
817             // 	code.emitDup(ctype);
818             // 	code.emitPushString(name);
819             //  Method setNameMethod =
820             //      Compilation.typeProcedure.getDeclaredMethod("setName", 1);
821             // 	code.emitInvokeVirtual(comp.setNameMethod);
822             //       }
823             //     // Set numArgs field.
824             //     code.emitDup(ctype);
825             //     code.emitPushInt(min_args | (max_args << 12));
826             //     code.emitPutField(comp.numArgsCallFrameField);
827             //     // Set static link field to this CallFrame.
828             //     code.emitDup(ctype);
829             //     code.emitPushThis();
830             //     code.emitPutField(comp.callerCallFrameField);
831             //   }
832           } else
833           */
834         {
835             LambdaExp outer = outerLambda();
836             rtype = Compilation.typeCompiledProc;
837             if ((flags & NO_FIELD) != 0
838                 || comp.dumpingInitializers
839                 || (comp.immediate && outer instanceof ModuleExp
840                     && comp.mainClass == comp.moduleClass)) {
841                 compileAsMethod(comp);
842                 addApplyMethod(comp, null);
843                 Variable savedInstance = comp.moduleInstanceVar;
844                 comp.moduleInstanceVar = null;
845                 ProcInitializer.emitLoadModuleMethod(this, comp);
846                 comp.moduleInstanceVar = savedInstance;
847             } else {
848                 Field field = compileSetField(comp);
849                 if (field.getStaticFlag())
850                     code.emitGetStatic(field);
851                 else {
852                     LambdaExp parent = comp.curLambda;
853                     while (parent.getInlineOnly() && parent.heapFrame == null)
854                         parent = parent.outerLambda();
855                     Variable frame
856                         = parent.heapFrame != null ? parent.heapFrame
857                         : parent.closureEnv;
858                     code.emitLoad(frame);
859                     code.emitGetField(field);
860                 }
861             }
862         }
863         target.compileFromStack(comp, rtype);
864     }
865 
getHeapFrameType()866     public ClassType getHeapFrameType() {
867         if (isClassGenerated())
868             return (ClassType) getType();
869         else
870             return (ClassType) heapFrame.getType();
871     }
872 
873 
getOwningLambda()874     public LambdaExp getOwningLambda() {
875         ScopeExp exp = getOuter();
876         for (;; exp = exp.getOuter()) {
877             if (exp == null)
878                 return null;
879             if (exp instanceof ModuleExp
880                 || (exp instanceof ClassExp && getNeedsClosureEnv())
881                 || (exp instanceof LambdaExp
882                     && ((LambdaExp) exp).heapFrame != null))
883                 return (LambdaExp) exp;
884         }
885     }
886 
887     String primMethodName;
getMethodName(Compilation comp)888     String getMethodName(Compilation comp) {
889         if (primMethodName == null) {
890             StringBuilder nameBuf = new StringBuilder(60);
891             LambdaExp outer = outerLambda();
892             String name = getName();
893            if (! (outer.isModuleBody() || outer instanceof ClassExp)
894                 || name == null) {
895                 nameBuf.append("lambda");
896                 nameBuf.append(+(++comp.method_counter));
897             }
898             if (outer instanceof ClassExp
899                 && this == ((ClassExp) outer).clinitMethod)
900                 nameBuf.append("<clinit>");
901             else if (getSymbol() != null)
902                 nameBuf.append(Mangling.mangleName(name));
903             primMethodName = nameBuf.toString();
904         }
905         return primMethodName;
906     }
907 
addMethodFor(Compilation comp, ObjectType closureEnvType)908     void addMethodFor(Compilation comp, ObjectType closureEnvType) {
909         ScopeExp sc = this;
910         while (sc != null && ! (sc instanceof ClassExp))
911             sc = sc.getOuter();
912         ClassType ctype;
913         // If this is nested inside a Class, then create the method in that
914         // class - in case it references a private field/method.
915         if (sc != null)
916             ctype = ((ClassExp) sc).instanceType;
917         else
918             ctype = getOwningLambda().getHeapFrameType();
919         addMethodFor(ctype, comp, closureEnvType);
920     }
921 
addMethodFor(ClassType ctype, Compilation comp, ObjectType closureEnvType)922     void addMethodFor(ClassType ctype, Compilation comp,
923                       ObjectType closureEnvType) {
924         // generate_unique_name (new_class, child.getName());
925         String name = getName();
926         LambdaExp outer = outerLambda();
927 
928         int key_args = keywords == null ? 0 : keywords.length;
929         boolean simpleMatch = true;
930         int numStubs =
931             ((flags & DEFAULT_CAPTURES_ARG) != 0) ? 0 : opt_args;
932         // check for complications
933         if (key_args > 0
934             || getFlag(HAS_NONTRIVIAL_PATTERN)) { simpleMatch = false; numStubs = 0; } // For simplicity - FIXME?
935         boolean varArgs = max_args < 0 || min_args + numStubs < max_args;
936 
937         boolean handleSuppliedArg = numStubs > 0 && getFlag(HAS_NONTRIVIAL_DEFAULT);
938         if (handleSuppliedArg)
939             numStubs++;
940         Method[] methods = new Method[numStubs + 1];
941         // We assume that for "pair" class methods that ClassExp.declareParts first
942         // calls this method to create the interface method, and then calls us
943         // to create the static implementation method.
944         primBodyMethods = methods;
945         if (primMethods == null)
946             primMethods = methods;
947 
948         boolean isStatic;
949         // 'I' if initMethod ($finit$); 'C' if clinitMethod (<clinit>).
950         char isInitMethod = '\0';
951         if (nameDecl != null
952             && nameDecl.getFlag(Declaration.NONSTATIC_SPECIFIED))
953             isStatic = false;
954         else if (nameDecl != null
955                  && nameDecl.getFlag(Declaration.STATIC_SPECIFIED))
956             isStatic = true;
957         else if (isClassMethod()) {
958             if (outer instanceof ClassExp) {
959                 ClassExp cl = (ClassExp) outer;
960                 isStatic = cl.isMakingClassPair() && closureEnvType != null;
961                 if (this == cl.initMethod)
962                     isInitMethod = 'I';
963                 else if (this == cl.clinitMethod) {
964                     isInitMethod = 'C';
965                     isStatic = true;
966                 }
967             } else
968                 isStatic = false;
969         } else if (thisVariable != null || closureEnvType == ctype)
970             isStatic = false;
971         else if (nameDecl != null && nameDecl.context instanceof ModuleExp) {
972             ModuleExp mexp = (ModuleExp) nameDecl.context;
973             isStatic = mexp.getSuperType() == null && mexp.getInterfaces() == null;
974         } else
975             isStatic = true;
976 
977         int mflags = isStatic ? Access.STATIC : 0;
978         if (nameDecl != null) {
979             if (nameDecl.needsExternalAccess())
980                 mflags |= Access.PUBLIC;
981             else {
982                 short defaultFlag = nameDecl.isPrivate() ? 0 : Access.PUBLIC;
983                 if (isClassMethod())
984                     defaultFlag = nameDecl.getAccessFlags(defaultFlag);
985                 mflags |= defaultFlag;
986             }
987         }
988         if (getFlag(PUBLIC_METHOD))
989             mflags |= Access.PUBLIC;
990         StringBuilder nameBuf = new StringBuilder(getMethodName(comp));
991         if (getFlag(SEQUENCE_RESULT))
992             nameBuf.append("$C");
993         boolean withContext
994             = (getCallConvention() >= Compilation.CALL_WITH_CONSUMER
995                && isInitMethod == '\0');
996         if (isInitMethod != '\0') {
997             if (isStatic) {
998                 // if cl.isMakingClassPair() - i.e. defining a non-simple class:
999                 // In this case the $finit$ method needs to be explicitly called
1000                 // by sub-class constructors.  See Compilation.callInitMethods.
1001                 mflags = (mflags & ~Access.PROTECTED+Access.PRIVATE)+Access.PUBLIC;
1002             } else {
1003                 // if ! cl.isMakingClassPair() - i.e. defining a simple class:
1004                 // Make it private to prevent inherited $finit$ from overriding
1005                 // the current one - and thus preventing its execution.
1006                 mflags = (mflags & ~Access.PUBLIC+Access.PROTECTED)+Access.PRIVATE;
1007             }
1008         }
1009         if (ctype.isInterface() || isAbstract())
1010             mflags |= Access.ABSTRACT;
1011         if (isNative())
1012             mflags |= Access.NATIVE;
1013 
1014         // If a class method has unspecified parameter types, see if we
1015         // can "inherit" the parameter types from an inherited method.
1016         if (isClassMethod() && outer instanceof ClassExp
1017             && min_args == max_args) {
1018             Method[] inherited = null;
1019             int iarg = 0;
1020             param_loop:
1021             for (Declaration param = firstDecl(); ;
1022                  param = param.nextDecl(), iarg++) {
1023                 if (param == null) {
1024                     if (returnType != null)
1025                         break;
1026                 } else if (param.isThisParameter()) {
1027                     iarg--;
1028                     continue;
1029                 } else if (param.getFlag(Declaration.TYPE_SPECIFIED))
1030                     continue;
1031                 if (inherited == null) {
1032                     final String mangled = nameBuf.toString();
1033                     gnu.bytecode.Filter filter
1034                         = new gnu.bytecode.Filter() {
1035                                 public boolean select(Object value) {
1036                                     gnu.bytecode.Method method = (gnu.bytecode.Method) value;
1037                                     if (! method.getName().equals(mangled))
1038                                         return false;
1039                                     Type[] ptypes = method.getParameterTypes();
1040                                     return ptypes.length == min_args;
1041                                 }
1042                             };
1043                     inherited = ctype.getMethods(filter, 2);
1044                 }
1045                 Type type = null;
1046                 for (int i = inherited.length;  --i >= 0; ) {
1047                     Method method = inherited[i];
1048                     Type ptype = param == null ? method.getReturnType()
1049                         : method.getParameterTypes()[iarg];
1050                     if (type == null)
1051                         type = ptype;
1052                     else if (ptype != type) {
1053                         // More than one method with inconsistent parameter type.
1054                         if (param == null)
1055                             break param_loop;
1056                         else
1057                             continue param_loop;
1058                     }
1059                 }
1060                 if (type != null) {
1061                     type = comp.getLanguage().getLangTypeFor(type);
1062                     if (param != null)
1063                         param.setType(type);
1064                     else
1065                         setCoercedReturnType(type);
1066                 }
1067                 if (param == null)
1068                     break param_loop;
1069             }
1070         }
1071 
1072         Type rtype
1073             = (getFlag(SEQUENCE_RESULT)
1074                || getCallConvention () >= Compilation.CALL_WITH_CONSUMER)
1075             ? Type.voidType
1076             : getReturnType().promoteIfUnsigned().getImplementationType();
1077         int extraArg = (closureEnvType != null && closureEnvType != ctype) ? 1 : 0;
1078 
1079         String rtypeEnc = comp.getLanguage().encodeType(getReturnType());
1080 
1081         int ctxArg = 0;
1082         if (getCallConvention () >= Compilation.CALL_WITH_CONSUMER
1083             && isInitMethod == '\0')
1084             ctxArg = 1;
1085 
1086         int nameBaseLength = nameBuf.length();
1087         for (int i = 0;  i <= numStubs;  i++) {
1088             nameBuf.setLength(nameBaseLength);
1089             ArrayList<Type> argTypes = new ArrayList<Type>();
1090             if (extraArg > 0)
1091                 argTypes.add(closureEnvType);
1092             Stack<String> encTypes = new Stack<String>();
1093             int encTypesSize = rtypeEnc == null /* || not interesting */ ? 0 : 1;
1094             encTypes.add(encTypesSize == 0 ? "" : rtypeEnc);
1095             Declaration var = firstDecl();
1096             if (var != null && var.isThisParameter())
1097                 var = var.nextDecl();
1098             int argi = 0;
1099             for (; var != null; var = var.nextDecl()) {
1100                 if (var.getFlag(Declaration.IS_SUPPLIED_PARAMETER)
1101                     && ! var.getFlag(Declaration.IS_PARAMETER )
1102                     && i < numStubs)
1103                     continue;
1104                 if (var.getFlag(Declaration.IS_REST_PARAMETER)) {
1105                 Type lastType = var.getType();
1106                 String lastTypeName = lastType.getName();
1107                 if (! simpleMatch)
1108                     ;
1109                 else if (handleSuppliedArg && i == numStubs)
1110                     nameBuf.append("$P");
1111                 else if (lastType instanceof ArrayType)
1112                     mflags |= Access.VARARGS;
1113                 else
1114                     nameBuf.append("$V");
1115                 } else if (numStubs > 0 && argi >= min_args + i)
1116                     break;
1117 
1118                 if (var.parameterForMethod())
1119                     argTypes.add(var.getType().promoteIfUnsigned().getImplementationType());
1120                 String encType = comp.getLanguage().encodeType(var.getType());
1121                 if (encType == null /* || not interesting */)
1122                     encType = "";
1123                 else
1124                     encTypesSize = encTypes.size()+1;
1125                 encTypes.add(encType);
1126                 if (var.getFlag(Declaration.IS_PARAMETER))
1127                     argi++;
1128             }
1129             if (ctxArg != 0)
1130                 argTypes.add(Compilation.typeCallContext);
1131             if (withContext)
1132                 nameBuf.append("$X");
1133 
1134             boolean classSpecified
1135                 = (outer instanceof ClassExp
1136                    || (outer instanceof ModuleExp
1137                        && (((ModuleExp) outer)
1138                            .getFlag(ModuleExp.SUPERTYPE_SPECIFIED))));
1139             if (! simpleMatch)
1140                 nameBuf.append("$P");
1141             name = nameBuf.toString();
1142             Type[] atypes = argTypes.toArray(new Type[argTypes.size()]);
1143 
1144             // Rename the method if an existing method has the same
1145             // name and type in this class.
1146             // Additionally, if the base class or interfaces were not explicitly
1147             // specified, then search super-classes for conflicting methods
1148             // (such as "run" or "apply").
1149             int renameCount = 0;
1150             int len = nameBuf.length();
1151             String suffix = nameBuf.substring(nameBaseLength, len);
1152             retry:
1153             for (;;) {
1154                 for (ClassType t = ctype;  t != null; t = t.getSuperclass()) {
1155                     if (t.getDeclaredMethod(name, atypes) != null) {
1156                         nameBuf.setLength(nameBaseLength);
1157                         nameBuf.append('$');
1158                         nameBuf.append(++renameCount);
1159                         nameBuf.append(suffix);
1160                         name = nameBuf.toString();
1161                         continue retry;
1162                     }
1163                     if (classSpecified)
1164                         // Do not search in super-classes
1165                         break;
1166                 }
1167                 break;
1168             }
1169 
1170             Method method = ctype.addMethod(name, atypes, rtype, mflags);
1171             // Maybe emit kawa.SourceMethodType annotation.
1172             if (encTypesSize > 0
1173                 && ! (nameDecl != null
1174                       && nameDecl.getAnnotation(kawa.SourceMethodType.class) != null)) {
1175                 AnnotationEntry ae =
1176                     new AnnotationEntry(ClassType.make("kawa.SourceMethodType"));
1177                 while (encTypes.size() > encTypesSize)
1178                     encTypes.pop();
1179                 ae.addMember("value", encTypes,
1180                              ArrayType.make(Type.javalangStringType));
1181                 RuntimeAnnotationsAttr.maybeAddAnnotation(method, ae);
1182             }
1183 
1184             methods[i] = method;
1185 
1186             if (throwsSpecification != null && throwsSpecification.length > 0) {
1187                 int n = throwsSpecification.length;
1188                 ClassType[] exceptions = new ClassType[n];
1189                 for (int j = 0;  j < n;  j++) {
1190                     ClassType exception = null;
1191                     Expression throwsExpr = throwsSpecification[j];
1192                     String msg = null;
1193                     if (throwsExpr instanceof ReferenceExp) {
1194                         ReferenceExp throwsRef = (ReferenceExp) throwsExpr;
1195                         Declaration decl = throwsRef.getBinding();
1196                         if (decl != null) {
1197                             Expression declValue = decl.getValue();
1198                             if (declValue instanceof ClassExp)
1199                                 exception
1200                                     = ((ClassExp) declValue).getCompiledClassType(comp);
1201                             else
1202                                 msg = "throws specification "+decl.getName()
1203                                     + " has non-class lexical binding";
1204                         }
1205                         else
1206                             msg = "unknown class "+throwsRef.getName();
1207                     }
1208                     else if (throwsExpr instanceof QuoteExp) {
1209                         Object value = ((QuoteExp) throwsExpr).getValue();
1210                         if (value instanceof Class)
1211                             value = Type.make((Class) value);
1212                         if (value instanceof ClassType)
1213                             exception = (ClassType) value;
1214                         if (exception != null
1215                             && ! exception.isSubtype(Type.javalangThrowableType))
1216                             msg = exception.getName() + " does not extend Throwable";
1217                     }
1218                     if (exception == null && msg == null)
1219                         msg = "invalid throws specification";
1220                     if (msg != null) {
1221                         comp.error('e', msg, throwsExpr);
1222                         exception = Type.javalangThrowableType;
1223                     }
1224                     exceptions[j] = exception;
1225                 }
1226                 ExceptionsAttr attr = new ExceptionsAttr(method);
1227                 attr.setExceptions(exceptions);
1228             }
1229         }
1230     }
1231 
1232     // Can we merge this with allocParameters?
allocChildClasses(Compilation comp)1233     public void allocChildClasses(Compilation comp) {
1234         Method main = getMainMethod();
1235 
1236         if (main != null && ! main.getStaticFlag()) {
1237             CodeAttr code = comp.getCode();
1238             // So this gets declared in the parameter_scope.
1239             scope = code.getCurrentScope();
1240             declareThis(main.getDeclaringClass());
1241             thisVariable.allocateLocal(code);
1242             scope = null;
1243         }
1244 
1245         Declaration decl = firstDecl();
1246         for (;;) {
1247             if (! getInlineOnly() && ! inlinedInCheckMethod()
1248                 && getCallConvention() >= Compilation.CALL_WITH_CONSUMER
1249                 && decl == null) {
1250                 Variable var =
1251                     getVarScope().addVariable(null,
1252                                               Compilation.typeCallContext,
1253                                               "$ctx");
1254                 var.setParameter(true);
1255             }
1256             if (decl == null)
1257                 break;
1258             Variable var = decl.var;
1259             // i is the register to use for the current parameter
1260             if (var != null
1261                 || (getInlineOnly() && decl.ignorable())
1262                 || ! decl.parameterForMethod())
1263                 ;
1264             else if (decl.isSimple () && ! decl.isIndirectBinding()) {
1265                 // For a simple parameter not captured by an inferior lambda,
1266                 // just allocate it in the incoming register.
1267                 var = decl.allocateVariable(null);
1268             } else {
1269                 // This variable was captured by an inner lambda.
1270                 // Its home location is in the heapFrame.
1271                 // Later, we copy it from its incoming register
1272                 // to its home location heapFrame.  Here we just create and
1273                 // assign a Variable for the incoming (register) value.
1274                 String vname = decl.getName();
1275                 if (vname != null)
1276                     vname = Mangling.mangleName(vname).intern();
1277                 Type vtype = decl.getType().promoteIfUnsigned().getImplementationType();
1278                 var = decl.var = getVarScope().addVariable(null, vtype, vname);
1279                 //getVarScope().addVariableAfter(var, decl);
1280                 var.setParameter (true);
1281                 //var.allocateLocal(code);
1282             }
1283             decl = decl.nextDecl();
1284         }
1285 
1286         declareClosureEnv();
1287 
1288         allocFrame(comp);
1289 
1290         allocChildMethods(comp);
1291     }
1292 
allocMethod(LambdaExp outer, Compilation comp)1293     void allocMethod(LambdaExp outer, Compilation comp) {
1294         ObjectType closureEnvType;
1295         if (currentModule().info != null) {
1296             int state = currentModule().info.getState();
1297             if (state>=Compilation.COMPILED && state != Compilation.ERROR_SEEN)
1298                 comp.error('f', "internal error - allocate method for "+this
1299                            +" in module "+currentModule()
1300                            +" that has already been compiled\n(Try removing all class files and doing a full re-compile.)");
1301         }
1302         if (! getNeedsClosureEnv())
1303             closureEnvType = null;
1304         else if (outer.isClassGenerated())
1305             closureEnvType = outer.getCompiledClassType(comp);
1306         else {
1307             LambdaExp owner = outer;
1308             while (owner.heapFrame == null)
1309                 owner = owner.outerLambda();
1310             closureEnvType = (ClassType) owner.heapFrame.getType();
1311         }
1312         addMethodFor(comp, closureEnvType);
1313     }
1314 
pushChild(LambdaExp child)1315     public void pushChild(LambdaExp child) {
1316         child.nextSibling = firstChild;
1317         firstChild = child;
1318     }
1319 
reverseChildList()1320     public void reverseChildList() {
1321         LambdaExp prev = null, child = firstChild;
1322         while (child != null) {
1323             LambdaExp next = child.nextSibling;
1324             child.nextSibling = prev;
1325             prev = child;
1326             child = next;
1327         }
1328         firstChild = prev;
1329     }
1330 
allocChildMethods(Compilation comp)1331     void allocChildMethods(Compilation comp) {
1332         for (LambdaExp child = firstChild;  child != null;
1333              child = child.nextSibling) {
1334             if (child instanceof ClassExp) {
1335                 ClassExp cl = (ClassExp) child;
1336                 if (cl.getNeedsClosureEnv())  {
1337                     ClassType parentFrameType;
1338                     if (isClassGenerated())
1339                         parentFrameType = (ClassType) getType();
1340                     else {
1341                         Variable parentFrame = this.heapFrame != null
1342                             ? this.heapFrame
1343                             : this.closureEnv;
1344                         parentFrameType = (ClassType) parentFrame.getType();
1345                     }
1346                     cl.closureEnvField = cl.staticLinkField
1347                         = cl.instanceType.setOuterLink(parentFrameType);
1348                 }
1349             }
1350         }
1351     }
1352 
allocFrame(Compilation comp)1353     public void allocFrame(Compilation comp) {
1354         if (heapFrame != null)  {
1355             ClassType frameType;
1356             if (isClassGenerated())
1357                 frameType = getCompiledClassType(comp);
1358             else  {
1359                 frameType = new ClassType(comp.generateClassName("frame"));
1360                 frameType.setSuper(comp.getModuleType()); // FIXME - not needed?
1361                 comp.addClass(frameType);
1362             }
1363             heapFrame.setType(frameType);
1364         }
1365     }
1366 
allocParameters(Compilation comp)1367     void allocParameters(Compilation comp) {
1368         CodeAttr code = comp.getCode();
1369         Scope sc = getVarScope();
1370         code.locals.enterScope(sc);
1371         int line = getLineNumber();
1372         if (line > 0)
1373             code.putLineNumber(getFileName(), line);
1374     }
1375 
1376     /** Rembembers stuff to do in <init> of this class. */
1377     Initializer initChain;
1378 
enterFunction(Compilation comp)1379     void enterFunction(Compilation comp) {
1380         CodeAttr code = comp.getCode();
1381 
1382         // Tail-calls loop back to here!
1383         if (! getFlag(LambdaExp.HAS_NONTRIVIAL_PATTERN))
1384             getVarScope().noteStartFunction(code);
1385 
1386         if (closureEnv != null && ! closureEnv.isParameter()
1387             && ! comp.usingCPStyle()) {
1388             if (! inlinedInCallerOrCheckMethodOnly()) {
1389                 code.emitPushThis();
1390                 Field field = closureEnvField;
1391                 if (field == null)
1392                     field = outerLambda().closureEnvField;
1393                 code.emitGetField(field);
1394                 code.emitStore(closureEnv);
1395             } else if (inlinedInCheckMethod()) {
1396                  comp.loadModuleRef(getOwningLambda().getHeapFrameType());
1397 
1398                  code.emitStore(closureEnv);
1399             } else if (! inlinedIn(outerLambda())) {
1400                 outerLambdaOrCaller().loadHeapFrame(comp);
1401                 code.emitStore(closureEnv);
1402             }
1403         }
1404         if (! comp.usingCPStyle()) {
1405             ClassType frameType = heapFrame == null
1406                 ? currentModule().getCompiledClassType(comp)
1407                 : (ClassType) heapFrame.getType();
1408             for (Declaration decl = capturedVars; decl != null;
1409                  decl = decl.nextCapturedVar) {
1410                 if (decl.getField() != null)
1411                     continue;
1412                 decl.makeField(frameType, comp, null);
1413             }
1414         }
1415         if (heapFrame != null && ! comp.usingCPStyle()) {
1416             ClassType frameType = (ClassType) heapFrame.getType();
1417             if (closureEnv != null && ! (this instanceof ModuleExp))
1418                 staticLinkField = frameType.addField("staticLink",
1419                                                      closureEnv.getType());
1420             if (! isClassGenerated()) {
1421                 frameType.setEnclosingMember(comp.method);
1422                 code.emitNew(frameType);
1423                 code.emitDup(frameType);
1424                 Method constructor = Compilation.getConstructor(frameType, this);
1425                 code.emitInvokeSpecial(constructor);
1426 
1427                 if (staticLinkField != null) {
1428                     code.emitDup(frameType);
1429                     code.emitLoad(closureEnv);
1430                     code.emitPutField(staticLinkField);
1431                 }
1432                 heapFrame.allocateLocal(code);
1433                 code.emitStore(heapFrame);
1434                 code.pushAutoPoppableScope().addVariable(heapFrame);
1435             }
1436         }
1437 
1438         if (! inlinedInCheckMethod() && ! (this instanceof ModuleExp)) {
1439             // For each non-artificial parameter, copy it from its incoming
1440             // location (a local variable register, or the argsArray) into
1441             // its home location, if they are different.
1442 
1443             for (Declaration param = firstDecl();  param != null;
1444                  param = param.nextDecl()) {
1445                 saveParameter(param, comp);
1446             }
1447         }
1448     }
1449 
saveParameter(Declaration param, Compilation comp)1450     void saveParameter(Declaration param, Compilation comp) {
1451             if (! param.isSimple() && ! param.ignorable()
1452                 || param.isIndirectBinding()) {
1453                 CodeAttr code = comp.getCode();
1454                 Type paramType = param.getType();
1455                 Type stackType = paramType;
1456                 // If the parameter is captured by an inferior lambda,
1457                 // then the incoming parameter needs to be copied into its
1458                 // slot in the heapFrame.
1459                 if (!param.isSimple())
1460                     param.loadOwningObject(null, comp);
1461                 // This part of the code pushes the incoming argument.
1462                 code.emitLoad(param.getVariable());
1463                 if (param.isIndirectBinding())
1464                     param.pushIndirectBinding(comp);
1465                 if (param.isSimple()) {
1466                     Variable var = param.getVariable();
1467                     if (param.isIndirectBinding())
1468                         var.setType(Compilation.typeLocation);
1469                     code.emitStore(var);
1470                 }
1471                 else
1472                     code.emitPutField(param.getField());
1473             }
1474     }
1475 
compileAsInlined(Compilation comp, Target target)1476     void compileAsInlined(Compilation comp, Target target) {
1477         flags |= LambdaExp.METHODS_COMPILED;
1478 	LambdaExp saveLambda = comp.curLambda;
1479 	comp.curLambda = this;
1480 	allocChildClasses(comp);
1481 	allocParameters(comp);
1482         CodeAttr code = comp.getCode();
1483         if (startForInlining == null)
1484             startForInlining = new Label(code);
1485         startForInlining.define(code);
1486 	ApplyExp.popParams(code, this, null, false);
1487 	enterFunction(comp);
1488 	body.compileWithPosition(comp, target);
1489 	compileEnd(comp);
1490 	comp.curLambda = saveLambda;
1491     }
1492 
compileAsMethod(Compilation comp)1493     void compileAsMethod(Compilation comp) {
1494         if ((flags & METHODS_COMPILED) != 0 || isAbstract() || isNative()
1495             || inlinedInCheckMethod())
1496             return;
1497         flags |= METHODS_COMPILED;
1498         if (primMethods == null)
1499             allocMethod(outerLambda(), comp);
1500         Method save_method = comp.method;
1501         LambdaExp save_lambda = comp.curLambda;
1502         comp.curLambda = this;
1503 
1504         Method method = primMethods[0];
1505         boolean isStatic = method.getStaticFlag();
1506         int numStubs = primMethods.length - 1;
1507         Type restArgType = restArgType();
1508 
1509         long[] saveDeclFlags = null;
1510         if (numStubs > 0) {
1511             saveDeclFlags = new long[countDecls()];
1512             int k = 0;
1513             for (Declaration decl = firstDecl();
1514                  decl != null; decl = decl.nextDecl())
1515                 saveDeclFlags[k++] = decl.flags;
1516         }
1517 
1518         boolean ctxArg = getCallConvention () >= Compilation.CALL_WITH_CONSUMER;
1519 
1520         for (int i = 0;  i <= numStubs;  i++) {
1521             comp.method = primMethods[i];
1522             if (nameDecl != null && ! isClassMethod()) // Only if i == numStubs ???
1523                 nameDecl.compileAnnotations(comp.method, ElementType.METHOD);
1524 
1525             if (i < numStubs) {
1526                 CodeAttr code = comp.method.startCode();
1527                 Declaration decl;
1528                 Variable callContextSave = comp.callContextVar;
1529                 Variable var = code.getArg(0);
1530                 if (! isStatic) {
1531                     code.emitPushThis();
1532                     if (getNeedsClosureEnv())
1533                         closureEnv = var;
1534                     var = code.getArg(1);
1535                 }
1536                 decl = firstDecl();
1537                 int copied = min_args + i;
1538                 if (getFlag(HAS_NONTRIVIAL_DEFAULT)
1539                     && i == numStubs-1
1540                     && restArgType != null)
1541                     copied++;
1542                 for (int j = 0;  j < copied;
1543                      j++, decl = decl.nextDecl()) {
1544                     decl.flags |= Declaration.IS_SIMPLE;
1545                     decl.var = var;
1546                     code.emitLoad(var);
1547                     var = var.nextVar();
1548                     if (decl.getFlag(Declaration.IS_SUPPLIED_PARAMETER)) {
1549                         code.emitPushInt(1);
1550                         decl = decl.nextDecl();
1551                     }
1552                 }
1553                 comp.callContextVar = ctxArg ? var : null;
1554                 boolean suppliedFlags = getFlag(HAS_NONTRIVIAL_DEFAULT);
1555                 int toCall = suppliedFlags ? numStubs : i + 1;
1556                 for (int j = i; decl != null && j < toCall && ! decl.getFlag(Declaration.IS_REST_PARAMETER); ) {
1557                     Expression defaultArg = decl.getInitValue();
1558                     if (decl.getFlag(Declaration.IS_SUPPLIED_PARAMETER)
1559                         && ! (defaultArg instanceof QuoteExp)) {
1560                         code.emitPushDefaultValue(decl.getType());
1561                     } else {
1562                         Target paramTarget =
1563                             StackTarget.getInstance(decl.getType());
1564                         defaultArg.compile(comp, paramTarget);
1565                     }
1566                     if (decl.getFlag(Declaration.IS_SUPPLIED_PARAMETER)) {
1567                         code.emitPushInt(0);
1568                         decl = decl.nextDecl();
1569                     }
1570                     decl = decl.nextDecl();
1571                     j++;
1572                     // Minor optimization: Normally stub[i] calls stub[i+1],
1573                     // which calls stub[i+2] etc until we get to stub[numStubs].
1574                     // That way any given default argument expression is only
1575                     // compiled into a single stub.  However, if the default is a
1576                     // constant it makes sense to call stub[j] (where j>i+1) directly.
1577                     if (toCall < numStubs
1578                         && decl.getInitValue() instanceof QuoteExp)
1579                         toCall++;
1580                 }
1581                 boolean varArgs = toCall == numStubs && i < opt_args && restArgType != null;
1582                 if (varArgs) {
1583                     Expression arg;
1584                     String lastTypeName = restArgType.getName();
1585                     if (restArgType == LangObjType.listType || "gnu.lists.LList".equals(lastTypeName))
1586                         arg = QuoteExp.emptyExp;
1587                     else if ("java.lang.Object[]".equals(lastTypeName))
1588                         arg = new QuoteExp(Values.noArgs);
1589                     else // FIXME
1590                         throw new Error("unimplemented #!rest type "+lastTypeName);
1591                     arg.compile(comp, restArgType);
1592                 }
1593                 if (ctxArg)
1594                     code.emitLoad(var);
1595                 if (isStatic)
1596                     code.emitInvokeStatic(primMethods[toCall]);
1597                 else
1598                     code.emitInvokeVirtual(primMethods[toCall]);
1599                 code.emitReturn();
1600                 closureEnv = null;
1601                 comp.callContextVar = callContextSave;
1602             } else {
1603                 if (saveDeclFlags != null) {
1604                     int k = 0;
1605                     for (Declaration decl = firstDecl();
1606                          decl != null; decl = decl.nextDecl()) {
1607                         decl.flags = saveDeclFlags[k++];
1608                         decl.var = null;
1609                     }
1610                 }
1611                 comp.method.initCode();
1612                 allocChildClasses(comp);
1613                 allocParameters(comp);
1614                 if (getFlag(HAS_NONTRIVIAL_DEFAULT)) {
1615                     for (Declaration decl = firstDecl();
1616                          decl != null; decl = decl.nextDecl()) {
1617                         Expression defaultArg = decl.getInitValue();
1618                         if (decl.getFlag(Declaration.IS_SUPPLIED_PARAMETER)) {
1619                             Declaration supp = decl.nextDecl();
1620                             if (! (defaultArg instanceof QuoteExp)) {
1621                                 CodeAttr code = comp.method.getCode();
1622                                 supp.load(null, 0, comp,
1623                                           Target.pushValue(Type.booleanType));
1624                                 Label doneDefault = new Label(code);
1625                                 code.emitGotoIfIntNeZero(doneDefault);
1626                                 code.emitIfThen();
1627                                 Target paramTarget =
1628                                     StackTarget.getInstance(decl.getType());
1629                                 defaultArg.compile(comp, paramTarget);
1630                                 decl.compileStore(comp);
1631                                 doneDefault.define(code);
1632                             }
1633                             decl = supp;
1634                         }
1635                     }
1636                 }
1637                 enterFunction(comp);
1638 
1639                 compileBody(comp);
1640             }
1641         }
1642 
1643         comp.method = save_method;
1644         comp.curLambda = save_lambda;
1645     }
1646 
1647     public void compileBody(Compilation comp) {
1648         Target target;
1649         Variable callContextSave = comp.callContextVar;
1650         comp.callContextVar = null;
1651         if (getCallConvention() >= Compilation.CALL_WITH_CONSUMER) {
1652             Variable var = getVarScope().lookup("$ctx");
1653             if (var != null && var.getType() == Compilation.typeCallContext)
1654                 comp.callContextVar = var;
1655             target = ConsumerTarget.makeContextTarget(comp, getReturnType());
1656         }
1657         else
1658             target = Target.pushValue(getReturnType());
1659         ScopeExp savedScope = comp.currentScope();
1660         comp.current_scope = this;
1661         body.compileWithPosition(comp, target,
1662                                  body.getLineNumber() > 0 ? body : this);
1663         comp.current_scope = savedScope;
1664         compileEnd(comp);
1665         comp.callContextVar = callContextSave;
1666     }
1667 
1668     /** A cache if this has already been evaluated. */
1669     Procedure thisValue;
1670 
visit(ExpVisitor<R,D> visitor, D d)1671     protected <R,D> R visit(ExpVisitor<R,D> visitor, D d) {
1672         Compilation comp = visitor.getCompilation();
1673         LambdaExp saveLambda;
1674         if (comp == null)
1675             saveLambda = null;
1676         else {
1677             saveLambda = comp.curLambda;
1678             comp.curLambda = this;
1679         }
1680         try {
1681             return visitor.visitLambdaExp(this, d);
1682         } finally {
1683             if (comp != null)
1684                 comp.curLambda = saveLambda;
1685         }
1686     }
1687 
visitChildren(ExpVisitor<R,D> visitor, D d)1688     protected <R,D> void visitChildren(ExpVisitor<R,D> visitor, D d) {
1689         visitChildrenOnly(visitor, d);
1690         visitProperties(visitor, d);
1691     }
1692 
visitChildrenOnly(ExpVisitor<R,D> visitor, D d)1693     protected final <R,D> void visitChildrenOnly(ExpVisitor<R,D> visitor, D d) {
1694         LambdaExp save = visitor.currentLambda;
1695         visitor.currentLambda = this;
1696         try {
1697             throwsSpecification = visitor.visitExps(throwsSpecification, d);
1698             visitor.visitDefaultArgs(this, d);
1699             if (visitor.exitValue == null && body != null)
1700                 body = visitor.update(body, visitor.visit(body, d));
1701         } finally {
1702             visitor.currentLambda = save;
1703         }
1704     }
1705 
visitProperties(ExpVisitor<R,D> visitor, D d)1706     protected final <R,D> void visitProperties(ExpVisitor<R,D> visitor, D d) {
1707         if (properties != null) {
1708             int len = properties.length;
1709             for (int i = 1;  i < len;  i += 2) {
1710                 Object val = properties[i];
1711                 if (val instanceof Expression) {
1712                     properties[i] = visitor.visitAndUpdate((Expression) val, d);
1713                 }
1714             }
1715         }
1716     }
1717 
mustCompile()1718     protected boolean mustCompile() {
1719         if (keywords != null && keywords.length > 0)
1720             return true;
1721         if (opt_args != 0) {
1722             for (Declaration p = firstDecl(); p != null; p = p.nextDecl()) {
1723                 Expression defaultArg = p.getInitValue();
1724                 // Non-constant default arguments require care with scoping.
1725                 if (defaultArg != null && ! (defaultArg instanceof QuoteExp))
1726                     return true;
1727             }
1728         }
1729         return false;
1730     }
1731 
1732     @Override
apply(CallContext ctx)1733     public void apply(CallContext ctx) throws Throwable {
1734         // It would be better to call setIndexes at compile-time, but that
1735         // doesn't work if we're called as a syntax expander at rewrite time.
1736         // Better, if this is a top-level eval, to create a "compile-time" module,
1737         // but I haven't figured out how to do that.  FIXME.
1738         setIndexes();
1739         ctx.writeValue(new Closure(this, ctx));
1740     }
1741 
evalDefaultArg(Declaration param, CallContext ctx)1742     Object evalDefaultArg(Declaration param, CallContext ctx) {
1743         try {
1744             return param.getInitValue().eval(ctx);
1745         } catch (Error ex) {
1746             throw ex;
1747         } catch (Throwable ex) {
1748             throw new WrappedException("error evaluating default argument", ex);
1749         }
1750     }
1751 
validateApply(ApplyExp exp, InlineCalls visitor, Type required, Declaration decl)1752     public Expression validateApply(ApplyExp exp, InlineCalls visitor,
1753                                     Type required, Declaration decl) {
1754         Expression[] args = exp.getArgs();
1755         if (! exp.isSimple()) {
1756             // We might be unable to inline this function. If we need to
1757             // call it using apply, it needs to be readable.
1758             // FIXME better to use pattern-matching:
1759             // Given: (define (fun a b c d) ...)
1760             // Translate: (fun x @y z) to:
1761             // (let (([t1 t2 t3 t4] [x @y z])) (fun t1 t2 t3 t4])
1762             setCanRead(true);
1763             if (nameDecl != null)
1764                 nameDecl.setCanRead(true);
1765         }
1766         if ((flags & ATTEMPT_INLINE) != 0) {
1767             Expression inlined = InlineCalls.inlineCall(this, exp, true);
1768             if (inlined != null)
1769                 return visitor.visit(inlined, required);
1770         }
1771         exp.visitArgs(visitor, this);
1772         int args_length = exp.args.length;
1773         int spliceCount = exp.spliceCount();
1774         int nonSpliceCount = args_length - spliceCount;
1775         int nonSpliceNonKeyCount = nonSpliceCount - 2 * exp.numKeywordArgs;
1776         String msg = WrongArguments.checkArgCount(getName(),
1777                                                   spliceCount > 0 ? 0 : min_args,
1778                                                   max_args,
1779                                                   nonSpliceNonKeyCount);
1780         if (msg != null) {
1781             return visitor.noteError(msg);
1782         }
1783         return exp;
1784     }
1785 
print(OutPort out)1786     public void print(OutPort out) {
1787         out.startLogicalBlock("(Lambda/", ")", 2);
1788         Object sym = getSymbol();
1789         if (sym != null) {
1790             out.print(sym);
1791             out.print('/');
1792         }
1793         out.print(id);
1794         out.print('/');
1795         out.print("fl:");  out.print(Integer.toHexString(flags));
1796         out.writeSpaceFill();
1797         printLineColumn(out);
1798         out.startLogicalBlock("(", false, ")");
1799         Special prevMode = null;
1800         int i = -1;
1801         int key_args = keywords == null ? 0 : keywords.length;
1802         Declaration decl = firstDecl();
1803         if (decl != null && decl.isThisParameter())
1804             i = -2;
1805         for (; decl != null;  decl = decl.nextDecl()) {
1806             if (decl != firstDecl())
1807                 out.writeSpaceFill();
1808             Special mode = prevMode;
1809             if (decl.getFlag(Declaration.IS_PARAMETER)) {
1810                 i++;
1811             if (i < min_args
1812                 || (i == min_args && decl.getFlag(Declaration.PATTERN_NESTED)))
1813                 mode = null;
1814             else if (i < min_args + opt_args)
1815                 mode = Special.optional;
1816             else if (decl.getFlag(Declaration.IS_REST_PARAMETER))
1817                 mode = Special.rest;
1818             else
1819                 mode = Special.key;
1820             }
1821             if (mode != prevMode) {
1822                 out.print(mode);
1823                 out.writeSpaceFill();
1824             }
1825             Expression defaultArg = decl.getInitValue();
1826             if (defaultArg != null)
1827                 out.startLogicalBlock("(", false, ")");
1828             if (decl.getFlag(Declaration.IS_SUPPLIED_PARAMETER)
1829                 && ! decl.getFlag(Declaration.IS_PARAMETER))
1830                 out.print("supplied:");
1831             decl.printInfo(out);
1832             if (defaultArg != null) {
1833                 if (defaultArg != QuoteExp.falseExp) {
1834                     out.writeSpaceFill();
1835                     out.print("default:");
1836                     out.writeSpaceFill();
1837                     defaultArg.print(out);
1838                 }
1839                 out.endLogicalBlock(")");
1840             }
1841             prevMode = mode;
1842         }
1843         out.endLogicalBlock(")");
1844         if (properties != null) {
1845             int plen = properties.length;
1846             for (int j = 0; j < plen; j += 2) {
1847                 Object key = properties[j];
1848                 if (key == null)
1849                     continue;
1850                 out.writeSpaceFill();
1851                 out.startLogicalBlock("", false, "");
1852                 out.print(key);
1853                 out.print(":");
1854                 out.writeSpaceFill();
1855                 out.print(properties[j+1]);
1856                 out.endLogicalBlock("");
1857             }
1858         }
1859         out.writeSpaceLinear();
1860         if (body == null)
1861             out.print("<null body>");
1862         else
1863             body.print(out);
1864         out.endLogicalBlock(")");
1865     }
1866 
getExpClassName()1867     protected final String getExpClassName() {
1868         String cname = getClass().getName();
1869         int index = cname.lastIndexOf('.');
1870         if (index >= 0)
1871             cname = cname.substring(index+1);
1872         return cname;
1873     }
1874 
side_effects()1875     public boolean side_effects () { return false; }
1876 
toString()1877     public String toString() {
1878         String str = getExpClassName()+':'+getSymbol()+'/'+id+'/';
1879 
1880 	int l = getLineNumber();
1881 	if (l <= 0 && body != null)
1882             l = body.getLineNumber();
1883 	if (l > 0)
1884             str = str + "l:" + l;
1885 
1886         return str;
1887     }
1888 
1889     /** If non-null, a sequence of (key, value)-pairs.
1890      * These will be used to call setProperty at run-time. */
1891     Object[] properties;
1892 
getProperty(Object key, Object defaultValue)1893     public Object getProperty(Object key, Object defaultValue) {
1894         if (properties != null) {
1895             for (int i = properties.length;  (i -= 2) >= 0; ) {
1896                 if (properties[i] == key)
1897                     return properties[i + 1];
1898             }
1899         }
1900         return defaultValue;
1901     }
1902 
setProperty(Object key, Object value)1903     public synchronized void setProperty(Object key, Object value) {
1904         properties = PropertySet.setProperty(properties, key, value);
1905     }
1906 
1907     /** If non-null, the type of values returned by this function.
1908      * If null, the return type has not been set or calculated yet. */
1909     public Type returnType;
1910 
1911     /** The return type of this function, i.e the type of its returned values. */
getReturnType()1912     public final Type getReturnType() {
1913         if (returnType == null) {
1914             returnType = Type.objectType;  // To guard against cycles.
1915             // body may not be set if define scan'd but not yet rewritten.
1916             if (body != null && ! isAbstract() && ! isNative()
1917                 && body.getFlag(Expression.VALIDATED))
1918                 returnType = body.getType();
1919         }
1920         return returnType;
1921     }
1922 
1923     /* Set the return type of this function. */
setReturnType(Type returnType)1924     public final void setReturnType(Type returnType) {
1925         this.returnType = returnType;
1926     }
1927 
setCoercedReturnType(Type returnType)1928     public final void setCoercedReturnType(Type returnType) {
1929         this.returnType = returnType;
1930         if (returnType != null
1931             && returnType != Type.objectType
1932             && returnType != Type.voidType
1933             && body != QuoteExp.abstractExp
1934             && body != QuoteExp.nativeExp) {
1935             Expression value = body;
1936             body = Compilation.makeCoercion(value, returnType);
1937             body.setLine(value);
1938         }
1939     }
1940 
maybeSetReturnType(LambdaExp lexp, Type type)1941     public static void maybeSetReturnType(LambdaExp lexp, Type type) {
1942         if (lexp.returnType == null && type != null
1943             && ! (type instanceof InlineCalls.LenientExpectedType)
1944             && ! (type instanceof InlineCalls.ValueNeededType))
1945             lexp.setCoercedReturnType(type);
1946     }
1947 
1948     /** Modify LambdaExp so result is coerced to given type. */
setCoercedReturnValue(Expression type, Language language)1949     public final void setCoercedReturnValue(Expression type,
1950                                             Language language) {
1951         if (! isAbstract() && ! isNative()) {
1952             Expression value = body;
1953             body = Compilation.makeCoercion(value, type);
1954             body.setLine(value);
1955         }
1956         gnu.bytecode.Type rtype = language.getTypeFor(type);
1957         if (rtype != null)
1958             setReturnType(rtype);
1959     }
1960 
1961     /** Get the first expression/statement in the body.
1962      * It dives down into {@code BeginExp}s.
1963      * Used to check for {@code invoke-special} calls in {@code @init} methods.
1964      */
getBodyFirstExpression()1965     public Expression getBodyFirstExpression() {
1966         Expression bodyFirst = body;
1967         for (;;) {
1968             if (bodyFirst instanceof BeginExp) {
1969                 BeginExp bbody = (BeginExp) bodyFirst;
1970                 if (bbody.length == 0)
1971                     bodyFirst = null;
1972                 else
1973                     bodyFirst = bbody.exps[0];
1974             } else if (bodyFirst instanceof LetExp) {
1975                 bodyFirst = ((LetExp) bodyFirst).getBody();
1976             } else
1977                 break;
1978         }
1979         return bodyFirst;
1980     }
1981 
1982     /** Check if argument is a this(...) or super(...) initializtion.
1983      * If so, return return the corresponding this or super class.
1984      */
checkForInitCall(Expression bodyFirst)1985     public ClassType checkForInitCall(Expression bodyFirst) {
1986         ClassType calledInit = null;
1987         if (bodyFirst instanceof ApplyExp) {
1988             Expression exp = ((ApplyExp) bodyFirst).func;
1989             if (exp instanceof QuoteExp) {
1990                 Object value = ((QuoteExp) exp).getValue();
1991                 if (value instanceof PrimProcedure) {
1992                     PrimProcedure pproc = (PrimProcedure) value;
1993                     Method meth = pproc.getMethod();
1994                     if (pproc.isSpecial()
1995                         && ("<init>".equals(meth.getName())))
1996                         calledInit = meth.getDeclaringClass();
1997                 }
1998             }
1999         }
2000         return calledInit;
2001     }
2002 
2003     public static class Closure extends MethodProc {
2004         Object[][] evalFrames;
2005         LambdaExp lambda;
2006 
numArgs()2007         public int numArgs() { return lambda.min_args | (lambda.max_args << 12); }
2008 
Closure(LambdaExp lexp, CallContext ctx)2009         public Closure(LambdaExp lexp, CallContext ctx) {
2010             super(true, applyToConsumer);
2011             this.lambda = lexp;
2012 
2013             Object[][] oldFrames = ctx.evalFrames;
2014             if (oldFrames != null) {
2015                 int n = oldFrames.length;
2016                 while (n > 0 && oldFrames[n-1] == null)
2017                     n--;
2018 
2019                 evalFrames = new Object[n][];
2020                 System.arraycopy(oldFrames, 0, evalFrames, 0, n);
2021             }
2022             setSymbol(lambda.getSymbol());
2023         }
2024 
applyToConsumer(Procedure proc, CallContext ctx)2025         public static Object applyToConsumer(Procedure proc, CallContext ctx)
2026                 throws Throwable {
2027             Closure closure = (Closure) proc;
2028             LambdaExp lambda = closure.lambda;
2029             Object[] args = ctx.getArgs();
2030             Object[][] evalFrames = closure.evalFrames;
2031             int num = proc.numArgs();
2032             int nargs = ctx.getArgCount();
2033             int min = num & 0xFFF;
2034             if (nargs < min) {
2035                 ctx.matchError(MethodProc.NO_MATCH_TOO_FEW_ARGS|min);
2036                 return ctx;
2037             }
2038             int max = num >> 12;
2039             if (nargs > max && max >= 0) {
2040                 ctx.matchError(MethodProc.NO_MATCH_TOO_MANY_ARGS|max);
2041                 return ctx;
2042             }
2043             Object[] evalFrame = new Object[lambda.frameSize];
2044             int key_args = lambda.keywords == null ? 0 : lambda.keywords.length;
2045             int opt_args = lambda.opt_args;
2046             int i = 0;
2047             int key_i = 0;
2048             int min_args = lambda.min_args;
2049             for (Declaration decl = lambda.firstDecl(); decl != null;
2050                  decl = decl.nextDecl()) {
2051                 Object value;
2052                 if (i < min_args)
2053                     value = args[i++];
2054                 else if (i < min_args + opt_args) {
2055                     if (i < nargs)
2056                         value = args[i++];
2057                     else
2058                         value = lambda.evalDefaultArg(decl, ctx);
2059                 } else if (lambda.max_args < 0 && i == min_args + opt_args) {
2060                     if (decl.type instanceof ArrayType) {
2061                         int rem = nargs - i;
2062                         Type elementType = ((ArrayType) decl.type).getComponentType();
2063                         if (elementType == Type.objectType) {
2064                             Object[] rest = new Object[rem];
2065                             System.arraycopy(args, i, rest, 0, rem);
2066                             value = rest;
2067                         } else {
2068                             Class elementClass = elementType.getReflectClass();
2069                             value
2070                                 = java.lang.reflect.Array.newInstance(elementClass, rem);
2071                             for (int j = 0;  j < rem;  j++) {
2072                                 Object el;
2073                                 try {
2074                                     el = elementType.coerceFromObject(args[i+j]);
2075                                 } catch (ClassCastException ex) {
2076                                     ctx.matchError(NO_MATCH_BAD_TYPE|(i+j));
2077                                     return ctx;
2078                                 }
2079                                 java.lang.reflect.Array.set(value, j, el);
2080                             }
2081                         }
2082                     }
2083                     else
2084                         value = LList.makeList(args, i);
2085                 }
2086                 else {
2087                     // Keyword argument.
2088                     Keyword keyword = lambda.keywords[key_i++];
2089                     int key_offset = min_args + opt_args;
2090                     value = Keyword.searchForKeyword(args, key_offset, keyword);
2091                     if (value == Special.dfault)
2092                         value = lambda.evalDefaultArg(decl, ctx);
2093                 }
2094                 if (decl.type != null) {
2095                     try {
2096                         value = decl.type.coerceFromObject(value);
2097                     } catch (ClassCastException ex) {
2098                         ctx.matchError(NO_MATCH_BAD_TYPE|i);
2099                         return ctx;
2100                     }
2101                 }
2102                 if (decl.isIndirectBinding()) {
2103                     gnu.mapping.Location loc = decl.makeIndirectLocationFor();
2104                     loc.set(value);
2105                     value = loc;
2106                 }
2107                 evalFrame[decl.evalIndex] = value;
2108             }
2109 
2110             ctx.next = ctx.numArguments();
2111             if (ctx.checkDone() != 0)
2112                 return ctx;
2113 
2114             int level = ScopeExp.nesting(lambda);
2115             Object[][] saveFrames = ctx.evalFrames;
2116 
2117             int numFrames = evalFrames == null ? 0 : evalFrames.length;
2118             if (level >= numFrames)
2119                 numFrames = level;
2120             numFrames += 10;
2121             Object[][] newFrames = new Object[numFrames][];
2122             if (evalFrames != null)
2123                 System.arraycopy(evalFrames, 0, newFrames, 0, evalFrames.length);
2124             newFrames[level] = evalFrame;
2125             ctx.evalFrames = newFrames;
2126 
2127             try {
2128                 if (lambda.body == null) {
2129                     // This can happen if a syntax-case macro calls a function
2130                     // in the same compilation unit.  FIXME.
2131                     StringBuffer sbuf = new StringBuffer("procedure ");
2132                     String name = lambda.getName();
2133                     if (name == null)
2134                         name = "<anonymous>";
2135                     sbuf.append(name);
2136                     int line = lambda.getLineNumber();
2137                     if (line > 0) {
2138                         sbuf.append(" at line ");
2139                         sbuf.append(line);
2140                     }
2141                     sbuf.append(" was called before it was expanded");
2142                     throw new RuntimeException(sbuf.toString());
2143                 }
2144                 lambda.body.apply(ctx);
2145             } finally {
2146                 ctx.evalFrames = saveFrames;
2147             }
2148             return ctx;
2149         }
2150 
getProperty(Object key, Object defaultValue)2151         public Object getProperty(Object key, Object defaultValue) {
2152             Object value = super.getProperty(key, defaultValue);
2153             if (value == null)
2154                 value = lambda.getProperty(key, defaultValue);
2155             return value;
2156         }
2157     }
2158 
2159     public static final MethodHandle applyToConsumer
2160         = lookupApplyHandle(Closure.class , "applyToConsumer");
2161 
2162 }
2163