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