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 genInitSingletonField(asmType, iv); 166 mv.visitInsn(RETURN); 167 FunctionCodegen.endVisit(mv, "<clinit>", fun); 168 } 169 } 170 171 private void generateBridge(@NotNull FunctionDescriptor interfaceFunction, @NotNull ClassBuilder cv) { 172 Method bridge = typeMapper.mapSignature(interfaceFunction).getAsmMethod(); 173 174 Method delegate = typeMapper.mapSignature(interfaceFunction.getName(), funDescriptor).getAsmMethod(); 175 176 if (bridge.getDescriptor().equals(delegate.getDescriptor())) { 177 return; 178 } 179 180 MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC | ACC_BRIDGE, interfaceFunction.getName().asString(), 181 bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY); 182 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 183 mv.visitCode(); 184 185 InstructionAdapter iv = new InstructionAdapter(mv); 186 187 iv.load(0, asmType); 188 189 ReceiverParameterDescriptor receiver = funDescriptor.getReceiverParameter(); 190 int count = 1; 191 if (receiver != null) { 192 StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(receiver.getType()), iv); 193 count++; 194 } 195 196 List<ValueParameterDescriptor> params = funDescriptor.getValueParameters(); 197 for (ValueParameterDescriptor param : params) { 198 StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(param.getType()), iv); 199 count++; 200 } 201 202 iv.invokevirtual(asmType.getInternalName(), interfaceFunction.getName().asString(), delegate.getDescriptor()); 203 StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv); 204 205 iv.areturn(bridge.getReturnType()); 206 207 FunctionCodegen.endVisit(mv, "bridge", fun); 208 } 209 } 210 211 @NotNull 212 private Method generateConstructor(@NotNull ClassBuilder cv) { 213 List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType); 214 215 Type[] argTypes = fieldListToTypeArray(args); 216 217 Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes); 218 MethodVisitor mv = cv.newMethod(fun, NO_FLAG_PACKAGE_PRIVATE, "<init>", constructor.getDescriptor(), null, 219 ArrayUtil.EMPTY_STRING_ARRAY); 220 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 221 mv.visitCode(); 222 InstructionAdapter iv = new InstructionAdapter(mv); 223 224 iv.load(0, superClass); 225 iv.invokespecial(superClass.getInternalName(), "<init>", "()V"); 226 227 int k = 1; 228 for (FieldInfo fieldInfo : args) { 229 k = AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, k, iv); 230 } 231 232 iv.visitInsn(RETURN); 233 234 FunctionCodegen.endVisit(iv, "constructor", fun); 235 } 236 return constructor; 237 } 238 239 @NotNull 240 public static List<FieldInfo> calculateConstructorParameters( 241 @NotNull JetTypeMapper typeMapper, 242 @NotNull CalculatedClosure closure, 243 @NotNull Type ownerType 244 ) { 245 BindingContext bindingContext = typeMapper.getBindingContext(); 246 List<FieldInfo> args = Lists.newArrayList(); 247 ClassDescriptor captureThis = closure.getCaptureThis(); 248 if (captureThis != null) { 249 Type type = typeMapper.mapType(captureThis); 250 args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD)); 251 } 252 ClassifierDescriptor captureReceiver = closure.getCaptureReceiver(); 253 if (captureReceiver != null) { 254 args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiver), CAPTURED_RECEIVER_FIELD)); 255 } 256 257 for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) { 258 if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { 259 Type sharedVarType = typeMapper.getSharedVarType(descriptor); 260 261 Type type = sharedVarType != null 262 ? sharedVarType 263 : typeMapper.mapType((VariableDescriptor) descriptor); 264 args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().asString())); 265 } 266 else if (isLocalNamedFun(descriptor)) { 267 Type classType = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor); 268 args.add(FieldInfo.createForHiddenField(ownerType, classType, "$" + descriptor.getName().asString())); 269 } 270 else if (descriptor instanceof FunctionDescriptor) { 271 assert captureReceiver != null; 272 } 273 } 274 return args; 275 } 276 277 private static Type[] fieldListToTypeArray(List<FieldInfo> args) { 278 Type[] argTypes = new Type[args.size()]; 279 for (int i = 0; i != argTypes.length; ++i) { 280 argTypes[i] = args.get(i).getFieldType(); 281 } 282 return argTypes; 283 } 284 285 @NotNull 286 private String getGenericSignature() { 287 ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, funDescriptor); 288 Collection<JetType> supertypes = classDescriptor.getTypeConstructor().getSupertypes(); 289 assert supertypes.size() == 1 : "Closure must have exactly one supertype: " + funDescriptor; 290 JetType supertype = supertypes.iterator().next(); 291 292 BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS, true); 293 typeMapper.writeFormalTypeParameters(Collections.<TypeParameterDescriptor>emptyList(), sw); 294 sw.writeSuperclass(); 295 typeMapper.mapSupertype(supertype, sw); 296 sw.writeSuperclassEnd(); 297 298 String signature = sw.makeJavaGenericSignature(); 299 assert signature != null : "Closure superclass must have a generic signature: " + funDescriptor; 300 return signature; 301 } 302 303 private static FunctionDescriptor getInvokeFunction(FunctionDescriptor funDescriptor) { 304 int paramCount = funDescriptor.getValueParameters().size(); 305 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); 306 ClassDescriptor funClass = funDescriptor.getReceiverParameter() == null 307 ? builtIns.getFunction(paramCount) 308 : builtIns.getExtensionFunction(paramCount); 309 return funClass.getDefaultType().getMemberScope().getFunctions(Name.identifier("invoke")).iterator().next(); 310 } 311 }