001: package gnu.expr;
002:
003: import gnu.bytecode.*;
004: import gnu.mapping.Named;
005:
006: /**
007: * The static information associated with a local variable binding.
008: * <p>
009: * These are the kinds of Declaration we use:
010: * <p>
011: * A local variable that is not captured by an inner lambda is stored
012: * in a Java local variables slot (register). The predicate isSimple ()
013: * is true, and offset is the number of the local variable slot.
014: * <p>
015: * If a local variable is captured by an inner lambda, the
016: * variable is stored in a field of the LambdaExp's heapFrame variable.
017: * (The latter declaration has isSimple and isArtificial true.)
018: * The Declaration's field specifies the Field used.
019: *
020: * If a function takes a fixed number of parameters, at most four,
021: * then the arguments are passed in Java registers 1..4.
022: * If a parameter is not captured by an inner lambda, the parameter
023: * has the flags isSimple and isParameter true.
024: * <p>
025: * A parameter named "foo" that is captured by an inner lambda is represented
026: * using two Declarations, named "foo" and "fooIncoming".
027: * The "fooIncoming" declaration is the actual parameter as passed
028: * by the caller using a Java local variable slot. It has isParameter(),
029: * isSimple(), and isArtificial set. The "foo" Declaration has isParameter()
030: * set. The procedure prologue copies "fooIncoming" to "foo", which acts
031: * just like a normal captured local variable.
032: * <p>
033: * If a function takes more than 4 or a variable number of parameters,
034: * the arguments are passed in an array (using the applyN virtual method).
035: * This array is referenced by the argsArray declaration, which has
036: * isSimple(), isParameter(), and isArtificial() true, and its offset is 1.
037: * The parameters are copied into the program-named variables by the
038: * procedure prologue, so the parameters henceforth act like local variables.
039: *
040: * @author Per Bothner
041: */
042:
043: public class Declaration {
044: static int counter;
045: /** Unique id number, to ease print-outs and debugging. */
046: protected int id = ++counter;
047:
048: /** The (interned) name of the new variable.
049: * This is the source-level (non-mangled) name. */
050: String name;
051:
052: public ScopeExp context;
053:
054: protected Type type;
055:
056: public final Type getType() {
057: return type;
058: }
059:
060: public final void setType(Type type) {
061: this .type = type;
062: if (var != null)
063: var.setType(type);
064: }
065:
066: public final String getName() {
067: return name;
068: }
069:
070: /* Declarations in a ScopeExp are linked together in a linked list. */
071: Declaration next;
072:
073: public final Declaration nextDecl() {
074: return next;
075: }
076:
077: Variable var;
078:
079: public Variable getVariable() {
080: return var;
081: }
082:
083: public final boolean isSimple() {
084: return (flags & IS_SIMPLE) != 0;
085: }
086:
087: public final void setSimple(boolean b) {
088: setFlag(b, IS_SIMPLE);
089: if (var != null)
090: var.setSimple(b);
091: }
092:
093: /** Return the ScopeExp that contains (declares) this Declaration. */
094: public final ScopeExp getContext() {
095: return context;
096: }
097:
098: /** Used to link Declarations in a LambdaExp's capturedVars list. */
099: Declaration nextCapturedVar;
100:
101: /** If non-null, field is relative to base.
102: * If IS_FLUID, base points to IS_UNKNOWN Binding. */
103: public Declaration base;
104:
105: public Field field;
106:
107: /** If this is a field in some object, load a reference to that object. */
108: public void loadOwningObject(Compilation comp) {
109: if (base != null)
110: base.load(comp);
111: else
112: getContext().currentLambda().loadHeapFrame(comp);
113: }
114:
115: public void load(Compilation comp) {
116: gnu.bytecode.CodeAttr code = comp.getCode();
117: if (field == null && getFlag(STATIC_SPECIFIED)
118: && value instanceof LambdaExp) {
119: LambdaExp lambda = (LambdaExp) value;
120: lambda.flags |= LambdaExp.NO_FIELD;
121: lambda.compileAsMethod(comp);
122: comp.topLambda.addApplyMethod(lambda);
123: makeField(comp, value);
124: }
125:
126: if (field != null) {
127: if (!field.getStaticFlag()) {
128: loadOwningObject(comp);
129: code.emitGetField(field);
130: } else
131: code.emitGetStatic(field);
132: } else {
133: Variable var = getVariable();
134: if (context instanceof ClassExp && var == null
135: && !getFlag(PROCEDURE)) {
136: ClassExp cl = (ClassExp) context;
137: if (cl.isMakingClassPair()) {
138: String getName = ClassExp.slotToMethodName("get",
139: getName());
140: Method getter = cl.type.getDeclaredMethod(getName,
141: 0);
142: cl.loadHeapFrame(comp);
143: code.emitInvoke(getter);
144: return;
145: }
146: }
147: if (var == null) {
148: var = allocateVariable(code);
149: }
150: code.emitLoad(var);
151: }
152: }
153:
154: /* Compile code to store a value (which must already be on the
155: stack) into this variable. */
156: public void compileStore(Compilation comp) {
157: gnu.bytecode.CodeAttr code = comp.getCode();
158: if (isSimple())
159: code.emitStore(getVariable());
160: else {
161: if (!field.getStaticFlag()) {
162: loadOwningObject(comp);
163: code.emitSwap();
164: code.emitPutField(field);
165: } else
166: code.emitPutStatic(field);
167: }
168: }
169:
170: /** If non-null, the single expression used to set this variable.
171: * If the variable can be set more than once, then value is null. */
172: protected Expression value = QuoteExp.undefined_exp;
173:
174: public final Expression getValue() {
175: return value;
176: }
177:
178: /** If getValue() is a constant, return the constant value, otherwise null. */
179: public final Object getConstantValue() {
180: if (!(value instanceof QuoteExp))
181: return null;
182: return ((QuoteExp) value).getValue();
183: }
184:
185: static final int INDIRECT_BINDING = 1;
186: static final int CAN_READ = 2;
187: static final int CAN_CALL = 4;
188: static final int CAN_WRITE = 8;
189: static final int IS_FLUID = 0x10;
190: static final int PRIVATE = 0x20;
191: static final int IS_SIMPLE = 0x40;
192: static final int PROCEDURE = 0x80;
193: static final int IS_ALIAS = 0x100;
194: /** Set if this is just a declaration, not a definition. */
195: public static final int NOT_DEFINING = 0x200;
196: public static final int EXPORT_SPECIFIED = 0x400;
197: public static final int STATIC_SPECIFIED = 0x800;
198: public static final int NONSTATIC_SPECIFIED = 0x1000;
199: public static final int TYPE_SPECIFIED = 0x2000;
200: public static final int IS_CONSTANT = 0x4000;
201: public static final int IS_SYNTAX = 0x8000;
202: public static final int IS_UNKNOWN = 0x10000;
203: public static final int PRIVATE_SPECIFIED = 0x20000;
204:
205: // This should be a type property, not a variable property, at some point!
206: public static final int IS_SINGLE_VALUE = 0x40000;
207:
208: public static final int TRANSIENT = 0x80000;
209: public static final int VOLATILE = 0x100000;
210:
211: public static final int NOT_INITIALIZED = 0x200000;
212:
213: protected int flags = IS_SIMPLE;
214:
215: public final boolean getFlag(int flag) {
216: return (flags & flag) != 0;
217: }
218:
219: public final void setFlag(boolean setting, int flag) {
220: if (setting)
221: flags |= flag;
222: else
223: flags &= ~flag;
224: }
225:
226: public final void setFlag(int flag) {
227: flags |= flag;
228: }
229:
230: public final boolean isPublic() {
231: return context instanceof ModuleExp && (flags & PRIVATE) == 0;
232: }
233:
234: public final boolean isPrivate() {
235: return (flags & PRIVATE) != 0;
236: }
237:
238: public final void setPrivate(boolean isPrivate) {
239: setFlag(isPrivate, PRIVATE);
240: }
241:
242: public final boolean isSpecifiedPrivate() {
243: return (flags & PRIVATE_SPECIFIED) != 0;
244: }
245:
246: public final void setSpecifiedPrivate(boolean isPrivate) {
247: setFlag(isPrivate, PRIVATE_SPECIFIED);
248: }
249:
250: public final boolean isAlias() {
251: return (flags & IS_ALIAS) != 0;
252: }
253:
254: public final void setAlias(boolean flag) {
255: setFlag(flag, IS_ALIAS);
256: }
257:
258: /** True if this is a fluid binding (in a FluidLetExp). */
259: public final boolean isFluid() {
260: return (flags & IS_FLUID) != 0;
261: }
262:
263: public final void setFluid(boolean fluid) {
264: setFlag(fluid, IS_FLUID);
265: }
266:
267: public final boolean isProcedureDecl() {
268: return (flags & PROCEDURE) != 0;
269: }
270:
271: public final void setProcedureDecl(boolean val) {
272: setFlag(val, PROCEDURE);
273: }
274:
275: /** True if the value of the variable is the contents of a Binding. */
276: public final boolean isIndirectBinding() {
277: return (flags & INDIRECT_BINDING) != 0;
278: }
279:
280: public final void setIndirectBinding(boolean indirectBinding) {
281: setFlag(indirectBinding, INDIRECT_BINDING);
282: }
283:
284: /* Note: You probably want to use !ignorable(). */
285: public final boolean getCanRead() {
286: return (flags & CAN_READ) != 0;
287: }
288:
289: public final void setCanRead(boolean read) {
290: setFlag(read, CAN_READ);
291: }
292:
293: public final void setCanRead() {
294: setFlag(true, CAN_READ);
295: if (base != null)
296: base.setCanRead();
297: }
298:
299: public final boolean getCanCall() {
300: return (flags & CAN_CALL) != 0;
301: }
302:
303: public final void setCanCall(boolean called) {
304: setFlag(called, CAN_CALL);
305: }
306:
307: public final void setCanCall() {
308: setFlag(true, CAN_CALL);
309: if (base != null)
310: base.setCanRead();
311: }
312:
313: public final boolean getCanWrite() {
314: return (flags & CAN_WRITE) != 0;
315: }
316:
317: public final void setCanWrite(boolean written) {
318: if (written)
319: flags |= CAN_WRITE;
320: else
321: flags &= ~CAN_WRITE;
322: }
323:
324: public final void setCanWrite() {
325: flags |= CAN_WRITE;
326: if (base != null)
327: base.setCanRead();
328: }
329:
330: public void setName(String name) {
331: this .name = name;
332: }
333:
334: /** True if we never need to access this declaration. */
335: // rename to isAccessed?
336: public boolean ignorable() {
337: if (getCanRead() || isPublic())
338: return false;
339: if (getCanWrite() && getFlag(IS_UNKNOWN))
340: return false;
341: if (!getCanCall())
342: return true;
343: Expression value = getValue();
344: if (value == null || !(value instanceof LambdaExp))
345: return false;
346: LambdaExp lexp = (LambdaExp) value;
347: return !lexp.isHandlingTailCalls() || lexp.getInlineOnly();
348: }
349:
350: /** Does this variable need to be initialized or is default ok
351: */
352: public boolean needsInit() {
353: // This is a kludge. Ideally, we should do some data-flow analysis.
354: // But at least it makes sure require'd variables are not initialized.
355: return !getFlag(NOT_INITIALIZED) && !ignorable()
356: && !(value == QuoteExp.nullExp && base != null);
357: }
358:
359: public boolean isStatic() {
360: return (getFlag(STATIC_SPECIFIED) || (context instanceof ModuleExp && ((ModuleExp) context)
361: .isStatic()));
362: }
363:
364: public final boolean isLexical() {
365: return !isFluid() && !isStatic();
366: }
367:
368: /** List of ApplyExp where this declaration is the function called.
369: * The applications are chained using their nextcall fields. */
370: public ApplyExp firstCall;
371:
372: public void noteValue(Expression value) {
373: // We allow assigning a real value after undefined ...
374: if (this .value == QuoteExp.undefined_exp) {
375: if (value instanceof LambdaExp)
376: ((LambdaExp) value).nameDecl = this ;
377: this .value = value;
378: } else if (this .value != value) {
379: if (this .value instanceof LambdaExp)
380: ((LambdaExp) this .value).nameDecl = null;
381: this .value = null;
382: }
383: }
384:
385: protected Declaration() {
386: }
387:
388: public Declaration(String name) {
389: this (name, Type.pointer_type);
390: }
391:
392: public Declaration(String s, Type type) {
393: name = s;
394: setType(type);
395: }
396:
397: public Declaration(String name, Field field) {
398: this .name = name;
399: setType(field.getType());
400: this .field = field;
401: setSimple(false);
402: }
403:
404: Method makeBindingMethod = null;
405:
406: /** Create a Binding object, given that isIndirectBinding().
407: Assume the initial value is already pushed on the stack;
408: leaves initialized Binding object on stack. */
409: public void pushIndirectBinding(Compilation comp) {
410: CodeAttr code = comp.getCode();
411: code.emitPushString(getName());
412: if (makeBindingMethod == null) {
413: Type[] args = new Type[2];
414: args[0] = Type.pointer_type;
415: args[1] = Type.string_type;
416: makeBindingMethod = Compilation.typeBinding.addMethod(
417: "make", args, Compilation.typeBinding,
418: Access.PUBLIC | Access.STATIC);
419: }
420: code.emitInvokeStatic(makeBindingMethod);
421: }
422:
423: public final Variable allocateVariable(CodeAttr code) {
424: if (!isSimple())
425: return null;
426: if (var == null) {
427: String vname = null;
428: if (name != null)
429: vname = Compilation.mangleName(getName());
430: if (isAlias() && getValue() instanceof ReferenceExp) {
431: Declaration base = followAliases(this );
432: var = base == null ? null : base.var;
433: } else {
434: Type type = isIndirectBinding() ? Compilation.typeLocation
435: : getType();
436: var = context.scope.addVariable(code, type, vname);
437: }
438: }
439: return var;
440: }
441:
442: /** Generate code to initialize the location for this.
443: Assume the initial value is already pushed on the stack. */
444: public void initBinding(Compilation comp) {
445: if (isIndirectBinding()) {
446: pushIndirectBinding(comp);
447: CodeAttr code = comp.getCode();
448: code.emitStore(getVariable());
449: } else
450: compileStore(comp);
451: }
452:
453: String filename;
454: int position;
455:
456: public final void setFile(String filename) {
457: this .filename = filename;
458: }
459:
460: public final void setLine(int lineno, int colno) {
461: position = (lineno << 12) + colno;
462: }
463:
464: public final void setLine(int lineno) {
465: setLine(lineno, 0);
466: }
467:
468: public final String getFile() {
469: return filename;
470: }
471:
472: /** Get the line number of (the start of) this Expression.
473: * The "first" line is line 1. */
474: public final int getLine() {
475: return position >> 12;
476: }
477:
478: public final int getColumn() {
479: return position & ((1 << 12) - 1);
480: }
481:
482: public String toString() {
483: return "Declaration[" + getName() + '/' + id + ']';
484: }
485:
486: public static Declaration followAliases(Declaration decl) {
487: while (decl != null && decl.isAlias()) {
488: Expression declValue = decl.getValue();
489: if (!(declValue instanceof ReferenceExp))
490: break;
491: ReferenceExp rexp = (ReferenceExp) declValue;
492: if (rexp.binding == null)
493: break;
494: decl = rexp.binding;
495: }
496: return decl;
497: }
498:
499: public void makeField(Compilation comp, Expression value) {
500: setSimple(false);
501: String fname = getName();
502: if (getFlag(IS_UNKNOWN))
503: fname = "id$" + fname;
504: fname = Compilation.mangleNameIfNeeded(fname);
505: int fflags = 0;
506: boolean isConstant = getFlag(IS_CONSTANT);
507: boolean typeSpecified = getFlag(TYPE_SPECIFIED);
508: if (isPublic() && !isConstant && !typeSpecified)
509: setIndirectBinding(true);
510: if (isIndirectBinding() || isConstant)
511: fflags |= Access.FINAL;
512: if (!isPrivate())
513: fflags |= Access.PUBLIC;
514: if (getFlag(STATIC_SPECIFIED)
515: || (isConstant && value instanceof QuoteExp))
516: fflags |= Access.STATIC;
517: if (getFlag(IS_UNKNOWN)) {
518: // This is a kludge. We really should set STATIC only if the module
519: // is static, in which case it should be safe to make it always FINAL.
520: // But for now we don't support non-static UNKNOWNs. FIXME.
521: fflags |= Access.STATIC;
522: if (!(context instanceof ModuleExp && ((ModuleExp) context)
523: .isStatic()))
524: fflags &= ~Access.FINAL;
525: }
526: Type ftype = (isIndirectBinding() ? Compilation.typeBinding
527: : value == null || typeSpecified ? getType() : value
528: .getType());
529:
530: field = comp.topClass.addField(fname, ftype, fflags);
531: setFieldValue(comp);
532: }
533:
534: void setFieldValue(Compilation comp) {
535: Type ftype = field.getType();
536: if (value instanceof QuoteExp) {
537: Object val = ((QuoteExp) value).getValue();
538: if (val != null
539: && val.getClass().getName().equals(ftype.getName())) {
540: Literal literal = comp.findLiteral(val);
541: if (literal.field == null)
542: literal.assign(field, comp);
543: }
544: }
545: if (value instanceof QuoteExp
546: && (ftype instanceof PrimType || "java.lang.String"
547: .equals(ftype.getName()))) {
548: Object val = ((QuoteExp) value).getValue();
549: if (val != null)
550: field.setConstantValue(val, field.getDeclaringClass());
551: } else if ((isIndirectBinding() || value != null)
552: && !getFlag(IS_UNKNOWN)) {
553: BindingInitializer init = new BindingInitializer(this ,
554: field, value);
555: if (field.getStaticFlag()) {
556: init.next = comp.topLambda.clinitChain;
557: comp.topLambda.clinitChain = init;
558: } else {
559: init.next = comp.mainLambda.initChain; // FIXME why mainLambda?
560: comp.mainLambda.initChain = init;
561: }
562: }
563: }
564:
565: public static Declaration getDeclaration(Named proc) {
566: return getDeclaration(proc, proc.getName());
567: }
568:
569: public static Declaration getDeclaration(Object proc, String name) {
570: if (name != null) {
571: Class procClass = PrimProcedure.getProcedureClass(proc);
572: if (procClass != null) {
573: ClassType procType = (ClassType) Type.make(procClass);
574: String fname = Compilation.mangleName(name);
575: gnu.bytecode.Field procField = procType
576: .getDeclaredField(fname);
577: if (procField != null) {
578: int fflags = procField.getModifiers();
579: if ((fflags & Access.STATIC) != 0) {
580: Declaration decl = new Declaration(name,
581: procField);
582: decl.noteValue(new QuoteExp(proc));
583: if ((fflags & Access.FINAL) != 0)
584: decl.setFlag(Declaration.IS_CONSTANT);
585: return decl;
586: }
587: }
588: }
589: }
590: return null;
591: }
592: }
|