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.org.objectweb.asm.ClassWriter;
021    import org.jetbrains.org.objectweb.asm.util.TraceClassVisitor;
022    
023    import java.io.PrintWriter;
024    import java.io.StringWriter;
025    
026    @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
027    public class ClassBuilderFactories {
028        @NotNull
029        public static ClassBuilderFactory THROW_EXCEPTION = new ClassBuilderFactory() {
030            @NotNull
031            @Override
032            public ClassBuilderMode getClassBuilderMode() {
033                return ClassBuilderMode.FULL;
034            }
035    
036            @Override
037            public ClassBuilder newClassBuilder() {
038                throw new IllegalStateException();
039            }
040    
041            @Override
042            public String asText(ClassBuilder builder) {
043                throw new IllegalStateException();
044            }
045    
046            @Override
047            public byte[] asBytes(ClassBuilder builder) {
048                throw new IllegalStateException();
049            }
050        };
051    
052        @NotNull
053        public static ClassBuilderFactory TEST = new ClassBuilderFactory() {
054            @NotNull
055            @Override
056            public ClassBuilderMode getClassBuilderMode() {
057                return ClassBuilderMode.FULL;
058            }
059    
060            @Override
061            public ClassBuilder newClassBuilder() {
062                return new TraceBuilder(new BinaryClassWriter());
063            }
064    
065            @Override
066            public String asText(ClassBuilder builder) {
067                TraceClassVisitor visitor = (TraceClassVisitor) builder.getVisitor();
068    
069                StringWriter writer = new StringWriter();
070                visitor.p.print(new PrintWriter(writer));
071    
072                return writer.toString();
073            }
074    
075            @Override
076            public byte[] asBytes(ClassBuilder builder) {
077                return ((TraceBuilder) builder).binary.toByteArray();
078            }
079        };
080    
081        @NotNull
082        public static ClassBuilderFactory BINARIES = new ClassBuilderFactory() {
083            @NotNull
084            @Override
085            public ClassBuilderMode getClassBuilderMode() {
086                return ClassBuilderMode.FULL;
087            }
088    
089            @Override
090            public ClassBuilder newClassBuilder() {
091                return new AbstractClassBuilder.Concrete(new BinaryClassWriter());
092            }
093    
094            @Override
095            public String asText(ClassBuilder builder) {
096                throw new UnsupportedOperationException("BINARIES generator asked for text");
097            }
098    
099            @Override
100            public byte[] asBytes(ClassBuilder builder) {
101                ClassWriter visitor = (ClassWriter) builder.getVisitor();
102                return visitor.toByteArray();
103            }
104        };
105    
106        private ClassBuilderFactories() {
107        }
108    
109        private static class BinaryClassWriter extends ClassWriter {
110            public BinaryClassWriter() {
111                super(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
112            }
113    
114            @Override
115            protected String getCommonSuperClass(String type1, String type2) {
116                try {
117                    return super.getCommonSuperClass(type1, type2);
118                }
119                catch (Throwable t) {
120                    // @todo we might need at some point do more sophisticated handling
121                    return "java/lang/Object";
122                }
123            }
124        }
125    
126        private static class TraceBuilder extends AbstractClassBuilder.Concrete {
127            public final BinaryClassWriter binary;
128    
129            public TraceBuilder(BinaryClassWriter binary) {
130                super(new TraceClassVisitor(binary, new PrintWriter(new StringWriter())));
131                this.binary = binary;
132            }
133        }
134    }