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