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