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