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