1 // Copyright (c) 2003, 2009, 2010, 2011 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.kawa.functions.*; 7 import gnu.kawa.io.OutPort; 8 import gnu.mapping.*; 9 import gnu.kawa.reflect.MappedArrayType; 10 import gnu.text.SourceLocator; 11 import gnu.text.SourceLocator; 12 import gnu.math.*; 13 import java.util.ArrayList; 14 import java.util.List; 15 import java.lang.reflect.Proxy; 16 import java.lang.annotation.ElementType; 17 18 /** 19 * The static information associated with a local variable binding. 20 * @author Per Bothner 21 * 22 * These are the kinds of Declaration we use: 23 * 24 * A local variable that is not captured by an inner lambda is stored 25 * in a Java local variables slot (register). The predicate isSimple () 26 * is true, and offset is the number of the local variable slot. 27 * 28 * If a local variable is captured by an inner lambda, the 29 * variable is stored in a field of the LambdaExp's heapFrame variable. 30 * (The latter declaration has isSimple and isArtificial true.) 31 * The Declaration's field specifies the Field used. 32 * 33 * If a function takes a fixed number of parameters, at most four, 34 * then the arguments are passed in Java registers 1..4. 35 * If a parameter is not captured by an inner lambda, the parameter 36 * has the flags isSimple and isParameter true. 37 * 38 * If a function takes more than 4 or a variable number of parameters, 39 * the arguments are passed in an array (using the applyN virtual method). 40 * This array is referenced by the argsArray declaration, which has 41 * isSimple(), isParameter(), and isArtificial() true, and its offset is 1. 42 * The parameters are copied into the program-named variables by the 43 * procedure prologue, so the parameters henceforth act like local variables. 44 */ 45 46 public class Declaration extends SourceLocator.Simple 47 { 48 static int counter; 49 /** Unique id number, to ease print-outs and debugging. 50 * If negative, a code to specify a builtin function. */ 51 protected int id = ++counter; 52 53 /** The name of the new variable, either an interned String or a Symbol. 54 * This is the source-level (non-mangled) name. */ 55 Object symbol; 56 setCode(int code)57 public void setCode (int code) 58 { 59 if (code >= 0) throw new Error("code must be negative"); 60 this.id = code; 61 } 62 getCode()63 public int getCode () { return id; } 64 65 public ScopeExp context; 66 67 /** The type of the value of this Declaration. 68 * It is null if the type is un-specified and not yet inferred. 69 * Will get set implicitly by getType, to avoid inconsistencies. 70 */ 71 public/*protected*/ Type type; 72 public/*protected*/ Expression typeExp; getTypeExp()73 public final Expression getTypeExp() 74 { 75 if (typeExp == null) 76 setType(Type.objectType); 77 return typeExp; 78 } getType()79 public final Type getType() 80 { 81 if (type == null) 82 { 83 Type t = Type.objectType; 84 type = t; // To protect against possible cycles. 85 if (! hasUnknownValue() && nvalues > 0) 86 { 87 int arithCount = 0; 88 for (int i = 0; i < nvalues; i++) 89 { 90 Expression vi = values[i].getValue(this); 91 boolean arithOp = false; 92 if (vi != null && ! (vi.getFlag(Expression.VALIDATED))) 93 { 94 // Special handling of arithmetic assignments like 95 // '(set! D (+ D V))', where D is this Declaration. 96 // We can then use the type of V, instead of the unknown 97 // type of (+ D V), to inductively determine the type of D. 98 Expression oparg = checkArithStepOp(vi); 99 if (oparg != null) 100 { 101 // oparg is the expression D above. 102 arithOp = true; 103 arithCount++; 104 vi = oparg; 105 } 106 } 107 Declaration d; 108 if ((vi != null && vi.getFlag(Expression.VALIDATED)) 109 || vi instanceof LambdaExp 110 || vi instanceof QuoteExp 111 || (vi instanceof ReferenceExp 112 && (d = ((ReferenceExp) vi).getBinding()) != null 113 && d.type != null)) 114 { 115 Type vt = vi.getType(); 116 if (i == 0) 117 t = vt; 118 else if (arithOp) 119 t = CompileArith.combineType(t, vt); 120 else 121 t = Language.unionType(t, vt); 122 } 123 else 124 { 125 t = Type.objectType; 126 break; 127 } 128 } 129 } 130 setType(t); 131 } 132 return type; 133 } 134 checkArithStepOp(Expression exp)135 private Expression checkArithStepOp (Expression exp) 136 { 137 if (! (exp instanceof ApplyExp)) 138 return null; 139 ApplyExp aexp = (ApplyExp) exp; 140 Expression func = aexp.getFunction(); 141 Compilation comp = Compilation.getCurrent(); 142 boolean isApplyFunc = comp.isSimpleApplyFunction(func); 143 if (aexp.getArgCount() == (isApplyFunc ? 3 : 2)) 144 { 145 if (isApplyFunc) 146 func = aexp.getArg(0); 147 Declaration fdecl; 148 if (func instanceof ReferenceExp 149 && (fdecl = ((ReferenceExp) func).getBinding()) != null 150 && fdecl.getValue() != null) 151 { 152 Object proc = fdecl.getValue().valueIfConstant(); 153 if (proc instanceof AddOp || proc instanceof MultiplyOp) 154 { 155 Expression arg1 = aexp.getArg(isApplyFunc ? 1 : 0); 156 Expression arg2 = aexp.getArg(isApplyFunc ? 2 : 1); 157 if (arg1 instanceof ReferenceExp 158 && ((ReferenceExp) arg1).getBinding() == this) 159 return arg2; 160 if (arg2 instanceof ReferenceExp 161 && ((ReferenceExp) arg2).getBinding() == this) 162 return arg1; 163 } 164 } 165 } 166 return null; 167 } 168 getTypeExpRaw()169 public Expression getTypeExpRaw () { return typeExp; } 170 setType(Type type)171 public final void setType(Type type) 172 { 173 if (type.isVoid()) 174 type = Type.objectType; 175 this.type = type; 176 typeExp = QuoteExp.getInstance(type); 177 } 178 setTypeExp(Expression typeExp)179 public final void setTypeExp (Expression typeExp) 180 { 181 this.typeExp = typeExp; 182 Type t = null; 183 if (typeExp instanceof TypeValue) 184 t = ((TypeValue) typeExp).getImplementationType(); 185 else 186 t = Language.getDefaultLanguage().getTypeFor(typeExp, false); 187 if (t == null) 188 t = Type.pointer_type; 189 this.type = t; 190 if (var != null) var.setType(t); 191 } 192 setType(Expression typeExp, Type type)193 public final void setType (Expression typeExp, Type type) 194 { 195 this.typeExp = typeExp; 196 this.type = type; 197 } 198 getName()199 public final String getName() 200 { 201 return symbol == null ? null : symbol instanceof Symbol ? ((Symbol) symbol).getName() 202 : symbol.toString(); 203 } setName(Object symbol)204 public final void setName(Object symbol) 205 { 206 this.symbol = symbol; 207 } 208 getSymbol()209 public final Object getSymbol() { return symbol; } setSymbol(Object symbol)210 public final void setSymbol(Object symbol) { this.symbol = symbol; } 211 212 /* Declarations in a ScopeExp are linked together in a linked list. */ 213 private Declaration next; 214 nextDecl()215 public final Declaration nextDecl() { return next; } setNext(Declaration next)216 public final void setNext(Declaration next) { this.next = next; } 217 218 /** Index in evalFrame for this scope, if interpreting. */ 219 int evalIndex; 220 221 Variable var; getVariable()222 public Variable getVariable() { return var; } 223 224 /** If non-zero, indicates this names a 'scan' of a sequence. 225 * The value property is a sequence; the declaration names 226 * "each" of the elements. 227 * This field is the amount of nesting within scan ('...') contexts. 228 */ getScanNesting()229 public int getScanNesting() { return scanNesting; } setScanNesting(int value)230 public void setScanNesting(int value) { scanNesting = value; } 231 int scanNesting; 232 isSimple()233 public final boolean isSimple() 234 { return (flags & IS_SIMPLE) != 0; } 235 setSimple(boolean b)236 public final void setSimple(boolean b) 237 { 238 setFlag(b, IS_SIMPLE); 239 if (var != null && ! var.isParameter()) var.setSimple(b); 240 } 241 setSyntax()242 public final void setSyntax () 243 { 244 setSimple(false); 245 setFlag(IS_CONSTANT|IS_SYNTAX|EARLY_INIT); 246 } 247 248 /** Return the ScopeExp that contains (declares) this Declaration. */ getContext()249 public final ScopeExp getContext() { return context; } 250 251 /** Used to link Declarations in a LambdaExp's capturedVars list. */ 252 Declaration nextCapturedVar; 253 254 /** If non-null, field is relative to base. 255 * If IS_FLUID, base points to IS_UNKNOWN Symbol. */ 256 public Declaration base; 257 258 private Field field; 259 public Method getterMethod; 260 public Method setterMethod; 261 262 /** If this is a field in some object, load a reference to that object. */ loadOwningObject(Declaration owner, Compilation comp)263 void loadOwningObject (Declaration owner, Compilation comp) 264 { 265 if (owner == null) 266 owner = base; 267 if (owner != null) 268 owner.load(null, 0, comp, Target.pushObject); 269 else 270 getContext().currentLambda().loadHeapFrame(comp); 271 } 272 loadFieldLocation(Declaration owner, Compilation comp)273 public Type loadFieldLocation(Declaration owner, Compilation comp) { 274 Field fld = getField(); 275 if (fld == null) 276 throw new Error("internal error: cannot take location of "+this); 277 Method meth; 278 ClassType ltype; 279 boolean immediate = comp.immediate; 280 if (! fld.getStaticFlag()) 281 loadOwningObject(owner, comp); 282 if (fld.getStaticFlag()) { 283 ltype = Compilation.typeStaticFieldLocation; 284 meth = ltype.getDeclaredMethod("make", immediate ? 1 : 2); 285 } else { 286 ltype = Compilation.typeFieldLocation; 287 meth = ltype.getDeclaredMethod("make", immediate ? 2 : 3); 288 } 289 if (immediate) 290 comp.compileConstant(this); 291 else { 292 comp.compileConstant(fld.getDeclaringClass().getName()); 293 comp.compileConstant(fld.getName()); 294 } 295 comp.getCode().emitInvokeStatic(meth); 296 return ltype; 297 } 298 load(AccessExp access, int flags, Compilation comp, Target target)299 public void load (AccessExp access, int flags, 300 Compilation comp, Target target) 301 { 302 if (target instanceof IgnoreTarget) 303 { 304 if (access.getFlag(ReferenceExp.ALLOCATE_ON_STACK_LAST)) 305 comp.getCode().emitPop(1); 306 return; 307 } 308 Declaration owner = access == null ? null : access.contextDecl(); 309 Expression dvalue = getValueRaw(); 310 if (isAlias() && dvalue instanceof ReferenceExp) 311 { 312 ReferenceExp rexp = (ReferenceExp) dvalue; 313 Declaration orig = rexp.binding; 314 if (orig != null 315 && ((flags & ReferenceExp.DONT_DEREFERENCE) == 0 316 || orig.isIndirectBinding()) 317 && (owner == null || ! orig.needsContext())) 318 { 319 orig.load(rexp, flags, comp, target); 320 return; 321 } 322 } 323 if (isFluid()) 324 { 325 if (context instanceof FluidLetExp) 326 { 327 base.load(access, flags, comp, target); 328 return; 329 } 330 } 331 CodeAttr code = comp.getCode(); 332 boolean dontDeref = (flags & ReferenceExp.DONT_DEREFERENCE) != 0; 333 Type rtype = dontDeref ? Compilation.typeLocation : getType(); 334 if (! isIndirectBinding() && dontDeref) 335 { 336 rtype = loadFieldLocation(owner, comp); 337 } 338 else if (getFlag(ALLOCATE_ON_STACK)) 339 { 340 int SP = code.getSP(); 341 if (access.getFlag(ReferenceExp.ALLOCATE_ON_STACK_LAST)) 342 ; 343 else if (SP == evalIndex) 344 code.emitDup(); 345 else if (SP == evalIndex+1) 346 { 347 code.emitSwap(); 348 code.emitDupX(); 349 } 350 else 351 throw new InternalError("allocate-on-stack mismatch"); 352 } 353 else 354 { 355 Object val; 356 Expression value = getValueRaw(); 357 if (type == Type.javalangClassType 358 && (value instanceof ClassExp || value instanceof ModuleExp)) 359 { 360 comp.loadClassRef(((LambdaExp) value).getCompiledClassType(comp)); 361 } 362 else if (getField() != null) 363 { 364 comp.usedClass(getField().getDeclaringClass()); 365 comp.usedClass(getField().getType()); 366 if (! field.getStaticFlag()) 367 { 368 loadOwningObject(owner, comp); 369 code.emitGetField(getField()); 370 } 371 else 372 code.emitGetStatic(getField()); 373 code.fixUnsigned(getType()); 374 } 375 else if (isClassField()) 376 { 377 String getName = ClassExp.slotToMethodName("get", getName()); 378 Method getter = ((ClassExp) context).compiledType 379 .getDeclaredMethod(getName, 0); 380 comp.usedClass(getter.getDeclaringClass()); 381 comp.usedClass(getter.getReturnType()); 382 loadOwningObject(owner, comp); 383 code.emitInvoke(getter); 384 } 385 else if (isIndirectBinding() && comp.immediate && getVariable() == null) 386 { 387 // This is a bit of a kludge. See comment in ModuleExp.evalModule. 388 Environment env = Environment.getCurrent(); 389 Symbol sym = symbol instanceof Symbol ? (Symbol) symbol 390 : env.getSymbol(symbol.toString()); 391 Object property = null; 392 if (isProcedureDecl() 393 && comp.getLanguage().hasSeparateFunctionNamespace()) 394 property = EnvironmentKey.FUNCTION; 395 gnu.mapping.Location loc = env.getLocation(sym, property); 396 comp.compileConstant(loc, Target.pushValue(Compilation.typeLocation)); 397 } 398 else if (comp.immediate && (val = getConstantValue()) != null) 399 { 400 comp.compileConstant(val, target); 401 return; 402 } 403 else if (value != QuoteExp.undefined_exp && value != null 404 && ignorable() 405 && ! (value instanceof LambdaExp)) 406 { 407 value.compile(comp, target); 408 return; 409 } 410 else 411 { 412 Variable var = getVariable(); 413 if (var == null) 414 var = allocateVariable(code, true); 415 code.emitLoad(var); 416 } 417 if (isIndirectBinding() && ! dontDeref) 418 { 419 String filename; 420 int line; 421 if (access != null 422 && (filename = access.getFileName()) != null 423 && (line = access.getLineNumber()) > 0) 424 { 425 // Wrap call to Location.get by a catch handler that 426 // calls setLine on the UnboundLocationException. 427 ClassType typeUnboundLocationException 428 = ClassType.make("gnu.mapping.UnboundLocationException"); 429 // See comment in CheckedTarget.emitCheckedCoerce. 430 boolean isInTry = code.isInTry(); 431 int column = access.getColumnNumber(); 432 Label startTry = new Label(code); 433 startTry.define(code); 434 code.emitInvokeVirtual(getLocationMethod); 435 Label endTry = new Label(code); 436 endTry.define(code); 437 Label endLabel = new Label(code); 438 endLabel.setTypes(code); 439 if (isInTry) 440 code.emitGoto(endLabel); 441 else 442 code.setUnreachable(); 443 int fragment_cookie = 0; 444 if (! isInTry) 445 fragment_cookie = code.beginFragment(endLabel); 446 code.addHandler(startTry, endTry, typeUnboundLocationException); 447 448 code.emitDup(typeUnboundLocationException); 449 code.emitPushString(filename); 450 code.emitPushInt(line); 451 code.emitPushInt(column); 452 code.emitInvokeVirtual(typeUnboundLocationException 453 .getDeclaredMethod("setLine", 3)); 454 code.emitThrow(); 455 if (isInTry) 456 endLabel.define(code); 457 else 458 code.endFragment(fragment_cookie); 459 } 460 else 461 code.emitInvokeVirtual(getLocationMethod); 462 if (isAlias() 463 || target.getType().getRawType() == Type.objectType) 464 rtype = Type.objectType; 465 else { 466 getType().emitCoerceFromObject(code); 467 rtype = getType(); 468 } 469 } 470 } 471 target.compileFromStack(comp, rtype); 472 } 473 474 static final Method getLocationMethod 475 = Compilation.typeLocation.addMethod("get", Type.typeArray0, 476 Type.objectType, Access.PUBLIC); 477 478 /* Compile code to store a value (which must already be on the 479 stack) into this variable. */ compileStore(Compilation comp)480 public void compileStore (Compilation comp) 481 { 482 gnu.bytecode.CodeAttr code = comp.getCode(); 483 if (isSimple ()) 484 code.emitStore(getVariable()); 485 else 486 { 487 if (! field.getStaticFlag()) 488 { 489 loadOwningObject(null, comp); 490 code.emitSwap(); 491 code.emitPutField(getField()); 492 } 493 else 494 code.emitPutStatic(getField()); 495 } 496 } 497 shouldEarlyInit()498 boolean shouldEarlyInit () 499 { 500 return getFlag(EARLY_INIT) || isCompiletimeConstant (); 501 } 502 isCompiletimeConstant()503 public boolean isCompiletimeConstant () 504 { 505 return getFlag(IS_CONSTANT) && hasConstantValue(); 506 } 507 508 /** This prefix is prepended to field names for unknown names. */ 509 static final String UNKNOWN_PREFIX = "loc$"; 510 511 /** This prefix is used in field names for a declaration that has 512 * both EXTERNAL_ACCESS and IS_PRIVATE set. */ 513 public static final String PRIVATE_PREFIX = "$Prvt$"; 514 515 /** If this flag is set then to get the actual value you have to dereference 516 * a <code>gnu.mapping.Location</code>. I.e. this <code>Declaration</code>'s 517 * <code>var</code> or <code>field</code> does not contain the 518 * <code>Declaration</code>'s value directly, but rather yields a 519 * <code>Location</code> that contains the <code>Declaration</code>'s value. 520 * Note that this flag indicates the <em>representation</em>: 521 * The result of <code>getValue()</code> is not the location, but the 522 * semantic value. after dereferencing. Likewise <code>getType</code> is 523 * the value after de-referencing, not a <code>Location</code> sub-class. */ 524 static final int INDIRECT_BINDING = 1; 525 526 static final int CAN_READ = 2; 527 static final int CAN_CALL = 4; 528 static final int CAN_WRITE = 8; 529 static final int IS_FLUID = 0x10; 530 static final int PRIVATE = 0x20; 531 static final int IS_SIMPLE = 0x40; 532 533 /** True if in the function namespace, for languages that distinguishes them. 534 * I.e. a function definition or macro definition. */ 535 public static final int PROCEDURE = 0x80; 536 537 public static final int IS_ALIAS = 0x100; 538 539 /** Set if this is just a declaration, not a definition. */ 540 public static final int NOT_DEFINING = 0x200; 541 542 public static final int EXPORT_SPECIFIED = 0x400; 543 public static final int STATIC_SPECIFIED = 0x800; 544 public static final int NONSTATIC_SPECIFIED = 0x1000; 545 public static final int TYPE_SPECIFIED = 0x2000; 546 public static final int IS_CONSTANT = 0x4000; 547 public static final int IS_SYNTAX = 0x8000; 548 public static final int IS_UNKNOWN = 0x10000; 549 public static final int IS_IMPORTED = 0x20000; 550 public static final int IS_CAPTURED = IS_IMPORTED; // Re-use bit. 551 552 // This should be a type property, not a variable property, at some point! 553 public static final int IS_SINGLE_VALUE = 0x40000; 554 555 /** This flag bit is set if this can be be accessed from other modules. 556 * Ignored unless PRIVATE. 557 * Used when an exported macro references a non-exported name. */ 558 public static final int EXTERNAL_ACCESS = 0x80000; 559 needsExternalAccess()560 public final boolean needsExternalAccess () 561 { 562 return (flags & EXTERNAL_ACCESS+PRIVATE) == EXTERNAL_ACCESS+PRIVATE 563 // Kludge - needed for macros - see Savannah bug #13601. 564 || (flags & IS_NAMESPACE_PREFIX+PRIVATE) == IS_NAMESPACE_PREFIX+PRIVATE; 565 } 566 567 /** If we need a 'context' supplied from a ReferenceExp or 'this. */ needsContext()568 public final boolean needsContext () 569 { 570 return base == null 571 && ((isClassField() && ! isStatic()) 572 || (getField() != null && ! field.getStaticFlag())); 573 } 574 575 /** True if this is a field or method in a class definition. */ 576 public static final int FIELD_OR_METHOD = 0x100000; 577 578 /** Set if this declares a namespace prefix (as in XML namespaces). */ 579 public static final int IS_NAMESPACE_PREFIX = 0x200000; 580 581 public static final int PRIVATE_ACCESS = 0x1000000; 582 public static final int PRIVATE_SPECIFIED = PRIVATE_ACCESS; /* deprecated*/ 583 public static final int PROTECTED_ACCESS = 0x2000000; 584 public static final int PUBLIC_ACCESS = 0x4000000; 585 public static final int PACKAGE_ACCESS = 0x8000000; 586 587 public static final int IS_DYNAMIC = 0x10000000; 588 589 /** Initialize in {@code <init>}/{@code <clinit>} 590 * rather than in {@code run}/{@code $run$}. */ 591 public static final int EARLY_INIT = 0x20000000; 592 /** A reference to a module instance. */ 593 public static final int MODULE_REFERENCE = 0x40000000; 594 595 public static final long VOLATILE_ACCESS = 0x80000000l; 596 public static final long TRANSIENT_ACCESS = 0x100000000l; 597 public static final long ENUM_ACCESS = 0x200000000l; 598 public static final long FINAL_ACCESS = 0x400000000l; 599 public static final long ABSTRACT_ACCESS = 0x800000000l; 600 public static final long SYNCHRONIZED_ACCESS = 0x1000000000l; 601 public static final long STRICTFP_ACCESS = 0x2000000000l; 602 public static final long CLASS_ACCESS_FLAGS = 603 PRIVATE_ACCESS|PROTECTED_ACCESS|ENUM_ACCESS|FINAL_ACCESS|ABSTRACT_ACCESS; 604 public static final long FIELD_ACCESS_FLAGS = PRIVATE_ACCESS|PROTECTED_ACCESS| 605 PUBLIC_ACCESS|PACKAGE_ACCESS|VOLATILE_ACCESS|TRANSIENT_ACCESS| 606 ENUM_ACCESS|FINAL_ACCESS; 607 public static final long METHOD_ACCESS_FLAGS = PRIVATE_ACCESS 608 |PROTECTED_ACCESS|PUBLIC_ACCESS|PACKAGE_ACCESS|FINAL_ACCESS 609 |SYNCHRONIZED_ACCESS|STRICTFP_ACCESS; 610 611 public static final long MAYBE_UNINITIALIZED_ACCESS = 0x4000000000l; 612 /** Allocate variable on JVM stack as an optimization. 613 * This means load is implemented as a dup instruction. 614 * (This is no faster on decent JVMs, but the bytecode is more compact.) 615 * Note this may cause an InternalError if this is loaded when the 616 * JVM stack has grown since the variable was initialized. 617 */ 618 public static final long ALLOCATE_ON_STACK = 0x8000000000l; 619 620 /** True for a variable inside a pattern, but not the top of the pattern. 621 * E.g. for a pattern [a [b c]] there is a main declaration for the 622 * incoming value - which does not have PATTERN_NESTED set. There are 623 * three declarations a, b, and c - which do have PATTERN_NESTED set. 624 * In addition there may be helper variables which are anonymous 625 * (i.e. getSymbol() returns null), like the match for the sequence [b c]; 626 * these also have PATTERN_NESTED set. */ 627 public static final long PATTERN_NESTED = 0x10000000000l; 628 629 /** See parameterForMethod() */ 630 public static final long SKIP_FOR_METHOD_PARAMETER = 0x20000000000l; 631 public static final long IS_REST_PARAMETER = 0x40000000000l; 632 public static final long IS_PARAMETER = 0x80000000000l; 633 /** Is this a supplied-parameter variable? 634 * If IS_SUPPLIED_PARAMETER is true and IS_PARAMETER is false 635 * then this is a boolean variable which reports if the previous parameter 636 * was provided by the argument list, rather than defaulted. 637 * If IS_SUPPLIED_PARAMETER is true and IS_PARAMETER is true then 638 * this is an optional or keyword parameter that has corresponding 639 * supplied-parameter later in the parameter list. 640 */ 641 public static final long IS_SUPPLIED_PARAMETER = 0x100000000000l; 642 /** Applies to a 'rest' parameter if it can match keywords. */ 643 public static final long KEYWORDS_OK = 0x200000000000l; 644 public static final long DONT_COPY = 0x400000000000l; 645 public static final long SCAN_OWNER = 0x800000000000l; 646 647 protected long flags = IS_SIMPLE; 648 getFlag(long flag)649 public final boolean getFlag (long flag) 650 { 651 return (flags & flag) != 0; 652 } 653 setFlag(boolean setting, long flag)654 public final void setFlag (boolean setting, long flag) 655 { 656 if (setting) flags |= flag; 657 else flags &= ~flag; 658 } 659 setFlag(long flag)660 public final void setFlag (long flag) 661 { 662 flags |= flag; 663 } 664 isPublic()665 public final boolean isPublic() 666 { return context instanceof ModuleExp && (flags & PRIVATE) == 0; } 667 isPrivate()668 public final boolean isPrivate() { return (flags & PRIVATE) != 0; } 669 isModuleLocal()670 public final boolean isModuleLocal() { 671 return ! isPublic() && ! needsExternalAccess(); 672 } 673 setPrivate(boolean isPrivate)674 public final void setPrivate(boolean isPrivate) 675 { 676 setFlag(isPrivate, PRIVATE); 677 } 678 getAccessFlags(short defaultFlags)679 public short getAccessFlags (short defaultFlags) 680 { 681 short flags; 682 if (getFlag(PRIVATE_ACCESS|PROTECTED_ACCESS|PACKAGE_ACCESS|PUBLIC_ACCESS)) 683 { 684 flags = 0; 685 if (getFlag(PRIVATE_ACCESS)) 686 flags |= Access.PRIVATE; 687 if (getFlag(PROTECTED_ACCESS)) 688 flags |= Access.PROTECTED; 689 if (getFlag(PUBLIC_ACCESS)) 690 flags |= Access.PUBLIC; 691 } 692 else 693 flags = defaultFlags; 694 if (getFlag(VOLATILE_ACCESS)) 695 flags |= Access.VOLATILE; 696 if (getFlag(TRANSIENT_ACCESS)) 697 flags |= Access.TRANSIENT; 698 if (getFlag(ENUM_ACCESS)) 699 flags |= Access.ENUM; 700 if (getFlag(FINAL_ACCESS)) 701 flags |= Access.FINAL; 702 if (getFlag(SYNCHRONIZED_ACCESS)) 703 flags |= Access.SYNCHRONIZED; 704 if (getFlag(STRICTFP_ACCESS)) 705 flags |= Access.STRICT; 706 return flags; 707 } 708 isAlias()709 public final boolean isAlias() { return (flags & IS_ALIAS) != 0; } setAlias(boolean flag)710 public final void setAlias(boolean flag) { setFlag(flag, IS_ALIAS); } 711 712 /** True if this is a fluid binding (in a FluidLetExp). 713 * Also true if this binding is the one re-bound by a FluidLetExp. */ isFluid()714 public final boolean isFluid () { return (flags & IS_FLUID) != 0; } 715 setFluid(boolean fluid)716 public final void setFluid (boolean fluid) { setFlag(fluid, IS_FLUID); } 717 isProcedureDecl()718 public final boolean isProcedureDecl () { return (flags & PROCEDURE) != 0; } 719 setProcedureDecl(boolean val)720 public final void setProcedureDecl (boolean val) { setFlag(val, PROCEDURE); } 721 isClassMethod()722 public final boolean isClassMethod () 723 { 724 return (flags & FIELD_OR_METHOD+PROCEDURE) == FIELD_OR_METHOD+PROCEDURE; 725 } 726 isClassField()727 public final boolean isClassField () 728 { 729 return (flags & FIELD_OR_METHOD+PROCEDURE) == FIELD_OR_METHOD; 730 } 731 isNamespaceDecl()732 public final boolean isNamespaceDecl () 733 { 734 return (flags & IS_NAMESPACE_PREFIX) != 0; 735 } 736 737 /** Is this a parameter for the generated method? 738 * For example if a lambda's parameter is the pattern {@code [x y]} 739 * then there is an anonymous parameter p0 that is the incoming 2-element 740 * sequence plus named parameters {@code x} and {@code y}. 741 * The later two are parameters for the generated method, 742 * but the anonymous p0 is not. 743 */ parameterForMethod()744 public final boolean parameterForMethod() { 745 return ! getFlag(SKIP_FOR_METHOD_PARAMETER); 746 } 747 748 /** True if the value of the variable is the contents of a Location. 749 * @see #INDIRECT_BINDING */ isIndirectBinding()750 public final boolean isIndirectBinding() 751 { return (flags & INDIRECT_BINDING) != 0; } 752 753 /** Note that the value of the variable is the contents of a Location. 754 * @see #INDIRECT_BINDING */ setIndirectBinding(boolean indirectBinding)755 public final void setIndirectBinding(boolean indirectBinding) 756 { 757 setFlag(indirectBinding, INDIRECT_BINDING); 758 } 759 maybeIndirectBinding(Compilation comp)760 public void maybeIndirectBinding(Compilation comp) { 761 if (isLexical() && ! inExternalModule(comp) && !getFlag(TYPE_SPECIFIED)) 762 setIndirectBinding(true); 763 } 764 inExternalModule(Compilation comp)765 public boolean inExternalModule(Compilation comp) { 766 return context instanceof ModuleExp && context != comp.mainLambda; 767 } 768 769 /** Does this encapsulate a boolean guard expression? 770 * In that case this is an unnamed pseudo-parameter, that matches no 771 * actual arguments but where {@code getInitValue()} is the expression. */ isGuard()772 public boolean isGuard() { 773 return typeExp == QuoteExp.isTrueTypeExp; 774 } 775 776 /* Note: You probably want to use !ignorable(). */ getCanRead()777 public final boolean getCanRead() { return (flags & CAN_READ) != 0; } setCanRead(boolean read)778 public final void setCanRead(boolean read) 779 { 780 setFlag(read, CAN_READ); 781 } setCanRead()782 public final void setCanRead() 783 { 784 setFlag(true, CAN_READ); 785 if (base != null) 786 base.setCanRead(); 787 } 788 getCanReadOrCall()789 public final boolean getCanReadOrCall() { 790 return (flags & (CAN_READ|CAN_CALL)) != 0; 791 } 792 getCanCall()793 public final boolean getCanCall() { return (flags & CAN_CALL) != 0; } setCanCall(boolean called)794 public final void setCanCall(boolean called) { setFlag(called, CAN_CALL); } setCanCall()795 public final void setCanCall() 796 { 797 setFlag(true, CAN_CALL); 798 if (base != null) 799 base.setCanRead(); 800 } 801 getCanWrite()802 public final boolean getCanWrite() 803 { return (flags & CAN_WRITE) != 0; } 804 setCanWrite(boolean written)805 public final void setCanWrite(boolean written) 806 { 807 if (written) flags |= CAN_WRITE; 808 else flags &= ~CAN_WRITE; 809 } 810 setCanWrite()811 public final void setCanWrite() 812 { 813 flags |= CAN_WRITE; 814 if (base != null) 815 base.setCanRead(); 816 } 817 818 /** Is this an implicit 'this' parameter? */ isThisParameter()819 public final boolean isThisParameter () 820 { 821 return symbol == ThisExp.THIS_NAME; 822 } 823 mayBeAccessedUninitialized()824 public boolean mayBeAccessedUninitialized () 825 { 826 return getFlag(MAYBE_UNINITIALIZED_ACCESS); 827 } 828 829 /** True if we never need to access this declaration. */ 830 // rename to isAccessed? ignorable()831 public boolean ignorable() 832 { 833 if (getCanRead() || isPublic()) 834 return false; 835 if (getCanWrite() && getFlag(IS_UNKNOWN)) 836 return false; 837 if (! getCanCall()) 838 return true; 839 Expression value = getValue(); 840 if (value == null || ! (value instanceof LambdaExp)) 841 return false; 842 LambdaExp lexp = (LambdaExp) value; 843 return lexp.getInlineOnly(); 844 } 845 isStatic()846 public boolean isStatic() 847 { 848 if (getField() != null) 849 return getField().getStaticFlag(); 850 if (getFlag(STATIC_SPECIFIED) 851 || isCompiletimeConstant()) 852 return true; 853 if (getFlag(NONSTATIC_SPECIFIED)) 854 return false; 855 LambdaExp lambda = context.currentLambda(); 856 return lambda instanceof ModuleExp 857 && ((ModuleExp) lambda).isStatic(); 858 } 859 isLexical()860 public final boolean isLexical() 861 { 862 return (flags & (IS_FLUID|IS_DYNAMIC|IS_UNKNOWN)) == 0; 863 } 864 isUnknown(Declaration decl)865 public static final boolean isUnknown (Declaration decl) 866 { 867 return decl == null || decl.getFlag(IS_UNKNOWN); 868 } 869 870 int numReferences; 871 872 /** List of ApplyExp where this declaration is the function called. 873 * The applications are chained using their nextCall fields. 874 * This is list is built twice: 875 * First in PushApply (for use during InlineCalls), 876 * then the list is clearest, then rebuilt in FindTailCalls. 877 * This is because InlineCalls may inline and re-arrange the call graph. 878 * The chain is not built the second time if STATIC_SPECIFIED. */ 879 public ApplyExp firstCall; 880 881 /** Add a call to the list headed by {@code firstCall}. */ addCaller(ApplyExp exp)882 public void addCaller (ApplyExp exp) 883 { 884 exp.nextCall = firstCall; 885 firstCall = exp; 886 } 887 888 /** Clear the list of callers headed by {@code firstCall}. */ clearCallList()889 public void clearCallList () 890 { 891 for (ApplyExp exp = firstCall; exp != null; ) 892 { 893 ApplyExp next = exp.nextCall; 894 exp.nextCall = null; 895 exp = next; 896 } 897 firstCall = null; 898 } 899 Declaration(Object name, Type type)900 public Declaration (Object name, Type type) 901 { 902 setName(name); 903 if (type != null) 904 setType(type); 905 } 906 Declaration(Variable var)907 public Declaration (Variable var) 908 { 909 this(var.getName(), var.getType()); 910 this.var = var; 911 } 912 Declaration(Object name)913 public Declaration (Object name) 914 { 915 this(name, (Type) null); 916 } 917 Declaration(Object name, Field field)918 public Declaration (Object name, Field field) 919 { 920 this(name, field.getType()); 921 this.field = field; 922 setSimple(false); 923 } 924 925 List<Expression> annotations; 926 927 /** The number of annotations associated with the declaration. */ numAnnotations()928 public int numAnnotations () 929 { 930 return annotations == null ? 0 : annotations.size(); 931 } 932 933 /** Indexed get of one of the annotations associated with this declaration. */ getAnnotation(int i)934 public Expression getAnnotation (int i) 935 { 936 return annotations.get(i); 937 } 938 939 public <T extends java.lang.annotation.Annotation> getAnnotation(Class<T> clas)940 T getAnnotation(Class<T> clas) { 941 int n = numAnnotations(); 942 for (int i = 0; i < n; i++) { 943 Object ann = getAnnotation(i).valueIfConstant(); 944 if (clas.isInstance(ann)) 945 return (T) ann; 946 } 947 return null; 948 } 949 getAnnotation(String className)950 public AnnotationEntry getAnnotation(String className) { 951 int n = numAnnotations(); 952 for (int i = 0; i < n; i++) { 953 Object ann = getAnnotation(i).valueIfConstant(); 954 if (ann instanceof AnnotationEntry) { 955 AnnotationEntry ae = 956 (AnnotationEntry) Proxy.getInvocationHandler(ann); 957 if (className.equals(ae.getAnnotationType())) { 958 return ae; 959 } 960 } 961 } 962 return null; 963 } 964 965 /** Replace one of the annotations associated with this declaration. */ setAnnotation(int i, Expression ann)966 public void setAnnotation (int i, Expression ann) 967 { 968 annotations.set(i, ann); 969 } 970 971 /** Add an annotation to the set of our annotations. 972 * @param exp A constant-valued expression that evaluates to an Annotation. 973 */ addAnnotation(Expression exp)974 public void addAnnotation (Expression exp) 975 { 976 if (annotations == null) 977 annotations = new ArrayList<Expression>(); 978 annotations.add(exp); 979 } 980 compileAnnotations(AttrContainer container, ElementType etype)981 public void compileAnnotations (AttrContainer container, ElementType etype) 982 { 983 if (container == null) 984 return; 985 int n = numAnnotations(); 986 for (int i = 0; i < n; i++) 987 { 988 Object ann = getAnnotation(i).valueIfConstant(); 989 if (ann != null) 990 { 991 AnnotationEntry ae = (AnnotationEntry) Proxy.getInvocationHandler(ann); 992 if (container != null && ae.hasTarget(etype)) 993 RuntimeAnnotationsAttr.maybeAddAnnotation(container, ae); 994 } 995 } 996 } 997 998 Method makeLocationMethod = null; 999 1000 /** Create a Location object, given that isIndirectBinding(). 1001 Assume the initial value is already pushed on the stack; 1002 leaves initialized Location object on stack. */ pushIndirectBinding(Compilation comp)1003 public void pushIndirectBinding (Compilation comp) 1004 { 1005 CodeAttr code = comp.getCode(); 1006 code.emitPushString(getName()); 1007 if (makeLocationMethod == null) 1008 { 1009 Type[] args = new Type[2]; 1010 args[0] = Type.pointer_type; 1011 args[1] = Type.string_type; 1012 makeLocationMethod 1013 = Compilation.typeLocation.addMethod("make", args, 1014 Compilation.typeLocation, 1015 Access.PUBLIC|Access.STATIC); 1016 } 1017 code.emitInvokeStatic(makeLocationMethod); 1018 } 1019 allocateVariable(CodeAttr code)1020 public final Variable allocateVariable(CodeAttr code) 1021 { 1022 return allocateVariable(code, false); 1023 } allocateVariable(CodeAttr code, boolean autoPopScope)1024 public final Variable allocateVariable(CodeAttr code, boolean autoPopScope) 1025 { 1026 if (! isSimple() || var == null) 1027 { 1028 String vname = null; 1029 if (symbol != null) 1030 vname = Mangling.mangleVariable(getName()); 1031 if (isAlias() && getValue() instanceof ReferenceExp) 1032 { 1033 Declaration base = followAliases(this); 1034 var = base == null ? null : base.var; 1035 } 1036 else 1037 { 1038 Type type = getImplementationType(); 1039 Scope scope = autoPopScope ? code.pushAutoPoppableScope() 1040 : context.getVarScope(); 1041 var = scope.addVariable(code, type, vname); 1042 } 1043 } 1044 return var; 1045 } 1046 getImplementationType()1047 public Type getImplementationType() { 1048 Type ftype = getType().getImplementationType(); 1049 if (isIndirectBinding() && ! ftype.isSubtype(Compilation.typeLocation)) { 1050 if (ftype == null || ftype == Type.objectType) 1051 ftype = Compilation.typeLocation; 1052 else { 1053 if (ftype instanceof PrimType) 1054 ftype = ((PrimType) ftype).boxedType(); 1055 ftype = new ParameterizedType(Compilation.typeLocation, ftype); 1056 } 1057 } 1058 int scan = getScanNesting(); 1059 if (scan > 0 && ! (type instanceof MappedArrayType)) { 1060 while (--scan >= 0) 1061 ftype = new ParameterizedType(Compilation.typeList, ftype); 1062 } 1063 return ftype; 1064 } 1065 printInfo(OutPort out)1066 public void printInfo(OutPort out) 1067 { 1068 StringBuffer sbuf = new StringBuffer(); 1069 printInfo(sbuf); 1070 out.startLogicalBlock("", "", 2); 1071 out.print(sbuf.toString()); 1072 int numAnnotations = numAnnotations(); 1073 if (numAnnotations > 0) 1074 { 1075 out.writeSpaceLinear(); 1076 out.print("Annotations:"); 1077 for (int i = 0; i < numAnnotations; i++) 1078 { 1079 out.writeSpaceLinear(); 1080 annotations.get(i).print(out); 1081 } 1082 } 1083 out.endLogicalBlock(""); 1084 } 1085 printInfo(StringBuffer sbuf)1086 public void printInfo(StringBuffer sbuf) 1087 { 1088 sbuf.append(symbol); 1089 if (true || // DEBUGGING 1090 symbol == null) 1091 ; 1092 else if (symbol instanceof SimpleSymbol) 1093 sbuf.append("[simple-symbol]"); 1094 else if (symbol instanceof Symbol) 1095 sbuf.append("[symbol]"); 1096 else if (symbol.toString().intern() == symbol) 1097 sbuf.append("[interned-string]"); 1098 else if (symbol instanceof String) 1099 sbuf.append("[noninterned-string]"); 1100 sbuf.append('#'); 1101 sbuf.append(id); 1102 /* 1103 int line = getLineNumber(); 1104 if (line != 0) 1105 { 1106 sbuf.append("/line:"); 1107 sbuf.append(line); 1108 int column = getColumnNumber(); 1109 if (column != 0) 1110 { 1111 sbuf.append(':'); 1112 sbuf.append(column); 1113 } 1114 } 1115 */ 1116 sbuf.append("/fl:"); 1117 sbuf.append(Long.toHexString(flags)); 1118 if (ignorable()) 1119 sbuf.append("(ignorable)"); 1120 Expression tx = typeExp; 1121 Type t = type; 1122 if (tx != null && ! (tx instanceof QuoteExp)) 1123 { 1124 sbuf.append("::"); 1125 sbuf.append(tx); 1126 } 1127 else if (t != null && t != Type.pointer_type) 1128 { 1129 sbuf.append("::"); 1130 sbuf.append(t.getName()); 1131 } 1132 if (base != null) 1133 { 1134 sbuf.append("(base:#"); 1135 sbuf.append(base.id); 1136 sbuf.append(')'); 1137 } 1138 } 1139 1140 toString()1141 public String toString() 1142 { 1143 return "Declaration["+symbol+'#'+id+']'; 1144 /* 1145 StringBuffer sbuf = new StringBuffer(); 1146 sbuf.append("Declaration["); 1147 printInfo(sbuf); 1148 sbuf.append(']'); 1149 return sbuf.toString(); 1150 */ 1151 } 1152 followAliases(Declaration decl)1153 public static Declaration followAliases (Declaration decl) 1154 { 1155 while (decl != null && decl.isAlias()) 1156 { 1157 Expression declValue = decl.getValue(); 1158 if (! (declValue instanceof ReferenceExp)) 1159 break; 1160 ReferenceExp rexp = (ReferenceExp) declValue; 1161 Declaration orig = rexp.binding; 1162 if (orig == null) 1163 break; 1164 decl = orig; 1165 } 1166 return decl; 1167 } 1168 makeField(Compilation comp, Expression value)1169 public void makeField(Compilation comp, Expression value) 1170 { 1171 setSimple(false); 1172 makeField(comp.mainClass, comp, value); 1173 } 1174 makeField(ClassType frameType, Compilation comp, Expression value)1175 public void makeField(ClassType frameType, Compilation comp, Expression value) 1176 { 1177 boolean external_access = needsExternalAccess(); 1178 int fflags = 0; 1179 boolean isConstant = getFlag(IS_CONSTANT); 1180 boolean typeSpecified = getFlag(TYPE_SPECIFIED); 1181 // In immediate mode we may need to access the field from a future 1182 // command in a different "runtime package" (see JVM spec) because it 1183 // gets loaded by a different class loader. So make the field public. 1184 if (isPublic() || external_access || comp.immediate) { 1185 fflags |= Access.PUBLIC; 1186 // FIXME do setIndirectBinding even if it's constant, 1187 // as long as just a define-constant or ! and not a class or alias 1188 if (comp.isInteractive() && context == comp.getModule() 1189 && ! isConstant) 1190 setIndirectBinding(true); 1191 } 1192 if (isStatic() 1193 // "Dynamic" variables use ThreadLocation, based on the current 1194 // Environment, so we don't need more than one static field. 1195 || (getFlag(Declaration.IS_UNKNOWN 1196 |Declaration.IS_DYNAMIC|Declaration.IS_FLUID) 1197 && isIndirectBinding() && ! isAlias()) 1198 || (value instanceof ClassExp 1199 && ! ((LambdaExp) value).getNeedsClosureEnv())) 1200 fflags |= Access.STATIC; 1201 if ((isIndirectBinding() 1202 || (isConstant 1203 && (shouldEarlyInit() 1204 || (context instanceof ModuleExp && ((ModuleExp) context).staticInitRun())))) 1205 && (context instanceof ClassExp || context instanceof ModuleExp)) 1206 fflags |= Access.FINAL; 1207 Type ftype = getImplementationType(); 1208 if (! ignorable()) 1209 { 1210 String dname = getName(); 1211 String fname = dname; 1212 boolean haveName = fname != null; 1213 int nlength; 1214 if (fname==null) 1215 { 1216 fname = "$unnamed$0"; 1217 nlength = fname.length() - 2; // Without the "$0". 1218 } 1219 else 1220 { 1221 fname = Mangling.mangleField(fname); 1222 if (getFlag(IS_UNKNOWN)) 1223 { 1224 fname = UNKNOWN_PREFIX + fname; 1225 haveName = false; 1226 } 1227 if (external_access && ! getFlag(Declaration.MODULE_REFERENCE)) 1228 { 1229 fname = PRIVATE_PREFIX + fname; 1230 haveName = false; 1231 } 1232 nlength = fname.length(); 1233 } 1234 int counter = 0; 1235 while (frameType.getDeclaredField(fname) != null) 1236 fname = fname.substring(0, nlength) + '$' + (++ counter); 1237 setField(frameType.addField (fname, ftype, fflags)); 1238 if (getAnnotation(kawa.SourceType.class) == null) { 1239 String encType = comp.getLanguage().encodeType(getType()); 1240 if (encType != null && encType.length() > 0) { 1241 AnnotationEntry ae = new AnnotationEntry(ClassType.make("kawa.SourceType")); 1242 ae.addMember("value", encType, Type.javalangStringType); 1243 RuntimeAnnotationsAttr.maybeAddAnnotation(getField(), ae); 1244 } 1245 } 1246 if (haveName) 1247 { 1248 this.maybeSourceName(getField(), Mangling.demangleField(fname)); 1249 } 1250 if (value instanceof QuoteExp) 1251 { 1252 Object val = ((QuoteExp) value).getValue(); 1253 if (getField().getStaticFlag() 1254 && val != null 1255 && val.getClass().getName().equals(ftype.getName())) 1256 { 1257 Literal literal = comp.litTable.findLiteral(val); 1258 if (literal.field == null) 1259 literal.assign(getField(), comp.litTable); 1260 } 1261 else if (ftype instanceof PrimType 1262 || "java.lang.String".equals(ftype.getName())) 1263 { 1264 if (val instanceof gnu.text.Char) 1265 val = gnu.math.IntNum.make(((gnu.text.Char) val).intValue()); 1266 getField().setConstantValue(val, frameType); 1267 return; 1268 } 1269 } 1270 } 1271 // The EARLY_INIT case is handled in SetExp.compile. 1272 if (! shouldEarlyInit() 1273 && context instanceof ModuleExp 1274 && (isIndirectBinding() 1275 || (value != null && ! (value instanceof ClassExp)))) 1276 { 1277 BindingInitializer.create(this, value, comp); 1278 } 1279 } 1280 1281 /** Add SourceName annotation to member, if needed. 1282 */ maybeSourceName(AttrContainer member, String expName)1283 public void maybeSourceName(AttrContainer member, String expName) { 1284 Object fsymbol = getSymbol(); 1285 String dname = getName(); 1286 String uri, prefix; 1287 boolean haveUri, havePrefix; 1288 // If name is a non-simple Symbol (i.e. with uri or prefix) 1289 // or the field name doesn't demangle to name, then emit 1290 // a SourceName annotation so we can recover the correct name. 1291 if (fsymbol instanceof Symbol) { 1292 uri = ((Symbol) fsymbol).getNamespaceURI(); 1293 prefix = ((Symbol) fsymbol).getPrefix(); 1294 if (uri == null) 1295 uri = ""; 1296 haveUri = ! "".equals(uri); 1297 havePrefix = ! "".equals(prefix); 1298 } else { 1299 uri = prefix = ""; 1300 haveUri = havePrefix = false; 1301 } 1302 // FIXME should optimize if uri == module.getNamespaceUri() 1303 if (haveUri || havePrefix 1304 || expName == null || ! expName.equals(dname)) { 1305 AnnotationEntry ae = new AnnotationEntry(ClassType.make("gnu.expr.SourceName")); 1306 ae.addMember("name", dname, Type.javalangStringType); 1307 if (haveUri) 1308 ae.addMember("uri", uri, Type.javalangStringType); 1309 if (havePrefix) 1310 ae.addMember("prefix", prefix, Type.javalangStringType); 1311 RuntimeAnnotationsAttr.maybeAddAnnotation(member, ae); 1312 } 1313 } 1314 1315 /* Used when evaluating for an indirect binding. */ makeIndirectLocationFor()1316 gnu.mapping.Location makeIndirectLocationFor () 1317 { 1318 Symbol sym = symbol instanceof Symbol ? (Symbol) symbol 1319 : Namespace.EmptyNamespace.getSymbol(symbol.toString().intern()); 1320 return gnu.mapping.Location.make(sym); 1321 } 1322 1323 /** Create a declaration corresponding to a static field. 1324 * @param cname name of class containing field 1325 * @param fname name of static field 1326 */ 1327 public static Declaration getDeclarationFromStatic(String cname, String fname)1328 getDeclarationFromStatic (String cname, String fname) 1329 { 1330 ClassType clas = ClassType.make(cname); 1331 Field fld = clas.getDeclaredField(fname); 1332 Declaration decl = new Declaration(fname, fld); 1333 decl.setFlag(Declaration.IS_CONSTANT|Declaration.STATIC_SPECIFIED); 1334 return decl; 1335 } 1336 1337 /** Similar to {@code getDeclarationFromStatic}, 1338 * but also do {@code noteValue} with the field's value. 1339 */ 1340 public static Declaration getDeclarationValueFromStatic(String className, String fieldName, String name)1341 getDeclarationValueFromStatic (String className, 1342 String fieldName, String name) 1343 { 1344 try 1345 { 1346 Class cls = Class.forName(className); 1347 java.lang.reflect.Field fld = cls.getDeclaredField(fieldName); 1348 Object value = fld.get(null); 1349 1350 Declaration decl 1351 = new Declaration(name, 1352 ClassType.make(className) 1353 .getDeclaredField(fieldName)); 1354 decl.noteValue(new QuoteExp(value)); 1355 decl.setFlag(Declaration.IS_CONSTANT|Declaration.STATIC_SPECIFIED); 1356 return decl; 1357 } 1358 catch (Exception ex) 1359 { 1360 throw new WrappedException(ex); 1361 } 1362 } 1363 getDeclaration(Named proc)1364 public static Declaration getDeclaration(Named proc) 1365 { 1366 return getDeclaration(proc, proc.getName()); 1367 } 1368 getDeclaration(Object proc, String name)1369 public static Declaration getDeclaration(Object proc, String name) 1370 { 1371 gnu.bytecode.Field procField = null; 1372 if (name != null) 1373 { 1374 /* 1375 // This is a way to map from the Procedure's name to a Field, 1376 // by assuming the name as the form "classname:fieldname". 1377 // It may be better to use names of the form "{classname}fieldname". 1378 // For now we don't need this feature. 1379 int colon = name.indexOf(':'); 1380 if (colon > 0) 1381 { 1382 try 1383 { 1384 ClassType procType 1385 = (ClassType) ClassType.make(name.substring(0, colon)); 1386 name = name.substring(colon+1); 1387 String fname = Mangling.mangleField(name); 1388 procField = procType.getDeclaredField(fname); 1389 } 1390 catch (Exception ex) 1391 { 1392 System.err.println("CAUGHT "+ex+" in getDeclaration for "+proc); 1393 return null; 1394 } 1395 } 1396 else 1397 */ 1398 { 1399 Class procClass = PrimProcedure.getProcedureClass(proc); 1400 if (procClass != null) 1401 { 1402 ClassType procType = (ClassType) Type.make(procClass); 1403 String fname = Mangling.mangleField(name); 1404 procField = procType.getDeclaredField(fname); 1405 } 1406 } 1407 } 1408 if (procField != null) 1409 { 1410 int fflags = procField.getModifiers(); 1411 if ((fflags & Access.STATIC) != 0) 1412 { 1413 Declaration decl = new Declaration(name, procField); 1414 decl.noteValue(new QuoteExp(proc)); 1415 if ((fflags & Access.FINAL) != 0) 1416 decl.setFlag(Declaration.IS_CONSTANT); 1417 return decl; 1418 } 1419 } 1420 return null; 1421 } 1422 1423 /** Get the "initial value" expression. 1424 * This is used for the initializing value in a LetExp, 1425 * a parameter's default value, or for pattern-matching. 1426 */ getInitValue()1427 public Expression getInitValue() { return initValue; } setInitValue(Expression init)1428 public void setInitValue(Expression init) { this.initValue = init; } 1429 private Expression initValue; 1430 1431 ValueSource values[]; 1432 int nvalues; 1433 static final ValueSource unknownValueInstance = 1434 new ValueSource(ValueSource.UNKNOWN_KIND, null, 0); 1435 static final ValueSource[] unknownValueValues = { unknownValueInstance }; 1436 hasUnknownValue()1437 public boolean hasUnknownValue () { return values == Declaration.unknownValueValues; } 1438 1439 /** The value of this <code>Declaration</code>, if known. 1440 * Usually the expression used to initialize the <code>Declaration</code>, 1441 * or null if the <code>Declaration</code> can be assigned a different 1442 * value after initialization. Note that this is the semantic value: If the 1443 * <code>INDIRECT_LOCATION</code> is set, then <code>getValue</code> is the 1444 * value <em>after</em> de-referencing the resulting <code>Location</code>. 1445 * An exception is if <code>isAlias()</code>; in that case 1446 * <code>getValue()</code> is an expression yielding a <code>Location</code> 1447 * which needs to be de-referenced to get this <code>Declaration</code>'s 1448 * actual value. 1449 */ getValue()1450 public final Expression getValue() 1451 { 1452 if (nvalues == 0) 1453 { 1454 if (getField() != null 1455 && getField().getDeclaringClass().isExisting() 1456 && ((getField().getModifiers() & Access.STATIC+Access.FINAL) 1457 == Access.STATIC+Access.FINAL) 1458 && ! isIndirectBinding()) 1459 { 1460 try 1461 { 1462 Expression value = new QuoteExp(getField().getReflectField().get(null)); 1463 noteValue(value); 1464 return value; 1465 } 1466 catch (Exception ex) 1467 { 1468 } 1469 } 1470 return QuoteExp.undefined_exp; 1471 } 1472 if (nvalues == 1) 1473 return values[0].getValue(this); 1474 return null; 1475 } 1476 getValueRaw()1477 public Expression getValueRaw () 1478 { 1479 if (nvalues == 0) 1480 return QuoteExp.undefined_exp; 1481 if (nvalues == 1) 1482 return values[0].getValue(this); 1483 return null; 1484 } 1485 1486 /** Set the value associated with this Declaration. 1487 * Most code should use noteValue instead. */ setValue(Expression value)1488 public final void setValue(Expression value) 1489 { 1490 values = null; 1491 nvalues = 0; 1492 noteValue(value); 1493 } 1494 1495 /** If getValue() is a constant, return the constant value, otherwise null. */ getConstantValue()1496 public final Object getConstantValue() 1497 { 1498 Object v = getValue(); 1499 if (! (v instanceof QuoteExp) || v == QuoteExp.undefined_exp) 1500 return null; 1501 return ((QuoteExp) v).getValue(); 1502 } 1503 hasConstantValue()1504 public final boolean hasConstantValue () 1505 { 1506 Object v = getValue(); 1507 return (v instanceof QuoteExp) && v != QuoteExp.undefined_exp; 1508 } 1509 getLambdaValue()1510 public LambdaExp getLambdaValue () 1511 { 1512 if (! isAlias() && nvalues == 1) 1513 { 1514 Expression val = values[0].getValue(this); 1515 if (val != null && val.getClass() == LambdaExp.class) 1516 return (LambdaExp) val; 1517 } 1518 return null; 1519 } 1520 noteValue(Expression value)1521 public void noteValue (Expression value) 1522 { 1523 checkNameDecl(value); 1524 if (value == null) 1525 noteValueUnknown(); 1526 else if (values != unknownValueValues) 1527 noteValue(new ValueSource(ValueSource.GENERAL_KIND, value, 0)); 1528 } 1529 noteValue(ValueSource value)1530 void noteValue (ValueSource value) 1531 { 1532 if (values == unknownValueValues) 1533 throw new InternalError(); 1534 if (values == null) 1535 values = new ValueSource[4]; 1536 else if (nvalues >= values.length) 1537 { 1538 ValueSource[] tmp = new ValueSource[2 * nvalues]; 1539 System.arraycopy(values, 0, tmp, 0, nvalues); 1540 values = tmp; 1541 } 1542 values[nvalues++] = value; 1543 } 1544 noteValueConstant(Object value)1545 public void noteValueConstant (Object value) 1546 { 1547 if (values != unknownValueValues) 1548 { 1549 noteValue(new QuoteExp(value)); 1550 } 1551 } 1552 noteValueUnknown()1553 public void noteValueUnknown () 1554 { 1555 checkNameDecl(null); 1556 values = unknownValueValues; 1557 nvalues = 1; 1558 } 1559 noteValueFromSet(SetExp setter)1560 public void noteValueFromSet (SetExp setter) 1561 { 1562 if (values != unknownValueValues) 1563 { 1564 checkNameDecl(setter.new_value); 1565 setter.valueIndex = nvalues; 1566 noteValue(new ValueSource(ValueSource.SET_RHS_KIND, setter, 0)); 1567 } 1568 } 1569 noteValueFromLet(ScopeExp letter)1570 public void noteValueFromLet (ScopeExp letter) 1571 { 1572 Expression init = getInitValue(); 1573 if (init != QuoteExp.undefined_exp && values != unknownValueValues) 1574 { 1575 checkNameDecl(init); 1576 noteValue(new ValueSource(ValueSource.LET_INIT_KIND, letter, 0)); 1577 } 1578 } 1579 noteValueFromApply(ApplyExp app, int index)1580 public void noteValueFromApply (ApplyExp app, int index) 1581 { 1582 if (values != unknownValueValues) 1583 noteValue(new ValueSource(ValueSource.APPLY_KIND, app, index)); 1584 } 1585 1586 /** Set symbol from initializing SetExp. 1587 * Used for an export-only alias, for handling export-with-rename. 1588 */ patchSymbolFromSet()1589 public boolean patchSymbolFromSet() { 1590 if (nvalues != 1 || values[0].kind != ValueSource.SET_RHS_KIND) 1591 return false; 1592 SetExp sexp = (SetExp) values[0].base; 1593 setSymbol(((SetExp) values[0].base).getSymbol()); 1594 return true; 1595 } 1596 checkNameDecl(Expression value)1597 private void checkNameDecl(Expression value) { 1598 if (nvalues == 1) { 1599 Expression old = values[0].getValue(this); 1600 if (old == value) 1601 return; 1602 if (old instanceof LambdaExp) 1603 ((LambdaExp) old).nameDecl = null; 1604 } 1605 if (value instanceof LambdaExp) 1606 ((LambdaExp) value).nameDecl = nvalues == 0 ? this : null; 1607 } 1608 getField()1609 public Field getField() { return field; } setField(Field field)1610 public void setField(Field field) { this.field = field; } 1611 1612 public static class ValueSource 1613 { 1614 static final int UNKNOWN_KIND = 0; 1615 static final int GENERAL_KIND = 1; 1616 static final int SET_RHS_KIND = 2; 1617 static final int LET_INIT_KIND = 3; 1618 static final int APPLY_KIND = 4; 1619 public int kind; 1620 public Expression base; 1621 public int index; 1622 ValueSource(int kind, Expression base, int index)1623 ValueSource (int kind, Expression base, int index) 1624 { 1625 this.kind = kind; 1626 this.base = base; 1627 this.index = index; 1628 } 1629 getValue(Declaration decl)1630 Expression getValue (Declaration decl) 1631 { 1632 switch (kind) 1633 { 1634 case UNKNOWN_KIND: 1635 return null; 1636 case GENERAL_KIND: 1637 return base; 1638 case SET_RHS_KIND: 1639 return ((SetExp) base).new_value; 1640 case LET_INIT_KIND: 1641 return decl.getInitValue(); 1642 case APPLY_KIND: 1643 ApplyExp app = (ApplyExp) base; 1644 int i = index; 1645 // If a function is called via an apply-function, the latter 1646 // might distribute a multiple-valued argument among multiple 1647 // parameters. Punt on that for now. 1648 Compilation comp = Compilation.getCurrent(); 1649 Expression afunc = app.getFunction(); 1650 if (comp.isSimpleApplyFunction(afunc)) 1651 i++; 1652 else if (comp.isApplyFunction(afunc)) 1653 return null; 1654 if (i >= app.getArgCount()) 1655 return null; 1656 return app.getArg(i); 1657 default: 1658 throw new Error(); 1659 } 1660 } 1661 } 1662 } 1663