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