1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.javaflow.bytecode.transformation.bcel;
18
19 import org.apache.bcel.Constants;
20 import org.apache.bcel.Repository;
21 import org.apache.bcel.classfile.Attribute;
22 import org.apache.bcel.classfile.ClassFormatException;
23 import org.apache.bcel.classfile.ClassParser;
24 import org.apache.bcel.classfile.ConstantCP;
25 import org.apache.bcel.classfile.ConstantNameAndType;
26 import org.apache.bcel.classfile.ConstantPool;
27 import org.apache.bcel.classfile.ConstantUtf8;
28 import org.apache.bcel.classfile.JavaClass;
29 import org.apache.bcel.classfile.Method;
30 import org.apache.bcel.generic.ACONST_NULL;
31 import org.apache.bcel.generic.ASTORE;
32 import org.apache.bcel.generic.BasicType;
33 import org.apache.bcel.generic.ClassGen;
34 import org.apache.bcel.generic.ConstantPoolGen;
35 import org.apache.bcel.generic.GOTO;
36 import org.apache.bcel.generic.IFEQ;
37 import org.apache.bcel.generic.IFNULL;
38 import org.apache.bcel.generic.INVOKESTATIC;
39 import org.apache.bcel.generic.Instruction;
40 import org.apache.bcel.generic.InstructionConstants;
41 import org.apache.bcel.generic.InstructionFactory;
42 import org.apache.bcel.generic.InstructionHandle;
43 import org.apache.bcel.generic.InstructionList;
44 import org.apache.bcel.generic.InstructionTargeter;
45 import org.apache.bcel.generic.InvokeInstruction;
46 import org.apache.bcel.generic.MethodGen;
47 import org.apache.bcel.generic.ObjectType;
48 import org.apache.bcel.generic.PUSH;
49 import org.apache.bcel.generic.RET;
50 import org.apache.bcel.generic.ReferenceType;
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.verifier.exc.AssertionViolatedException;
55 import org.apache.commons.javaflow.bytecode.Continuable;
56 import org.apache.commons.javaflow.bytecode.StackRecorder;
57 import org.apache.commons.javaflow.bytecode.transformation.ResourceTransformer;
58 import org.apache.commons.javaflow.bytecode.transformation.bcel.analyser.ControlFlowGraph;
59 import org.apache.commons.javaflow.bytecode.transformation.bcel.analyser.ExceptionHandler;
60 import org.apache.commons.javaflow.bytecode.transformation.bcel.analyser.ExecutionPath;
61 import org.apache.commons.javaflow.bytecode.transformation.bcel.analyser.ExecutionVisitor;
62 import org.apache.commons.javaflow.bytecode.transformation.bcel.analyser.Frame;
63 import org.apache.commons.javaflow.bytecode.transformation.bcel.analyser.InstructionContext;
64 import org.apache.commons.javaflow.bytecode.transformation.bcel.analyser.LocalVariables;
65 import org.apache.commons.javaflow.bytecode.transformation.bcel.analyser.OperandStack;
66 import org.apache.commons.javaflow.bytecode.transformation.bcel.analyser.UninitializedObjectType;
67 import org.apache.commons.logging.Log;
68 import org.apache.commons.logging.LogFactory;
69
70 import java.io.ByteArrayInputStream;
71 import java.io.FileOutputStream;
72 import java.io.IOException;
73 import java.io.InputStream;
74 import java.util.Vector;
75
76
77
78
79
80
81
82
83 public final class BcelClassTransformer implements ResourceTransformer {
84
85 private final static Log log = LogFactory.getLog(BcelClassTransformer.class);
86
87 private static final String STACK_RECORDER_CLASS = StackRecorder.class.getName();
88 private static final ObjectType STACK_RECORDER_TYPE = new ObjectType(STACK_RECORDER_CLASS);
89 private static final String CONTINUABLE_CLASS = Continuable.class.getName();
90 private static final String STACK_METHOD = "get";
91 private static final String POP_METHOD = "pop";
92 private static final String PUSH_METHOD = "push";
93 private static final String RESTORING_FIELD = "isRestoring";
94 private static final String CAPTURING_FIELD = "isCapturing";
95
96 private boolean currentMethodStatic = false;
97 public static boolean debug = false;
98
99
100
101
102
103
104
105
106
107
108
109 private org.apache.bcel.util.Repository repository;
110
111
112
113
114
115 private static final Object repositoryLock = new Object();
116
117 static {
118 try {
119 debug = System.getProperty(BcelClassTransformer.class.getName()+".debug")!=null;
120 } catch (SecurityException e) {
121
122 }
123 }
124
125 public BcelClassTransformer() {
126 }
127
128 public BcelClassTransformer(org.apache.bcel.util.Repository repository) {
129 this.repository = repository;
130 }
131
132 public byte[] transform(final byte[] original) {
133 if(repository==null) {
134 return doTransform(original);
135 } else {
136 synchronized(repositoryLock) {
137 org.apache.bcel.util.Repository old = Repository.getRepository();
138 Repository.setRepository(repository);
139 try {
140 return doTransform(original);
141 } finally {
142 Repository.setRepository(old);
143 }
144 }
145 }
146 }
147
148 private byte[] doTransform(final byte[] original) {
149
150 final InputStream is = new ByteArrayInputStream(original);
151
152 final ClassParser parser = new ClassParser(is, null);
153 JavaClass javaClazz = null;
154 try {
155 javaClazz = parser.parse();
156 } catch (ClassFormatException e2) {
157 e2.printStackTrace();
158 } catch (IOException e2) {
159 e2.printStackTrace();
160 }
161
162 Repository.addClass(javaClazz);
163
164 log.debug("transforming class " + javaClazz.getClassName());
165
166
167
168 {
169 String[] intfs = javaClazz.getInterfaceNames();
170 for( int i=0; i<intfs.length; i++ )
171 if(intfs[i].equals(CONTINUABLE_CLASS)) {
172
173 log.debug(javaClazz.getClassName()+" is already instrumented. Skipping");
174 return original;
175 }
176 }
177
178 final ClassGen clazzGen = new ClassGen(javaClazz);
179 final ConstantPoolGen cp = clazzGen.getConstantPool();
180
181 if(debug) {
182 dump(javaClazz, ".orig");
183 }
184
185
186 final ExecutionVisitor ev = new ExecutionVisitor();
187 ev.setConstantPoolGen(cp);
188
189
190
191
192 final Method[] methods = clazzGen.getMethods();
193 for (int i = 0; i < methods.length; i++) {
194 final MethodGen method = new MethodGen(methods[i], clazzGen.getClassName(), cp);
195 currentMethodStatic = methods[i].isStatic();
196 if (needsRewriting(method)) {
197
198
199 final ControlFlowGraph cfg = new ControlFlowGraph(method);
200
201 analyse(clazzGen, method, cfg, ev);
202
203 try {
204
205 rewrite(method, cfg);
206 } catch (ClassNotFoundException e1) {
207 e1.printStackTrace();
208 }
209
210 clazzGen.replaceMethod(methods[i], method.getMethod());
211 }
212 }
213
214 clazzGen.addInterface(CONTINUABLE_CLASS);
215 JavaClass newClass = clazzGen.getJavaClass();
216 final byte[] changed = newClass.getBytes();
217
218 if(debug) {
219 dump(newClass, ".rewritten");
220 }
221
222 return changed;
223 }
224
225
226
227
228 private void dump(JavaClass javaClazz, String suffix) {
229 String path = javaClazz.getClassName()+suffix;
230
231 final byte[] orig = javaClazz.getBytes();
232
233 FileOutputStream out = null;
234 try {
235 out = new FileOutputStream(path);
236
237 log.debug("writing " + path);
238
239 out.write(orig);
240 out.flush();
241 } catch (final IOException e) {
242 e.printStackTrace();
243
244 try {
245 if (out != null) {
246 out.close();
247 }
248 } catch (final IOException e1) {
249 log.error(e1.getMessage(), e1);
250 } finally {
251 out = null;
252 }
253 }
254
255 try {
256 out = new FileOutputStream(path + ".java");
257
258 log.debug("writing " + path + ".java");
259
260 final DecompilingVisitor v = new DecompilingVisitor(javaClazz, out);
261 v.start();
262 } catch (final Exception e) {
263 e.printStackTrace();
264
265 try {
266 if (out != null) {
267 out.close();
268 }
269 } catch (final IOException e1) {
270 log.error(e1.getMessage(), e1);
271 } finally {
272 out = null;
273 }
274 }
275 }
276
277 private boolean needsRewriting(MethodGen m) {
278 if (m.getName().equals(Constants.CONSTRUCTOR_NAME)
279 || m.getName().equals(Constants.STATIC_INITIALIZER_NAME)
280 || m.isNative()
281 || m.isAbstract()) {
282 return false;
283 } else {
284 return true;
285 }
286 }
287
288 private void analyse(ClassGen clazz, MethodGen method, ControlFlowGraph cfg, ExecutionVisitor ev) {
289 log.debug("analyse " + method.getName());
290
291 final Frame vanillaFrame = craeteInitialFrame(method, clazz);
292
293 final Vector ics = new Vector();
294 final Vector ecs = new Vector();
295
296 final InstructionContext start = cfg.contextOf(method.getInstructionList().getStart());
297
298 start.execute(vanillaFrame, ExecutionPath.EMPTY, ev);
299
300
301 ics.add(start);
302 ecs.add(ExecutionPath.EMPTY);
303
304 while (!ics.isEmpty()) {
305 final InstructionContext u = (InstructionContext) ics.remove(0);
306 final ExecutionPath oldchain = (ExecutionPath) ecs.remove(0);
307 final ExecutionPath newchain = oldchain.append(u);
308
309 if ((u.getInstruction().getInstruction()) instanceof RET) {
310
311 InstructionHandle jsr = oldchain.lastExecutionJSR().getInstruction();
312
313 final InstructionContext theSuccessor = cfg.contextOf(jsr.getNext());
314
315 if (theSuccessor.execute(u.getOutFrame(oldchain), newchain, ev)) {
316 ics.add(theSuccessor);
317 ecs.add(newchain);
318 }
319 } else {
320
321 final InstructionContext[] succs = u.getSuccessors();
322 for (int s = 0; s < succs.length; s++) {
323 final InstructionContext v = succs[s];
324
325 if (v.execute(u.getOutFrame(oldchain), newchain, ev)) {
326 ics.add(v);
327 ecs.add(newchain);
328 }
329 }
330 }
331
332 final ExceptionHandler[] exc_hds = u.getExceptionHandlers();
333 for (int s = 0; s < exc_hds.length; s++) {
334 final InstructionContext v = cfg.contextOf(exc_hds[s].getHandlerStart());
335
336
337
338
339
340
341
342
343 final LocalVariables newLocals = u.getOutFrame(oldchain).getLocals();
344 final OperandStack newStack = new OperandStack(
345 u.getOutFrame(oldchain).getStack().maxStack(),
346 (exc_hds[s].getExceptionType() == null ? Type.THROWABLE : exc_hds[s]
347 .getExceptionType()));
348 final Frame newFrame = new Frame(newLocals, newStack);
349
350 if (v.execute(newFrame, ExecutionPath.EMPTY, ev)) {
351 ics.add(v);
352 ecs.add(ExecutionPath.EMPTY);
353 }
354 }
355 }
356 }
357
358
359
360
361
362 private Frame craeteInitialFrame(MethodGen method, ClassGen clazz) {
363 final Frame vanillaFrame = new Frame(method.getMaxLocals(), method.getMaxStack());
364 if (!method.isStatic()) {
365 if (method.getName().equals(Constants.CONSTRUCTOR_NAME)) {
366 Frame._this = new UninitializedObjectType(new ObjectType(clazz.getClassName()));
367 vanillaFrame.getLocals().set(0, new UninitializedObjectType(new ObjectType(clazz.getClassName())));
368 } else {
369 Frame._this = null;
370 vanillaFrame.getLocals().set(0, new ObjectType(clazz.getClassName()));
371 }
372 }
373
374 final Type[] argtypes = method.getArgumentTypes();
375 int twoslotoffset = 0;
376 for (int j = 0; j < argtypes.length; j++) {
377 if ((argtypes[j] == Type.SHORT) || (argtypes[j] == Type.BYTE) || (argtypes[j] == Type.CHAR) || (argtypes[j] == Type.BOOLEAN)) {
378 argtypes[j] = Type.INT;
379 }
380 vanillaFrame.getLocals().set(twoslotoffset + j + (method.isStatic() ? 0 : 1), argtypes[j]);
381 if (argtypes[j].getSize() == 2) {
382 twoslotoffset++;
383 vanillaFrame.getLocals().set(twoslotoffset + j + (method.isStatic() ? 0 : 1), Type.UNKNOWN);
384 }
385 }
386
387 return vanillaFrame;
388 }
389
390 private void rewrite(MethodGen method, ControlFlowGraph cfg) throws ClassNotFoundException {
391 final InstructionFactory insFactory = new InstructionFactory(method.getConstantPool());
392 final Vector invokeIns = new Vector();
393 final InstructionList insList = method.getInstructionList();
394 InstructionHandle ins = insList.getStart();
395 final InstructionList restorer = new InstructionList();
396 int count = 0;
397
398
399
400 int[] localVarsSize = new int[1];
401 localVarsSize[0] = method.getMaxLocals();
402
403 while (ins != null) {
404 InstructionHandle next = ins.getNext();
405
406
407 InstructionContext context = null;
408 Frame frame = null;
409 try {
410 context = cfg.contextOf(ins);
411 frame = context.getOutFrame(ExecutionPath.EMPTY);
412 } catch (AssertionViolatedException ave) {
413
414 }
415 if (frame != null) {
416 if (rewriteable(method, ins)) {
417
418
419
420 final InvokeInstruction invoke = (InvokeInstruction) ins.getInstruction();
421 final Type[] arguments = invoke.getArgumentTypes(method.getConstantPool());
422 ReferenceType objecttype = null;
423 if (!(invoke instanceof INVOKESTATIC)) {
424 objecttype = (ReferenceType) context.getInFrame().getStack().peek(arguments.length);
425 }
426 final InstructionList rList = restoreFrame(method, ins, insFactory, frame, objecttype);
427 insList.append(ins, saveFrame(method, ins, count++, insFactory, frame));
428 invokeIns.addElement(rList.getStart());
429 restorer.append(rList);
430 }
431
432 if (ins.getInstruction().getOpcode() == Constants.NEW) {
433 try {
434
435 while (next != null && next.getInstruction().getOpcode() == Constants.DUP) {
436 context = cfg.contextOf(next);
437 context.getOutFrame(ExecutionPath.EMPTY);
438 final InstructionHandle newnext = next.getNext();
439 insList.delete(next);
440 next = newnext;
441 }
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459 if(next!=null && next.getNext()!=null && next.getNext().getInstruction().getOpcode() == Constants.DUP_X2) {
460 InstructionHandle dupx2ptr = next.getNext();
461 final InstructionHandle newnext = dupx2ptr.getNext();
462 insList.insert(dupx2ptr, InstructionConstants.DUP);
463 insList.delete(dupx2ptr);
464 next = newnext;
465 }
466 final InstructionTargeter[] targeter = ins.getTargeters();
467 if (targeter != null) {
468 final InstructionHandle newnext = ins.getNext();
469 for (int i = 0; i < targeter.length; i++) {
470 targeter[i].updateTarget(ins, newnext);
471 }
472 }
473 insList.delete(ins);
474 } catch (TargetLostException tle) {
475 throw new ClassNotFoundException(tle.getMessage(), tle);
476 }
477 } else if (ins.getInstruction().getOpcode() == Constants.INVOKESPECIAL) {
478
479
480 frame = context.getInFrame();
481 final InvokeInstruction invoke = (InvokeInstruction) ins.getInstruction();
482 final Type[] arguments = invoke.getArgumentTypes(method.getConstantPool());
483
484 final OperandStack os = frame.getStack();
485 final Type type = os.peek(arguments.length);
486 if (type instanceof UninitializedObjectType) {
487 final ObjectType objecttype = ((UninitializedObjectType) type).getInitialized();
488 final InstructionList duplicator = duplicateStack(method, invoke, objecttype, localVarsSize);
489 final InstructionTargeter[] targeter = ins.getTargeters();
490
491 if (targeter != null) {
492 final InstructionHandle newnext = duplicator.getStart();
493 for (int i = 0; i < targeter.length; i++) {
494 targeter[i].updateTarget(ins, newnext);
495 }
496 }
497 insList.insert(ins, duplicator);
498 }
499 }
500 }
501 ins = next;
502 }
503
504
505 final int varStack = method.getMaxLocals();
506
507 Instruction loadStackRecorder = InstructionFactory.createLoad(STACK_RECORDER_TYPE, varStack);
508
509 final InstructionHandle firstIns = insList.getStart();
510 if (count > 0) {
511 final InstructionHandle[] tableTargets = new InstructionHandle[count];
512 int[] match = new int[count];
513 for (int i = 0; i < count; i++) {
514 match[i] = i;
515 }
516 invokeIns.copyInto(tableTargets);
517 insList.insert(restorer);
518
519
520 insList.insert(new TABLESWITCH(match, tableTargets, firstIns));
521 insList.insert(insFactory.createInvoke(STACK_RECORDER_CLASS, getPopMethod(Type.INT), Type.INT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
522 insList.insert(loadStackRecorder);
523
524
525 insList.insert(new IFEQ(firstIns));
526 insList.insert(insFactory.createFieldAccess(STACK_RECORDER_CLASS, RESTORING_FIELD, Type.BOOLEAN, Constants.GETFIELD));
527 insList.insert(loadStackRecorder);
528
529
530 insList.insert(new IFNULL(firstIns));
531
532
533 insList.insert(InstructionFactory.createStore(STACK_RECORDER_TYPE, varStack));
534 insList.insert(InstructionConstants.DUP);
535 insList.insert(insFactory.createInvoke(STACK_RECORDER_CLASS, STACK_METHOD, STACK_RECORDER_TYPE, Type.NO_ARGS, Constants.INVOKESTATIC));
536
537
538 localVarsSize[0] = Math.max( localVarsSize[0], method.getMaxLocals()+1 );
539
540
541 method.setMaxStack(method.getMaxStack() + 2);
542 }
543
544 method.setMaxLocals(localVarsSize[0]);
545
546
547
548
549 method.setMaxStack(method.getMaxStack() + 1);
550
551
552
553
554 Attribute[] atts = method.getCodeAttributes();
555 for( int i=0; i<atts.length; i++ ) {
556 if(atts[i].getNameIndex()==method.getConstantPool().lookupUtf8("LocalVariableTypeTable"))
557 method.removeCodeAttribute(atts[i]);
558 }
559 }
560
561
562
563
564 private InstructionList duplicateStack(MethodGen method, InvokeInstruction invoke, ObjectType objecttype, int[] localVarsSize) {
565
566 final InstructionFactory insFactory = new InstructionFactory(method.getConstantPool());
567 final InstructionList insList = new InstructionList();
568
569 final Type[] arguments = invoke.getArgumentTypes(method.getConstantPool());
570
571 int localVarOffset = method.getMaxLocals()+1;
572
573
574 for (int i = arguments.length - 1; i >= 0; i--) {
575 Type type = arguments[i];
576 insList.append(InstructionFactory.createStore(type,localVarOffset));
577 localVarOffset += type.getSize();
578 }
579
580 localVarsSize[0] = Math.max(localVarsSize[0],localVarOffset);
581
582
583 insList.append(insFactory.createNew(objecttype));
584 insList.append(InstructionConstants.DUP);
585
586
587 for (int i = 0; i < arguments.length; i++) {
588 Type type = arguments[i];
589
590 localVarOffset -= type.getSize();
591 insList.append(InstructionFactory.createLoad(type,localVarOffset));
592 if(type instanceof ReferenceType) {
593
594 insList.append(InstructionConstants.ACONST_NULL);
595 insList.append(InstructionFactory.createStore(type,localVarOffset));
596 }
597 }
598 return insList;
599 }
600
601 private boolean rewriteable(MethodGen method, InstructionHandle handle) {
602
603 int opcode = handle.getInstruction().getOpcode();
604
605 if(!(handle.getInstruction() instanceof InvokeInstruction))
606 return false;
607
608 if (opcode == Constants.INVOKESPECIAL) {
609 final InvokeInstruction ivs = (InvokeInstruction) handle.getInstruction();
610 final String mName = ivs.getMethodName(method.getConstantPool());
611 if(mName.equals(Constants.CONSTRUCTOR_NAME))
612 return false;
613 }
614
615
616
617
618
619
620
621
622
623 return true;
624 }
625
626 private InstructionList saveFrame(MethodGen method, InstructionHandle handle, int pc, InstructionFactory insFactory, Frame frame) {
627 final InstructionList insList = new InstructionList();
628
629
630 final InvokeInstruction inv = (InvokeInstruction) handle.getInstruction();
631 final Type returnType = getReturnType(method.getConstantPool().getConstantPool(), inv.getIndex());
632 if (returnType.getSize() > 0) {
633 insList.insert(InstructionFactory.createPop(returnType.getSize()));
634 }
635 boolean skipFirst = returnType.getSize() > 0;
636
637
638
639
640
641
642 Instruction loadStackRecorder = InstructionFactory.createLoad(STACK_RECORDER_TYPE, method.getMaxLocals());
643
644
645 final OperandStack os = frame.getStack();
646 for (int i = skipFirst ? 1 : 0; i < os.size(); i++) {
647 Type type = os.peek(i);
648 if (type instanceof BasicType) {
649 if (type.getSize() < 2 && !type.equals(Type.FLOAT)) {
650 type = Type.INT;
651 }
652
653
654 if (type.equals(Type.LONG) || type.equals(Type.DOUBLE)) {
655 insList.append(InstructionConstants.ACONST_NULL);
656 insList.append(loadStackRecorder);
657 insList.append(InstructionConstants.DUP2_X2);
658 insList.append(InstructionConstants.POP2);
659 } else {
660 insList.append(loadStackRecorder);
661 insList.append(InstructionConstants.SWAP);
662 }
663 insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPushMethod(type), Type.VOID, new Type[] { type }, Constants.INVOKEVIRTUAL));
664 if (type.equals(Type.LONG) || type.equals(Type.DOUBLE))
665 insList.append(InstructionConstants.POP);
666 } else if (type == null) {
667 insList.append(InstructionConstants.POP);
668 } else if (type instanceof UninitializedObjectType) {
669
670
671 } else if (type instanceof ReferenceType) {
672 if(type.equals(Type.NULL)) {
673
674
675
676 insList.append(InstructionConstants.POP);
677 } else {
678 insList.append(loadStackRecorder);
679 insList.append(InstructionConstants.SWAP);
680 insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPushMethod(Type.OBJECT), Type.VOID, new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL));
681 }
682 }
683 }
684
685 if (debug) {
686 insList.insert(insFactory.createPrintln("capturing invocation "+method));
687 }
688 insList.insert(new IFEQ(handle.getNext()));
689
690
691 insList.insert(insFactory.createFieldAccess(STACK_RECORDER_CLASS, CAPTURING_FIELD, Type.BOOLEAN, Constants.GETFIELD));
692 insList.insert(loadStackRecorder);
693
694
695 insList.insert(new IFNULL(handle.getNext()));
696 insList.insert(loadStackRecorder);
697
698
699
700
701
702
703 final LocalVariables lvs = frame.getLocals();
704 for (int i = 0; i < lvs.maxLocals(); i++) {
705 Type type = lvs.get(i);
706 if (type instanceof BasicType) {
707 insList.append(loadStackRecorder);
708 insList.append(InstructionFactory.createLoad(type, i));
709 if (type.getSize() < 2 && !type.equals(Type.FLOAT))
710 type = Type.INT;
711 insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPushMethod(type), Type.VOID, new Type[] { type }, Constants.INVOKEVIRTUAL));
712 } else if (type == null || type==Type.NULL) {
713
714 } else if (type instanceof UninitializedObjectType) {
715
716 } else if (type instanceof ReferenceType) {
717 if (i == 0 && !currentMethodStatic) {
718
719 insList.append(loadStackRecorder);
720 insList.append(InstructionFactory.createLoad(type, i));
721 insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, PUSH_METHOD + "Reference", Type.VOID, new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL));
722 }
723 insList.append(loadStackRecorder);
724 insList.append(InstructionFactory.createLoad(type, i));
725 insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPushMethod(Type.OBJECT), Type.VOID, new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL));
726 }
727 }
728
729 insList.append(loadStackRecorder);
730 insList.append(new PUSH(method.getConstantPool(), pc));
731 insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPushMethod(Type.INT), Type.VOID, new Type[] { Type.INT }, Constants.INVOKEVIRTUAL));
732
733 insList.append(InstructionFactory.createNull(method.getReturnType()));
734 insList.append(InstructionFactory.createReturn(method.getReturnType()));
735 return insList;
736 }
737
738 private InstructionList restoreFrame(MethodGen method, InstructionHandle handle, InstructionFactory insFactory, Frame frame, ReferenceType objecttype) {
739 final InstructionList insList = new InstructionList();
740
741
742
743
744
745 final LocalVariables lvs = frame.getLocals();
746 Instruction loadStackRecorder = InstructionFactory.createLoad(STACK_RECORDER_TYPE, method.getMaxLocals());
747
748 for (int i = lvs.maxLocals() - 1; i >= 0; i--) {
749 Type type = lvs.get(i);
750 if (type instanceof BasicType) {
751 insList.append(loadStackRecorder);
752 if (type.getSize() < 2 && !type.equals(Type.FLOAT)) {
753 type = Type.INT;
754 }
755 insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPopMethod(type), type, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
756 insList.append(InstructionFactory.createStore(type, i));
757 } else if (type == null) {
758 insList.append(InstructionConstants.ACONST_NULL);
759 insList.append(new ASTORE(i));
760 } else if (type instanceof UninitializedObjectType) {
761
762
763 throw new Error("assertion failure");
764 } else if (type instanceof ReferenceType) {
765 if (type==Type.NULL) {
766
767
768
769 insList.append(InstructionConstants.ACONST_NULL);
770 } else {
771 insList.append(loadStackRecorder);
772 insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPopMethod(Type.OBJECT), Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
773 if (!type.equals(Type.OBJECT)) {
774 insList.append(insFactory.createCast(Type.OBJECT, type));
775 }
776 }
777 insList.append(new ASTORE(i));
778 }
779 }
780
781 final InvokeInstruction inv = (InvokeInstruction) handle.getInstruction();
782 final Type returnType = getReturnType(method.getConstantPool().getConstantPool(), inv.getIndex());
783 boolean skipFirst = returnType.getSize() > 0;
784
785
786
787
788
789
790 final OperandStack os = frame.getStack();
791 for (int i = os.size() - 1; i >= (skipFirst ? 1 : 0); i--) {
792 Type type = os.peek(i);
793 if (type instanceof BasicType) {
794 if (type.getSize() < 2 && !type.equals(Type.FLOAT)) {
795 type = Type.INT;
796 }
797 insList.append(loadStackRecorder);
798 insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPopMethod(type), type, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
799 } else if (type == null || type==Type.NULL) {
800 insList.append(new ACONST_NULL());
801 } else if (type instanceof UninitializedObjectType) {
802
803
804 } else if (type instanceof ReferenceType) {
805 insList.append(loadStackRecorder);
806 insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPopMethod(Type.OBJECT), Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
807 if (!type.equals(Type.OBJECT))
808 insList.append(insFactory.createCast(Type.OBJECT, type));
809 }
810 }
811
812 if (!(inv instanceof INVOKESTATIC)) {
813 insList.append(loadStackRecorder);
814 insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, POP_METHOD + "Reference", Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
815 insList.append(insFactory.createCast(Type.OBJECT, objecttype));
816 }
817
818 final Type[] paramTypes = getParamTypes(method.getConstantPool().getConstantPool(), inv.getIndex());
819 for (int j = 0; j < paramTypes.length; j++) {
820 insList.append(InstructionFactory.createNull(paramTypes[j]));
821 }
822
823 insList.append(new GOTO(handle));
824 return insList;
825 }
826
827 private Type[] getParamTypes(ConstantPool cp, int index) {
828 final ConstantCP cmr = (ConstantCP) cp.getConstant(index);
829 final ConstantNameAndType cnat = (ConstantNameAndType) cp.getConstant(cmr.getNameAndTypeIndex());
830 final String sig = ((ConstantUtf8) cp.getConstant(cnat.getSignatureIndex())).getBytes();
831 return Type.getArgumentTypes(sig);
832 }
833
834 private Type getReturnType(ConstantPool cp, int index) {
835 final ConstantCP cmr = (ConstantCP) cp.getConstant(index);
836 final ConstantNameAndType cnat = (ConstantNameAndType) cp.getConstant(cmr.getNameAndTypeIndex());
837 final String sig = ((ConstantUtf8) cp.getConstant(cnat.getSignatureIndex())).getBytes();
838 return Type.getReturnType(sig);
839 }
840
841 private String getPopMethod(Type type) {
842 return POP_METHOD + getTypeSuffix(type);
843 }
844
845 private String getPushMethod(Type type) {
846 return PUSH_METHOD + getTypeSuffix(type);
847 }
848
849 private String getTypeSuffix(Type type) {
850 if (type.equals(Type.BOOLEAN))
851 return "Int";
852 else if (type.equals(Type.CHAR))
853 return "Int";
854 else if (type.equals(Type.FLOAT))
855 return "Float";
856 else if (type.equals(Type.DOUBLE))
857 return "Double";
858 else if (type.equals(Type.BYTE))
859 return "Int";
860 else if (type.equals(Type.SHORT))
861 return "Int";
862 else if (type.equals(Type.INT))
863 return "Int";
864 else if (type.equals(Type.LONG))
865 return "Long";
866
867 return "Object";
868 }
869
870 }