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