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 }