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 static net.sf.retrotranslator.runtime.asm.Opcodes.*;
036: import net.sf.retrotranslator.runtime.impl.RuntimeTools;
037: import static net.sf.retrotranslator.runtime.impl.RuntimeTools.CONSTRUCTOR_NAME;
038:
039: /**
040: * @author Taras Puchko
041: */
042: class InstantiationAnalysisVisitor extends ClassAdapter {
043:
044: private final ReplacementLocator locator;
045: private final Map<String, List<InstantiationPoint>> pointListMap;
046: private final SystemLogger logger;
047: private String this Name;
048: private String super Name;
049:
050: public InstantiationAnalysisVisitor(ClassVisitor visitor,
051: ReplacementLocator locator,
052: Map<String, List<InstantiationPoint>> pointListMap,
053: SystemLogger logger) {
054: super (visitor);
055: this .locator = locator;
056: this .pointListMap = pointListMap;
057: this .logger = logger;
058: }
059:
060: public void visit(final int version, final int access,
061: final String name, final String signature,
062: final String super Name, final String[] interfaces) {
063: super .visit(version, access, name, signature, super Name,
064: interfaces);
065: this .this Name = name;
066: this .super Name = super Name;
067: }
068:
069: public MethodVisitor visitMethod(final int access,
070: final String name, final String desc,
071: final String signature, final String[] exceptions) {
072: MethodVisitor visitor = super .visitMethod(access, name, desc,
073: signature, exceptions);
074: return visitor == null ? null
075: : new InstantiationAnalysisMethodVisitor(visitor, name,
076: desc);
077: }
078:
079: private class InstantiationAnalysisMethodVisitor extends
080: AbstractMethodVisitor {
081:
082: private final List<InstantiationPoint> points = new ArrayList<InstantiationPoint>();
083: private final Map<Label, InstantiationFrame> frames = new HashMap<Label, InstantiationFrame>();
084: private InstantiationFrame currentFrame;
085: private final String methodName;
086: private final String methodDesc;
087: private boolean active = true;
088: private InstantiationPoint currentPoint;
089: private int allocationIndex;
090: private int duplicationIndex;
091: private int initializationIndex;
092:
093: public InstantiationAnalysisMethodVisitor(
094: MethodVisitor visitor, String methodName,
095: String methodDesc) {
096: super (visitor);
097: this .methodName = methodName;
098: this .methodDesc = methodDesc;
099: this .currentFrame = new InstantiationFrame(!methodName
100: .equals(CONSTRUCTOR_NAME));
101: }
102:
103: protected void flush() {
104: currentPoint = null;
105: }
106:
107: public void visitLabel(Label label) {
108: super .visitLabel(label);
109: InstantiationFrame frame = frames.remove(label);
110: if (frame != null) {
111: currentFrame = frame;
112: }
113: }
114:
115: public void visitJumpInsn(int opcode, Label label) {
116: super .visitJumpInsn(opcode, label);
117: saveFrame(label);
118: }
119:
120: public void visitLookupSwitchInsn(Label dflt, int[] keys,
121: Label[] labels) {
122: super .visitLookupSwitchInsn(dflt, keys, labels);
123: saveFrames(dflt, labels);
124: }
125:
126: public void visitTableSwitchInsn(int min, int max, Label dflt,
127: Label[] labels) {
128: super .visitTableSwitchInsn(min, max, dflt, labels);
129: saveFrames(dflt, labels);
130: }
131:
132: private void saveFrames(Label label, Label[] labels) {
133: saveFrame(label);
134: for (Label currentLabel : labels) {
135: saveFrame(currentLabel);
136: }
137: }
138:
139: private void saveFrame(Label label) {
140: if (!frames.containsKey(label)) {
141: frames.put(label, new InstantiationFrame(currentFrame));
142: }
143: }
144:
145: public void visitTypeInsn(int opcode, String desc) {
146: super .visitTypeInsn(opcode, desc);
147: if (opcode == NEW && active) {
148: currentPoint = new InstantiationPoint(desc,
149: ++allocationIndex);
150: currentFrame.addLast(currentPoint);
151: }
152: }
153:
154: public void visitInsn(int opcode) {
155: if (opcode == DUP && active) {
156: duplicationIndex++;
157: if (currentPoint != null) {
158: currentPoint.setDuplicationIndex(duplicationIndex);
159: }
160: }
161: super .visitInsn(opcode);
162: }
163:
164: public void visitMethodInsn(int opcode, String owner,
165: String name, String desc) {
166: super .visitMethodInsn(opcode, owner, name, desc);
167: if (opcode != INVOKESPECIAL
168: || !name.equals(CONSTRUCTOR_NAME) || !active) {
169: return;
170: }
171: initializationIndex++;
172: InstantiationPoint point = currentFrame.pollLast();
173: if (point != null) {
174: if (!owner.equals(point.getInternalName())
175: || point.getInitializationIndex() != 0) {
176: active = false;
177: return;
178: }
179: } else {
180: if (currentFrame.isInitialized()
181: || (!owner.equals(this Name) && !owner
182: .equals(super Name))) {
183: active = false;
184: return;
185: }
186: currentFrame.setInitialized(true);
187: }
188: ClassReplacement classReplacement = locator
189: .getReplacement(owner);
190: if (classReplacement == null) {
191: return;
192: }
193: MemberReplacement memberReplacement = classReplacement
194: .getInstantiationReplacements().get(desc);
195: if (memberReplacement == null) {
196: return;
197: }
198: if (point == null || point.getDuplicationIndex() == 0) {
199: logger.logForFile(Level.WARNING, "Cannot translate "
200: + RuntimeTools.getDisplayClassName(owner)
201: + " constructor call in " + methodName
202: + " method.");
203: return;
204: }
205: point.setInitializationIndex(initializationIndex);
206: point.setReplacement(memberReplacement);
207: points.add(point);
208: }
209:
210: public void visitEnd() {
211: super .visitEnd();
212: if (active) {
213: if (!points.isEmpty()) {
214: pointListMap.put(methodName + methodDesc, points);
215: }
216: } else {
217: logger.logForFile(Level.INFO, "Cannot analyze "
218: + methodName + " method.");
219: }
220: }
221: }
222:
223: }
|