KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > expr > LitTable


1 package gnu.expr;
2 import java.io.*;
3 import gnu.bytecode.*;
4 import java.lang.reflect.Array JavaDoc;
5 import java.util.*;
6
7 /** Manages the literals of a Compilation.
8  * Implements ObjectOutput, because we use externalization to determine
9  * how literals get compiled into code that re-creates the literal. */

10
11 public class LitTable implements ObjectOutput
12 {
13   Compilation comp;
14   ClassType mainClass;
15
16   /* #ifdef use:java.util.IdentityHashMap */
17   IdentityHashMap literalTable = new IdentityHashMap(100);
18   /* #else */
19   // Hashtable literalTable = new Hashtable(100);
20
/* #endif */
21
22   static Hashtable staticTable = new Hashtable (100);
23
24   int literalsCount;
25
26   /** Rembembers literals to initialize (in <clinit>). */
27   Literal literalsChain;
28
29   public LitTable(Compilation comp)
30   {
31     this.comp = comp;
32     this.mainClass = comp.mainClass;
33   }
34
35   public void emit() throws IOException
36   {
37     // We use two passes. The first generates the graph of
38
// objects and how they are generated.
39
// The second pass actually emits code.
40
// The reason for using two passes is so we can detect cycles
41
// and sharing using the first pass. This generates better code:
42
// If an object is only used once, and is not a top-level literal,
43
// they we don't need to allocate a Field for it. And if an object
44
// does not cyclically depend on itself, we can allocate *and*
45
// initialize using a single call, which generates better code.
46

47     // Here is the first pass.
48
for (Literal init = literalsChain; init != null;
49      init = init.next)
50       {
51     writeObject(init.value);
52       }
53
54     // Here is the second pass.
55
for (Literal init = literalsChain; init != null;
56      init = init.next)
57       {
58     emit(init, true);
59       }
60
61     // For speedier garbage collection.
62
literalTable = null;
63     literalsCount = 0;
64   }
65
66   Object JavaDoc[] valueStack = new Object JavaDoc[20];
67   Type[] typeStack = new Type[20];
68   int stackPointer;
69   
70   void push(Object JavaDoc value, Type type)
71   {
72     if (stackPointer >= valueStack.length)
73       {
74     Object JavaDoc[] newValues = new Object JavaDoc[2 * valueStack.length];
75     Type[] newTypes = new Type[2 * typeStack.length];
76     System.arraycopy(valueStack, 0, newValues, 0, stackPointer);
77     System.arraycopy(typeStack, 0, newTypes, 0, stackPointer);
78     valueStack = newValues;
79     typeStack = newTypes;
80       }
81     valueStack[stackPointer] = value;
82     typeStack[stackPointer] = type;
83     stackPointer++;
84   }
85
86   void error(String JavaDoc msg)
87   {
88     throw new Error JavaDoc(msg);
89   }
90
91   public void flush()
92   {
93   }
94
95   public void close()
96   {
97   }
98
99   public void write(int b) throws IOException
100   {
101     error("cannot handle call to write(int) when externalizing literal");
102   }
103
104   public void writeBytes(String JavaDoc s) throws IOException
105   {
106     error("cannot handle call to writeBytes(String) when externalizing literal");
107   }
108
109   public void write(byte[] b) throws IOException
110   {
111     error("cannot handle call to write(byte[]) when externalizing literal");
112   }
113
114   public void write(byte[] b, int off, int len) throws IOException
115   {
116     error("cannot handle call to write(byte[],int,int) when externalizing literal");
117   }
118
119   public void writeBoolean(boolean v)
120   {
121     push(new Boolean JavaDoc(v), Type.boolean_type);
122   }
123
124   public void writeChar(int v)
125   {
126     push(new Character JavaDoc((char) v), Type.char_type);
127   }
128
129   public void writeByte(int v)
130   {
131     push(new Byte JavaDoc((byte) v), Type.byte_type);
132   }
133
134   public void writeShort(int v)
135   {
136     push(new Short JavaDoc((short) v), Type.short_type);
137   }
138
139   public void writeInt(int v)
140   {
141     push(new Integer JavaDoc(v), Type.int_type);
142   }
143
144   public void writeLong(long v)
145   {
146     push(new Long JavaDoc(v), Type.long_type);
147   }
148
149   public void writeFloat(float v)
150   {
151     push(new Float JavaDoc(v), Type.float_type);
152   }
153
154   public void writeDouble(double v)
155   {
156     push(new Double JavaDoc(v), Type.double_type);
157   }
158
159   public void writeUTF(String JavaDoc v)
160   {
161     push(v, Type.string_type);
162   }
163
164   public void writeChars(String JavaDoc v)
165   {
166     push(v, Type.string_type);
167   }
168
169   public void writeObject(Object JavaDoc obj) throws IOException
170   {
171     Literal lit = findLiteral(obj);
172
173     // Usually a no-op, but if the literalTable is a Hashtable (rather
174
// than an IdentityHashMap) then we might find a literal whose
175
// value is equals to obj, but not identical. This can lead to trouble,
176
// e.g. if one is a Pair and the other is a PairWithPosition.
177
/* #ifndef use:java.util.IdentityHashMap */
178     // obj = lit.value;
179
/* #endif */
180
181     if ((lit.flags & (Literal.WRITTEN|Literal.WRITING)) != 0)
182       {
183     // It is referenced more than once, so we we need a Field
184
// to save the value.
185
if (lit.field == null
186         && obj != null && ! (obj instanceof String JavaDoc))
187       lit.assign(this);
188     if ((lit.flags & Literal.WRITTEN) == 0)
189       lit.flags |= Literal.CYCLIC;
190       }
191     else
192       {
193     lit.flags |= Literal.WRITING;
194     int oldStack = stackPointer;
195     if (obj instanceof gnu.lists.FString
196         && ((gnu.lists.FString) obj).size() < 65535)
197       { // Optimization.
198
push(obj.toString(), Type.string_type);
199       }
200     else if (obj instanceof Externalizable)
201       {
202         ((Externalizable) obj).writeExternal(this);
203       }
204     else if (obj instanceof Object JavaDoc[])
205       {
206         Object JavaDoc[] arr = (Object JavaDoc[]) obj;
207         for (int i = 0; i < arr.length; i++)
208           {
209         writeObject(arr[i]);
210           }
211       }
212     else if (obj == null
213                  || obj instanceof String JavaDoc || lit.type instanceof ArrayType)
214       {
215         // nothing to do
216
}
217         else if (obj instanceof java.math.BigInteger JavaDoc)
218           {
219             writeChars(obj.toString());
220           }
221         else if (obj instanceof java.math.BigDecimal JavaDoc)
222           {
223             java.math.BigDecimal JavaDoc dec = (java.math.BigDecimal JavaDoc) obj;
224             /* #ifdef JAVA2 */
225             writeObject(dec.unscaledValue());
226             writeInt(dec.scale());
227             /* #else */
228             // writeChars(obj.toString());
229
/* #endif */
230           }
231     else if (obj instanceof Integer JavaDoc)
232       push(obj, Type.int_type);
233     else if (obj instanceof Short JavaDoc)
234       push(obj, Type.short_type);
235     else if (obj instanceof Byte JavaDoc)
236       push(obj, Type.byte_type);
237     else if (obj instanceof Long JavaDoc)
238       push(obj, Type.long_type);
239     else if (obj instanceof Double JavaDoc)
240       push(obj, Type.double_type);
241     else if (obj instanceof Float JavaDoc)
242       push(obj, Type.float_type);
243     else if (obj instanceof Character JavaDoc)
244       push(obj, Type.char_type);
245         else if (obj instanceof Class JavaDoc)
246           push(obj, Type.java_lang_Class_type);
247     else
248       error(obj.getClass().getName()+" does not implement Externalizable");
249     int nargs = stackPointer - oldStack;
250     if (nargs == 0)
251       {
252         lit.argValues = gnu.mapping.Values.noArgs;
253         lit.argTypes = Type.typeArray0;
254       }
255     else
256       {
257         lit.argValues = new Object JavaDoc[nargs];
258         lit.argTypes = new Type[nargs];
259         System.arraycopy(valueStack, oldStack, lit.argValues, 0, nargs);
260         System.arraycopy(typeStack, oldStack, lit.argTypes, 0, nargs);
261         stackPointer = oldStack;
262       }
263     lit.flags |= Literal.WRITTEN;
264       }
265     push(lit, lit.type);
266   }
267
268   public Literal findLiteral (Object JavaDoc value)
269   {
270     if (value == null)
271       return Literal.nullLiteral;
272     Literal literal = (Literal) literalTable.get(value);
273     if (literal != null)
274       return literal;
275     if (comp.immediate)
276       return new Literal (value, this);
277     Class JavaDoc valueClass = value.getClass();
278     Type valueType = Type.make(valueClass);
279
280     synchronized (staticTable)
281       {
282     literal = (Literal) staticTable.get(value);
283     if ((literal == null || literal.value != value)
284         && valueType instanceof ClassType)
285       {
286         // Add all the static final public fields to staticTable.
287
int needed_mod = Access.STATIC | Access.FINAL | Access.PUBLIC;
288         Class JavaDoc fldClass = valueClass;
289         ClassType fldType = (ClassType) valueType;
290         while (staticTable.get(fldClass) == null)
291           {
292         // This is a convention to note that we've scanned valueType.
293
staticTable.put(fldClass, fldClass);
294         for (Field fld = fldType.getFields();
295              fld != null; fld = fld.getNext())
296           {
297             if ((fld.getModifiers() & needed_mod) == needed_mod)
298               {
299             try
300               {
301                 java.lang.reflect.Field JavaDoc rfld = fld.getReflectField();
302                 Object JavaDoc litValue = rfld.get(null);
303                 if (litValue == null
304                 || ! fldClass.isInstance(litValue))
305                   continue;
306                 Literal lit = new Literal (litValue, fld, this);
307                 staticTable.put(litValue, lit);
308                 staticTable.put(lit, litValue);
309                 if (value == litValue)
310                   literal = lit;
311               }
312             catch (Throwable JavaDoc ex)
313               {
314                 error("caught "+ex+" getting static field "+fld);
315               }
316               }
317           }
318         fldClass = fldClass.getSuperclass();
319         if (fldClass == null)
320           break;
321         fldType = (ClassType) Type.make(fldClass);
322           }
323       }
324       }
325
326     if (literal != null)
327       literalTable.put(value, literal);
328     else
329       literal = new Literal (value, valueType, this);
330     return literal;
331   }
332
333   Method getMethod (ClassType type, String JavaDoc name,
334             Literal literal, boolean isStatic)
335   {
336     Type[] argTypes = literal.argTypes;
337     Method method = type.getDeclaredMethods();
338     int argLength = argTypes.length;
339     Method best = null;
340     long bestArrayArgs = 0;
341     boolean ambiguous = false;
342     Type[] bParameters = null;
343   methodLoop:
344     for (; method != null; method = method.getNext())
345       {
346     if (! name.equals(method.getName()))
347       continue;
348     boolean mstatic = method.getStaticFlag();
349     if (isStatic != mstatic)
350       continue;
351     // One bit set for each array parameter.
352
long arrayArgs = 0;
353     Type[] mParameters = method.getParameterTypes();
354     int iarg = 0; int iparam = 0;
355     for (;; iarg++, iparam++)
356       {
357         if (iarg == argLength && iparam == mParameters.length)
358           {
359         if (best == null || (bestArrayArgs != 0 && arrayArgs == 0))
360           {
361             best = method;
362             bParameters = mParameters;
363             bestArrayArgs = arrayArgs;
364           }
365         else if (arrayArgs == 0)
366           {
367             // Now see which of 'best' and 'method' is more specific.
368

369             // True if we know best cannot be the more specific.
370
boolean not1 = false;
371             // True if we know new method cannot be the more specific.
372
boolean not2 = false;
373             for (int j = argLength; --j >= 0; )
374               {
375             int c = bParameters[j].compare(mParameters[j]);
376             if (c != 1)
377               {
378                 not2 = true;
379                 if (not1)
380                   break;
381               }
382             if (c != -1)
383               {
384                 not1 = true;
385                 if (not2)
386                   break;
387               }
388               }
389             if (not1)
390               {
391             best = method;
392             bParameters = mParameters;
393               }
394             ambiguous = not1 && not2;
395           }
396         continue methodLoop; // Look for other matches.
397
}
398         if (iarg == argLength || iparam == mParameters.length)
399           continue methodLoop; // fail on this method
400
Type aType = argTypes[iarg];
401         Type pType = mParameters[iparam];
402         if (aType.isSubtype(pType))
403           ; // OK so far
404
else if (pType instanceof ArrayType && iparam < 64
405              && (aType == Type.int_type || aType == Type.short_type))
406           {
407         int count = ((Number JavaDoc) literal.argValues[iarg]).intValue();
408         if (count < 0 && type.getName().equals("gnu.math.IntNum"))
409           count -= 0x80000000; // special hack for IntNum.
410
Type elementType = ((ArrayType) pType).getComponentType();
411         if (count < 0 || iarg + count >= argLength)
412           continue methodLoop; // fail on this method
413
else
414           {
415             for (int j = count; --j >= 0; )
416               {
417             Type t = argTypes[iarg + j + 1];
418             if (elementType instanceof PrimType
419                 ? elementType.getSignature() != t.getSignature()
420                 : ! t.isSubtype(elementType))
421               continue methodLoop; // fail on this method
422
}
423             iarg += count;
424             arrayArgs |= 1 << iparam;
425           }
426           }
427         else
428           {
429           continue methodLoop; // fail on this method
430
}
431       }
432       }
433     if (ambiguous)
434       return null;
435     if (bestArrayArgs != 0)
436       {
437     Object JavaDoc[] args = new Object JavaDoc[bParameters.length];
438     Type[] types = new Type[bParameters.length];
439     int iarg = 0; int iparam = 0;
440     for (;; iarg++, iparam++)
441       {
442         if (iarg == argLength)
443           break;
444         Type pType = bParameters[iparam];
445         if ((bestArrayArgs & (1 << iparam)) == 0)
446           {
447         args[iparam] = literal.argValues[iarg];
448         types[iparam] = literal.argTypes[iarg];
449           }
450         else
451           {
452         int count = ((Number JavaDoc) literal.argValues[iarg]).intValue();
453         boolean isIntNum = type.getName().equals("gnu.math.IntNum");
454         if (isIntNum)
455           count -= 0x80000000; // special hack for IntNum.
456
Type elementType = ((ArrayType) pType).getComponentType();
457         types[iparam] = pType;
458         args[iparam] = Array.newInstance(elementType.getReflectClass(),
459                          count);
460         Object JavaDoc[] argValues = literal.argValues;
461         if (isIntNum)
462           {
463             // Special kludge for IntNum: words are Externalized
464
// in big-endian (network) order, but the representation
465
// is little-endian.
466
int[] arr = (int[]) args[iparam];
467             for (int j = count; j > 0; j--)
468               arr[count - j]
469             = ((Integer JavaDoc) argValues[iarg + j]).intValue();
470           }
471         else
472           {
473             for (int j = count; --j >= 0; )
474               Array.set(args[iparam], j, argValues[iarg + 1 + j]);
475           }
476         Literal arrayLiteral = new Literal(args[iparam], pType);
477         if (elementType instanceof ObjectType)
478           arrayLiteral.argValues = (Object JavaDoc[]) args[iparam];
479         args[iparam] = arrayLiteral;
480         iarg += count;
481           }
482       }
483     literal.argValues = args;
484     literal.argTypes = types;
485       }
486     return best;
487   }
488
489   void putArgs(Literal literal, CodeAttr code)
490   {
491     Type[] argTypes = literal.argTypes;
492     int len = argTypes.length;
493     for (int i = 0; i < len; i++)
494       {
495     Object JavaDoc value = literal.argValues[i];
496     if (value instanceof Literal)
497       emit((Literal) value, false);
498     else
499       comp.compileConstant(value, new StackTarget(argTypes[i]));
500       }
501   }
502
503   private void store (Literal literal, boolean ignore, CodeAttr code)
504   {
505     if (literal.field != null)
506       {
507     if (! ignore)
508       code.emitDup(literal.type);
509     code.emitPutStatic(literal.field);
510       }
511     literal.flags |= Literal.EMITTED;
512   }
513
514   void emit(Literal literal, boolean ignore)
515   {
516     CodeAttr code = comp.getCode();
517     if (literal.value == null)
518       {
519     if (! ignore)
520       code.emitPushNull();
521       }
522     else if (literal.value instanceof String JavaDoc)
523       {
524     if (! ignore)
525       code.emitPushString(literal.value.toString ());
526       }
527     else if ((literal.flags & Literal.EMITTED) != 0)
528       {
529     if (! ignore)
530       code.emitGetStatic(literal.field);
531       }
532     else if (literal.value instanceof Object JavaDoc[])
533       {
534     int len = literal.argValues.length;
535     Type elementType = ((ArrayType) literal.type).getComponentType();
536     code.emitPushInt(len);
537     code.emitNewArray(elementType);
538     store(literal, ignore, code);
539     for (int i = 0; i < len; i++)
540       {
541         Literal el = (Literal) literal.argValues[i];
542         if (el.value == null)
543           continue;
544         code.emitDup(elementType);
545         code.emitPushInt(i);
546         emit(el, false);
547         code.emitArrayStore(elementType);
548       }
549       }
550     else if (literal.type instanceof ArrayType)
551       {
552     code.emitPushPrimArray(literal.value, (ArrayType) literal.type);
553     store(literal, ignore, code);
554       }
555     else if (literal.value instanceof Class JavaDoc)
556       {
557     comp.loadClassRef(((Class JavaDoc) literal.value).getName());
558     store(literal, ignore, code);
559       }
560     else if (literal.value instanceof ClassType
561          && ! ((ClassType) literal.value).isExisting())
562       {
563     // We need to special case ClassTypes that are (currently)
564
// non-existing, because the corresponding reflective Class
565
// needs to be loaded using the correct ClassLoader.
566
comp.loadClassRef((ClassType) literal.value);
567     code.emitInvokeStatic(Compilation.typeType.getDeclaredMethod("make", 1));
568     code.emitCheckcast(Compilation.typeClassType);
569     store(literal, ignore, code);
570       }
571     else
572       {
573     ClassType type = (ClassType) literal.type;
574     boolean useDefaultInit = (literal.flags & Literal.CYCLIC) != 0;
575     Method method = null;
576     boolean makeStatic = false;
577     if (! useDefaultInit)
578       {
579         // look for matching "make" method;
580
method = getMethod(type, "make", literal, true);
581         // otherwise look for matching constructor;
582
if (method != null)
583           makeStatic = true;
584         else if (literal.argTypes.length > 0)
585           method = getMethod(type, "<init>", literal, false);
586         if (method == null)
587           useDefaultInit = true;
588       }
589     if (useDefaultInit)
590       {
591         method = getMethod(type, "set", literal, false);
592         // otherwise error;
593
}
594     if (method == null && literal.argTypes.length > 0)
595       error("no method to construct "+literal.type);
596     if (makeStatic)
597       {
598         putArgs(literal, code);
599         code.emitInvokeStatic(method);
600       }
601     else if (useDefaultInit)
602       {
603         code.emitNew(type);
604         code.emitDup(type);
605         Method init0 = type.getDeclaredMethod("<init>", 0);
606         code.emitInvokeSpecial(init0);
607       }
608     else
609       {
610         code.emitNew(type);
611         code.emitDup(type);
612         putArgs(literal, code);
613         code.emitInvokeSpecial(method);
614       }
615     Method resolveMethod
616       = makeStatic ? null : type.getDeclaredMethod("readResolve", 0);
617     if (resolveMethod != null)
618       {
619         code.emitInvokeVirtual(resolveMethod);
620         type.emitCoerceFromObject(code);
621       }
622     store(literal, ignore && ! (useDefaultInit && method != null), code);
623     if (useDefaultInit && method != null)
624       {
625         if (! ignore)
626           code.emitDup(type);
627         putArgs(literal, code);
628         code.emitInvokeVirtual(method);
629       }
630       }
631   }
632
633 }
634
Popular Tags