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