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