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 TEXT = 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 ClassBuilder.Concrete(new TraceClassVisitor(new PrintWriter(new StringWriter())));
067            }
068    
069            @Override
070            public String asText(ClassBuilder builder) {
071                TraceClassVisitor visitor = (TraceClassVisitor) builder.getVisitor();
072    
073                StringWriter writer = new StringWriter();
074                visitor.p.print(new PrintWriter(writer));
075    
076                return writer.toString();
077            }
078    
079            @Override
080            public byte[] asBytes(ClassBuilder builder) {
081                throw new UnsupportedOperationException("TEXT generator asked for bytes");
082            }
083        };
084    
085        public static ClassBuilderFactory BINARIES = new ClassBuilderFactory() {
086            @NotNull
087            @Override
088            public ClassBuilderMode getClassBuilderMode() {
089                return ClassBuilderMode.FULL;
090            }
091    
092            @Override
093            public ClassBuilder newClassBuilder() {
094                return new ClassBuilder.Concrete(new BinaryClassWriter());
095            }
096    
097            @Override
098            public String asText(ClassBuilder builder) {
099                throw new UnsupportedOperationException("BINARIES generator asked for text");
100            }
101    
102            @Override
103            public byte[] asBytes(ClassBuilder builder) {
104                ClassWriter visitor = (ClassWriter) builder.getVisitor();
105                return visitor.toByteArray();
106            }
107        };
108    
109        private ClassBuilderFactories() {
110        }
111    
112        private static class BinaryClassWriter extends ClassWriter {
113            public BinaryClassWriter() {
114                super(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
115            }
116    
117            @Override
118            protected String getCommonSuperClass(String type1, String type2) {
119                try {
120                    return super.getCommonSuperClass(type1, type2);
121                }
122                catch (Throwable t) {
123                    // @todo we might need at some point do more sophisticated handling
124                    return "java/lang/Object";
125                }
126            }
127        }
128    
129        private static class TraceBuilder extends ClassBuilder.Concrete {
130            public final BinaryClassWriter binary;
131    
132            public TraceBuilder(BinaryClassWriter binary) {
133                super(new TraceClassVisitor(binary, new PrintWriter(new StringWriter())));
134                this.binary = binary;
135            }
136        }
137    }