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 com.google.common.collect.Lists; 020 import com.intellij.psi.PsiElement; 021 import com.intellij.util.ArrayUtil; 022 import org.jetbrains.annotations.NotNull; 023 import org.jetbrains.annotations.Nullable; 024 import org.jetbrains.jet.codegen.binding.CalculatedClosure; 025 import org.jetbrains.jet.codegen.context.CodegenContext; 026 import org.jetbrains.jet.codegen.context.LocalLookup; 027 import org.jetbrains.jet.codegen.signature.BothSignatureWriter; 028 import org.jetbrains.jet.codegen.state.GenerationState; 029 import org.jetbrains.jet.codegen.state.JetTypeMapper; 030 import org.jetbrains.jet.lang.descriptors.*; 031 import org.jetbrains.jet.lang.resolve.BindingContext; 032 import org.jetbrains.jet.lang.resolve.DescriptorUtils; 033 import org.jetbrains.jet.lang.resolve.java.JvmAbi; 034 import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature; 035 import org.jetbrains.jet.lang.resolve.name.Name; 036 import org.jetbrains.jet.lang.types.JetType; 037 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 038 import org.jetbrains.org.objectweb.asm.MethodVisitor; 039 import org.jetbrains.org.objectweb.asm.Type; 040 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; 041 import org.jetbrains.org.objectweb.asm.commons.Method; 042 043 import java.util.ArrayList; 044 import java.util.Collections; 045 import java.util.List; 046 047 import static org.jetbrains.jet.codegen.AsmUtil.*; 048 import static org.jetbrains.jet.codegen.JvmCodegenUtil.isConst; 049 import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; 050 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; 051 import static org.jetbrains.org.objectweb.asm.Opcodes.*; 052 053 public class ClosureCodegen extends ParentCodegenAware { 054 private final PsiElement fun; 055 private final FunctionDescriptor funDescriptor; 056 private final SamType samType; 057 private final JetType superClassType; 058 private final List<JetType> superInterfaceTypes; 059 private final CodegenContext context; 060 private final FunctionGenerationStrategy strategy; 061 private final CalculatedClosure closure; 062 private final Type asmType; 063 private final int visibilityFlag; 064 private final KotlinSyntheticClass.Kind syntheticClassKind; 065 066 private Method constructor; 067 068 public ClosureCodegen( 069 @NotNull GenerationState state, 070 @NotNull PsiElement fun, 071 @NotNull FunctionDescriptor funDescriptor, 072 @Nullable SamType samType, 073 @NotNull CodegenContext parentContext, 074 @NotNull KotlinSyntheticClass.Kind syntheticClassKind, 075 @NotNull LocalLookup localLookup, 076 @NotNull FunctionGenerationStrategy strategy, 077 @Nullable MemberCodegen<?> parentCodegen 078 ) { 079 super(state, parentCodegen); 080 081 this.fun = fun; 082 this.funDescriptor = funDescriptor; 083 this.samType = samType; 084 this.context = parentContext.intoClosure(funDescriptor, localLookup, typeMapper); 085 this.syntheticClassKind = syntheticClassKind; 086 this.strategy = strategy; 087 088 ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, funDescriptor); 089 090 if (samType == null) { 091 this.superInterfaceTypes = new ArrayList<JetType>(); 092 093 JetType superClassType = null; 094 for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { 095 ClassifierDescriptor classifier = supertype.getConstructor().getDeclarationDescriptor(); 096 if (DescriptorUtils.isTrait(classifier)) { 097 superInterfaceTypes.add(supertype); 098 } 099 else { 100 assert superClassType == null : "Closure class can't have more than one superclass: " + funDescriptor; 101 superClassType = supertype; 102 } 103 } 104 assert superClassType != null : "Closure class should have a superclass: " + funDescriptor; 105 106 this.superClassType = superClassType; 107 } 108 else { 109 this.superInterfaceTypes = Collections.singletonList(samType.getType()); 110 this.superClassType = KotlinBuiltIns.getInstance().getAnyType(); 111 } 112 113 this.closure = bindingContext.get(CLOSURE, classDescriptor); 114 assert closure != null : "Closure must be calculated for class: " + classDescriptor; 115 116 this.asmType = asmTypeForAnonymousClass(bindingContext, funDescriptor); 117 118 visibilityFlag = AsmUtil.getVisibilityAccessFlagForAnonymous(classDescriptor); 119 } 120 121 public void gen() { 122 ClassBuilder cv = state.getFactory().newVisitor(asmType, fun.getContainingFile()); 123 124 FunctionDescriptor erasedInterfaceFunction; 125 if (samType == null) { 126 erasedInterfaceFunction = getErasedInvokeFunction(funDescriptor); 127 } 128 else { 129 erasedInterfaceFunction = samType.getAbstractMethod().getOriginal(); 130 } 131 132 BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS); 133 if (samType != null) { 134 typeMapper.writeFormalTypeParameters(samType.getType().getConstructor().getParameters(), sw); 135 } 136 sw.writeSuperclass(); 137 Type superClassAsmType = typeMapper.mapSupertype(superClassType, sw); 138 sw.writeSuperclassEnd(); 139 String[] superInterfaceAsmTypes = new String[superInterfaceTypes.size()]; 140 for (int i = 0; i < superInterfaceTypes.size(); i++) { 141 JetType superInterfaceType = superInterfaceTypes.get(i); 142 sw.writeInterface(); 143 superInterfaceAsmTypes[i] = typeMapper.mapSupertype(superInterfaceType, sw).getInternalName(); 144 sw.writeInterfaceEnd(); 145 } 146 147 cv.defineClass(fun, 148 V1_6, 149 ACC_FINAL | ACC_SUPER | visibilityFlag, 150 asmType.getInternalName(), 151 sw.makeJavaGenericSignature(), 152 superClassAsmType.getInternalName(), 153 superInterfaceAsmTypes 154 ); 155 cv.visitSource(fun.getContainingFile().getName(), null); 156 157 writeKotlinSyntheticClassAnnotation(cv, syntheticClassKind); 158 159 JvmMethodSignature jvmMethodSignature = 160 typeMapper.mapSignature(funDescriptor).replaceName(erasedInterfaceFunction.getName().toString()); 161 generateBridge(cv, typeMapper.mapSignature(erasedInterfaceFunction).getAsmMethod(), jvmMethodSignature.getAsmMethod()); 162 163 FunctionCodegen fc = new FunctionCodegen(context, cv, state, getParentCodegen()); 164 fc.generateMethod(fun, jvmMethodSignature, funDescriptor, strategy); 165 166 this.constructor = generateConstructor(cv, superClassAsmType); 167 168 if (isConst(closure)) { 169 generateConstInstance(cv); 170 } 171 172 genClosureFields(closure, cv, typeMapper); 173 174 fc.generateDefaultIfNeeded(context.intoFunction(funDescriptor), 175 typeMapper.mapSignature(funDescriptor), 176 funDescriptor, 177 context.getContextKind(), 178 DefaultParameterValueLoader.DEFAULT, 179 null); 180 181 182 AsmUtil.writeOuterClassAndEnclosingMethod(anonymousClassForFunction(bindingContext, funDescriptor), funDescriptor, typeMapper, cv); 183 cv.done(); 184 } 185 186 @NotNull 187 public StackValue putInstanceOnStack(@NotNull InstructionAdapter v, @NotNull ExpressionCodegen codegen) { 188 if (isConst(closure)) { 189 v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor()); 190 } 191 else { 192 v.anew(asmType); 193 v.dup(); 194 195 codegen.pushClosureOnStack(closure, false, codegen.defaultCallGenerator); 196 v.invokespecial(asmType.getInternalName(), "<init>", constructor.getDescriptor()); 197 } 198 return StackValue.onStack(asmType); 199 } 200 201 202 private void generateConstInstance(@NotNull ClassBuilder cv) { 203 MethodVisitor mv = cv.newMethod(fun, ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY); 204 InstructionAdapter iv = new InstructionAdapter(mv); 205 206 cv.newField(fun, ACC_STATIC | ACC_FINAL, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(), null, null); 207 208 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 209 mv.visitCode(); 210 iv.anew(asmType); 211 iv.dup(); 212 iv.invokespecial(asmType.getInternalName(), "<init>", "()V"); 213 iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor()); 214 mv.visitInsn(RETURN); 215 FunctionCodegen.endVisit(mv, "<clinit>", fun); 216 } 217 } 218 219 private void generateBridge(@NotNull ClassBuilder cv, @NotNull Method bridge, @NotNull Method delegate) { 220 if (bridge.equals(delegate)) return; 221 222 MethodVisitor mv = 223 cv.newMethod(fun, ACC_PUBLIC | ACC_BRIDGE, bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY); 224 225 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; 226 227 mv.visitCode(); 228 229 InstructionAdapter iv = new InstructionAdapter(mv); 230 iv.load(0, asmType); 231 232 ReceiverParameterDescriptor receiver = funDescriptor.getReceiverParameter(); 233 int count = 1; 234 if (receiver != null) { 235 StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(receiver.getType()), iv); 236 count++; 237 } 238 239 List<ValueParameterDescriptor> params = funDescriptor.getValueParameters(); 240 for (ValueParameterDescriptor param : params) { 241 StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(param.getType()), iv); 242 count++; 243 } 244 245 iv.invokevirtual(asmType.getInternalName(), delegate.getName(), delegate.getDescriptor()); 246 StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv); 247 248 iv.areturn(bridge.getReturnType()); 249 250 FunctionCodegen.endVisit(mv, "bridge", fun); 251 } 252 253 @NotNull 254 private Method generateConstructor(@NotNull ClassBuilder cv, @NotNull Type superClassAsmType) { 255 List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType); 256 257 return generateConstructor(cv, args, fun, superClassAsmType, state, visibilityFlag); 258 } 259 260 public static Method generateConstructor( 261 @NotNull ClassBuilder cv, 262 @NotNull List<FieldInfo> args, 263 @Nullable PsiElement fun, 264 @NotNull Type superClass, 265 @NotNull GenerationState state, 266 int flags 267 ) { 268 Type[] argTypes = fieldListToTypeArray(args); 269 270 Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes); 271 MethodVisitor mv = cv.newMethod(fun, flags, "<init>", constructor.getDescriptor(), null, 272 ArrayUtil.EMPTY_STRING_ARRAY); 273 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 274 mv.visitCode(); 275 InstructionAdapter iv = new InstructionAdapter(mv); 276 277 int k = 1; 278 for (FieldInfo fieldInfo : args) { 279 k = AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, k, iv); 280 } 281 282 iv.load(0, superClass); 283 iv.invokespecial(superClass.getInternalName(), "<init>", "()V"); 284 285 iv.visitInsn(RETURN); 286 287 FunctionCodegen.endVisit(iv, "constructor", fun); 288 } 289 return constructor; 290 } 291 292 @NotNull 293 public static List<FieldInfo> calculateConstructorParameters( 294 @NotNull JetTypeMapper typeMapper, 295 @NotNull CalculatedClosure closure, 296 @NotNull Type ownerType 297 ) { 298 BindingContext bindingContext = typeMapper.getBindingContext(); 299 List<FieldInfo> args = Lists.newArrayList(); 300 ClassDescriptor captureThis = closure.getCaptureThis(); 301 if (captureThis != null) { 302 Type type = typeMapper.mapType(captureThis); 303 args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD)); 304 } 305 JetType captureReceiverType = closure.getCaptureReceiverType(); 306 if (captureReceiverType != null) { 307 args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), CAPTURED_RECEIVER_FIELD)); 308 } 309 310 for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) { 311 if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { 312 Type sharedVarType = typeMapper.getSharedVarType(descriptor); 313 314 Type type = sharedVarType != null 315 ? sharedVarType 316 : typeMapper.mapType((VariableDescriptor) descriptor); 317 args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().asString())); 318 } 319 else if (isLocalNamedFun(descriptor)) { 320 Type classType = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor); 321 args.add(FieldInfo.createForHiddenField(ownerType, classType, "$" + descriptor.getName().asString())); 322 } 323 else if (descriptor instanceof FunctionDescriptor) { 324 assert captureReceiverType != null; 325 } 326 } 327 return args; 328 } 329 330 private static Type[] fieldListToTypeArray(List<FieldInfo> args) { 331 Type[] argTypes = new Type[args.size()]; 332 for (int i = 0; i != argTypes.length; ++i) { 333 argTypes[i] = args.get(i).getFieldType(); 334 } 335 return argTypes; 336 } 337 338 @NotNull 339 public static FunctionDescriptor getErasedInvokeFunction(@NotNull FunctionDescriptor funDescriptor) { 340 int arity = funDescriptor.getValueParameters().size(); 341 ClassDescriptor funClass = funDescriptor.getReceiverParameter() == null 342 ? KotlinBuiltIns.getInstance().getFunction(arity) 343 : KotlinBuiltIns.getInstance().getExtensionFunction(arity); 344 return funClass.getDefaultType().getMemberScope().getFunctions(Name.identifier("invoke")).iterator().next(); 345 } 346 }