1 package gov.nasa.jpf.jvm; 20 21 import gov.nasa.jpf.Config; 22 import gov.nasa.jpf.JPFException; 23 import gov.nasa.jpf.jvm.bytecode.Instruction; 24 import gov.nasa.jpf.util.Debug; 25 26 import java.lang.reflect.*; 27 28 import java.util.HashMap ; 29 import java.util.Map ; 30 31 32 38 public class NativePeer { 39 static ClassLoader loader; 40 static HashMap peers; 41 static final String COND_EXEC_PREFIX = "$isExecutable_"; 42 static final String COND_DETERM_PREFIX = "$isDeterministic_"; 43 static final int MAX = 6; 44 static Object [][] argCache; 45 46 ClassInfo ci; 47 Class peerClass; 48 HashMap methods; 49 50 public static void init (Config config) { 51 loader = ClassLoader.getSystemClassLoader(); 55 peers = new HashMap (); 56 57 argCache = new Object [MAX][]; 58 59 for (int i = 0; i < MAX; i++) { 60 argCache[i] = new Object [i]; 61 } 62 } 63 64 NativePeer () { 65 } 67 68 NativePeer (Class peerClass, ClassInfo ci) { 69 initialize(peerClass, ci, true); 70 } 71 72 79 static NativePeer getNativePeer (ClassInfo ci) { 80 String clsName = ci.getName(); 81 NativePeer peer = (NativePeer) peers.get(clsName); 82 Class peerCls = null; 83 String pcn = null; 84 85 if (peer == null) { 86 try { 90 pcn = getSystemPeerClassName(clsName); 91 peerCls = loader.loadClass(pcn); 92 } catch (Throwable x) { 93 try { 94 pcn = getUserPeerClassName(clsName); 95 peerCls = loader.loadClass(pcn); 96 } catch (Throwable xx) { 97 try { 98 pcn = getGlobalPeerClassName(clsName); 99 peerCls = loader.loadClass(pcn); 100 } catch (Throwable xxx) { 101 } 105 } 106 } 107 108 if (peerCls != null) { 109 try { 110 String dcn = getPeerDispatcherClassName(peerCls.getName()); 111 Class dispatcherClass = loader.loadClass(dcn); 112 113 Debug.print(Debug.DEBUG, "load peer dispatcher: "); 114 Debug.println(Debug.DEBUG, dcn); 115 116 peer = (NativePeer) dispatcherClass.newInstance(); 117 peer.initialize(peerCls, ci, false); 118 } catch (Throwable xxxx) { 119 if (!(xxxx instanceof ClassNotFoundException )) { 120 System.err.println("error loading dispatcher: " + xxxx); 122 } 123 124 Debug.print(Debug.DEBUG, "load peer: "); 125 Debug.println(Debug.DEBUG, pcn); 126 127 peer = new NativePeer(peerCls, ci); 128 } 129 130 if (peer != null) { 131 peers.put(clsName, peer); 132 } 133 } 134 } 135 136 return peer; 137 } 138 139 static String getPeerDispatcherClassName (String clsName) { 140 return (clsName + '$'); 141 } 142 143 147 static String getSystemPeerClassName (String clsName) { 148 return "gov.nasa.jpf.jvm.JPF_" + clsName.replace('.', '_'); 150 } 151 152 159 static String getUserPeerClassName (String clsName) { 160 int i = clsName.lastIndexOf('.'); 161 String pkg = clsName.substring(0, i+1); 162 163 return (pkg + "JPF_" + clsName.replace('.', '_')); 164 } 165 166 174 static String getGlobalPeerClassName (String clsName) { 175 return "JPF_" + clsName.replace('.', '_'); 176 } 177 178 boolean isMethodCondDeterministic (ThreadInfo ti, MethodInfo mi) { 179 Boolean ret = Boolean.FALSE; 180 Object [] args = null; 181 Method mth; 182 MJIEnv env = ti.getMJIEnv(); 183 184 env.setCallEnvironment(mi); 185 186 if ((mth = getDetermCondMethod(mi)) == null) { 187 throw new JPFException("no isDeterministic() condition: " + 190 mi.getName()); 191 } 192 193 try { 194 args = getArguments(env, ti, mi, mth); 195 ret = (Boolean ) mth.invoke(peerClass, args); 196 197 } catch (Throwable x) { 199 x.printStackTrace(); 201 } 202 203 return ret.booleanValue(); 204 } 205 206 boolean isMethodCondExecutable (ThreadInfo ti, MethodInfo mi) { 207 Boolean ret = Boolean.FALSE; 208 Object [] args = null; 209 Method mth; 210 MJIEnv env = ti.getMJIEnv(); 211 212 env.setCallEnvironment(mi); 213 214 if ((mth = getExecCondMethod(mi)) == null) { 215 throw new JPFException("no isExecutable() condition: " + 218 mi.getName()); 219 } 220 221 try { 222 args = getArguments(env, ti, mi, mth); 223 ret = (Boolean ) mth.invoke(peerClass, args); 224 225 } catch (Throwable x) { 227 x.printStackTrace(); 229 } 230 231 return ret.booleanValue(); 232 } 233 234 boolean isMethodDeterministic (Method m) { 235 return ((m.getModifiers() & Modifier.FINAL) == 0); 243 } 244 245 Instruction executeMethod (ThreadInfo ti, MethodInfo mi) { 246 Object ret = null; 247 Object [] args = null; 248 Method mth; 249 String exception; 250 MJIEnv env = ti.getMJIEnv(); 251 ElementInfo ei = null; 252 253 env.setCallEnvironment(mi); 254 255 if ((mth = getMethod(mi)) == null) { 256 return ti.createAndThrowException("java.lang.UnsatisfiedLinkError", 257 "cannot find native " + ci.getName() + '.' + 258 mi.getName()); 259 } 260 261 try { 262 args = getArguments(env, ti, mi, mth); 263 264 if (mi.isSynchronized()){ 267 ei = env.getElementInfo(((Integer )args[1]).intValue()); 268 ei.lock(ti); 269 } 270 271 ret = mth.invoke(peerClass, args); 272 273 if ((exception = env.getException()) != null) { 275 String details = env.getExceptionDetails(); 276 277 return ti.createAndThrowException(exception, details); 283 } 284 285 if (env.getRepeat()) { 286 return ti.getPC(); 288 } 289 290 ti.removeArguments(mi); 294 295 pushReturnValue(ti, mi, ret); 296 } catch (IllegalArgumentException iax) { 297 System.out.println(iax); 298 return ti.createAndThrowException("java.lang.IllegalArgumentException", 299 "calling " + ci.getName() + '.' + 300 mi.getName()); 301 } catch (IllegalAccessException ilax) { 302 return ti.createAndThrowException("java.lang.IllegalAccessException", 303 "calling " + ci.getName() + '.' + 304 mi.getName()); 305 } catch (InvocationTargetException itx) { 306 return ti.createAndThrowException( 309 "java.lang.reflect.InvocationTargetException", 310 "in " + ci.getName() + '.' + mi.getName() + " : " + itx.getCause()); 311 } finally { 312 if (mi.isSynchronized() && ei.isLocked()){ 316 ei.unlock(ti); 317 } 318 319 env.clearCallEnvironment(); 321 } 322 323 Instruction pc = ti.getPC(); 324 325 if (pc == null) { 330 return null; 331 } 332 333 return pc.getNext(); 335 } 336 337 void initialize (Class peerClass, ClassInfo ci, boolean cacheMethods) { 338 if ((this.ci != null) || (this.peerClass != null)) { 339 throw new RuntimeException ("cannot re-initialize NativePeer: " + 340 peerClass.getName()); 341 } 342 343 this.ci = ci; 344 this.peerClass = peerClass; 345 346 loadMethods(cacheMethods); 347 } 348 349 private static boolean isMJICandidate (Method mth) { 350 return ((mth.getModifiers() & (Modifier.PUBLIC | Modifier.STATIC)) == (Modifier.PUBLIC | Modifier.STATIC)); 352 } 353 354 private Object [] getArgArray (int n) { 355 if (n < MAX) { 360 return argCache[n]; 361 } else { 362 return new Object [n]; 363 } 364 } 365 366 371 private Object [] getArguments (MJIEnv env, ThreadInfo ti, MethodInfo mi, 372 Method mth) { 373 int nArgs = mi.getNumberOfArguments(); 374 Object [] a = getArgArray(nArgs + 2); 375 byte[] argTypes = mi.getArgumentTypes(); 376 int stackOffset; 377 int i; 378 int j; 379 int k; 380 int ival; 381 long lval; 382 383 for (i = 0, stackOffset = 0, j = nArgs + 1, k = nArgs - 1; 384 i < nArgs; 385 i++, j--, k--) { 386 switch (argTypes[k]) { 387 case Types.T_BOOLEAN: 388 ival = ti.peek(stackOffset); 389 a[j] = new Boolean (Types.intToBoolean(ival)); 390 391 break; 392 393 case Types.T_BYTE: 394 ival = ti.peek(stackOffset); 395 a[j] = new Byte ((byte) ival); 396 397 break; 398 399 case Types.T_CHAR: 400 ival = ti.peek(stackOffset); 401 a[j] = new Character ((char) ival); 402 403 break; 404 405 case Types.T_SHORT: 406 ival = ti.peek(stackOffset); 407 a[j] = new Short ((short) ival); 408 409 break; 410 411 case Types.T_INT: 412 ival = ti.peek(stackOffset); 413 a[j] = new Integer (ival); 414 415 break; 416 417 case Types.T_LONG: 418 lval = ti.longPeek(stackOffset); 419 stackOffset++; a[j] = new Long (lval); 421 422 break; 423 424 case Types.T_FLOAT: 425 ival = ti.peek(stackOffset); 426 a[j] = new Float (Types.intToFloat(ival)); 427 428 break; 429 430 case Types.T_DOUBLE: 431 lval = ti.longPeek(stackOffset); 432 stackOffset++; a[j] = new Double (Types.longToDouble(lval)); 434 435 break; 436 437 default: 438 ival = ti.peek(stackOffset); 439 a[j] = new Integer (ival); 440 } 441 442 stackOffset++; 443 } 444 445 if (mi.isStatic()) { 446 a[1] = new Integer (ci.getClassObjectRef()); 447 } else { 448 a[1] = new Integer (ti.getCalleeThis(mi)); 449 } 450 451 a[0] = env; 452 453 return a; 454 } 455 456 private Method getDetermCondMethod (MethodInfo mi) { 457 return getMethod(COND_DETERM_PREFIX, mi); 458 } 459 460 private Method getExecCondMethod (MethodInfo mi) { 461 return getMethod(COND_EXEC_PREFIX, mi); 462 } 463 464 private void setMJIAttributes (MethodInfo mi, boolean isDeterministic, 465 boolean isCondDeterministic, 466 boolean isCondExecutable) { 467 mi.setMJI(true); 468 469 if (!isDeterministic) { 471 mi.setDeterministic(isDeterministic); 472 } 473 474 if (isCondDeterministic) { 475 mi.setCondDeterministic(isCondDeterministic); 476 } 477 478 if (isCondExecutable) { 479 mi.setCondExecutable(isCondExecutable); 480 } 481 } 482 483 private Method getMethod (MethodInfo mi) { 484 return getMethod(null, mi); 485 } 486 487 private Method getMethod (String prefix, MethodInfo mi) { 488 String name = mi.getUniqueName(); 489 490 if (prefix != null) { 491 name = prefix + name; 492 } 493 494 return (Method) methods.get(name); 495 } 496 497 502 private void loadMethods (boolean cacheMethods) { 503 Method[] m = peerClass.getDeclaredMethods(); 504 methods = new HashMap (m.length); 505 506 Map methodInfos = ci.getDeclaredMethods(); 507 MethodInfo[] mis = null; 508 509 for (int i = 0; i < m.length; i++) { 510 boolean isDeterministic = true; 511 boolean isCondDeterministic = false; 512 boolean isCondExecutable = false; 513 String prefix = ""; 514 Method mth = m[i]; 515 516 if (isMJICandidate(mth)) { 517 String mn = mth.getName(); 522 523 if (mn.equals("$clinit")) { 526 mn = "<clinit>"; 527 } else if (mn.startsWith("$init")) { 528 mn = "<init>" + mn.substring(5); 529 } 530 531 if (mn.startsWith(COND_DETERM_PREFIX)) { 533 prefix = COND_DETERM_PREFIX; 534 mn = mn.substring(17); 535 isCondDeterministic = true; 536 } else if (mn.startsWith(COND_EXEC_PREFIX)) { 537 prefix = COND_EXEC_PREFIX; 538 mn = mn.substring(14); 539 isCondExecutable = true; 540 } else { isDeterministic = isMethodDeterministic(mth); 542 } 543 544 String mname = Types.getJNIMethodName(mn); 545 String argSig = Types.getJNIArgSignature(mn); 546 547 if (argSig != null) { 548 mname += argSig; 549 } 550 551 MethodInfo mi = (MethodInfo) methodInfos.get(mname); 558 559 if ((mi == null) && (argSig == null)) { 560 if (mis == null) { mis = new MethodInfo[methodInfos.size()]; 565 methodInfos.values().toArray(mis); 566 } 567 568 mi = searchMethod(mname, mis); 569 } 570 571 if (mi != null) { 572 Debug.print(Debug.DEBUG, " load MJI method: "); 573 Debug.print(Debug.DEBUG, prefix); 574 Debug.println(Debug.DEBUG, mname); 575 576 setMJIAttributes(mi, isDeterministic, isCondDeterministic, 577 isCondExecutable); 578 579 if (cacheMethods) { 580 if (isCondDeterministic || isCondExecutable) { 581 methods.put(prefix + mi.getUniqueName(), mth); 583 } else { 584 methods.put(mi.getUniqueName(), mth); } 587 } else { 588 } 590 } else { 591 Debug.println(Debug.WARNING, "orphant NativePeer method: " + ci.getName() + '.' + mn); 595 } 596 } 597 } 598 } 599 600 private static MethodInfo searchMethod (String mname, MethodInfo[] methods) { 601 for (int j = 0; j < methods.length; j++) { 602 if (methods[j].getName().equals(mname)) { 603 return methods[j]; 610 } 611 } 612 613 return null; 614 } 615 616 private void pushReturnValue (ThreadInfo ti, MethodInfo mi, Object ret) { 617 int ival; 618 long lval; 619 620 if (ret != null) { 624 switch (mi.getReturnType()) { 625 case Types.T_BOOLEAN: 626 ival = Types.booleanToInt(((Boolean ) ret).booleanValue()); 627 ti.push(ival, false); 628 629 break; 630 631 case Types.T_BYTE: 632 ti.push(((Byte ) ret).byteValue(), false); 633 634 break; 635 636 case Types.T_CHAR: 637 ti.push(((Character ) ret).charValue(), false); 638 639 break; 640 641 case Types.T_SHORT: 642 ti.push(((Short ) ret).shortValue(), false); 643 644 break; 645 646 case Types.T_INT: 647 ti.push(((Integer ) ret).intValue(), false); 648 649 break; 650 651 case Types.T_LONG: 652 ti.longPush(((Long ) ret).longValue()); 653 654 break; 655 656 case Types.T_FLOAT: 657 ival = Types.floatToInt(((Float ) ret).floatValue()); 658 ti.push(ival, false); 659 660 break; 661 662 case Types.T_DOUBLE: 663 lval = Types.doubleToLong(((Double ) ret).doubleValue()); 664 ti.longPush(lval); 665 666 break; 667 668 default: 669 670 ti.push(((Integer ) ret).intValue(), true); 672 } 673 } 674 } 675 } 676 677 | Popular Tags |