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