001: package gnu.expr;
002:
003: import gnu.bytecode.*;
004: import gnu.mapping.*;
005:
006: /** This class is used to represent "combination" or "application".
007: * A function and arguments are evaluated, and then the function applied.
008: * @author Per Bothner
009: */
010:
011: public class ApplyExp extends Expression {
012: Expression func;
013: Expression[] args;
014: boolean tailCall;
015:
016: /** true if this is a special (super) call. */
017: boolean special;
018:
019: /** Containing LambdaExp. */
020: LambdaExp context;
021:
022: /** The next ApplyExp in ((ReferenceExp)func).binding.firstCall list. */
023: public ApplyExp nextCall;
024:
025: public final Expression getFunction() {
026: return func;
027: }
028:
029: public final Expression[] getArgs() {
030: return args;
031: }
032:
033: public final int getArgCount() {
034: return args.length;
035: }
036:
037: public void setArgs(Expression[] args) {
038: this .args = args;
039: }
040:
041: public final boolean isTailCall() {
042: return tailCall;
043: }
044:
045: public final void setTailCall(boolean tailCall) {
046: this .tailCall = tailCall;
047: }
048:
049: public ApplyExp(Expression f, Expression[] a) {
050: this (f, a, false);
051: }
052:
053: public ApplyExp(Expression f, Expression[] a, boolean special) {
054: func = f;
055: args = a;
056: this .special = special;
057: }
058:
059: public ApplyExp(Procedure p, Expression[] a) {
060: func = new QuoteExp(p);
061: args = a;
062: }
063:
064: public ApplyExp(Method m, Expression[] a) {
065: func = new QuoteExp(new PrimProcedure(m));
066: args = a;
067: }
068:
069: public Object eval(Environment env) throws Throwable {
070: Procedure proc = (Procedure) func.eval(env);
071: int n = args.length;
072: Object[] vals = new Object[n];
073: for (int i = 0; i < n; i++)
074: vals[i] = args[i].eval(env);
075: return proc.applyN(vals);
076: }
077:
078: public void eval(Environment env, CallContext ctx) throws Throwable {
079: Procedure proc = (Procedure) func.eval(env);
080: int n = args.length;
081: Object[] vals = new Object[n];
082: for (int i = 0; i < n; i++)
083: vals[i] = args[i].eval(env);
084: ctx.setArgsN(vals);
085: ctx.proc = proc;
086: }
087:
088: public static void compileToArray(Expression[] args,
089: Compilation comp) {
090: CodeAttr code = comp.getCode();
091: if (args.length == 0) {
092: code.emitGetStatic(Compilation.noArgsField);
093: return;
094: }
095: LambdaExp caller = comp.curLambda;
096: code.emitPushInt(args.length);
097: code.emitNewArray(Type.pointer_type);
098: for (int i = 0; i < args.length; ++i) {
099: Expression arg = args[i];
100: if (comp.usingCPStyle && !(arg instanceof QuoteExp)
101: && !(arg instanceof ReferenceExp)) {
102: // If the argument involves a CPStyle function call, we will
103: // have to save and restore anything on the JVM stack into
104: // fields in the CallFrame. This is expensive, so defer
105: // pushing the duplicated argument array and the index
106: // until *after* we've calculated the argument. The downside
107: // is that we have to do some extra stack operations.
108: // However, these are cheap (and get compiled away when
109: // compiling to native code).
110: arg.compile(comp, Target.pushObject);
111: code.emitSwap();
112: code.emitDup(1, 1);
113: code.emitSwap();
114: code.emitPushInt(i);
115: code.emitSwap();
116: } else {
117: code.emitDup(comp.objArrayType);
118: code.emitPushInt(i);
119: arg.compile(comp, Target.pushObject);
120: }
121: code.emitArrayStore(Type.pointer_type);
122: }
123: }
124:
125: public void compile(Compilation comp, Target target) {
126: try {
127: compile(this , comp, target, true);
128: } catch (VerificationError e) {
129: throw bossa.util.User.error(bossa.util.Location.make(this ),
130: e.getMessage());
131: }
132: }
133:
134: public static void compile(ApplyExp exp, Compilation comp,
135: Target target) {
136: compile(exp, comp, target, false);
137: }
138:
139: static void compile(ApplyExp exp, Compilation comp, Target target,
140: boolean checkInlineable) {
141: int args_length = exp.args.length;
142: Expression exp_func = exp.func;
143: LambdaExp func_lambda = null;
144: String func_name = null;
145: if (exp_func instanceof LambdaExp) {
146: func_lambda = (LambdaExp) exp_func;
147: func_name = func_lambda.getName();
148: if (func_name == null)
149: func_name = "<lambda>";
150: } else if (exp_func instanceof ReferenceExp) {
151: Declaration func_decl = ((ReferenceExp) exp_func).binding;
152: if (!func_decl.getFlag(Declaration.IS_UNKNOWN)) {
153: Expression value = func_decl.getValue();
154: func_name = func_decl.getName();
155: if (value != null && value instanceof LambdaExp)
156: func_lambda = (LambdaExp) value;
157: if (value != null && value instanceof QuoteExp) {
158: Object quotedValue = ((QuoteExp) value).getValue();
159: Procedure proc;
160: String msg = null;
161: if (!(quotedValue instanceof Procedure)) {
162: proc = null;
163: msg = "calling " + func_name
164: + " which is not a procedure";
165: } else if (checkInlineable
166: && quotedValue instanceof Inlineable) {
167: ((Inlineable) quotedValue).compile(exp, comp,
168: target);
169: return;
170: } else {
171: proc = (Procedure) quotedValue;
172: msg = WrongArguments.checkArgCount(proc,
173: args_length);
174: }
175: if (msg != null)
176: comp.error('w', msg);
177: else {
178: PrimProcedure pproc = PrimProcedure
179: .getMethodFor(proc, func_decl,
180: exp.args, comp.getInterpreter());
181: if (pproc != null) {
182: if (!pproc.getStaticFlag())
183: func_decl.base.load(comp);
184: pproc.compile(null, exp.args, comp, target);
185: return;
186: }
187: }
188: }
189: }
190: } else if (exp_func instanceof QuoteExp) {
191: Object proc = ((QuoteExp) exp_func).getValue();
192: if (proc instanceof Inlineable) {
193: if (checkInlineable) {
194: ((Inlineable) proc).compile(exp, comp, target);
195: return;
196: }
197:
198: // If it wasn't inlineable, we already checked for this in Translator.
199: PrimProcedure pproc = PrimProcedure.getMethodFor(
200: (Procedure) proc, exp.args);
201: if (pproc != null) {
202: exp = new ApplyExp(pproc, exp.args);
203: ((Inlineable) pproc).compile(exp, comp, target);
204: return;
205: }
206: }
207: }
208:
209: gnu.bytecode.CodeAttr code = comp.getCode();
210: Method method;
211:
212: if (func_lambda != null) {
213: // These error message should really be done earlier,
214: // but we do not have the right information until the rewrite pass
215: // is finished. Perhaps InlineCalls would work? FIXME
216: String msg = null;
217: if (func_lambda.isClassMethod())
218: args_length--;
219: if (args_length < func_lambda.min_args)
220: msg = "too few args for ";
221: else if (func_lambda.max_args >= 0
222: && args_length > func_lambda.max_args)
223: msg = "too many args " + args_length + " for ";
224: else if (!func_lambda.isHandlingTailCalls()
225: && (method = func_lambda.getMethod(args_length)) != null) {
226: boolean is_static = method.getStaticFlag();
227: Expression[] args = exp.getArgs();
228: int extraArg = 0;
229: Type[] argTypes = method.getParameterTypes();
230: // ?? Procedure.checkArgCount(this, args.length); // FIXME
231: /* For Per, it seems that when a function is static the
232: this parameter is implicit, which is why he wants to
233: load the heap frame. I remove it for Nice.
234: */
235: if (/*! is_static || */func_lambda.declareClosureEnv() != null) {
236: if (is_static)
237: extraArg = 1;
238: if (comp.curLambda == func_lambda)
239: code.emitLoad(func_lambda.closureEnv); // Recursive call.
240: else
241: func_lambda.getHeapLambda().loadHeapFrame(comp);
242: }
243:
244: boolean varArgs = func_lambda.restArgType() != null;
245: PrimProcedure
246: .compileArgs(
247: args,
248: func_lambda.isClassMethod() ? (Type) method
249: .getDeclaringClass()
250: : extraArg > 0 ? Type.void_type
251: : null, argTypes,
252: varArgs, func_name, func_lambda, comp);
253: if (exp.special)
254: code.emitInvokeSpecial(method);
255: else
256: code.emitInvoke(method);
257: target.compileFromStack(comp, func_lambda
258: .getReturnType());
259: return;
260: }
261: if (msg != null) {
262: comp.error('w', msg + func_name);
263: func_lambda = null;
264: }
265: }
266:
267: if (comp.usingCPStyle()) {
268: {
269: Label l = new Label(code);
270: gnu.bytecode.SwitchState fswitch = comp.fswitch;
271: int pc = fswitch.getMaxValue() + 1;
272: fswitch.addCase(pc, l, code);
273: exp_func.compile(comp, new StackTarget(
274: comp.typeProcedure));
275: code.emitLoad(comp.callStackContext);
276:
277: // Emit: context->pc = pc.
278: code.emitLoad(comp.callStackContext);
279: code.emitPushInt(pc);
280: code.emitPutField(Compilation.pcCallContextField);
281: code.emitInvokeVirtual(comp.applyCpsMethod);
282:
283: // emit[save java stack, if needed]
284: Type[] stackTypes = code.saveStackTypeState(false);
285: java.util.Stack stackFields = new java.util.Stack();
286: if (stackTypes != null) {
287: for (int i = stackTypes.length; --i >= 0;) {
288: Field fld = comp.allocLocalField(stackTypes[i],
289: null);
290: code.emitPushThis();
291: code.emitSwap();
292: code.emitPutField(fld);
293: stackFields.push(fld);
294: }
295: }
296:
297: code.emitReturn();
298: l.define(code);
299:
300: // emit[restore java stack, if needed]
301: if (stackTypes != null) {
302: for (int i = stackTypes.length; --i >= 0;) {
303: Field fld = (Field) stackFields.pop();
304: code.emitPushThis();
305: code.emitGetField(fld);
306: comp.freeLocalField(fld);
307: }
308: }
309:
310: /* FIXME
311: // Load result from stack.value to target.
312: code.emitLoad(comp.callStackContext);
313: code.emitGetField(comp.valueCallContextField);
314: target.compileFromStack(comp, Type.pointer_type);
315: */
316: }
317: return;
318: }
319:
320: // Check for tail-recursion.
321: boolean tail_recurse = exp.tailCall && func_lambda != null
322: && func_lambda == comp.curLambda;
323:
324: if (func_lambda != null && func_lambda.getInlineOnly()
325: && !tail_recurse && func_lambda.min_args == args_length) {
326: Declaration param = func_lambda.firstDecl();
327: for (int i = 0; i < args_length; ++i) {
328: exp.args[i].compile(comp, param.getType());
329: param = param.nextDecl();
330: }
331: LambdaExp saveLambda = comp.curLambda;
332: comp.curLambda = func_lambda;
333: func_lambda.allocChildClasses(comp);
334: func_lambda.allocParameters(comp);
335: popParams(code, func_lambda, false);
336: func_lambda.enterFunction(comp);
337: func_lambda.body.compileWithPosition(comp, target);
338: func_lambda.compileEnd(comp);
339: // comp.method.popScope();
340: func_lambda.compileChildMethods(comp);
341: comp.curLambda = saveLambda;
342: return;
343: }
344:
345: if (comp.curLambda != null
346: && comp.curLambda.isHandlingTailCalls()
347: && !comp.curLambda.getInlineOnly()) {
348: ClassType typeContext = comp.typeCallContext;
349: exp_func.compile(comp, new StackTarget(comp.typeProcedure));
350: code.emitLoad(comp.callStackContext);
351: code.emitDupX();
352: // Stack: context, proc, context
353: if (!exp.isTailCall())
354: code.emitDupX();
355: // evaluate args to frame-locals vars; // may recurse!
356: if (args_length <= 4) {
357: for (int i = 0; i < args_length; ++i)
358: exp.args[i].compile(comp, Target.pushObject);
359: code.emitInvoke(typeContext.getDeclaredMethod(
360: "setArgs", args_length));
361: } else {
362: compileToArray(exp.args, comp);
363: code.emitInvoke(typeContext.getDeclaredMethod(
364: "setArgsN", 1));
365: }
366: if (exp.isTailCall()) {
367: // Stack: context, proc
368: code.emitPutField(comp.procCallContextField);
369: code.emitReturn();
370: } else if (target instanceof ConsumerTarget) {
371: code.emitPutField(comp.procCallContextField);
372: code.emitLoad(((ConsumerTarget) target)
373: .getConsumerVariable());
374: code.emitInvoke(typeContext.getDeclaredMethod(
375: "runUntilValue", 1));
376: } else {
377: code.emitPutField(comp.procCallContextField);
378: code.emitInvoke(typeContext.getDeclaredMethod(
379: "runUntilValue", 0));
380: target.compileFromStack(comp, Type.pointer_type);
381: }
382: return;
383: }
384:
385: if (!tail_recurse)
386: exp_func.compile(comp, new StackTarget(comp.typeProcedure));
387:
388: boolean toArray = (tail_recurse ? func_lambda.min_args != func_lambda.max_args
389: : args_length > 4);
390: if (toArray) {
391: compileToArray(exp.args, comp);
392: method = comp.applyNmethod;
393: } else if (tail_recurse) {
394: Declaration param = func_lambda.firstDecl();
395: for (int i = 0; i < args_length; ++i) {
396: exp.args[i].compile(comp, param.getType());
397: param = param.nextDecl();
398: }
399: method = null;
400: } else {
401: for (int i = 0; i < args_length; ++i)
402: exp.args[i].compile(comp, Target.pushObject);
403: method = comp.applymethods[args_length];
404: }
405: if (tail_recurse) {
406: popParams(code, func_lambda, toArray);
407: code.emitTailCall(false, func_lambda.scope);
408: return;
409: }
410: code.emitInvokeVirtual(method);
411: target.compileFromStack(comp, Type.pointer_type);
412: }
413:
414: protected Expression walk(ExpWalker walker) {
415: return walker.walkApplyExp(this );
416: }
417:
418: protected void walkChildren(ExpWalker walker) {
419: func = func.walk(walker);
420: if (walker.exitValue == null)
421: args = walker.walkExps(args);
422: }
423:
424: public void print(OutPort out) {
425: out.startLogicalBlock("(Apply", ")", 2);
426: if (tailCall)
427: out.print(" [tailcall]");
428: out.writeSpaceFill();
429: printLineColumn(out);
430: func.print(out);
431: for (int i = 0; i < args.length; ++i) {
432: out.writeSpaceLinear();
433: args[i].print(out);
434: }
435: out.endLogicalBlock(")");
436: }
437:
438: private static void popParams(CodeAttr code, LambdaExp lexp,
439: boolean toArray) {
440: Variable params = lexp.scope.firstVar();
441: if (params != null && params.getName() == "this")
442: params = params.nextVar();
443: if (params != null && params.getName() == "$ctx")
444: params = params.nextVar();
445: if (params != null && params.getName() == "argsArray") {
446: if (toArray) {
447: popParams(code, params, 1);
448: return;
449: }
450: params = params.nextVar();
451: }
452: popParams(code, params, lexp.min_args);
453: }
454:
455: // Recursive helper function.
456: private static void popParams(CodeAttr code, Variable vars,
457: int count) {
458: if (count > 0) {
459: popParams(code, vars.nextVar(), count - 1);
460: code.emitStore(vars);
461: }
462: }
463:
464: public final gnu.bytecode.Type getType() {
465: Expression afunc = func;
466: if (afunc instanceof ReferenceExp) {
467: Declaration func_decl = ((ReferenceExp) afunc).binding;
468: if (func_decl != null
469: && !func_decl.getFlag(Declaration.IS_UNKNOWN))
470: afunc = func_decl.getValue();
471: }
472: if (afunc instanceof QuoteExp) {
473: Object proc = ((QuoteExp) afunc).getValue();
474: if (proc instanceof Inlineable)
475: return ((Inlineable) proc).getReturnType(args);
476: }
477: if (afunc instanceof LambdaExp) {
478: return ((LambdaExp) afunc).getReturnType();
479: }
480: return super .getType();
481: }
482:
483: public static Expression inlineIfConstant(Procedure proc,
484: ApplyExp exp) {
485: int len = exp.args.length;
486: for (int i = len; --i >= 0;) {
487: if (!(exp.args[i] instanceof QuoteExp))
488: return exp;
489: }
490: Object[] vals = new Object[len];
491: for (int i = len; --i >= 0;) {
492: vals[i] = ((QuoteExp) (exp.args[i])).getValue();
493: }
494: try {
495: return new QuoteExp(proc.applyN(vals));
496: } catch (Throwable ex) {
497: // Should emit error message or warning. FIXME.
498: return null;
499: }
500: }
501:
502: }
|