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