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 net.sf.retrotranslator.runtime.impl.EmptyVisitor;
036:
037: /**
038: * @author Taras Puchko
039: */
040: class ObjectMethodsVisitor extends ClassAdapter {
041:
042: private static final String OBJECT_NAME = Type
043: .getInternalName(Object.class);
044:
045: private static ObjectMethod[] PUBLIC_METHODS = {
046: new ObjectMethod(boolean.class, "equals", Object.class),
047: new ObjectMethod(int.class, "hashCode"),
048: new ObjectMethod(String.class, "toString") };
049:
050: private static ObjectMethod[] PROTECTED_METHODS = {
051: new ObjectMethod(Object.class, "clone"),
052: new ObjectMethod(void.class, "finalize") };
053:
054: private final ReplacementLocator locator;
055:
056: public ObjectMethodsVisitor(ClassVisitor visitor,
057: ReplacementLocator locator) {
058: super (visitor);
059: this .locator = locator;
060: }
061:
062: public MethodVisitor visitMethod(int access, String name,
063: String desc, String signature, String[] exceptions) {
064: MethodVisitor visitor = super .visitMethod(access, name, desc,
065: signature, exceptions);
066: return visitor == null ? null : new MethodAdapter(visitor) {
067: public void visitMethodInsn(int opcode, String owner,
068: String name, String desc) {
069: if (opcode == INVOKEVIRTUAL && owner.charAt(0) == '[') {
070: mv.visitMethodInsn(opcode, OBJECT_NAME, name, desc);
071: return;
072: }
073: if (opcode == INVOKEINTERFACE) {
074: for (ObjectMethod method : PUBLIC_METHODS) {
075: if (method.equals(name, desc)) {
076: mv.visitMethodInsn(INVOKEVIRTUAL,
077: OBJECT_NAME, name, desc);
078: return;
079: }
080: }
081: for (ObjectMethod method : PROTECTED_METHODS) {
082: if (method.equals(name, desc)) {
083: String methodOwner = findMethodOwner(owner,
084: method);
085: if (methodOwner != null) {
086: mv.visitMethodInsn(opcode, methodOwner,
087: name, desc);
088: return;
089: }
090: }
091: }
092: }
093: super .visitMethodInsn(opcode, owner, name, desc);
094: }
095: };
096: }
097:
098: private String findMethodOwner(String className, ObjectMethod method) {
099: String uniqueTypeName = locator.getUniqueTypeName(className);
100: ClassReader reader = locator.getEnvironment().findClassReader(
101: uniqueTypeName);
102: if (reader == null) {
103: return null;
104: }
105: MethodSearchingVisitor visitor = new MethodSearchingVisitor(
106: method);
107: reader.accept(visitor, true);
108: if (visitor.methodFound) {
109: return uniqueTypeName;
110: }
111: if (visitor.interfaces != null) {
112: for (String anInterface : visitor.interfaces) {
113: String owner = findMethodOwner(anInterface, method);
114: if (owner != null) {
115: return owner;
116: }
117: }
118: }
119: return null;
120: }
121:
122: private static class MethodSearchingVisitor extends EmptyVisitor {
123:
124: private final ObjectMethod method;
125: public boolean methodFound;
126: public String[] interfaces;
127:
128: public MethodSearchingVisitor(ObjectMethod method) {
129: this .method = method;
130: }
131:
132: public void visit(int version, int access, String name,
133: String signature, String super Name, String[] interfaces) {
134: this .interfaces = interfaces;
135: }
136:
137: public MethodVisitor visitMethod(int access, String name,
138: String desc, String signature, String[] exceptions) {
139: if (method.equals(name, desc)) {
140: methodFound = true;
141: }
142: return null;
143: }
144: }
145:
146: private static class ObjectMethod {
147:
148: public final String name;
149: public final String desc;
150:
151: public ObjectMethod(Class returnType, String name,
152: Class... parameterTypes) {
153: this .name = name;
154: this .desc = TransformerTools.descriptor(returnType,
155: parameterTypes);
156: }
157:
158: public boolean equals(String name, String desc) {
159: return name.equals(this.name) && desc.equals(this.desc);
160: }
161: }
162:
163: }
|