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