001: /***
002: * Retrotranslator: a Java bytecode transformer that translates Java classes
003: * compiled with JDK 5.0 into classes that can be run on JVM 1.4.
004: *
005: * Copyright (c) 2005 - 2008 Taras Puchko
006: * All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * 3. Neither the name of the copyright holders nor the names of its
017: * contributors may be used to endorse or promote products derived from
018: * this software without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
021: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
022: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
023: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
024: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
025: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
026: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
027: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
028: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
029: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
030: * THE POSSIBILITY OF SUCH DAMAGE.
031: */package net.sf.retrotranslator.transformer;
032:
033: import net.sf.retrotranslator.runtime.asm.*;
034: import static net.sf.retrotranslator.runtime.asm.Opcodes.*;
035: import static net.sf.retrotranslator.runtime.impl.RuntimeTools.CONSTRUCTOR_NAME;
036:
037: /**
038: * @author Taras Puchko
039: */
040: class GeneralReplacementVisitor extends GenericClassVisitor {
041:
042: private static final String LONG_ARG_DESCRIPTOR = TransformerTools
043: .descriptor(long.class);
044: private static final String DOUBLE_ARG_DESCRIPTOR = TransformerTools
045: .descriptor(double.class);
046:
047: private final ReplacementLocator locator;
048: private final NameTranslator translator;
049: private String currentClassName;
050: private boolean threadLocalExcluded;
051:
052: public GeneralReplacementVisitor(ClassVisitor classVisitor,
053: final ReplacementLocator locator) {
054: super (classVisitor);
055: this .locator = locator;
056: translator = new NameTranslator() {
057: protected String typeName(String s) {
058: if (isExcluded(s))
059: return s;
060: return locator.getUniqueTypeName(s);
061: }
062: };
063: }
064:
065: protected String identifier(String s) {
066: return fixIdentifier(s);
067: }
068:
069: protected String typeName(String s) {
070: if (isExcluded(s))
071: return s;
072: return locator.getReferenceTypeName(s);
073: }
074:
075: public void visit(int version, int access, String name,
076: String signature, String super Name, String[] interfaces) {
077: currentClassName = name;
078: threadLocalExcluded = name.endsWith("ThreadLocal_$Container");
079: super .visit(version, access, translator.typeName(name),
080: translator.declarationSignature(signature), translator
081: .typeName(super Name), translator
082: .typeNames(interfaces));
083: }
084:
085: private boolean isExcluded(String name) {
086: return name == null
087: || threadLocalExcluded
088: && (name.equals("java/lang/ThreadLocal") || name
089: .equals("java/lang/InheritableThreadLocal"));
090: }
091:
092: protected void visitTypeInstruction(MethodVisitor visitor,
093: int opcode, String desc) {
094: if (opcode == CHECKCAST || opcode == INSTANCEOF) {
095: ClassReplacement classReplacement = locator
096: .getReplacement(desc);
097: if (classReplacement != null) {
098: MemberReplacement method = opcode == CHECKCAST ? classReplacement
099: .getCheckCastReplacement()
100: : classReplacement.getInstanceOfReplacement();
101: if (method != null
102: && !method.getOwner().equals(currentClassName)) {
103: visitor.visitMethodInsn(INVOKESTATIC, method
104: .getOwner(), method.getName(), method
105: .getDesc());
106: return;
107: }
108: }
109: }
110: super .visitTypeInstruction(visitor, opcode, desc);
111: }
112:
113: protected void visitFieldInstruction(MethodVisitor visitor,
114: int opcode, String owner, String name, String desc) {
115: if (opcode == GETSTATIC || opcode == PUTSTATIC) {
116: ClassReplacement replacement = locator
117: .getReplacement(owner);
118: if (replacement != null) {
119: MemberKey key = new MemberKey(true, name,
120: typeDescriptor(desc));
121: MemberReplacement field = replacement
122: .getFieldReplacements().get(key);
123: if (field != null
124: && !field.getOwner().equals(currentClassName)) {
125: visitor.visitFieldInsn(opcode, field.getOwner(),
126: field.getName(), field.getDesc());
127: return;
128: }
129: }
130: }
131: super .visitFieldInstruction(visitor, opcode, owner, name, desc);
132: }
133:
134: protected void visitMethodInstruction(MethodVisitor visitor,
135: int opcode, String owner, String name, String desc) {
136: ClassReplacement replacement = locator.getReplacement(owner);
137: if (replacement != null) {
138: owner = typeName(owner);
139: desc = methodDescriptor(desc);
140: if (opcode == INVOKESPECIAL
141: && name.equals(CONSTRUCTOR_NAME)) {
142: if (visitConstructor(replacement, visitor, owner, desc)) {
143: return;
144: }
145: replacement = locator.getReplacement(owner);
146: if (replacement != null
147: && visitConstructor(replacement, visitor,
148: owner, desc)) {
149: return;
150: }
151: } else {
152: MemberKey key = new MemberKey(opcode == INVOKESTATIC,
153: name, desc);
154: MemberReplacement method = replacement
155: .getMethodReplacements().get(key);
156: if (method == null) {
157: replacement = locator.getReplacement(owner);
158: method = replacement == null ? null : replacement
159: .getMethodReplacements().get(key);
160: }
161: if (method != null
162: && !method.getOwner().equals(currentClassName)) {
163: visitor.visitMethodInsn(INVOKESTATIC, method
164: .getOwner(), method.getName(), method
165: .getDesc());
166: return;
167: }
168: }
169: }
170: super
171: .visitMethodInstruction(visitor, opcode, owner, name,
172: desc);
173: }
174:
175: private boolean visitConstructor(ClassReplacement replacement,
176: MethodVisitor visitor, String owner, String desc) {
177: ConstructorReplacement constructorReplacement = replacement
178: .getConstructorReplacements().get(desc);
179: if (constructorReplacement != null) {
180: buildInstance(visitor, owner, constructorReplacement);
181: return true;
182: }
183: MemberReplacement converter = replacement
184: .getConverterReplacements().get(desc);
185: if (converter != null) {
186: visitor.visitMethodInsn(INVOKESTATIC, converter.getOwner(),
187: converter.getName(), converter.getDesc());
188: visitor.visitMethodInsn(INVOKESPECIAL, owner,
189: CONSTRUCTOR_NAME, ClassReplacement
190: .getConstructorDesc(converter));
191: return true;
192: }
193: return false;
194: }
195:
196: private void buildInstance(MethodVisitor visitor, String owner,
197: ConstructorReplacement replacement) {
198: MemberReplacement creator = replacement.getCreator();
199: visitor.visitMethodInsn(INVOKESTATIC, creator.getOwner(),
200: creator.getName(), creator.getDesc());
201: MemberReplacement initializer = replacement.getInitializer();
202: if (initializer != null) {
203: visitor.visitInsn(DUP2);
204: }
205: MemberReplacement[] arguments = replacement.getArguments();
206: if (arguments.length == 0) {
207: visitor.visitInsn(POP);
208: } else {
209: pushArguments(visitor, arguments);
210: }
211: visitor.visitMethodInsn(INVOKESPECIAL, owner, CONSTRUCTOR_NAME,
212: replacement.getConstructorDesc());
213: if (initializer != null) {
214: visitor.visitInsn(SWAP);
215: visitor.visitMethodInsn(INVOKEVIRTUAL, initializer
216: .getOwner(), initializer.getName(), initializer
217: .getDesc());
218: }
219: }
220:
221: private void pushArguments(MethodVisitor visitor,
222: MemberReplacement[] arguments) {
223: for (int i = 0; i < arguments.length; i++) {
224: MemberReplacement argument = arguments[i];
225: boolean notLast = i + 1 < arguments.length;
226: if (notLast) {
227: visitor.visitInsn(DUP);
228: }
229: visitor.visitMethodInsn(INVOKEVIRTUAL, argument.getOwner(),
230: argument.getName(), argument.getDesc());
231: if (notLast) {
232: swap(visitor, argument);
233: }
234: }
235: }
236:
237: private void swap(MethodVisitor visitor, MemberReplacement argument) {
238: if (argument.getDesc().equals(LONG_ARG_DESCRIPTOR)
239: || argument.getDesc().equals(DOUBLE_ARG_DESCRIPTOR)) {
240: visitor.visitInsn(DUP2_X1);
241: visitor.visitInsn(POP2);
242: } else {
243: visitor.visitInsn(SWAP);
244: }
245: }
246:
247: }
|