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.RuntimeTools;
036:
037: /**
038: * @author Taras Puchko
039: */
040: class ReflectionInitVisitor extends ClassAdapter {
041:
042: private static final String CLASS_NAME = Type
043: .getInternalName(Class.class);
044: private static final MemberKey SET_ENCODED_METADATA_KEY = new MemberKey(
045: true, "setEncodedMetadata", TransformerTools.descriptor(
046: void.class, Class.class, String.class));
047:
048: private final EmbeddingConverter converter;
049: private final byte[] metadata;
050: private MemberReplacement replacement;
051: private boolean initialized;
052: private String className;
053:
054: public ReflectionInitVisitor(ClassVisitor visitor,
055: MemberReplacement replacement,
056: EmbeddingConverter converter, byte[] metadata) {
057: super (visitor);
058: this .converter = converter;
059: this .metadata = metadata;
060: this .replacement = replacement;
061: }
062:
063: public static MemberReplacement getMethodReplacement(
064: ReplacementLocator locator) {
065: ClassReplacement replacement = locator
066: .getReplacement(CLASS_NAME);
067: return replacement == null ? null : replacement
068: .getMethodReplacements().get(SET_ENCODED_METADATA_KEY);
069: }
070:
071: public void visit(int version, int access, String name,
072: String signature, String super Name, String[] interfaces) {
073: className = name;
074: super .visit(version, access, name, signature, super Name,
075: interfaces);
076: }
077:
078: public MethodVisitor visitMethod(int access, String name,
079: String desc, String signature, String[] exceptions) {
080: MethodVisitor visitor = super .visitMethod(access, name, desc,
081: signature, exceptions);
082: if (name.equals(RuntimeTools.STATIC_NAME)) {
083: initialized = true;
084: return new ClassInitMethodVisitor(visitor);
085: }
086: return visitor;
087: }
088:
089: public void visitEnd() {
090: if (!initialized) {
091: MethodVisitor visitor = new ClassInitMethodVisitor(super
092: .visitMethod(ACC_STATIC, RuntimeTools.STATIC_NAME,
093: TransformerTools.descriptor(void.class),
094: null, null));
095: visitor.visitCode();
096: visitor.visitInsn(RETURN);
097: visitor.visitMaxs(0, 0);
098: visitor.visitEnd();
099: }
100: super .visitEnd();
101: }
102:
103: private String getEncodedMetadata() {
104: char[] chars = new char[metadata.length];
105: for (int i = 0; i < chars.length; i++) {
106: chars[i] = (char) (127 - metadata[i]);
107: }
108: return new String(chars);
109: }
110:
111: private class ClassInitMethodVisitor extends MethodAdapter {
112:
113: private ClassInitMethodVisitor(MethodVisitor mv) {
114: super (mv);
115: }
116:
117: public void visitCode() {
118: super .visitCode();
119: mv.visitInsn(ICONST_0);
120: mv.visitTypeInsn(ANEWARRAY, className);
121: mv.visitMethodInsn(INVOKEVIRTUAL, Type
122: .getInternalName(Object.class), "getClass",
123: TransformerTools.descriptor(Class.class));
124: mv.visitMethodInsn(INVOKEVIRTUAL, Type
125: .getInternalName(Class.class), "getComponentType",
126: TransformerTools.descriptor(Class.class));
127: mv.visitLdcInsn(getEncodedMetadata());
128: String owner = replacement.getOwner();
129: if (converter != null) {
130: owner = converter.convertClassName(owner);
131: }
132: mv.visitMethodInsn(INVOKESTATIC, owner, replacement
133: .getName(), replacement.getDesc());
134: }
135:
136: }
137:
138: }
|