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 static net.sf.retrotranslator.runtime.impl.RuntimeTools.CONSTRUCTOR_NAME;
037:
038: /**
039: * @author Taras Puchko
040: */
041: class InnerClassVisitor extends ClassAdapter {
042:
043: private String this Name;
044: private String super Name;
045:
046: public InnerClassVisitor(ClassVisitor visitor) {
047: super (visitor);
048: }
049:
050: public void visit(int version, int access, String name,
051: String signature, String super Name, String[] interfaces) {
052: this .this Name = name;
053: this .super Name = super Name;
054: super .visit(version, access, name, signature, super Name,
055: interfaces);
056: }
057:
058: public MethodVisitor visitMethod(int access, String name,
059: String desc, String signature, String[] exceptions) {
060: MethodVisitor methodVisitor = super .visitMethod(access, name,
061: desc, signature, exceptions);
062: if (methodVisitor != null && super Name != null
063: && name.equals(CONSTRUCTOR_NAME)) {
064: return new InnerClassMethodVisitor(methodVisitor);
065: }
066: return methodVisitor;
067: }
068:
069: private static class FieldAssignment {
070:
071: public final int localVariable;
072: public final String fieldName;
073: public final String fieldType;
074:
075: public FieldAssignment(int localVariable, String fieldName,
076: String fieldType) {
077: this .localVariable = localVariable;
078: this .fieldName = fieldName;
079: this .fieldType = fieldType;
080: }
081:
082: }
083:
084: private class InnerClassMethodVisitor extends AbstractMethodVisitor {
085:
086: private boolean initialized;
087: private int this Count;
088: private int super Count;
089:
090: private boolean this Loaded;
091: private Integer localVariable;
092: private List<FieldAssignment> assignments;
093:
094: public InnerClassMethodVisitor(MethodVisitor visitor) {
095: super (visitor);
096: }
097:
098: protected void flush() {
099: if (this Loaded) {
100: mv.visitVarInsn(ALOAD, 0);
101: this Loaded = false;
102: if (localVariable != null) {
103: mv.visitVarInsn(ALOAD, localVariable);
104: localVariable = null;
105: }
106: }
107: if (initialized && assignments != null) {
108: for (FieldAssignment assignment : assignments) {
109: mv.visitVarInsn(ALOAD, 0);
110: mv.visitVarInsn(ALOAD, assignment.localVariable);
111: mv.visitFieldInsn(PUTFIELD, this Name,
112: assignment.fieldName, assignment.fieldType);
113: }
114: assignments = null;
115: }
116: }
117:
118: public void visitVarInsn(int opcode, int var) {
119: if (!initialized && opcode == ALOAD
120: && localVariable == null) {
121: if (this Loaded) {
122: localVariable = var;
123: return;
124: }
125: if (var == 0) {
126: this Loaded = true;
127: return;
128: }
129: }
130: super .visitVarInsn(opcode, var);
131: }
132:
133: public void visitFieldInsn(int opcode, String owner,
134: String name, String desc) {
135: if (!initialized && opcode == PUTFIELD
136: && localVariable != null && owner.equals(this Name)) {
137: if (assignments == null) {
138: assignments = new ArrayList<FieldAssignment>();
139: }
140: assignments.add(new FieldAssignment(localVariable,
141: name, desc));
142: this Loaded = false;
143: localVariable = null;
144: return;
145: }
146: super .visitFieldInsn(opcode, owner, name, desc);
147: }
148:
149: public void visitTypeInsn(int opcode, String desc) {
150: super .visitTypeInsn(opcode, desc);
151: if (initialized || opcode != NEW) {
152: return;
153: }
154: if (desc.equals(this Name)) {
155: this Count++;
156: }
157: if (desc.equals(super Name)) {
158: super Count++;
159: }
160: }
161:
162: public void visitMethodInsn(int opcode, String owner,
163: String name, String desc) {
164: super .visitMethodInsn(opcode, owner, name, desc);
165: if (initialized || opcode != INVOKESPECIAL
166: || !name.equals(CONSTRUCTOR_NAME)) {
167: return;
168: }
169: if (owner.equals(this Name)) {
170: if (this Count > 0) {
171: this Count--;
172: } else {
173: initialized = true;
174: }
175: }
176: if (owner.equals(super Name)) {
177: if (super Count > 0) {
178: super Count--;
179: } else {
180: initialized = true;
181: }
182: }
183: }
184:
185: public void visitEnd() {
186: super .visitEnd();
187: if (!initialized) {
188: throw new IllegalStateException(
189: "Constructor not called.");
190: }
191: }
192: }
193:
194: }
|