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:
037: /**
038: * @author Taras Puchko
039: */
040: class ClassLiteralVisitor extends ClassAdapter {
041:
042: private static final Map<Integer, Integer> primitiveTypes = getPrimitiveTypes();
043:
044: private Set<String> currentFieldNames = new HashSet<String>();
045: private Set<String> syntheticFieldNames = new HashSet<String>();
046: private String currentClassName;
047: private boolean isInterface;
048:
049: public ClassLiteralVisitor(final ClassVisitor cv) {
050: super (cv);
051: }
052:
053: public void visit(final int version, final int access,
054: final String name, final String signature,
055: final String super Name, final String[] interfaces) {
056: currentClassName = name;
057: isInterface = (access & ACC_INTERFACE) != 0;
058: super .visit(version, access, name, signature, super Name,
059: interfaces);
060: }
061:
062: public void visitEnd() {
063: for (String fieldName : syntheticFieldNames) {
064: if (!currentFieldNames.contains(fieldName)) {
065: cv.visitField(ACC_STATIC + ACC_SYNTHETIC, fieldName,
066: Type.getDescriptor(Class.class), null, null)
067: .visitEnd();
068: }
069: }
070: super .visitEnd();
071: }
072:
073: public FieldVisitor visitField(final int access, final String name,
074: final String desc, final String signature,
075: final Object value) {
076: currentFieldNames.add(name);
077: return super .visitField(access, name, desc, signature, value);
078: }
079:
080: public MethodVisitor visitMethod(final int access,
081: final String name, final String desc,
082: final String signature, final String[] exceptions) {
083: MethodVisitor visitor = super .visitMethod(access, name, desc,
084: signature, exceptions);
085: return visitor == null ? null : new MethodAdapter(visitor) {
086:
087: public void visitLdcInsn(final Object cst) {
088: if (cst instanceof Type) {
089: visitClassLiteral((Type) cst);
090: } else {
091: super .visitLdcInsn(cst);
092: }
093: }
094:
095: private void visitClassLiteral(Type type) {
096: if (isInterface) {
097: loadClassLiteral(type);
098: return;
099: }
100: String fieldName = getFieldName(type);
101: syntheticFieldNames.add(fieldName);
102: mv.visitFieldInsn(GETSTATIC, currentClassName,
103: fieldName, Type.getDescriptor(Class.class));
104: mv.visitInsn(DUP);
105: Label label = new Label();
106: visitJumpInsn(IFNONNULL, label);
107: mv.visitInsn(POP);
108: loadClassLiteral(type);
109: mv.visitInsn(DUP);
110: visitFieldInsn(PUTSTATIC, currentClassName, fieldName,
111: Type.getDescriptor(Class.class));
112: visitLabel(label);
113: }
114:
115: private void loadClassLiteral(Type type) {
116: mv.visitInsn(ICONST_0);
117: visitNewArray(type);
118: mv.visitMethodInsn(INVOKEVIRTUAL, Type
119: .getInternalName(Object.class), "getClass",
120: TransformerTools.descriptor(Class.class));
121: if (type.getSort() != Type.ARRAY) {
122: mv.visitMethodInsn(INVOKEVIRTUAL, Type
123: .getInternalName(Class.class),
124: "getComponentType", TransformerTools
125: .descriptor(Class.class));
126: }
127: }
128:
129: private void visitNewArray(Type type) {
130: if (type.getSort() != Type.ARRAY) {
131: mv.visitTypeInsn(ANEWARRAY, type.getInternalName());
132: } else if (type.getDimensions() != 1) {
133: mv.visitTypeInsn(ANEWARRAY, type.toString()
134: .substring(1));
135: } else {
136: Type elementType = type.getElementType();
137: if (elementType.getSort() == Type.OBJECT) {
138: mv.visitTypeInsn(ANEWARRAY, elementType
139: .getInternalName());
140: } else {
141: mv.visitIntInsn(NEWARRAY, primitiveTypes
142: .get(elementType.getSort()));
143: }
144: }
145: }
146:
147: };
148: }
149:
150: private static String getFieldName(Type type) {
151: String var = type.getDescriptor();
152: if (var.startsWith("L")) {
153: var = "class$" + var.substring(1);
154: } else if (var.startsWith("[")) {
155: var = "array$" + var.substring(1);
156: }
157: if (var.endsWith(";")) {
158: var = var.substring(0, var.length() - 1);
159: }
160: return var.replace('[', '$').replace('/', '$');
161: }
162:
163: private static Map<Integer, Integer> getPrimitiveTypes() {
164: Map<Integer, Integer> types = new HashMap<Integer, Integer>();
165: types.put(Type.BOOLEAN, T_BOOLEAN);
166: types.put(Type.CHAR, T_CHAR);
167: types.put(Type.FLOAT, T_FLOAT);
168: types.put(Type.DOUBLE, T_DOUBLE);
169: types.put(Type.BYTE, T_BYTE);
170: types.put(Type.SHORT, T_SHORT);
171: types.put(Type.INT, T_INT);
172: types.put(Type.LONG, T_LONG);
173: return types;
174: }
175: }
|