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