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