01: /*
02: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
03: */
04: package com.tc.object.bytecode;
05:
06: import com.tc.asm.ClassAdapter;
07: import com.tc.asm.ClassVisitor;
08: import com.tc.asm.MethodAdapter;
09: import com.tc.asm.MethodVisitor;
10: import com.tc.asm.Opcodes;
11: import com.tc.object.bytecode.hook.impl.JavaLangArrayHelpers;
12:
13: public class AbstractStringBuilderAdapter extends ClassAdapter {
14: private String stringBuilderInternalName;
15:
16: public AbstractStringBuilderAdapter(ClassVisitor cv,
17: String stringBuilderClassName) {
18: super (cv);
19:
20: this .stringBuilderInternalName = stringBuilderClassName
21: .replace('.', '/');
22: }
23:
24: public MethodVisitor visitMethod(int access, String name,
25: String desc, String signature, String[] exceptions) {
26: MethodVisitor mv = super .visitMethod(access, name, desc,
27: signature, exceptions);
28: if ((DuplicateMethodAdapter.MANAGED_PREFIX + "append")
29: .equals(name)) {
30: if (("(I)L" + stringBuilderInternalName + ";").equals(desc)) {
31: return new AppendAdapter(mv, "I");
32: } else if (("(J)L" + stringBuilderInternalName + ";")
33: .equals(desc)) {
34: return new AppendAdapter(mv, "J");
35: }
36: }
37:
38: return mv;
39: }
40:
41: private class AppendAdapter extends MethodAdapter implements
42: Opcodes {
43:
44: private final int spaceNeededSlot;
45: private final int countSlot;
46: private boolean hasVisitedOnce = false;
47:
48: public AppendAdapter(MethodVisitor mv, String type) {
49: super (mv);
50:
51: if (!"J".equals(type) && !"I".equals(type)) {
52: throw new AssertionError("bad type: " + type);
53: }
54:
55: this .spaceNeededSlot = type.equals("I") ? 2 : 3;
56: this .countSlot = type.equals("I") ? 3 : 4;
57: }
58:
59: public void visitInsn(int opcode) {
60: if (opcode == ARETURN) {
61:
62: // This is a hack to fix append(int) and append(long) where the argument is either Integer.MIN_VALUE
63: // or Long.MIN_VALUE. In either of those cases, we do not want to call
64: // JavaLangArrayHelpers.javaLangAbstractStringBuilderAppend.
65: if (!hasVisitedOnce) {
66: hasVisitedOnce = true;
67: super .visitInsn(opcode);
68: return;
69: }
70:
71: mv.visitVarInsn(ALOAD, 0);
72: mv.visitMethodInsn(INVOKEVIRTUAL,
73: stringBuilderInternalName, ByteCodeUtil
74: .fieldGetterMethod("value"), "()[C");
75: mv.visitVarInsn(ILOAD, spaceNeededSlot);
76: mv.visitVarInsn(ILOAD, countSlot);
77: mv.visitMethodInsn(INVOKESTATIC,
78: JavaLangArrayHelpers.CLASS,
79: "javaLangAbstractStringBuilderAppend",
80: "([CII)V");
81:
82: super.visitInsn(opcode);
83: return;
84: }
85:
86: super.visitInsn(opcode);
87: }
88:
89: }
90:
91: }
|