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.annotations.Nullable;
021 import org.jetbrains.asm4.MethodVisitor;
022 import org.jetbrains.asm4.Type;
023 import org.jetbrains.jet.codegen.context.ClassContext;
024 import org.jetbrains.jet.codegen.state.GenerationState;
025 import org.jetbrains.jet.lang.descriptors.*;
026 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
027 import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
028 import org.jetbrains.jet.lang.psi.*;
029 import org.jetbrains.jet.lang.resolve.BindingContext;
030 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
031 import org.jetbrains.jet.lang.resolve.name.Name;
032
033 import java.util.Collections;
034 import java.util.List;
035
036 import static org.jetbrains.asm4.Opcodes.*;
037 import static org.jetbrains.jet.codegen.AsmUtil.genMethodThrow;
038 import static org.jetbrains.jet.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
039
040 public abstract class ClassBodyCodegen extends MemberCodegen {
041 protected final JetClassOrObject myClass;
042 protected final OwnerKind kind;
043 protected final ClassDescriptor descriptor;
044 protected final ClassBuilder v;
045 protected final ClassContext context;
046
047 private MethodVisitor clInitMethod;
048
049 private ExpressionCodegen clInitCodegen;
050
051 protected ClassBodyCodegen(
052 @NotNull JetClassOrObject aClass,
053 @NotNull ClassContext context,
054 @NotNull ClassBuilder v,
055 @NotNull GenerationState state,
056 @Nullable MemberCodegen parentCodegen
057 ) {
058 super(state, parentCodegen);
059 descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
060 myClass = aClass;
061 this.context = context;
062 this.kind = context.getContextKind();
063 this.v = v;
064 }
065
066 public void generate() {
067 generateDeclaration();
068
069 generateClassBody();
070
071 generateSyntheticParts();
072
073 generateStaticInitializer();
074
075 generateRemoveInIterator();
076
077 generateKotlinAnnotation();
078 }
079
080 protected abstract void generateDeclaration();
081
082 protected void generateKotlinAnnotation() {
083 }
084
085 protected void generateSyntheticParts() {
086 }
087
088 private void generateClassBody() {
089 FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state);
090 PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, this);
091
092 if (kind != OwnerKind.TRAIT_IMPL) {
093 //generate nested classes first and only then generate class body. It necessary to access to nested CodegenContexts
094 for (JetDeclaration declaration : myClass.getDeclarations()) {
095 if (shouldProcessFirst(declaration)) {
096 generateDeclaration(propertyCodegen, declaration);
097 }
098 }
099 }
100
101 for (JetDeclaration declaration : myClass.getDeclarations()) {
102 if (!shouldProcessFirst(declaration)) {
103 generateDeclaration(propertyCodegen, declaration);
104 }
105 }
106
107 generatePrimaryConstructorProperties(propertyCodegen, myClass);
108 }
109
110 private boolean shouldProcessFirst(JetDeclaration declaration) {
111 return false == (declaration instanceof JetProperty || declaration instanceof JetNamedFunction);
112 }
113
114
115 protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration) {
116 if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) {
117 genFunctionOrProperty(context, (JetTypeParameterListOwner) declaration, v);
118 }
119 else if (declaration instanceof JetClassOrObject) {
120 if (declaration instanceof JetEnumEntry && !enumEntryNeedSubclass(
121 state.getBindingContext(), (JetEnumEntry) declaration)) {
122 return;
123 }
124
125 genClassOrObject(context, (JetClassOrObject) declaration);
126 }
127 else if (declaration instanceof JetClassObject) {
128 genClassOrObject(context, ((JetClassObject) declaration).getObjectDeclaration());
129 }
130 }
131
132 private void generatePrimaryConstructorProperties(PropertyCodegen propertyCodegen, JetClassOrObject origin) {
133 boolean isAnnotation = origin instanceof JetClass && ((JetClass) origin).isAnnotation();
134 for (JetParameter p : getPrimaryConstructorParameters()) {
135 if (p.getValOrVarNode() != null) {
136 PropertyDescriptor propertyDescriptor = state.getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, p);
137 if (propertyDescriptor != null) {
138 if (!isAnnotation) {
139 propertyCodegen.generatePrimaryConstructorProperty(p, propertyDescriptor);
140 }
141 else {
142 propertyCodegen.generateConstructorPropertyAsMethodForAnnotationClass(p, propertyDescriptor);
143 }
144 }
145 }
146 }
147 }
148
149 protected @NotNull List<JetParameter> getPrimaryConstructorParameters() {
150 if (myClass instanceof JetClass) {
151 return ((JetClass) myClass).getPrimaryConstructorParameters();
152 }
153 return Collections.emptyList();
154 }
155
156 private void generateStaticInitializer() {
157 if (clInitMethod != null) {
158 createOrGetClInitMethod();
159
160 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
161 ExpressionCodegen codegen = createOrGetClInitCodegen();
162
163 createOrGetClInitMethod().visitInsn(RETURN);
164 FunctionCodegen.endVisit(codegen.v, "static initializer", myClass);
165 }
166 }
167 }
168
169 @Nullable
170 protected MethodVisitor createOrGetClInitMethod() {
171 if (clInitMethod == null) {
172 clInitMethod = v.newMethod(null, ACC_STATIC, "<clinit>", "()V", null, null);
173 }
174 return clInitMethod;
175 }
176
177 @Nullable
178 protected ExpressionCodegen createOrGetClInitCodegen() {
179 assert state.getClassBuilderMode() == ClassBuilderMode.FULL;
180 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
181 if (clInitCodegen == null) {
182 MethodVisitor method = createOrGetClInitMethod();
183 method.visitCode();
184 SimpleFunctionDescriptorImpl clInit =
185 new SimpleFunctionDescriptorImpl(descriptor, Collections.<AnnotationDescriptor>emptyList(),
186 Name.special("<clinit>"),
187 CallableMemberDescriptor.Kind.SYNTHESIZED);
188 clInit.initialize(null, null, Collections.<TypeParameterDescriptor>emptyList(),
189 Collections.<ValueParameterDescriptor>emptyList(), null, null, Visibilities.PRIVATE, false);
190
191 clInitCodegen = new ExpressionCodegen(method, new FrameMap(), Type.VOID_TYPE, context.intoFunction(clInit), state);
192 }
193 }
194 return clInitCodegen;
195 }
196
197 private void generateRemoveInIterator() {
198 // generates stub 'remove' function for subclasses of Iterator to be compatible with java.util.Iterator
199 if (DescriptorUtils.isIteratorWithoutRemoveImpl(descriptor)) {
200 MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "remove", "()V", null, null);
201 genMethodThrow(mv, "java/lang/UnsupportedOperationException", "Mutating method called on a Kotlin Iterator");
202 }
203 }
204 }