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 java.util.*;
034: import net.sf.retrotranslator.runtime.asm.*;
035: import net.sf.retrotranslator.runtime.impl.*;
036:
037: /**
038: * @author Taras Puchko
039: */
040: class ReferenceVerifyingVisitor extends GenericClassVisitor {
041:
042: private final ClassVersion target;
043: private final TargetEnvironment environment;
044: private final SystemLogger logger;
045: private Set<String> warnings;
046:
047: public ReferenceVerifyingVisitor(ClassVersion target,
048: TargetEnvironment environment, SystemLogger logger) {
049: super (new EmptyVisitor());
050: this .target = target;
051: this .environment = environment;
052: this .logger = logger;
053: }
054:
055: public int verify(byte[] bytes) {
056: warnings = new LinkedHashSet<String>();
057: new ClassReader(bytes).accept(this , true);
058: return warnings.size();
059: }
060:
061: public void visit(int version, int access, String name,
062: String signature, String super Name, String[] interfaces) {
063: checkVersion(version, name);
064: super .visit(version, access, name, signature, super Name,
065: interfaces);
066: }
067:
068: private void checkVersion(int version, String name) {
069: if (target.isBefore(version)) {
070: println("Incompatible class: "
071: + RuntimeTools.getDisplayClassName(name));
072: }
073: }
074:
075: protected String typeName(String s) {
076: if (s == null)
077: return null;
078: try {
079: environment.getClassReader(s);
080: } catch (ClassNotFoundException e) {
081: printClassNotFound(e);
082: }
083: return s;
084: }
085:
086: private void printClassNotFound(ClassNotFoundException e) {
087: println("Class not found: "
088: + RuntimeTools.getDisplayClassName(e.getMessage()));
089: }
090:
091: protected void visitFieldInstruction(MethodVisitor visitor,
092: int opcode, String owner, String name, String desc) {
093: super .visitFieldInstruction(visitor, opcode, owner, name, desc);
094: boolean stat = (opcode == Opcodes.GETSTATIC || opcode == Opcodes.PUTSTATIC);
095: try {
096: int found = findMember(false, stat, name, desc, owner);
097: if (found == 0) {
098: println(getFieldInfo(owner, stat, name, desc,
099: "not found"));
100: } else if (found > 1) {
101: println(getFieldInfo(owner, stat, name, desc,
102: "duplicated"));
103: }
104: } catch (ClassNotFoundException e) {
105: cannotVerify(getFieldInfo(owner, stat, name, desc,
106: "not verified"), e);
107: }
108: }
109:
110: protected void visitMethodInstruction(MethodVisitor visitor,
111: int opcode, String owner, String name, String desc) {
112: super
113: .visitMethodInstruction(visitor, opcode, owner, name,
114: desc);
115: if (owner.startsWith("["))
116: return;
117: boolean stat = (opcode == Opcodes.INVOKESTATIC);
118: try {
119: int found = findMember(true, stat, name, desc, owner);
120: if (found == 0) {
121: println(getMethodInfo(owner, stat, name, desc,
122: "not found"));
123: } else if (found > 1) {
124: println(getMethodInfo(owner, stat, name, desc,
125: "duplicated"));
126: }
127: } catch (ClassNotFoundException e) {
128: cannotVerify(getMethodInfo(owner, stat, name, desc,
129: "not verified"), e);
130: }
131: }
132:
133: private int findMember(boolean method, boolean stat, String name,
134: String desc, String owner) throws ClassNotFoundException {
135: return new MemberFinder(environment, method, stat, name, desc) {
136: public void visit(int version, int access, String name,
137: String signature, String super Name,
138: String[] interfaces) {
139: checkVersion(version, name);
140: super .visit(version, access, name, signature,
141: super Name, interfaces);
142: }
143: }.findIn(owner, null);
144: }
145:
146: private void cannotVerify(String text, ClassNotFoundException e) {
147: printClassNotFound(e);
148: println(text);
149: }
150:
151: private void println(String text) {
152: if (!warnings.contains(text)) {
153: warnings.add(text);
154: logger.logForFile(Level.WARNING, text);
155: }
156: }
157:
158: private static String getFieldInfo(String owner, boolean stat,
159: String name, String desc, String message) {
160: StringBuffer buffer = new StringBuffer("Field ")
161: .append(message).append(": ");
162: if (stat)
163: buffer.append("static ");
164: buffer.append(Type.getType(desc).getClassName()).append(' ');
165: buffer.append(RuntimeTools.getDisplayClassName(owner)).append(
166: '.').append(name);
167: return buffer.toString();
168: }
169:
170: private static String getMethodInfo(String owner, boolean stat,
171: String name, String desc, String message) {
172: StringBuffer buffer = new StringBuffer();
173: if (name.equals(RuntimeTools.CONSTRUCTOR_NAME)) {
174: buffer.append("Constructor ").append(message).append(": ");
175: buffer.append(RuntimeTools.getDisplayClassName(owner));
176: } else {
177: buffer.append("Method ").append(message).append(": ");
178: if (stat)
179: buffer.append("static ");
180: buffer.append(Type.getReturnType(desc).getClassName());
181: buffer.append(' ').append(
182: RuntimeTools.getDisplayClassName(owner))
183: .append('.').append(name);
184: }
185: buffer.append('(');
186: boolean first = true;
187: for (Type type : Type.getArgumentTypes(desc)) {
188: buffer.append(first ? "" : ",").append(type.getClassName());
189: first = false;
190: }
191: return buffer.append(')').toString();
192: }
193:
194: }
|