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