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.BytecodeTransformer;
036:
037: /**
038: * @author Taras Puchko
039: */
040: class ClassTransformer implements BytecodeTransformer {
041:
042: private final boolean lazy;
043: private final boolean stripsign;
044: private final boolean stripannot;
045: private final boolean retainflags;
046: private final ReflectionMode reflectionMode;
047: private final EmbeddingConverter converter;
048: private final SystemLogger logger;
049: private final ReplacementLocatorFactory factory;
050:
051: public ClassTransformer(boolean lazy, boolean stripsign,
052: boolean stripannot, boolean retainflags,
053: ReflectionMode reflectionMode, SystemLogger logger,
054: EmbeddingConverter converter,
055: ReplacementLocatorFactory factory) {
056: this .lazy = lazy;
057: this .stripsign = stripsign;
058: this .stripannot = stripannot;
059: this .retainflags = retainflags;
060: this .reflectionMode = reflectionMode;
061: this .converter = converter;
062: this .logger = logger;
063: this .factory = factory;
064: }
065:
066: public byte[] transform(byte[] bytes, int offset, int length) {
067: ClassVersion target = factory.getMode().getTarget();
068: if (lazy
069: && !target.isBefore(TransformerTools.getClassVersion(
070: bytes, offset))) {
071: if (offset == 0 && length == bytes.length)
072: return bytes;
073: byte[] result = new byte[length];
074: System.arraycopy(bytes, offset, result, 0, length);
075: return result;
076: }
077: ReplacementLocator locator = factory.getLocator();
078: MethodCounter counter = new MethodCounter();
079: Map<String, List<InstantiationPoint>> pointListMap = new HashMap<String, List<InstantiationPoint>>();
080: ClassWriter classWriter = new ClassWriter(true);
081: ClassVisitor visitor = new InstantiationAnalysisVisitor(
082: classWriter, locator, pointListMap, logger);
083: visitor = new DuplicateInterfacesVisitor(new VersionVisitor(
084: visitor, target), logger, counter);
085: if (target.isBefore(ClassVersion.VERSION_12)) {
086: visitor = new MirandaMethodsVisitor(visitor, locator);
087: }
088: if (target.isBefore(ClassVersion.VERSION_13)) {
089: visitor = new InheritedConstantVisitor(
090: new SynchronizedBlockVisitor(visitor), locator);
091: }
092: if (target.isBefore(ClassVersion.VERSION_14)) {
093: visitor = new InnerClassVisitor(visitor);
094: }
095: if (target.isBefore(ClassVersion.VERSION_15)) {
096: visitor = new ObjectMethodsVisitor(new ClassLiteralVisitor(
097: visitor), locator);
098: }
099: if (!factory.isRetainapi()) {
100: visitor = new SpecificReplacementVisitor(visitor, target,
101: locator, factory.getMode());
102: }
103: visitor = new GeneralReplacementVisitor(visitor, locator);
104: new ClassReader(bytes, offset, length).accept(visitor, false);
105: if (counter.containsDuplicates()) {
106: byte[] bytecode = classWriter.toByteArray();
107: classWriter = new ClassWriter(true);
108: pointListMap.clear();
109: visitor = new InstantiationAnalysisVisitor(classWriter,
110: locator, pointListMap, logger);
111: new ClassReader(bytecode).accept(
112: new DuplicateMethodsVisitor(visitor, logger,
113: counter), false);
114: }
115: if (!pointListMap.isEmpty()) {
116: byte[] bytecode = classWriter.toByteArray();
117: classWriter = new ClassWriter(true);
118: new ClassReader(bytecode).accept(
119: new InstantiationReplacementVisitor(classWriter,
120: pointListMap), false);
121: }
122: if (converter != null) {
123: byte[] bytecode = classWriter.toByteArray();
124: classWriter = new ClassWriter(true);
125: new ClassReader(bytecode).accept(new PrefixingVisitor(
126: classWriter, converter), false);
127: }
128: if (reflectionMode == ReflectionMode.SAFE) {
129: MemberReplacement replacement = ReflectionInitVisitor
130: .getMethodReplacement(locator);
131: if (replacement != null) {
132: byte[] bytecode = classWriter.toByteArray();
133: ReflectionDataVisitor dataVisitor = new ReflectionDataVisitor();
134: new ClassReader(bytecode).accept(dataVisitor, true);
135: classWriter = new ClassWriter(true);
136: visitor = new ReflectionInitVisitor(classWriter,
137: replacement, converter, dataVisitor
138: .toByteArray());
139: new ClassReader(bytecode).accept(visitor, false);
140: }
141: }
142: if (stripsign || stripannot) {
143: byte[] bytecode = classWriter.toByteArray();
144: classWriter = new ClassWriter(true);
145: ClassVisitor stripVisitor = classWriter;
146: if (stripsign) {
147: stripVisitor = new SignatureStrippingVisitor(
148: stripVisitor);
149: }
150: if (stripannot) {
151: stripVisitor = new AnnotationStrippingVisitor(
152: stripVisitor);
153: }
154: new ClassReader(bytecode).accept(stripVisitor, false);
155: }
156: return classWriter.toByteArray(target
157: .isBefore(ClassVersion.VERSION_15)
158: && !retainflags);
159: }
160:
161: }
|