001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.jet.codegen;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.asm4.ClassWriter;
021    import org.jetbrains.asm4.util.TraceClassVisitor;
022    
023    import java.io.PrintWriter;
024    import java.io.StringWriter;
025    
026    @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
027    public class ClassBuilderFactories {
028    
029        public static ClassBuilderFactory TEST = new ClassBuilderFactory() {
030            @NotNull
031            @Override
032            public ClassBuilderMode getClassBuilderMode() {
033                return ClassBuilderMode.FULL;
034            }
035    
036            @Override
037            public ClassBuilder newClassBuilder() {
038                return new TraceBuilder(new BinaryClassWriter());
039            }
040    
041            @Override
042            public String asText(ClassBuilder builder) {
043                TraceClassVisitor visitor = (TraceClassVisitor) builder.getVisitor();
044    
045                StringWriter writer = new StringWriter();
046                visitor.p.print(new PrintWriter(writer));
047    
048                return writer.toString();
049            }
050    
051            @Override
052            public byte[] asBytes(ClassBuilder builder) {
053                return ((TraceBuilder) builder).binary.toByteArray();
054            }
055        };
056    
057        public static ClassBuilderFactory BINARIES = new ClassBuilderFactory() {
058            @NotNull
059            @Override
060            public ClassBuilderMode getClassBuilderMode() {
061                return ClassBuilderMode.FULL;
062            }
063    
064            @Override
065            public ClassBuilder newClassBuilder() {
066                return new AbstractClassBuilder.Concrete(new BinaryClassWriter());
067            }
068    
069            @Override
070            public String asText(ClassBuilder builder) {
071                throw new UnsupportedOperationException("BINARIES generator asked for text");
072            }
073    
074            @Override
075            public byte[] asBytes(ClassBuilder builder) {
076                ClassWriter visitor = (ClassWriter) builder.getVisitor();
077                return visitor.toByteArray();
078            }
079        };
080    
081        private ClassBuilderFactories() {
082        }
083    
084        private static class BinaryClassWriter extends ClassWriter {
085            public BinaryClassWriter() {
086                super(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
087            }
088    
089            @Override
090            protected String getCommonSuperClass(String type1, String type2) {
091                try {
092                    return super.getCommonSuperClass(type1, type2);
093                }
094                catch (Throwable t) {
095                    // @todo we might need at some point do more sophisticated handling
096                    return "java/lang/Object";
097                }
098            }
099        }
100    
101        private static class TraceBuilder extends AbstractClassBuilder.Concrete {
102            public final BinaryClassWriter binary;
103    
104            public TraceBuilder(BinaryClassWriter binary) {
105                super(new TraceClassVisitor(binary, new PrintWriter(new StringWriter())));
106                this.binary = binary;
107            }
108        }
109    }