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 117 generateBridge(interfaceFunction, cv); 118 119 JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(interfaceFunction.getName(), funDescriptor); 120 121 FunctionCodegen fc = new FunctionCodegen(context, cv, state, getParentCodegen()); 122 fc.generateMethod(fun, jvmMethodSignature, funDescriptor, strategy); 123 124 this.constructor = generateConstructor(cv); 125 126 if (isConst(closure)) { 127 generateConstInstance(cv); 128 } 129 130 genClosureFields(closure, cv, typeMapper); 131 132 fc.generateDefaultIfNeeded(context.intoFunction(funDescriptor), 133 typeMapper.mapSignature(Name.identifier("invoke"), funDescriptor), 134 funDescriptor, 135 context.getContextKind(), 136 DefaultParameterValueLoader.DEFAULT); 137 138 cv.done(); 139 } 140 141 @NotNull 142 public StackValue putInstanceOnStack(@NotNull InstructionAdapter v, @NotNull ExpressionCodegen codegen) { 143 if (isConst(closure)) { 144 v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor()); 145 } 146 else { 147 v.anew(asmType); 148 v.dup(); 149 150 codegen.pushClosureOnStack(closure, false); 151 v.invokespecial(asmType.getInternalName(), "<init>", constructor.getDescriptor()); 152 } 153 return StackValue.onStack(asmType); 154 } 155 156 157 private void generateConstInstance(@NotNull ClassBuilder cv) { 158 MethodVisitor mv = cv.newMethod(fun, ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY); 159 InstructionAdapter iv = new InstructionAdapter(mv); 160 161 cv.newField(fun, ACC_STATIC | ACC_FINAL, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(), null, null); 162 163 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 164 mv.visitCode(); 165 iv.anew(asmType); 166 iv.dup(); 167 iv.invokespecial(asmType.getInternalName(), "<init>", "()V"); 168 iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor()); 169 mv.visitInsn(RETURN); 170 FunctionCodegen.endVisit(mv, "<clinit>", fun); 171 } 172 } 173 174 private void generateBridge(@NotNull FunctionDescriptor interfaceFunction, @NotNull ClassBuilder cv) { 175 Method bridge = typeMapper.mapSignature(interfaceFunction).getAsmMethod(); 176 177 Method delegate = typeMapper.mapSignature(interfaceFunction.getName(), funDescriptor).getAsmMethod(); 178 179 if (bridge.getDescriptor().equals(delegate.getDescriptor())) { 180 return; 181 } 182 183 MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC | ACC_BRIDGE, interfaceFunction.getName().asString(), 184 bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY); 185 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 186 mv.visitCode(); 187 188 InstructionAdapter iv = new InstructionAdapter(mv); 189 190 iv.load(0, asmType); 191 192 ReceiverParameterDescriptor receiver = funDescriptor.getReceiverParameter(); 193 int count = 1; 194 if (receiver != null) { 195 StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(receiver.getType()), iv); 196 count++; 197 } 198 199 List<ValueParameterDescriptor> params = funDescriptor.getValueParameters(); 200 for (ValueParameterDescriptor param : params) { 201 StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(param.getType()), iv); 202 count++; 203 } 204 205 iv.invokevirtual(asmType.getInternalName(), interfaceFunction.getName().asString(), delegate.getDescriptor()); 206 StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv); 207 208 iv.areturn(bridge.getReturnType()); 209 210 FunctionCodegen.endVisit(mv, "bridge", fun); 211 } 212 } 213 214 @NotNull 215 private Method generateConstructor(@NotNull ClassBuilder cv) { 216 List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType); 217 218 Type[] argTypes = fieldListToTypeArray(args); 219 220 Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes); 221 MethodVisitor mv = cv.newMethod(fun, NO_FLAG_PACKAGE_PRIVATE, "<init>", constructor.getDescriptor(), null, 222 ArrayUtil.EMPTY_STRING_ARRAY); 223 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 224 mv.visitCode(); 225 InstructionAdapter iv = new InstructionAdapter(mv); 226 227 iv.load(0, superClass); 228 iv.invokespecial(superClass.getInternalName(), "<init>", "()V"); 229 230 int k = 1; 231 for (FieldInfo fieldInfo : args) { 232 k = AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, k, iv); 233 } 234 235 iv.visitInsn(RETURN); 236 237 FunctionCodegen.endVisit(iv, "constructor", fun); 238 } 239 return constructor; 240 } 241 242 @NotNull 243 public static List<FieldInfo> calculateConstructorParameters( 244 @NotNull JetTypeMapper typeMapper, 245 @NotNull CalculatedClosure closure, 246 @NotNull Type ownerType 247 ) { 248 BindingContext bindingContext = typeMapper.getBindingContext(); 249 List<FieldInfo> args = Lists.newArrayList(); 250 ClassDescriptor captureThis = closure.getCaptureThis(); 251 if (captureThis != null) { 252 Type type = typeMapper.mapType(captureThis); 253 args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD)); 254 } 255 JetType captureReceiverType = closure.getCaptureReceiverType(); 256 if (captureReceiverType != null) { 257 args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), CAPTURED_RECEIVER_FIELD)); 258 } 259 260 for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) { 261 if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { 262 Type sharedVarType = typeMapper.getSharedVarType(descriptor); 263 264 Type type = sharedVarType != null 265 ? sharedVarType 266 : typeMapper.mapType((VariableDescriptor) descriptor); 267 args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().asString())); 268 } 269 else if (isLocalNamedFun(descriptor)) { 270 Type classType = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor); 271 args.add(FieldInfo.createForHiddenField(ownerType, classType, "$" + descriptor.getName().asString())); 272 } 273 else if (descriptor instanceof FunctionDescriptor) { 274 assert captureReceiverType != null; 275 } 276 } 277 return args; 278 } 279 280 private static Type[] fieldListToTypeArray(List<FieldInfo> args) { 281 Type[] argTypes = new Type[args.size()]; 282 for (int i = 0; i != argTypes.length; ++i) { 283 argTypes[i] = args.get(i).getFieldType(); 284 } 285 return argTypes; 286 } 287 288 @NotNull 289 private String getGenericSignature() { 290 ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, funDescriptor); 291 Collection<JetType> supertypes = classDescriptor.getTypeConstructor().getSupertypes(); 292 assert supertypes.size() == 1 : "Closure must have exactly one supertype: " + funDescriptor; 293 JetType supertype = supertypes.iterator().next(); 294 295 BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS, true); 296 typeMapper.writeFormalTypeParameters(Collections.<TypeParameterDescriptor>emptyList(), sw); 297 sw.writeSuperclass(); 298 typeMapper.mapSupertype(supertype, sw); 299 sw.writeSuperclassEnd(); 300 301 String signature = sw.makeJavaGenericSignature(); 302 assert signature != null : "Closure superclass must have a generic signature: " + funDescriptor; 303 return signature; 304 } 305 306 private static FunctionDescriptor getInvokeFunction(FunctionDescriptor funDescriptor) { 307 int paramCount = funDescriptor.getValueParameters().size(); 308 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); 309 ClassDescriptor funClass = funDescriptor.getReceiverParameter() == null 310 ? builtIns.getFunction(paramCount) 311 : builtIns.getExtensionFunction(paramCount); 312 return funClass.getDefaultType().getMemberScope().getFunctions(Name.identifier("invoke")).iterator().next(); 313 } 314 }