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