001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.bytecode;
006:
007: import com.tc.asm.ClassAdapter;
008: import com.tc.asm.ClassVisitor;
009: import com.tc.asm.MethodAdapter;
010: import com.tc.asm.MethodVisitor;
011: import com.tc.asm.Opcodes;
012: import com.tc.object.bytecode.hook.impl.JavaLangArrayHelpers;
013: import com.tc.util.Assert;
014: import com.tc.util.runtime.VmVersion;
015: import com.tc.util.runtime.Vm;
016:
017: public class JavaLangStringAdapter extends ClassAdapter implements
018: Opcodes {
019:
020: private final VmVersion vmVersion;
021: private final boolean portableStringBuffer;
022:
023: public JavaLangStringAdapter(ClassVisitor cv, VmVersion vmVersion,
024: boolean portableStringBuffer) {
025: super (cv);
026: this .vmVersion = vmVersion;
027: this .portableStringBuffer = portableStringBuffer;
028: }
029:
030: public MethodVisitor visitMethod(int access, String name,
031: String desc, String signature, String[] exceptions) {
032: MethodVisitor mv = super .visitMethod(access, name, desc,
033: signature, exceptions);
034: if ("getBytes".equals(name) && "(II[BI)V".equals(desc)) {
035: return rewriteGetBytes(mv);
036: } else if ("<init>".equals(name)
037: && "(Ljava/lang/StringBuffer;)V".equals(desc)) {
038: if (vmVersion.isJDK14() && portableStringBuffer) {
039: return rewriteStringBufferConstructor(mv);
040: }
041: } else if ("getChars".equals(name) && "(II[CI)V".equals(desc)) {
042: // make formatter sane
043: return new GetCharsAdapter(mv);
044: } else if ("getChars".equals(name) && "([CI)V".equals(desc)) {
045: // This method is in the 1.5 Sun impl of String
046: return new GetCharsAdapter(mv);
047: }
048:
049: return new RewriteGetCharsCallsAdapter(mv);
050: }
051:
052: public void visitEnd() {
053: addFastGetChars();
054: super .visitEnd();
055: }
056:
057: private void addFastGetChars() {
058: // Called by the unmanaged paths of StringBuffer, StringBuilder, etc. Also called it strategic places where the
059: // target char[] is known (or assumed) to be non-shared
060: MethodVisitor mv = super .visitMethod(
061: ACC_SYNTHETIC | ACC_PUBLIC, "getCharsFast", "(II[CI)V",
062: null, null);
063: mv.visitCode();
064: mv.visitVarInsn(ALOAD, 0);
065: mv.visitFieldInsn(GETFIELD, "java/lang/String", "value", "[C");
066: mv.visitVarInsn(ALOAD, 0);
067: mv.visitFieldInsn(GETFIELD, "java/lang/String", "offset", "I");
068: mv.visitVarInsn(ILOAD, 1);
069: mv.visitInsn(IADD);
070: mv.visitVarInsn(ALOAD, 3);
071: mv.visitVarInsn(ILOAD, 4);
072: mv.visitVarInsn(ILOAD, 2);
073: mv.visitVarInsn(ILOAD, 1);
074: mv.visitInsn(ISUB);
075: mv.visitMethodInsn(INVOKESTATIC, "java/lang/System",
076: "arraycopy",
077: "(Ljava/lang/Object;ILjava/lang/Object;II)V");
078: mv.visitInsn(RETURN);
079: mv.visitMaxs(0, 0);
080: mv.visitEnd();
081:
082: // Called from (Abstract)StringBuilder.insert|repace()
083: mv = super .visitMethod(ACC_SYNTHETIC, "getCharsFast", "([CI)V",
084: null, null);
085: mv.visitCode();
086: mv.visitVarInsn(ALOAD, 0);
087: mv.visitFieldInsn(GETFIELD, "java/lang/String", "value", "[C");
088: mv.visitVarInsn(ALOAD, 0);
089: mv.visitFieldInsn(GETFIELD, "java/lang/String", "offset", "I");
090: mv.visitVarInsn(ALOAD, 1);
091: mv.visitVarInsn(ILOAD, 2);
092: mv.visitVarInsn(ALOAD, 0);
093: mv.visitFieldInsn(GETFIELD, "java/lang/String", "count", "I");
094: mv.visitMethodInsn(INVOKESTATIC, "java/lang/System",
095: "arraycopy",
096: "(Ljava/lang/Object;ILjava/lang/Object;II)V");
097: mv.visitInsn(RETURN);
098: mv.visitMaxs(0, 0);
099: mv.visitEnd();
100: }
101:
102: private MethodVisitor rewriteStringBufferConstructor(
103: MethodVisitor mv) {
104: // move the sync into StringBuffer.toString() where it belongs
105: Assert.assertTrue(Vm.isJDK14());
106: mv.visitCode();
107: mv.visitVarInsn(ALOAD, 0);
108: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>",
109: "()V");
110: mv.visitVarInsn(ALOAD, 1);
111: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer",
112: "toString", "()Ljava/lang/String;");
113: mv.visitVarInsn(ASTORE, 2);
114: mv.visitVarInsn(ALOAD, 0);
115: mv.visitVarInsn(ALOAD, 2);
116: mv.visitFieldInsn(GETFIELD, "java/lang/String", "value", "[C");
117: mv.visitFieldInsn(PUTFIELD, "java/lang/String", "value", "[C");
118: mv.visitVarInsn(ALOAD, 0);
119: mv.visitVarInsn(ALOAD, 2);
120: mv.visitFieldInsn(GETFIELD, "java/lang/String", "count", "I");
121: mv.visitFieldInsn(PUTFIELD, "java/lang/String", "count", "I");
122: mv.visitVarInsn(ALOAD, 0);
123: mv.visitVarInsn(ALOAD, 2);
124: mv.visitFieldInsn(GETFIELD, "java/lang/String", "offset", "I");
125: mv.visitFieldInsn(PUTFIELD, "java/lang/String", "offset", "I");
126: mv.visitInsn(RETURN);
127: mv.visitMaxs(0, 0);
128: return null;
129: }
130:
131: private MethodVisitor rewriteGetBytes(MethodVisitor mv) {
132: mv.visitCode();
133: mv.visitVarInsn(ILOAD, 1);
134: mv.visitVarInsn(ILOAD, 2);
135: mv.visitVarInsn(ALOAD, 3);
136: mv.visitVarInsn(ILOAD, 4);
137: mv.visitVarInsn(ALOAD, 0);
138: mv.visitFieldInsn(GETFIELD, "java/lang/String", "count", "I");
139: mv.visitVarInsn(ALOAD, 0);
140: mv.visitFieldInsn(GETFIELD, "java/lang/String", "offset", "I");
141: mv.visitVarInsn(ALOAD, 0);
142: mv.visitFieldInsn(GETFIELD, "java/lang/String", "value", "[C");
143: mv.visitMethodInsn(INVOKESTATIC, JavaLangArrayHelpers.CLASS,
144: "javaLangStringGetBytes", "(II[BIII[C)V");
145: mv.visitInsn(RETURN);
146: mv.visitMaxs(0, 0);
147: mv.visitEnd();
148: return null;
149: }
150:
151: private static class RewriteGetCharsCallsAdapter extends
152: MethodAdapter {
153:
154: public RewriteGetCharsCallsAdapter(MethodVisitor mv) {
155: super (mv);
156: }
157:
158: public void visitMethodInsn(int opcode, String owner,
159: String name, String desc) {
160: if ((INVOKEVIRTUAL == opcode)
161: && ("java/lang/String".equals(owner) && "getChars"
162: .equals(name))) {
163: super .visitMethodInsn(opcode, owner, "getCharsFast",
164: desc);
165: } else {
166: super .visitMethodInsn(opcode, owner, name, desc);
167: }
168: }
169:
170: }
171:
172: private static class GetCharsAdapter extends MethodAdapter {
173:
174: public GetCharsAdapter(MethodVisitor mv) {
175: super (mv);
176: }
177:
178: public void visitMethodInsn(int opcode, String owner,
179: String name, String desc) {
180: if ((opcode == INVOKESTATIC)
181: && "java/lang/System".equals(owner)
182: && "arraycopy".equals(name)) {
183: super .visitMethodInsn(INVOKESTATIC,
184: JavaLangArrayHelpers.CLASS, "charArrayCopy",
185: "([CI[CII)V");
186: } else {
187: super.visitMethodInsn(opcode, owner, name, desc);
188: }
189: }
190:
191: }
192:
193: }
|