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 }