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