1 package gnu.expr; 2 import java.io.*; 3 import gnu.bytecode.*; 4 import java.lang.reflect.Array ; 5 import java.util.*; 6 7 10 11 public class LitTable implements ObjectOutput 12 { 13 Compilation comp; 14 ClassType mainClass; 15 16 17 IdentityHashMap literalTable = new IdentityHashMap(100); 18 19 21 22 static Hashtable staticTable = new Hashtable (100); 23 24 int literalsCount; 25 26 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 47 for (Literal init = literalsChain; init != null; 49 init = init.next) 50 { 51 writeObject(init.value); 52 } 53 54 for (Literal init = literalsChain; init != null; 56 init = init.next) 57 { 58 emit(init, true); 59 } 60 61 literalTable = null; 63 literalsCount = 0; 64 } 65 66 Object [] valueStack = new Object [20]; 67 Type[] typeStack = new Type[20]; 68 int stackPointer; 69 70 void push(Object value, Type type) 71 { 72 if (stackPointer >= valueStack.length) 73 { 74 Object [] newValues = new Object [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 msg) 87 { 88 throw new Error (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 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 (v), Type.boolean_type); 122 } 123 124 public void writeChar(int v) 125 { 126 push(new Character ((char) v), Type.char_type); 127 } 128 129 public void writeByte(int v) 130 { 131 push(new Byte ((byte) v), Type.byte_type); 132 } 133 134 public void writeShort(int v) 135 { 136 push(new Short ((short) v), Type.short_type); 137 } 138 139 public void writeInt(int v) 140 { 141 push(new Integer (v), Type.int_type); 142 } 143 144 public void writeLong(long v) 145 { 146 push(new Long (v), Type.long_type); 147 } 148 149 public void writeFloat(float v) 150 { 151 push(new Float (v), Type.float_type); 152 } 153 154 public void writeDouble(double v) 155 { 156 push(new Double (v), Type.double_type); 157 } 158 159 public void writeUTF(String v) 160 { 161 push(v, Type.string_type); 162 } 163 164 public void writeChars(String v) 165 { 166 push(v, Type.string_type); 167 } 168 169 public void writeObject(Object obj) throws IOException 170 { 171 Literal lit = findLiteral(obj); 172 173 178 180 181 if ((lit.flags & (Literal.WRITTEN|Literal.WRITING)) != 0) 182 { 183 if (lit.field == null 186 && obj != null && ! (obj instanceof String )) 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 { 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 []) 205 { 206 Object [] arr = (Object []) 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 || lit.type instanceof ArrayType) 214 { 215 } 217 else if (obj instanceof java.math.BigInteger ) 218 { 219 writeChars(obj.toString()); 220 } 221 else if (obj instanceof java.math.BigDecimal ) 222 { 223 java.math.BigDecimal dec = (java.math.BigDecimal ) obj; 224 225 writeObject(dec.unscaledValue()); 226 writeInt(dec.scale()); 227 228 230 } 231 else if (obj instanceof Integer ) 232 push(obj, Type.int_type); 233 else if (obj instanceof Short ) 234 push(obj, Type.short_type); 235 else if (obj instanceof Byte ) 236 push(obj, Type.byte_type); 237 else if (obj instanceof Long ) 238 push(obj, Type.long_type); 239 else if (obj instanceof Double ) 240 push(obj, Type.double_type); 241 else if (obj instanceof Float ) 242 push(obj, Type.float_type); 243 else if (obj instanceof Character ) 244 push(obj, Type.char_type); 245 else if (obj instanceof Class ) 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 [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 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 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 int needed_mod = Access.STATIC | Access.FINAL | Access.PUBLIC; 288 Class fldClass = valueClass; 289 ClassType fldType = (ClassType) valueType; 290 while (staticTable.get(fldClass) == null) 291 { 292 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 rfld = fld.getReflectField(); 302 Object 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 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 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 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 369 boolean not1 = false; 371 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; } 398 if (iarg == argLength || iparam == mParameters.length) 399 continue methodLoop; Type aType = argTypes[iarg]; 401 Type pType = mParameters[iparam]; 402 if (aType.isSubtype(pType)) 403 ; else if (pType instanceof ArrayType && iparam < 64 405 && (aType == Type.int_type || aType == Type.short_type)) 406 { 407 int count = ((Number ) literal.argValues[iarg]).intValue(); 408 if (count < 0 && type.getName().equals("gnu.math.IntNum")) 409 count -= 0x80000000; Type elementType = ((ArrayType) pType).getComponentType(); 411 if (count < 0 || iarg + count >= argLength) 412 continue methodLoop; 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; } 423 iarg += count; 424 arrayArgs |= 1 << iparam; 425 } 426 } 427 else 428 { 429 continue methodLoop; } 431 } 432 } 433 if (ambiguous) 434 return null; 435 if (bestArrayArgs != 0) 436 { 437 Object [] args = new Object [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 ) literal.argValues[iarg]).intValue(); 453 boolean isIntNum = type.getName().equals("gnu.math.IntNum"); 454 if (isIntNum) 455 count -= 0x80000000; Type elementType = ((ArrayType) pType).getComponentType(); 457 types[iparam] = pType; 458 args[iparam] = Array.newInstance(elementType.getReflectClass(), 459 count); 460 Object [] argValues = literal.argValues; 461 if (isIntNum) 462 { 463 int[] arr = (int[]) args[iparam]; 467 for (int j = count; j > 0; j--) 468 arr[count - j] 469 = ((Integer ) 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 []) 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 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 ) 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 []) 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 ) 556 { 557 comp.loadClassRef(((Class ) literal.value).getName()); 558 store(literal, ignore, code); 559 } 560 else if (literal.value instanceof ClassType 561 && ! ((ClassType) literal.value).isExisting()) 562 { 563 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 method = getMethod(type, "make", literal, true); 581 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 } 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 |