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