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