1 16 package org.apache.cocoon.components.flow.java; 17 18 import java.util.ArrayList ; 19 import java.util.Vector ; 20 21 import org.apache.bcel.Constants; 22 import org.apache.bcel.Repository; 23 import org.apache.bcel.classfile.ConstantCP; 24 import org.apache.bcel.classfile.ConstantNameAndType; 25 import org.apache.bcel.classfile.ConstantPool; 26 import org.apache.bcel.classfile.ConstantUtf8; 27 import org.apache.bcel.classfile.JavaClass; 28 import org.apache.bcel.classfile.Method; 29 import org.apache.bcel.generic.ACONST_NULL; 30 import org.apache.bcel.generic.BasicType; 31 import org.apache.bcel.generic.ClassGen; 32 import org.apache.bcel.generic.ConstantPoolGen; 33 import org.apache.bcel.generic.GOTO; 34 import org.apache.bcel.generic.IFEQ; 35 import org.apache.bcel.generic.IFNONNULL; 36 import org.apache.bcel.generic.IFNULL; 37 import org.apache.bcel.generic.INVOKESTATIC; 38 import org.apache.bcel.generic.InstructionConstants; 39 import org.apache.bcel.generic.InstructionFactory; 40 import org.apache.bcel.generic.InstructionHandle; 41 import org.apache.bcel.generic.InstructionList; 42 import org.apache.bcel.generic.InstructionTargeter; 43 import org.apache.bcel.generic.InvokeInstruction; 44 import org.apache.bcel.generic.MethodGen; 45 import org.apache.bcel.generic.ObjectType; 46 import org.apache.bcel.generic.PUSH; 47 import org.apache.bcel.generic.RET; 48 import org.apache.bcel.generic.ReferenceType; 49 import org.apache.bcel.generic.ReturnaddressType; 50 import org.apache.bcel.generic.SWAP; 51 import org.apache.bcel.generic.TABLESWITCH; 52 import org.apache.bcel.generic.TargetLostException; 53 import org.apache.bcel.generic.Type; 54 import org.apache.bcel.util.ClassLoaderRepository; 55 import org.apache.bcel.verifier.exc.AssertionViolatedException; 56 import org.apache.bcel.verifier.structurals.ControlFlowGraph; 57 import org.apache.bcel.verifier.structurals.ExceptionHandler; 58 import org.apache.bcel.verifier.structurals.ExecutionVisitor; 59 import org.apache.bcel.verifier.structurals.Frame; 60 import org.apache.bcel.verifier.structurals.InstConstraintVisitor; 61 import org.apache.bcel.verifier.structurals.InstructionContext; 62 import org.apache.bcel.verifier.structurals.LocalVariables; 63 import org.apache.bcel.verifier.structurals.OperandStack; 64 import org.apache.bcel.verifier.structurals.UninitializedObjectType; 65 66 77 public class ContinuationClassLoader extends ClassLoader { 78 79 private static final String CONTINUATION_CLASS = Continuation.class.getName(); 80 private static final ObjectType CONTINUATION_TYPE = new ObjectType(CONTINUATION_CLASS); 81 82 private static final String STACK_CLASS = ContinuationStack.class.getName(); 83 private static final ObjectType STACK_TYPE = new ObjectType(STACK_CLASS); 84 85 private static final String CONTINUABLE_CLASS = Continuable.class.getName(); 86 87 private static final String CONTINUATIONCAPABLE_CLASS = ContinuationCapable.class.getName(); 88 89 private static final String CONTINUATION_METHOD = "currentContinuation"; 90 private static final String STACK_METHOD = "getStack"; 91 private static final String POP_METHOD = "pop"; 92 private static final String PUSH_METHOD = "push"; 93 private static final String RESTORING_METHOD = "isRestoring"; 94 private static final String CAPURING_METHOD = "isCapturing"; 95 96 private static boolean currentMethodStatic; 97 98 public ContinuationClassLoader(ClassLoader parent) { 99 super(parent); 100 Repository.setRepository(new ClassLoaderRepository(parent)); 101 } 102 103 protected synchronized Class loadClass(String name, boolean resolve) 104 throws ClassNotFoundException { 105 Class c = super.loadClass(name, resolve); 107 108 if ((Continuable.class.isAssignableFrom(c)) && 110 (!ContinuationCapable.class.isAssignableFrom(c)) && 111 (!c.isInterface())) { 112 JavaClass clazz = Repository.lookupClass(c); 113 114 byte data[] = transform(clazz); 115 c = defineClass(name, data, 0, data.length); 116 } 117 if (c == null) { 118 throw new ClassNotFoundException (name); 119 } 120 if (resolve) { 121 resolveClass(c); 122 } 123 return c; 124 } 125 126 private byte[] transform(JavaClass javaclazz) throws ClassNotFoundException { 127 ClassGen clazz = new ClassGen(javaclazz); 129 ConstantPoolGen cp = clazz.getConstantPool(); 130 InstConstraintVisitor icv = new InstConstraintVisitor(); 132 icv.setConstantPoolGen(cp); 133 ExecutionVisitor ev = new ExecutionVisitor(); 135 ev.setConstantPoolGen(cp); 136 137 Method[] methods = clazz.getMethods(); 138 for (int i = 0; i < methods.length; i++) { 139 MethodGen method = new MethodGen(methods[i], clazz.getClassName(), cp); 140 141 currentMethodStatic = methods[i].isStatic(); 142 if (isValid(method)) { 143 ControlFlowGraph cfg = new ControlFlowGraph(method); 146 analyse(clazz, method, cfg, icv, ev); 147 rewrite(method, cfg); 149 clazz.replaceMethod(methods[i], method.getMethod()); 151 } 152 } 153 clazz.addInterface(CONTINUATIONCAPABLE_CLASS); 154 return clazz.getJavaClass().getBytes(); 155 } 156 157 private boolean isValid(MethodGen m) { 158 if (m.getName().equals(Constants.CONSTRUCTOR_NAME) 159 || m.getName().equals(Constants.STATIC_INITIALIZER_NAME) 160 || m.isNative() 161 || m.isAbstract()) { 162 return false; 163 } else { 164 return true; 165 } 166 } 167 168 private void analyse(ClassGen clazz, MethodGen method, ControlFlowGraph cfg, 169 InstConstraintVisitor icv, ExecutionVisitor ev) { 170 Frame vanillaFrame = new Frame(method.getMaxLocals(), method.getMaxStack()); 172 if (!method.isStatic()) { 173 if (method.getName().equals(Constants.CONSTRUCTOR_NAME)) { 174 Frame._this = new UninitializedObjectType(new ObjectType(clazz.getClassName())); 175 vanillaFrame.getLocals().set(0, new UninitializedObjectType(new ObjectType(clazz.getClassName()))); 176 } else { 177 Frame._this = null; 178 vanillaFrame.getLocals().set(0, new ObjectType(clazz.getClassName())); 179 } 180 } 181 Type[] argtypes = method.getArgumentTypes(); 183 int twoslotoffset = 0; 184 for (int j = 0; j < argtypes.length; j++) { 185 if ((argtypes[j] == Type.SHORT) || 186 (argtypes[j] == Type.BYTE) || 187 (argtypes[j] == Type.CHAR) || 188 (argtypes[j] == Type.BOOLEAN)) { 189 argtypes[j] = Type.INT; 190 } 191 vanillaFrame.getLocals().set(twoslotoffset + j + (method.isStatic() ? 0 : 1), argtypes[j]); 192 if (argtypes[j].getSize() == 2) { 193 twoslotoffset++; 194 vanillaFrame.getLocals().set(twoslotoffset + j + (method.isStatic() ? 0 : 1), Type.UNKNOWN); 195 } 196 } 197 icv.setMethodGen(method); 198 199 Vector ics = new Vector (); Vector ecs = new Vector (); 202 InstructionContext start = cfg.contextOf(method.getInstructionList().getStart()); 203 204 start.execute(vanillaFrame, new ArrayList (), icv, ev); 205 ics.add(start); 208 ecs.add(new ArrayList ()); 209 210 while (!ics.isEmpty()) { 211 InstructionContext u = (InstructionContext)ics.remove(0); 212 ArrayList ec = (ArrayList )ecs.remove(0); 213 214 ArrayList oldchain = (ArrayList )(ec.clone()); 215 ArrayList newchain = (ArrayList )(ec.clone()); 216 newchain.add(u); 217 218 if ((u.getInstruction().getInstruction()) instanceof RET) { 219 RET ret = (RET)u.getInstruction().getInstruction(); 222 ReturnaddressType t = (ReturnaddressType)u.getOutFrame(oldchain).getLocals().get(ret.getIndex()); 223 InstructionContext theSuccessor = cfg.contextOf(t.getTarget()); 224 225 if (theSuccessor.execute(u.getOutFrame(oldchain), newchain, icv, ev)) { 226 ics.add(theSuccessor); 227 ecs.add(newchain.clone()); 228 } 229 } else { InstructionContext[] succs = u.getSuccessors(); 232 for (int s = 0; s < succs.length; s++) { 233 InstructionContext v = succs[s]; 234 if (v.execute(u.getOutFrame(oldchain), newchain, icv, ev)) { 235 ics.add(v); 236 ecs.add(newchain.clone()); 237 } 238 } 239 } 240 ExceptionHandler[] exc_hds = u.getExceptionHandlers(); 242 for (int s = 0; s < exc_hds.length; s++) { 243 InstructionContext v = cfg.contextOf(exc_hds[s].getHandlerStart()); 244 249 LocalVariables newLocals = u.getOutFrame(oldchain).getLocals(); 250 OperandStack newStack = new OperandStack( 251 u.getOutFrame(oldchain).getStack().maxStack(), 252 (exc_hds[s].getExceptionType() == null 253 ? Type.THROWABLE 254 : exc_hds[s].getExceptionType())); 255 Frame newFrame = new Frame(newLocals, newStack); 256 257 if (v.execute(newFrame, new ArrayList (), icv, ev)) { 258 ics.add(v); 259 ecs.add(new ArrayList ()); 260 } 261 } 262 } 263 } 264 265 private void rewrite(MethodGen method, ControlFlowGraph cfg) 266 throws ClassNotFoundException { 267 InstructionFactory insFactory = new InstructionFactory(method.getConstantPool()); 268 Vector invokeIns = new Vector (); 269 int count = 0; 270 InstructionList insList = method.getInstructionList(); 271 InstructionHandle ins = insList.getStart(); 272 InstructionList restorer = new InstructionList(); 273 while (ins != null) { 274 InstructionHandle next = ins.getNext(); 275 276 InstructionContext context = null; 278 Frame frame = null; 279 try { 280 context = cfg.contextOf(ins); 281 frame = context.getOutFrame(new ArrayList ()); 282 } catch (AssertionViolatedException ave) { 283 } 285 if (frame != null) { 286 if (rewriteable(method, ins)) { 287 289 InvokeInstruction invoke = (InvokeInstruction)ins.getInstruction(); 291 Type[] arguments = invoke.getArgumentTypes(method.getConstantPool()); 292 ObjectType objecttype = null; 293 if (!(invoke instanceof INVOKESTATIC)) { 294 objecttype = (ObjectType)context.getInFrame().getStack().peek(arguments.length); 295 } 296 InstructionList rList = restoreFrame(method, ins, insFactory, frame, objecttype); 297 insList.append(ins, saveFrame(method, ins, count++, insFactory, frame)); 298 invokeIns.addElement(rList.getStart()); 299 restorer.append(rList); 300 } 301 if (ins.getInstruction().getOpcode() == Constants.NEW) { 303 try { 304 while (next != null && next.getInstruction().getOpcode() == Constants.DUP) { 306 context = cfg.contextOf(next); 307 frame = context.getOutFrame(new ArrayList ()); 308 InstructionHandle newnext = next.getNext(); 309 insList.delete(next); 310 next = newnext; 311 } 312 InstructionTargeter[] targeter = ins.getTargeters(); 313 if (targeter != null) { 314 InstructionHandle newnext = ins.getNext(); 315 for (int i = 0; i < targeter.length; i++) { 316 targeter[i].updateTarget(ins, newnext); 317 } 318 } 319 insList.delete(ins); 320 } catch (TargetLostException tle) { 321 throw new ClassNotFoundException (tle.getMessage(), tle); 322 } 323 } else if (ins.getInstruction().getOpcode() == Constants.INVOKESPECIAL) { 324 frame = context.getInFrame(); 326 InvokeInstruction invoke = (InvokeInstruction)ins.getInstruction(); 327 Type[] arguments = invoke.getArgumentTypes(method.getConstantPool()); 328 329 OperandStack os = frame.getStack(); 330 Type type = os.peek(arguments.length); 331 if (type instanceof UninitializedObjectType) { 332 ObjectType objecttype = ((UninitializedObjectType) type).getInitialized(); 333 InstructionList duplicator = duplicateStack(method, invoke, objecttype); 334 InstructionTargeter[] targeter = ins.getTargeters(); 335 336 if (targeter!=null) { 337 InstructionHandle newnext = duplicator.getStart(); 338 for(int i=0; i < targeter.length; i++) { 339 targeter[i].updateTarget(ins, newnext); 340 } 341 } 342 insList.insert(ins, duplicator); 343 } 344 } 345 } 346 ins = next; 347 } 348 InstructionHandle firstIns = insList.getStart(); 349 if (count > 0) { 350 InstructionHandle[] tableTargets = new InstructionHandle[count]; 351 int[] match = new int[count]; 352 for (int i = 0; i < count; i++) { 353 match[i] = i; 354 } 355 invokeIns.copyInto(tableTargets); 356 insList.insert(restorer); 357 358 insList.insert(new TABLESWITCH(match, tableTargets, firstIns)); 360 insList.insert(insFactory.createInvoke(STACK_CLASS, getPopMethod(Type.INT), Type.INT, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 361 insList.insert(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 362 363 insList.insert(new IFEQ(firstIns)); 365 insList.insert(insFactory.createInvoke(CONTINUATION_CLASS, RESTORING_METHOD, Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 366 insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, method.getMaxLocals())); 367 } 368 369 insList.insert(InstructionFactory.createStore(STACK_TYPE, method.getMaxLocals()+1)); 371 insList.insert(insFactory.createInvoke(CONTINUATION_CLASS, STACK_METHOD, STACK_TYPE, 372 Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 373 InstructionHandle restore_handle = insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, method.getMaxLocals())); 374 375 insList.insert(new GOTO(firstIns)); 377 insList.insert(InstructionFactory.createStore(STACK_TYPE, method.getMaxLocals()+1)); 378 insList.insert(insFactory.createInvoke(STACK_CLASS, Constants.CONSTRUCTOR_NAME, Type.VOID, Type.NO_ARGS, Constants. INVOKESPECIAL)); 379 insList.insert(InstructionFactory.createDup(STACK_TYPE.getSize())); 380 insList.insert(insFactory.createNew(STACK_TYPE)); 381 382 insList.insert(new IFNONNULL(restore_handle)); 384 insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, method.getMaxLocals())); 385 386 insList.insert(InstructionFactory.createStore(CONTINUATION_TYPE, method.getMaxLocals())); 388 insList.insert(insFactory.createInvoke(CONTINUATION_CLASS, CONTINUATION_METHOD, CONTINUATION_TYPE, 389 Type.NO_ARGS, Constants.INVOKESTATIC)); 390 391 method.setMaxLocals(method.getMaxLocals() + 2); 393 method.setMaxStack(method.getMaxStack() + 2); 394 } 395 396 private InstructionList duplicateStack(MethodGen method, InvokeInstruction invoke, 397 ObjectType objecttype) throws ClassNotFoundException { 398 InstructionFactory insFactory = new InstructionFactory(method.getConstantPool()); 400 InstructionList insList = new InstructionList(); 401 402 Type[] arguments = invoke.getArgumentTypes(method.getConstantPool()); 403 for (int i = arguments.length - 1; i >= 0; i--) { 405 Type type = arguments[i]; 406 insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 407 insList.append(new SWAP()); 408 if (type instanceof BasicType) { 409 if (type.getSize() < 2 && !type.equals(Type.FLOAT)) { 410 type = Type.INT; 411 } 412 insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(type), Type.VOID, new Type[]{type}, Constants.INVOKEVIRTUAL)); 413 } else if (type instanceof ReferenceType) { 414 insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(Type.OBJECT), Type.VOID, new Type[]{Type.OBJECT}, Constants.INVOKEVIRTUAL)); 415 } 416 } 417 insList.append(insFactory.createNew(objecttype)); 419 insList.append(InstructionFactory.createDup(objecttype.getSize())); 420 for (int i = 0; i < arguments.length; i++) { 422 Type type = arguments[i]; 423 insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 424 if (type instanceof BasicType) { 425 if (type.getSize() < 2 && !type.equals(Type.FLOAT)) { 426 type = Type.INT; 427 } 428 insList.append(insFactory.createInvoke(STACK_CLASS, getPopMethod(type), type, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 429 } else if (type instanceof ReferenceType) { 430 insList.append(insFactory.createInvoke(STACK_CLASS, getPopMethod(Type.OBJECT), Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 431 if (!type.equals(Type.OBJECT)) { 432 insList.append(insFactory.createCast(Type.OBJECT, type)); 433 } 434 } 435 } 436 return insList; 437 } 438 439 private boolean rewriteable(MethodGen method, InstructionHandle handle) 440 throws ClassNotFoundException { 441 int opcode = handle.getInstruction().getOpcode(); 443 boolean invokeSpecialSuper = false; 444 if (opcode == Constants.INVOKESPECIAL) { 445 InvokeInstruction ivs = (InvokeInstruction) handle.getInstruction(); 446 String mName = ivs.getMethodName(method.getConstantPool()); 447 invokeSpecialSuper = !mName.equals(Constants.CONSTRUCTOR_NAME); 448 } 449 450 if (opcode == Constants.INVOKEVIRTUAL || 451 opcode == Constants.INVOKESTATIC || 452 opcode == Constants.INVOKEINTERFACE || 453 invokeSpecialSuper) { 454 455 int index = ((InvokeInstruction) handle.getInstruction()).getIndex(); 456 String classname = getObjectType(method.getConstantPool().getConstantPool(), index).getClassName(); 457 458 return Repository.implementationOf(classname, CONTINUABLE_CLASS) || 460 Repository.instanceOf(classname, CONTINUATION_CLASS); 461 } 462 return false; 463 } 464 465 private InstructionList saveFrame(MethodGen method, InstructionHandle handle, int pc, 466 InstructionFactory insFactory, Frame frame) { 467 InstructionList insList = new InstructionList(); 468 469 InvokeInstruction inv = (InvokeInstruction) handle.getInstruction(); 471 Type returnType = getReturnType(method.getConstantPool().getConstantPool(), inv.getIndex()); 472 if (returnType.getSize() > 0) { 473 insList.insert(InstructionFactory.createPop(returnType.getSize())); 474 } 475 boolean skipFirst = returnType.getSize() > 0; 476 477 OperandStack os = frame.getStack(); 479 for (int i = skipFirst ? 1 : 0; i < os.size(); i++) { 480 Type type = os.peek(i); 481 if (type instanceof BasicType) { 482 if (type.getSize() < 2 && !type.equals(Type.FLOAT)) { 483 type = Type.INT; 484 } 485 insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 486 insList.append(new SWAP()); insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(type), Type.VOID, new Type[]{type}, Constants.INVOKEVIRTUAL)); 488 } else if (type == null) { 489 insList.append(InstructionConstants.POP); 490 } else if (type instanceof UninitializedObjectType) { 491 } else if (type instanceof ReferenceType) { 494 insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 495 insList.append(new SWAP()); 496 insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(Type.OBJECT), Type.VOID, new Type[]{Type.OBJECT}, Constants.INVOKEVIRTUAL)); 497 } 498 } 499 insList.insert(new IFEQ(handle.getNext())); 501 insList.insert(insFactory.createInvoke(CONTINUATION_CLASS, CAPURING_METHOD, Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 503 insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, method.getMaxLocals())); 504 insList.insert(new IFNULL(handle.getNext())); 506 insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, method.getMaxLocals())); 507 LocalVariables lvs = frame.getLocals(); 509 for (int i = 0; i < lvs.maxLocals(); i++) { 510 Type type = lvs.get(i); 511 if (type instanceof BasicType) { 512 insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 513 insList.append(InstructionFactory.createLoad(type, i)); 514 if (type.getSize() < 2 && !type.equals(Type.FLOAT)) 515 type = Type.INT; 516 insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(type), Type.VOID, new Type[]{type}, Constants.INVOKEVIRTUAL)); 517 } else if (type == null) { 518 } else if (type instanceof UninitializedObjectType) { 520 } else if (type instanceof ReferenceType) { 522 if (i == 0 && !currentMethodStatic) { 523 insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 525 insList.append(InstructionFactory.createLoad(type, i)); 526 insList.append(insFactory.createInvoke(STACK_CLASS, PUSH_METHOD + "Reference", Type.VOID, new Type[]{Type.OBJECT}, Constants.INVOKEVIRTUAL)); 527 } 528 insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 529 insList.append(InstructionFactory.createLoad(type, i)); 530 insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(Type.OBJECT), Type.VOID, new Type[]{Type.OBJECT}, Constants.INVOKEVIRTUAL)); 531 } 532 } 533 insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 535 insList.append(new PUSH(method.getConstantPool(), pc)); 536 insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(Type.INT), Type.VOID, new Type[]{Type.INT}, Constants.INVOKEVIRTUAL)); 537 insList.append(InstructionFactory.createNull(method.getReturnType())); 539 insList.append(InstructionFactory.createReturn(method.getReturnType())); 540 return insList; 541 } 542 543 private InstructionList restoreFrame(MethodGen method, InstructionHandle handle, 544 InstructionFactory insFactory, Frame frame, ObjectType objecttype) { 545 InstructionList insList = new InstructionList(); 546 LocalVariables lvs = frame.getLocals(); 548 for (int i = lvs.maxLocals() - 1; i >= 0; i--) { 549 Type type = lvs.get(i); 550 if (type instanceof BasicType) { 551 insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 552 if (type.getSize() < 2 && !type.equals(Type.FLOAT)) { 553 type = Type.INT; 554 } 555 insList.append(insFactory.createInvoke(STACK_CLASS, getPopMethod(type), type, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 556 insList.append(InstructionFactory.createStore(type, i)); 557 } else if (type == null) { 558 insList.append(new ACONST_NULL()); 559 insList.append(InstructionFactory.createStore(new ObjectType("<null object>"), i)); 560 } else if (type instanceof UninitializedObjectType) { 561 } else if (type instanceof ReferenceType) { 564 insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 565 insList.append(insFactory.createInvoke(STACK_CLASS, getPopMethod(Type.OBJECT), Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 566 if (!type.equals(Type.OBJECT) && (!type.equals(Type.NULL))) { 567 insList.append(insFactory.createCast(Type.OBJECT, type)); 568 } 569 insList.append(InstructionFactory.createStore(type, i)); 570 } 571 } 572 573 InvokeInstruction inv = (InvokeInstruction) handle.getInstruction(); 574 Type returnType = getReturnType(method.getConstantPool().getConstantPool(), inv.getIndex()); 575 boolean skipFirst = returnType.getSize() > 0; 576 577 OperandStack os = frame.getStack(); 579 for (int i = os.size() - 1; i >= (skipFirst ? 1 : 0); i--) { 580 Type type = os.peek(i); 581 if (type instanceof BasicType) { 582 if (type.getSize() < 2 && !type.equals(Type.FLOAT)) { 583 type = Type.INT; 584 } 585 insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 586 insList.append(insFactory.createInvoke(STACK_CLASS, getPopMethod(type), type, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 587 } else if (type == null) { 588 insList.append(new ACONST_NULL()); 589 } else if (type instanceof UninitializedObjectType) { 590 } else if (type instanceof ReferenceType) { 593 insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 594 insList.append(insFactory.createInvoke(STACK_CLASS, getPopMethod(Type.OBJECT), Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 595 if (!type.equals(Type.OBJECT)) 596 insList.append(insFactory.createCast(Type.OBJECT, type)); 597 } 598 } 599 if (!(inv instanceof INVOKESTATIC)) { 601 insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1)); 602 insList.append(insFactory.createInvoke(STACK_CLASS, POP_METHOD + "Reference", Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 603 insList.append(insFactory.createCast(Type.OBJECT, objecttype)); 604 } 605 Type[] paramTypes = getParamTypes(method.getConstantPool().getConstantPool(), inv.getIndex()); 607 for (int j = 0; j < paramTypes.length; j++) { 608 insList.append(InstructionFactory.createNull(paramTypes[j])); 609 } 610 insList.append(new GOTO(handle)); 612 return insList; 613 } 614 615 private ObjectType getObjectType(ConstantPool cp, int index) { 616 ConstantCP cmr = (ConstantCP) cp.getConstant(index); 617 String sig = cp.getConstantString(cmr.getClassIndex(), Constants.CONSTANT_Class); 618 return new ObjectType(sig.replace('/', '.')); 619 } 620 621 private Type[] getParamTypes(ConstantPool cp, int index) { 622 ConstantCP cmr = (ConstantCP) cp.getConstant(index); 623 ConstantNameAndType cnat = (ConstantNameAndType) cp.getConstant(cmr.getNameAndTypeIndex()); 624 String sig = ((ConstantUtf8) cp.getConstant(cnat.getSignatureIndex())).getBytes(); 625 return Type.getArgumentTypes(sig); 626 } 627 628 private Type getReturnType(ConstantPool cp, int index) { 629 ConstantCP cmr = (ConstantCP) cp.getConstant(index); 630 ConstantNameAndType cnat = (ConstantNameAndType) cp.getConstant(cmr.getNameAndTypeIndex()); 631 String sig = ((ConstantUtf8) cp.getConstant(cnat.getSignatureIndex())).getBytes(); 632 return Type.getReturnType(sig); 633 } 634 635 private String getPopMethod(Type type) { 636 return POP_METHOD + getTypeSuffix(type); 637 } 638 639 private String getPushMethod(Type type) { 640 return PUSH_METHOD + getTypeSuffix(type); 641 } 642 643 private String getTypeSuffix(Type type) { 644 if (type.equals(Type.BOOLEAN)) 645 return "Int"; 646 else if (type.equals(Type.CHAR)) 647 return "Int"; 648 else if (type.equals(Type.FLOAT)) 649 return "Float"; 650 else if (type.equals(Type.DOUBLE)) 651 return "Double"; 652 else if (type.equals(Type.BYTE)) 653 return "Int"; 654 else if (type.equals(Type.SHORT)) 655 return "Int"; 656 else if (type.equals(Type.INT)) 657 return "Int"; 658 else if (type.equals(Type.LONG)) 659 return "Long"; 660 return "Object"; 662 } 663 } 664 | Popular Tags |